summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/file_sys/romfs.cpp3
-rw-r--r--src/core/frontend/emu_window.h41
-rw-r--r--src/core/memory.cpp127
-rw-r--r--src/core/memory.h78
4 files changed, 237 insertions, 12 deletions
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index c909d1ce4..120032134 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -5,6 +5,7 @@
#include <memory>
#include "common/common_types.h"
+#include "common/string_util.h"
#include "common/swap.h"
#include "core/file_sys/fsmitm_romfsbuild.h"
#include "core/file_sys/romfs.h"
@@ -126,7 +127,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
return out->GetSubdirectories().front();
while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) {
- if (out->GetSubdirectories().front()->GetName() == "data" &&
+ if (Common::ToLower(out->GetSubdirectories().front()->GetName()) == "data" &&
type == RomFSExtractionType::Truncated)
break;
out = out->GetSubdirectories().front();
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 72294d4d8..13aa14934 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -12,6 +12,15 @@
namespace Core::Frontend {
+/// Information for the Graphics Backends signifying what type of screen pointer is in
+/// WindowInformation
+enum class WindowSystemType {
+ Headless,
+ Windows,
+ X11,
+ Wayland,
+};
+
/**
* Represents a drawing context that supports graphics operations.
*/
@@ -76,6 +85,23 @@ public:
std::pair<unsigned, unsigned> min_client_area_size;
};
+ /// Data describing host window system information
+ struct WindowSystemInfo {
+ // Window system type. Determines which GL context or Vulkan WSI is used.
+ WindowSystemType type = WindowSystemType::Headless;
+
+ // Connection to a display server. This is used on X11 and Wayland platforms.
+ void* display_connection = nullptr;
+
+ // Render surface. This is a pointer to the native window handle, which depends
+ // on the platform. e.g. HWND for Windows, Window for X11. If the surface is
+ // set to nullptr, the video backend will run in headless mode.
+ void* render_surface = nullptr;
+
+ // Scale of the render surface. For hidpi systems, this will be >1.
+ float render_surface_scale = 1.0f;
+ };
+
/// Polls window events
virtual void PollEvents() = 0;
@@ -87,10 +113,6 @@ public:
/// Returns if window is shown (not minimized)
virtual bool IsShown() const = 0;
- /// Retrieves Vulkan specific handlers from the window
- virtual void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
- void* surface) const = 0;
-
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
* @param framebuffer_x Framebuffer x-coordinate that was pressed
@@ -128,6 +150,13 @@ public:
}
/**
+ * Returns system information about the drawing area.
+ */
+ const WindowSystemInfo& GetWindowInfo() const {
+ return window_info;
+ }
+
+ /**
* Gets the framebuffer layout (width, height, and screen regions)
* @note This method is thread-safe
*/
@@ -142,7 +171,7 @@ public:
void UpdateCurrentFramebufferLayout(unsigned width, unsigned height);
protected:
- EmuWindow();
+ explicit EmuWindow();
virtual ~EmuWindow();
/**
@@ -179,6 +208,8 @@ protected:
client_area_height = size.second;
}
+ WindowSystemInfo window_info;
+
private:
/**
* Handler called when the minimal client area was requested to be changed via SetConfig.
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index f0888327f..6061d37ae 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -242,7 +242,52 @@ struct Memory::Impl {
}
case Common::PageType::RasterizerCachedMemory: {
const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
- system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
+ system.GPU().FlushRegion(current_vaddr, copy_amount);
+ std::memcpy(dest_buffer, host_ptr, copy_amount);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ page_index++;
+ page_offset = 0;
+ dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
+ remaining_size -= copy_amount;
+ }
+ }
+
+ void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+ const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+
+ std::size_t remaining_size = size;
+ std::size_t page_index = src_addr >> PAGE_BITS;
+ std::size_t page_offset = src_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, src_addr, size);
+ std::memset(dest_buffer, 0, copy_amount);
+ break;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+
+ const u8* const src_ptr =
+ page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
+ std::memcpy(dest_buffer, src_ptr, copy_amount);
+ break;
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
std::memcpy(dest_buffer, host_ptr, copy_amount);
break;
}
@@ -261,6 +306,10 @@ struct Memory::Impl {
ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
}
+ void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
+ ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size);
+ }
+
void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
const std::size_t size) {
const auto& page_table = process.VMManager().page_table;
@@ -290,7 +339,50 @@ struct Memory::Impl {
}
case Common::PageType::RasterizerCachedMemory: {
u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
- system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
+ system.GPU().InvalidateRegion(current_vaddr, copy_amount);
+ std::memcpy(host_ptr, src_buffer, copy_amount);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ page_index++;
+ page_offset = 0;
+ src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
+ remaining_size -= copy_amount;
+ }
+ }
+
+ void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr,
+ const void* src_buffer, const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+ std::size_t remaining_size = size;
+ std::size_t page_index = dest_addr >> PAGE_BITS;
+ std::size_t page_offset = dest_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, dest_addr, size);
+ break;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+
+ u8* const dest_ptr =
+ page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
+ std::memcpy(dest_ptr, src_buffer, copy_amount);
+ break;
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
std::memcpy(host_ptr, src_buffer, copy_amount);
break;
}
@@ -309,6 +401,10 @@ struct Memory::Impl {
WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
}
+ void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+ WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size);
+ }
+
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
@@ -337,7 +433,7 @@ struct Memory::Impl {
}
case Common::PageType::RasterizerCachedMemory: {
u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
- system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
+ system.GPU().InvalidateRegion(current_vaddr, copy_amount);
std::memset(host_ptr, 0, copy_amount);
break;
}
@@ -384,7 +480,7 @@ struct Memory::Impl {
}
case Common::PageType::RasterizerCachedMemory: {
const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
- system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
+ system.GPU().FlushRegion(current_vaddr, copy_amount);
WriteBlock(process, dest_addr, host_ptr, copy_amount);
break;
}
@@ -545,7 +641,7 @@ struct Memory::Impl {
break;
case Common::PageType::RasterizerCachedMemory: {
const u8* const host_ptr = GetPointerFromVMA(vaddr);
- system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
+ system.GPU().FlushRegion(vaddr, sizeof(T));
T value;
std::memcpy(&value, host_ptr, sizeof(T));
return value;
@@ -587,7 +683,7 @@ struct Memory::Impl {
break;
case Common::PageType::RasterizerCachedMemory: {
u8* const host_ptr{GetPointerFromVMA(vaddr)};
- system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
+ system.GPU().InvalidateRegion(vaddr, sizeof(T));
std::memcpy(host_ptr, &data, sizeof(T));
break;
}
@@ -696,6 +792,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
impl->ReadBlock(src_addr, dest_buffer, size);
}
+void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr,
+ void* dest_buffer, const std::size_t size) {
+ impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size);
+}
+
+void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
+ impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
+}
+
void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
std::size_t size) {
impl->WriteBlock(process, dest_addr, src_buffer, size);
@@ -705,6 +810,16 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std
impl->WriteBlock(dest_addr, src_buffer, size);
}
+void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr,
+ const void* src_buffer, std::size_t size) {
+ impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size);
+}
+
+void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
+}
+
void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
impl->ZeroBlock(process, dest_addr, size);
}
diff --git a/src/core/memory.h b/src/core/memory.h
index 8913a9da4..b92d678a4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -295,6 +295,27 @@ public:
std::size_t size);
/**
+ * Reads a contiguous block of bytes from a specified process' address space.
+ * This unsafe version does not trigger GPU flushing.
+ *
+ * @param process The process to read the data from.
+ * @param src_addr The virtual address to begin reading from.
+ * @param dest_buffer The buffer to place the read bytes into.
+ * @param size The amount of data to read, in bytes.
+ *
+ * @note If a size of 0 is specified, then this function reads nothing and
+ * no attempts to access memory are made at all.
+ *
+ * @pre dest_buffer must be at least size bytes in length, otherwise a
+ * buffer overrun will occur.
+ *
+ * @post The range [dest_buffer, size) contains the read bytes from the
+ * process' address space.
+ */
+ void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
+ std::size_t size);
+
+ /**
* Reads a contiguous block of bytes from the current process' address space.
*
* @param src_addr The virtual address to begin reading from.
@@ -313,6 +334,25 @@ public:
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
/**
+ * Reads a contiguous block of bytes from the current process' address space.
+ * This unsafe version does not trigger GPU flushing.
+ *
+ * @param src_addr The virtual address to begin reading from.
+ * @param dest_buffer The buffer to place the read bytes into.
+ * @param size The amount of data to read, in bytes.
+ *
+ * @note If a size of 0 is specified, then this function reads nothing and
+ * no attempts to access memory are made at all.
+ *
+ * @pre dest_buffer must be at least size bytes in length, otherwise a
+ * buffer overrun will occur.
+ *
+ * @post The range [dest_buffer, size) contains the read bytes from the
+ * current process' address space.
+ */
+ void ReadBlockUnsafe(VAddr src_addr, void* dest_buffer, std::size_t size);
+
+ /**
* Writes a range of bytes into a given process' address space at the specified
* virtual address.
*
@@ -336,6 +376,26 @@ public:
std::size_t size);
/**
+ * Writes a range of bytes into a given process' address space at the specified
+ * virtual address.
+ * This unsafe version does not invalidate GPU Memory.
+ *
+ * @param process The process to write data into the address space of.
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ */
+ void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ std::size_t size);
+
+ /**
* Writes a range of bytes into the current process' address space at the specified
* virtual address.
*
@@ -357,6 +417,24 @@ public:
void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
/**
+ * Writes a range of bytes into the current process' address space at the specified
+ * virtual address.
+ * This unsafe version does not invalidate GPU Memory.
+ *
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the current process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the current process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ */
+ void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size);
+
+ /**
* Fills the specified address range within a process' address space with zeroes.
*
* @param process The process that will have a portion of its memory zeroed out.