diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/citra_qt/bootmanager.cpp | 2 | ||||
-rw-r--r-- | src/citra_qt/debugger/disassembler.cpp | 2 | ||||
-rw-r--r-- | src/citra_qt/main.cpp | 5 | ||||
-rw-r--r-- | src/citra_qt/main.h | 2 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 43 | ||||
-rw-r--r-- | src/core/hle/applets/applet.cpp | 9 | ||||
-rw-r--r-- | src/core/hle/applets/applet.h | 3 | ||||
-rw-r--r-- | src/core/hle/service/am/am.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/am/am_net.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt.cpp | 53 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt.h | 30 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt_a.cpp | 1 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt_s.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt_u.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/soc_u.cpp | 10 | ||||
-rw-r--r-- | src/core/hw/y2r.cpp | 1 | ||||
-rw-r--r-- | src/video_core/command_processor.cpp | 80 | ||||
-rw-r--r-- | src/video_core/vertex_shader.cpp | 6 |
19 files changed, 185 insertions, 80 deletions
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b12bd858b..a96fbea5f 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -94,7 +94,7 @@ private: }; GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) : - QWidget(parent), emu_thread(emu_thread), keyboard_id(0) { + QWidget(parent), keyboard_id(0), emu_thread(emu_thread) { std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); setWindowTitle(QString::fromStdString(window_title)); diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 1e5ef5299..d3629bbf6 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -159,7 +159,7 @@ void DisassemblerModel::SetNextInstruction(unsigned int address) { } DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) : - QDockWidget(parent), emu_thread(emu_thread), base_addr(0) { + QDockWidget(parent), base_addr(0), emu_thread(emu_thread) { disasm_ui.setupUi(this); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 2746de779..e93e8ebb8 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -207,7 +207,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) } } -void GMainWindow::BootGame(std::string filename) { +void GMainWindow::BootGame(const std::string& filename) { LOG_INFO(Frontend, "Citra starting...\n"); // Initialize the core emulation @@ -263,6 +263,7 @@ void GMainWindow::ShutdownGame() { // Update the GUI ui.action_Start->setEnabled(false); + ui.action_Start->setText(tr("Start")); ui.action_Pause->setEnabled(false); ui.action_Stop->setEnabled(false); render_window->hide(); @@ -291,6 +292,8 @@ void GMainWindow::OnStartGame() emu_thread->SetRunning(true); ui.action_Start->setEnabled(false); + ui.action_Start->setText(tr("Continue")); + ui.action_Pause->setEnabled(true); ui.action_Stop->setEnabled(true); } diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 242b08c39..9fe9e0c9c 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -55,7 +55,7 @@ signals: void EmulationStopping(); private: - void BootGame(std::string filename); + void BootGame(const std::string& filename); void ShutdownGame(); void closeEvent(QCloseEvent* event) override; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index d022546ed..bb0cbb4dc 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3886,7 +3886,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #endif arm_inst* inst_base; unsigned int addr; - unsigned int phys_addr; unsigned int num_instrs = 0; int ptr; @@ -3905,8 +3904,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { else cpu->Reg[15] &= 0xfffffffc; - phys_addr = cpu->Reg[15]; - // Find the cached instruction cream, otherwise translate it... auto itr = cpu->instruction_cache.find(cpu->Reg[15]); if (itr != cpu->instruction_cache.end()) { @@ -3924,9 +3921,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { adc_inst* const inst_cream = (adc_inst*)inst_base->component; + u32 rn_val = RN; + if (inst_cream->Rn == 15) + rn_val += 2 * cpu->GetInstructionSize(); + bool carry; bool overflow; - RD = AddWithCarry(RN, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); + RD = AddWithCarry(rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); if (inst_cream->S && (inst_cream->Rd == 15)) { if (CurrentModeHasSPSR) { @@ -3987,11 +3988,17 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { } AND_INST: { - and_inst *inst_cream = (and_inst *)inst_base->component; - if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { + and_inst* const inst_cream = (and_inst*)inst_base->component; + u32 lop = RN; u32 rop = SHIFTER_OPERAND; + + if (inst_cream->Rn == 15) + lop += 2 * cpu->GetInstructionSize(); + RD = lop & rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { if (CurrentModeHasSPSR) { cpu->Cpsr = cpu->Spsr_copy; @@ -4164,9 +4171,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { cmn_inst* const inst_cream = (cmn_inst*)inst_base->component; + u32 rn_val = RN; + if (inst_cream->Rn == 15) + rn_val += 2 * cpu->GetInstructionSize(); + bool carry; bool overflow; - u32 result = AddWithCarry(RN, SHIFTER_OPERAND, 0, &carry, &overflow); + u32 result = AddWithCarry(rn_val, SHIFTER_OPERAND, 0, &carry, &overflow); UPDATE_NFLAG(result); UPDATE_ZFLAG(result); @@ -4905,6 +4916,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { u32 lop = RN; u32 rop = SHIFTER_OPERAND; + + if (inst_cream->Rn == 15) + lop += 2 * cpu->GetInstructionSize(); + RD = lop | rop; if (inst_cream->S && (inst_cream->Rd == 15)) { @@ -5195,9 +5210,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { rsc_inst* const inst_cream = (rsc_inst*)inst_base->component; + u32 rn_val = RN; + if (inst_cream->Rn == 15) + rn_val += 2 * cpu->GetInstructionSize(); + bool carry; bool overflow; - RD = AddWithCarry(~RN, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); + RD = AddWithCarry(~rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); if (inst_cream->S && (inst_cream->Rd == 15)) { if (CurrentModeHasSPSR) { @@ -5335,9 +5354,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { sbc_inst* const inst_cream = (sbc_inst*)inst_base->component; + u32 rn_val = RN; + if (inst_cream->Rn == 15) + rn_val += 2 * cpu->GetInstructionSize(); + bool carry; bool overflow; - RD = AddWithCarry(RN, ~SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); + RD = AddWithCarry(rn_val, ~SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); if (inst_cream->S && (inst_cream->Rd == 15)) { if (CurrentModeHasSPSR) { @@ -6171,7 +6194,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { u32 rn_val = RN; if (inst_cream->Rn == 15) - rn_val += 8; + rn_val += 2 * cpu->GetInstructionSize(); bool carry; bool overflow; diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 826f6cbb6..bc2a1829e 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -89,12 +89,21 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) return result; } +bool IsLibraryAppletRunning() { + // Check the applets map for instances of any applet + for (auto itr = applets.begin(); itr != applets.end(); ++itr) + if (itr->second != nullptr) + return true; + return false; +} + void Init() { // Register the applet update callback applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); } void Shutdown() { + CoreTiming::RemoveEvent(applet_update_event); } } diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h index b235d0b8a..af442f81d 100644 --- a/src/core/hle/applets/applet.h +++ b/src/core/hle/applets/applet.h @@ -67,6 +67,9 @@ protected: Service::APT::AppletId id; ///< Id of this Applet }; +/// Returns whether a library applet is currently running +bool IsLibraryAppletRunning(); + /// Initializes the HLE applets void Init(); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 7332478fb..7ae4859a7 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -5,6 +5,7 @@ #include "common/logging/log.h" #include "core/hle/service/service.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/am/am_app.h" #include "core/hle/service/am/am_net.h" #include "core/hle/service/am/am_sys.h" @@ -35,7 +36,7 @@ void GetTitleIDList(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = 0; - LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); + LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u. Address=0x%08X", num_titles, media_type, addr); } void GetNumContentInfos(Service::Interface* self) { diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp index b1af0e9d8..aa391f3b2 100644 --- a/src/core/hle/service/am/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp @@ -28,7 +28,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08130000, nullptr, "GetTotalContents"}, {0x08140042, nullptr, "GetContentIndexes"}, {0x08150044, nullptr, "GetContentsInfo"}, - {0x08190108, nullptr, "Unknown"}, + {0x08180042, nullptr, "GetCTCert"}, + {0x08190108, nullptr, "SetCertificates"}, {0x081B00C2, nullptr, "InstallTitlesFinish"}, }; diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 7b6ab4ce0..35402341b 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -101,18 +101,19 @@ void NotifyToWait(Service::Interface* self) { void GetLockHandle(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field + // Bits [0:2] are the applet type (System, Library, etc) + // Bit 5 tells the application that there's a pending APT parameter, + // this will cause the app to wait until parameter_event is signaled. + u32 applet_attributes = cmd_buff[1]; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - // Not sure what these parameters are used for, but retail apps check that they are 0 after - // GetLockHandle has been called. - cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable. - cmd_buff[3] = 0; - cmd_buff[4] = 0; - + cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable. + cmd_buff[3] = 0; // Least significant bit = power button state + cmd_buff[4] = IPC::CopyHandleDesc(); cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); - LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); + + LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], applet_attributes); } void Enable(Service::Interface* self) { @@ -139,13 +140,16 @@ void IsRegistered(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 app_id = cmd_buff[1]; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - /// TODO(Subv): It is currently unknown what this value (0x400) means, - /// but i believe it is used as a global "LibraryApplet" id, to verify if there's - /// any LibApplet currently running. This is not verified. - if (app_id != 0x400) + + // TODO(Subv): An application is considered "registered" if it has already called APT::Enable + // handle this properly once we implement multiprocess support. + cmd_buff[2] = 0; // Set to not registered by default + + if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { + cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0; + } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { cmd_buff[2] = 1; // Set to registered - else - cmd_buff[2] = 0; // Set to not registered + } LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); } @@ -330,7 +334,26 @@ void GetAppCpuTimeLimit(Service::Interface* self) { void PrepareToStartLibraryApplet(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); - cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; + auto applet = HLE::Applets::Applet::Get(applet_id); + if (applet) { + LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); + cmd_buff[1] = RESULT_SUCCESS.raw; + } else { + cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; + } + LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); +} + +void PreloadLibraryApplet(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); + auto applet = HLE::Applets::Applet::Get(applet_id); + if (applet) { + LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); + cmd_buff[1] = RESULT_SUCCESS.raw; + } else { + cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; + } LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); } diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 72972d05b..4a72b6b5c 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -62,6 +62,7 @@ enum class AppletId : u32 { Extrapad = 0x208, Memolib = 0x209, Application = 0x300, + AnyLibraryApplet = 0x400, SoftwareKeyboard2 = 0x401, }; @@ -96,8 +97,26 @@ void GetSharedFont(Service::Interface* self); */ void NotifyToWait(Service::Interface* self); +/** + * APT::GetLockHandle service function + * Inputs: + * 1 : Applet attributes + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Applet attributes + * 3 : Power button state + * 4 : IPC handle descriptor + * 5 : APT mutex handle + */ void GetLockHandle(Service::Interface* self); +/** + * APT::Enable service function + * Inputs: + * 1 : Applet attributes + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ void Enable(Service::Interface* self); /** @@ -284,6 +303,17 @@ void GetAppCpuTimeLimit(Service::Interface* self); void PrepareToStartLibraryApplet(Service::Interface* self); /** + * APT::PreloadLibraryApplet service function + * Inputs: + * 0 : Command header [0x00160040] + * 1 : Id of the applet to start + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +void PreloadLibraryApplet(Service::Interface* self); + +/** * APT::StartLibraryApplet service function * Inputs: * 0 : Command header [0x001E0084] diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 88de339f9..22800c56f 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -21,6 +21,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000D0080, ReceiveParameter, "ReceiveParameter"}, {0x000E0080, GlanceParameter, "GlanceParameter"}, {0x000F0100, CancelParameter, "CancelParameter"}, + {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, {0x003B0040, nullptr, "CancelLibraryApplet?"}, diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 396d1f04a..3ac6ff94f 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -32,9 +32,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00130000, nullptr, "GetPreparationState"}, {0x00140040, nullptr, "SetPreparationState"}, {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, - {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, + {0x00180040, PrepareToStartLibraryApplet,"PrepareToStartLibraryApplet"}, {0x00190040, nullptr, "PrepareToStartSystemApplet"}, {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, {0x001B00C4, nullptr, "StartApplication"}, diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index b724cd72b..146bfd595 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -33,7 +33,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00130000, nullptr, "GetPreparationState"}, {0x00140040, nullptr, "SetPreparationState"}, {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, {0x00190040, nullptr, "PrepareToStartSystemApplet"}, diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp index 155b97f69..f84ce4d72 100644 --- a/src/core/hle/service/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro.cpp @@ -40,7 +40,8 @@ static void Initialize(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_LDR, "(STUBBED) called"); + LOG_WARNING(Service_LDR, "(STUBBED) called. crs_buffer_ptr=0x%08X, crs_size=0x%08X, address=0x%08X, value=0x%08X, process=0x%08X", + crs_buffer_ptr, crs_size, address, value, process); } /** @@ -69,7 +70,8 @@ static void LoadCRR(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_LDR, "(STUBBED) called"); + LOG_WARNING(Service_LDR, "(STUBBED) called. crs_buffer_ptr=0x%08X, crs_size=0x%08X, value=0x%08X, process=0x%08X", + crs_buffer_ptr, crs_size, value, process); } const Interface::FunctionInfo FunctionTable[] = { diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index d0e166fdf..d768a3fc7 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -481,11 +481,17 @@ static void GetHostId(Service::Interface* self) { char name[128]; gethostname(name, sizeof(name)); - hostent* host = gethostbyname(name); - in_addr* addr = reinterpret_cast<in_addr*>(host->h_addr); + addrinfo hints = {}; + addrinfo* res; + + hints.ai_family = AF_INET; + getaddrinfo(name, NULL, &hints, &res); + sockaddr_in* sock_addr = reinterpret_cast<sockaddr_in*>(res->ai_addr); + in_addr* addr = &sock_addr->sin_addr; cmd_buffer[2] = addr->s_addr; cmd_buffer[1] = 0; + freeaddrinfo(res); } static void Close(Service::Interface* self) { diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp index f80e26ecd..082a4db82 100644 --- a/src/core/hw/y2r.cpp +++ b/src/core/hw/y2r.cpp @@ -14,6 +14,7 @@ #include "common/vector_math.h" #include "core/hle/service/y2r_u.h" +#include "core/hw/y2r.h" #include "core/memory.h" namespace HW { diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index ef9584abd..36c3b9947 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -221,57 +221,53 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { // Initialize data for the current vertex VertexShader::InputVertex input; - // Load a debugging token to check whether this gets loaded by the running - // application or not. - static const float24 debug_token = float24::FromRawFloat24(0x00abcdef); - input.attr[0].w = debug_token; - for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { - // Load the default attribute if we're configured to do so, this data will be overwritten by the loader data if it's set - if (attribute_config.IsDefaultAttribute(i)) { + if (vertex_attribute_elements[i] != 0) { + // Default attribute values set if array elements have < 4 components. This + // is *not* carried over from the default attribute settings even if they're + // enabled for this attribute. + static const float24 zero = float24::FromFloat32(0.0f); + static const float24 one = float24::FromFloat32(1.0f); + input.attr[i] = Math::Vec4<float24>(zero, zero, zero, one); + + // Load per-vertex data from the loader arrays + for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { + u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; + const u8* srcdata = Memory::GetPhysicalPointer(source_addr); + + if (g_debug_context && Pica::g_debug_context->recorder) { + memory_accesses.AddAccess(source_addr, + (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4 + : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1); + } + + const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : + (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : + (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata : + *(float*)srcdata; + + input.attr[i][comp] = float24::FromFloat32(srcval); + LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", + comp, i, vertex, index, + attribute_config.GetPhysicalBaseAddress(), + vertex_attribute_sources[i] - base_address, + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i], + input.attr[i][comp].ToFloat32()); + } + } else if (attribute_config.IsDefaultAttribute(i)) { + // Load the default attribute if we're configured to do so input.attr[i] = g_state.vs.default_attributes[i]; LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)", i, vertex, index, input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); - } - - // Load per-vertex data from the loader arrays - for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { - u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; - const u8* srcdata = Memory::GetPhysicalPointer(source_addr); - - if (g_debug_context && Pica::g_debug_context->recorder) { - memory_accesses.AddAccess(source_addr, - (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4 - : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1); - } - - const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : - (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : - (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata : - *(float*)srcdata; - - input.attr[i][comp] = float24::FromFloat32(srcval); - LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", - comp, i, vertex, index, - attribute_config.GetPhysicalBaseAddress(), - vertex_attribute_sources[i] - base_address, - vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i], - input.attr[i][comp].ToFloat32()); + } else { + // TODO(yuriks): In this case, no data gets loaded and the vertex remains + // with the last value it had. This isn't currently maintained + // as global state, however, and so won't work in Cita yet. } } - // HACK: Some games do not initialize the vertex position's w component. This leads - // to critical issues since it messes up perspective division. As a - // workaround, we force the fourth component to 1.0 if we find this to be the - // case. - // To do this, we additionally have to assume that the first input attribute - // is the vertex position, since there's no information about this other than - // the empiric observation that this is usually the case. - if (input.attr[0].w == debug_token) - input.attr[0].w = float24::FromFloat32(1.0); - if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index 960ae5779..5f66f3455 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp @@ -609,6 +609,12 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs: } } + // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation + for (int i = 0; i < 4; ++i) { + ret.color[i] = float24::FromFloat32( + std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f)); + } + LOG_TRACE(Render_Software, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)", ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(), |