updated documentation on UILayer and GameSurfaceLayer (C++)

This commit is contained in:
amwatson 2024-02-10 15:16:10 -06:00
parent 3d1e4a38e5
commit 1cb2346ece
4 changed files with 88 additions and 26 deletions

View file

@ -144,6 +144,7 @@ abstract class VrUILayer(
onSurfaceCreated()
}
/*** Debug/Testing */
fun writeBitmapToDisk(bmp: Bitmap, outName: String?) {
val sdCard = activity.externalCacheDir
if (sdCard != null && outName != null) {

View file

@ -78,6 +78,7 @@ public:
/** Constructor.
* @param position: position of the layer, in world space
* @param jni: the JNI environment. Should be attached to the current thread
* @param activity object: reference to the current activity. Used to get
* the class information for gameSurfaceClass
* @param session a valid XrSession
@ -91,13 +92,14 @@ public:
*/
void SetSurface() const;
/** Called once-per-frame. Populates the given layer descriptor to show the
/** Called once-per-frame. Populates the layer list to show the
* top and bottom panels as two separate layers.
*
* @param space the XrSpace this layer should be positioned with. The
* center of the layer is placed in the center of the FOV.
* @param layers the array of layers to populate
* @param layerCount the number of layers in the array
* @param layerCount the layer count passed to XrEndFrame. This is incremented by
* the number of layers added by this function.
*/
void Frame(const XrSpace& space, std::vector<XrCompositionLayer>& layers,
uint32_t& layerCount) const;

View file

@ -1,16 +1,17 @@
/*******************************************************************************
/***************************************************************************************************
Filename : UILayer.cpp
Filename : UILayer.h
Content : Handles the projection of the "Game Surface" panels into XR.
Includes the "top" panel (stereo game screen) and the "bottom"
panel (mono touchpad).
Content : Utility class for creating interactive Android UI windows that
are displayed in the VR environment.
Authors : Amanda M. Watson
License : Licensed under GPLv3 or any later version.
Refer to the license.txt file included.
*******************************************************************************/
***************************************************************************************************/
#include "UILayer.h"
@ -31,12 +32,7 @@ License : Licensed under GPLv3 or any later version.
namespace {
/** Used to translate texture coordinates into the corresponding coordinates
* on the Android Activity Window.
*
* EmulationActivity still thinks its window
* (invisible) shows the game surface, so when we forward touch events to
* corresponding coordinates on the window, it will be as if the user touched
* the game surface.
* on the virtual Window.
*/
class AndroidWindowBounds {
public:
@ -87,6 +83,7 @@ struct BoundsHandle {
//-----------------------------------------------------------------------------
// JNI functions
extern "C" JNIEXPORT void JNICALL
Java_org_citra_citra_1emu_vr_ui_VrUILayer_00024Companion_nativeSetBounds(JNIEnv* env, jobject thiz,
jlong handle, jint left,

View file

@ -1,16 +1,77 @@
/***************************************************************************************************
Filename : UILayer.h
Content : Utility class for creating interactive Android UI windows that
are displayed in the VR environment.
The UILayer manages two things:
1. a virtual display window that is created and managed by the
Android OS. This window is used to display the UI.
2. A surface-backed XrSwapchain that the virtual window renders into.
From Android's perspective, it's rendering a group of views to a secondary
display, while in reality it's rendering to a surface that is composited
into the VR environment.
UILayer will translate clicks on the VR layer into touch events on the corresponding
Android window.
This method is relatively efficient, but it must be used carefully. It
will only render the UI when the UI has changed; however, it will continue rendering
when the UI is not visible if there are updates. Additionally, while the UIs I am
using are small enough that < 10MiB in RAM/GPU memory respectively, it could be
a dumb, costly use of GPU resources to allocate huge, high-resolution UIs on init
that are rarely used.
Therefore, be careful on the front-end: don't create UIs that animate/update while
they aren't visible, and don't create UIs that are too large. If these are needed,
use another technique.
(note: if rendering expensive UIs for occasional use is ever necessary, note that,
because CitraVR is made of compositor layers on top of a compositor-rendered
background, there is 0 risk of juddering due to missed frame updates. Therefore,
you can get awaay with something most VR apps cannot: you can miss a bunch of
frames in order to do an expensive one-time operation on the render thread in the
frame loop -- like allocate a swapchain and construct a UI over a multi-frame period
(dropping all frames in the process) -- with 0 risk of judder. If you are certain
you can successfully de-init an expensive UI after it's used without any dangling
resources, just do that instead of having it persist from init. The
TryCreateSwapchain() paradigm is designed to support this, though you need to
add a de-init function)
Authors : Amanda M. Watson
License : Licensed under GPLv3 or any later version.
Refer to the license.txt file included.
***************************************************************************************************/
#pragma once
#include "../OpenXR.h"
#include "../Swapchain.h"
#include "../utils/Common.h"
#include <string>
/*
================================================================================
UILayer
================================================================================
*/
class UILayer {
public:
/** Constructor.
* @param position: position of the layer, in world space
* @param className: the class name of the Java class representing the UI layer.
* This class should subclass org.citra.citra_emu.ui.VrUILayer.
* @param position: position of the layer
* @param orientation: orientation of the layer
* @param jni: the JNI environment. Should be attached to the current thread
* @param activity object: reference to the current activity. Used to get
* the class information for gameSurfaceClass
* the class information for UILayer
* @param session a valid XrSession
*/
UILayer(const std::string& className, const XrVector3f&& position,
@ -18,18 +79,14 @@ public:
const XrSession& session);
~UILayer();
/** Called on resume. Sets the surface in the native rendering library.
* Overrides the normal surface passed by Citra
*/
void SetSurface() const;
/** Called once-per-frame. Populates the given layer descriptor to show the
* top and bottom panels as two separate layers.
/** Called once-per-frame. Populates the given layer list with a single layer
* representing the UI layer.
*
* @param space the XrSpace this layer should be positioned with. The
* center of the layer is placed in the center of the FOV.
* @param layers the array of layers to populate
* @param layerCount the number of layers in the array
* @param layerCount the layer count passed to XrEndFrame. This is incremented by
* the number of layers added by this function.
*/
void Frame(const XrSpace& space, std::vector<XrCompositionLayer>& layers,
uint32_t& layerCount) const;
@ -66,6 +123,12 @@ public:
*/
void TryCreateSwapchain();
/** Forwards the click event to the corresponding position on the Android UI window.
* @param pos2d the 2D position of the click in the Android display coordinate
* system.
* @param type the type of the click event. 0 for down, 1 for up, 2 for movement (while cursor
* is already pressed).
*/
void SendClickToUI(const XrVector2f& pos2d, const int type);
private:
@ -73,13 +136,12 @@ private:
const XrSession& session);
void Shutdown();
bool mIsSwapchainCreated = false;
const XrSession mSession;
Swapchain mSwapchain;
XrPosef mPanelFromWorld;
bool mIsSwapchainCreated = false;
//============================
// JNI objects
JNIEnv* mEnv = nullptr;