Compare commits

..

21 Commits

Author SHA1 Message Date
Lioncash
ea8f633dc0 service/am: Correct behavior of CreateTransferMemoryStorage()
For whatever reason, shared memory was being used here instead of
transfer memory, which (quite clearly) will not work based off the name
of the function.

This corrects this wonky usage of shared memory.
2019-04-03 17:49:21 -04:00
Lioncash
140cd5e209 kernel/transfer_memory: Add accessors to data and sizes
Also amend erroneous use of size_t. We should be using u64 here.
2019-04-03 17:49:16 -04:00
bunnei
7931a68d4e Merge pull request #2302 from ReinUsesLisp/vk-swapchain
vk_swapchain: Implement a swapchain manager
2019-04-03 11:50:05 -04:00
bunnei
580e3564c9 Merge pull request #2305 from lioncash/shared
kernel/shared_memory: Sanitize supplied size when unmapping
2019-04-03 11:48:11 -04:00
bunnei
74a4a50470 Merge pull request #2314 from lioncash/const
kernel/thread: Minor interface cleanup
2019-04-03 11:46:17 -04:00
bunnei
774fa0b828 Merge pull request #2326 from lioncash/translation
yuzu/applets/{profile_select, software_keyboard}: Use QDialogButtonBox standard buttons instead of custom ones where applicable
2019-04-03 11:44:18 -04:00
Lioncash
65ae1ac4e5 yuzu/applets/software_keyboard: Use QDialogButtonBox standard buttons instead of custom buttons
Like the previous change, this allows Qt to handle proper translations
of the UI buttons, rather than us needing to handle it.
2019-04-03 11:17:10 -04:00
Lioncash
a504bad3fb yuzu/applets/profile_select: Use QDialogButtonBox standard buttons instead of custom buttons
Makes for shorter code, while also not requiring the buttons to be
directly translated, they'll be handled by Qt itself.
2019-04-03 11:15:54 -04:00
bunnei
e796351a0d Merge pull request #2270 from lioncash/plist
kernel/svc: Implement svcGetProcessList and svcGetThreadList
2019-04-02 21:40:39 -04:00
bunnei
57279e1981 Merge pull request #2313 from lioncash/reslimit
kernel/resource_limit: Remove the name member from resource limits
2019-04-02 16:03:54 -04:00
Lioncash
28719ee3b4 kernel/svc: Implement svcGetThreadList
Similarly like svcGetProcessList, this retrieves the list of threads
from the current process. In the kernel itself, a process instance
maintains a list of threads, which are used within this function.

Threads are registered to a process' thread list at thread
initialization, and unregistered from the list upon thread destruction
(if said thread has a non-null owning process).

We assert on the debug event case, as we currently don't implement
kernel debug objects.
2019-04-02 00:48:40 -04:00
Lioncash
cb2bce8006 kernel/svc: Implement svcGetProcessList
This service function simply copies out a specified number of kernel
process IDs, while simultaneously reporting the total number of
processes.
2019-04-02 00:47:14 -04:00
Mat M
628153cccd Merge pull request #2316 from ReinUsesLisp/fixup-process
process: Fix up compilation
2019-04-02 00:46:00 -04:00
Lioncash
4366241739 kernel/thread: Make AllWaitObjectsReady() a const qualified member function
Now that ShouldWait() is a const qualified member function, this one can
be made const qualified as well, since it can handle passing a const
qualified this pointer to ShouldWait().
2019-04-01 18:23:50 -04:00
Lioncash
20cc0b8d3c kernel/wait_object: Make ShouldWait() take thread members by pointer-to-const
Given this is intended as a querying function, it doesn't make sense to
allow the implementer to modify the state of the given thread.
2019-04-01 18:19:45 -04:00
Lioncash
2d70c30fb2 kernel/thread: Avoid sign conversion within GetCommandBufferAddress()
Previously this was performing a u64 + int sign conversion. When dealing
with addresses, we should generally be keeping the arithmetic in the
same signedness type.

This also gets rid of the static lifetime of the constant, as there's no
need to make a trivial type like this potentially live for the entire
duration of the program.
2019-04-01 17:59:45 -04:00
Lioncash
26d0381161 kernel/thread: Make parameter of GetWaitObjectIndex() const qualified
The pointed to member is never actually modified, so it can be made
const.
2019-04-01 17:48:33 -04:00
Lioncash
d09e98f566 kernel/resource_limit: Remove the name member from resource limits
This doesn't really provide any benefit to the resource limit interface.
There's no way for callers to any of the service functions for resource
limits to provide a custom name, so all created instances of resource
limits other than the system resource limit would have a name of
"Unknown".

The system resource limit itself is already trivially identifiable from
its limit values, so there's no real need to take up space in the object to
identify one object meaningfully out of N total objects.
2019-04-01 16:49:28 -04:00
Lioncash
108be41316 kernel/shared_memory: Remove unused core/memory.h include
Nothing from this header is used, so we can remove this include, getting
rid of a dependency on it.
2019-03-29 18:16:22 -04:00
Lioncash
c6147a439d kernel/shared_memory: Sanitize supplied size when unmapping
The kernel makes sure that the given size to unmap is always the same
size as the entire region managed by the shared memory instance,
otherwise it returns an error code signifying an invalid size.

This is similarly done for transfer memory (which we already check for).
2019-03-29 18:16:19 -04:00
ReinUsesLisp
746dab407e vk_swapchain: Implement a swapchain manager 2019-03-29 00:00:51 -03:00
27 changed files with 515 additions and 68 deletions

View File

@@ -115,7 +115,7 @@ struct KernelCore::Impl {
// Creates the default system resource limit
void InitializeSystemResourceLimit(KernelCore& kernel) {
system_resource_limit = ResourceLimit::Create(kernel, "System");
system_resource_limit = ResourceLimit::Create(kernel);
// If setting the default system values fails, then something seriously wrong has occurred.
ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
@@ -191,6 +191,10 @@ const Process* KernelCore::CurrentProcess() const {
return impl->current_process;
}
const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const {
return impl->process_list;
}
void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
impl->named_ports.emplace(std::move(name), std::move(port));
}

View File

@@ -72,6 +72,9 @@ public:
/// Retrieves a const pointer to the current process.
const Process* CurrentProcess() const;
/// Retrieves the list of processes.
const std::vector<SharedPtr<Process>>& GetProcessList() const;
/// Adds a port to the named port table
void AddNamedPort(std::string name, SharedPtr<ClientPort> port);

View File

@@ -80,6 +80,14 @@ u64 Process::GetTotalPhysicalMemoryUsed() const {
return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size;
}
void Process::RegisterThread(const Thread* thread) {
thread_list.push_back(thread);
}
void Process::UnregisterThread(const Thread* thread) {
thread_list.remove(thread);
}
ResultCode Process::ClearSignalState() {
if (status == ProcessStatus::Exited) {
LOG_ERROR(Kernel, "called on a terminated process instance.");
@@ -249,7 +257,7 @@ void Process::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
}
bool Process::ShouldWait(Thread* thread) const {
bool Process::ShouldWait(const Thread* thread) const {
return !is_signaled;
}

View File

@@ -7,6 +7,7 @@
#include <array>
#include <bitset>
#include <cstddef>
#include <list>
#include <string>
#include <vector>
#include <boost/container/static_vector.hpp>
@@ -189,6 +190,19 @@ public:
/// Retrieves the total physical memory used by this process in bytes.
u64 GetTotalPhysicalMemoryUsed() const;
/// Gets the list of all threads created with this process as their owner.
const std::list<const Thread*>& GetThreadList() const {
return thread_list;
}
/// Registers a thread as being created under this process,
/// adding it to this process' thread list.
void RegisterThread(const Thread* thread);
/// Unregisters a thread from this process, removing it
/// from this process' thread list.
void UnregisterThread(const Thread* thread);
/// Clears the signaled state of the process if and only if it's signaled.
///
/// @pre The process must not be already terminated. If this is called on a
@@ -237,7 +251,7 @@ private:
~Process() override;
/// Checks if the specified thread should wait until this process is available.
bool ShouldWait(Thread* thread) const override;
bool ShouldWait(const Thread* thread) const override;
/// Acquires/locks this process for the specified thread if it's available.
void Acquire(Thread* thread) override;
@@ -308,6 +322,9 @@ private:
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
/// List of threads that are running with this process as their owner.
std::list<const Thread*> thread_list;
/// System context
Core::System& system;

View File

@@ -14,7 +14,7 @@ namespace Kernel {
ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
ReadableEvent::~ReadableEvent() = default;
bool ReadableEvent::ShouldWait(Thread* thread) const {
bool ReadableEvent::ShouldWait(const Thread* thread) const {
return !signaled;
}

View File

@@ -36,7 +36,7 @@ public:
return HANDLE_TYPE;
}
bool ShouldWait(Thread* thread) const override;
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
/// Unconditionally clears the readable event's state.

View File

@@ -16,11 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
ResourceLimit::~ResourceLimit() = default;
SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) {
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel));
resource_limit->name = std::move(name);
return resource_limit;
SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
return new ResourceLimit(kernel);
}
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {

View File

@@ -31,16 +31,14 @@ constexpr bool IsValidResourceType(ResourceType type) {
class ResourceLimit final : public Object {
public:
/**
* Creates a resource limit object.
*/
static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown");
/// Creates a resource limit object.
static SharedPtr<ResourceLimit> Create(KernelCore& kernel);
std::string GetTypeName() const override {
return "ResourceLimit";
}
std::string GetName() const override {
return name;
return GetTypeName();
}
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
@@ -95,9 +93,6 @@ private:
ResourceArray limits{};
/// Current resource limit values.
ResourceArray values{};
/// Name of resource limit object.
std::string name;
};
} // namespace Kernel

View File

@@ -30,7 +30,7 @@ void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session)
pending_sessions.push_back(std::move(pending_session));
}
bool ServerPort::ShouldWait(Thread* thread) const {
bool ServerPort::ShouldWait(const Thread* thread) const {
// If there are no pending sessions, we wait until a new one is added.
return pending_sessions.empty();
}

View File

@@ -75,7 +75,7 @@ public:
/// waiting to be accepted by this port.
void AppendPendingSession(SharedPtr<ServerSession> pending_session);
bool ShouldWait(Thread* thread) const override;
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
private:

View File

@@ -46,7 +46,7 @@ ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, st
return MakeResult(std::move(server_session));
}
bool ServerSession::ShouldWait(Thread* thread) const {
bool ServerSession::ShouldWait(const Thread* thread) const {
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
if (parent->client == nullptr)
return false;

View File

@@ -82,7 +82,7 @@ public:
*/
ResultCode HandleSyncRequest(SharedPtr<Thread> thread);
bool ShouldWait(Thread* thread) const override;
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;

View File

@@ -9,7 +9,6 @@
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/memory.h"
namespace Kernel {
@@ -119,7 +118,15 @@ ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermi
ConvertPermissions(permissions));
}
ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) {
ResultCode SharedMemory::Unmap(Process& target_process, VAddr address, u64 unmap_size) {
if (unmap_size != size) {
LOG_ERROR(Kernel,
"Invalid size passed to Unmap. Size must be equal to the size of the "
"memory managed. Shared memory size=0x{:016X}, Unmap size=0x{:016X}",
size, unmap_size);
return ERR_INVALID_SIZE;
}
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
// mapped to a SharedMemory.
return target_process.VMManager().UnmapRange(address, size);

View File

@@ -104,11 +104,17 @@ public:
/**
* Unmaps a shared memory block from the specified address in system memory
*
* @param target_process Process from which to unmap the memory block.
* @param address Address in system memory where the shared memory block is mapped
* @param address Address in system memory where the shared memory block is mapped.
* @param unmap_size The amount of bytes to unmap from this shared memory instance.
*
* @return Result code of the unmap operation
*
* @pre The given size to unmap must be the same size as the amount of memory managed by
* the SharedMemory instance itself, otherwise ERR_INVALID_SIZE will be returned.
*/
ResultCode Unmap(Process& target_process, VAddr address);
ResultCode Unmap(Process& target_process, VAddr address, u64 unmap_size);
/**
* Gets a pointer to the shared memory block

View File

@@ -1140,7 +1140,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
return ERR_INVALID_MEMORY_RANGE;
}
return shared_memory->Unmap(*current_process, addr);
return shared_memory->Unmap(*current_process, addr, size);
}
static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_address,
@@ -1983,6 +1983,83 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource
return RESULT_SUCCESS;
}
static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids,
u32 out_process_ids_size) {
LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}",
out_process_ids, out_process_ids_size);
// If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail.
if ((out_process_ids_size & 0xF0000000) != 0) {
LOG_ERROR(Kernel_SVC,
"Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}",
out_process_ids_size);
return ERR_OUT_OF_RANGE;
}
const auto& kernel = Core::System::GetInstance().Kernel();
const auto& vm_manager = kernel.CurrentProcess()->VMManager();
const auto total_copy_size = out_process_ids_size * sizeof(u64);
if (out_process_ids_size > 0 &&
!vm_manager.IsWithinAddressSpace(out_process_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_process_ids, out_process_ids + total_copy_size);
return ERR_INVALID_ADDRESS_STATE;
}
const auto& process_list = kernel.GetProcessList();
const auto num_processes = process_list.size();
const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
for (std::size_t i = 0; i < copy_amount; ++i) {
Memory::Write64(out_process_ids, process_list[i]->GetProcessID());
out_process_ids += sizeof(u64);
}
*out_num_processes = static_cast<u32>(num_processes);
return RESULT_SUCCESS;
}
ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thread_ids_size,
Handle debug_handle) {
// TODO: Handle this case when debug events are supported.
UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}",
out_thread_ids, out_thread_ids_size);
// If the size is negative or larger than INT32_MAX / sizeof(u64)
if ((out_thread_ids_size & 0xF0000000) != 0) {
LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
out_thread_ids_size);
return ERR_OUT_OF_RANGE;
}
const auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
const auto& vm_manager = current_process->VMManager();
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
if (out_thread_ids_size > 0 &&
!vm_manager.IsWithinAddressSpace(out_thread_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_thread_ids, out_thread_ids + total_copy_size);
return ERR_INVALID_ADDRESS_STATE;
}
const auto& thread_list = current_process->GetThreadList();
const auto num_threads = thread_list.size();
const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
auto list_iter = thread_list.cbegin();
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID());
out_thread_ids += sizeof(u64);
}
*out_num_threads = static_cast<u32>(num_threads);
return RESULT_SUCCESS;
}
namespace {
struct FunctionDef {
using Func = void();
@@ -2095,8 +2172,8 @@ static const FunctionDef SVC_Table[] = {
{0x62, nullptr, "TerminateDebugProcess"},
{0x63, nullptr, "GetDebugEvent"},
{0x64, nullptr, "ContinueDebugEvent"},
{0x65, nullptr, "GetProcessList"},
{0x66, nullptr, "GetThreadList"},
{0x65, SvcWrap<GetProcessList>, "GetProcessList"},
{0x66, SvcWrap<GetThreadList>, "GetThreadList"},
{0x67, nullptr, "GetDebugThreadContext"},
{0x68, nullptr, "SetDebugThreadContext"},
{0x69, nullptr, "QueryDebugProcessMemory"},

View File

@@ -78,6 +78,14 @@ void SvcWrap() {
FuncReturn(retval);
}
template <ResultCode func(u32*, u64, u32)>
void SvcWrap() {
u32 param_1 = 0;
const u32 retval = func(&param_1, Param(1), static_cast<u32>(Param(2))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
template <ResultCode func(u64*, u32)>
void SvcWrap() {
u64 param_1 = 0;

View File

@@ -28,7 +28,7 @@
namespace Kernel {
bool Thread::ShouldWait(Thread* thread) const {
bool Thread::ShouldWait(const Thread* thread) const {
return status != ThreadStatus::Dead;
}
@@ -62,6 +62,8 @@ void Thread::Stop() {
}
wait_objects.clear();
owner_process->UnregisterThread(this);
// Mark the TLS slot in the thread's page as free.
owner_process->FreeTLSSlot(tls_address);
}
@@ -202,6 +204,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->scheduler->AddThread(thread);
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
thread->owner_process->RegisterThread(thread.get());
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
ResetThreadContext(thread->context, stack_top, entry_point, arg);
@@ -229,16 +233,16 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
s32 Thread::GetWaitObjectIndex(WaitObject* object) const {
s32 Thread::GetWaitObjectIndex(const WaitObject* object) const {
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
}
VAddr Thread::GetCommandBufferAddress() const {
// Offset from the start of TLS at which the IPC command buffer begins.
static constexpr int CommandHeaderOffset = 0x80;
return GetTLSAddress() + CommandHeaderOffset;
constexpr u64 command_header_offset = 0x80;
return GetTLSAddress() + command_header_offset;
}
void Thread::SetStatus(ThreadStatus new_status) {
@@ -367,7 +371,7 @@ void Thread::ChangeScheduler() {
system.CpuCore(processor_id).PrepareReschedule();
}
bool Thread::AllWaitObjectsReady() {
bool Thread::AllWaitObjectsReady() const {
return std::none_of(
wait_objects.begin(), wait_objects.end(),
[this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); });

View File

@@ -111,7 +111,7 @@ public:
return HANDLE_TYPE;
}
bool ShouldWait(Thread* thread) const override;
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
/**
@@ -205,7 +205,7 @@ public:
* object in the list.
* @param object Object to query the index of.
*/
s32 GetWaitObjectIndex(WaitObject* object) const;
s32 GetWaitObjectIndex(const WaitObject* object) const;
/**
* Stops a thread, invalidating it from further use
@@ -299,7 +299,7 @@ public:
}
/// Determines whether all the objects this thread is waiting on are ready.
bool AllWaitObjectsReady();
bool AllWaitObjectsReady() const;
const MutexWaitingThreads& GetMutexWaitingThreads() const {
return wait_mutex_threads;

View File

@@ -14,8 +14,8 @@ namespace Kernel {
TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
TransferMemory::~TransferMemory() = default;
SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
size_t size, MemoryPermission permissions) {
SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size,
MemoryPermission permissions) {
SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)};
transfer_memory->base_address = base_address;
@@ -26,7 +26,15 @@ SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_
return transfer_memory;
}
ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermission permissions) {
const u8* TransferMemory::GetPointer() const {
return backing_block.get()->data();
}
u64 TransferMemory::GetSize() const {
return memory_size;
}
ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission permissions) {
if (memory_size != size) {
return ERR_INVALID_SIZE;
}
@@ -39,13 +47,13 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
return ERR_INVALID_STATE;
}
backing_block = std::make_shared<std::vector<u8>>(size);
const auto map_state = owner_permissions == MemoryPermission::None
? MemoryState::TransferMemoryIsolated
: MemoryState::TransferMemory;
auto& vm_manager = owner_process->VMManager();
const auto map_result = vm_manager.MapMemoryBlock(
address, std::make_shared<std::vector<u8>>(size), 0, size, map_state);
const auto map_result = vm_manager.MapMemoryBlock(address, backing_block, 0, size, map_state);
if (map_result.Failed()) {
return map_result.Code();
}
@@ -54,7 +62,7 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
return RESULT_SUCCESS;
}
ResultCode TransferMemory::UnmapMemory(VAddr address, size_t size) {
ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
if (memory_size != size) {
return ERR_INVALID_SIZE;
}

View File

@@ -4,6 +4,9 @@
#pragma once
#include <memory>
#include <vector>
#include "core/hle/kernel/object.h"
union ResultCode;
@@ -25,7 +28,7 @@ class TransferMemory final : public Object {
public:
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, size_t size,
static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
MemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
@@ -46,6 +49,12 @@ public:
return HANDLE_TYPE;
}
/// Gets a pointer to the backing block of this instance.
const u8* GetPointer() const;
/// Gets the size of the memory backing this instance in bytes.
u64 GetSize() const;
/// Attempts to map transfer memory with the given range and memory permissions.
///
/// @param address The base address to being mapping memory at.
@@ -56,7 +65,7 @@ public:
/// the same values that were given when creating the transfer memory
/// instance.
///
ResultCode MapMemory(VAddr address, size_t size, MemoryPermission permissions);
ResultCode MapMemory(VAddr address, u64 size, MemoryPermission permissions);
/// Unmaps the transfer memory with the given range
///
@@ -66,17 +75,20 @@ public:
/// @pre The given address and size must be the same as the ones used
/// to create the transfer memory instance.
///
ResultCode UnmapMemory(VAddr address, size_t size);
ResultCode UnmapMemory(VAddr address, u64 size);
private:
explicit TransferMemory(KernelCore& kernel);
~TransferMemory() override;
/// Memory block backing this instance.
std::shared_ptr<std::vector<u8>> backing_block;
/// The base address for the memory managed by this instance.
VAddr base_address = 0;
/// Size of the memory, in bytes, that this instance manages.
size_t memory_size = 0;
u64 memory_size = 0;
/// The memory permissions that are applied to this instance.
MemoryPermission owner_permissions{};

View File

@@ -24,7 +24,7 @@ public:
* @param thread The thread about which we're deciding.
* @return True if the current thread should wait due to this object being unavailable
*/
virtual bool ShouldWait(Thread* thread) const = 0;
virtual bool ShouldWait(const Thread* thread) const = 0;
/// Acquire/lock the object for the specified thread if it is available
virtual void Acquire(Thread* thread) = 0;

View File

@@ -13,7 +13,7 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
@@ -907,19 +907,19 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rp.SetCurrentOffset(3);
const auto handle{rp.Pop<Kernel::Handle>()};
const auto shared_mem =
Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>(
const auto transfer_mem =
Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(
handle);
if (shared_mem == nullptr) {
if (transfer_mem == nullptr) {
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(-1));
return;
}
const u8* mem_begin = shared_mem->GetPointer();
const u8* mem_end = mem_begin + shared_mem->GetSize();
const u8* const mem_begin = transfer_mem->GetPointer();
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
std::vector<u8> memory{mem_begin, mem_end};
IPC::ResponseBuilder rb{ctx, 2, 0, 1};

View File

@@ -128,7 +128,9 @@ if (ENABLE_VULKAN)
renderer_vulkan/vk_scheduler.cpp
renderer_vulkan/vk_scheduler.h
renderer_vulkan/vk_stream_buffer.cpp
renderer_vulkan/vk_stream_buffer.h)
renderer_vulkan/vk_stream_buffer.h
renderer_vulkan/vk_swapchain.cpp
renderer_vulkan/vk_swapchain.h)
target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
target_compile_definitions(video_core PRIVATE HAS_VULKAN)

View File

@@ -0,0 +1,210 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <limits>
#include <vector>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "video_core/renderer_vulkan/declarations.h"
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
namespace Vulkan {
namespace {
vk::SurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& formats) {
if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) {
return {vk::Format::eB8G8R8A8Unorm, vk::ColorSpaceKHR::eSrgbNonlinear};
}
const auto& found = std::find_if(formats.begin(), formats.end(), [](const auto& format) {
return format.format == vk::Format::eB8G8R8A8Unorm &&
format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
});
return found != formats.end() ? *found : formats[0];
}
vk::PresentModeKHR ChooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& modes) {
// Mailbox doesn't lock the application like fifo (vsync), prefer it
const auto& found = std::find_if(modes.begin(), modes.end(), [](const auto& mode) {
return mode == vk::PresentModeKHR::eMailbox;
});
return found != modes.end() ? *found : vk::PresentModeKHR::eFifo;
}
vk::Extent2D ChooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width,
u32 height) {
constexpr auto undefined_size{std::numeric_limits<u32>::max()};
if (capabilities.currentExtent.width != undefined_size) {
return capabilities.currentExtent;
}
vk::Extent2D extent = {width, height};
extent.width = std::max(capabilities.minImageExtent.width,
std::min(capabilities.maxImageExtent.width, extent.width));
extent.height = std::max(capabilities.minImageExtent.height,
std::min(capabilities.maxImageExtent.height, extent.height));
return extent;
}
} // namespace
VKSwapchain::VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device)
: surface{surface}, device{device} {}
VKSwapchain::~VKSwapchain() = default;
void VKSwapchain::Create(u32 width, u32 height) {
const auto dev = device.GetLogical();
const auto& dld = device.GetDispatchLoader();
const auto physical_device = device.GetPhysical();
const vk::SurfaceCapabilitiesKHR capabilities{
physical_device.getSurfaceCapabilitiesKHR(surface, dld)};
if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return;
}
dev.waitIdle(dld);
Destroy();
CreateSwapchain(capabilities, width, height);
CreateSemaphores();
CreateImageViews();
fences.resize(image_count, nullptr);
}
void VKSwapchain::AcquireNextImage() {
const auto dev{device.GetLogical()};
const auto& dld{device.GetDispatchLoader()};
dev.acquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
*present_semaphores[frame_index], {}, &image_index, dld);
if (auto& fence = fences[image_index]; fence) {
fence->Wait();
fence->Release();
fence = nullptr;
}
}
bool VKSwapchain::Present(vk::Semaphore render_semaphore, VKFence& fence) {
const vk::Semaphore present_semaphore{*present_semaphores[frame_index]};
const std::array<vk::Semaphore, 2> semaphores{present_semaphore, render_semaphore};
const u32 wait_semaphore_count{render_semaphore ? 2U : 1U};
const auto& dld{device.GetDispatchLoader()};
const auto present_queue{device.GetPresentQueue()};
bool recreated = false;
const vk::PresentInfoKHR present_info(wait_semaphore_count, semaphores.data(), 1,
&swapchain.get(), &image_index, {});
switch (const auto result = present_queue.presentKHR(&present_info, dld); result) {
case vk::Result::eSuccess:
break;
case vk::Result::eErrorOutOfDateKHR:
if (current_width > 0 && current_height > 0) {
Create(current_width, current_height);
recreated = true;
}
break;
default:
LOG_CRITICAL(Render_Vulkan, "Vulkan failed to present swapchain due to {}!",
vk::to_string(result));
UNREACHABLE();
}
ASSERT(fences[image_index] == nullptr);
fences[image_index] = &fence;
frame_index = (frame_index + 1) % image_count;
return recreated;
}
bool VKSwapchain::HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const {
// TODO(Rodrigo): Handle framebuffer pixel format changes
return framebuffer.width != current_width || framebuffer.height != current_height;
}
void VKSwapchain::CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width,
u32 height) {
const auto dev{device.GetLogical()};
const auto& dld{device.GetDispatchLoader()};
const auto physical_device{device.GetPhysical()};
const std::vector<vk::SurfaceFormatKHR> formats{
physical_device.getSurfaceFormatsKHR(surface, dld)};
const std::vector<vk::PresentModeKHR> present_modes{
physical_device.getSurfacePresentModesKHR(surface, dld)};
const vk::SurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)};
const vk::PresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)};
extent = ChooseSwapExtent(capabilities, width, height);
current_width = extent.width;
current_height = extent.height;
u32 requested_image_count{capabilities.minImageCount + 1};
if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) {
requested_image_count = capabilities.maxImageCount;
}
vk::SwapchainCreateInfoKHR swapchain_ci(
{}, surface, requested_image_count, surface_format.format, surface_format.colorSpace,
extent, 1, vk::ImageUsageFlagBits::eColorAttachment, {}, {}, {},
capabilities.currentTransform, vk::CompositeAlphaFlagBitsKHR::eOpaque, present_mode, false,
{});
const u32 graphics_family{device.GetGraphicsFamily()};
const u32 present_family{device.GetPresentFamily()};
const std::array<u32, 2> queue_indices{graphics_family, present_family};
if (graphics_family != present_family) {
swapchain_ci.imageSharingMode = vk::SharingMode::eConcurrent;
swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size());
swapchain_ci.pQueueFamilyIndices = queue_indices.data();
} else {
swapchain_ci.imageSharingMode = vk::SharingMode::eExclusive;
}
swapchain = dev.createSwapchainKHRUnique(swapchain_ci, nullptr, dld);
images = dev.getSwapchainImagesKHR(*swapchain, dld);
image_count = static_cast<u32>(images.size());
image_format = surface_format.format;
}
void VKSwapchain::CreateSemaphores() {
const auto dev{device.GetLogical()};
const auto& dld{device.GetDispatchLoader()};
present_semaphores.resize(image_count);
for (std::size_t i = 0; i < image_count; i++) {
present_semaphores[i] = dev.createSemaphoreUnique({}, nullptr, dld);
}
}
void VKSwapchain::CreateImageViews() {
const auto dev{device.GetLogical()};
const auto& dld{device.GetDispatchLoader()};
image_views.resize(image_count);
for (std::size_t i = 0; i < image_count; i++) {
const vk::ImageViewCreateInfo image_view_ci({}, images[i], vk::ImageViewType::e2D,
image_format, {},
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
image_views[i] = dev.createImageViewUnique(image_view_ci, nullptr, dld);
}
}
void VKSwapchain::Destroy() {
frame_index = 0;
present_semaphores.clear();
framebuffers.clear();
image_views.clear();
swapchain.reset();
}
} // namespace Vulkan

View File

@@ -0,0 +1,92 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "common/common_types.h"
#include "video_core/renderer_vulkan/declarations.h"
namespace Layout {
struct FramebufferLayout;
}
namespace Vulkan {
class VKDevice;
class VKFence;
class VKSwapchain {
public:
explicit VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device);
~VKSwapchain();
/// Creates (or recreates) the swapchain with a given size.
void Create(u32 width, u32 height);
/// Acquires the next image in the swapchain, waits as needed.
void AcquireNextImage();
/// Presents the rendered image to the swapchain. Returns true when the swapchains had to be
/// recreated. Takes responsability for the ownership of fence.
bool Present(vk::Semaphore render_semaphore, VKFence& fence);
/// Returns true when the framebuffer layout has changed.
bool HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const;
const vk::Extent2D& GetSize() const {
return extent;
}
u32 GetImageCount() const {
return image_count;
}
u32 GetImageIndex() const {
return image_index;
}
vk::Image GetImageIndex(u32 index) const {
return images[index];
}
vk::ImageView GetImageViewIndex(u32 index) const {
return *image_views[index];
}
vk::Format GetImageFormat() const {
return image_format;
}
private:
void CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, u32 height);
void CreateSemaphores();
void CreateImageViews();
void Destroy();
const vk::SurfaceKHR surface;
const VKDevice& device;
UniqueSwapchainKHR swapchain;
u32 image_count{};
std::vector<vk::Image> images;
std::vector<UniqueImageView> image_views;
std::vector<UniqueFramebuffer> framebuffers;
std::vector<VKFence*> fences;
std::vector<UniqueSemaphore> present_semaphores;
u32 image_index{};
u32 frame_index{};
vk::Format image_format{};
vk::Extent2D extent{};
u32 current_width{};
u32 current_height{};
};
} // namespace Vulkan

View File

@@ -58,10 +58,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
scroll_area = new QScrollArea;
buttons = new QDialogButtonBox;
buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
buttons->addButton(tr("OK"), QDialogButtonBox::AcceptRole);
buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject);

View File

@@ -75,13 +75,13 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length));
});
buttons = new QDialogButtonBox;
buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
buttons->addButton(parameters.submit_text.empty()
? tr("OK")
: QString::fromStdU16String(parameters.submit_text),
QDialogButtonBox::AcceptRole);
buttons = new QDialogButtonBox(QDialogButtonBox::Cancel);
if (parameters.submit_text.empty()) {
buttons->addButton(QDialogButtonBox::Ok);
} else {
buttons->addButton(QString::fromStdU16String(parameters.submit_text),
QDialogButtonBox::AcceptRole);
}
connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
layout->addWidget(header_label);