Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 54 additions & 46 deletions src/gui/gui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -786,47 +786,32 @@ void PCSX::GUI::init(std::function<void()> applyArguments) {
m_hwrEditor.title = l_("Hardware Registers");
m_biosEditor.title = l_("BIOS");
m_vramEditor.title = l_("VRAM");
m_vramEditor.editor.WriteFn = [](uint8_t* data, size_t offset, uint8_t writtenByte) {
constexpr size_t vramWidth = 1024;
constexpr size_t stride = vramWidth * sizeof(uint16_t); // Number of bytes per line of VRAM

// x and y coordinates of pixel
const auto x = (offset % stride) / sizeof(uint16_t);
const auto y = offset / stride;
const bool offsetIsOdd = (offset & 1) == 1;
const auto maskedOffset = offset & ~1;
uint16_t newPixel;

if (offsetIsOdd) {
newPixel = (writtenByte << 8) | data[maskedOffset];
} else {
newPixel = writtenByte | (data[maskedOffset] << 8);
}

g_emulator->m_gpu->partialUpdateVRAM(x, y, 1, 1, &newPixel);
};

auto exportFn = [this](ImU8* data, size_t len, size_t base_addr, std::string postfixName) {
std::filesystem::path writeFilepath =
g_system->getPersistentDir() / (getSaveStatePrefix(true) + "mem_" + postfixName + ".bin");
IO<File> f(new PosixFile(writeFilepath.string(), FileOps::TRUNCATE));
if (!f->failed()) {
f->write(data, len);
f->close();
g_system->log(LogClass::UI, "Memory exported to: %s\n", writeFilepath.string().c_str());
} else {
g_system->log(LogClass::UI, "Failed to export memory to: %s\n", writeFilepath.string().c_str());
}
auto makeExportFn = [this](MemoryEditorWrapper &wrapper, std::string postfixName) {
return [this, &wrapper, postfixName](size_t len, size_t base_addr) {
std::filesystem::path writeFilepath =
g_system->getPersistentDir() / (getSaveStatePrefix(true) + "mem_" + postfixName + ".bin");
IO<File> out(new PosixFile(writeFilepath.string(), FileOps::TRUNCATE));
if (!out->failed()) {
std::vector<uint8_t> buf(len);
if (wrapper.editor.Cache.BulkReadFn) {
wrapper.editor.Cache.BulkReadFn(buf.data(), 0, len);
}
out->write(buf.data(), len);
out->close();
g_system->log(LogClass::UI, "Memory exported to: %s\n", writeFilepath.string().c_str());
} else {
g_system->log(LogClass::UI, "Failed to export memory to: %s\n", writeFilepath.string().c_str());
}
};
};
#define EXPORT_FUNC(name) [=](ImU8* data, size_t len, size_t base_addr) { exportFn(data, len, base_addr, name); }
for (auto& editor : m_mainMemEditors) {
editor.editor.ExportFn = EXPORT_FUNC("wram");
editor.editor.ExportFn = makeExportFn(editor, "wram");
}
m_parallelPortEditor.editor.ExportFn = EXPORT_FUNC("parallel");
m_scratchPadEditor.editor.ExportFn = EXPORT_FUNC("scratch");
m_hwrEditor.editor.ExportFn = EXPORT_FUNC("hwr");
m_biosEditor.editor.ExportFn = EXPORT_FUNC("bios");
m_vramEditor.editor.ExportFn = EXPORT_FUNC("vram");
m_parallelPortEditor.editor.ExportFn = makeExportFn(m_parallelPortEditor, "parallel");
m_scratchPadEditor.editor.ExportFn = makeExportFn(m_scratchPadEditor, "scratch");
m_hwrEditor.editor.ExportFn = makeExportFn(m_hwrEditor, "hwr");
m_biosEditor.editor.ExportFn = makeExportFn(m_biosEditor, "bios");
m_vramEditor.editor.ExportFn = makeExportFn(m_vramEditor, "vram");

m_offscreenShaderEditor.init();
m_outputShaderEditor.init();
Expand Down Expand Up @@ -1616,47 +1601,70 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)"));
}

{
IO<File> memFile = g_emulator->m_mem->getMemoryAsFile();
unsigned counter = 0;
for (auto& editor : m_mainMemEditors) {
if (editor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
editor.draw(g_emulator->m_mem->m_wram, 8 * 1024 * 1024);
editor.draw(memFile, 8 * 1024 * 1024);
}
counter++;
}
if (m_parallelPortEditor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
m_parallelPortEditor.draw(g_emulator->m_mem->m_exp1, 512 * 1024);
m_parallelPortEditor.draw(memFile, 512 * 1024);
}
counter++;
if (m_scratchPadEditor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
m_scratchPadEditor.draw(g_emulator->m_mem->m_hard, 1024);
m_scratchPadEditor.draw(memFile, 1024);
}
counter++;
if (m_hwrEditor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
m_hwrEditor.draw(g_emulator->m_mem->m_hard + 4 * 1024, 8 * 1024);
m_hwrEditor.draw(memFile, 8 * 1024);
}
counter++;
if (m_biosEditor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
m_biosEditor.draw(g_emulator->m_mem->m_bios, 512 * 1024);
m_biosEditor.draw(memFile, 512 * 1024);
}
counter++;
if (m_vramEditor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);

// This const_cast is disgusting but we only use it to satisfy the type system
// The slice data is indeed treated as read-only
const Slice vram = g_emulator->m_gpu->getVRAM();
m_vramEditor.draw(const_cast<void*>(vram.data()), vram.size());
auto* vramData = (const ImU8*)vram.data();
size_t vramSize = vram.size();
m_vramEditor.editor.ReadFn = [vramData](size_t off) -> ImU8 { return vramData[off]; };
m_vramEditor.editor.WriteFn = [vramData](size_t off, ImU8 writtenByte) {
constexpr size_t vramWidth = 1024;
constexpr size_t stride = vramWidth * sizeof(uint16_t);

const auto x = (off % stride) / sizeof(uint16_t);
const auto y = off / stride;
const bool offsetIsOdd = (off & 1) == 1;
const auto maskedOffset = off & ~(size_t)1;
uint16_t newPixel;

if (offsetIsOdd) {
newPixel = (writtenByte << 8) | vramData[maskedOffset];
} else {
newPixel = writtenByte | (vramData[maskedOffset + 1] << 8);
}

g_emulator->m_gpu->partialUpdateVRAM(x, y, 1, 1, &newPixel);
};
m_vramEditor.editor.Cache.BulkReadFn = [vramData](void* dest, size_t off, size_t len) {
memcpy(dest, vramData + off, len);
};
m_vramEditor.editor.DrawWindow(m_vramEditor.title(), vramSize);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}

Expand Down
22 changes: 21 additions & 1 deletion src/gui/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,27 @@ class GUI final : public UI {
std::function<const char *()> title;

void MenuItem() { ImGui::MenuItem(title(), nullptr, &m_show); }
void draw(void *mem, size_t size) { editor.DrawWindow(title(), mem, size); }
void draw(void *mem, size_t size) {
editor.ReadFn = [mem](size_t off) -> ImU8 { return ((ImU8 *)mem)[off]; };
editor.WriteFn = [mem](size_t off, ImU8 d) { ((ImU8 *)mem)[off] = d; };
editor.Cache.BulkReadFn = [mem](void *dest, size_t off, size_t len) {
memcpy(dest, (ImU8 *)mem + off, len);
};
editor.DrawWindow(title(), size);
}
void draw(IO<File> file, size_t size) {
IO<File> sub(new SubFile(file, m_baseAddr, size, FileOps::READWRITE));
editor.ReadFn = [sub](size_t off) mutable -> ImU8 {
ImU8 b;
sub->readAt(&b, 1, off);
return b;
};
editor.WriteFn = [sub](size_t off, ImU8 d) mutable { sub->writeAt(&d, 1, off); };
editor.Cache.BulkReadFn = [sub](void *dest, size_t off, size_t len) mutable {
sub->readAt(dest, len, off);
};
editor.DrawWindow(title(), size);
}
};
std::string m_stringHolder;
const size_t wramBaseAddr = 0x80000000;
Expand Down
37 changes: 37 additions & 0 deletions src/support/file.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check warning on line 1 in src/support/file.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Code Duplication

introduced similar code in: PCSX::SubFile::readAt,PCSX::SubFile::wSeek,PCSX::SubFile::writeAt. Avoid duplicated, aka copy-pasted, code inside the module. More duplication lowers the code health.

MIT License

Expand Down Expand Up @@ -312,6 +312,43 @@
return m_file->readAt(dest, size, ptr + m_start);
}

ssize_t PCSX::SubFile::wSeek(ssize_t pos, int wheel) {
switch (wheel) {
case SEEK_SET:
m_ptrW = pos;
break;
case SEEK_END:
m_ptrW = m_size - pos;
break;
case SEEK_CUR:
m_ptrW += pos;
break;
}
m_ptrW = std::max(std::min(m_ptrW, m_size), size_t(0));
return m_ptrW;
}

ssize_t PCSX::SubFile::write(const void *src, size_t size) {
ssize_t ret = writeAt(src, size, m_ptrW);
if (ret < 0) return ret;
m_ptrW += ret;
if ((m_ptrW < 0) || (m_ptrW > m_size)) {
throw std::runtime_error("SubFile write pointer got out of bound - shouldn't happen");
}
return ret;
}

ssize_t PCSX::SubFile::writeAt(const void *src, size_t size, size_t ptr) {
ssize_t excess = size + ptr - m_size;
if (excess > 0) {
if (excess > size) {
return -1;
}
size -= excess;
}
return m_file->writeAt(src, size, ptr + m_start);
}

ssize_t PCSX::Fifo::read(void *dest_, size_t size) {
if (size == 0) return 0;
uint8_t *dest = static_cast<uint8_t *>(dest_);
Expand Down
10 changes: 10 additions & 0 deletions src/support/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,18 +457,28 @@ class SubFile : public File {
m_file(file),
m_start(start),
m_size(size < 0 ? file->size() - start : size) {}
SubFile(IO<File> file, size_t start, ssize_t size, FileOps::ReadWrite)
: File(file->seekable() ? RW_SEEKABLE : RW_STREAM),
m_file(file),
m_start(start),
m_size(size < 0 ? file->size() - start : size) {}
virtual ssize_t rSeek(ssize_t pos, int wheel) final override;
virtual ssize_t rTell() final override { return m_ptrR; }
virtual ssize_t wSeek(ssize_t pos, int wheel) final override;
virtual ssize_t wTell() final override { return m_ptrW; }
virtual size_t size() final override { return m_size; }
virtual ssize_t read(void* dest, size_t size) final override;
virtual ssize_t readAt(void* dest, size_t size, size_t ptr) final override;
virtual ssize_t write(const void* src, size_t size) final override;
virtual ssize_t writeAt(const void* src, size_t size, size_t ptr) final override;
virtual bool eof() final override { return m_ptrR == m_size; }
virtual File* dup() final override { return new SubFile(m_file, m_start, m_size); }
virtual bool failed() final override { return m_file->failed(); }

private:
IO<File> m_file;
size_t m_ptrR = 0;
size_t m_ptrW = 0;
const size_t m_start = 0;
const size_t m_size = 0;
};
Expand Down
Loading
Loading