some optimizations. apply current transform to native window instead of defaulting to Identity

This commit is contained in:
Emmanuel Hansen 2023-08-08 16:06:35 +00:00
parent c732a9fbb6
commit 7a2fadb499
12 changed files with 473 additions and 35 deletions

View File

@ -30,6 +30,7 @@ namespace LibRyujinx
{
private static ManualResetEvent _surfaceEvent;
private static long _surfacePtr;
private static long _window = 0;
public static VulkanLoader? VulkanLoader { get; private set; }
@ -48,6 +49,9 @@ namespace LibRyujinx
[DllImport("libryujinxjni")]
internal extern static void onFrameEnd(double time);
[DllImport("libryujinxjni")]
internal extern static void setCurrentTransform(long native_window, int transform);
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
[UnmanagedCallersOnly(EntryPoint = "JNI_OnLoad")]
@ -236,9 +240,10 @@ namespace LibRyujinx
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsSetSurface")]
public static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr)
public static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr, JLong window)
{
_surfacePtr = surfacePtr;
_window = window;
_surfaceEvent.Set();
}

View File

@ -185,7 +185,22 @@ namespace LibRyujinx
while (device.ConsumeFrameAvailable())
{
device.PresentFrame(() => _swapBuffersCallback?.Invoke());
device.PresentFrame(() =>
{
VulkanRenderer? vk = device.Gpu.Renderer as VulkanRenderer;
if(vk == null)
{
vk = (device.Gpu.Renderer as ThreadedRenderer)?.BaseRenderer as VulkanRenderer;
}
if(vk != null)
{
var transform = vk.CurrentTransform;
setCurrentTransform(_window, (int)transform);
}
_swapBuffersCallback?.Invoke();
});
}
}

View File

@ -72,6 +72,8 @@ namespace Ryujinx.Graphics.Vulkan
public IWindow Window => _window;
public SurfaceTransformFlagsKHR CurrentTransform => _window.CurrentTransform;
private readonly Func<Instance, Vk, SurfaceKHR> _getSurface;
private readonly Func<string[]> _getRequiredExtensions;
private readonly string _preferredGpuId;

View File

@ -132,6 +132,8 @@ namespace Ryujinx.Graphics.Vulkan
var oldSwapchain = _swapchain;
CurrentTransform = capabilities.CurrentTransform;
var swapchainCreateInfo = new SwapchainCreateInfoKHR
{
SType = StructureType.SwapchainCreateInfoKhr,
@ -143,7 +145,7 @@ namespace Ryujinx.Graphics.Vulkan
ImageUsage = ImageUsageFlags.ColorAttachmentBit | ImageUsageFlags.TransferDstBit | ImageUsageFlags.StorageBit,
ImageSharingMode = SharingMode.Exclusive,
ImageArrayLayers = 1,
PreTransform = Ryujinx.Common.SystemInfo.SystemInfo.IsAndroid() ? SurfaceTransformFlagsKHR.IdentityBitKhr : capabilities.CurrentTransform,
PreTransform = capabilities.CurrentTransform,
CompositeAlpha = ChooseCompositeAlpha(capabilities.SupportedCompositeAlpha),
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
Clipped = true,

View File

@ -1,4 +1,5 @@
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
namespace Ryujinx.Graphics.Vulkan
@ -7,6 +8,8 @@ namespace Ryujinx.Graphics.Vulkan
{
public bool ScreenCaptureRequested { get; set; }
public SurfaceTransformFlagsKHR CurrentTransform { get; set; }
public abstract void Dispose();
public abstract void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback);
public abstract void SetSize(int width, int height);

View File

@ -0,0 +1,305 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Copyright © 2021 The Android Open Source Project
#pragma once
/* A collection of various types from AOSP that allow us to access private APIs for Native Window which we utilize for emulating the guest SF more accurately */
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=29;drc=cb496acbe593326e8d5d563847067d02b2df40ec
*/
#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=34-38;drc=cb496acbe593326e8d5d563847067d02b2df40ec
*/
#define ANDROID_NATIVE_MAKE_CONSTANT(a, b, c, d) \
((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
(ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
(ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
(ANDROID_NATIVE_UNSIGNED_CAST(d)))
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=60;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
*/
#define ANDROID_NATIVE_WINDOW_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
constexpr int AndroidNativeWindowMagic{ANDROID_NATIVE_WINDOW_MAGIC};
#undef ANDROID_NATIVE_WINDOW_MAGIC
#undef ANDROID_NATIVE_MAKE_CONSTANT
#undef ANDROID_NATIVE_UNSIGNED_CAST
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=325-331;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
*/
constexpr int64_t NativeWindowTimestampAuto{-9223372036854775807LL - 1};
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=198-259;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
*/
enum {
NATIVE_WINDOW_CONNECT = 1, /* deprecated */
NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
NATIVE_WINDOW_SET_CROP = 3, /* private */
NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
NATIVE_WINDOW_LOCK = 11, /* private */
NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
NATIVE_WINDOW_API_CONNECT = 13, /* private */
NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
NATIVE_WINDOW_SET_AUTO_PREROTATION = 35,
NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */
NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
NATIVE_WINDOW_SET_FRAME_RATE = 40,
NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR = 41, /* private */
NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR = 42, /* private */
NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */
NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */
};
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=43-56;drc=cb496acbe593326e8d5d563847067d02b2df40ec
*/
struct android_native_base_t {
int magic;
int version;
void *reserved[4];
void (*incRef)(android_native_base_t *);
void (*decRef)(android_native_base_t *);
};
/**
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=341-560;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
*/
struct ANativeWindow {
struct android_native_base_t common;
/* flags describing some attributes of this surface or its updater */
const uint32_t flags;
/* min swap interval supported by this updated */
const int minSwapInterval;
/* max swap interval supported by this updated */
const int maxSwapInterval;
/* horizontal and vertical resolution in DPI */
const float xdpi;
const float ydpi;
/* Some storage reserved for the OEM's driver. */
intptr_t oem[4];
/*
* Set the swap interval for this surface.
*
* Returns 0 on success or -errno on error.
*/
int (*setSwapInterval)(struct ANativeWindow *window,
int interval);
/*
* Hook called by EGL to acquire a buffer. After this call, the buffer
* is not locked, so its content cannot be modified. This call may block if
* no buffers are available.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* Returns 0 on success or -errno on error.
*
* XXX: This function is deprecated. It will continue to work for some
* time for binary compatibility, but the new dequeueBuffer function that
* outputs a fence file descriptor should be used in its place.
*/
int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow *window,
struct ANativeWindowBuffer **buffer);
/*
* hook called by EGL to lock a buffer. This MUST be called before modifying
* the content of a buffer. The buffer must have been acquired with
* dequeueBuffer first.
*
* Returns 0 on success or -errno on error.
*
* XXX: This function is deprecated. It will continue to work for some
* time for binary compatibility, but it is essentially a no-op, and calls
* to it should be removed.
*/
int (*lockBuffer_DEPRECATED)(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer);
/*
* Hook called by EGL when modifications to the render buffer are done.
* This unlocks and post the buffer.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* Buffers MUST be queued in the same order than they were dequeued.
*
* Returns 0 on success or -errno on error.
*
* XXX: This function is deprecated. It will continue to work for some
* time for binary compatibility, but the new queueBuffer function that
* takes a fence file descriptor should be used in its place (pass a value
* of -1 for the fence file descriptor if there is no valid one to pass).
*/
int (*queueBuffer_DEPRECATED)(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer);
/*
* hook used to retrieve information about the native window.
*
* Returns 0 on success or -errno on error.
*/
int (*query)(const struct ANativeWindow *window,
int what, int *value);
/*
* hook used to perform various operations on the surface.
* (*perform)() is a generic mechanism to add functionality to
* ANativeWindow while keeping backward binary compatibility.
*
* DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions
* defined below.
*
* (*perform)() returns -ENOENT if the 'what' parameter is not supported
* by the surface's implementation.
*
* See above for a list of valid operations, such as
* NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
*/
int (*perform)(struct ANativeWindow *window,
int operation, ...);
/*
* Hook used to cancel a buffer that has been dequeued.
* No synchronization is performed between dequeue() and cancel(), so
* either external synchronization is needed, or these functions must be
* called from the same thread.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* XXX: This function is deprecated. It will continue to work for some
* time for binary compatibility, but the new cancelBuffer function that
* takes a fence file descriptor should be used in its place (pass a value
* of -1 for the fence file descriptor if there is no valid one to pass).
*/
int (*cancelBuffer_DEPRECATED)(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer);
/*
* Hook called by EGL to acquire a buffer. This call may block if no
* buffers are available.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* The libsync fence file descriptor returned in the int pointed to by the
* fenceFd argument will refer to the fence that must signal before the
* dequeued buffer may be written to. A value of -1 indicates that the
* caller may access the buffer immediately without waiting on a fence. If
* a valid file descriptor is returned (i.e. any value except -1) then the
* caller is responsible for closing the file descriptor.
*
* Returns 0 on success or -errno on error.
*/
int (*dequeueBuffer)(struct ANativeWindow *window,
struct ANativeWindowBuffer **buffer, int *fenceFd);
/*
* Hook called by EGL when modifications to the render buffer are done.
* This unlocks and post the buffer.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* The fenceFd argument specifies a libsync fence file descriptor for a
* fence that must signal before the buffer can be accessed. If the buffer
* can be accessed immediately then a value of -1 should be used. The
* caller must not use the file descriptor after it is passed to
* queueBuffer, and the ANativeWindow implementation is responsible for
* closing it.
*
* Returns 0 on success or -errno on error.
*/
int (*queueBuffer)(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer, int fenceFd);
/*
* Hook used to cancel a buffer that has been dequeued.
* No synchronization is performed between dequeue() and cancel(), so
* either external synchronization is needed, or these functions must be
* called from the same thread.
*
* The window holds a reference to the buffer between dequeueBuffer and
* either queueBuffer or cancelBuffer, so clients only need their own
* reference if they might use the buffer after queueing or canceling it.
* Holding a reference to a buffer after queueing or canceling it is only
* allowed if a specific buffer count has been set.
*
* The fenceFd argument specifies a libsync fence file decsriptor for a
* fence that must signal before the buffer can be accessed. If the buffer
* can be accessed immediately then a value of -1 should be used.
*
* Note that if the client has not waited on the fence that was returned
* from dequeueBuffer, that same fence should be passed to cancelBuffer to
* ensure that future uses of the buffer are preceded by a wait on that
* fence. The caller must not use the file descriptor after it is passed
* to cancelBuffer, and the ANativeWindow implementation is responsible for
* closing it.
*
* Returns 0 on success or -errno on error.
*/
int (*cancelBuffer)(struct ANativeWindow *window,
struct ANativeWindowBuffer *buffer, int fenceFd);
};

View File

@ -18,6 +18,7 @@
#include <cassert>
#include <fcntl.h>
#include "libraries/adrenotools/include/adrenotools/driver.h"
#include "native_window.h"
// A macro to pass call to Vulkan and check for return value for success
#define CALL_VK(func) \

View File

@ -52,7 +52,6 @@ extern "C"
jobject instance,
jobject surface) {
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
return nativeWindow == NULL ? -1 : (jlong) nativeWindow;
}
@ -67,28 +66,6 @@ extern "C"
ANativeWindow_release(nativeWindow);
}
JNIEXPORT jlong JNICALL
Java_org_ryujinx_android_NativeHelpers_createSurface(
JNIEnv *env,
jobject instance,
jlong vulkanInstance,
jlong window) {
auto nativeWindow = (ANativeWindow *) window;
if (nativeWindow != NULL)
return -1;
VkSurfaceKHR surface;
auto vkInstance = VkInstance(vulkanInstance);
auto fpCreateAndroidSurfaceKHR =
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance, "vkCreateAndroidSurfaceKHR"));
if (!fpCreateAndroidSurfaceKHR)
return -1;
VkAndroidSurfaceCreateInfoKHR info = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR };
info.window = nativeWindow;
VK_CHECK(fpCreateAndroidSurfaceKHR(vkInstance, &info, nullptr, &surface));
return (jlong)surface;
}
JNIEXPORT void JNICALL
Java_org_ryujinx_android_NativeHelpers_attachCurrentThread(
JNIEnv *env,
@ -192,6 +169,54 @@ void onFrameEnd(double time) {
nano);
}
extern "C"
void setCurrentTransform(long native_window, int transform){
if(native_window == 0 || native_window == -1)
return;
auto nativeWindow = (ANativeWindow *) native_window;
auto nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
transform = transform >> 1;
// transform is a valid VkSurfaceTransformFlagBitsKHR
switch (transform) {
case 0x1:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
break;
case 0x2:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
break;
case 0x4:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_180;
break;
case 0x8:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_270;
break;
case 0x10:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL;
break;
case 0x20:
nativeTransform = static_cast<ANativeWindowTransform>(
ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
ANATIVEWINDOW_TRANSFORM_ROTATE_90);
break;
case 0x40:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL;
break;
case 0x80:
nativeTransform = static_cast<ANativeWindowTransform>(
ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
ANATIVEWINDOW_TRANSFORM_ROTATE_90);
break;
case 0x100:
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
break;
}
nativeWindow->perform(nativeWindow, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, static_cast<int32_t>(nativeTransform));
}
extern "C"
JNIEXPORT jlong JNICALL
Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
@ -231,3 +256,30 @@ JNIEXPORT void JNICALL
Java_org_ryujinx_android_NativeHelpers_setTurboMode(JNIEnv *env, jobject thiz, jboolean enable) {
adrenotools_set_turbo(enable);
}
extern "C"
JNIEXPORT jint JNICALL
Java_org_ryujinx_android_NativeHelpers_getMaxSwapInterval(JNIEnv *env, jobject thiz,
jlong native_window) {
auto nativeWindow = (ANativeWindow *) native_window;
return nativeWindow->maxSwapInterval;
}
extern "C"
JNIEXPORT jint JNICALL
Java_org_ryujinx_android_NativeHelpers_getMinSwapInterval(JNIEnv *env, jobject thiz,
jlong native_window) {
auto nativeWindow = (ANativeWindow *) native_window;
return nativeWindow->minSwapInterval;
}
extern "C"
JNIEXPORT jint JNICALL
Java_org_ryujinx_android_NativeHelpers_setSwapInterval(JNIEnv *env, jobject thiz,
jlong native_window, jint swap_interval) {
auto nativeWindow = (ANativeWindow *) native_window;
return nativeWindow->setSwapInterval(nativeWindow, swap_interval);
}

View File

@ -21,11 +21,14 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
private var _guestThread: Thread? = null
private var _isInit: Boolean = false
private var _isStarted: Boolean = false
private val nativeWindow : NativeWindow
private var _nativeRyujinx: RyujinxNative = RyujinxNative()
init {
holder.addCallback(this)
nativeWindow = NativeWindow(this)
}
override fun surfaceCreated(holder: SurfaceHolder) {
@ -38,9 +41,10 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
if(_width != width || _height != height)
{
val nativeHelpers = NativeHelpers()
val window = nativeHelpers.getNativeWindow(holder.surface)
_nativeRyujinx.graphicsSetSurface(window)
val window = nativeWindow.requeryWindowHandle()
_nativeRyujinx.graphicsSetSurface(window, nativeWindow.nativePointer)
nativeWindow.swapInterval = 0;
}
_width = width

View File

@ -9,14 +9,21 @@ class NativeHelpers {
System.loadLibrary("ryujinxjni")
}
}
external fun releaseNativeWindow(window: Long)
external fun createSurface(vkInstance:Long, window:Long) : Long
external fun getCreateSurfacePtr(): Long
external fun getNativeWindow(surface: Surface): Long
external fun attachCurrentThread()
external fun detachCurrentThread()
external fun loadDriver(nativeLibPath:String, privateAppsPath:String, driverName:String) : Long
external fun loadDriver(
nativeLibPath: String,
privateAppsPath: String,
driverName: String
): Long
external fun setTurboMode(enable: Boolean)
external fun getMaxSwapInterval(nativeWindow: Long): Int
external fun getMinSwapInterval(nativeWindow: Long): Int
external fun setSwapInterval(nativeWindow: Long, swapInterval: Int): Int
}

View File

@ -0,0 +1,42 @@
package org.ryujinx.android
import android.view.SurfaceView
class NativeWindow(val surface: SurfaceView) {
var nativePointer: Long
var nativeHelpers: NativeHelpers = NativeHelpers()
private var _swapInterval : Int = 0
var maxSwapInterval : Int = 0
get() {
return if (nativePointer == -1L) 0 else nativeHelpers.getMaxSwapInterval(nativePointer)
}
var minSwapInterval : Int = 0
get() {
return if (nativePointer == -1L) 0 else nativeHelpers.getMinSwapInterval(nativePointer)
}
var swapInterval : Int
get() {
return _swapInterval
}
set(value) {
if(nativePointer == -1L || nativeHelpers.setSwapInterval(nativePointer, value) == 0)
_swapInterval = value
}
init {
nativePointer = nativeHelpers.getNativeWindow(surface.holder.surface);
swapInterval = maxOf(1, minSwapInterval)
}
fun requeryWindowHandle() : Long {
nativePointer = nativeHelpers.getNativeWindow(surface.holder.surface)
swapInterval = swapInterval
return nativePointer
}
}

View File

@ -47,7 +47,7 @@ class RyujinxNative {
external fun inputSetButtonReleased(button: Int, id: Int)
external fun inputConnectGamepad(index: Int): Int
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int)
external fun graphicsSetSurface(surface: Long)
external fun graphicsSetSurface(surface: Long, window: Long)
external fun deviceCloseEmulation()
external fun deviceSignalEmulationClose()
external fun deviceGetDlcTitleId(path: String, ncaPath: String) : String