summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CMakeLists.txt11
-rw-r--r--externals/cmake-modules/FindSDL2.cmake239
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp53
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp50
-rw-r--r--src/core/hle/kernel/svc.cpp8
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp66
-rw-r--r--src/core/hle/kernel/transfer_memory.h19
-rw-r--r--src/core/hle/kernel/vm_manager.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.h60
-rw-r--r--src/core/hle/kernel/wait_object.cpp13
-rw-r--r--src/core/hle/service/am/am.cpp92
-rw-r--r--src/core/hle/service/am/am.h30
-rw-r--r--src/core/hle/service/am/applets/applets.cpp26
-rw-r--r--src/core/hle/service/am/applets/applets.h24
-rw-r--r--src/core/hle/service/am/applets/error.cpp2
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp14
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp13
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp6
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp4
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/prepo/prepo.cpp30
-rw-r--r--src/video_core/engines/maxwell_3d.cpp91
-rw-r--r--src/video_core/engines/maxwell_3d.h29
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-rw-r--r--src/video_core/gpu.cpp18
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/gpu_thread.h2
-rw-r--r--src/video_core/memory_manager.cpp14
-rw-r--r--src/video_core/memory_manager.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp128
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h7
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.h1
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h20
-rw-r--r--src/video_core/shader/decode/shift.cpp113
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp3
-rw-r--r--src/yuzu/configuration/configure_ui.ui7
-rw-r--r--src/yuzu/game_list_worker.cpp3
-rw-r--r--src/yuzu/uisettings.h1
44 files changed, 605 insertions, 655 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc782e252..44ed4196d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,15 +151,16 @@ if (ENABLE_SDL2)
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
- else()
- find_package(SDL2 REQUIRED)
- endif()
- if (SDL2_FOUND)
- # TODO(yuriks): Make FindSDL2.cmake export an IMPORTED library instead
add_library(SDL2 INTERFACE)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
+ else()
+ find_package(SDL2 REQUIRED)
+ include_directories(${SDL2_INCLUDE_DIRS})
+
+ add_library(SDL2 INTERFACE)
+ target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
endif()
else()
set(SDL2_FOUND NO)
diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake
deleted file mode 100644
index 22ce752c5..000000000
--- a/externals/cmake-modules/FindSDL2.cmake
+++ /dev/null
@@ -1,239 +0,0 @@
-
-# This module defines
-# SDL2_LIBRARY, the name of the library to link against
-# SDL2_FOUND, if false, do not try to link to SDL2
-# SDL2_INCLUDE_DIR, where to find SDL.h
-# SDL2_DLL_DIR, where to find SDL2.dll if it exists
-#
-# This module responds to the the flag:
-# SDL2_BUILDING_LIBRARY
-# If this is defined, then no SDL2main will be linked in because
-# only applications need main().
-# Otherwise, it is assumed you are building an application and this
-# module will attempt to locate and set the the proper link flags
-# as part of the returned SDL2_LIBRARY variable.
-#
-# Don't forget to include SDLmain.h and SDLmain.m your project for the
-# OS X framework based version. (Other versions link to -lSDL2main which
-# this module will try to find on your behalf.) Also for OS X, this
-# module will automatically add the -framework Cocoa on your behalf.
-#
-#
-# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
-# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
-# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
-# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
-# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
-# as appropriate. These values are used to generate the final SDL2_LIBRARY
-# variable, but when these values are unset, SDL2_LIBRARY does not get created.
-#
-#
-# $SDL2DIR is an environment variable that would
-# correspond to the ./configure --prefix=$SDL2DIR
-# used in building SDL2.
-# l.e.galup 9-20-02
-#
-# Modified by Eric Wing.
-# Added code to assist with automated building by using environmental variables
-# and providing a more controlled/consistent search behavior.
-# Added new modifications to recognize OS X frameworks and
-# additional Unix paths (FreeBSD, etc).
-# Also corrected the header search path to follow "proper" SDL guidelines.
-# Added a search for SDL2main which is needed by some platforms.
-# Added a search for threads which is needed by some platforms.
-# Added needed compile switches for MinGW.
-#
-# On OSX, this will prefer the Framework version (if found) over others.
-# People will have to manually change the cache values of
-# SDL2_LIBRARY to override this selection or set the CMake environment
-# CMAKE_INCLUDE_PATH to modify the search paths.
-#
-# Note that the header path has changed from SDL2/SDL.h to just SDL.h
-# This needed to change because "proper" SDL convention
-# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
-# reasons because not all systems place things in SDL2/ (see FreeBSD).
-
-#=============================================================================
-# Copyright 2003-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License").
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2016 Kitware, Inc.
-# Copyright 2000-2011 Insight Software Consortium
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-# nor the names of their contributors may be used to endorse or promote
-# products derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# ------------------------------------------------------------------------------
-#
-# The above copyright and license notice applies to distributions of
-# CMake in source and binary form. Some source files contain additional
-# notices of original copyright by their contributors; see each source
-# for details. Third-party software packages supplied with CMake under
-# compatible licenses provide their own copyright notices documented in
-# corresponding subdirectories.
-#
-# ------------------------------------------------------------------------------
-#
-# CMake was initially developed by Kitware with the following sponsorship:
-#
-# * National Library of Medicine at the National Institutes of Health
-# as part of the Insight Segmentation and Registration Toolkit (ITK).
-#
-# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
-# Visualization Initiative.
-#
-# * National Alliance for Medical Image Computing (NAMIC) is funded by the
-# National Institutes of Health through the NIH Roadmap for Medical Research,
-# Grant U54 EB005149.
-#
-# * Kitware, Inc.
-#
-
-message("<FindSDL2.cmake>")
-
-SET(SDL2_SEARCH_PATHS
- ~/Library/Frameworks
- /Library/Frameworks
- /usr/local
- /usr
- /sw # Fink
- /opt/local # DarwinPorts
- /opt/csw # Blastwave
- /opt
- ${SDL2_PATH}
-)
-
-if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(VC_LIB_PATH_SUFFIX lib/x64)
-else()
- set(VC_LIB_PATH_SUFFIX lib/x86)
-endif()
-
-FIND_LIBRARY(SDL2_LIBRARY_TEMP
- NAMES SDL2
- HINTS
- $ENV{SDL2DIR}
- PATH_SUFFIXES lib64 lib ${VC_LIB_PATH_SUFFIX}
- PATHS ${SDL2_SEARCH_PATHS}
-)
-
-IF(SDL2_LIBRARY_TEMP)
- if(MSVC)
- get_filename_component(SDL2_DLL_DIR_TEMP ${SDL2_LIBRARY_TEMP} DIRECTORY)
- if(EXISTS ${SDL2_DLL_DIR_TEMP}/SDL2.dll)
- set(SDL2_DLL_DIR ${SDL2_DLL_DIR_TEMP})
- unset(SDL2_DLL_DIR_TEMP)
- endif()
- endif()
-
- FIND_PATH(SDL2_INCLUDE_DIR SDL.h
- HINTS
- $ENV{SDL2DIR}
- PATH_SUFFIXES include/SDL2 include
- PATHS ${SDL2_SEARCH_PATHS}
- )
-
- IF(NOT SDL2_BUILDING_LIBRARY)
- IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
- # Non-OS X framework versions expect you to also dynamically link to
- # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
- # seem to provide SDL2main for compatibility even though they don't
- # necessarily need it.
- FIND_LIBRARY(SDL2MAIN_LIBRARY
- NAMES SDL2main
- HINTS
- $ENV{SDL2DIR}
- PATH_SUFFIXES lib64 lib
- PATHS ${SDL2_SEARCH_PATHS}
- )
- ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
- ENDIF(NOT SDL2_BUILDING_LIBRARY)
-
- # SDL2 may require threads on your system.
- # The Apple build may not need an explicit flag because one of the
- # frameworks may already provide it.
- # But for non-OSX systems, I will use the CMake Threads package.
- IF(NOT APPLE)
- FIND_PACKAGE(Threads)
- ENDIF(NOT APPLE)
-
- # MinGW needs an additional library, mwindows
- # It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
- # (Actually on second look, I think it only needs one of the m* libraries.)
- IF(MINGW)
- SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
- ENDIF(MINGW)
-
- # For SDL2main
- IF(NOT SDL2_BUILDING_LIBRARY)
- IF(SDL2MAIN_LIBRARY)
- SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
- ENDIF(SDL2MAIN_LIBRARY)
- ENDIF(NOT SDL2_BUILDING_LIBRARY)
-
- # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
- # CMake doesn't display the -framework Cocoa string in the UI even
- # though it actually is there if I modify a pre-used variable.
- # I think it has something to do with the CACHE STRING.
- # So I use a temporary variable until the end so I can set the
- # "real" variable in one-shot.
- IF(APPLE)
- SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
- ENDIF(APPLE)
-
- # For threads, as mentioned Apple doesn't need this.
- # In fact, there seems to be a problem if I used the Threads package
- # and try using this line, so I'm just skipping it entirely for OS X.
- IF(NOT APPLE)
- SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
- ENDIF(NOT APPLE)
-
- # For MinGW library
- IF(MINGW)
- SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
- ENDIF(MINGW)
-
- # Set the final string here so the GUI reflects the final state.
- SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
-
- # Unset the temp variable to INTERNAL so it is not seen in the CMake GUI
- UNSET(SDL2_LIBRARY_TEMP)
-ENDIF(SDL2_LIBRARY_TEMP)
-
-message("</FindSDL2.cmake>")
-
-INCLUDE(FindPackageHandleStandardArgs)
-
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2ea3dcb61..8475b698c 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -201,42 +201,39 @@ void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
const VAddr arb_addr = thread->GetArbiterWaitAddress();
std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread>& current_thread = *it;
- if (current_thread->GetPriority() >= thread->GetPriority()) {
- thread_list.insert(it, thread);
- return;
- }
- ++it;
+
+ const auto iter =
+ std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) {
+ return entry->GetPriority() >= thread->GetPriority();
+ });
+
+ if (iter == thread_list.cend()) {
+ thread_list.push_back(std::move(thread));
+ } else {
+ thread_list.insert(iter, std::move(thread));
}
- thread_list.push_back(std::move(thread));
}
void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
const VAddr arb_addr = thread->GetArbiterWaitAddress();
std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread>& current_thread = *it;
- if (current_thread.get() == thread.get()) {
- thread_list.erase(it);
- return;
- }
- ++it;
- }
- UNREACHABLE();
+
+ const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(),
+ [&thread](const auto& entry) { return thread == entry; });
+
+ ASSERT(iter != thread_list.cend());
+
+ thread_list.erase(iter);
}
-std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) {
- std::vector<std::shared_ptr<Thread>> result;
- std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- std::shared_ptr<Thread> current_thread = *it;
- result.push_back(std::move(current_thread));
- ++it;
+std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
+ VAddr address) const {
+ const auto iter = arb_threads.find(address);
+ if (iter == arb_threads.cend()) {
+ return {};
}
- return result;
+
+ const std::list<std::shared_ptr<Thread>>& thread_list = iter->second;
+ return {thread_list.cbegin(), thread_list.cend()};
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 386983e54..f958eee5a 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -86,7 +86,7 @@ private:
void RemoveThread(std::shared_ptr<Thread> thread);
// Gets the threads waiting on an address.
- std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address);
+ std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
/// List of threads waiting for a address arbiter
std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 2db28dcf0..ab05788d7 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -284,13 +284,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
std::vector<u8> buffer;
- const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_a) {
+ ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
buffer.resize(BufferDescriptorA()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
} else {
+ ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
buffer.resize(BufferDescriptorX()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
}
@@ -305,7 +310,8 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
return 0;
}
- const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
+ const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
+ BufferDescriptorB()[buffer_index].Size()};
const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
if (size > buffer_size) {
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
@@ -315,8 +321,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_b) {
+ ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
+ "BufferDescriptorB invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size,
+ "BufferDescriptorB buffer_index {} is not large enough", buffer_index);
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
+ ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
+ "BufferDescriptorC invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size,
+ "BufferDescriptorC buffer_index {} is not large enough", buffer_index);
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
@@ -324,15 +338,35 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
}
std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const {
- const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
- return is_buffer_a ? BufferDescriptorA()[buffer_index].Size()
- : BufferDescriptorX()[buffer_index].Size();
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
+ if (is_buffer_a) {
+ ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0,
+ "BufferDescriptorA buffer_index {} is empty", buffer_index);
+ return BufferDescriptorA()[buffer_index].Size();
+ } else {
+ ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0,
+ "BufferDescriptorX buffer_index {} is empty", buffer_index);
+ return BufferDescriptorX()[buffer_index].Size();
+ }
}
std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const {
- const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
- return is_buffer_b ? BufferDescriptorB()[buffer_index].Size()
- : BufferDescriptorC()[buffer_index].Size();
+ const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
+ BufferDescriptorB()[buffer_index].Size()};
+ if (is_buffer_b) {
+ ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
+ "BufferDescriptorB invalid buffer_index {}", buffer_index);
+ return BufferDescriptorB()[buffer_index].Size();
+ } else {
+ ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
+ "BufferDescriptorC invalid buffer_index {}", buffer_index);
+ return BufferDescriptorC()[buffer_index].Size();
+ }
}
std::string HLERequestContext::Description() const {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1d99bf7a2..9cae5c73d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
}
auto& kernel = system.Kernel();
- auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms);
+ auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
+
+ if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
+ return reserve_result;
+ }
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- const auto result = handle_table.Create(std::move(transfer_mem_handle));
+ const auto result{handle_table.Create(std::move(transfer_mem_handle))};
if (result.Failed()) {
return result.Code();
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index e965b5b04..ad464e03b 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -474,7 +474,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) {
return;
}
- auto& scheduler = Core::System::GetInstance().GlobalScheduler();
+ auto& scheduler = kernel.GlobalScheduler();
if (processor_id >= 0) {
scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
}
@@ -506,7 +506,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
}
void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
- auto& scheduler = Core::System::GetInstance().GlobalScheduler();
+ auto& scheduler = kernel.GlobalScheduler();
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable ||
current_priority >= THREADPRIO_COUNT) {
return;
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
index f0e73f57b..f2d3f8b49 100644
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ b/src/core/hle/kernel/transfer_memory.cpp
@@ -8,15 +8,23 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/result.h"
+#include "core/memory.h"
namespace Kernel {
-TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
-TransferMemory::~TransferMemory() = default;
+TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory)
+ : Object{kernel}, memory{memory} {}
-std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
- u64 size, MemoryPermission permissions) {
- std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)};
+TransferMemory::~TransferMemory() {
+ // Release memory region when transfer memory is destroyed
+ Reset();
+}
+
+std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory,
+ VAddr base_address, u64 size,
+ MemoryPermission permissions) {
+ std::shared_ptr<TransferMemory> transfer_memory{
+ std::make_shared<TransferMemory>(kernel, memory)};
transfer_memory->base_address = base_address;
transfer_memory->memory_size = size;
@@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr
}
const u8* TransferMemory::GetPointer() const {
- return backing_block.get()->data();
+ return memory.GetPointer(base_address);
}
u64 TransferMemory::GetSize() const {
@@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p
return RESULT_SUCCESS;
}
+ResultCode TransferMemory::Reserve() {
+ auto& vm_manager{owner_process->VMManager()};
+ const auto check_range_result{vm_manager.CheckRangeState(
+ base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All,
+ VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None,
+ MemoryAttribute::IpcAndDeviceMapped)};
+
+ if (check_range_result.Failed()) {
+ return check_range_result.Code();
+ }
+
+ auto [state_, permissions_, attribute] = *check_range_result;
+
+ if (const auto result{vm_manager.ReprotectRange(
+ base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))};
+ result.IsError()) {
+ return result;
+ }
+
+ return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
+ attribute | MemoryAttribute::Locked);
+}
+
+ResultCode TransferMemory::Reset() {
+ auto& vm_manager{owner_process->VMManager()};
+ if (const auto result{vm_manager.CheckRangeState(
+ base_address, memory_size,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None,
+ VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked,
+ MemoryAttribute::IpcAndDeviceMapped)};
+ result.Failed()) {
+ return result.Code();
+ }
+
+ if (const auto result{
+ vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)};
+ result.IsError()) {
+ return result;
+ }
+
+ return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
+ MemoryAttribute::None);
+}
+
ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
if (memory_size != size) {
return ERR_INVALID_SIZE;
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index 0a6e15d18..6e388536a 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -11,6 +11,10 @@
union ResultCode;
+namespace Memory {
+class Memory;
+}
+
namespace Kernel {
class KernelCore;
@@ -26,12 +30,13 @@ enum class MemoryPermission : u32;
///
class TransferMemory final : public Object {
public:
- explicit TransferMemory(KernelCore& kernel);
+ explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory);
~TransferMemory() override;
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
- static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
+ static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory,
+ VAddr base_address, u64 size,
MemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
@@ -80,6 +85,14 @@ public:
///
ResultCode UnmapMemory(VAddr address, u64 size);
+ /// Reserves the region to be used for the transfer memory, called after the transfer memory is
+ /// created.
+ ResultCode Reserve();
+
+ /// Resets the region previously used for the transfer memory, called after the transfer memory
+ /// is closed.
+ ResultCode Reset();
+
private:
/// Memory block backing this instance.
std::shared_ptr<PhysicalMemory> backing_block;
@@ -98,6 +111,8 @@ private:
/// Whether or not this transfer memory instance has mapped memory.
bool is_mapped = false;
+
+ Memory::Memory& memory;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 0b3500fce..024c22901 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const {
ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
MemoryAttribute attribute) {
- constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped;
+ constexpr auto ignore_mask =
+ MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked;
constexpr auto attribute_mask = ~ignore_mask;
const auto result = CheckRangeState(
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 850a7ebc3..90b4b006a 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 {
DeviceMapped = 4,
/// Uncached memory
Uncached = 8,
+
+ IpcAndDeviceMapped = LockedForIPC | DeviceMapped,
};
constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
@@ -654,6 +656,35 @@ public:
/// is scheduled.
Common::PageTable page_table{Memory::PAGE_BITS};
+ using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
+
+ /// Checks if an address range adheres to the specified states provided.
+ ///
+ /// @param address The starting address of the address range.
+ /// @param size The size of the address range.
+ /// @param state_mask The memory state mask.
+ /// @param state The state to compare the individual VMA states against,
+ /// which is done in the form of: (vma.state & state_mask) != state.
+ /// @param permission_mask The memory permissions mask.
+ /// @param permissions The permission to compare the individual VMA permissions against,
+ /// which is done in the form of:
+ /// (vma.permission & permission_mask) != permission.
+ /// @param attribute_mask The memory attribute mask.
+ /// @param attribute The memory attributes to compare the individual VMA attributes
+ /// against, which is done in the form of:
+ /// (vma.attributes & attribute_mask) != attribute.
+ /// @param ignore_mask The memory attributes to ignore during the check.
+ ///
+ /// @returns If successful, returns a tuple containing the memory attributes
+ /// (with ignored bits specified by ignore_mask unset), memory permissions, and
+ /// memory state across the memory range.
+ /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
+ ///
+ CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
+ VMAPermission permission_mask, VMAPermission permissions,
+ MemoryAttribute attribute_mask, MemoryAttribute attribute,
+ MemoryAttribute ignore_mask) const;
+
private:
using VMAIter = VMAMap::iterator;
@@ -707,35 +738,6 @@ private:
/// Clears out the page table
void ClearPageTable();
- using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
-
- /// Checks if an address range adheres to the specified states provided.
- ///
- /// @param address The starting address of the address range.
- /// @param size The size of the address range.
- /// @param state_mask The memory state mask.
- /// @param state The state to compare the individual VMA states against,
- /// which is done in the form of: (vma.state & state_mask) != state.
- /// @param permission_mask The memory permissions mask.
- /// @param permissions The permission to compare the individual VMA permissions against,
- /// which is done in the form of:
- /// (vma.permission & permission_mask) != permission.
- /// @param attribute_mask The memory attribute mask.
- /// @param attribute The memory attributes to compare the individual VMA attributes
- /// against, which is done in the form of:
- /// (vma.attributes & attribute_mask) != attribute.
- /// @param ignore_mask The memory attributes to ignore during the check.
- ///
- /// @returns If successful, returns a tuple containing the memory attributes
- /// (with ignored bits specified by ignore_mask unset), memory permissions, and
- /// memory state across the memory range.
- /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
- ///
- CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
- VMAPermission permission_mask, VMAPermission permissions,
- MemoryAttribute attribute_mask, MemoryAttribute attribute,
- MemoryAttribute ignore_mask) const;
-
/// Gets the amount of memory currently mapped (state != Unmapped) in a range.
ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const;
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index a0c806e8f..1838260fd 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -50,17 +50,8 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
if (ShouldWait(thread.get()))
continue;
- // A thread is ready to run if it's either in ThreadStatus::WaitSynch
- // and the rest of the objects it is waiting on are ready.
- bool ready_to_run = true;
- if (thread_status == ThreadStatus::WaitSynch) {
- ready_to_run = thread->AllWaitObjectsReady();
- }
-
- if (ready_to_run) {
- candidate = thread.get();
- candidate_priority = thread->GetPriority();
- }
+ candidate = thread.get();
+ candidate_priority = thread->GetPriority();
}
return SharedFrom(candidate);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 95aa5d23d..cc978713b 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
apm_sys->SetCpuBoostMode(ctx);
}
-IStorage::IStorage(std::vector<u8> buffer)
- : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
+IStorageImpl::~IStorageImpl() = default;
+
+class StorageDataImpl final : public IStorageImpl {
+public:
+ explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {}
+
+ std::vector<u8>& GetData() override {
+ return buffer;
+ }
+
+ const std::vector<u8>& GetData() const override {
+ return buffer;
+ }
+
+ std::size_t GetSize() const override {
+ return buffer.size();
+ }
+
+private:
+ std::vector<u8> buffer;
+};
+
+IStorage::IStorage(std::vector<u8>&& buffer)
+ : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} {
+ Register();
+}
+
+void IStorage::Register() {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
@@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer)
IStorage::~IStorage() = default;
-const std::vector<u8>& IStorage::GetData() const {
- return buffer;
+void IStorage::Open(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorageAccessor>(*this);
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
@@ -816,7 +847,7 @@ private:
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -825,26 +856,25 @@ private:
void PopOutData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
const auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) {
LOG_ERROR(Service_AM,
"storage is a nullptr. There is no data in the current normal channel");
-
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
}
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IStorage>(std::move(*storage));
+ rb.PushIpcInterface<IStorage>(std::move(storage));
}
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>());
ASSERT(applet->IsInitialized());
applet->ExecuteInteractive();
@@ -857,19 +887,18 @@ private:
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
const auto storage = applet->GetBroker().PopInteractiveDataToGame();
if (storage == nullptr) {
LOG_ERROR(Service_AM,
"storage is a nullptr. There is no data in the current interactive channel");
-
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
}
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IStorage>(std::move(*storage));
+ rb.PushIpcInterface<IStorage>(std::move(storage));
}
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
@@ -891,15 +920,6 @@ private:
std::shared_ptr<Applets::Applet> applet;
};
-void IStorage::Open(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_AM, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IStorageAccessor>(*this);
-}
-
IStorageAccessor::IStorageAccessor(IStorage& storage)
: ServiceFramework("IStorageAccessor"), backing(storage) {
// clang-format off
@@ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(backing.buffer.size()));
+ rb.Push(static_cast<u64>(backing.GetSize()));
}
void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
@@ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
- if (data.size() > backing.buffer.size() - offset) {
+ if (data.size() > backing.GetSize() - offset) {
LOG_ERROR(Service_AM,
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
- backing.buffer.size(), data.size(), offset);
+ backing.GetSize(), data.size(), offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
- std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
+ std::memcpy(backing.GetData().data() + offset, data.data(), data.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
- if (size > backing.buffer.size() - offset) {
+ if (size > backing.GetSize() - offset) {
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
- backing.buffer.size(), size, offset);
+ backing.GetSize(), size, offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
- ctx.WriteBuffer(backing.buffer.data() + offset, size);
+ ctx.WriteBuffer(backing.GetData().data() + offset, size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rp.SetCurrentOffset(3);
const auto handle{rp.Pop<Kernel::Handle>()};
- const auto transfer_mem =
+ auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
@@ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
+ rb.PushIpcInterface<IStorage>(std::move(memory));
}
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
@@ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
- const auto data =
- backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
-
+ auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::IStorage>(*data);
+ rb.PushIpcInterface<IStorage>(std::move(*data));
launch_popped_application_specific = true;
return;
}
@@ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
std::memcpy(buffer.data(), &params, buffer.size());
- rb.PushIpcInterface<AM::IStorage>(buffer);
+ rb.PushIpcInterface<IStorage>(std::move(buffer));
launch_popped_account_preselect = true;
return;
}
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 448817be9..0b9a4332d 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -12,7 +12,8 @@
namespace Kernel {
class KernelCore;
-}
+class TransferMemory;
+} // namespace Kernel
namespace Service::NVFlinger {
class NVFlinger;
@@ -188,19 +189,36 @@ private:
std::shared_ptr<AppletMessageQueue> msg_queue;
};
+class IStorageImpl {
+public:
+ virtual ~IStorageImpl();
+ virtual std::vector<u8>& GetData() = 0;
+ virtual const std::vector<u8>& GetData() const = 0;
+ virtual std::size_t GetSize() const = 0;
+};
+
class IStorage final : public ServiceFramework<IStorage> {
public:
- explicit IStorage(std::vector<u8> buffer);
+ explicit IStorage(std::vector<u8>&& buffer);
~IStorage() override;
- const std::vector<u8>& GetData() const;
+ std::vector<u8>& GetData() {
+ return impl->GetData();
+ }
+
+ const std::vector<u8>& GetData() const {
+ return impl->GetData();
+ }
+
+ std::size_t GetSize() const {
+ return impl->GetSize();
+ }
private:
+ void Register();
void Open(Kernel::HLERequestContext& ctx);
- std::vector<u8> buffer;
-
- friend class IStorageAccessor;
+ std::shared_ptr<IStorageImpl> impl;
};
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 92f995f8f..c3261f3e6 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -50,16 +50,17 @@ AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() co
return {std::move(out_normal), std::move(out_interactive)};
}
-std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
+std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
if (out_channel.empty())
return nullptr;
auto out = std::move(out_channel.front());
out_channel.pop_front();
+ pop_out_data_event.writable->Clear();
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
+std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
if (in_channel.empty())
return nullptr;
@@ -68,16 +69,17 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
+std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
if (out_interactive_channel.empty())
return nullptr;
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
+ pop_interactive_out_data_event.writable->Clear();
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
+std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
if (in_interactive_channel.empty())
return nullptr;
@@ -86,21 +88,21 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
return out;
}
-void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
- in_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
+ in_channel.emplace_back(std::move(storage));
}
-void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
- out_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
+ out_channel.emplace_back(std::move(storage));
pop_out_data_event.writable->Signal();
}
-void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
- in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
+ in_interactive_channel.emplace_back(std::move(storage));
}
-void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
- out_interactive_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
+ out_interactive_channel.emplace_back(std::move(storage));
pop_interactive_out_data_event.writable->Signal();
}
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 16e61fc6f..e75be86a2 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -72,17 +72,17 @@ public:
// Retrieves but does not pop the data sent to applet.
RawChannelData PeekDataToAppletForDebug() const;
- std::unique_ptr<IStorage> PopNormalDataToGame();
- std::unique_ptr<IStorage> PopNormalDataToApplet();
+ std::shared_ptr<IStorage> PopNormalDataToGame();
+ std::shared_ptr<IStorage> PopNormalDataToApplet();
- std::unique_ptr<IStorage> PopInteractiveDataToGame();
- std::unique_ptr<IStorage> PopInteractiveDataToApplet();
+ std::shared_ptr<IStorage> PopInteractiveDataToGame();
+ std::shared_ptr<IStorage> PopInteractiveDataToApplet();
- void PushNormalDataFromGame(IStorage storage);
- void PushNormalDataFromApplet(IStorage storage);
+ void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
+ void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
- void PushInteractiveDataFromGame(IStorage storage);
- void PushInteractiveDataFromApplet(IStorage storage);
+ void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
+ void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
void SignalStateChanged() const;
@@ -94,16 +94,16 @@ private:
// Queues are named from applet's perspective
// PopNormalDataToApplet and PushNormalDataFromGame
- std::deque<std::unique_ptr<IStorage>> in_channel;
+ std::deque<std::shared_ptr<IStorage>> in_channel;
// PopNormalDataToGame and PushNormalDataFromApplet
- std::deque<std::unique_ptr<IStorage>> out_channel;
+ std::deque<std::shared_ptr<IStorage>> out_channel;
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
- std::deque<std::unique_ptr<IStorage>> in_interactive_channel;
+ std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
- std::deque<std::unique_ptr<IStorage>> out_interactive_channel;
+ std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
Kernel::EventPair state_changed_event;
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index eab0d42c9..f12fd7f89 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -186,7 +186,7 @@ void Error::Execute() {
void Error::DisplayCompleted() {
complete = true;
- broker.PushNormalDataFromApplet(IStorage{{}});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
broker.SignalStateChanged();
}
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 328438a1d..104501ac5 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -20,7 +20,7 @@ namespace Service::AM::Applets {
constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
- std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
+ std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
@@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) {
std::vector<u8> out(sizeof(Return));
std::memcpy(out.data(), &return_, sizeof(Return));
- broker.PushNormalDataFromApplet(IStorage{out});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out)));
broker.SignalStateChanged();
}
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
}
void PhotoViewer::ViewFinished() {
- broker.PushNormalDataFromApplet(IStorage{{}});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
broker.SignalStateChanged();
}
@@ -234,8 +234,8 @@ void StubApplet::ExecuteInteractive() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "ExecuteInteractive");
- broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
- broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
broker.SignalStateChanged();
}
@@ -243,8 +243,8 @@ void StubApplet::Execute() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "Execute");
- broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
- broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
broker.SignalStateChanged();
}
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 3eba696ca..70cc23552 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() {
void ProfileSelect::Execute() {
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
return;
}
@@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
std::memcpy(final_data.data(), &output, final_data.size());
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
broker.SignalStateChanged();
}
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 748559cd0..54e63c138 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() {
void SoftwareKeyboard::Execute() {
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
+ broker.SignalStateChanged();
return;
}
@@ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
if (config.utf_8) {
- const u64 size = text->size() + 8;
+ const u64 size = text->size() + sizeof(u64);
const auto new_text = Common::UTF16ToUTF8(*text);
std::memcpy(output_sub.data(), &size, sizeof(u64));
@@ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::memcpy(output_main.data() + 4, new_text.data(),
std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
} else {
- const u64 size = text->size() * 2 + 8;
+ const u64 size = text->size() * 2 + sizeof(u64);
std::memcpy(output_sub.data(), &size, sizeof(u64));
std::memcpy(output_sub.data() + 8, text->data(),
std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
@@ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
final_data = output_main;
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main)));
broker.SignalStateChanged();
} else {
- broker.PushInteractiveDataFromApplet(IStorage{output_sub});
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub)));
}
} else {
output_main[0] = 1;
complete = true;
- broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main)));
broker.SignalStateChanged();
}
}
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 5546ef6e8..12443c910 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -284,7 +284,7 @@ void WebBrowser::Finalize() {
std::vector<u8> data(sizeof(WebCommonReturnValue));
std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
- broker.PushNormalDataFromApplet(IStorage{data});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data)));
broker.SignalStateChanged();
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index cb839e4a2..d19513cbb 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -170,8 +170,10 @@ public:
{3, nullptr, "SetContextForMultiStream"},
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
{5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
- {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
- {7, nullptr, "DecodeInterleavedForMultiStream"},
+ {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
+ {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
+ {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
+ {9, nullptr, "DecodeInterleavedForMultiStream"},
};
// clang-format on
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 6f5ea095a..def3410cc 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -117,13 +117,13 @@ bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
}
bool NullBackend::Clear(u64 title_id) {
- LOG_DEBUG(Service_BCAT, "called, title_id={:016X}");
+ LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
return true;
}
void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
- LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id,
+ LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
Common::HexToString(passphrase));
}
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 55d62fc5e..e6811d5b5 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -420,7 +420,7 @@ public:
return;
}
- IFile file(result.Unwrap());
+ auto file = std::make_shared<IFile>(result.Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -445,7 +445,7 @@ public:
return;
}
- IDirectory directory(result.Unwrap());
+ auto directory = std::make_shared<IDirectory>(result.Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -794,8 +794,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
- SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
+ auto filesystem = std::make_shared<IFileSystem>(
+ fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -846,7 +846,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
id = FileSys::StorageId::NandSystem;
}
- IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
+ auto filesystem =
+ std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -898,7 +899,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
return;
}
- IStorage storage(std::move(romfs.Unwrap()));
+ auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -937,7 +938,8 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
FileSys::PatchManager pm{title_id};
- IStorage storage(pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
+ auto storage = std::make_shared<IStorage>(
+ pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 5eb26caf8..8f1be0e48 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -50,16 +50,16 @@ private:
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
- const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = ctx.ReadBuffer(1);
+ std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
+ if (Type == Core::Reporter::PlayReportType::New) {
+ data.emplace_back(ctx.ReadBuffer(1));
+ }
- LOG_DEBUG(Service_PREPO,
- "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}",
- static_cast<u8>(Type), process_id, data1.size(), data2.size());
+ LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}",
+ static_cast<u8>(Type), process_id, data[0].size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
- process_id);
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -70,19 +70,19 @@ private:
IPC::RequestParser rp{ctx};
const auto user_id = rp.PopRaw<u128>();
const auto process_id = rp.PopRaw<u64>();
-
- const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = ctx.ReadBuffer(1);
+ std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
+ if (Type == Core::Reporter::PlayReportType::New) {
+ data.emplace_back(ctx.ReadBuffer(1));
+ }
LOG_DEBUG(
Service_PREPO,
- "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, "
- "data2_size={:016X}",
- static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size());
+ "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}",
+ static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
- process_id, user_id);
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id,
+ user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7cea146f0..0b3e8749b 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -9,6 +9,7 @@
#include "core/core_timing.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/shader_type.h"
+#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/textures/texture.h"
@@ -519,61 +520,63 @@ void Maxwell3D::ProcessFirmwareCall4() {
regs.reg_array[0xd00] = 1;
}
-void Maxwell3D::ProcessQueryGet() {
+void Maxwell3D::StampQueryResult(u64 payload, bool long_query) {
+ struct LongQueryResult {
+ u64_le value;
+ u64_le timestamp;
+ };
+ static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size");
const GPUVAddr sequence_address{regs.query.QueryAddress()};
- // Since the sequence address is given as a GPU VAddr, we have to convert it to an application
- // VAddr before writing.
+ if (long_query) {
+ // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
+ // GPU, this command may actually take a while to complete in real hardware due to GPU
+ // wait queues.
+ LongQueryResult query_result{payload, system.GPU().GetTicks()};
+ memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
+ } else {
+ memory_manager.Write<u32>(sequence_address, static_cast<u32>(payload));
+ }
+}
+void Maxwell3D::ProcessQueryGet() {
// TODO(Subv): Support the other query units.
ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop,
"Units other than CROP are unimplemented");
- u64 result = 0;
-
- // TODO(Subv): Support the other query variables
- switch (regs.query.query_get.select) {
- case Regs::QuerySelect::Zero:
- // This seems to actually write the query sequence to the query address.
- result = regs.query.query_sequence;
+ switch (regs.query.query_get.operation) {
+ case Regs::QueryOperation::Release: {
+ const u64 result = regs.query.query_sequence;
+ StampQueryResult(result, regs.query.query_get.short_query == 0);
break;
- default:
- result = 1;
- UNIMPLEMENTED_MSG("Unimplemented query select type {}",
- static_cast<u32>(regs.query.query_get.select.Value()));
}
-
- // TODO(Subv): Research and implement how query sync conditions work.
-
- struct LongQueryResult {
- u64_le value;
- u64_le timestamp;
- };
- static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size");
-
- switch (regs.query.query_get.mode) {
- case Regs::QueryMode::Write:
- case Regs::QueryMode::Write2: {
- u32 sequence = regs.query.query_sequence;
- if (regs.query.query_get.short_query) {
- // Write the current query sequence to the sequence address.
- // TODO(Subv): Find out what happens if you use a long query type but mark it as a short
- // query.
- memory_manager.Write<u32>(sequence_address, sequence);
- } else {
- // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
- // GPU, this command may actually take a while to complete in real hardware due to GPU
- // wait queues.
- LongQueryResult query_result{};
- query_result.value = result;
- // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming
- query_result.timestamp = system.CoreTiming().GetTicks();
- memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
+ case Regs::QueryOperation::Acquire: {
+ // Todo(Blinkhawk): Under this operation, the GPU waits for the CPU
+ // to write a value that matches the current payload.
+ UNIMPLEMENTED_MSG("Unimplemented query operation ACQUIRE");
+ break;
+ }
+ case Regs::QueryOperation::Counter: {
+ u64 result{};
+ switch (regs.query.query_get.select) {
+ case Regs::QuerySelect::Zero:
+ result = 0;
+ break;
+ default:
+ result = 1;
+ UNIMPLEMENTED_MSG("Unimplemented query select type {}",
+ static_cast<u32>(regs.query.query_get.select.Value()));
}
+ StampQueryResult(result, regs.query.query_get.short_query == 0);
+ break;
+ }
+ case Regs::QueryOperation::Trap: {
+ UNIMPLEMENTED_MSG("Unimplemented query operation TRAP");
+ break;
+ }
+ default: {
+ UNIMPLEMENTED_MSG("Unknown query operation");
break;
}
- default:
- UNIMPLEMENTED_MSG("Query mode {} not implemented",
- static_cast<u32>(regs.query.query_get.mode.Value()));
}
}
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 8808bbf76..0a2af54e5 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -71,12 +71,11 @@ public:
static constexpr std::size_t MaxConstBuffers = 18;
static constexpr std::size_t MaxConstBufferSize = 0x10000;
- enum class QueryMode : u32 {
- Write = 0,
- Sync = 1,
- // TODO(Subv): It is currently unknown what the difference between method 2 and method 0
- // is.
- Write2 = 2,
+ enum class QueryOperation : u32 {
+ Release = 0,
+ Acquire = 1,
+ Counter = 2,
+ Trap = 3,
};
enum class QueryUnit : u32 {
@@ -704,8 +703,8 @@ public:
INSERT_UNION_PADDING_WORDS(0x15);
s32 stencil_back_func_ref;
- u32 stencil_back_func_mask;
u32 stencil_back_mask;
+ u32 stencil_back_func_mask;
INSERT_UNION_PADDING_WORDS(0xC);
@@ -862,7 +861,11 @@ public:
float point_size;
- INSERT_UNION_PADDING_WORDS(0x7);
+ INSERT_UNION_PADDING_WORDS(0x1);
+
+ u32 point_sprite_enable;
+
+ INSERT_UNION_PADDING_WORDS(0x5);
u32 zeta_enable;
@@ -1077,7 +1080,7 @@ public:
u32 query_sequence;
union {
u32 raw;
- BitField<0, 2, QueryMode> mode;
+ BitField<0, 2, QueryOperation> operation;
BitField<4, 1, u32> fence;
BitField<12, 4, QueryUnit> unit;
BitField<16, 1, QuerySyncCondition> sync_cond;
@@ -1409,6 +1412,9 @@ private:
/// Handles a write to the QUERY_GET register.
void ProcessQueryGet();
+ // Writes the query result accordingly
+ void StampQueryResult(u64 payload, bool long_query);
+
// Handles Conditional Rendering
void ProcessQueryCondition();
@@ -1458,8 +1464,8 @@ ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
ASSERT_REG_POSITION(patch_vertices, 0x373);
ASSERT_REG_POSITION(scissor_test, 0x380);
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
-ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D6);
-ASSERT_REG_POSITION(stencil_back_mask, 0x3D7);
+ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
+ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
ASSERT_REG_POSITION(color_mask_common, 0x3E4);
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
ASSERT_REG_POSITION(depth_bounds, 0x3E7);
@@ -1494,6 +1500,7 @@ ASSERT_REG_POSITION(vb_element_base, 0x50D);
ASSERT_REG_POSITION(vb_base_instance, 0x50E);
ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
ASSERT_REG_POSITION(point_size, 0x546);
+ASSERT_REG_POSITION(point_sprite_enable, 0x548);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(multisample_control, 0x54F);
ASSERT_REG_POSITION(condition, 0x554);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 955f981bd..c9bc83cd7 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -624,6 +624,19 @@ enum class ShuffleOperation : u64 {
Bfly = 3, // shuffleXorNV
};
+enum class ShfType : u64 {
+ Bits32 = 0,
+ U64 = 2,
+ S64 = 3,
+};
+
+enum class ShfXmode : u64 {
+ None = 0,
+ HI = 1,
+ X = 2,
+ XHI = 3,
+};
+
union Instruction {
constexpr Instruction& operator=(const Instruction& instr) {
value = instr.value;
@@ -776,6 +789,13 @@ union Instruction {
} shr;
union {
+ BitField<37, 2, ShfType> type;
+ BitField<48, 2, ShfXmode> xmode;
+ BitField<50, 1, u64> wrap;
+ BitField<20, 6, u64> immediate;
+ } shf;
+
+ union {
BitField<39, 5, u64> shift_amount;
BitField<48, 1, u64> negate_b;
BitField<49, 1, u64> negate_a;
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index b9c5c41a2..4419ab735 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -6,6 +6,7 @@
#include "common/microprofile.h"
#include "core/core.h"
#include "core/core_timing.h"
+#include "core/core_timing_util.h"
#include "core/memory.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
@@ -23,7 +24,7 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
: system{system}, renderer{renderer}, is_async{is_async} {
auto& rasterizer{renderer.Rasterizer()};
- memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
+ memory_manager = std::make_unique<Tegra::MemoryManager>(system);
dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
@@ -122,6 +123,19 @@ bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
return true;
}
+u64 GPU::GetTicks() const {
+ // This values were reversed engineered by fincs from NVN
+ // The gpu clock is reported in units of 385/625 nanoseconds
+ constexpr u64 gpu_ticks_num = 384;
+ constexpr u64 gpu_ticks_den = 625;
+
+ const u64 cpu_ticks = system.CoreTiming().GetTicks();
+ const u64 nanoseconds = Core::Timing::CyclesToNs(cpu_ticks).count();
+ const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
+ const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
+ return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
+}
+
void GPU::FlushCommands() {
renderer.Rasterizer().FlushCommands();
}
@@ -340,7 +354,7 @@ void GPU::ProcessSemaphoreTriggerMethod() {
block.sequence = regs.semaphore_sequence;
// TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
// CoreTiming
- block.timestamp = system.CoreTiming().GetTicks();
+ block.timestamp = GetTicks();
memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
sizeof(block));
} else {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b648317bb..07727210c 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -192,6 +192,8 @@ public:
bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
+ u64 GetTicks() const;
+
std::unique_lock<std::mutex> LockSync() {
return std::unique_lock{sync_mutex};
}
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 08dc96bb3..882e2d9c7 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -86,7 +86,7 @@ struct CommandDataContainer {
struct SynchState final {
std::atomic_bool is_running{true};
- using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
+ using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
CommandQueue queue;
u64 last_fence{};
std::atomic<u64> signaled_fence{};
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 11848fbce..f1d50be3e 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -9,13 +9,12 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
+#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
-#include "video_core/rasterizer_interface.h"
namespace Tegra {
-MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
- : rasterizer{rasterizer}, system{system} {
+MemoryManager::MemoryManager(Core::System& system) : system{system} {
std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
std::fill(page_table.attributes.begin(), page_table.attributes.end(),
Common::PageType::Unmapped);
@@ -84,7 +83,8 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
const auto cpu_addr = GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
- rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
+ system.GPU().FlushAndInvalidateRegion(cache_addr, aligned_size);
+
UnmapRange(gpu_addr, aligned_size);
ASSERT(system.CurrentProcess()
->VMManager()
@@ -242,7 +242,7 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::s
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
- rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
+ system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
std::memcpy(dest_buffer, src_ptr, copy_amount);
break;
}
@@ -292,7 +292,7 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
u8* dest_ptr{page_table.pointers[page_index] + page_offset};
- rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
+ system.GPU().InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
std::memcpy(dest_ptr, src_buffer, copy_amount);
break;
}
@@ -340,7 +340,7 @@ void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
- rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
+ system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
WriteBlock(dest_addr, src_ptr, copy_amount);
break;
}
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index aea010087..393447eb4 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -10,10 +10,6 @@
#include "common/common_types.h"
#include "common/page_table.h"
-namespace VideoCore {
-class RasterizerInterface;
-}
-
namespace Core {
class System;
}
@@ -51,7 +47,7 @@ struct VirtualMemoryArea {
class MemoryManager final {
public:
- explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
+ explicit MemoryManager(Core::System& system);
~MemoryManager();
GPUVAddr AllocateSpace(u64 size, u64 align);
@@ -176,7 +172,6 @@ private:
Common::PageTable page_table{page_bits};
VMAMap vma_map;
- VideoCore::RasterizerInterface& rasterizer;
Core::System& system;
};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 362942e09..b0eb14c8b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -248,9 +248,6 @@ void RasterizerOpenGL::SetupVertexInstances(GLuint vao) {
}
GLintptr RasterizerOpenGL::SetupIndexBuffer() {
- if (accelerate_draw != AccelDraw::Indexed) {
- return 0;
- }
MICROPROFILE_SCOPE(OpenGL_Index);
const auto& regs = system.GPU().Maxwell3D().regs;
const std::size_t size = CalculateIndexBufferSize();
@@ -546,7 +543,8 @@ void RasterizerOpenGL::Clear() {
}
}
-void RasterizerOpenGL::DrawPrelude() {
+void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
auto& gpu = system.GPU().Maxwell3D();
SyncRasterizeEnable(state);
@@ -567,9 +565,6 @@ void RasterizerOpenGL::DrawPrelude() {
buffer_cache.Acquire();
- // Draw the vertex batch
- const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
-
std::size_t buffer_size = CalculateVertexArraysSize();
// Add space for index buffer
@@ -596,7 +591,11 @@ void RasterizerOpenGL::DrawPrelude() {
// Upload vertex and index data.
SetupVertexBuffer(vao);
SetupVertexInstances(vao);
- index_buffer_offset = SetupIndexBuffer();
+
+ GLintptr index_buffer_offset;
+ if (is_indexed) {
+ index_buffer_offset = SetupIndexBuffer();
+ }
// Prepare packed bindings.
bind_ubo_pushbuffer.Setup();
@@ -630,6 +629,7 @@ void RasterizerOpenGL::DrawPrelude() {
// As all cached buffers are invalidated, we need to recheck their state.
gpu.dirty.ResetVertexArrays();
}
+ gpu.dirty.memory_general = false;
shader_program_manager->ApplyTo(state);
state.Apply();
@@ -637,106 +637,33 @@ void RasterizerOpenGL::DrawPrelude() {
if (texture_cache.TextureBarrier()) {
glTextureBarrier();
}
-}
-
-struct DrawParams {
- bool is_indexed{};
- bool is_instanced{};
- GLenum primitive_mode{};
- GLint count{};
- GLint base_vertex{};
-
- // Indexed settings
- GLenum index_format{};
- GLintptr index_buffer_offset{};
-
- // Instanced setting
- GLint num_instances{};
- GLint base_instance{};
-
- void DispatchDraw() {
- if (is_indexed) {
- const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
- if (is_instanced) {
- glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
- index_buffer_ptr, num_instances,
- base_vertex, base_instance);
- } else {
- glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
- base_vertex);
- }
- } else {
- if (is_instanced) {
- glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances,
- base_instance);
- } else {
- glDrawArrays(primitive_mode, base_vertex, count);
- }
- }
- }
-};
-
-bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
- accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
- MICROPROFILE_SCOPE(OpenGL_Drawing);
-
- DrawPrelude();
-
- auto& maxwell3d = system.GPU().Maxwell3D();
- const auto& regs = maxwell3d.regs;
- const auto current_instance = maxwell3d.state.current_instance;
- DrawParams draw_call{};
- draw_call.is_indexed = is_indexed;
- draw_call.num_instances = static_cast<GLint>(1);
- draw_call.base_instance = static_cast<GLint>(current_instance);
- draw_call.is_instanced = current_instance > 0;
- draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
- if (draw_call.is_indexed) {
- draw_call.count = static_cast<GLint>(regs.index_array.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
- draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
- draw_call.index_buffer_offset = index_buffer_offset;
+ const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance);
+ const GLsizei num_instances =
+ static_cast<GLsizei>(is_instanced ? gpu.mme_draw.instance_count : 1);
+ if (is_indexed) {
+ const GLenum index_format = MaxwellToGL::IndexFormat(gpu.regs.index_array.format);
+ const GLint base_vertex = static_cast<GLint>(gpu.regs.vb_element_base);
+ const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.index_array.count);
+ glDrawElementsInstancedBaseVertexBaseInstance(
+ primitive_mode, num_vertices, index_format,
+ reinterpret_cast<const void*>(index_buffer_offset), num_instances, base_vertex,
+ base_instance);
} else {
- draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
+ const GLint base_vertex = static_cast<GLint>(gpu.regs.vertex_buffer.first);
+ const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.vertex_buffer.count);
+ glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, num_vertices, num_instances,
+ base_instance);
}
- draw_call.DispatchDraw();
+}
- maxwell3d.dirty.memory_general = false;
- accelerate_draw = AccelDraw::Disabled;
+bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
+ Draw(is_indexed, false);
return true;
}
bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) {
- accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
-
- MICROPROFILE_SCOPE(OpenGL_Drawing);
-
- DrawPrelude();
-
- auto& maxwell3d = system.GPU().Maxwell3D();
- const auto& regs = maxwell3d.regs;
- const auto& draw_setup = maxwell3d.mme_draw;
- DrawParams draw_call{};
- draw_call.is_indexed = is_indexed;
- draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count);
- draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance);
- draw_call.is_instanced = draw_setup.instance_count > 1;
- draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
- if (draw_call.is_indexed) {
- draw_call.count = static_cast<GLint>(regs.index_array.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
- draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
- draw_call.index_buffer_offset = index_buffer_offset;
- } else {
- draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
- }
- draw_call.DispatchDraw();
-
- maxwell3d.dirty.memory_general = false;
- accelerate_draw = AccelDraw::Disabled;
+ Draw(is_indexed, true);
return true;
}
@@ -1293,6 +1220,7 @@ void RasterizerOpenGL::SyncPointState() {
// Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
// in OpenGL).
state.point.program_control = regs.vp_point_size.enable != 0;
+ state.point.sprite = regs.point_sprite_enable != 0;
state.point.size = std::max(1.0f, regs.point_size);
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6a27cf497..0501f3828 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -103,7 +103,7 @@ private:
std::size_t size);
/// Syncs all the state, shaders, render targets and textures setting before a draw call.
- void DrawPrelude();
+ void Draw(bool is_indexed, bool is_instanced);
/// Configures the current textures to use for the draw command.
void SetupDrawTextures(std::size_t stage_index, const Shader& shader);
@@ -220,12 +220,7 @@ private:
GLintptr SetupIndexBuffer();
- GLintptr index_buffer_offset;
-
void SetupShaders(GLenum primitive_mode);
-
- enum class AccelDraw { Disabled, Arrays, Indexed };
- AccelDraw accelerate_draw = AccelDraw::Disabled;
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index cc185e9e1..ab1f7983c 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -128,6 +128,7 @@ void OpenGLState::ApplyClipDistances() {
void OpenGLState::ApplyPointSize() {
Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control);
+ Enable(GL_POINT_SPRITE, cur_state.point.sprite, point.sprite);
if (UpdateValue(cur_state.point.size, point.size)) {
glPointSize(point.size);
}
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 678e5cd89..4953eeda2 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -132,6 +132,7 @@ public:
struct {
bool program_control = false; // GL_PROGRAM_POINT_SIZE
+ bool sprite = false; // GL_POINT_SPRITE
GLfloat size = 1.0f; // GL_POINT_SIZE
} point;
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index ea4f35663..7ed505628 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -47,8 +47,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_UNSIGNED_INT_2_10_10_10_REV;
default:
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
- UNREACHABLE();
+ LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
return {};
}
case Maxwell::VertexAttribute::Type::SignedInt:
@@ -72,8 +71,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_INT_2_10_10_10_REV;
default:
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
- UNREACHABLE();
+ LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
return {};
}
case Maxwell::VertexAttribute::Type::Float:
@@ -89,13 +87,19 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return GL_FLOAT;
default:
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
- UNREACHABLE();
+ LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
+ return {};
+ }
+ case Maxwell::VertexAttribute::Type::UnsignedScaled:
+ switch (attrib.size) {
+ case Maxwell::VertexAttribute::Size::Size_8_8:
+ return GL_UNSIGNED_BYTE;
+ default:
+ LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
return {};
}
default:
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
- UNREACHABLE();
+ LOG_ERROR(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
return {};
}
}
diff --git a/src/video_core/shader/decode/shift.cpp b/src/video_core/shader/decode/shift.cpp
index d419e9c45..3b391d3e6 100644
--- a/src/video_core/shader/decode/shift.cpp
+++ b/src/video_core/shader/decode/shift.cpp
@@ -10,8 +10,80 @@
namespace VideoCommon::Shader {
+using std::move;
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
+using Tegra::Shader::ShfType;
+using Tegra::Shader::ShfXmode;
+
+namespace {
+
+Node IsFull(Node shift) {
+ return Operation(OperationCode::LogicalIEqual, move(shift), Immediate(32));
+}
+
+Node Shift(OperationCode opcode, Node value, Node shift) {
+ Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32));
+ Node shifted = Operation(opcode, move(value), shift);
+ return Operation(OperationCode::Select, IsFull(move(shift)), Immediate(0), move(shifted));
+}
+
+Node ClampShift(Node shift, s32 size = 32) {
+ shift = Operation(OperationCode::IMax, move(shift), Immediate(0));
+ return Operation(OperationCode::IMin, move(shift), Immediate(size));
+}
+
+Node WrapShift(Node shift, s32 size = 32) {
+ return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1));
+}
+
+Node ShiftRight(Node low, Node high, Node shift, Node low_shift, ShfType type) {
+ // These values are used when the shift value is less than 32
+ Node less_low = Shift(OperationCode::ILogicalShiftRight, low, shift);
+ Node less_high = Shift(OperationCode::ILogicalShiftLeft, high, low_shift);
+ Node less = Operation(OperationCode::IBitwiseOr, move(less_high), move(less_low));
+
+ if (type == ShfType::Bits32) {
+ // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
+ return Operation(OperationCode::Select, IsFull(move(shift)), move(high), move(less));
+ }
+
+ // And these when it's larger than or 32
+ const bool is_signed = type == ShfType::S64;
+ const auto opcode = SignedToUnsignedCode(OperationCode::IArithmeticShiftRight, is_signed);
+ Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
+ Node greater = Shift(opcode, high, move(reduced));
+
+ Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
+ Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
+
+ Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
+ return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
+}
+
+Node ShiftLeft(Node low, Node high, Node shift, Node low_shift, ShfType type) {
+ // These values are used when the shift value is less than 32
+ Node less_low = Operation(OperationCode::ILogicalShiftRight, low, low_shift);
+ Node less_high = Operation(OperationCode::ILogicalShiftLeft, high, shift);
+ Node less = Operation(OperationCode::IBitwiseOr, move(less_low), move(less_high));
+
+ if (type == ShfType::Bits32) {
+ // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
+ return Operation(OperationCode::Select, IsFull(move(shift)), move(low), move(less));
+ }
+
+ // And these when it's larger than or 32
+ Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
+ Node greater = Shift(OperationCode::ILogicalShiftLeft, move(low), move(reduced));
+
+ Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
+ Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
+
+ Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
+ return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
+}
+
+} // Anonymous namespace
u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
@@ -28,29 +100,48 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
}
}();
- switch (opcode->get().GetId()) {
+ switch (const auto opid = opcode->get().GetId(); opid) {
case OpCode::Id::SHR_C:
case OpCode::Id::SHR_R:
case OpCode::Id::SHR_IMM: {
- if (instr.shr.wrap) {
- op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
- } else {
- op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
- op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
- }
+ op_b = instr.shr.wrap ? WrapShift(move(op_b)) : ClampShift(move(op_b));
Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
- std::move(op_a), std::move(op_b));
+ move(op_a), move(op_b));
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
- SetRegister(bb, instr.gpr0, std::move(value));
+ SetRegister(bb, instr.gpr0, move(value));
break;
}
case OpCode::Id::SHL_C:
case OpCode::Id::SHL_R:
case OpCode::Id::SHL_IMM: {
- const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
+ Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
- SetRegister(bb, instr.gpr0, value);
+ SetRegister(bb, instr.gpr0, move(value));
+ break;
+ }
+ case OpCode::Id::SHF_RIGHT_R:
+ case OpCode::Id::SHF_RIGHT_IMM:
+ case OpCode::Id::SHF_LEFT_R:
+ case OpCode::Id::SHF_LEFT_IMM: {
+ UNIMPLEMENTED_IF(instr.generates_cc);
+ UNIMPLEMENTED_IF_MSG(instr.shf.xmode != ShfXmode::None, "xmode={}",
+ static_cast<int>(instr.shf.xmode.Value()));
+
+ if (instr.is_b_imm) {
+ op_b = Immediate(static_cast<u32>(instr.shf.immediate));
+ }
+ const s32 size = instr.shf.type == ShfType::Bits32 ? 32 : 64;
+ Node shift = instr.shf.wrap ? WrapShift(move(op_b), size) : ClampShift(move(op_b), size);
+
+ Node negated_shift = Operation(OperationCode::INegate, shift);
+ Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32));
+
+ const bool is_right = opid == OpCode::Id::SHF_RIGHT_R || opid == OpCode::Id::SHF_RIGHT_IMM;
+ Node value = (is_right ? ShiftRight : ShiftLeft)(
+ move(op_a), GetRegister(instr.gpr39), move(shift), move(low_shift), instr.shf.type);
+
+ SetRegister(bb, instr.gpr0, move(value));
break;
}
default:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 280d81ba9..cd94693c1 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -742,7 +742,6 @@ void Config::ReadUIValues() {
void Config::ReadUIGamelistValues() {
qt_config->beginGroup(QStringLiteral("UIGameList"));
- UISettings::values.show_unknown = ReadSetting(QStringLiteral("show_unknown"), true).toBool();
UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool();
UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt();
UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt();
@@ -1159,7 +1158,6 @@ void Config::SaveUIValues() {
void Config::SaveUIGamelistValues() {
qt_config->beginGroup(QStringLiteral("UIGameList"));
- WriteSetting(QStringLiteral("show_unknown"), UISettings::values.show_unknown, true);
WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true);
WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64);
WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3);
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index c4a84cc67..94424ee44 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -40,7 +40,6 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
- connect(ui->show_unknown, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureUi::RequestGameListUpdate);
connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
@@ -60,7 +59,6 @@ ConfigureUi::~ConfigureUi() = default;
void ConfigureUi::ApplyConfiguration() {
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
- UISettings::values.show_unknown = ui->show_unknown->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
@@ -74,7 +72,6 @@ void ConfigureUi::RequestGameListUpdate() {
void ConfigureUi::SetConfiguration() {
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
- ui->show_unknown->setChecked(UISettings::values.show_unknown);
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
ui->icon_size_combobox->setCurrentIndex(
ui->icon_size_combobox->findData(UISettings::values.icon_size));
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui
index aa36bd112..bd5c5d3c2 100644
--- a/src/yuzu/configuration/configure_ui.ui
+++ b/src/yuzu/configuration/configure_ui.ui
@@ -52,13 +52,6 @@
<item>
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
- <widget class="QCheckBox" name="show_unknown">
- <property name="text">
- <string>Show files with type 'Unknown'</string>
- </property>
- </widget>
- </item>
- <item>
<widget class="QCheckBox" name="show_add_ons">
<property name="text">
<string>Show Add-Ons Column</string>
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 4c81ef12b..da2c27aa2 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -298,8 +298,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
}
const auto file_type = loader->GetFileType();
- if ((file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) &&
- !UISettings::values.show_unknown) {
+ if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
return true;
}
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index bc7725a01..a675ecf4d 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -89,7 +89,6 @@ struct Values {
int profile_index;
// Game List
- bool show_unknown;
bool show_add_ons;
uint32_t icon_size;
uint8_t row_1_text_id;