1
// Copyright (c) 2013- PPSSPP Project.
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
20
#include "base/compat.h"
21
#include "gfx_es2/gpu_features.h"
22
#include "i18n/i18n.h"
23
#include "ui/ui_context.h"
25
#include "ui/viewgroup.h"
27
#include "profiler/profiler.h"
29
#include "Common/LogManager.h"
30
#include "Common/CPUDetect.h"
32
#include "Core/MemMap.h"
33
#include "Core/Config.h"
34
#include "Core/System.h"
35
#include "Core/CoreParameter.h"
36
#include "Core/MIPS/MIPSTables.h"
37
#include "Core/MIPS/JitCommon/JitBlockCache.h"
38
#include "Core/MIPS/JitCommon/JitCommon.h"
39
#include "GPU/GPUInterface.h"
40
#include "GPU/GPUState.h"
41
#include "UI/MiscScreens.h"
42
#include "UI/DevScreens.h"
43
#include "UI/GameSettingsScreen.h"
46
// Want to avoid including the full header here as it includes d3dx.h
50
static const char *logLevelList[] = {
59
void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
61
I18NCategory *dev = GetI18NCategory("Developer");
62
I18NCategory *sy = GetI18NCategory("System");
64
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
65
LinearLayout *items = new LinearLayout(ORIENT_VERTICAL);
67
#if !defined(MOBILE_DEVICE)
68
items->Add(new Choice(dev->T("Log View")))->OnClick.Handle(this, &DevMenu::OnLogView);
70
items->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DevMenu::OnLogConfig);
71
items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools);
72
items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare);
73
items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenu::OnShaderView);
74
items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame);
75
items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame);
76
items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug);
78
items->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), ""));
84
RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener();
86
ring->SetEnable(true);
90
UI::EventReturn DevMenu::OnToggleAudioDebug(UI::EventParams &e) {
91
g_Config.bShowAudioDebug = !g_Config.bShowAudioDebug;
92
return UI::EVENT_DONE;
96
UI::EventReturn DevMenu::OnLogView(UI::EventParams &e) {
97
UpdateUIState(UISTATE_PAUSEMENU);
98
screenManager()->push(new LogScreen());
99
return UI::EVENT_DONE;
102
UI::EventReturn DevMenu::OnLogConfig(UI::EventParams &e) {
103
UpdateUIState(UISTATE_PAUSEMENU);
104
screenManager()->push(new LogConfigScreen());
105
return UI::EVENT_DONE;
108
UI::EventReturn DevMenu::OnDeveloperTools(UI::EventParams &e) {
109
UpdateUIState(UISTATE_PAUSEMENU);
110
screenManager()->push(new DeveloperToolsScreen());
111
return UI::EVENT_DONE;
114
UI::EventReturn DevMenu::OnJitCompare(UI::EventParams &e) {
115
UpdateUIState(UISTATE_PAUSEMENU);
116
screenManager()->push(new JitCompareScreen());
117
return UI::EVENT_DONE;
120
UI::EventReturn DevMenu::OnShaderView(UI::EventParams &e) {
121
UpdateUIState(UISTATE_PAUSEMENU);
122
screenManager()->push(new ShaderListScreen());
123
return UI::EVENT_DONE;
128
UI::EventReturn DevMenu::OnFreezeFrame(UI::EventParams &e) {
129
if (PSP_CoreParameter().frozen) {
130
PSP_CoreParameter().frozen = false;
132
PSP_CoreParameter().freezeNext = true;
134
return UI::EVENT_DONE;
137
UI::EventReturn DevMenu::OnDumpFrame(UI::EventParams &e) {
138
gpu->DumpNextFrame();
139
return UI::EVENT_DONE;
142
void DevMenu::dialogFinished(const Screen *dialog, DialogResult result) {
143
UpdateUIState(UISTATE_INGAME);
144
// Close when a subscreen got closed.
145
// TODO: a bug in screenmanager causes this not to work here.
146
// screenManager()->finishDialog(this, DR_OK);
149
void LogScreen::UpdateLog() {
151
RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener();
155
for (int i = ring->GetCount() - 1; i >= 0; i--) {
156
TextView *v = vert_->Add(new TextView(ring->TextAt(i), FLAG_DYNAMIC_ASCII, false));
157
uint32_t color = 0xFFFFFF;
158
switch (ring->LevelAt(i)) {
159
case LogTypes::LDEBUG: color = 0xE0E0E0; break;
160
case LogTypes::LWARNING: color = 0x50FFFF; break;
161
case LogTypes::LERROR: color = 0x5050FF; break;
162
case LogTypes::LNOTICE: color = 0x30FF30; break;
163
case LogTypes::LINFO: color = 0xFFFFFF; break;
164
case LogTypes::LVERBOSE: color = 0xC0C0C0; break;
166
v->SetTextColor(0xFF000000 | color);
171
void LogScreen::update(InputState &input) {
172
UIDialogScreenWithBackground::update(input);
175
scroll_->ScrollToBottom();
179
void LogScreen::CreateViews() {
181
I18NCategory *di = GetI18NCategory("Dialog");
183
LinearLayout *outer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
186
scroll_ = outer->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0)));
187
LinearLayout *bottom = outer->Add(new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
188
bottom->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
189
cmdLine_ = bottom->Add(new TextEdit("", "Command Line", new LinearLayoutParams(1.0)));
190
cmdLine_->OnEnter.Handle(this, &LogScreen::OnSubmit);
191
bottom->Add(new Button(di->T("Submit")))->OnClick.Handle(this, &LogScreen::OnSubmit);
193
vert_ = scroll_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
194
vert_->SetSpacing(0);
199
UI::EventReturn LogScreen::OnSubmit(UI::EventParams &e) {
200
std::string cmd = cmdLine_->GetText();
202
// TODO: Can add all sorts of fun stuff here that we can't be bothered writing proper UI for, like various memdumps etc.
204
NOTICE_LOG(HLE, "Submitted: %s", cmd.c_str());
207
cmdLine_->SetText("");
208
cmdLine_->SetFocus();
209
return UI::EVENT_DONE;
212
void LogConfigScreen::CreateViews() {
215
I18NCategory *di = GetI18NCategory("Dialog");
216
I18NCategory *dev = GetI18NCategory("Developer");
218
root_ = new ScrollView(ORIENT_VERTICAL);
220
LinearLayout *vert = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
223
LinearLayout *topbar = new LinearLayout(ORIENT_HORIZONTAL);
224
topbar->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
225
topbar->Add(new Choice(di->T("Toggle All")))->OnClick.Handle(this, &LogConfigScreen::OnToggleAll);
226
topbar->Add(new Choice(dev->T("Log Level")))->OnClick.Handle(this, &LogConfigScreen::OnLogLevel);
230
vert->Add(new ItemHeader(dev->T("Logging Channels")));
232
LogManager *logMan = LogManager::GetInstance();
236
UI::GridLayoutSettings gridsettings(cellSize, 64, 5);
237
gridsettings.fillCells = true;
238
GridLayout *grid = vert->Add(new GridLayout(gridsettings, new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
240
for (int i = 0; i < LogManager::GetNumChannels(); i++) {
241
LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
242
LogChannel *chan = logMan->GetLogChannel(type);
243
LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(cellSize - 50, WRAP_CONTENT));
245
row->Add(new CheckBox(&chan->enable_, "", "", new LinearLayoutParams(50, WRAP_CONTENT)));
246
row->Add(new PopupMultiChoice(&chan->level_, chan->GetFullName(), logLevelList, 1, 6, 0, screenManager(), new LinearLayoutParams(1.0)));
251
UI::EventReturn LogConfigScreen::OnToggleAll(UI::EventParams &e) {
252
LogManager *logMan = LogManager::GetInstance();
254
for (int i = 0; i < LogManager::GetNumChannels(); i++) {
255
LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
256
LogChannel *chan = logMan->GetLogChannel(type);
257
chan->enable_ = !chan->enable_;
260
return UI::EVENT_DONE;
263
UI::EventReturn LogConfigScreen::OnLogLevelChange(UI::EventParams &e) {
265
return UI::EVENT_DONE;
268
UI::EventReturn LogConfigScreen::OnLogLevel(UI::EventParams &e) {
269
I18NCategory *dev = GetI18NCategory("Developer");
271
auto logLevelScreen = new LogLevelScreen(dev->T("Log Level"));
272
logLevelScreen->OnChoice.Handle(this, &LogConfigScreen::OnLogLevelChange);
273
screenManager()->push(logLevelScreen);
274
return UI::EVENT_DONE;
277
LogLevelScreen::LogLevelScreen(const std::string &title) : ListPopupScreen(title) {
279
std::vector<std::string> list;
280
for(int i = 0; i < NUMLOGLEVEL; ++i) {
281
list.push_back(logLevelList[i]);
283
adaptor_ = UI::StringVectorListAdaptor(list, -1);
286
void LogLevelScreen::OnCompleted(DialogResult result) {
289
int selected = listView_->GetSelected();
290
LogManager *logMan = LogManager::GetInstance();
292
for (int i = 0; i < LogManager::GetNumChannels(); ++i) {
293
LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
294
LogChannel *chan = logMan->GetLogChannel(type);
296
chan->level_ = selected + 1;
300
const char *GetCompilerABI() {
302
return "armeabi-v7a";
307
#elif defined(_M_IX86)
309
#elif defined(_M_X64)
316
void SystemInfoScreen::CreateViews() {
317
// NOTE: Do not translate this section. It will change a lot and will be impossible to keep up.
318
I18NCategory *di = GetI18NCategory("Dialog");
321
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
323
ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f));
324
root_->Add(leftColumn);
326
AddStandardBack(root_);
328
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 225, new AnchorLayoutParams(10, 0, 10, 0, false));
329
tabHolder->SetTag("DevSystemInfo");
331
root_->Add(tabHolder);
332
ViewGroup *deviceSpecsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
333
deviceSpecsScroll->SetTag("DevSystemInfoDeviceSpecs");
334
LinearLayout *deviceSpecs = new LinearLayout(ORIENT_VERTICAL);
335
deviceSpecs->SetSpacing(0);
336
deviceSpecsScroll->Add(deviceSpecs);
337
tabHolder->AddTab("Device Info", deviceSpecsScroll);
339
deviceSpecs->Add(new ItemHeader("System Information"));
340
deviceSpecs->Add(new InfoItem("Name", System_GetProperty(SYSPROP_NAME)));
341
deviceSpecs->Add(new InfoItem("Lang/Region", System_GetProperty(SYSPROP_LANGREGION)));
342
deviceSpecs->Add(new InfoItem("ABI", GetCompilerABI()));
343
deviceSpecs->Add(new ItemHeader("CPU Information"));
344
deviceSpecs->Add(new InfoItem("Name", cpu_info.brand_string));
345
#if defined(ARM) || defined(ARM64) || defined(MIPS)
346
deviceSpecs->Add(new InfoItem("Cores", StringFromInt(cpu_info.num_cores)));
348
int totalThreads = cpu_info.num_cores * cpu_info.logical_cpu_count;
349
std::string cores = StringFromFormat("%d (%d per core, %d cores)", totalThreads, cpu_info.logical_cpu_count, cpu_info.num_cores);
350
deviceSpecs->Add(new InfoItem("Threads", cores));
352
deviceSpecs->Add(new ItemHeader("GPU Information"));
354
Thin3DContext *thin3d = screenManager()->getThin3DContext();
356
deviceSpecs->Add(new InfoItem("3D API", thin3d->GetInfoString(T3DInfo::APINAME)));
357
deviceSpecs->Add(new InfoItem("Vendor", std::string(thin3d->GetInfoString(T3DInfo::VENDORSTRING)) + " (" + thin3d->GetInfoString(T3DInfo::VENDOR) + ")"));
358
deviceSpecs->Add(new InfoItem("Model", thin3d->GetInfoString(T3DInfo::RENDERER)));
360
deviceSpecs->Add(new InfoItem("Driver Version", System_GetProperty(SYSPROP_GPUDRIVER_VERSION)));
361
if (GetGPUBackend() == GPUBackend::DIRECT3D9) {
362
deviceSpecs->Add(new InfoItem("D3DX Version", StringFromFormat("%d", GetD3DXVersion())));
367
deviceSpecs->Add(new ItemHeader("Audio Information"));
368
deviceSpecs->Add(new InfoItem("Sample rate", StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE))));
369
deviceSpecs->Add(new InfoItem("Frames per buffer", StringFromFormat("%d", System_GetPropertyInt(SYSPROP_AUDIO_FRAMES_PER_BUFFER))));
370
deviceSpecs->Add(new InfoItem("Optimal sample rate", StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE))));
371
deviceSpecs->Add(new InfoItem("Optimal frames per buffer", StringFromFormat("%d", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER))));
373
deviceSpecs->Add(new ItemHeader("Display Information"));
374
deviceSpecs->Add(new InfoItem("Native Resolution", StringFromFormat("%dx%d",
375
System_GetPropertyInt(SYSPROP_DISPLAY_XRES),
376
System_GetPropertyInt(SYSPROP_DISPLAY_YRES))));
377
deviceSpecs->Add(new InfoItem("Refresh rate", StringFromFormat("%0.3f Hz", (float)System_GetPropertyInt(SYSPROP_DISPLAY_REFRESH_RATE) / 1000.0f)));
381
deviceSpecs->Add(new ItemHeader("Version Information"));
382
std::string apiVersion;
383
if (GetGPUBackend() == GPUBackend::OPENGL) {
384
if (gl_extensions.IsGLES) {
385
apiVersion = StringFromFormat("v%d.%d.%d ES", gl_extensions.ver[0], gl_extensions.ver[1], gl_extensions.ver[2]);
387
apiVersion = StringFromFormat("v%d.%d.%d", gl_extensions.ver[0], gl_extensions.ver[1], gl_extensions.ver[2]);
390
apiVersion = thin3d->GetInfoString(T3DInfo::APIVERSION);
391
if (apiVersion.size() > 30)
392
apiVersion.resize(30);
394
deviceSpecs->Add(new InfoItem("API Version", apiVersion));
395
deviceSpecs->Add(new InfoItem("Shading Language", thin3d->GetInfoString(T3DInfo::SHADELANGVERSION)));
398
std::string moga = System_GetProperty(SYSPROP_MOGA_VERSION);
400
moga = "(none detected)";
402
deviceSpecs->Add(new InfoItem("Moga", moga));
407
sprintf(temp, "%dx%d", System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES));
408
deviceSpecs->Add(new InfoItem("Display resolution", temp));
411
ViewGroup *cpuExtensionsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
412
cpuExtensionsScroll->SetTag("DevSystemInfoCPUExt");
413
LinearLayout *cpuExtensions = new LinearLayout(ORIENT_VERTICAL);
414
cpuExtensions->SetSpacing(0);
415
cpuExtensionsScroll->Add(cpuExtensions);
417
tabHolder->AddTab("CPU Extensions", cpuExtensionsScroll);
419
cpuExtensions->Add(new ItemHeader("CPU Extensions"));
420
std::vector<std::string> exts;
421
SplitString(cpu_info.Summarize(), ',', exts);
422
for (size_t i = 2; i < exts.size(); i++) {
423
cpuExtensions->Add(new TextView(exts[i]))->SetFocusable(true);
426
ViewGroup *oglExtensionsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
427
oglExtensionsScroll->SetTag("DevSystemInfoOGLExt");
428
LinearLayout *oglExtensions = new LinearLayout(ORIENT_VERTICAL);
429
oglExtensions->SetSpacing(0);
430
oglExtensionsScroll->Add(oglExtensions);
432
if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) {
433
tabHolder->AddTab("OGL Extensions", oglExtensionsScroll);
435
if (!gl_extensions.IsGLES) {
436
oglExtensions->Add(new ItemHeader("OpenGL Extensions"));
437
} else if (gl_extensions.GLES3) {
438
oglExtensions->Add(new ItemHeader("OpenGL ES 3.0 Extensions"));
440
oglExtensions->Add(new ItemHeader("OpenGL ES 2.0 Extensions"));
443
SplitString(g_all_gl_extensions, ' ', exts);
444
std::sort(exts.begin(), exts.end());
445
for (size_t i = 0; i < exts.size(); i++) {
446
oglExtensions->Add(new TextView(exts[i]))->SetFocusable(true);
450
SplitString(g_all_egl_extensions, ' ', exts);
451
std::sort(exts.begin(), exts.end());
453
// If there aren't any EGL extensions, no need to show the tab.
454
if (exts.size() > 0) {
455
ViewGroup *eglExtensionsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
456
eglExtensionsScroll->SetTag("DevSystemInfoEGLExt");
457
LinearLayout *eglExtensions = new LinearLayout(ORIENT_VERTICAL);
458
eglExtensions->SetSpacing(0);
459
eglExtensionsScroll->Add(eglExtensions);
461
tabHolder->AddTab("EGL Extensions", eglExtensionsScroll);
463
eglExtensions->Add(new ItemHeader("EGL Extensions"));
465
for (size_t i = 0; i < exts.size(); i++) {
466
eglExtensions->Add(new TextView(exts[i]))->SetFocusable(true);
469
} else if (g_Config.iGPUBackend == GPU_BACKEND_VULKAN) {
470
tabHolder->AddTab("Vulkan Features", oglExtensionsScroll);
472
oglExtensions->Add(new ItemHeader("Vulkan Features"));
473
std::vector<std::string> features = thin3d->GetFeatureList();
474
for (auto &feature : features) {
475
oglExtensions->Add(new TextView(feature))->SetFocusable(true);
480
void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {
483
I18NCategory *dev = GetI18NCategory("Developer");
485
addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);
486
parent->Add(addrView_);
488
ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40));
491
for (int i = 0; i < 16; ++i) {
493
snprintf(temp, 16, " %X ", i);
494
buttons_[i] = new Button(temp);
495
grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton);
498
parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace);
501
void AddressPromptScreen::OnCompleted(DialogResult result) {
502
if (result == DR_OK) {
510
UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) {
511
for (int i = 0; i < 16; ++i) {
512
if (buttons_[i] == e.v) {
516
return UI::EVENT_DONE;
519
UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) {
521
return UI::EVENT_DONE;
524
void AddressPromptScreen::AddDigit(int n) {
525
if ((addr_ & 0xF0000000) == 0) {
526
addr_ = addr_ * 16 + n;
528
UpdatePreviewDigits();
531
void AddressPromptScreen::BackspaceDigit() {
533
UpdatePreviewDigits();
536
void AddressPromptScreen::UpdatePreviewDigits() {
537
I18NCategory *dev = GetI18NCategory("Developer");
541
snprintf(temp, 32, "%8X", addr_);
542
addrView_->SetText(temp);
544
addrView_->SetText(dev->T("Enter address"));
548
bool AddressPromptScreen::key(const KeyInput &key) {
549
if (key.flags & KEY_DOWN) {
550
if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) {
551
AddDigit(key.keyCode - NKCODE_0);
552
} else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) {
553
AddDigit(10 + key.keyCode - NKCODE_A);
554
// NKCODE_DEL is backspace.
555
} else if (key.keyCode == NKCODE_DEL) {
557
} else if (key.keyCode == NKCODE_ENTER) {
559
screenManager()->finishDialog(this, DR_OK);
561
return UIDialogScreen::key(key);
564
return UIDialogScreen::key(key);
569
// Three panes: Block chooser, MIPS view, ARM/x86 view
570
void JitCompareScreen::CreateViews() {
571
I18NCategory *di = GetI18NCategory("Dialog");
572
I18NCategory *dev = GetI18NCategory("Developer");
576
root_ = new LinearLayout(ORIENT_HORIZONTAL);
578
ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
579
LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
581
ScrollView *midColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f)));
582
LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
583
midColumn->SetTag("JitCompareLeftDisasm");
584
leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL));
585
leftDisasm_->SetSpacing(0.0f);
587
ScrollView *rightColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f)));
588
rightColumnScroll->SetTag("JitCompareRightDisasm");
589
LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
590
rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL));
591
rightDisasm_->SetSpacing(0.0f);
593
leftColumn->Add(new Choice(dev->T("Current")))->OnClick.Handle(this, &JitCompareScreen::OnCurrentBlock);
594
leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock);
595
leftColumn->Add(new Choice(dev->T("Prev")))->OnClick.Handle(this, &JitCompareScreen::OnPrevBlock);
596
leftColumn->Add(new Choice(dev->T("Next")))->OnClick.Handle(this, &JitCompareScreen::OnNextBlock);
597
leftColumn->Add(new Choice(dev->T("Random")))->OnClick.Handle(this, &JitCompareScreen::OnRandomBlock);
598
leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomFPUBlock);
599
leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomVFPUBlock);
600
leftColumn->Add(new Choice(dev->T("Stats")))->OnClick.Handle(this, &JitCompareScreen::OnShowStats);
601
leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
602
blockName_ = leftColumn->Add(new TextView(dev->T("No block")));
603
blockAddr_ = leftColumn->Add(new TextEdit("", "", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
604
blockAddr_->OnTextChange.Handle(this, &JitCompareScreen::OnAddressChange);
605
blockStats_ = leftColumn->Add(new TextView(""));
607
EventParams ignore = {0};
608
OnCurrentBlock(ignore);
611
void JitCompareScreen::UpdateDisasm() {
612
leftDisasm_->Clear();
613
rightDisasm_->Clear();
617
I18NCategory *dev = GetI18NCategory("Developer");
619
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
622
snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCache->GetNumBlocks());
623
blockName_->SetText(temp);
625
if (currentBlock_ < 0 || currentBlock_ >= blockCache->GetNumBlocks()) {
626
leftDisasm_->Add(new TextView(dev->T("No block")));
627
rightDisasm_->Add(new TextView(dev->T("No block")));
628
blockStats_->SetText("");
632
JitBlock *block = blockCache->GetBlock(currentBlock_);
634
snprintf(temp, sizeof(temp), "%08x", block->originalAddress);
635
blockAddr_->SetText(temp);
637
// Alright. First generate the MIPS disassembly.
639
// TODO: Need a way to communicate branch continuing.
640
for (u32 addr = block->originalAddress; addr <= block->originalAddress + block->originalSize * 4; addr += 4) {
642
MIPSDisAsm(Memory::Read_Instruction(addr), addr, temp, true);
643
std::string mipsDis = temp;
644
leftDisasm_->Add(new TextView(mipsDis))->SetFocusable(true);
648
std::vector<std::string> targetDis = DisassembleArm2(block->normalEntry, block->codeSize);
650
std::vector<std::string> targetDis = DisassembleArm64(block->normalEntry, block->codeSize);
651
#elif defined(_M_IX86) || defined(_M_X64)
652
std::vector<std::string> targetDis = DisassembleX86(block->normalEntry, block->codeSize);
654
#if defined(ARM) || defined(ARM64) || defined(_M_IX86) || defined(_M_X64)
655
for (size_t i = 0; i < targetDis.size(); i++) {
656
rightDisasm_->Add(new TextView(targetDis[i]))->SetFocusable(true);
660
int numMips = leftDisasm_->GetNumSubviews();
661
int numHost = rightDisasm_->GetNumSubviews();
663
snprintf(temp, sizeof(temp), "%d to %d : %d%%", numMips, numHost, 100 * numHost / numMips);
664
blockStats_->SetText(temp);
667
UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) {
668
if (!MIPSComp::jit) {
669
return UI::EVENT_DONE;
671
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
673
return UI::EVENT_DONE;
675
if (blockAddr_->GetText().size() > 8)
676
return UI::EVENT_DONE;
677
if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) {
678
if (Memory::IsValidAddress(addr)) {
679
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr);
683
return UI::EVENT_DONE;
686
UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) {
687
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
688
BlockCacheStats bcStats;
689
blockCache->ComputeStats(bcStats);
690
NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks);
691
NOTICE_LOG(JIT, "Average Bloat: %0.2f%%", 100 * bcStats.avgBloat);
692
NOTICE_LOG(JIT, "Min Bloat: %0.2f%% (%08x)", 100 * bcStats.minBloat, bcStats.minBloatBlock);
693
NOTICE_LOG(JIT, "Max Bloat: %0.2f%% (%08x)", 100 * bcStats.maxBloat, bcStats.maxBloatBlock);
695
int ctr = 0, sz = (int)bcStats.bloatMap.size();
696
for (auto iter : bcStats.bloatMap) {
697
if (ctr < 10 || ctr > sz - 10) {
698
NOTICE_LOG(JIT, "%08x: %f", iter.second, iter.first);
699
} else if (ctr == 10) {
700
NOTICE_LOG(JIT, "...");
705
return UI::EVENT_DONE;
709
UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
710
I18NCategory *dev = GetI18NCategory("Developer");
712
auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));
713
addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);
714
screenManager()->push(addressPrompt);
715
return UI::EVENT_DONE;
718
UI::EventReturn JitCompareScreen::OnPrevBlock(UI::EventParams &e) {
721
return UI::EVENT_DONE;
724
UI::EventReturn JitCompareScreen::OnNextBlock(UI::EventParams &e) {
727
return UI::EVENT_DONE;
730
UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
731
if (!MIPSComp::jit) {
732
return UI::EVENT_DONE;
735
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
737
return UI::EVENT_DONE;
739
if (Memory::IsValidAddress(e.a)) {
740
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
745
return UI::EVENT_DONE;
748
UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
749
if (!MIPSComp::jit) {
750
return UI::EVENT_DONE;
753
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
755
return UI::EVENT_DONE;
757
int numBlocks = blockCache->GetNumBlocks();
759
currentBlock_ = rand() % numBlocks;
762
return UI::EVENT_DONE;
765
UI::EventReturn JitCompareScreen::OnRandomVFPUBlock(UI::EventParams &e) {
766
OnRandomBlock(IS_VFPU);
767
return UI::EVENT_DONE;
770
UI::EventReturn JitCompareScreen::OnRandomFPUBlock(UI::EventParams &e) {
771
OnRandomBlock(IS_FPU);
772
return UI::EVENT_DONE;
775
void JitCompareScreen::OnRandomBlock(int flag) {
776
if (!MIPSComp::jit) {
779
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
783
int numBlocks = blockCache->GetNumBlocks();
785
bool anyWanted = false;
787
while (!anyWanted && tries < 10000) {
788
currentBlock_ = rand() % numBlocks;
789
const JitBlock *b = blockCache->GetBlock(currentBlock_);
790
for (u32 addr = b->originalAddress; addr <= b->originalAddress + b->originalSize; addr += 4) {
791
MIPSOpcode opcode = Memory::Read_Instruction(addr);
792
if (MIPSGetInfo(opcode) & flag) {
794
MIPSDisAsm(opcode, addr, temp);
795
// INFO_LOG(HLE, "Stopping VFPU instruction: %s", temp);
806
UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
807
if (!MIPSComp::jit) {
808
return UI::EVENT_DONE;
810
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
812
return UI::EVENT_DONE;
813
std::vector<int> blockNum;
814
blockCache->GetBlockNumbersFromAddress(currentMIPS->pc, &blockNum);
815
if (blockNum.size() > 0) {
816
currentBlock_ = blockNum[0];
821
return UI::EVENT_DONE;
824
void ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) {
826
std::vector<std::string> shaderIds_ = gpu->DebugGetShaderIDs(shaderType);
827
for (auto id : shaderIds_) {
828
Choice *choice = view->Add(new Choice(gpu->DebugGetShaderString(id, shaderType, SHADER_STRING_SHORT_DESC)));
830
choice->OnClick.Handle(this, &ShaderListScreen::OnShaderClick);
834
struct { DebugShaderType type; const char *name; } shaderTypes[] = {
835
{ SHADER_TYPE_VERTEX, "Vertex" },
836
{ SHADER_TYPE_FRAGMENT, "Fragment" },
837
// { SHADER_TYPE_GEOMETRY, "Geometry" },
838
{ SHADER_TYPE_VERTEXLOADER, "VertexLoader" },
841
void ShaderListScreen::CreateViews() {
844
I18NCategory *di = GetI18NCategory("Dialog");
846
LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL);
849
tabs_ = new TabHolder(ORIENT_HORIZONTAL, 40, new LinearLayoutParams(1.0));
850
tabs_->SetTag("DevShaderList");
852
layout->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
854
for (size_t i = 0; i < ARRAY_SIZE(shaderTypes); i++) {
855
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0));
856
LinearLayout *shaderList = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
857
ListShaders(shaderTypes[i].type, shaderList);
858
scroll->Add(shaderList);
859
tabs_->AddTab(shaderTypes[i].name, scroll);
863
UI::EventReturn ShaderListScreen::OnShaderClick(UI::EventParams &e) {
865
std::string id = e.v->Tag();
866
DebugShaderType type = shaderTypes[tabs_->GetCurrentTab()].type;
867
screenManager()->push(new ShaderViewScreen(id, type));
871
void ShaderViewScreen::CreateViews() {
874
I18NCategory *di = GetI18NCategory("Dialog");
876
LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL);
879
layout->Add(new TextView(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC)));
881
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0));
882
scroll->SetTag("DevShaderView");
885
LinearLayout *lineLayout = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
886
lineLayout->SetSpacing(0.0);
887
scroll->Add(lineLayout);
889
std::vector<std::string> lines;
890
SplitString(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SOURCE_CODE), '\n', lines);
892
for (auto line : lines) {
893
lineLayout->Add(new TextView(line, FLAG_DYNAMIC_ASCII, true));
896
layout->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);