Compare commits

..

2 Commits

Author SHA1 Message Date
Caio Oliveira
8cff8e346f HEAERS 2025-12-26 02:20:06 -03:00
CamilleLaVey
bb7e63f8ae [hle] BufferDescritorC 2025-12-26 05:38:38 +01:00
3 changed files with 89 additions and 16 deletions

View File

@@ -219,6 +219,11 @@ public:
}
}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
// TODO: This does not seem to be possible on Windows.
return false;
}
void EnableDirectMappedAddress() {
// TODO
UNREACHABLE();
@@ -612,6 +617,24 @@ public:
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
#ifdef __linux__
// Only incur syscall cost IF memset would be slower (theshold = 16MiB)
// TODO(lizzie): Smarter way to dynamically get this threshold (broadwell != raptor lake) for example
if (length >= 2097152UL * 8) {
// Set MADV_REMOVE on backing map to destroy it instantly.
// This also deletes the area from the backing file.
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
return true;
} else {
return false;
}
#else
return false;
#endif
}
void EnableDirectMappedAddress() {
virtual_base = nullptr;
}
@@ -739,7 +762,9 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission
}
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
std::memset(backing_base + physical_offset, fill_value, length);
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
std::memset(backing_base + physical_offset, fill_value, length);
}
}
void HostMemory::EnableDirectMappedAddress() {

View File

@@ -1,8 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <cstring>
#include <sstream>
#include <boost/range/algorithm_ext/erase.hpp>
@@ -187,7 +191,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
if (!command_header->IsTipc()) {
// Padding to align to 16 bytes
@@ -294,7 +298,15 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer() {
}
// Write the domain objects to the command buffer, these go after the raw untranslated data.
// TODO(Subv): This completely ignores C buffers.
if (buffer_c_offset != 0 && !buffer_c_descriptors.empty()) {
constexpr u32 WORDS_PER_DESCRIPTOR = sizeof(IPC::BufferDescriptorC) / sizeof(u32);
u32 descriptor_offset = buffer_c_offset;
for (const auto& descriptor : buffer_c_descriptors) {
std::memcpy(&cmd_buf[descriptor_offset], &descriptor, sizeof(descriptor));
descriptor_offset += WORDS_PER_DESCRIPTOR;
}
}
if (GetManager()->IsDomain()) {
current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
@@ -393,10 +405,14 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
BufferDescriptorB()[buffer_index].Size()};
const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
if (buffer_size == 0) {
LOG_WARNING(Core, "WriteBuffer target index {} has zero capacity", buffer_index);
return 0;
}
if (size > buffer_size) {
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
size = buffer_size; // TODO(bunnei): This needs to be HW tested
LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping",
size, buffer_size);
size = buffer_size;
}
if (is_buffer_b) {
@@ -418,15 +434,25 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size,
std::size_t buffer_index) const {
if (buffer_index >= BufferDescriptorB().size() || size == 0) {
if (buffer_index >= BufferDescriptorB().size()) {
LOG_WARNING(Core, "WriteBufferB invalid buffer index {}", buffer_index);
return 0;
}
if (size == 0) {
LOG_WARNING(Core, "skip empty buffer write (B)");
return 0;
}
const auto buffer_size{BufferDescriptorB()[buffer_index].Size()};
if (buffer_size == 0) {
LOG_WARNING(Core, "WriteBufferB target index {} has zero capacity", buffer_index);
return 0;
}
if (size > buffer_size) {
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
size = buffer_size; // TODO(bunnei): This needs to be HW tested
LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping",
size, buffer_size);
size = buffer_size;
}
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
@@ -435,15 +461,25 @@ std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size
std::size_t HLERequestContext::WriteBufferC(const void* buffer, std::size_t size,
std::size_t buffer_index) const {
if (buffer_index >= BufferDescriptorC().size() || size == 0) {
if (buffer_index >= BufferDescriptorC().size()) {
LOG_WARNING(Core, "WriteBufferC invalid buffer index {}", buffer_index);
return 0;
}
if (size == 0) {
LOG_WARNING(Core, "skip empty buffer write (C)");
return 0;
}
const auto buffer_size{BufferDescriptorC()[buffer_index].Size()};
if (buffer_size == 0) {
LOG_WARNING(Core, "WriteBufferC target index {} has zero capacity", buffer_index);
return 0;
}
if (size > buffer_size) {
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
size = buffer_size; // TODO(bunnei): This needs to be HW tested
LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping",
size, buffer_size);
size = buffer_size;
}
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
@@ -473,12 +509,20 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorB().size() > buffer_index, { return 0; },
"BufferDescriptorB invalid buffer_index {}", buffer_index);
return BufferDescriptorB()[buffer_index].Size();
const auto size = BufferDescriptorB()[buffer_index].Size();
if (size == 0) {
LOG_WARNING(Core, "BufferDescriptorB index {} has zero size", buffer_index);
}
return size;
} else {
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorC().size() > buffer_index, { return 0; },
"BufferDescriptorC invalid buffer_index {}", buffer_index);
return BufferDescriptorC()[buffer_index].Size();
const auto size = BufferDescriptorC()[buffer_index].Size();
if (size == 0) {
LOG_WARNING(Core, "BufferDescriptorC index {} has zero size", buffer_index);
}
return size;
}
return 0;
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -422,6 +425,7 @@ private:
u32 data_payload_offset{};
u32 handles_offset{};
u32 domain_offset{};
u32 buffer_c_offset{};
std::weak_ptr<SessionRequestManager> manager{};
bool is_deferred{false};