clang-formatted code from my clang-format to citra's (I like mine better, but it's easier that way)

This commit is contained in:
amwatson 2024-01-16 18:33:27 -06:00
parent 51147c49be
commit b3b21894ae
19 changed files with 1150 additions and 1697 deletions

View file

@ -14,23 +14,19 @@ License : Licensed under GPLv2 or any later version.
#include "utils/LogUtils.h"
#include "utils/XrMath.h"
namespace
{
namespace {
constexpr uint32_t CURSOR_WIDTH = 16;
constexpr uint32_t CURSOR_HEIGHT = CURSOR_WIDTH;
constexpr uint32_t CURSOR_WIDTH = 16;
constexpr uint32_t CURSOR_HEIGHT = CURSOR_WIDTH;
constexpr uint32_t SUPER_SAMPLE_FACTOR = 2;
constexpr uint8_t CURSOR_ALPHA = 255;
constexpr uint8_t COLOR_WHITE_RGB[3] = {255, 255,
255}; // White color for the cursor.
constexpr uint8_t COLOR_CYAN_RGB[3] = {10, 185,
180}; // Cyan color for the cursor.
constexpr uint8_t COLOR_WHITE_RGB[3] = {255, 255, 255}; // White color for the cursor.
constexpr uint8_t COLOR_CYAN_RGB[3] = {10, 185, 180}; // Cyan color for the cursor.
constexpr uint8_t OUTLINE_COLOR_RGB[3] = {0, 0,
0}; // Black color for the outline.
constexpr uint32_t OUTLINE_THICKNESS = 2;
constexpr uint8_t OUTLINE_COLOR_RGB[3] = {0, 0, 0}; // Black color for the outline.
constexpr uint32_t OUTLINE_THICKNESS = 2;
typedef std::array<uint8_t, CURSOR_WIDTH * CURSOR_HEIGHT * 4> CursorBuffer;
@ -41,24 +37,23 @@ typedef std::array<uint8_t, CURSOR_WIDTH * CURSOR_HEIGHT * 4> CursorBuffer;
#warning "CursorLayer.cpp is designed to be compiled with C++17 or later."
#endif
Swapchain CreateSwapchain(const XrSession& session)
{
Swapchain swapchain;
Swapchain CreateSwapchain(const XrSession& session) {
Swapchain swapchain;
XrSwapchainCreateInfo swapChainCreateInfo;
memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo));
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapChainCreateInfo.createFlags = XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
swapChainCreateInfo.format = GL_SRGB8_ALPHA8;
swapChainCreateInfo.usageFlags =
XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
swapChainCreateInfo.format = GL_SRGB8_ALPHA8;
swapChainCreateInfo.sampleCount = 1;
swapChainCreateInfo.width = CURSOR_WIDTH;
swapChainCreateInfo.height = CURSOR_HEIGHT;
swapChainCreateInfo.faceCount = 1;
swapChainCreateInfo.arraySize = 1;
swapChainCreateInfo.mipCount = 1;
swapChainCreateInfo.width = CURSOR_WIDTH;
swapChainCreateInfo.height = CURSOR_HEIGHT;
swapChainCreateInfo.faceCount = 1;
swapChainCreateInfo.arraySize = 1;
swapChainCreateInfo.mipCount = 1;
swapchain.Width = swapChainCreateInfo.width;
swapchain.Width = swapChainCreateInfo.width;
swapchain.Height = swapChainCreateInfo.height;
// Create the swapchain.
@ -66,16 +61,14 @@ Swapchain CreateSwapchain(const XrSession& session)
return swapchain;
}
std::vector<XrSwapchainImageOpenGLESKHR>
CreateSwapchainImages(const XrSession& session, const XrSwapchain& xrSwapchain)
{
std::vector<XrSwapchainImageOpenGLESKHR> CreateSwapchainImages(const XrSession& session,
const XrSwapchain& xrSwapchain) {
uint32_t length;
OXR(xrEnumerateSwapchainImages(xrSwapchain, 0, &length, NULL));
std::vector<XrSwapchainImageOpenGLESKHR> images =
std::vector<XrSwapchainImageOpenGLESKHR>(length);
for (size_t i = 0; i < images.size(); i++)
{
for (size_t i = 0; i < images.size(); i++) {
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
images[i].next = NULL;
}
@ -85,48 +78,37 @@ CreateSwapchainImages(const XrSession& session, const XrSwapchain& xrSwapchain)
return images;
}
CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
{
constexpr uint32_t SUPER_WIDTH = CURSOR_WIDTH * SUPER_SAMPLE_FACTOR;
CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3]) {
constexpr uint32_t SUPER_WIDTH = CURSOR_WIDTH * SUPER_SAMPLE_FACTOR;
constexpr uint32_t SUPER_HEIGHT = CURSOR_HEIGHT * SUPER_SAMPLE_FACTOR;
uint8_t superCursorData[SUPER_WIDTH * SUPER_HEIGHT * 4];
uint8_t superCursorData[SUPER_WIDTH * SUPER_HEIGHT * 4];
// Create the high-res cursor.
{
constexpr uint32_t superCenterX = SUPER_WIDTH / 2;
constexpr uint32_t superCenterY = SUPER_HEIGHT / 2;
constexpr uint32_t superRadius =
SUPER_WIDTH / 2; // Adjust the radius as needed.
constexpr uint32_t superOutlineThickness =
OUTLINE_THICKNESS * SUPER_SAMPLE_FACTOR;
constexpr uint32_t superRadius = SUPER_WIDTH / 2; // Adjust the radius as needed.
constexpr uint32_t superOutlineThickness = OUTLINE_THICKNESS * SUPER_SAMPLE_FACTOR;
for (uint32_t y = 0; y < SUPER_HEIGHT; y++)
{
for (uint32_t x = 0; x < SUPER_WIDTH; x++)
{
const uint32_t index = (y * SUPER_WIDTH + x) * 4;
const int32_t dx = x - superCenterX;
const int32_t dy = y - superCenterY;
for (uint32_t y = 0; y < SUPER_HEIGHT; y++) {
for (uint32_t x = 0; x < SUPER_WIDTH; x++) {
const uint32_t index = (y * SUPER_WIDTH + x) * 4;
const int32_t dx = x - superCenterX;
const int32_t dy = y - superCenterY;
const uint32_t distanceSquared = dx * dx + dy * dy;
if (distanceSquared < (superRadius * superRadius) &&
distanceSquared >= ((superRadius - superOutlineThickness) *
(superRadius - superOutlineThickness)))
{
(superRadius - superOutlineThickness))) {
// Pixel is part of the outline.
memcpy(&superCursorData[index], OUTLINE_COLOR_RGB, 3);
superCursorData[index + 3] = CURSOR_ALPHA;
}
else if (distanceSquared <
((superRadius - superOutlineThickness) *
(superRadius - superOutlineThickness)))
{
} else if (distanceSquared < ((superRadius - superOutlineThickness) *
(superRadius - superOutlineThickness))) {
// Pixel is inside the circle.
memcpy(&superCursorData[index], colorRGB, 3);
superCursorData[index + 3] = CURSOR_ALPHA;
}
else
{
} else {
// Pixel is outside the circle (transparent).
memset(&superCursorData[index], 0, 4);
}
@ -136,21 +118,16 @@ CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
CursorBuffer cursorData;
// Downsample to the final image.
for (uint32_t y = 0; y < CURSOR_HEIGHT; y++)
{
for (uint32_t x = 0; x < CURSOR_WIDTH; x++)
{
for (uint32_t y = 0; y < CURSOR_HEIGHT; y++) {
for (uint32_t x = 0; x < CURSOR_WIDTH; x++) {
uint32_t index = (y * CURSOR_WIDTH + x) * 4;
uint32_t r = 0, g = 0, b = 0, a = 0;
for (uint32_t dy = 0; dy < SUPER_SAMPLE_FACTOR; dy++)
{
for (uint32_t dx = 0; dx < SUPER_SAMPLE_FACTOR; dx++)
{
const uint32_t superIndex =
((y * SUPER_SAMPLE_FACTOR + dy) * SUPER_WIDTH +
(x * SUPER_SAMPLE_FACTOR + dx)) *
4;
for (uint32_t dy = 0; dy < SUPER_SAMPLE_FACTOR; dy++) {
for (uint32_t dx = 0; dx < SUPER_SAMPLE_FACTOR; dx++) {
const uint32_t superIndex = ((y * SUPER_SAMPLE_FACTOR + dy) * SUPER_WIDTH +
(x * SUPER_SAMPLE_FACTOR + dx)) *
4;
r += superCursorData[superIndex];
g += superCursorData[superIndex + 1];
b += superCursorData[superIndex + 2];
@ -159,81 +136,65 @@ CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
}
cursorData[index] = r / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 1] =
g / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 2] =
b / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 3] =
a / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 1] = g / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 2] = b / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
cursorData[index + 3] = a / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
}
}
return cursorData;
}
void GenerateCursorImage(
const XrSwapchain& xrSwapchain,
const std::vector<XrSwapchainImageOpenGLESKHR>& xrImages,
const uint8_t colorRGB[3])
{
void GenerateCursorImage(const XrSwapchain& xrSwapchain,
const std::vector<XrSwapchainImageOpenGLESKHR>& xrImages,
const uint8_t colorRGB[3]) {
const CursorBuffer cursorData = CreateSuperSampledCursorBuffer(colorRGB);
uint32_t index = 0;
XrSwapchainImageAcquireInfo acquireInfo = {
XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
uint32_t index = 0;
XrSwapchainImageAcquireInfo acquireInfo = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
OXR(xrAcquireSwapchainImage(xrSwapchain, &acquireInfo, &index));
XrSwapchainImageWaitInfo waitInfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO,
NULL, 0};
XrSwapchainImageWaitInfo waitInfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, NULL, 0};
OXR(xrWaitSwapchainImage(xrSwapchain, &waitInfo));
glBindTexture(GL_TEXTURE_2D, xrImages[0].image);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CURSOR_WIDTH, CURSOR_HEIGHT,
GL_RGBA, GL_UNSIGNED_BYTE, cursorData.data());
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CURSOR_WIDTH, CURSOR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE,
cursorData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
XrSwapchainImageReleaseInfo releaseInfo = {
XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(xrSwapchain, &releaseInfo));
}
} // anonymous namespace
CursorLayer::CursorImage::CursorImage(const XrSession& session,
const uint8_t colorRGB[3])
{
mSwapchain = CreateSwapchain(session);
CursorLayer::CursorImage::CursorImage(const XrSession& session, const uint8_t colorRGB[3]) {
mSwapchain = CreateSwapchain(session);
mSwapchainImages = CreateSwapchainImages(session, mSwapchain.Handle);
GenerateCursorImage(mSwapchain.Handle, mSwapchainImages, colorRGB);
}
CursorLayer::CursorImage::~CursorImage()
{
if (mSwapchain.Handle != XR_NULL_HANDLE)
{
CursorLayer::CursorImage::~CursorImage() {
if (mSwapchain.Handle != XR_NULL_HANDLE) {
xrDestroySwapchain(mSwapchain.Handle);
}
// destroy images.
for (size_t i = 0; i < mSwapchainImages.size(); i++)
{
for (size_t i = 0; i < mSwapchainImages.size(); i++) {
glDeleteTextures(1, &mSwapchainImages[i].image);
}
}
CursorLayer::CursorLayer(const XrSession& session)
: mCursorImages({CursorImage(session, COLOR_WHITE_RGB),
CursorImage(session, COLOR_CYAN_RGB)})
{
: mCursorImages({CursorImage(session, COLOR_WHITE_RGB), CursorImage(session, COLOR_CYAN_RGB)}) {
}
void CursorLayer::Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
const XrPosef& cursorPose, const float scaleFactor,
const CursorType& cursorType) const
{
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
const CursorType& cursorType) const {
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
@ -242,15 +203,14 @@ void CursorLayer::Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
const auto& swapchain =
mCursorImages.at(static_cast<size_t>(cursorType)).GetSwapchain();
layer.subImage.swapchain = swapchain.Handle;
layer.subImage.imageRect.offset.x = 0;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.imageRect.extent.width = swapchain.Width;
const auto& swapchain = mCursorImages.at(static_cast<size_t>(cursorType)).GetSwapchain();
layer.subImage.swapchain = swapchain.Handle;
layer.subImage.imageRect.offset.x = 0;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.imageRect.extent.width = swapchain.Width;
layer.subImage.imageRect.extent.height = swapchain.Height;
layer.size.width = scaleFactor;
layer.size.width = scaleFactor;
layer.size.height = layer.size.width * swapchain.Height / swapchain.Width;
layer.subImage.imageArrayIndex = 0;
layer.pose = cursorPose;
layer.pose = cursorPose;
}

View file

@ -17,7 +17,7 @@ License : Licensed under GPLv2 or any later version.
#include <EGL/egl.h>
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_PLATFORM_ANDROID 1
#include <openxr/openxr_platform.h>
@ -32,18 +32,12 @@ CursorLayer
================================================================================
*/
class CursorLayer
{
class CursorLayer {
public:
/** The type of cursor to render.
* Determines the color of the cursor.
**/
enum class CursorType
{
CURSOR_TYPE_NORMAL,
CURSOR_TYPE_TOP_PANEL,
NUM_CURSOR_TYPES
};
enum class CursorType { CURSOR_TYPE_NORMAL, CURSOR_TYPE_TOP_PANEL, NUM_CURSOR_TYPES };
/**
* @param session a valid XR Session
*/
@ -58,14 +52,12 @@ public:
* @param scaleFactor the scale factor to apply to the cursor
* @param cursorType the type of cursor to render
*/
void Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
const XrPosef& cursorPose, const float scaleFactor,
const CursorType& cursorType) const;
void Frame(const XrSpace& space, XrCompositionLayerQuad& layer, const XrPosef& cursorPose,
const float scaleFactor, const CursorType& cursorType) const;
private:
/** Helper class to manage the cursor image. */
class CursorImage
{
class CursorImage {
public:
/** Create a new cursor image.
*
@ -76,13 +68,14 @@ private:
~CursorImage();
/** Get the swapchain used to render the cursor. */
const Swapchain& GetSwapchain() const { return mSwapchain; }
const Swapchain& GetSwapchain() const {
return mSwapchain;
}
private:
Swapchain mSwapchain;
Swapchain mSwapchain;
std::vector<XrSwapchainImageOpenGLESKHR> mSwapchainImages;
};
std::array<CursorImage, static_cast<size_t>(CursorType::NUM_CURSOR_TYPES)>
mCursorImages;
std::array<CursorImage, static_cast<size_t>(CursorType::NUM_CURSOR_TYPES)> mCursorImages;
};

View file

@ -26,8 +26,7 @@ License : Licensed under GPLv2 or any later version.
#include <stdlib.h>
namespace
{
namespace {
constexpr float kLowerPanelScaleFactor = 0.75f;
/** Used to translate texture coordinates into the corresponding coordinates
@ -38,27 +37,26 @@ constexpr float kLowerPanelScaleFactor = 0.75f;
* corresponding coordinates on the window, it will be as if the user touched
* the game surface.
*/
class AndroidWindowSpace
{
class AndroidWindowSpace {
public:
AndroidWindowSpace(const float widthInDp, const float heightInDp)
: widthInDp_(widthInDp)
, heightInDp_(heightInDp)
{
: widthInDp_(widthInDp), heightInDp_(heightInDp) {}
float Width() const {
return widthInDp_;
}
float Height() const {
return heightInDp_;
}
float Width() const { return widthInDp_; }
float Height() const { return heightInDp_; }
// "DP" refers to display pixels, which are the same as Android's
// "density-independent pixels" (dp).
const float widthInDp_ = 0;
const float widthInDp_ = 0;
const float heightInDp_ = 0;
// given a 2D point in worldspace 'point2d', returns the transformed
// coordinate in DP, written to 'result'
void Transform(const XrVector2f& point2d, XrVector2f& result) const
{
const float width = static_cast<float>(Width());
void Transform(const XrVector2f& point2d, XrVector2f& result) const {
const float width = static_cast<float>(Width());
const float height = static_cast<float>(Height());
result.x = (point2d.x * width) + (width / 2.0f);
@ -73,65 +71,52 @@ public:
static constexpr std::chrono::milliseconds kMinTimeBetweenChecks(500);
// Get density on an interval
float GetDensitySysprop()
{
static constexpr float kDefaultDensity =
GameSurfaceLayer::DEFAULT_QUAD_DENSITY;
float GetDensitySysprop() {
static constexpr float kDefaultDensity = GameSurfaceLayer::DEFAULT_QUAD_DENSITY;
static float lastDensity = kDefaultDensity;
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
// Only check the sysprop every 500ms
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
{
lastTime = std::chrono::steady_clock::now();
lastDensity = SyspropUtils::GetSysPropAsFloat("debug.citra.density",
kDefaultDensity);
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
lastTime = std::chrono::steady_clock::now();
lastDensity = SyspropUtils::GetSysPropAsFloat("debug.citra.density", kDefaultDensity);
}
return lastDensity;
}
int32_t GetCylinderSysprop()
{
int32_t GetCylinderSysprop() {
static constexpr int32_t kDefaultCylinder = 0;
static int32_t lastCylinder = kDefaultCylinder;
static int32_t lastCylinder = kDefaultCylinder;
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
// Only check the sysprop every 500ms
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
{
lastTime = std::chrono::steady_clock::now();
lastCylinder = SyspropUtils::GetSysPropAsInt("debug.citra.cylinder",
kDefaultCylinder);
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
lastTime = std::chrono::steady_clock::now();
lastCylinder = SyspropUtils::GetSysPropAsInt("debug.citra.cylinder", kDefaultCylinder);
}
return lastCylinder;
}
float GetRadiusSysprop()
{
static constexpr float kDefaultRadius =
GameSurfaceLayer::DEFAULT_CYLINDER_RADIUS;
float GetRadiusSysprop() {
static constexpr float kDefaultRadius = GameSurfaceLayer::DEFAULT_CYLINDER_RADIUS;
static float lastRadius = kDefaultRadius;
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
// Only check the sysprop every 500ms
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
{
lastTime = std::chrono::steady_clock::now();
lastRadius = SyspropUtils::GetSysPropAsFloat("debug.citra.radius",
kDefaultRadius);
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
lastTime = std::chrono::steady_clock::now();
lastRadius = SyspropUtils::GetSysPropAsFloat("debug.citra.radius", kDefaultRadius);
}
return lastRadius;
}
float GetCentralAngleSysprop()
{
float GetCentralAngleSysprop() {
static constexpr float kDefaultCentralAngle =
GameSurfaceLayer::DEFAULT_CYLINDER_CENTRAL_ANGLE_DEGREES;
static float lastCentralAngle = kDefaultCentralAngle;
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
// Only check the sysprop every 500ms
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
{
lastTime = std::chrono::steady_clock::now();
lastCentralAngle = SyspropUtils::GetSysPropAsFloat(
"debug.citra.cylinder_degrees", kDefaultCentralAngle);
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
lastTime = std::chrono::steady_clock::now();
lastCentralAngle =
SyspropUtils::GetSysPropAsFloat("debug.citra.cylinder_degrees", kDefaultCentralAngle);
}
return lastCentralAngle;
}
@ -144,23 +129,19 @@ float GetCentralAngleSysprop()
* - Rotated 45 degrees away from viewer
* - Half the distance away from viewer as top panel
*/
XrPosef CreateLowerPanelFromWorld(const XrPosef& topPanelFromWorld)
{
XrPosef CreateLowerPanelFromWorld(const XrPosef& topPanelFromWorld) {
constexpr float kLowerPanelYOffset = -0.75f;
constexpr float kLowerPanelYOffset = -0.75f;
XrPosef lowerPanelFromWorld = topPanelFromWorld;
// Pitch the lower panel away from the viewer 45 degrees
lowerPanelFromWorld.orientation =
XrMath::Quatf::FromEuler(0.0f, -MATH_FLOAT_PI / 4.0f, 0.0f);
lowerPanelFromWorld.orientation = XrMath::Quatf::FromEuler(0.0f, -MATH_FLOAT_PI / 4.0f, 0.0f);
lowerPanelFromWorld.position.y += kLowerPanelYOffset;
lowerPanelFromWorld.position.z = -1.5f;
return lowerPanelFromWorld;
}
XrVector3f CalculatePanelPosition(const XrVector3f& viewerPosition,
const XrVector3f& controllerPosition,
float sphereRadius)
{
const XrVector3f& controllerPosition, float sphereRadius) {
// Vector from viewer to controller
XrVector3f viewerToController = controllerPosition - viewerPosition;
XrMath::Vector3f::Normalize(viewerToController);
@ -171,8 +152,7 @@ XrVector3f CalculatePanelPosition(const XrVector3f& viewerPosition,
XrQuaternionf CalculatePanelRotation(const XrVector3f& windowPosition,
const XrVector3f& viewerPosition,
const XrVector3f& upDirection)
{
const XrVector3f& upDirection) {
// Compute forward direction (normalized)
XrVector3f forward = viewerPosition - windowPosition;
XrMath::Vector3f::Normalize(forward);
@ -187,28 +167,24 @@ XrQuaternionf CalculatePanelRotation(const XrVector3f& windowPosition,
return XrMath::Quatf::FromThreeVectors(forward, up, right);
}
bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld,
const uint32_t panelWidth,
const uint32_t panelHeight,
const XrVector2f& scaleFactor,
bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld, const uint32_t panelWidth,
const uint32_t panelHeight, const XrVector2f& scaleFactor,
const XrVector3f& start, const XrVector3f& end,
XrVector2f& result2d, XrPosef& result3d)
{
const XrPosef worldFromPanel = XrMath::Posef::Inverted(panelFromWorld);
const XrVector3f localStart =
XrMath::Posef::Transform(worldFromPanel, start);
const XrPosef worldFromPanel = XrMath::Posef::Inverted(panelFromWorld);
const XrVector3f localStart = XrMath::Posef::Transform(worldFromPanel, start);
const XrVector3f localEnd = XrMath::Posef::Transform(worldFromPanel, end);
// Note: assumes layer lies in the XZ plane
const float tan = localStart.z / (localStart.z - localEnd.z);
// Check for backwards controller
if (tan < 0)
{
if (tan < 0) {
ALOGD("Backwards controller");
return false;
}
result3d.position = start + (end - start) * tan;
result3d.position = start + (end - start) * tan;
result3d.orientation = panelFromWorld.orientation;
const XrVector2f result2dNDC = {
@ -218,103 +194,88 @@ bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld,
const AndroidWindowSpace androidSpace(panelWidth, panelHeight);
androidSpace.Transform(result2dNDC, result2d);
const bool isInBounds = result2d.x >= 0 && result2d.y >= 0 &&
result2d.x < androidSpace.Width() &&
result2d.y < androidSpace.Height();
result2d.x < androidSpace.Width() && result2d.y < androidSpace.Height();
result2d.y += androidSpace.Height();
if (!isInBounds) { return false; }
if (!isInBounds) {
return false;
}
return true;
}
// Uses a density for scaling and sets aspect ratio
XrVector2f GetDensityScaleForSize(const int32_t texWidth,
const int32_t texHeight,
const float scaleFactor)
{
XrVector2f GetDensityScaleForSize(const int32_t texWidth, const int32_t texHeight,
const float scaleFactor) {
const float density = GetDensitySysprop();
return XrVector2f{2.0f * static_cast<float>(texWidth) / density,
(static_cast<float>(texHeight) / density)} *
scaleFactor;
}
XrPosef CreateTopPanelFromWorld(const XrVector3f& position)
{
XrPosef CreateTopPanelFromWorld(const XrVector3f& position) {
return XrPosef{XrMath::Quatf::Identity(), position};
}
} // anonymous namespace
GameSurfaceLayer::GameSurfaceLayer(const XrVector3f&& position, JNIEnv* env,
jobject activityObject,
GameSurfaceLayer::GameSurfaceLayer(const XrVector3f&& position, JNIEnv* env, jobject activityObject,
const XrSession& session)
: session_(session)
, topPanelFromWorld_(CreateTopPanelFromWorld(position))
, lowerPanelFromWorld_(CreateLowerPanelFromWorld(topPanelFromWorld_))
, env_(env)
, activityObject_(activityObject)
: session_(session), topPanelFromWorld_(CreateTopPanelFromWorld(position)),
lowerPanelFromWorld_(CreateLowerPanelFromWorld(topPanelFromWorld_)), env_(env),
activityObject_(activityObject)
{
const int32_t initializationStatus =
Init(activityObject, position, session);
if (initializationStatus < 0)
{
FAIL("Could not initialize GameSurfaceLayer -- error '%d'",
initializationStatus);
const int32_t initializationStatus = Init(activityObject, position, session);
if (initializationStatus < 0) {
FAIL("Could not initialize GameSurfaceLayer -- error '%d'", initializationStatus);
}
}
GameSurfaceLayer::~GameSurfaceLayer() { Shutdown(); }
void GameSurfaceLayer::SetSurface() const
{
assert(vrGameSurfaceClass_ != nullptr);
assert(setSurfaceMethodID_ != nullptr);
env_->CallStaticVoidMethod(vrGameSurfaceClass_, setSurfaceMethodID_,
activityObject_, surface_);
GameSurfaceLayer::~GameSurfaceLayer() {
Shutdown();
}
void GameSurfaceLayer::Frame(const XrSpace& space,
std::vector<XrCompositionLayer>& layers,
uint32_t& layerCount) const
void GameSurfaceLayer::SetSurface() const {
assert(vrGameSurfaceClass_ != nullptr);
assert(setSurfaceMethodID_ != nullptr);
env_->CallStaticVoidMethod(vrGameSurfaceClass_, setSurfaceMethodID_, activityObject_, surface_);
}
void GameSurfaceLayer::Frame(const XrSpace& space, std::vector<XrCompositionLayer>& layers,
uint32_t& layerCount) const
{
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelHeight = swapchain_.Height / 2;
const double aspectRatio =
const double aspectRatio =
static_cast<double>(2 * panelWidth) / static_cast<double>(panelHeight);
// Prevent a seam between the top and bottom view
constexpr uint32_t verticalBorderTex = 1;
const int32_t useCylinder = GetCylinderSysprop();
if (useCylinder == 1)
{
const int32_t useCylinder = GetCylinderSysprop();
if (useCylinder == 1) {
// Create the Top Display Panel (Curved display)
for (uint32_t eye = 0; eye < NUM_EYES; eye++)
{
for (uint32_t eye = 0; eye < NUM_EYES; eye++) {
XrCompositionLayerCylinderKHR layer = {};
layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR;
layer.layerFlags =
XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |=
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
// NOTE: may not want unpremultiplied alpha
layer.space = space;
layer.eyeVisibility =
eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
layer.eyeVisibility = eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = eye == 0 ? 0 : panelWidth;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = eye == 0 ? 0 : panelWidth;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.imageRect.extent.width = panelWidth;
layer.subImage.imageRect.extent.height =
panelHeight - verticalBorderTex;
layer.subImage.imageRect.extent.height = panelHeight - verticalBorderTex;
layer.subImage.imageArrayIndex = 0;
layer.pose = topPanelFromWorld_;
layer.pose = topPanelFromWorld_;
layer.pose.position.z += GetRadiusSysprop();
// Radius effectively controls the width of the cylinder shape.
@ -322,46 +283,37 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
// covered by the texture. Together, they control the
// scale of the texture.
const float radius = GetRadiusSysprop();
layer.radius = radius;
layer.centralAngle =
GetCentralAngleSysprop() * MATH_FLOAT_PI / 180.0f;
layer.aspectRatio = -aspectRatio;
layer.radius = radius;
layer.centralAngle = GetCentralAngleSysprop() * MATH_FLOAT_PI / 180.0f;
layer.aspectRatio = -aspectRatio;
layers[layerCount++].mCylinder = layer;
}
}
else
{
} else {
// Create the Top Display Panel (Flat display)
for (uint32_t eye = 0; eye < 2; eye++)
{
for (uint32_t eye = 0; eye < 2; eye++) {
XrCompositionLayerQuad layer = {};
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
layer.layerFlags =
XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |=
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
// NOTE: may not want unpremultiplied alpha
layer.space = space;
layer.eyeVisibility =
eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
layer.eyeVisibility = eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = (eye == 0 ? 0 : panelWidth) + 125;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = (eye == 0 ? 0 : panelWidth) + 125;
layer.subImage.imageRect.offset.y = 0;
layer.subImage.imageRect.extent.width = panelWidth - 250;
layer.subImage.imageRect.extent.height =
panelHeight - verticalBorderTex;
layer.subImage.imageRect.extent.height = panelHeight - verticalBorderTex;
layer.subImage.imageArrayIndex = 0;
layer.pose = topPanelFromWorld_;
layer.pose = topPanelFromWorld_;
// Scale to get the desired density within the visible area (if we
// want).
const auto scale =
GetDensityScaleForSize(panelWidth - 250, -panelHeight, 1.0f);
layer.size.width = scale.x;
const auto scale = GetDensityScaleForSize(panelWidth - 250, -panelHeight, 1.0f);
layer.size.width = scale.x;
layer.size.height = scale.y;
layers[layerCount++].mQuad = layer;
@ -377,10 +329,9 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
{
XrCompositionLayerQuad layer = {};
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layer.layerFlags |=
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
// NOTE: may not want unpremultiplied alpha
@ -388,69 +339,61 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = 225;
layer.subImage.imageRect.offset.y = panelHeight + verticalBorderTex;
layer.subImage.swapchain = swapchain_.Handle;
layer.subImage.imageRect.offset.x = 225;
layer.subImage.imageRect.offset.y = panelHeight + verticalBorderTex;
layer.subImage.imageRect.extent.width = panelWidth - 450;
layer.subImage.imageRect.extent.height = panelHeight;
layer.subImage.imageArrayIndex = 0;
layer.pose = lowerPanelFromWorld_;
const auto scale = GetDensityScaleForSize(panelWidth - 450, -panelHeight,
kLowerPanelScaleFactor);
layer.size.width = scale.x;
layer.subImage.imageArrayIndex = 0;
layer.pose = lowerPanelFromWorld_;
const auto scale =
GetDensityScaleForSize(panelWidth - 450, -panelHeight, kLowerPanelScaleFactor);
layer.size.width = scale.x;
layer.size.height = scale.y;
layers[layerCount++].mQuad = layer;
}
}
bool GameSurfaceLayer::GetRayIntersectionWithPanelTopPanel(
const XrVector3f& start,
const XrVector3f& end,
XrVector2f& result2d,
XrPosef& result3d) const
bool GameSurfaceLayer::GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
const XrVector3f& end,
XrVector2f& result2d,
XrPosef& result3d) const
{
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelHeight = swapchain_.Height / 2;
const auto scale = GetDensityScaleForSize(panelWidth, panelHeight, 1.0f);
return ::GetRayIntersectionWithPanel(topPanelFromWorld_, panelWidth,
panelHeight, scale, start, end,
result2d, result3d);
return ::GetRayIntersectionWithPanel(topPanelFromWorld_, panelWidth, panelHeight, scale, start,
end, result2d, result3d);
}
bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start,
const XrVector3f& end,
XrVector2f& result2d,
XrPosef& result3d) const
{
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelHeight = swapchain_.Height / 2;
bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start, const XrVector3f& end,
XrVector2f& result2d, XrPosef& result3d) const {
const uint32_t panelWidth = swapchain_.Width / 2;
const uint32_t panelHeight = swapchain_.Height / 2;
const XrVector2f scale =
GetDensityScaleForSize(panelWidth, panelHeight, kLowerPanelScaleFactor);
return ::GetRayIntersectionWithPanel(lowerPanelFromWorld_, panelWidth,
panelHeight, scale, start, end,
result2d, result3d);
return ::GetRayIntersectionWithPanel(lowerPanelFromWorld_, panelWidth, panelHeight, scale,
start, end, result2d, result3d);
}
void GameSurfaceLayer::SetTopPanelFromController(
const XrVector3f& controllerPosition)
{
void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPosition) {
static const XrVector3f viewerPosition{0, 0, 0}; // Set viewer position
const float sphereRadius = XrMath::Vector3f::Length(
topPanelFromWorld_.position -
viewerPosition); // Set the initial distance of the
const float sphereRadius = XrMath::Vector3f::Length(
topPanelFromWorld_.position - viewerPosition); // Set the initial distance of the
// window from the viewer
const XrVector3f windowUpDirection{0, 1, 0}; // Y is up
const XrVector3f windowPosition = CalculatePanelPosition(
viewerPosition, controllerPosition, sphereRadius);
const XrQuaternionf windowRotation = CalculatePanelRotation(
windowPosition, viewerPosition, windowUpDirection);
if (windowPosition.y < 0) { return; }
if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f)
{
const XrVector3f windowPosition =
CalculatePanelPosition(viewerPosition, controllerPosition, sphereRadius);
const XrQuaternionf windowRotation =
CalculatePanelRotation(windowPosition, viewerPosition, windowUpDirection);
if (windowPosition.y < 0) {
return;
}
if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f) {
return;
}
@ -458,30 +401,24 @@ void GameSurfaceLayer::SetTopPanelFromController(
}
// based on thumbstick, modify the depth of the top panel
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY)
{
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
static constexpr float kMaxDepth = -10.0f;
topPanelFromWorld_.position.z -= (thumbstickY * kDepthSpeed);
topPanelFromWorld_.position.z = std::min(topPanelFromWorld_.position.z,
lowerPanelFromWorld_.position.z);
topPanelFromWorld_.position.z =
std::max(topPanelFromWorld_.position.z, kMaxDepth);
std::min(topPanelFromWorld_.position.z, lowerPanelFromWorld_.position.z);
topPanelFromWorld_.position.z = std::max(topPanelFromWorld_.position.z, kMaxDepth);
}
// Next error code: -2
int32_t GameSurfaceLayer::Init(const jobject activityObject,
const XrVector3f& position,
const XrSession& session)
{
int32_t GameSurfaceLayer::Init(const jobject activityObject, const XrVector3f& position,
const XrSession& session) {
static const std::string gameSurfaceClassName =
"org/citra/citra_emu/vr/GameSurfaceLayer";
vrGameSurfaceClass_ = JniUtils::GetGlobalClassReference(
env_, activityObject, gameSurfaceClassName);
BAIL_ON_COND(vrGameSurfaceClass_ == nullptr,
"No java Game Surface Layer class", -1);
static const std::string gameSurfaceClassName = "org/citra/citra_emu/vr/GameSurfaceLayer";
vrGameSurfaceClass_ =
JniUtils::GetGlobalClassReference(env_, activityObject, gameSurfaceClassName);
BAIL_ON_COND(vrGameSurfaceClass_ == nullptr, "No java Game Surface Layer class", -1);
CreateSwapchain();
SetSurface();
@ -489,27 +426,24 @@ int32_t GameSurfaceLayer::Init(const jobject activityObject,
return 0;
}
void GameSurfaceLayer::Shutdown()
{
void GameSurfaceLayer::Shutdown() {
xrDestroySwapchain(swapchain_.Handle);
// This currently causes a memory exception
// env_->DeleteGlobalRef(vrGameSurfaceClass_);
}
void GameSurfaceLayer::CreateSwapchain()
{
void GameSurfaceLayer::CreateSwapchain() {
// Initialize swapchain
{
XrSwapchainCreateInfo xsci;
memset(&xsci, 0, sizeof(xsci));
xsci.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
xsci.next = nullptr;
xsci.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
xsci.format = 0;
xsci.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
xsci.next = nullptr;
xsci.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
xsci.format = 0;
xsci.sampleCount = 0;
xsci.width = SURFACE_WIDTH;
xsci.height = SURFACE_HEIGHT;
xsci.width = SURFACE_WIDTH;
xsci.height = SURFACE_HEIGHT;
xsci.faceCount = 0;
xsci.arraySize = 0;
@ -518,27 +452,25 @@ void GameSurfaceLayer::CreateSwapchain()
// so that you do not need them.
xsci.mipCount = 0;
PFN_xrCreateSwapchainAndroidSurfaceKHR
pfnCreateSwapchainAndroidSurfaceKHR = nullptr;
PFN_xrCreateSwapchainAndroidSurfaceKHR pfnCreateSwapchainAndroidSurfaceKHR = nullptr;
assert(OpenXr::GetInstance() != XR_NULL_HANDLE);
XrResult xrResult = xrGetInstanceProcAddr(
OpenXr::GetInstance(), "xrCreateSwapchainAndroidSurfaceKHR",
(PFN_xrVoidFunction*)(&pfnCreateSwapchainAndroidSurfaceKHR));
if (xrResult != XR_SUCCESS ||
pfnCreateSwapchainAndroidSurfaceKHR == nullptr)
{
XrResult xrResult =
xrGetInstanceProcAddr(OpenXr::GetInstance(), "xrCreateSwapchainAndroidSurfaceKHR",
(PFN_xrVoidFunction*)(&pfnCreateSwapchainAndroidSurfaceKHR));
if (xrResult != XR_SUCCESS || pfnCreateSwapchainAndroidSurfaceKHR == nullptr) {
FAIL("xrGetInstanceProcAddr failed for "
"xrCreateSwapchainAndroidSurfaceKHR");
}
OXR(pfnCreateSwapchainAndroidSurfaceKHR(session_, &xsci,
&swapchain_.Handle, &surface_));
swapchain_.Width = xsci.width;
OXR(pfnCreateSwapchainAndroidSurfaceKHR(session_, &xsci, &swapchain_.Handle, &surface_));
swapchain_.Width = xsci.width;
swapchain_.Height = xsci.height;
}
setSurfaceMethodID_ = env_->GetStaticMethodID(
vrGameSurfaceClass_, "setSurface",
"(Lorg/citra/citra_emu/vr/VrActivity;Landroid/view/Surface;)V");
if (setSurfaceMethodID_ == nullptr) { FAIL("Couldn't find setSurface()"); }
setSurfaceMethodID_ =
env_->GetStaticMethodID(vrGameSurfaceClass_, "setSurface",
"(Lorg/citra/citra_emu/vr/VrActivity;Landroid/view/Surface;)V");
if (setSurfaceMethodID_ == nullptr) {
FAIL("Couldn't find setSurface()");
}
}

View file

@ -52,10 +52,10 @@ License : Licensed under GPLv2 or any later version.
*******************************************************************************/
#pragma once
#include "../../../../../../core/3ds.h" // for 3ds screen sizes.
#include "OpenXR.h"
#include "Swapchain.h"
#include "utils/Common.h"
#include "../../../../../../core/3ds.h" // for 3ds screen sizes.
#include <jni.h>
@ -69,16 +69,14 @@ License : Licensed under GPLv2 or any later version.
================================================================================
*/
class GameSurfaceLayer
{
class GameSurfaceLayer {
public:
// Density scale for surface. Citra's auto-scale sets this as the internal
// resolution.
static constexpr uint32_t SCALE_FACTOR = 5;
static constexpr float DEFAULT_QUAD_DENSITY =
240 * static_cast<float>(SCALE_FACTOR);
static constexpr float DEFAULT_CYLINDER_RADIUS = 2.0f;
static constexpr float DEFAULT_QUAD_DENSITY = 240 * static_cast<float>(SCALE_FACTOR);
static constexpr float DEFAULT_CYLINDER_RADIUS = 2.0f;
static constexpr float DEFAULT_CYLINDER_CENTRAL_ANGLE_DEGREES = 55.0f;
/** Constructor.
@ -87,8 +85,8 @@ public:
* the class information for gameSurfaceClass
* @param session a valid XrSession
*/
GameSurfaceLayer(const XrVector3f&& position, JNIEnv* jni,
jobject activityObject, const XrSession& session);
GameSurfaceLayer(const XrVector3f&& position, JNIEnv* jni, jobject activityObject,
const XrSession& session);
~GameSurfaceLayer();
/** Called on resume. Sets the surface in the native rendering library.
@ -126,21 +124,16 @@ public:
*
* Note: assumes viewer is looking down the -Z axis.
*/
bool GetRayIntersectionWithPanel(const XrVector3f& start,
const XrVector3f& end,
XrVector2f& result2d,
XrPosef& result3d) const;
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
const XrVector3f& end,
XrVector2f& result2d,
XrPosef& result3d) const;
bool GetRayIntersectionWithPanel(const XrVector3f& start, const XrVector3f& end,
XrVector2f& result2d, XrPosef& result3d) const;
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start, const XrVector3f& end,
XrVector2f& result2d, XrPosef& result3d) const;
void SetTopPanelFromController(const XrVector3f& controllerPosition);
void SetTopPanelFromThumbstick(const float thumbstickY);
private:
int Init(const jobject activityObject, const XrVector3f& position,
const XrSession& session);
int Init(const jobject activityObject, const XrVector3f& position, const XrSession& session);
void Shutdown();
/** Creates the swapchain.
@ -148,31 +141,29 @@ private:
void CreateSwapchain();
static constexpr uint32_t SURFACE_WIDTH =
(NUM_EYES * std::max(Core::kScreenTopWidth, Core::kScreenBottomWidth) *
SCALE_FACTOR) - 1500;
(NUM_EYES * std::max(Core::kScreenTopWidth, Core::kScreenBottomWidth) * SCALE_FACTOR) -
1500;
static constexpr uint32_t SURFACE_HEIGHT =
(Core::kScreenTopHeight + Core::kScreenBottomHeight) * SCALE_FACTOR;
// Width and height should both be even numbers, as the swapchain will
// be split twice: once (horizontally) for stereo views, and once
// (vertically) for the upper/lower screen.
static_assert((SURFACE_WIDTH % 2) == 0,
"Swapchain width must be a multiple of 2");
static_assert((SURFACE_HEIGHT % 2) == 0,
"Swapchain height must be a multiple of 2");
static_assert((SURFACE_WIDTH % 2) == 0, "Swapchain width must be a multiple of 2");
static_assert((SURFACE_HEIGHT % 2) == 0, "Swapchain height must be a multiple of 2");
const XrSession session_;
Swapchain swapchain_;
Swapchain swapchain_;
XrPosef topPanelFromWorld_;
XrPosef lowerPanelFromWorld_;
//============================
// JNI objects
JNIEnv* env_ = nullptr;
jobject activityObject_ = nullptr;
jclass vrGameSurfaceClass_ = nullptr;
jobject surface_ = nullptr;
JNIEnv* env_ = nullptr;
jobject activityObject_ = nullptr;
jclass vrGameSurfaceClass_ = nullptr;
jobject surface_ = nullptr;
//============================
// JNI methods

View file

@ -20,28 +20,25 @@ License : Licensed under GPLv2 or any later version.
#include <assert.h>
#define BAIL_ON_ERR(fn, returnCode) \
do { \
const int32_t ret = fn; \
if (ret < 0) \
{ \
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
return (returnCode); \
} \
#define BAIL_ON_ERR(fn, returnCode) \
do { \
const int32_t ret = fn; \
if (ret < 0) { \
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
return (returnCode); \
} \
} while (0)
XrInstance instance;
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError)
{
if (XR_FAILED(result))
{
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError) {
if (XR_FAILED(result)) {
char errorBuffer[XR_MAX_RESULT_STRING_SIZE];
xrResultToString(instance, result, errorBuffer);
if (failOnError)
{
if (failOnError) {
FAIL("OpenXR error: %s: %s\n", function, errorBuffer);
} else {
ALOGV("OpenXR error: %s: %s\n", function, errorBuffer);
}
else { ALOGV("OpenXR error: %s: %s\n", function, errorBuffer); }
}
}
@ -52,35 +49,29 @@ void OXR_CheckErrors(XrResult result, const char* function, bool failOnError)
================================================================================
*/
namespace
{
namespace {
#define DECL_PFN(pfn) PFN_##pfn pfn = nullptr
#define INIT_PFN(pfn) \
OXR(xrGetInstanceProcAddr(instance, #pfn, (PFN_xrVoidFunction*)(&pfn)))
#define INIT_PFN(pfn) OXR(xrGetInstanceProcAddr(instance, #pfn, (PFN_xrVoidFunction*)(&pfn)))
DECL_PFN(xrEnumerateDisplayRefreshRatesFB);
DECL_PFN(xrRequestDisplayRefreshRateFB);
void InitOXRFunctions(const XrInstance xrInstance)
{
void InitOXRFunctions(const XrInstance xrInstance) {
assert(xrInstance != XR_NULL_HANDLE);
INIT_PFN(xrEnumerateDisplayRefreshRatesFB);
INIT_PFN(xrRequestDisplayRefreshRateFB);
}
[[maybe_unused]] void XrEnumerateLayerProperties()
{
XrResult result;
[[maybe_unused]] void XrEnumerateLayerProperties() {
XrResult result;
PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties;
OXR(result = xrGetInstanceProcAddr(
XR_NULL_HANDLE, "xrEnumerateApiLayerProperties",
(PFN_xrVoidFunction*)&xrEnumerateApiLayerProperties));
if (result != XR_SUCCESS)
{
OXR(result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateApiLayerProperties",
(PFN_xrVoidFunction*)&xrEnumerateApiLayerProperties));
if (result != XR_SUCCESS) {
FAIL("Failed to get xrEnumerateApiLayerProperties function pointer.");
}
uint32_t numInputLayers = 0;
uint32_t numInputLayers = 0;
uint32_t numOutputLayers = 0;
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers, NULL));
@ -88,25 +79,21 @@ void InitOXRFunctions(const XrInstance xrInstance)
auto layerProperties = std::vector<XrApiLayerProperties>(numOutputLayers);
for (auto& lp : layerProperties)
{
for (auto& lp : layerProperties) {
lp.type = XR_TYPE_API_LAYER_PROPERTIES;
lp.next = NULL;
}
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers,
layerProperties.data()));
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers, layerProperties.data()));
for (uint32_t i = 0; i < numOutputLayers; i++)
{
for (uint32_t i = 0; i < numOutputLayers; i++) {
ALOGI("Found layer %s", layerProperties[i].layerName);
}
}
// Next return code: -3
int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
const size_t numRequiredExtensions)
{
const size_t numRequiredExtensions) {
#ifndef NDEBUG
XrEnumerateLayerProperties();
@ -116,65 +103,50 @@ int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
// runtime.
{
XrResult result;
PFN_xrEnumerateInstanceExtensionProperties
xrEnumerateInstanceExtensionProperties;
PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties;
OXR(result = xrGetInstanceProcAddr(
XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties",
(PFN_xrVoidFunction*)&xrEnumerateInstanceExtensionProperties));
if (result != XR_SUCCESS)
{
if (result != XR_SUCCESS) {
ALOGE("Failed to get xrEnumerateInstanceExtensionProperties "
"function pointer.");
return -1;
}
uint32_t numInputExtensions = 0;
uint32_t numInputExtensions = 0;
uint32_t numOutputExtensions = 0;
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions,
&numOutputExtensions, NULL));
ALOGV("xrEnumerateInstanceExtensionProperties found %u extension(s).",
numOutputExtensions);
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions, &numOutputExtensions,
NULL));
ALOGV("xrEnumerateInstanceExtensionProperties found %u extension(s).", numOutputExtensions);
numInputExtensions = numOutputExtensions;
auto extensionProperties =
std::vector<XrExtensionProperties>(numOutputExtensions);
auto extensionProperties = std::vector<XrExtensionProperties>(numOutputExtensions);
for (auto& ext : extensionProperties)
{
for (auto& ext : extensionProperties) {
ext.type = XR_TYPE_EXTENSION_PROPERTIES;
ext.next = NULL;
}
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions,
&numOutputExtensions,
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions, &numOutputExtensions,
extensionProperties.data()));
#ifndef NDEBUG
for (uint32_t i = 0; i < numOutputExtensions; i++)
{
ALOGV("Extension #%d = '%s'.", i,
extensionProperties[i].extensionName);
for (uint32_t i = 0; i < numOutputExtensions; i++) {
ALOGV("Extension #%d = '%s'.", i, extensionProperties[i].extensionName);
}
#endif
for (uint32_t i = 0; i < numRequiredExtensions; i++)
{
for (uint32_t i = 0; i < numRequiredExtensions; i++) {
bool found = false;
for (uint32_t j = 0; j < numOutputExtensions; j++)
{
if (!strcmp(requiredExtensionNames[i],
extensionProperties[j].extensionName))
{
ALOGD("Found required extension %s",
requiredExtensionNames[i]);
for (uint32_t j = 0; j < numOutputExtensions; j++) {
if (!strcmp(requiredExtensionNames[i], extensionProperties[j].extensionName)) {
ALOGD("Found required extension %s", requiredExtensionNames[i]);
found = true;
break;
}
}
if (!found)
{
ALOGE("Failed to find required extension %s",
requiredExtensionNames[i]);
if (!found) {
ALOGE("Failed to find required extension %s", requiredExtensionNames[i]);
return -2;
}
}
@ -182,8 +154,7 @@ int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
return 0;
}
XrInstance XrInstanceCreate()
{
XrInstance XrInstanceCreate() {
// Check that the extensions required are present.
static const char* const requiredExtensionNames[] = {
XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME,
@ -199,8 +170,7 @@ XrInstance XrInstanceCreate()
static constexpr size_t numRequiredExtensions =
sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]);
BAIL_ON_ERR(XrCheckRequiredExtensions(&requiredExtensionNames[0],
numRequiredExtensions),
BAIL_ON_ERR(XrCheckRequiredExtensions(&requiredExtensionNames[0], numRequiredExtensions),
XR_NULL_HANDLE);
XrApplicationInfo appInfo = {};
@ -208,25 +178,23 @@ XrInstance XrInstanceCreate()
appInfo.applicationVersion = 0;
strcpy(appInfo.engineName, "custom");
appInfo.engineVersion = 0;
appInfo.apiVersion = XR_CURRENT_API_VERSION;
appInfo.apiVersion = XR_CURRENT_API_VERSION;
XrInstanceCreateInfo ici = {};
ici.type = XR_TYPE_INSTANCE_CREATE_INFO;
ici.next = nullptr;
ici.createFlags = 0;
ici.applicationInfo = appInfo;
ici.enabledApiLayerCount = 0;
ici.enabledApiLayerNames = NULL;
XrInstanceCreateInfo ici = {};
ici.type = XR_TYPE_INSTANCE_CREATE_INFO;
ici.next = nullptr;
ici.createFlags = 0;
ici.applicationInfo = appInfo;
ici.enabledApiLayerCount = 0;
ici.enabledApiLayerNames = NULL;
ici.enabledExtensionCount = numRequiredExtensions;
ici.enabledExtensionNames = requiredExtensionNames;
XrResult initResult;
XrResult initResult;
XrInstance instanceLocal;
OXR(initResult = xrCreateInstance(&ici, &instanceLocal));
if (initResult != XR_SUCCESS)
{
ALOGE("ERROR(%s()): Failed to create XR instance_: %d.", __FUNCTION__,
initResult);
if (initResult != XR_SUCCESS) {
ALOGE("ERROR(%s()): Failed to create XR instance_: %d.", __FUNCTION__, initResult);
return XR_NULL_HANDLE;
}
// Log runtime instance info
@ -244,73 +212,61 @@ XrInstance XrInstanceCreate()
}
// Next return code: -2
int32_t XrInitializeLoaderTrampoline(JavaVM* jvm, jobject activityObject)
{
int32_t XrInitializeLoaderTrampoline(JavaVM* jvm, jobject activityObject) {
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR",
(PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
if (xrInitializeLoaderKHR != nullptr)
{
if (xrInitializeLoaderKHR != nullptr) {
XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
memset(&loaderInitializeInfoAndroid, 0,
sizeof(loaderInitializeInfoAndroid));
memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid));
loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
loaderInitializeInfoAndroid.next = NULL;
loaderInitializeInfoAndroid.applicationVM = jvm;
loaderInitializeInfoAndroid.applicationVM = jvm;
loaderInitializeInfoAndroid.applicationContext = activityObject;
xrInitializeLoaderKHR(
(XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
}
else
{
xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
} else {
ALOGE("%s(): xrInitializeLoaderKHR is NULL", __FUNCTION__);
return -1;
}
return 0;
}
XrSession XrSessionCreate(const XrInstance& localInstance,
const XrSystemId& systemId,
const std::unique_ptr<EglContext>& egl)
{
XrSession XrSessionCreate(const XrInstance& localInstance, const XrSystemId& systemId,
const std::unique_ptr<EglContext>& egl) {
XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = {};
graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
graphicsBinding.next = NULL;
graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
graphicsBinding.next = NULL;
graphicsBinding.display = egl->mDisplay;
graphicsBinding.config = egl->mConfig;
graphicsBinding.config = egl->mConfig;
graphicsBinding.context = egl->mContext;
XrSessionCreateInfo sessionCreateInfo = {};
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &graphicsBinding;
sessionCreateInfo.createFlags = 0;
sessionCreateInfo.systemId = systemId;
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &graphicsBinding;
sessionCreateInfo.createFlags = 0;
sessionCreateInfo.systemId = systemId;
XrSession session;
XrResult initResult;
OXR(initResult =
xrCreateSession(localInstance, &sessionCreateInfo, &session));
if (initResult != XR_SUCCESS)
{
XrResult initResult;
OXR(initResult = xrCreateSession(localInstance, &sessionCreateInfo, &session));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to create XR session: %d.", initResult);
return XR_NULL_HANDLE;
}
return session;
}
XrSystemId XrGetSystemId(const XrInstance& instanceLocal)
{
XrSystemId XrGetSystemId(const XrInstance& instanceLocal) {
XrSystemId systemId = XR_NULL_SYSTEM_ID;
XrSystemGetInfo sgi = {};
sgi.type = XR_TYPE_SYSTEM_GET_INFO;
sgi.next = NULL;
sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
sgi.type = XR_TYPE_SYSTEM_GET_INFO;
sgi.next = NULL;
sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
XrResult initResult;
OXR(initResult = xrGetSystem(instanceLocal, &sgi, &systemId));
if (initResult != XR_SUCCESS)
{
if (initResult != XR_SUCCESS) {
ALOGE("ERROR (%s()): Failed to get system.", __FUNCTION__);
return XR_NULL_SYSTEM_ID;
}
@ -319,38 +275,35 @@ XrSystemId XrGetSystemId(const XrInstance& instanceLocal)
// TODO give users a choice, since the highest refresh rate also drains battery
// life.
void SetHighestRefreshRate(const XrSession& session)
{
void SetHighestRefreshRate(const XrSession& session) {
// attempts to set desired refresh rate. If not available, sets highest
// refresh rate.
static constexpr float desiredRefreshRate = 90.0f;
// Enumerate refresh rates
uint32_t numRefreshRates = 0;
OXR(xrEnumerateDisplayRefreshRatesFB(session, 0, &numRefreshRates,
nullptr));
OXR(xrEnumerateDisplayRefreshRatesFB(session, 0, &numRefreshRates, nullptr));
std::vector<float> availableRefreshRates(numRefreshRates);
OXR(xrEnumerateDisplayRefreshRatesFB(session, availableRefreshRates.size(),
&numRefreshRates,
OXR(xrEnumerateDisplayRefreshRatesFB(session, availableRefreshRates.size(), &numRefreshRates,
availableRefreshRates.data()));
assert((size_t)numRefreshRates == availableRefreshRates.size());
bool hasDesiredRefreshRate = false;
float maxRefreshRate = 0;
for (auto r : availableRefreshRates)
{
if (r == desiredRefreshRate) { hasDesiredRefreshRate = true; }
if (r > maxRefreshRate) { maxRefreshRate = r; }
bool hasDesiredRefreshRate = false;
float maxRefreshRate = 0;
for (auto r : availableRefreshRates) {
if (r == desiredRefreshRate) {
hasDesiredRefreshRate = true;
}
if (r > maxRefreshRate) {
maxRefreshRate = r;
}
}
const float refreshRate =
hasDesiredRefreshRate ? desiredRefreshRate : maxRefreshRate;
const float refreshRate = hasDesiredRefreshRate ? desiredRefreshRate : maxRefreshRate;
ALOGI("Setting max refresh rate %.1fHz", refreshRate);
OXR(xrRequestDisplayRefreshRateFB(session, refreshRate));
}
size_t GetMaxLayerCount(const XrInstance& instanceLocal,
const XrSystemId& systemId)
{
size_t GetMaxLayerCount(const XrInstance& instanceLocal, const XrSystemId& systemId) {
XrSystemProperties systemProperties = {};
systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
OXR(xrGetSystemProperties(instanceLocal, systemId, &systemProperties));
ALOGV("System Properties: Name=%s VendorId=%x", systemProperties.systemName,
@ -361,21 +314,22 @@ size_t GetMaxLayerCount(const XrInstance& instanceLocal,
systemProperties.graphicsProperties.maxLayerCount);
ALOGV("System Tracking Properties: OrientationTracking=%s "
"PositionTracking=%s",
systemProperties.trackingProperties.orientationTracking ? "True"
: "False",
systemProperties.trackingProperties.positionTracking ? "True"
: "False");
systemProperties.trackingProperties.orientationTracking ? "True" : "False",
systemProperties.trackingProperties.positionTracking ? "True" : "False");
return systemProperties.graphicsProperties.maxLayerCount;
}
} // anonymous namespace
XrInstance& OpenXr::GetInstance() { return instance; }
XrInstance& OpenXr::GetInstance() {
return instance;
}
int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject)
{
for (int eye = 0; eye < 2; eye++) { viewConfigurationViews_[eye] = {}; }
int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject) {
for (int eye = 0; eye < 2; eye++) {
viewConfigurationViews_[eye] = {};
}
BAIL_ON_ERR(OpenXRInit(jvm, activityObject), -1);
BAIL_ON_ERR(XrViewConfigInit(), -2);
BAIL_ON_ERR(XrSpaceInit(), -3);
@ -384,69 +338,56 @@ int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject)
}
// Next return code: -2
int32_t OpenXr::XrViewConfigInit()
{
int32_t OpenXr::XrViewConfigInit() {
// Enumerate the viewport configurations.
uint32_t viewportConfigTypeCount = 0;
OXR(xrEnumerateViewConfigurations(instance_, systemId_, 0,
&viewportConfigTypeCount, NULL));
OXR(xrEnumerateViewConfigurations(instance_, systemId_, 0, &viewportConfigTypeCount, NULL));
auto viewportConfigurationTypes =
std::vector<XrViewConfigurationType>(viewportConfigTypeCount);
auto viewportConfigurationTypes = std::vector<XrViewConfigurationType>(viewportConfigTypeCount);
OXR(xrEnumerateViewConfigurations(
instance_, systemId_, viewportConfigTypeCount, &viewportConfigTypeCount,
viewportConfigurationTypes.data()));
OXR(xrEnumerateViewConfigurations(instance_, systemId_, viewportConfigTypeCount,
&viewportConfigTypeCount, viewportConfigurationTypes.data()));
ALOGV("Available Viewport Configuration Types: %d",
viewportConfigTypeCount);
ALOGV("Available Viewport Configuration Types: %d", viewportConfigTypeCount);
bool foundSupportedViewport;
for (uint32_t i = 0; i < viewportConfigTypeCount; i++)
{
const XrViewConfigurationType viewportConfigType =
viewportConfigurationTypes[i];
for (uint32_t i = 0; i < viewportConfigTypeCount; i++) {
const XrViewConfigurationType viewportConfigType = viewportConfigurationTypes[i];
ALOGV("Viewport configuration type %d : %s", viewportConfigType,
viewportConfigType == VIEW_CONFIG_TYPE ? "Selected" : "");
XrViewConfigurationProperties viewportConfig;
viewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
OXR(xrGetViewConfigurationProperties(
instance_, systemId_, viewportConfigType, &viewportConfig));
ALOGV("FovMutable=%s ConfigurationType %d",
viewportConfig.fovMutable ? "true" : "false",
OXR(xrGetViewConfigurationProperties(instance_, systemId_, viewportConfigType,
&viewportConfig));
ALOGV("FovMutable=%s ConfigurationType %d", viewportConfig.fovMutable ? "true" : "false",
viewportConfig.viewConfigurationType);
uint32_t viewCount;
OXR(xrEnumerateViewConfigurationViews(
instance_, systemId_, viewportConfigType, 0, &viewCount, NULL));
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_, viewportConfigType, 0,
&viewCount, NULL));
if (viewCount > 0)
{
if (viewCount > 0) {
auto elements = std::vector<XrViewConfigurationView>(viewCount);
for (uint32_t e = 0; e < viewCount; e++)
{
for (uint32_t e = 0; e < viewCount; e++) {
elements[e].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
elements[e].next = NULL;
}
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_,
viewportConfigType, viewCount,
&viewCount, elements.data()));
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_, viewportConfigType,
viewCount, &viewCount, elements.data()));
// Log the view config info for each view type for debugging
// purposes.
for (uint32_t e = 0; e < viewCount; e++)
{
for (uint32_t e = 0; e < viewCount; e++) {
const XrViewConfigurationView* element = &elements[e];
(void)element;
ALOGV("Viewport [%d]: Recommended Width=%d Height=%d "
"SampleCount=%d",
e, element->recommendedImageRectWidth,
element->recommendedImageRectHeight,
e, element->recommendedImageRectWidth, element->recommendedImageRectHeight,
element->recommendedSwapchainSampleCount);
ALOGV("Viewport [%d]: Max Width=%d Height=%d SampleCount=%d", e,
@ -455,20 +396,18 @@ int32_t OpenXr::XrViewConfigInit()
}
// Cache the view config properties for the selected config type.
if (viewportConfigType == VIEW_CONFIG_TYPE)
{
if (viewportConfigType == VIEW_CONFIG_TYPE) {
foundSupportedViewport = true;
assert(viewCount == NUM_EYES);
for (uint32_t e = 0; e < viewCount; e++)
{
for (uint32_t e = 0; e < viewCount; e++) {
viewConfigurationViews_[e] = elements[e];
}
}
} else {
ALOGD("Empty viewport configuration type: %d", viewCount);
}
else { ALOGD("Empty viewport configuration type: %d", viewCount); }
}
if (!foundSupportedViewport)
{
if (!foundSupportedViewport) {
ALOGE("No supported viewport found");
return -1;
}
@ -477,13 +416,11 @@ int32_t OpenXr::XrViewConfigInit()
// type.
viewportConfig_.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
OXR(xrGetViewConfigurationProperties(instance_, systemId_, VIEW_CONFIG_TYPE,
&viewportConfig_));
OXR(xrGetViewConfigurationProperties(instance_, systemId_, VIEW_CONFIG_TYPE, &viewportConfig_));
return 0;
}
int32_t OpenXr::XrSpaceInit()
{
int32_t OpenXr::XrSpaceInit() {
bool stageSupported = false;
uint32_t numOutputSpaces = 0;
@ -494,10 +431,8 @@ int32_t OpenXr::XrSpaceInit()
OXR(xrEnumerateReferenceSpaces(session_, numOutputSpaces, &numOutputSpaces,
referenceSpaces.data()));
for (uint32_t i = 0; i < numOutputSpaces; i++)
{
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE)
{
for (uint32_t i = 0; i < numOutputSpaces; i++) {
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
stageSupported = true;
break;
}
@ -515,10 +450,8 @@ int32_t OpenXr::XrSpaceInit()
OXR(xrCreateReferenceSpace(session_, &spaceCreateInfo, &localSpace_));
}
if (stageSupported)
{
XrReferenceSpaceCreateInfo spaceCreateInfo = {
XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
if (stageSupported) {
XrReferenceSpaceCreateInfo spaceCreateInfo = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
@ -528,28 +461,23 @@ int32_t OpenXr::XrSpaceInit()
return 0;
}
void OpenXr::XrSpaceDestroy()
{
if (headSpace_ != XR_NULL_HANDLE)
{
void OpenXr::XrSpaceDestroy() {
if (headSpace_ != XR_NULL_HANDLE) {
OXR(xrDestroySpace(headSpace_));
headSpace_ = XR_NULL_HANDLE;
}
if (localSpace_ != XR_NULL_HANDLE)
{
if (localSpace_ != XR_NULL_HANDLE) {
OXR(xrDestroySpace(localSpace_));
localSpace_ = XR_NULL_HANDLE;
}
if (stageSpace_ != XR_NULL_HANDLE)
{
if (stageSpace_ != XR_NULL_HANDLE) {
OXR(xrDestroySpace(stageSpace_));
stageSpace_ = XR_NULL_HANDLE;
}
}
// Next return code: -7
int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
{
int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject) {
/////////////////////////////////////
// Initialize OpenXR loader
@ -560,8 +488,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
// Create the OpenXR instance.
/////////////////////////////////////
instance_ = XrInstanceCreate();
if (instance_ == XR_NULL_HANDLE)
{
if (instance_ == XR_NULL_HANDLE) {
ALOGE("Failed to create XR instance");
return -2;
}
@ -569,8 +496,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
instance = instance_;
systemId_ = XrGetSystemId(instance_);
if (systemId_ == XR_NULL_SYSTEM_ID)
{
if (systemId_ == XR_NULL_SYSTEM_ID) {
ALOGE("Failed to retrieve XR system ID");
return -3;
}
@ -582,16 +508,13 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
////////////////////////////////
{
// Get the graphics requirements.
PFN_xrGetOpenGLESGraphicsRequirementsKHR
pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
OXR(xrGetInstanceProcAddr(
instance_, "xrGetOpenGLESGraphicsRequirementsKHR",
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));
PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
OXR(xrGetInstanceProcAddr(instance_, "xrGetOpenGLESGraphicsRequirementsKHR",
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));
XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {};
graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(instance_, systemId_,
&graphicsRequirements));
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(instance_, systemId_, &graphicsRequirements));
{
// Create the EGL Context
@ -604,8 +527,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
glGetIntegerv(GL_MINOR_VERSION, &eglMinor);
const XrVersion eglVersion = XR_MAKE_VERSION(eglMajor, eglMinor, 0);
if (eglVersion < graphicsRequirements.minApiVersionSupported ||
eglVersion > graphicsRequirements.maxApiVersionSupported)
{
eglVersion > graphicsRequirements.maxApiVersionSupported) {
ALOGE("GLES version %d.%d not supported", eglMajor, eglMinor);
return -5;
}
@ -621,8 +543,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
// Create the OpenXR Session.
//////////////////////////////
session_ = XrSessionCreate(instance, systemId_, eglContext_);
if (session_ == XR_NULL_HANDLE)
{
if (session_ == XR_NULL_HANDLE) {
ALOGE("Failed to create XR session");
return -6;
}
@ -632,18 +553,15 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
return 0;
}
void OpenXr::Shutdown()
{
void OpenXr::Shutdown() {
XrSpaceDestroy();
if (session_ != XR_NULL_HANDLE)
{
if (session_ != XR_NULL_HANDLE) {
OXR(xrDestroySession(session_));
session_ = XR_NULL_HANDLE;
}
if (instance_ != XR_NULL_HANDLE)
{
if (instance_ != XR_NULL_HANDLE) {
OXR(xrDestroyInstance(instance_));
instance_ = XR_NULL_HANDLE;
}

View file

@ -16,7 +16,7 @@ License : Licensed under GPLv2 or any later version.
#include <jni.h>
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_PLATFORM_ANDROID 1
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
@ -26,30 +26,29 @@ License : Licensed under GPLv2 or any later version.
#define OXR(func) OXR_CheckErrors(func, #func, true);
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError);
class OpenXr
{
class OpenXr {
public:
static XrInstance& GetInstance();
int32_t Init(JavaVM* const jvm, const jobject activityObject);
void Shutdown();
int32_t Init(JavaVM* const jvm, const jobject activityObject);
void Shutdown();
XrInstance instance_ = XR_NULL_HANDLE;
XrSystemId systemId_ = XR_NULL_SYSTEM_ID;
XrSession session_ = XR_NULL_HANDLE;
XrSession session_ = XR_NULL_HANDLE;
// this structure contains the HMD's recommended eye textures sizes. In
// OpenXR, this is meant to be extensible to allow spectator views as well.
// One for each eye.
XrViewConfigurationView viewConfigurationViews_[2] = {};
XrViewConfigurationProperties viewportConfig_ = {};
XrViewConfigurationView viewConfigurationViews_[2] = {};
XrViewConfigurationProperties viewportConfig_ = {};
static constexpr XrViewConfigurationType VIEW_CONFIG_TYPE =
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
XrSpace headSpace_ = XR_NULL_HANDLE;
XrSpace headSpace_ = XR_NULL_HANDLE;
XrSpace forwardDirectionSpace_ = XR_NULL_HANDLE;
XrSpace localSpace_ = XR_NULL_HANDLE;
XrSpace stageSpace_ = XR_NULL_HANDLE;
size_t maxLayerCount_ = 0;
XrSpace localSpace_ = XR_NULL_HANDLE;
XrSpace stageSpace_ = XR_NULL_HANDLE;
size_t maxLayerCount_ = 0;
// EGL context
std::unique_ptr<EglContext> eglContext_;
@ -58,5 +57,5 @@ private:
int32_t OpenXRInit(JavaVM* const jvm, const jobject activityObject);
int32_t XrViewConfigInit();
int32_t XrSpaceInit();
void XrSpaceDestroy();
void XrSpaceDestroy();
};

View file

@ -13,9 +13,8 @@ License : Licensed under GPLv2 or any later version.
#pragma once
#include <openxr/openxr.h>
struct Swapchain
{
struct Swapchain {
XrSwapchain Handle;
uint32_t Width;
uint32_t Height;
uint32_t Width;
uint32_t Height;
};

View file

@ -9,8 +9,8 @@ License : Licensed under GPLv2 or any later version.
*******************************************************************************/
#include "XrController.h"
#include "OpenXR.h"
#include "XrController.h"
#include "utils/LogUtils.h"
#include <vector>
@ -23,24 +23,20 @@ License : Licensed under GPLv2 or any later version.
#define ALOG_INPUT_VERBOSE(...)
#endif
namespace
{
namespace {
XrAction CreateAction(XrActionSet actionSet, XrActionType type,
const char* actionName, const char* localizedName,
int countSubactionPaths = 0,
XrPath* subactionPaths = nullptr)
{
XrAction CreateAction(XrActionSet actionSet, XrActionType type, const char* actionName,
const char* localizedName, int countSubactionPaths = 0,
XrPath* subactionPaths = nullptr) {
ALOG_INPUT_VERBOSE("CreateAction %s, %d" actionName, countSubactionPaths);
XrActionCreateInfo aci = {};
aci.type = XR_TYPE_ACTION_CREATE_INFO;
aci.next = nullptr;
aci.actionType = type;
if (countSubactionPaths > 0)
{
aci.type = XR_TYPE_ACTION_CREATE_INFO;
aci.next = nullptr;
aci.actionType = type;
if (countSubactionPaths > 0) {
aci.countSubactionPaths = countSubactionPaths;
aci.subactionPaths = subactionPaths;
aci.subactionPaths = subactionPaths;
}
strcpy(aci.actionName, actionName);
strcpy(aci.localizedActionName, localizedName ? localizedName : actionName);
@ -49,10 +45,8 @@ XrAction CreateAction(XrActionSet actionSet, XrActionType type,
return action;
}
XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance,
XrAction action,
const char* bindingString)
{
XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance, XrAction action,
const char* bindingString) {
XrActionSuggestedBinding asb;
asb.action = action;
XrPath bindingPath;
@ -61,24 +55,20 @@ XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance,
return asb;
}
XrSpace CreateActionSpace(const XrSession& session, XrAction poseAction,
XrPath subactionPath)
{
XrActionSpaceCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
asci.action = poseAction;
XrSpace CreateActionSpace(const XrSession& session, XrAction poseAction, XrPath subactionPath) {
XrActionSpaceCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
asci.action = poseAction;
asci.poseInActionSpace.orientation.w = 1.0f;
asci.subactionPath = subactionPath;
XrSpace actionSpace = XR_NULL_HANDLE;
asci.subactionPath = subactionPath;
XrSpace actionSpace = XR_NULL_HANDLE;
OXR(xrCreateActionSpace(session, &asci, &actionSpace));
return actionSpace;
}
} // anonymous namespace
InputStateStatic::InputStateStatic(const XrInstance& instance,
const XrSession& session)
{
InputStateStatic::InputStateStatic(const XrInstance& instance, const XrSession& session) {
// Create action set.
{
XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO};
@ -87,46 +77,34 @@ InputStateStatic::InputStateStatic(const XrInstance& instance,
actionSetInfo.priority = 2;
OXR(xrCreateActionSet(instance, &actionSetInfo, &mActionSet));
}
mRightHandIndexTriggerAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"right_index_trigger", "Right Index Trigger");
mLeftHandIndexTriggerAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"left_index_trigger", "Left Index Trigger");
mLeftMenuButtonAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu", "Menu");
mAButtonAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "a", "A button");
mBButtonAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "b", "B button");
mXButtonAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "x", "X button");
mYButtonAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "y", "Y button");
mRightHandIndexTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"right_index_trigger", "Right Index Trigger");
mLeftHandIndexTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"left_index_trigger", "Left Index Trigger");
mLeftMenuButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu", "Menu");
mAButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "a", "A button");
mBButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "b", "B button");
mXButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "x", "X button");
mYButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "y", "Y button");
OXR(xrStringToPath(instance, "/user/hand/left", &mLeftHandSubactionPath));
OXR(xrStringToPath(instance, "/user/hand/right", &mRightHandSubactionPath));
XrPath handSubactionPaths[2] = {mLeftHandSubactionPath,
mRightHandSubactionPath};
XrPath handSubactionPaths[2] = {mLeftHandSubactionPath, mRightHandSubactionPath};
mHandPoseAction = CreateAction(mActionSet, XR_ACTION_TYPE_POSE_INPUT,
"aim_pose", nullptr, 2, handSubactionPaths);
mHandPoseAction = CreateAction(mActionSet, XR_ACTION_TYPE_POSE_INPUT, "aim_pose", nullptr, 2,
handSubactionPaths);
mThumbStickAction =
CreateAction(mActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "thumb_stick",
nullptr, 2, handSubactionPaths);
mThumbStickAction = CreateAction(mActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "thumb_stick",
nullptr, 2, handSubactionPaths);
mThumbClickAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumb_click",
nullptr, 2, handSubactionPaths);
mThumbClickAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumb_click",
nullptr, 2, handSubactionPaths);
mSqueezeTriggerAction =
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"squeeze_trigger", nullptr, 2, handSubactionPaths);
mSqueezeTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
"squeeze_trigger", nullptr, 2, handSubactionPaths);
XrPath interactionProfilePath = XR_NULL_PATH;
OXR(xrStringToPath(instance,
"/interaction_profiles/oculus/touch_controller",
OXR(xrStringToPath(instance, "/interaction_profiles/oculus/touch_controller",
&interactionProfilePath));
// Create bindings for Quest controllers.
@ -134,66 +112,60 @@ InputStateStatic::InputStateStatic(const XrInstance& instance,
// Map bindings
std::vector<XrActionSuggestedBinding> bindings;
bindings.push_back(ActionSuggestedBinding(
instance, mAButtonAction, "/user/hand/right/input/a/click"));
bindings.push_back(ActionSuggestedBinding(
instance, mBButtonAction, "/user/hand/right/input/b/click"));
bindings.push_back(ActionSuggestedBinding(
instance, mXButtonAction, "/user/hand/left/input/x/click"));
bindings.push_back(ActionSuggestedBinding(
instance, mYButtonAction, "/user/hand/left/input/y/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mAButtonAction, "/user/hand/right/input/a/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mBButtonAction, "/user/hand/right/input/b/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mXButtonAction, "/user/hand/left/input/x/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mYButtonAction, "/user/hand/left/input/y/click"));
bindings.push_back(ActionSuggestedBinding(instance, mLeftHandIndexTriggerAction,
"/user/hand/left/input/trigger"));
bindings.push_back(ActionSuggestedBinding(instance, mRightHandIndexTriggerAction,
"/user/hand/right/input/trigger"));
bindings.push_back(
ActionSuggestedBinding(instance, mLeftHandIndexTriggerAction,
"/user/hand/left/input/trigger"));
ActionSuggestedBinding(instance, mHandPoseAction, "/user/hand/left/input/aim/pose"));
bindings.push_back(
ActionSuggestedBinding(instance, mRightHandIndexTriggerAction,
"/user/hand/right/input/trigger"));
bindings.push_back(ActionSuggestedBinding(
instance, mHandPoseAction, "/user/hand/left/input/aim/pose"));
bindings.push_back(ActionSuggestedBinding(
instance, mHandPoseAction, "/user/hand/right/input/aim/pose"));
bindings.push_back(
ActionSuggestedBinding(instance, mLeftMenuButtonAction,
"/user/hand/left/input/menu/click"));
bindings.push_back(ActionSuggestedBinding(
instance, mThumbStickAction, "/user/hand/left/input/thumbstick"));
bindings.push_back(ActionSuggestedBinding(
instance, mThumbStickAction, "/user/hand/right/input/thumbstick"));
ActionSuggestedBinding(instance, mHandPoseAction, "/user/hand/right/input/aim/pose"));
bindings.push_back(ActionSuggestedBinding(instance, mLeftMenuButtonAction,
"/user/hand/left/input/menu/click"));
bindings.push_back(ActionSuggestedBinding(instance, mThumbStickAction,
"/user/hand/left/input/thumbstick"));
bindings.push_back(ActionSuggestedBinding(instance, mThumbStickAction,
"/user/hand/right/input/thumbstick"));
bindings.push_back(
ActionSuggestedBinding(instance, mThumbClickAction,
"/user/hand/right/input/thumbstick/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mThumbClickAction,
"/user/hand/left/input/thumbstick/click"));
bindings.push_back(ActionSuggestedBinding(instance, mThumbClickAction,
"/user/hand/right/input/thumbstick/click"));
bindings.push_back(ActionSuggestedBinding(instance, mThumbClickAction,
"/user/hand/left/input/thumbstick/click"));
bindings.push_back(
ActionSuggestedBinding(instance, mSqueezeTriggerAction,
"/user/hand/right/input/squeeze/value"));
bindings.push_back(
ActionSuggestedBinding(instance, mSqueezeTriggerAction,
"/user/hand/left/input/squeeze/value"));
bindings.push_back(ActionSuggestedBinding(instance, mSqueezeTriggerAction,
"/user/hand/right/input/squeeze/value"));
bindings.push_back(ActionSuggestedBinding(instance, mSqueezeTriggerAction,
"/user/hand/left/input/squeeze/value"));
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.interactionProfile = interactionProfilePath;
suggestedBindings.suggestedBindings = &bindings[0];
suggestedBindings.interactionProfile = interactionProfilePath;
suggestedBindings.suggestedBindings = &bindings[0];
suggestedBindings.countSuggestedBindings = bindings.size();
OXR(xrSuggestInteractionProfileBindings(instance, &suggestedBindings));
// Attach to session
XrSessionActionSetsAttachInfo attachInfo = {};
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.countActionSets = 1;
attachInfo.actionSets = &mActionSet;
attachInfo.actionSets = &mActionSet;
OXR(xrAttachSessionActionSets(session, &attachInfo));
}
}
InputStateStatic::~InputStateStatic()
{
if (mActionSet != XR_NULL_HANDLE) { OXR(xrDestroyActionSet(mActionSet)); }
InputStateStatic::~InputStateStatic() {
if (mActionSet != XR_NULL_HANDLE) {
OXR(xrDestroyActionSet(mActionSet));
}
OXR(xrDestroyAction(mLeftHandIndexTriggerAction));
OXR(xrDestroyAction(mRightHandIndexTriggerAction));
OXR(xrDestroyAction(mLeftMenuButtonAction));
@ -206,62 +178,54 @@ InputStateStatic::~InputStateStatic()
OXR(xrDestroyAction(mThumbClickAction));
OXR(xrDestroyAction(mSqueezeTriggerAction));
if (mLeftHandSpace != XR_NULL_HANDLE)
{
if (mLeftHandSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(mLeftHandSpace));
}
if (mRightHandSpace != XR_NULL_HANDLE)
{
if (mRightHandSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(mRightHandSpace));
}
}
XrActionStateBoolean SyncButtonState(const XrSession& session,
const XrAction& action,
const XrPath& subactionPath = XR_NULL_PATH)
{
XrActionStateBoolean SyncButtonState(const XrSession& session, const XrAction& action,
const XrPath& subactionPath = XR_NULL_PATH) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
XrActionStateBoolean state = {};
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
OXR(xrGetActionStateBoolean(session, &getInfo, &state));
return state;
}
XrActionStateVector2f
SyncVector2fState(const XrSession& session, const XrAction& action,
const XrPath& subactionPath = XR_NULL_PATH)
{
XrActionStateVector2f SyncVector2fState(const XrSession& session, const XrAction& action,
const XrPath& subactionPath = XR_NULL_PATH) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
XrActionStateVector2f state = {};
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
OXR(xrGetActionStateVector2f(session, &getInfo, &state));
return state;
}
void InputStateFrame::SyncButtonsAndThumbSticks(
const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState)
{
const XrSession& session, const std::unique_ptr<InputStateStatic>& staticState) {
assert(staticState != nullptr);
XrActiveActionSet activeActionSet = {};
activeActionSet.actionSet = staticState->mActionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
activeActionSet.actionSet = staticState->mActionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
XrActionsSyncInfo syncInfo = {};
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.next = nullptr;
XrActionsSyncInfo syncInfo = {};
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.next = nullptr;
syncInfo.countActiveActionSets = 1;
syncInfo.activeActionSets = &activeActionSet;
syncInfo.activeActionSets = &activeActionSet;
OXR(xrSyncActions(session, &syncInfo));
// Sync button states
@ -270,92 +234,71 @@ void InputStateFrame::SyncButtonsAndThumbSticks(
mXButtonState = SyncButtonState(session, staticState->mXButtonAction);
mYButtonState = SyncButtonState(session, staticState->mYButtonAction);
mLeftMenuButtonState =
SyncButtonState(session, staticState->mLeftMenuButtonAction);
mLeftMenuButtonState = SyncButtonState(session, staticState->mLeftMenuButtonAction);
// Sync thumbstick states
mThumbStickState[LEFT_CONTROLLER] =
SyncVector2fState(session, staticState->mThumbStickAction,
staticState->mLeftHandSubactionPath);
mThumbStickState[RIGHT_CONTROLLER] =
SyncVector2fState(session, staticState->mThumbStickAction,
staticState->mRightHandSubactionPath);
mThumbStickState[LEFT_CONTROLLER] = SyncVector2fState(session, staticState->mThumbStickAction,
staticState->mLeftHandSubactionPath);
mThumbStickState[RIGHT_CONTROLLER] = SyncVector2fState(session, staticState->mThumbStickAction,
staticState->mRightHandSubactionPath);
// Sync thumbstick click states
mThumbStickClickState[LEFT_CONTROLLER] =
SyncButtonState(session, staticState->mThumbClickAction,
staticState->mLeftHandSubactionPath);
mThumbStickClickState[RIGHT_CONTROLLER] =
SyncButtonState(session, staticState->mThumbClickAction,
staticState->mRightHandSubactionPath);
mThumbStickClickState[LEFT_CONTROLLER] = SyncButtonState(
session, staticState->mThumbClickAction, staticState->mLeftHandSubactionPath);
mThumbStickClickState[RIGHT_CONTROLLER] = SyncButtonState(
session, staticState->mThumbClickAction, staticState->mRightHandSubactionPath);
// Sync index trigger states
mIndexTriggerState[LEFT_CONTROLLER] =
SyncButtonState(session, staticState->mLeftHandIndexTriggerAction,
staticState->mLeftHandSubactionPath);
mIndexTriggerState[RIGHT_CONTROLLER] =
SyncButtonState(session, staticState->mRightHandIndexTriggerAction,
staticState->mRightHandSubactionPath);
mIndexTriggerState[LEFT_CONTROLLER] = SyncButtonState(
session, staticState->mLeftHandIndexTriggerAction, staticState->mLeftHandSubactionPath);
mIndexTriggerState[RIGHT_CONTROLLER] = SyncButtonState(
session, staticState->mRightHandIndexTriggerAction, staticState->mRightHandSubactionPath);
// Sync squeeze trigger states
mSqueezeTriggerState[LEFT_CONTROLLER] =
SyncButtonState(session, staticState->mSqueezeTriggerAction,
staticState->mLeftHandSubactionPath);
mSqueezeTriggerState[RIGHT_CONTROLLER] =
SyncButtonState(session, staticState->mSqueezeTriggerAction,
staticState->mRightHandSubactionPath);
mSqueezeTriggerState[LEFT_CONTROLLER] = SyncButtonState(
session, staticState->mSqueezeTriggerAction, staticState->mLeftHandSubactionPath);
mSqueezeTriggerState[RIGHT_CONTROLLER] = SyncButtonState(
session, staticState->mSqueezeTriggerAction, staticState->mRightHandSubactionPath);
if (staticState->mLeftHandSpace == XR_NULL_HANDLE)
{
staticState->mLeftHandSpace =
CreateActionSpace(session, staticState->mHandPoseAction,
staticState->mLeftHandSubactionPath);
if (staticState->mLeftHandSpace == XR_NULL_HANDLE) {
staticState->mLeftHandSpace = CreateActionSpace(session, staticState->mHandPoseAction,
staticState->mLeftHandSubactionPath);
}
if (staticState->mRightHandSpace == XR_NULL_HANDLE)
{
staticState->mRightHandSpace =
CreateActionSpace(session, staticState->mHandPoseAction,
staticState->mRightHandSubactionPath);
if (staticState->mRightHandSpace == XR_NULL_HANDLE) {
staticState->mRightHandSpace = CreateActionSpace(session, staticState->mHandPoseAction,
staticState->mRightHandSubactionPath);
}
// get the active state and pose for the two comtrollers
if (staticState->mLeftHandSpace != XR_NULL_HANDLE)
{
XrActionStateGetInfo getInfo = {
.type = XR_TYPE_ACTION_STATE_GET_INFO,
.action = staticState->mHandPoseAction,
.subactionPath = staticState->mLeftHandSubactionPath};
if (staticState->mLeftHandSpace != XR_NULL_HANDLE) {
XrActionStateGetInfo getInfo = {.type = XR_TYPE_ACTION_STATE_GET_INFO,
.action = staticState->mHandPoseAction,
.subactionPath = staticState->mLeftHandSubactionPath};
XrActionStatePose handPose = {.type = XR_TYPE_ACTION_STATE_POSE};
OXR(xrGetActionStatePose(session, &getInfo, &handPose));
mIsHandActive[LEFT_CONTROLLER] = handPose.isActive;
}
if (staticState->mRightHandSpace != XR_NULL_HANDLE)
{
XrActionStateGetInfo getInfo = {
.type = XR_TYPE_ACTION_STATE_GET_INFO,
.action = staticState->mHandPoseAction,
.subactionPath = staticState->mRightHandSubactionPath};
if (staticState->mRightHandSpace != XR_NULL_HANDLE) {
XrActionStateGetInfo getInfo = {.type = XR_TYPE_ACTION_STATE_GET_INFO,
.action = staticState->mHandPoseAction,
.subactionPath = staticState->mRightHandSubactionPath};
XrActionStatePose handPose = {.type = XR_TYPE_ACTION_STATE_POSE};
OXR(xrGetActionStatePose(session, &getInfo, &handPose));
mIsHandActive[RIGHT_CONTROLLER] = handPose.isActive;
}
}
void InputStateFrame::SyncHandPoses(
const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState,
const XrSpace& referenceSpace,
const XrTime predictedDisplayTime)
{
OXR(xrLocateSpace(staticState->mRightHandSpace, referenceSpace,
predictedDisplayTime,
void InputStateFrame::SyncHandPoses(const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState,
const XrSpace& referenceSpace,
const XrTime predictedDisplayTime) {
OXR(xrLocateSpace(staticState->mRightHandSpace, referenceSpace, predictedDisplayTime,
&mHandPositions[InputStateFrame::RIGHT_CONTROLLER]));
mIsHandActive[RIGHT_CONTROLLER] =
(mHandPositions[InputStateFrame::RIGHT_CONTROLLER].locationFlags &
XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
OXR(xrLocateSpace(staticState->mLeftHandSpace, referenceSpace,
predictedDisplayTime,
OXR(xrLocateSpace(staticState->mLeftHandSpace, referenceSpace, predictedDisplayTime,
&mHandPositions[InputStateFrame::LEFT_CONTROLLER]));
mIsHandActive[LEFT_CONTROLLER] =
(mHandPositions[InputStateFrame::LEFT_CONTROLLER].locationFlags &
@ -364,40 +307,29 @@ void InputStateFrame::SyncHandPoses(
// Determine preferred hand.
{
// First, determine which controllers are active
const bool isLeftHandActive = mIsHandActive[LEFT_CONTROLLER];
const bool isLeftHandActive = mIsHandActive[LEFT_CONTROLLER];
const bool isRightHandActive = mIsHandActive[RIGHT_CONTROLLER];
// if only one controller is active, use that one
if (isLeftHandActive && !isRightHandActive)
{
if (isLeftHandActive && !isRightHandActive) {
mPreferredHand = LEFT_CONTROLLER;
}
else if (!isLeftHandActive && isRightHandActive)
{
} else if (!isLeftHandActive && isRightHandActive) {
mPreferredHand = RIGHT_CONTROLLER;
}
else if (isLeftHandActive && isRightHandActive)
{
} else if (isLeftHandActive && isRightHandActive) {
// if both controllers are active, use whichever one last pressed
// the index trigger
if (mIndexTriggerState[LEFT_CONTROLLER].changedSinceLastSync &&
mIndexTriggerState[LEFT_CONTROLLER].currentState == 1)
{
mIndexTriggerState[LEFT_CONTROLLER].currentState == 1) {
mPreferredHand = LEFT_CONTROLLER;
}
if (mIndexTriggerState[RIGHT_CONTROLLER].changedSinceLastSync &&
mIndexTriggerState[RIGHT_CONTROLLER].currentState == 1)
{
mIndexTriggerState[RIGHT_CONTROLLER].currentState == 1) {
mPreferredHand = RIGHT_CONTROLLER;
}
else
{
} else {
// if neither controller has pressed the index trigger, use the
// last active controller
}
}
else
{
} else {
// if no controllers are active, use the last active controller
}
}

View file

@ -18,63 +18,54 @@ License : Licensed under GPLv2 or any later version.
#include <jni.h> // needed for openxr_platform.h when XR_USE_PLATFORM_ANDROID is defined
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_PLATFORM_ANDROID 1
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <memory> // for unique_ptr
class InputStateStatic
{
class InputStateStatic {
public:
InputStateStatic(const XrInstance& instance, const XrSession& session);
~InputStateStatic();
XrActionSet mActionSet = XR_NULL_HANDLE;
XrSpace mLeftHandSpace = XR_NULL_HANDLE;
XrPath mLeftHandSubactionPath;
XrPath mLeftHandSubactionPath;
XrAction mLeftHandIndexTriggerAction = XR_NULL_HANDLE;
XrAction mXButtonAction = XR_NULL_HANDLE;
XrAction mYButtonAction = XR_NULL_HANDLE;
XrAction mLeftMenuButtonAction = XR_NULL_HANDLE;
XrAction mXButtonAction = XR_NULL_HANDLE;
XrAction mYButtonAction = XR_NULL_HANDLE;
XrAction mLeftMenuButtonAction = XR_NULL_HANDLE;
XrSpace mRightHandSpace = XR_NULL_HANDLE;
XrPath mRightHandSubactionPath;
XrPath mRightHandSubactionPath;
XrAction mRightHandIndexTriggerAction = XR_NULL_HANDLE;
XrAction mAButtonAction = XR_NULL_HANDLE;
XrAction mBButtonAction = XR_NULL_HANDLE;
XrAction mAButtonAction = XR_NULL_HANDLE;
XrAction mBButtonAction = XR_NULL_HANDLE;
XrAction mThumbStickAction = XR_NULL_HANDLE;
XrAction mHandPoseAction = XR_NULL_HANDLE;
XrAction mThumbClickAction = XR_NULL_HANDLE;
XrAction mThumbStickAction = XR_NULL_HANDLE;
XrAction mHandPoseAction = XR_NULL_HANDLE;
XrAction mThumbClickAction = XR_NULL_HANDLE;
XrAction mSqueezeTriggerAction = XR_NULL_HANDLE;
};
struct InputStateFrame
{
struct InputStateFrame {
void SyncButtonsAndThumbSticks(
const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState);
void SyncButtonsAndThumbSticks(const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState);
// Called after SyncButtonsAndThumbSticks
void SyncHandPoses(const XrSession& session,
void SyncHandPoses(const XrSession& session,
const std::unique_ptr<InputStateStatic>& staticState,
const XrSpace& referenceSpace,
const XrTime predictedDisplayTime);
enum
{
LEFT_CONTROLLER,
RIGHT_CONTROLLER,
NUM_CONTROLLERS
} mPreferredHand = RIGHT_CONTROLLER;
const XrSpace& referenceSpace, const XrTime predictedDisplayTime);
enum { LEFT_CONTROLLER, RIGHT_CONTROLLER, NUM_CONTROLLERS } mPreferredHand = RIGHT_CONTROLLER;
XrActionStateVector2f mThumbStickState[NUM_CONTROLLERS];
XrActionStateBoolean mThumbStickClickState[NUM_CONTROLLERS];
XrActionStateBoolean mIndexTriggerState[NUM_CONTROLLERS];
XrActionStateBoolean mSqueezeTriggerState[NUM_CONTROLLERS];
XrActionStateBoolean mThumbStickClickState[NUM_CONTROLLERS];
XrActionStateBoolean mIndexTriggerState[NUM_CONTROLLERS];
XrActionStateBoolean mSqueezeTriggerState[NUM_CONTROLLERS];
// Left hand buttons.
XrActionStateBoolean mXButtonState;
@ -85,7 +76,7 @@ struct InputStateFrame
XrActionStateBoolean mAButtonState;
XrActionStateBoolean mBButtonState;
XrSpaceLocation mHandPositions[NUM_CONTROLLERS] = {
{XR_TYPE_SPACE_LOCATION}, {XR_TYPE_SPACE_LOCATION}};
XrSpaceLocation mHandPositions[NUM_CONTROLLERS] = {{XR_TYPE_SPACE_LOCATION},
{XR_TYPE_SPACE_LOCATION}};
bool mIsHandActive[NUM_CONTROLLERS] = {false, false};
};

View file

@ -9,105 +9,96 @@ License : Licensed under GPLv2 or any later version.
*******************************************************************************/
#include "Egl.h"
#include "../utils/LogUtils.h"
#include "Egl.h"
namespace
{
namespace {
const char* EglErrorToStr(const EGLint error)
{
switch (error)
{
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "UNKNOWN";
const char* EglErrorToStr(const EGLint error) {
switch (error) {
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "UNKNOWN";
}
}
} // anonymous namespace
EglContext::EglContext()
{
EglContext::EglContext() {
const int32_t ret = Init();
if (ret < 0) { FAIL("EglContext::EglContext() failed: ret=%i", ret); }
if (ret < 0) {
FAIL("EglContext::EglContext() failed: ret=%i", ret);
}
}
EglContext::~EglContext() { Shutdown(); }
EglContext::~EglContext() {
Shutdown();
}
// next return code: -7
int32_t EglContext::Init()
{
int32_t EglContext::Init() {
mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (mDisplay == EGL_NO_DISPLAY)
{
ALOGE(" eglGetDisplay() failed: %s",
EglErrorToStr(eglGetError()));
if (mDisplay == EGL_NO_DISPLAY) {
ALOGE(" eglGetDisplay() failed: %s", EglErrorToStr(eglGetError()));
return -1;
}
{
ALOGV(" eglInitialize(mDisplay, &MajorVersion, &MinorVersion)");
EGLint majorVersion = 0;
EGLint minorVersion = 0;
if (eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_FALSE)
{
ALOGE(" eglInitialize() failed: %s",
EglErrorToStr(eglGetError()));
if (eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_FALSE) {
ALOGE(" eglInitialize() failed: %s", EglErrorToStr(eglGetError()));
return -2;
}
}
EGLint numConfigs = 0;
const EGLint configAttribs[] = {
EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_ALPHA_SIZE,
8,
EGL_DEPTH_SIZE, // probably don't need
0,
EGL_STENCIL_SIZE, // probably don't need, but we'll see.
0,
EGL_SAMPLES,
0,
EGL_NONE};
EGLint numConfigs = 0;
const EGLint configAttribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_ALPHA_SIZE,
8,
EGL_DEPTH_SIZE, // probably don't need
0,
EGL_STENCIL_SIZE, // probably don't need, but we'll see.
0,
EGL_SAMPLES,
0,
EGL_NONE};
if (eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs) ==
EGL_FALSE)
{
ALOGE(" eglChooseConfig() failed: %s",
EglErrorToStr(eglGetError()));
if (eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs) == EGL_FALSE) {
ALOGE(" eglChooseConfig() failed: %s", EglErrorToStr(eglGetError()));
return -3;
}
// print out chosen config attributes
@ -152,33 +143,25 @@ int32_t EglContext::Init()
ALOGV(" mContext = eglCreateContext(mDisplay, mConfig, "
"EGL_NO_CONTEXT, "
"contextAttribs)");
mContext =
eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
if (mContext == EGL_NO_CONTEXT)
{
ALOGE(" eglCreateContext() failed: %s",
EglErrorToStr(eglGetError()));
mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
if (mContext == EGL_NO_CONTEXT) {
ALOGE(" eglCreateContext() failed: %s", EglErrorToStr(eglGetError()));
return -4;
}
const EGLint surfaceAttribs[] = {EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE};
ALOGV(" mDummySurface = eglCreatePbufferSurface(mDisplay, mConfig, "
"surfaceAttribs)");
mDummySurface = eglCreatePbufferSurface(mDisplay, mConfig, surfaceAttribs);
if (mDummySurface == EGL_NO_SURFACE)
{
ALOGE(" eglCreatePbufferSurface() failed: %s",
EglErrorToStr(eglGetError()));
if (mDummySurface == EGL_NO_SURFACE) {
ALOGE(" eglCreatePbufferSurface() failed: %s", EglErrorToStr(eglGetError()));
eglDestroyContext(mDisplay, mContext);
mContext = EGL_NO_CONTEXT;
return -5;
}
ALOGV(" eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, "
"mContext)");
if (eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, mContext) ==
EGL_FALSE)
{
ALOGE(" eglMakeCurrent() failed: %s",
EglErrorToStr(eglGetError()));
if (eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, mContext) == EGL_FALSE) {
ALOGE(" eglMakeCurrent() failed: %s", EglErrorToStr(eglGetError()));
eglDestroySurface(mDisplay, mDummySurface);
eglDestroyContext(mDisplay, mContext);
mContext = EGL_NO_CONTEXT;
@ -188,23 +171,18 @@ int32_t EglContext::Init()
return 0;
}
void EglContext::Shutdown()
{
if (mContext != EGL_NO_CONTEXT)
{
ALOGV(
" eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, "
"EGL_NO_CONTEXT)");
eglMakeCurrent(
mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
void EglContext::Shutdown() {
if (mContext != EGL_NO_CONTEXT) {
ALOGV(" eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, "
"EGL_NO_CONTEXT)");
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
ALOGV(" eglDestroySurface(mDisplay, mDummySurface)");
eglDestroySurface(mDisplay, mDummySurface);
ALOGV(" eglDestroyContext(mDisplay, mContext)");
eglDestroyContext(mDisplay, mContext);
mContext = EGL_NO_CONTEXT;
}
if (mDisplay != EGL_NO_DISPLAY)
{
if (mDisplay != EGL_NO_DISPLAY) {
ALOGV(" eglTerminate(mDisplay)");
eglTerminate(mDisplay);
mDisplay = EGL_NO_DISPLAY;

View file

@ -16,20 +16,19 @@ License : Licensed under GPLv2 or any later version.
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
class EglContext
{
class EglContext {
public:
EglContext();
~EglContext();
EGLDisplay mDisplay = 0;
EGLConfig mConfig = 0;
EGLConfig mConfig = 0;
EGLContext mContext = EGL_NO_CONTEXT;
private:
int32_t Init();
void Shutdown();
void Shutdown();
// Create an unused surface because our device doesn't support creating a
// surfaceless context (KHR_surfaceless_context) (It's available in AOSP as
// a module, though, so that might be cool).

View file

@ -12,9 +12,8 @@ License : Licensed under GPLv2 or any later version.
#pragma once
#include "OpenXR.h"
namespace vr
{
namespace vr {
XrSession& GetSession();
void PrioritizeTid(const int tid);
void PrioritizeTid(const int tid);
} // namespace vr

View file

@ -15,32 +15,28 @@ License : Licensed under GPLv2 or any later version.
#include <openxr/openxr.h>
#ifndef NUM_EYES
#define NUM_EYES \
2 // this will never change, it just helps people know what we mean.
#define NUM_EYES 2 // this will never change, it just helps people know what we mean.
#endif
#define BAIL_ON_COND(cond, errorStr, returnCode) \
do { \
if (cond) \
{ \
ALOGE("ERROR (%s): %s", __FUNCTION__, errorStr); \
return (returnCode); \
} \
#define BAIL_ON_COND(cond, errorStr, returnCode) \
do { \
if (cond) { \
ALOGE("ERROR (%s): %s", __FUNCTION__, errorStr); \
return (returnCode); \
} \
} while (0)
#define BAIL_ON_ERR(fn, returnCode) \
do { \
const int32_t ret = fn; \
if (ret < 0) \
{ \
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
return (returnCode); \
} \
#define BAIL_ON_ERR(fn, returnCode) \
do { \
const int32_t ret = fn; \
if (ret < 0) { \
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
return (returnCode); \
} \
} while (0)
union XrCompositionLayer
{
XrCompositionLayerQuad mQuad;
union XrCompositionLayer {
XrCompositionLayerQuad mQuad;
XrCompositionLayerCylinderKHR mCylinder;
XrCompositionLayerPassthroughFB Passthrough;
};

View file

@ -15,62 +15,54 @@ License : Licensed under GPLv2 or any later version.
#include "LogUtils.h"
jclass JniUtils::GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
const std::string& className)
{
const std::string& className) {
// First, get the class object of the activity to get its class loader
const jclass activityClass = jni->GetObjectClass(activityObject);
if (activityClass == nullptr)
{
if (activityClass == nullptr) {
ALOGE("Failed to get activity class");
return nullptr;
}
// Get the getClassLoader method ID
const jmethodID getClassLoaderMethod = jni->GetMethodID(
activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
if (getClassLoaderMethod == nullptr)
{
const jmethodID getClassLoaderMethod =
jni->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
if (getClassLoaderMethod == nullptr) {
ALOGE("Failed to get getClassLoader method ID");
return nullptr;
}
// Call getClassLoader of the activity object to obtain the class loader
const jobject classLoaderObject =
jni->CallObjectMethod(activityObject, getClassLoaderMethod);
if (classLoaderObject == nullptr)
{
const jobject classLoaderObject = jni->CallObjectMethod(activityObject, getClassLoaderMethod);
if (classLoaderObject == nullptr) {
ALOGE("Failed to get class loader object");
return nullptr;
}
// Get the class loader class
const jclass classLoaderClass = jni->FindClass("java/lang/ClassLoader");
if (classLoaderClass == nullptr)
{
if (classLoaderClass == nullptr) {
ALOGE("Failed to get class loader class");
return nullptr;
}
// Get the findClass method ID from the class loader class
const jmethodID findClassMethod = jni->GetMethodID(
classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
if (findClassMethod == nullptr)
{
const jmethodID findClassMethod =
jni->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
if (findClassMethod == nullptr) {
ALOGE("Failed to get findClass method ID");
return nullptr;
}
// Convert the class name string to a jstring
const jstring javaClassName = jni->NewStringUTF(className.c_str());
if (javaClassName == nullptr)
{
if (javaClassName == nullptr) {
ALOGE("Failed to convert class name to jstring");
return nullptr;
}
// Call findClass on the class loader object with the class name
const jclass classToFind = static_cast<jclass>(jni->CallObjectMethod(
classLoaderObject, findClassMethod, javaClassName));
const jclass classToFind = static_cast<jclass>(
jni->CallObjectMethod(classLoaderObject, findClassMethod, javaClassName));
// Clean up local references
jni->DeleteLocalRef(activityClass);
@ -78,15 +70,13 @@ jclass JniUtils::GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
jni->DeleteLocalRef(classLoaderClass);
jni->DeleteLocalRef(javaClassName);
if (classToFind == nullptr)
{
if (classToFind == nullptr) {
// Handle error (Class not found)
return nullptr;
}
// Create a global reference to the class
const jclass globalClassRef =
reinterpret_cast<jclass>(jni->NewGlobalRef(classToFind));
const jclass globalClassRef = reinterpret_cast<jclass>(jni->NewGlobalRef(classToFind));
// Clean up the local reference of the class
jni->DeleteLocalRef(classToFind);

View file

@ -22,8 +22,6 @@ License : Licensed under GPLv2 or any later version.
#include <string>
namespace JniUtils
{
jclass GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
const std::string& className);
namespace JniUtils {
jclass GetGlobalClassReference(JNIEnv* jni, jobject activityObject, const std::string& className);
} // namespace JniUtils

View file

@ -20,15 +20,14 @@ License : Licensed under GPLv2 or any later version.
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGV(...) \
__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#ifndef NDEBUG
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
#define ALOGD(...)
#endif
#define FAIL(...) \
do { \
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__); \
abort(); \
#define FAIL(...) \
do { \
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__); \
abort(); \
} while (0)

View file

@ -14,44 +14,41 @@ License : Licensed under GPLv2 or any later version.
#include <sys/system_properties.h>
namespace SyspropUtils
{
static inline float GetSysPropAsFloat(const char* propertyName,
const float defaultValue)
{
char value[PROP_VALUE_MAX];
namespace SyspropUtils {
static inline float GetSysPropAsFloat(const char* propertyName, const float defaultValue) {
char value[PROP_VALUE_MAX];
int32_t length = __system_property_get(propertyName, value);
if (length > 0)
{
if (length > 0) {
// Attempt to convert the string to a float
char* end;
float float_value = std::strtof(value, &end);
// Check if the conversion was successful (end points to the end of the
// number)
if (end != value) { return float_value; }
if (end != value) {
return float_value;
}
}
// Return default value if property is not set or conversion failed
return defaultValue;
}
static inline int32_t GetSysPropAsInt(const char* propertyName,
const int32_t defaultValue)
{
char value[PROP_VALUE_MAX];
static inline int32_t GetSysPropAsInt(const char* propertyName, const int32_t defaultValue) {
char value[PROP_VALUE_MAX];
int32_t length = __system_property_get(propertyName, value);
if (length > 0)
{
if (length > 0) {
// Attempt to convert the string to an int
char* end;
char* end;
int32_t int_value = std::strtol(value, &end, 10);
// Check if the conversion was successful (end points to the end of the
// number)
if (end != value) { return int_value; }
if (end != value) {
return int_value;
}
}
// Return default value if property is not set or conversion failed

View file

@ -12,8 +12,8 @@ License : Licensed under GPLv2 or any later version.
#include "LogUtils.h"
#include <assert.h>
#include <cmath>
#include <assert.h>
#ifndef MATH_FLOAT_PI
#define MATH_FLOAT_PI 3.14159265358979323846f
@ -23,34 +23,27 @@ License : Licensed under GPLv2 or any later version.
#define MATH_FLOAT_TWOPI MATH_FLOAT_PI * 2.0f
#endif
static inline XrVector2f operator*(const XrVector2f& lhs, const float rhs)
{
static inline XrVector2f operator*(const XrVector2f& lhs, const float rhs) {
return XrVector2f{lhs.x * rhs, lhs.y * rhs};
}
static inline XrVector3f operator+(const XrVector3f& lhs, const XrVector3f& rhs)
{
static inline XrVector3f operator+(const XrVector3f& lhs, const XrVector3f& rhs) {
return XrVector3f{lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z};
}
static inline XrVector3f operator-(const XrVector3f& lhs, const XrVector3f& rhs)
{
static inline XrVector3f operator-(const XrVector3f& lhs, const XrVector3f& rhs) {
return XrVector3f{lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z};
}
static inline XrVector3f operator*(const XrVector3f& lhs, const float rhs)
{
static inline XrVector3f operator*(const XrVector3f& lhs, const float rhs) {
return XrVector3f{lhs.x * rhs, lhs.y * rhs, lhs.z * rhs};
}
static inline XrVector3f operator*(const float lhs, const XrVector3f& rhs)
{
static inline XrVector3f operator*(const float lhs, const XrVector3f& rhs) {
return XrVector3f{lhs * rhs.x, lhs * rhs.y, lhs * rhs.z};
}
static inline XrQuaternionf operator*(const XrQuaternionf& lhs,
const XrQuaternionf& rhs)
{
static inline XrQuaternionf operator*(const XrQuaternionf& lhs, const XrQuaternionf& rhs) {
XrQuaternionf result;
result.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y;
result.y = lhs.w * rhs.y - lhs.x * rhs.z + lhs.y * rhs.w + lhs.z * rhs.x;
@ -59,75 +52,64 @@ static inline XrQuaternionf operator*(const XrQuaternionf& lhs,
return result;
}
namespace XrMath
{
namespace XrMath {
static constexpr float kEpsilon = 0.00001f;
static inline float SafeRcpSqrt(const float x)
{
return (x >= std::numeric_limits<float>::min())
? 1.0f / sqrtf(x)
: std::numeric_limits<float>::max();
static inline float SafeRcpSqrt(const float x) {
return (x >= std::numeric_limits<float>::min()) ? 1.0f / sqrtf(x)
: std::numeric_limits<float>::max();
}
class Vector3f
{
class Vector3f {
public:
static float LengthSq(const XrVector3f& v)
{
static float LengthSq(const XrVector3f& v) {
return v.x * v.x + v.y * v.y + v.z * v.z;
}
static float Length(const XrVector3f& v) { return sqrtf(LengthSq(v)); }
static float Length(const XrVector3f& v) {
return sqrtf(LengthSq(v));
}
static void Normalize(XrVector3f& v)
{
static void Normalize(XrVector3f& v) {
const float lengthRcp = SafeRcpSqrt(LengthSq(v));
v.x *= lengthRcp;
v.y *= lengthRcp;
v.z *= lengthRcp;
}
static XrVector3f Normalized(const XrVector3f& v)
{
static XrVector3f Normalized(const XrVector3f& v) {
XrVector3f res = v;
Normalize(res);
return res;
}
static XrVector3f Cross(const XrVector3f& a, const XrVector3f& b)
{
return XrVector3f{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x};
static XrVector3f Cross(const XrVector3f& a, const XrVector3f& b) {
return XrVector3f{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
};
class Quatf
{
class Quatf {
public:
static XrQuaternionf Identity()
{
static XrQuaternionf Identity() {
return XrQuaternionf{0.0f, 0.0f, 0.0f, 1.0f};
}
// Given a yaw (Y-axis), pitch (X-axis) and roll (Z-axis) in radians, create
// a quaternion representing the same rotation
static XrQuaternionf FromEuler(const float yawInRadians,
const float pitchInRadians,
const float rollInRadians)
{
static XrQuaternionf FromEuler(const float yawInRadians, const float pitchInRadians,
const float rollInRadians) {
// Calculate half angles
const float halfPitch = pitchInRadians * 0.5f;
const float halfYaw = yawInRadians * 0.5f;
const float halfRoll = rollInRadians * 0.5f;
const float halfYaw = yawInRadians * 0.5f;
const float halfRoll = rollInRadians * 0.5f;
// Calculate sin and cos for each half angle
const float sinPitch = std::sin(halfPitch);
const float cosPitch = std::cos(halfPitch);
const float sinYaw = std::sin(halfYaw);
const float cosYaw = std::cos(halfYaw);
const float sinRoll = std::sin(halfRoll);
const float cosRoll = std::cos(halfRoll);
const float sinYaw = std::sin(halfYaw);
const float cosYaw = std::cos(halfYaw);
const float sinRoll = std::sin(halfRoll);
const float cosRoll = std::cos(halfRoll);
// Create quaternions for each rotation
const XrQuaternionf qx = {sinPitch, 0.0f, 0.0f, cosPitch};
@ -139,43 +121,36 @@ public:
}
// Yaw (around Y-axis)
static float GetYawInRadians(const XrQuaternionf& q)
{
static float GetYawInRadians(const XrQuaternionf& q) {
assert(IsNormalized(q));
return atan2f(2.0f * (q.x * q.y + q.w * q.z),
q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z);
}
// Pitch (around X-axis)
static float GetPitchInRadians(const XrQuaternionf& q)
{
static float GetPitchInRadians(const XrQuaternionf& q) {
assert(IsNormalized(q));
return asinf(-2.0f * (q.x * q.z - q.w * q.y));
}
// Roll (around Z-axis)
static float GetRollInRadians(const XrQuaternionf& q)
{
static float GetRollInRadians(const XrQuaternionf& q) {
assert(IsNormalized(q));
return atan2f(2.0f * (q.y * q.z + q.w * q.x),
q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z);
}
[[maybe_unused]] static bool IsNormalized(const XrQuaternionf& q)
{
return fabs(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w - 1.0f) <
kEpsilon;
[[maybe_unused]] static bool IsNormalized(const XrQuaternionf& q) {
return fabs(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w - 1.0f) < kEpsilon;
}
static XrQuaternionf Inverted(const XrQuaternionf& q)
{
static XrQuaternionf Inverted(const XrQuaternionf& q) {
assert(IsNormalized(q));
return XrQuaternionf{-q.x, -q.y, -q.z, q.w};
}
// Formula: v' = q * v * q*
// Where q* is the conjugate of q
static XrVector3f Rotate(const XrQuaternionf& q, const XrVector3f& _v)
{
static XrVector3f Rotate(const XrQuaternionf& q, const XrVector3f& _v) {
assert(IsNormalized(q));
const float vx = 2 * (q.y * _v.z - q.z * _v.y);
@ -190,63 +165,47 @@ public:
// Compute a quaternion representing a rotation between three orthogonal
// basis vectors. These vectors correspond to the forward, up, and right
// directions of a rotation matrix.
static XrQuaternionf FromThreeVectors(const XrVector3f& forward,
const XrVector3f& up,
const XrVector3f& right)
{
static XrQuaternionf FromThreeVectors(const XrVector3f& forward, const XrVector3f& up,
const XrVector3f& right) {
const float trace = right.x + up.y + forward.z;
if (trace > 0.0f)
{
if (trace > 0.0f) {
const float s = 0.5f / sqrtf(trace + 1.0f);
return XrQuaternionf{(up.z - forward.y) * s,
(forward.x - right.z) * s,
return XrQuaternionf{(up.z - forward.y) * s, (forward.x - right.z) * s,
(right.y - up.x) * s, 0.25f / s};
}
if (right.x > up.y && right.x > forward.z)
{
if (right.x > up.y && right.x > forward.z) {
const float s = 2.0f * sqrtf(1.0f + right.x - up.y - forward.z);
return XrQuaternionf{0.25f * s, (up.x + right.y) / s,
(forward.x + right.z) / s,
return XrQuaternionf{0.25f * s, (up.x + right.y) / s, (forward.x + right.z) / s,
(up.z - forward.y) / s};
}
else if (up.y > forward.z)
{
} else if (up.y > forward.z) {
const float s = 2.0f * sqrtf(1.0f + up.y - right.x - forward.z);
return XrQuaternionf{(up.x + right.y) / s, 0.25f * s,
(forward.y + up.z) / s,
return XrQuaternionf{(up.x + right.y) / s, 0.25f * s, (forward.y + up.z) / s,
(forward.x - right.z) / s};
}
else
{
} else {
const float s = 2.0f * sqrtf(1.0f + forward.z - right.x - up.y);
return XrQuaternionf{(forward.x + right.z) / s,
(forward.y + up.z) / s, 0.25f * s,
return XrQuaternionf{(forward.x + right.z) / s, (forward.y + up.z) / s, 0.25f * s,
(up.z - forward.y) / s};
}
}
};
class Posef
{
class Posef {
public:
static XrPosef Identity()
{
static XrPosef Identity() {
return XrPosef{Quatf::Identity(), {0.0f, 0.0f, 0.0f}};
}
static XrVector3f Transform(const XrPosef& pose, const XrVector3f& vector)
{
static XrVector3f Transform(const XrPosef& pose, const XrVector3f& vector) {
return Quatf::Rotate(pose.orientation, vector) + pose.position;
}
static XrPosef Inverted(const XrPosef& pose)
{
static XrPosef Inverted(const XrPosef& pose) {
const XrQuaternionf invOrientation = Quatf::Inverted(pose.orientation);
XrVector3f invPosition = Quatf::Rotate(invOrientation, pose.position);
invPosition.x = -invPosition.x;
invPosition.y = -invPosition.y;
invPosition.z = -invPosition.z;
invPosition.x = -invPosition.x;
invPosition.y = -invPosition.y;
invPosition.z = -invPosition.z;
return {invOrientation, invPosition};
}

File diff suppressed because it is too large Load diff