diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 99bb8cc1..ffd9558a 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -Wno-unused-command-line-argument") if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") add_compile_definitions(NDEBUG) @@ -48,7 +49,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/audio/track.cpp ${source_DIR}/skyline/audio/resampler.cpp ${source_DIR}/skyline/audio/adpcm_decoder.cpp - ${source_DIR}/skyline/gpu.cpp + ${source_DIR}/skyline/gpu/presentation_engine.cpp ${source_DIR}/skyline/gpu/macro_interpreter.cpp ${source_DIR}/skyline/gpu/memory_manager.cpp ${source_DIR}/skyline/gpu/gpfifo.cpp diff --git a/app/src/main/cpp/emu_jni.cpp b/app/src/main/cpp/emu_jni.cpp index da6e83a1..754d713d 100644 --- a/app/src/main/cpp/emu_jni.cpp +++ b/app/src/main/cpp/emu_jni.cpp @@ -9,34 +9,19 @@ #include "skyline/common.h" #include "skyline/os.h" #include "skyline/jvm.h" +#include "skyline/gpu.h" #include "skyline/input.h" -bool Halt; -jobject Surface; -skyline::GroupMutex JniMtx; skyline::u16 fps; skyline::u32 frametime; +std::weak_ptr gpuWeak; std::weak_ptr inputWeak; -void signalHandler(int signal) { - __android_log_print(ANDROID_LOG_FATAL, "emu-cpp", "Halting program due to signal: %s", strsignal(signal)); - exit(signal); -} - extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(JNIEnv *env, jobject instance, jstring romUriJstring, jint romType, jint romFd, jint preferenceFd, jstring appFilesPathJstring) { - Halt = false; fps = 0; frametime = 0; - /* - std::signal(SIGTERM, signalHandler); - std::signal(SIGSEGV, signalHandler); - std::signal(SIGINT, signalHandler); - std::signal(SIGILL, signalHandler); - std::signal(SIGABRT, signalHandler); - std::signal(SIGFPE, signalHandler); - */ - + pthread_setname_np(pthread_self(), "EmuMain"); setpriority(PRIO_PROCESS, static_cast(gettid()), -8); // Set the priority of this process to the highest value auto jvmManager{std::make_shared(env, instance)}; @@ -51,6 +36,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( try { skyline::kernel::OS os(jvmManager, logger, settings, std::string(appFilesPath)); + gpuWeak = os.state.gpu; inputWeak = os.state.input; jvmManager->InitializeControllers(); env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath); @@ -76,21 +62,16 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication( close(romFd); } -extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setHalt(JNIEnv *, jobject, jboolean halt) { - JniMtx.lock(skyline::GroupMutex::Group::Group2); - Halt = halt; - JniMtx.unlock(); +extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_exitGuest(JNIEnv *, jobject, jboolean halt) { + // TODO + exit(0); } -extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *env, jobject, jobject surface) { - JniMtx.lock(skyline::GroupMutex::Group::Group2); - if (!env->IsSameObject(Surface, nullptr)) - env->DeleteGlobalRef(Surface); - if (!env->IsSameObject(surface, nullptr)) - Surface = env->NewGlobalRef(surface); - else - Surface = surface; - JniMtx.unlock(); +extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *, jobject, jobject surface) { + auto gpu{gpuWeak.lock()}; + while (!gpu) + gpu = gpuWeak.lock(); + gpu->presentation.UpdateSurface(surface); } extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject) { @@ -112,38 +93,32 @@ extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_updateContr } extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jint index, jlong mask, jboolean pressed) { - try { - auto input{inputWeak.lock()}; - auto device{input->npad.controllers[index].device}; - if (device) - device->SetButtonState(skyline::input::NpadButton{.raw = static_cast(mask)}, pressed); - } catch (const std::bad_weak_ptr &) { - // We don't mind if we miss button updates while input hasn't been initialized - } + auto input{inputWeak.lock()}; + if (!input) + return; // We don't mind if we miss button updates while input hasn't been initialized + auto device{input->npad.controllers[index].device}; + if (device) + device->SetButtonState(skyline::input::NpadButton{.raw = static_cast(mask)}, pressed); } extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint index, jint axis, jint value) { - try { - auto input{inputWeak.lock()}; - auto device{input->npad.controllers[index].device}; - if (device) - device->SetAxisValue(static_cast(axis), value); - } catch (const std::bad_weak_ptr &) { - // We don't mind if we miss axis updates while input hasn't been initialized - } + auto input{inputWeak.lock()}; + if (!input) + return; // We don't mind if we miss axis updates while input hasn't been initialized + auto device{input->npad.controllers[index].device}; + if (device) + device->SetAxisValue(static_cast(axis), value); } extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setTouchState(JNIEnv *env, jobject, jintArray pointsJni) { - try { - using Point = skyline::input::TouchScreenPoint; + using Point = skyline::input::TouchScreenPoint; - auto input{inputWeak.lock()}; - jboolean isCopy{false}; + auto input{inputWeak.lock()}; + if (!input) + return; // We don't mind if we miss touch updates while input hasn't been initialized + jboolean isCopy{false}; - skyline::span points(reinterpret_cast(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint))); - input->touch.SetState(points); - env->ReleaseIntArrayElements(pointsJni, reinterpret_cast(points.data()), JNI_ABORT); - } catch (const std::bad_weak_ptr &) { - // We don't mind if we miss axis updates while input hasn't been initialized - } + skyline::span points(reinterpret_cast(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint))); + input->touch.SetState(points); + env->ReleaseIntArrayElements(pointsJni, reinterpret_cast(points.data()), JNI_ABORT); } diff --git a/app/src/main/cpp/skyline/audio.h b/app/src/main/cpp/skyline/audio.h index 5c2fcf6f..d5209aa0 100644 --- a/app/src/main/cpp/skyline/audio.h +++ b/app/src/main/cpp/skyline/audio.h @@ -14,7 +14,7 @@ namespace skyline::audio { oboe::AudioStreamBuilder builder; oboe::ManagedStream outputStream; std::vector> audioTracks; - Mutex trackLock; //!< Synchronizes modifications to the audio tracks + std::mutex trackLock; //!< Synchronizes modifications to the audio tracks public: Audio(const DeviceState &state); diff --git a/app/src/main/cpp/skyline/audio/circular_buffer.h b/app/src/main/cpp/skyline/audio/circular_buffer.h index 2ea64fb2..c6344d63 100644 --- a/app/src/main/cpp/skyline/audio/circular_buffer.h +++ b/app/src/main/cpp/skyline/audio/circular_buffer.h @@ -19,14 +19,13 @@ namespace skyline::audio { Type *start{array.begin()}; //!< The start/oldest element of the internal array Type *end{array.begin()}; //!< The end/newest element of the internal array bool empty{true}; //!< If the buffer is full or empty, as start == end can mean either - Mutex mtx; //!< Synchronizes buffer operations so they don't overlap + std::mutex mtx; //!< Synchronizes buffer operations so they don't overlap public: /** * @brief Reads data from this buffer into the specified buffer - * @param address The address to write buffer data into - * @param maxSize The maximum amount of data to write in units of Type * @param copyFunction If this is specified, then this is called rather than memcpy + * @param copyOffset The offset into the buffer after which to use memcpy rather than copyFunction, -1 will use it for the entire buffer * @return The amount of data written into the input buffer in units of Type */ inline size_t Read(span buffer, void copyFunction(Type *, Type *) = {}, ssize_t copyOffset = -1) { @@ -35,7 +34,7 @@ namespace skyline::audio { if (empty) return 0; - Type* pointer{buffer.data()}; + Type *pointer{buffer.data()}; ssize_t maxSize{static_cast(buffer.size())}, size{}, sizeBegin{}, sizeEnd{}; if (start < end) { @@ -95,7 +94,7 @@ namespace skyline::audio { inline void Append(span buffer) { std::lock_guard guard(mtx); - Type* pointer{buffer.data()}; + Type *pointer{buffer.data()}; ssize_t size{static_cast(buffer.size())}; while (size) { if (start <= end && end != array.end()) { diff --git a/app/src/main/cpp/skyline/audio/track.h b/app/src/main/cpp/skyline/audio/track.h index 0041df2b..ce63dde0 100644 --- a/app/src/main/cpp/skyline/audio/track.h +++ b/app/src/main/cpp/skyline/audio/track.h @@ -20,7 +20,7 @@ namespace skyline::audio { public: CircularBuffer samples; //!< A circular buffer with all appended audio samples - Mutex bufferLock; //!< Synchronizes appending to audio buffers + std::mutex bufferLock; //!< Synchronizes appending to audio buffers AudioOutState playbackState{AudioOutState::Stopped}; //!< The current state of playback u64 sampleCounter{}; //!< A counter used for tracking when buffers have been played and can be released diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index caefd1e9..d3731da2 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -11,61 +11,6 @@ #include "kernel/types/KThread.h" namespace skyline { - void Mutex::lock() { - while (true) { - for (int i{}; i < 1000; ++i) { - if (!flag.test_and_set(std::memory_order_acquire)) - return; - - asm volatile("yield"); - } - sched_yield(); - } - } - - void GroupMutex::lock(Group group) { - auto none{Group::None}; - constexpr u64 timeout{100}; // The timeout in ns - auto end{util::GetTimeNs() + timeout}; - - while (true) { - if (next == group) { - if (flag == group) { - std::lock_guard lock(mtx); - - if (flag == group) { - auto groupT{group}; - next.compare_exchange_strong(groupT, Group::None); - num++; - - return; - } - } else { - flag.compare_exchange_weak(none, group); - } - } else if (flag == group && (next == Group::None || util::GetTimeNs() >= end)) { - std::lock_guard lock(mtx); - - if (flag == group) { - num++; - return; - } - } else { - next.compare_exchange_weak(none, group); - } - - none = Group::None; - asm volatile("yield"); - } - } - - void GroupMutex::unlock() { - std::lock_guard lock(mtx); - - if (!--num) - flag.exchange(next); - } - Settings::Settings(int fd) { tinyxml2::XMLDocument pref; @@ -125,6 +70,7 @@ namespace skyline { Logger::Logger(const std::string &path, LogLevel configLevel) : configLevel(configLevel) { logFile.open(path, std::ios::trunc); + UpdateTag(); WriteHeader("Logging started"); } @@ -133,6 +79,17 @@ namespace skyline { logFile.flush(); } + thread_local static std::string logTag, threadName; + + void Logger::UpdateTag() { + std::array name; + if (!pthread_getname_np(pthread_self(), name.data(), name.size())) + threadName = name.data(); + else + threadName = "unk"; + logTag = std::string("emu-cpp-") + threadName; + } + void Logger::WriteHeader(const std::string &str) { __android_log_write(ANDROID_LOG_INFO, "emu-cpp", str.c_str()); @@ -144,14 +101,17 @@ namespace skyline { constexpr std::array levelCharacter{'0', '1', '2', '3', '4'}; // The LogLevel as written out to a file constexpr std::array levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE}; // This corresponds to LogLevel and provides it's equivalent for NDK Logging - __android_log_write(levelAlog[static_cast(level)], "emu-cpp", str.c_str()); + if (logTag.empty()) + UpdateTag(); + + __android_log_write(levelAlog[static_cast(level)], logTag.c_str(), str.c_str()); for (auto &character : str) if (character == '\n') character = '\\'; std::lock_guard guard(mtx); - logFile << "1|" << levelCharacter[static_cast(level)] << '|' << std::dec << pthread_self() << '|' << str << '\n'; + logFile << "1|" << levelCharacter[static_cast(level)] << '|' << threadName << '|' << str << '\n'; } DeviceState::DeviceState(kernel::OS *os, std::shared_ptr &process, std::shared_ptr jvmManager, std::shared_ptr settings, std::shared_ptr logger) diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 1a27cc6e..fb9d31f0 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -362,73 +362,13 @@ namespace skyline { template span(const Container &) -> span; - /** - * @brief The Mutex class is a wrapper around an atomic bool used for low-contention synchronization - */ - class Mutex { - std::atomic_flag flag = ATOMIC_FLAG_INIT; //!< An atomic flag to hold the state of the mutex - - public: - /** - * @brief Wait on and lock the mutex - */ - void lock(); - - /** - * @brief Try to lock the mutex if it is unlocked else return - * @return If the mutex was successfully locked or not - */ - inline bool try_lock() { - return !flag.test_and_set(std::memory_order_acquire); - } - - /** - * @brief Unlock the mutex if it is held by this thread - */ - inline void unlock() { - flag.clear(std::memory_order_release); - } - }; - - /** - * @brief The GroupMutex class is a special type of mutex that allows two groups of users and only allows one group to run in parallel - */ - class GroupMutex { - public: - /** - * @brief All the possible owners of the mutex - */ - enum class Group : u8 { - None = 0, //!< No group owns this mutex - Group1 = 1, //!< Group 1 owns this mutex - Group2 = 2, //!< Group 2 owns this mutex - }; - - /** - * @brief Wait on and lock the mutex - */ - void lock(Group group = Group::Group1); - - /** - * @brief Unlock the mutex - * @note Undefined behavior in case unlocked by thread in non-owner group - */ - void unlock(); - - private: - std::atomic flag{Group::None}; //!< An atomic flag to hold which group holds the mutex - std::atomic next{Group::None}; //!< An atomic flag to hold which group will hold the mutex next - std::atomic num{}; //!< An atomic u8 keeping track of how many users are holding the mutex - Mutex mtx; //!< A mutex to lock before changing of num and flag - }; - /** * @brief The Logger class is to write log output to file and logcat */ class Logger { private: std::ofstream logFile; //!< An output stream to the log file - Mutex mtx; //!< A mutex to lock before logging anything + std::mutex mtx; //!< A mutex to lock before logging anything public: enum class LogLevel { @@ -452,6 +392,11 @@ namespace skyline { */ ~Logger(); + /** + * @brief Update the tag in log messages with a new thread name + */ + static void UpdateTag(); + /** * @brief Writes a header, should only be used for emulation starting and ending */ diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp deleted file mode 100644 index cb6b6b45..00000000 --- a/app/src/main/cpp/skyline/gpu.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#include "gpu.h" -#include "jvm.h" -#include -#include - -extern bool Halt; -extern jobject Surface; -extern skyline::u16 fps; -extern skyline::u32 frametime; - -namespace skyline::gpu { - GPU::GPU(const DeviceState &state) : state(state), memoryManager(state), gpfifo(state), fermi2D(std::make_shared(state)), keplerMemory(std::make_shared(state)), maxwell3D(std::make_shared(state)), maxwellCompute(std::make_shared(state)), maxwellDma(std::make_shared(state)), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared(state)), bufferEvent(std::make_shared(state)) { - ANativeWindow_acquire(window); - resolution.width = static_cast(ANativeWindow_getWidth(window)); - resolution.height = static_cast(ANativeWindow_getHeight(window)); - format = ANativeWindow_getFormat(window); - vsyncEvent->Signal(); - } - - GPU::~GPU() { - ANativeWindow_release(window); - } - - void GPU::Loop() { - gpfifo.Run(); - vsyncEvent->Signal(); - - if (surfaceUpdate) { - if (Surface == nullptr) - return; - window = ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface); - ANativeWindow_acquire(window); - resolution.width = static_cast(ANativeWindow_getWidth(window)); - resolution.height = static_cast(ANativeWindow_getHeight(window)); - format = ANativeWindow_getFormat(window); - surfaceUpdate = false; - } else if (Surface == nullptr) { - surfaceUpdate = true; - return; - } - - if (!presentationQueue.empty()) { - auto &texture{presentationQueue.front()}; - presentationQueue.pop(); - - auto textureFormat{texture->GetAndroidFormat()}; - if (resolution != texture->dimensions || textureFormat != format) { - ANativeWindow_setBuffersGeometry(window, texture->dimensions.width, texture->dimensions.height, textureFormat); - resolution = texture->dimensions; - format = textureFormat; - } - - ANativeWindow_Buffer windowBuffer; - ARect rect; - - ANativeWindow_lock(window, &windowBuffer, &rect); - std::memcpy(windowBuffer.bits, texture->backing.data(), texture->backing.size()); - ANativeWindow_unlockAndPost(window); - - vsyncEvent->Signal(); - texture->releaseCallback(); - - if (frameTimestamp) { - auto now{util::GetTimeNs()}; - - frametime = static_cast((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals - fps = static_cast(constant::NsInSecond / (now - frameTimestamp)); - - frameTimestamp = now; - } else { - frameTimestamp = util::GetTimeNs(); - } - } - } -} diff --git a/app/src/main/cpp/skyline/gpu.h b/app/src/main/cpp/skyline/gpu.h index c781e8cf..e1e4bf1a 100644 --- a/app/src/main/cpp/skyline/gpu.h +++ b/app/src/main/cpp/skyline/gpu.h @@ -3,11 +3,10 @@ #pragma once -#include -#include "services/nvdrv/devices/nvmap.h" #include "gpu/gpfifo.h" #include "gpu/syncpoint.h" #include "gpu/engines/maxwell_3d.h" +#include "gpu/presentation_engine.h" namespace skyline::gpu { /** @@ -15,18 +14,11 @@ namespace skyline::gpu { */ class GPU { private: - ANativeWindow *window; //!< The ANativeWindow that is presented to const DeviceState &state; - bool surfaceUpdate{}; //!< If the surface needs to be updated - u64 frameTimestamp{}; //!< The timestamp of the last frame being shown public: - std::queue> presentationQueue; //!< A queue of all the PresentationTextures to be posted to the display - texture::Dimensions resolution{}; //!< The resolution of the surface - i32 format{}; //!< The format of the display window - std::shared_ptr vsyncEvent; //!< This KEvent is triggered every time a frame is drawn - std::shared_ptr bufferEvent; //!< This KEvent is triggered every time a buffer is freed - vmm::MemoryManager memoryManager; //!< The GPU Virtual Memory Manager + PresentationEngine presentation; + vmm::MemoryManager memoryManager; std::shared_ptr fermi2D; std::shared_ptr maxwell3D; std::shared_ptr maxwellCompute; @@ -35,10 +27,6 @@ namespace skyline::gpu { gpfifo::GPFIFO gpfifo; std::array syncpoints{}; - GPU(const DeviceState &state); - - ~GPU(); - - void Loop(); + inline GPU(const DeviceState &state) : state(state), presentation(state), memoryManager(state), gpfifo(state), fermi2D(std::make_shared(state)), keplerMemory(std::make_shared(state)), maxwell3D(std::make_shared(state)), maxwellCompute(std::make_shared(state)), maxwellDma(std::make_shared(state)) {} }; } diff --git a/app/src/main/cpp/skyline/gpu/circular_queue.h b/app/src/main/cpp/skyline/gpu/circular_queue.h new file mode 100644 index 00000000..ec0ea971 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/circular_queue.h @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::gpu { + /** + * @brief An efficient consumer-producer structure with internal synchronization + */ + template + class CircularQueue { + private: + std::vector vector; //!< The internal vector holding the circular queue's data, we use a byte vector due to the default item construction/destruction semantics not being appropriate for a circular buffer + Type *start{reinterpret_cast(vector.begin().base())}; //!< The start/oldest element of the queue + Type *end{reinterpret_cast(vector.begin().base())}; //!< The end/newest element of the queue + std::mutex consumptionMutex; + std::condition_variable consumeCondition; + std::mutex productionMutex; + std::condition_variable produceCondition; + + public: + CircularQueue(size_t size) : vector(size * sizeof(Type)) {} + + ~CircularQueue() { + ssize_t size{}; + if (start < end) + size = end - start; + else + size = (reinterpret_cast(vector.end().base()) - start) + (end - reinterpret_cast(vector.begin().base())); + + while (size--) { + std::destroy_at(start); + if (start + 1 == reinterpret_cast(vector.end().base())) + start = reinterpret_cast(vector.begin().base()); + } + } + + /** + * @brief A blocking for-each that runs on every item and waits till new items to run on them as well + * @param function A function that is called for each item (with the only parameter as a reference to that item) + */ + template + [[noreturn]] inline void Process(F function) { + while (true) { + if (start == end) { + std::unique_lock lock(productionMutex); + produceCondition.wait(lock, [this]() { return start != end; }); + } + + ssize_t size{}; + if (start < end) + size = end - start; + else + size = (reinterpret_cast(vector.end().base()) - start) + (end - reinterpret_cast(vector.begin().base())); + + while (size--) { + function(*start); + if (start + 1 != reinterpret_cast(vector.end().base())) + start++; + else + start = reinterpret_cast(vector.begin().base()); + } + + consumeCondition.notify_one(); + } + } + + inline void Push(const Type &item) { + std::unique_lock lock(productionMutex); + auto next{end + 1}; + next = (next == reinterpret_cast(vector.end().base())) ? reinterpret_cast(vector.begin().base()) : next; + if (next == start) { + std::unique_lock consumeLock(consumptionMutex); + consumeCondition.wait(consumeLock, [=]() { return next != start; }); + } + *next = item; + end = next; + produceCondition.notify_one(); + } + + inline void Append(span buffer) { + std::unique_lock lock(productionMutex); + for (auto &item : buffer) { + auto next{end + 1}; + next = (next == reinterpret_cast(vector.end().base())) ? reinterpret_cast(vector.begin().base()) : next; + if (next == start) { + std::unique_lock consumeLock(consumptionMutex); + consumeCondition.wait(consumeLock, [=]() { return next != start; }); + } + *next = item; + end = next; + } + produceCondition.notify_one(); + } + + /** + * @brief Appends a buffer with an alternative input type while supplied transformation function + * @param tranformation A function that takes in an item of TransformedType as input and returns an item of Type + */ + template + inline void AppendTranform(span buffer, Transformation transformation) { + std::unique_lock lock(productionMutex); + auto next{end}; + for (auto &item : buffer) { + end = (end == reinterpret_cast(vector.end().base())) ? reinterpret_cast(vector.begin().base()) : end; + if (start == end + 1) { + std::unique_lock consumeLock(consumptionMutex); + consumeCondition.wait(consumeLock, [=]() { return start != end + 1; }); + } + *(end++) = transformation(item); + } + produceCondition.notify_one(); + } + }; +} diff --git a/app/src/main/cpp/skyline/gpu/engines/maxwell_3d.h b/app/src/main/cpp/skyline/gpu/engines/maxwell_3d.h index 6b2423d9..ab929956 100644 --- a/app/src/main/cpp/skyline/gpu/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/gpu/engines/maxwell_3d.h @@ -3,7 +3,6 @@ #pragma once -#include #include #include "engine.h" diff --git a/app/src/main/cpp/skyline/gpu/gpfifo.cpp b/app/src/main/cpp/skyline/gpu/gpfifo.cpp index 719dc545..e724929e 100644 --- a/app/src/main/cpp/skyline/gpu/gpfifo.cpp +++ b/app/src/main/cpp/skyline/gpu/gpfifo.cpp @@ -77,27 +77,28 @@ namespace skyline::gpu::gpfifo { } } + void GPFIFO::Initialize(size_t numBuffers) { + if (pushBuffers) + throw exception("GPFIFO Initialization cannot be done multiple times"); + pushBuffers.emplace(numBuffers); + thread = std::thread(&GPFIFO::Run, this); + } + void GPFIFO::Run() { - std::lock_guard lock(pushBufferQueueLock); - while (!pushBufferQueue.empty()) { - auto pushBuffer{pushBufferQueue.front()}; + pthread_setname_np(pthread_self(), "GPFIFO"); + pushBuffers->Process([this](PushBuffer& pushBuffer){ if (pushBuffer.segment.empty()) pushBuffer.Fetch(state.gpu->memoryManager); - Process(pushBuffer.segment); - pushBufferQueue.pop(); - } + }); } void GPFIFO::Push(span entries) { - std::lock_guard lock(pushBufferQueueLock); - bool beforeBarrier{false}; - - for (const auto &entry : entries) { + bool beforeBarrier{true}; + pushBuffers->AppendTranform(entries, [&beforeBarrier, this](const GpEntry& entry){ if (entry.sync == GpEntry::Sync::Wait) beforeBarrier = false; - - pushBufferQueue.emplace(PushBuffer(entry, state.gpu->memoryManager, beforeBarrier)); - } + return PushBuffer(entry, state.gpu->memoryManager, beforeBarrier); + }); } } diff --git a/app/src/main/cpp/skyline/gpu/gpfifo.h b/app/src/main/cpp/skyline/gpu/gpfifo.h index cb4c6195..2366d545 100644 --- a/app/src/main/cpp/skyline/gpu/gpfifo.h +++ b/app/src/main/cpp/skyline/gpu/gpfifo.h @@ -3,7 +3,7 @@ #pragma once -#include +#include "circular_queue.h" #include "engines/gpfifo.h" #include "memory_manager.h" @@ -147,8 +147,8 @@ namespace skyline::gpu { const DeviceState &state; engine::GPFIFO gpfifoEngine; //!< The engine for processing GPFIFO method calls std::array, 8> subchannels; - std::queue pushBufferQueue; - skyline::Mutex pushBufferQueueLock; //!< Synchronizes pushbuffer queue insertions as the GPU is multi-threaded + std::optional> pushBuffers; + std::thread thread; //!< The thread that manages processing of push-buffers /** * @brief Processes a pushbuffer segment, calling methods as needed @@ -163,6 +163,11 @@ namespace skyline::gpu { public: GPFIFO(const DeviceState &state) : state(state), gpfifoEngine(state) {} + /** + * @param numBuffers The amount of push-buffers to allocate in the circular buffer + */ + void Initialize(size_t numBuffers); + /** * @brief Executes all pending entries in the FIFO */ diff --git a/app/src/main/cpp/skyline/gpu/presentation_engine.cpp b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp new file mode 100644 index 00000000..f23ea28b --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "jvm.h" +#include "presentation_engine.h" + +extern skyline::u16 fps; +extern skyline::u32 frametime; + +namespace skyline::gpu { + PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared(state)), bufferEvent(std::make_shared(state)) {} + + PresentationEngine::~PresentationEngine() { + if (window) + ANativeWindow_release(window); + auto env{state.jvm->GetEnv()}; + if (!env->IsSameObject(surface, nullptr)) + env->DeleteGlobalRef(surface); + } + + void PresentationEngine::UpdateSurface(jobject newSurface) { + std::lock_guard lock(windowMutex); + auto env{state.jvm->GetEnv()}; + if (!env->IsSameObject(surface, nullptr)) { + env->DeleteGlobalRef(surface); + surface = nullptr; + } + if (!env->IsSameObject(newSurface, nullptr)) + surface = env->NewGlobalRef(newSurface); + if (surface) { + window = ANativeWindow_fromSurface(state.jvm->GetEnv(), surface); + ANativeWindow_acquire(window); + resolution.width = static_cast(ANativeWindow_getWidth(window)); + resolution.height = static_cast(ANativeWindow_getHeight(window)); + format = ANativeWindow_getFormat(window); + windowConditional.notify_all(); + } else { + window = nullptr; + } + } + + void PresentationEngine::Present(const std::shared_ptr &texture) { + std::unique_lock lock(windowMutex); + if (!window) + windowConditional.wait(lock, [this]() { return window; }); + + auto textureFormat{[&texture]() { + switch (texture->format.vkFormat) { + case vk::Format::eR8G8B8A8Unorm: + return WINDOW_FORMAT_RGBA_8888; + case vk::Format::eR5G6B5UnormPack16: + return WINDOW_FORMAT_RGB_565; + default: + throw exception("Cannot find corresponding Android surface format"); + } + }()}; + if (resolution != texture->dimensions || textureFormat != format) { + ANativeWindow_setBuffersGeometry(window, texture->dimensions.width, texture->dimensions.height, textureFormat); + resolution = texture->dimensions; + format = textureFormat; + } + + ANativeWindow_Buffer buffer; + ARect rect; + + ANativeWindow_lock(window, &buffer, &rect); + std::memcpy(buffer.bits, texture->backing.data(), texture->backing.size()); + ANativeWindow_unlockAndPost(window); + + vsyncEvent->Signal(); + + if (frameTimestamp) { + auto now{util::GetTimeNs()}; + + frametime = static_cast((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals + fps = static_cast(constant::NsInSecond / (now - frameTimestamp)); + + frameTimestamp = now; + } else { + frameTimestamp = util::GetTimeNs(); + } + } +} diff --git a/app/src/main/cpp/skyline/gpu/presentation_engine.h b/app/src/main/cpp/skyline/gpu/presentation_engine.h new file mode 100644 index 00000000..e66d6ff5 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/presentation_engine.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include "texture.h" + +struct ANativeWindow; + +namespace skyline::gpu { + class PresentationEngine { + private: + const DeviceState &state; + std::mutex windowMutex; + std::condition_variable windowConditional; + jobject surface; //!< The Surface object backing the ANativeWindow + u64 frameTimestamp{}; //!< The timestamp of the last frame being shown + + public: + texture::Dimensions resolution{}; + i32 format{}; + std::shared_ptr vsyncEvent; //!< Signalled every time a frame is drawn + std::shared_ptr bufferEvent; //!< Signalled every time a buffer is freed + + PresentationEngine(const DeviceState &state); + + ~PresentationEngine(); + + void UpdateSurface(jobject newSurface); + + void Present(const std::shared_ptr& texture); + + ANativeWindow *window{}; + }; +} diff --git a/app/src/main/cpp/skyline/gpu/syncpoint.h b/app/src/main/cpp/skyline/gpu/syncpoint.h index 36cc940e..ae5dc8a3 100644 --- a/app/src/main/cpp/skyline/gpu/syncpoint.h +++ b/app/src/main/cpp/skyline/gpu/syncpoint.h @@ -21,7 +21,7 @@ namespace skyline { std::function callback; //!< The callback to do after the wait has ended }; - Mutex waiterLock; //!< Synchronizes insertions and deletions of waiters + std::mutex waiterLock; //!< Synchronizes insertions and deletions of waiters std::map waiterMap; u64 nextWaiterId{1}; diff --git a/app/src/main/cpp/skyline/gpu/texture.cpp b/app/src/main/cpp/skyline/gpu/texture.cpp index 5ea03e64..94c2e9b5 100644 --- a/app/src/main/cpp/skyline/gpu/texture.cpp +++ b/app/src/main/cpp/skyline/gpu/texture.cpp @@ -17,14 +17,6 @@ namespace skyline::gpu { return sharedHost; } - std::shared_ptr GuestTexture::InitializePresentationTexture() { - if (!host.expired()) - throw exception("Trying to create multiple PresentationTexture objects from a single GuestTexture"); - auto presentation{std::make_shared(state, shared_from_this(), dimensions, format)}; - host = std::static_pointer_cast(presentation); - return presentation; - } - Texture::Texture(const DeviceState &state, std::shared_ptr guest, texture::Dimensions dimensions, texture::Format format, texture::Swizzle swizzle) : state(state), guest(guest), dimensions(dimensions), format(format), swizzle(swizzle) { SynchronizeHost(); } @@ -92,17 +84,4 @@ namespace skyline::gpu { std::memcpy(output, pointer, size); } } - - PresentationTexture::PresentationTexture(const DeviceState &state, const std::shared_ptr &guest, const texture::Dimensions &dimensions, const texture::Format &format, const std::function &releaseCallback) : releaseCallback(releaseCallback), Texture(state, guest, dimensions, format, {}) {} - - i32 PresentationTexture::GetAndroidFormat() { - switch (format.vkFormat) { - case vk::Format::eR8G8B8A8Unorm: - return WINDOW_FORMAT_RGBA_8888; - case vk::Format::eR5G6B5UnormPack16: - return WINDOW_FORMAT_RGB_565; - default: - throw exception("GetAndroidFormat: Cannot find corresponding Android surface format"); - } - } } diff --git a/app/src/main/cpp/skyline/gpu/texture.h b/app/src/main/cpp/skyline/gpu/texture.h index 4c66f349..226e7972 100644 --- a/app/src/main/cpp/skyline/gpu/texture.h +++ b/app/src/main/cpp/skyline/gpu/texture.h @@ -114,7 +114,6 @@ namespace skyline { } class Texture; - class PresentationTexture; /** * @brief A texture present in guest memory, it can be used to create a corresponding Texture object for usage on the host @@ -146,11 +145,6 @@ namespace skyline { * @note There can only be one host texture for a corresponding guest texture */ std::shared_ptr InitializeTexture(std::optional format = std::nullopt, std::optional dimensions = std::nullopt, texture::Swizzle swizzle = {}); - - protected: - std::shared_ptr InitializePresentationTexture(); - - friend service::hosbinder::GraphicBufferProducer; }; /** @@ -203,20 +197,5 @@ namespace skyline { */ void SynchronizeGuest(); }; - - /** - * @brief A texture object alongside a release callback used for display presentation - */ - class PresentationTexture : public Texture { - public: - std::function releaseCallback; //!< The release callback after this texture has been displayed - - PresentationTexture(const DeviceState &state, const std::shared_ptr &guest, const texture::Dimensions &dimensions, const texture::Format &format, const std::function &releaseCallback = {}); - - /** - * @return The corresponding Android surface format for the current texture format - */ - i32 GetAndroidFormat(); - }; } } diff --git a/app/src/main/cpp/skyline/input.h b/app/src/main/cpp/skyline/input.h index 382768c9..80195900 100644 --- a/app/src/main/cpp/skyline/input.h +++ b/app/src/main/cpp/skyline/input.h @@ -24,6 +24,6 @@ namespace skyline::input { NpadManager npad; TouchManager touch; - Input(const DeviceState &state) : state(state), kHid(std::make_shared(state, sizeof(HidSharedMemory))), hid(reinterpret_cast(kHid->kernel.ptr)), npad(state, hid), touch(state, hid) {} + inline Input(const DeviceState &state) : state(state), kHid(std::make_shared(state, sizeof(HidSharedMemory))), hid(reinterpret_cast(kHid->kernel.ptr)), npad(state, hid), touch(state, hid) {} }; } diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index da2bb428..fddd710e 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -33,11 +33,14 @@ namespace skyline::kernel { throw exception("VMM initialization with unknown address space"); } + // Search for a suitable carveout in host AS to fit the guest AS inside of std::ifstream mapsFile("/proc/self/maps"); std::string maps((std::istreambuf_iterator(mapsFile)), std::istreambuf_iterator()); - size_t line{}, start{}, alignedStart{}; + size_t line{}, start{1ULL << 35}, alignedStart{1ULL << 35}; // 1 << 35 is where QC KGSL (Kernel Graphic Support Layer) maps down from, we skip over this or KGSL goes OOM do { auto end{util::HexStringToInt(std::string_view(maps.data() + line, sizeof(u64) * 2))}; + if (end < start) + continue; if (end - start > base.size + (alignedStart - start)) { // We don't want to overflow if alignedStart > start base.address = alignedStart; break; @@ -54,11 +57,22 @@ namespace skyline::kernel { mmap(reinterpret_cast(base.address), base.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - chunks = {ChunkDescriptor{ - .ptr = reinterpret_cast(addressSpace.address), - .size = addressSpace.size, - .state = memory::states::Unmapped, - }}; + chunks = { + ChunkDescriptor{ + .ptr = reinterpret_cast(addressSpace.address), + .size = base.address - addressSpace.address, + .state = memory::states::Reserved, + }, + ChunkDescriptor{ + .ptr = reinterpret_cast(base.address), + .size = base.size, + .state = memory::states::Unmapped, + }, + ChunkDescriptor{ + .ptr = reinterpret_cast(base.address + base.size), + .size = addressSpace.size - (base.address + base.size), + .state = memory::states::Reserved, + }}; } void MemoryManager::InitializeRegions(u8 *codeStart, u64 size) { diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 155ac8dd..f1b86a6b 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -196,7 +196,7 @@ namespace skyline::kernel::svc { .ipcRefCount = 0, }; - state.logger->Debug("svcQueryMemory: Pointer: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-'); + state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-'); } else { auto addressSpaceEnd{reinterpret_cast(state.process->memory.addressSpace.address + state.process->memory.addressSpace.size)}; diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 369e40a6..efbff1c4 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -44,8 +44,8 @@ namespace skyline { std::unordered_map>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it std::unordered_map>> conditionals; //!< A map from a conditional variable's address to a vector of threads waiting on it - Mutex mutexLock; - Mutex conditionalLock; + std::mutex mutexLock; + std::mutex conditionalLock; /** * @brief The status of a single TLS page (A page is 4096 bytes on ARMv8) diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index bf209f07..10d94fef 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -1,14 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include -#include #include -#include +#include +#include #include #include -#include -#include #include "KProcess.h" namespace skyline::kernel::type { @@ -41,6 +38,7 @@ namespace skyline::kernel::type { void KThread::StartThread() { pthread_setname_np(pthread_self(), fmt::format("HOS-{}", id).c_str()); + state.logger->UpdateTag(); if (!ctx.tpidrroEl0) ctx.tpidrroEl0 = parent->AllocateTlsSlot(); diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 258da19f..d3f0a636 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -12,10 +12,6 @@ #include "nce/instructions.h" #include "nce.h" -extern bool Halt; -extern jobject Surface; -extern skyline::GroupMutex JniMtx; - namespace skyline::nce { void NCE::SvcHandler(u16 svc, ThreadContext *ctx) { const auto &state{*ctx->state}; @@ -79,27 +75,6 @@ namespace skyline::nce { NCE::NCE(DeviceState &state) : state(state) {} - void NCE::Execute() { - try { - while (true) { - std::lock_guard guard(JniMtx); - if (Halt) - break; - state.gpu->Loop(); - } - } catch (const std::exception &e) { - state.logger->Error(e.what()); - } catch (...) { - state.logger->Error("An unknown exception has occurred"); - } - - if (!Halt) { - JniMtx.lock(GroupMutex::Group::Group2); - Halt = true; - JniMtx.unlock(); - } - } - constexpr u8 MainSvcTrampolineSize{17}; // Size of the main SVC trampoline function in u32 units constexpr u32 TpidrEl0{0x5E82}; // ID of TPIDR_EL0 in MRS constexpr u32 TpidrroEl0{0x5E83}; // ID of TPIDRRO_EL0 in MRS diff --git a/app/src/main/cpp/skyline/nce.h b/app/src/main/cpp/skyline/nce.h index e023b8cb..fd2b6385 100644 --- a/app/src/main/cpp/skyline/nce.h +++ b/app/src/main/cpp/skyline/nce.h @@ -21,8 +21,6 @@ namespace skyline::nce { NCE(DeviceState &state); - void Execute(); - struct PatchData { size_t size; //!< Size of the .patch section std::vector offsets; //!< Offsets in .text of instructions that need to be patched diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index a2d185a9..414e844c 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -32,8 +32,6 @@ namespace skyline::kernel { process = std::make_shared(state); auto entry{state.loader->LoadProcessData(process, state)}; process->InitializeHeap(); - process->CreateThread(entry)->Start(); - - state.nce->Execute(); + process->CreateThread(entry)->Start(true); } } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index 1c42f649..6598a2ac 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -1,14 +1,16 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include -#include -#include #include +#include +#include +#include #include "GraphicBufferProducer.h" namespace skyline::service::hosbinder { - Buffer::Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr &texture) : gbpBuffer(gbpBuffer), texture(texture) {} + Buffer::Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr &texture) : gbpBuffer(gbpBuffer), texture(texture) {} GraphicBufferProducer::GraphicBufferProducer(const DeviceState &state) : state(state) {} @@ -64,15 +66,10 @@ namespace skyline::service::hosbinder { auto buffer{queue.at(data.slot)}; buffer->status = BufferStatus::Queued; - auto slot{data.slot}; - auto bufferEvent{state.gpu->bufferEvent}; - buffer->texture->releaseCallback = [this, slot, bufferEvent]() { - queue.at(slot)->status = BufferStatus::Free; - bufferEvent->Signal(); - }; - buffer->texture->SynchronizeHost(); - state.gpu->presentationQueue.push(buffer->texture); + state.gpu->presentation.Present(buffer->texture); + queue.at(data.slot)->status = BufferStatus::Free; + state.gpu->presentation.bufferEvent->Signal(); struct { u32 width; @@ -140,11 +137,11 @@ namespace skyline::service::hosbinder { gpu::texture::Format format; switch (gbpBuffer.format) { - case WINDOW_FORMAT_RGBA_8888: - case WINDOW_FORMAT_RGBX_8888: + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: format = gpu::format::RGBA8888Unorm; break; - case WINDOW_FORMAT_RGB_565: + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: format = gpu::format::RGB565Unorm; break; default: @@ -153,8 +150,8 @@ namespace skyline::service::hosbinder { auto texture{std::make_shared(state, nvBuffer->pointer + gbpBuffer.offset, gpu::texture::Dimensions(gbpBuffer.width, gbpBuffer.height), format, gpu::texture::TileMode::Block, gpu::texture::TileConfig{.surfaceWidth = static_cast(gbpBuffer.stride), .blockHeight = static_cast(1U << gbpBuffer.blockHeightLog2), .blockDepth = 1})}; - queue[data.slot] = std::make_shared(gbpBuffer, texture->InitializePresentationTexture()); - state.gpu->bufferEvent->Signal(); + queue[data.slot] = std::make_shared(gbpBuffer, texture->InitializeTexture()); + state.gpu->presentation.bufferEvent->Signal(); state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data.slot, gbpBuffer.magic, gbpBuffer.width, gbpBuffer.height, gbpBuffer.stride, gbpBuffer.format, gbpBuffer.usage, gbpBuffer.index, gbpBuffer.nvmapId, gbpBuffer.nvmapHandle, gbpBuffer.offset, (1U << gbpBuffer.blockHeightLog2), gbpBuffer.size); } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h index 8260b114..a4ad1d25 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h @@ -6,7 +6,7 @@ #include namespace skyline::gpu { - class PresentationTexture; + class Texture; } namespace skyline::service::hosbinder { @@ -47,10 +47,10 @@ namespace skyline::service::hosbinder { class Buffer { public: BufferStatus status{BufferStatus::Free}; - std::shared_ptr texture; + std::shared_ptr texture; GbpBuffer gbpBuffer; - Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr &texture); + Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr &texture); }; /** diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp index e8b20bce..c867d5a7 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp @@ -40,7 +40,7 @@ namespace skyline::service::hosbinder { } Result IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - KHandle handle{state.process->InsertItem(state.gpu->bufferEvent)}; + KHandle handle{state.process->InsertItem(state.gpu->presentation.bufferEvent)}; state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp index 81cbe64a..1e88a5e8 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp @@ -110,6 +110,8 @@ namespace skyline::service::nvdrv::device { u32 reserved[3]; // In } &data = buffer.as(); + state.gpu->gpfifo.Initialize(data.numEntries); + auto driver{nvdrv::driver.lock()}; channelFence.UpdateValue(driver->hostSyncpoint); data.fence = channelFence; diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h index 19456938..66788c80 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h @@ -23,7 +23,7 @@ namespace skyline::service::nvdrv { const DeviceState &state; std::array syncpoints{}; - Mutex reservationLock; + std::mutex reservationLock; /** * @note reservationLock should be locked when calling this diff --git a/app/src/main/cpp/skyline/services/serviceman.h b/app/src/main/cpp/skyline/services/serviceman.h index da76ae16..f43c831f 100644 --- a/app/src/main/cpp/skyline/services/serviceman.h +++ b/app/src/main/cpp/skyline/services/serviceman.h @@ -14,7 +14,7 @@ namespace skyline::service { private: const DeviceState &state; std::unordered_map> serviceMap; //!< A mapping from a Service to the underlying object - Mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes + std::mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes /** * @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp index 88930250..4a7a9ab2 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp @@ -95,7 +95,7 @@ namespace skyline::service::visrv { } Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - KHandle handle{state.process->InsertItem(state.gpu->vsyncEvent)}; + KHandle handle{state.process->InsertItem(state.gpu->presentation.vsyncEvent)}; state.logger->Debug("VSync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index 1ee28892..e346b171 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -43,11 +43,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo @Volatile private var surface : Surface? = null - /** - * A condition variable keeping track of if the surface is ready or not - */ - private var surfaceReady = ConditionVariable() - /** * A boolean flag denoting if the emulation thread should call finish() or not */ @@ -77,7 +72,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo * * @param halt The value to set halt to */ - private external fun setHalt(halt : Boolean) + private external fun exitGuest(halt : Boolean) /** * This sets the surface object in libskyline to the provided value, emulation is halted if set to null @@ -175,10 +170,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo val preferenceFd = ParcelFileDescriptor.open(File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml"), ParcelFileDescriptor.MODE_READ_WRITE) emulationThread = Thread { - surfaceReady.block() - executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), applicationContext.filesDir.canonicalPath + "/") - if (shouldFinish) runOnUiThread { finish() } } @@ -243,7 +235,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo override fun onNewIntent(intent : Intent?) { shouldFinish = false - setHalt(true) + exitGuest(true) emulationThread.join() shouldFinish = true @@ -259,7 +251,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo override fun onDestroy() { shouldFinish = false - setHalt(true) + exitGuest(true) emulationThread.join(1000) vibrators.forEach { (_, vibrator) -> vibrator.cancel() } @@ -275,7 +267,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo Log.d(Tag, "surfaceCreated Holder: $holder") surface = holder.surface setSurface(surface) - surfaceReady.open() } /** @@ -290,7 +281,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo */ override fun surfaceDestroyed(holder : SurfaceHolder) { Log.d(Tag, "surfaceDestroyed Holder: $holder") - surfaceReady.close() surface = null setSurface(surface) }