Add DaydreamVR native libraries and services
Upstreaming the main VR system components from master-dreamos-dev
into goog/master.
Bug: None
Test: `m -j32` succeeds. Sailfish boots and basic_vr sample app works
Change-Id: I853015872afc443aecee10411ef2d6b79184d051
diff --git a/libs/vr/libgvr/.clang-format b/libs/vr/libgvr/.clang-format
new file mode 100644
index 0000000..3287160
--- /dev/null
+++ b/libs/vr/libgvr/.clang-format
@@ -0,0 +1,2 @@
+Language: Cpp
+DisableFormat: true
diff --git a/libs/vr/libgvr/Android.mk b/libs/vr/libgvr/Android.mk
new file mode 100644
index 0000000..bcb3961
--- /dev/null
+++ b/libs/vr/libgvr/Android.mk
@@ -0,0 +1,126 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LOCAL_PATH := $(call my-dir)
+
+include_dirs := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/prebuilt/include
+
+# Java platform library for the system implementation of the GVR API.
+include $(CLEAR_VARS)
+LOCAL_MODULE := gvr_platform
+LOCAL_MODULE_STEM := com.google.vr.gvr.platform
+LOCAL_REQUIRED_MODULES := libgvr_system_loader libgvr_system
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+include $(BUILD_JAVA_LIBRARY)
+
+# Library to perform dlopen on the actual platform library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_system_loader
+LOCAL_SRC_FILES := library_loader.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library implementing the GVR API.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_system
+
+LOCAL_SRC_FILES := \
+ shim_gvr.cpp \
+ shim_gvr_controller.cpp \
+ shim_gvr_private.cpp \
+ deviceparams/CardboardDevice.nolite.proto
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+LOCAL_C_INCLUDES := $(include_dirs)
+LOCAL_C_INCLUDES += $(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(include_dirs)
+
+gvr_api_linker_script := $(LOCAL_PATH)/exported_apis.lds
+LOCAL_ADDITIONAL_DEPENDENCIES := $(gvr_api_linker_script)
+
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
+LOCAL_LDFLAGS += -Wl,-version-script,$(gvr_api_linker_script)
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libbase \
+ libbinder \
+ libcutils \
+ libutils \
+ libgui \
+ libui \
+ libEGL \
+ libGLESv2 \
+ libvulkan \
+ libhardware \
+ liblog \
+ libsync \
+ libevent \
+ libprotobuf-cpp-full
+
+LOCAL_STATIC_LIBRARIES := \
+ libdisplay \
+ libbufferhub \
+ libbufferhubqueue \
+ libchrome \
+ libdvrcommon \
+ libeds \
+ libdvrgraphics \
+ libsensor \
+ libperformance \
+ libpdx_default_transport \
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Prebuilt shared library for libgvr_audio.so
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_audio
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MULTILIB := both
+LOCAL_SRC_FILES_arm := prebuilt/lib/android_arm/libgvr_audio.so
+LOCAL_SRC_FILES_arm64 := prebuilt/lib/android_arm64/libgvr_audio.so
+include $(BUILD_PREBUILT)
+
+# Prebuilt shared library for libgvr.so
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/prebuilt/include
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MULTILIB := both
+LOCAL_SRC_FILES_arm := prebuilt/lib/android_arm/libgvr.so
+LOCAL_SRC_FILES_arm64 := prebuilt/lib/android_arm64/libgvr.so
+include $(BUILD_PREBUILT)
+
+# Prebuilt Java static library for common_library.aar
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ gvr_common_library_aar:prebuilt/lib/common_library.aar
+include $(BUILD_MULTI_PREBUILT)
+
+# Dummy libgvr_ext to be used along side libgvr.so prebuilt.
+# This shall be replaced with Google3 prebuilts in future.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_ext
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SRC_FILES := dummy_gvr_ext.cpp
+LOCAL_STATIC_LIBRARIES := libchrome
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES += libgvr
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/vr/libgvr/CPPLINT.cfg b/libs/vr/libgvr/CPPLINT.cfg
new file mode 100644
index 0000000..2da1c50
--- /dev/null
+++ b/libs/vr/libgvr/CPPLINT.cfg
@@ -0,0 +1 @@
+filter=-build/header_guard,-build/include_alpha
diff --git a/libs/vr/libgvr/README.dreamos b/libs/vr/libgvr/README.dreamos
new file mode 100644
index 0000000..d847210
--- /dev/null
+++ b/libs/vr/libgvr/README.dreamos
@@ -0,0 +1 @@
+Files under public/vr/gvr were imported from the public Google VR SDK.
diff --git a/libs/vr/libgvr/com.google.vr.gvr.platform.xml b/libs/vr/libgvr/com.google.vr.gvr.platform.xml
new file mode 100644
index 0000000..9297c7f
--- /dev/null
+++ b/libs/vr/libgvr/com.google.vr.gvr.platform.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <library name="com.google.vr.gvr.platform"
+ file="/system/framework/com.google.vr.gvr.platform.jar" />
+</permissions>
diff --git a/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto b/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto
new file mode 100644
index 0000000..77b5d72
--- /dev/null
+++ b/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto
@@ -0,0 +1,299 @@
+
+syntax = "proto2";
+
+option java_package = "com.google.vrtoolkit.cardboard.proto";
+option java_outer_classname = "CardboardDevice";
+option optimize_for = SPEED;
+
+package proto;
+
+
+/**
+ * Message describing properties of a VR head mount device (HMD) which uses an
+ * interchangeable smartphone as a display (e.g. Google Cardboard).
+ *
+ * While some properties are certain (e.g. inter_lens_distance), others
+ * represent nominal values which may be refined depending on context (e.g.
+ * viewport_angles).
+ *
+ * Lengths are in meters unless noted otherwise. Fields are _required_
+ * unless noted otherwise.
+ *
+ * Some context on why this set of parameters are deemed necessary and
+ * sufficient:
+ * * FOV scale can be reasonably approximated from lens-to-screen distance
+ * and display size (i.e. knowing lens focal length isn't crucial).
+ * * Lenses are assumed to be horizontally centered with respect to
+ * display.
+ * * The display is not necessarily vertically centered. For interchangeable
+ * phones where the device rests against a tray, we can derive
+ * the vertical offset from tray-to-lens height along with phone-specific
+ * bezel and screen sizes (supplied separately).
+ */
+message DeviceParams {
+ // String identifying the device's vendor (e.g. "Google, Inc.").
+ // A device's [vendor, model] pair is expected to be globally unique.
+ optional string vendor = 1;
+
+ // String identifying the device's model, including revision info if
+ // needed (e.g. "Cardboard v1"). A device's [vendor, model] pair is
+ // expected to be globally unique.
+ optional string model = 2;
+
+ // Distance from the display screen to the optical center of lenses.
+ // This is a required field for distortion rendering, and must be positive.
+ optional float screen_to_lens_distance = 3;
+
+ // Horizontal distance between optical center of the lenses.
+ // This is a required field for distortion rendering, and must be positive.
+ optional float inter_lens_distance = 4;
+
+ // Four-element tuple (left, right, bottom, top) of left eye's view extent
+ // angles relative to center, assuming the following:
+ // * eye is aligned with optical center of lens
+ // * display screen is equal or larger than extents viewable through lens
+ // * nominal eye-to-lens distance
+ // * mirrored field of view will be applied to the right eye
+ // These values are essentially used as an optimization to avoid rendering
+ // pixels which can't be seen.
+ // This is a required field for distortion rendering, and angles must be
+ // positive.
+ repeated float left_eye_field_of_view_angles = 5 [packed = true];
+
+ enum VerticalAlignmentType {
+ BOTTOM = 0; // phone rests against a fixed bottom tray
+ CENTER = 1; // phone screen assumed to be centered w.r.t. lenses
+ TOP = 2; // phone rests against a fixed top tray
+ }
+
+ // Set according to vertical alignment strategy-- see enum comments above.
+ // NOTE: If you set this to CENTER, see special instructions for the
+ // tray_to_lens_distance field below.
+ optional VerticalAlignmentType vertical_alignment = 11 [default = BOTTOM];
+
+ // If the phone is aligned vertically within the device by resting against
+ // a fixed top or bottom tray, this is the distance from the tray to
+ // optical center of the lenses.
+ // This is a required field for distortion rendering, and must be positive.
+ // NOTE: Due to a bug in initial versions of the SDK's, this field
+ // must be set explicitly to .035 when vertical_alignment = CENTER.
+ optional float tray_to_lens_distance = 6;
+
+ // Coefficients Ki for pincushion distortion function which maps
+ // from position on real screen to virtual screen (i.e. texture) relative
+ // to optical center:
+ //
+ // p' = p (1 + K1 r^2 + K2 r^4 + ... + Kn r^(2n))
+ //
+ // where r is the distance in tan-angle units from the optical center,
+ // p the input point, and p' the output point. Tan-angle units can be
+ // computed as distance on the screen divided by distance from the
+ // virtual eye to the screen.
+ repeated float distortion_coefficients = 7 [packed = true];
+ // Slots 8, 9 reserved for per-color channel distortion.
+
+ // Optionally, whether the head mount uses a magnet in any part of its
+ // design. Intended as hint as to whether phone's magnetometer is
+ // available for tasks such as orientation tracking.
+ optional bool has_magnet = 10;
+
+ enum ButtonType {
+ // No physical button, and touch screen is not easily accessible.
+ NONE = 0;
+ // HMD has integrated magnet switch similar to original Cardboard.
+ MAGNET = 1;
+ // At least a portion of touch screen is easily accessible to user for taps.
+ TOUCH = 2;
+ // Touch screen is triggered indirectly via integrated button on the HMD.
+ INDIRECT_TOUCH = 3;
+ }
+
+ // Specify primary input mechanism of the HMD. Intended for advisory
+ // purposes only, to address simple questions such as "can HMD
+ // be used with apps requiring a physical button event?" or "what icon
+ // should be used to represent button action to the user?".
+ optional ButtonType primary_button = 12 [default = MAGNET];
+
+ // Some internal data for Cardboard. This data is not intended to be
+ // set or used by developers, and any data in this proto is not guaranteed
+ // to be supported with new SDK updates.
+ optional CardboardInternalParams internal = 1729;
+
+ // Optionally, specifies the additional parameters that are necessary for
+ // a Daydream-ready headset. This field is non-null if the headset is
+ // Daydream-ready.
+ // TODO(b/30112366) The inclusion of this message inside a DeviceParams is a
+ // somewhat ugly result of some historical choices in the SDK. We should
+ // consider refactoring our code to allow us to remove this, and the
+ // CardboardInternalParams messages from this proto.
+ optional DaydreamInternalParams daydream_internal = 196883;
+}
+
+// TODO(b/27108179): CardboardInternalParams should be migrated into its own
+// file, and not live in this file.
+
+/**
+ * Message describing parameters that are used internally by Cardboard
+ * and VRToolkit. These parameters don't necessarily fit into the DeviceParams
+ * notion of a VR viewer combined with user's phone (e.g. case of viewer with
+ * dedicated display, etc.) and are not intended to be used by developers
+ * and may or may not be supported or changed without notice on new releases
+ * of the Cardboard SDK or VR Toolkit.
+ */
+message CardboardInternalParams {
+ // Used to specify a per-eye post-process transformation -- an optional
+ // rotation and x-axis reflection -- to be applied after distortion
+ // correction.
+ enum OrientationType {
+ CCW_0_DEGREES = 0;
+ CCW_90_DEGREES = 1;
+ CCW_180_DEGREES = 2;
+ CCW_270_DEGREES = 3;
+ CCW_0_DEGREES_MIRRORED = 4;
+ CCW_90_DEGREES_MIRRORED = 5;
+ CCW_180_DEGREES_MIRRORED = 6;
+ CCW_270_DEGREES_MIRRORED = 7;
+ }
+
+ // Specify a post-process transformation that is applied after the distortion
+ // function. This field is optional, if not specified, CCW_0_DEGREES is
+ // assumed. If repeated, the first orientation is for the left eye, the second
+ // is for the right eye.
+ //
+ // For example, if [CCW_90_DEGREES, CCW_270_DEGREES_MIRRORED] is specified,
+ //
+ // this input:
+ //
+ // ***************** *****************
+ // *1 2* *1 2*
+ // * * * * *** *
+ // * * * * * * *
+ // * **** * * * * *
+ // *4 3* *4 3*
+ // ***************** *****************
+ //
+ // is rendered on the screen like this:
+ //
+ // ***************** *****************
+ // *2 * 3* *3 * 2*
+ // * * * * ** *
+ // * * * * * *
+ // * *** * * *** *
+ // *1 4* *4 1*
+ // ***************** *****************
+ repeated OrientationType eye_orientations = 1 [packed = true];
+
+ // Specify a horizontal offset from the middle of the screen to the center of
+ // the lens, in meters. If one is not provided, half of the inter lens
+ // distance is used.
+ //
+ // This is only necessary if the HMD has some sort of periscope effect, where
+ // the position of the lenses, relative to the screen, is different than
+ // their position relative to the user.
+ //
+ // For example, in the HMD below, two mirrors reflect the image from the
+ // screen to the user, creating a larger inter lens distance than the screen
+ // can support.
+ //
+ // [In the diagram below, S = screen, L = lens]
+ //
+ // screen_center_to_lens_distance
+ // |--|
+ //
+ // -------------------------
+ // | SSSSSSSSSSSS |
+ // | | | | |
+ // | /----/ | \----\ |
+ // | | | | |
+ // | LLL LLL |
+ //
+ // |---------------|
+ // inter_lens_distance
+ //
+ optional float screen_center_to_lens_distance = 2;
+
+ // Optional x-dimension physical pixels per inch of the external display,
+ // assuming landscape orientation. If set, this will override OS-reported
+ // values.
+ optional float x_ppi_override = 3;
+
+ // Optional y-dimension physical pixels per inch of the external display,
+ // assuming landscape orientation. If set, this will override OS-reported
+ // values.
+ optional float y_ppi_override = 4;
+
+ // Optional string identifying the device's accelerometer and gyroscope.
+ // If either field is filled out, the corresponding sensor (gyroscope or
+ // accelerometer) will be used for head tracking.
+ //
+ // Valid strings are usually found in:
+ // vendor/<vendorname>/<devicename>/xxx/sensors.cpp
+ //
+ // For dynamic sensors, this string will be provided in a separate way.
+ //
+ // NB: Vendors and manufacturers should make the name of the sensor as
+ // specific as possible, since if multiple sensors with the same name are
+ // connected, the first will be used.
+ optional string accelerometer = 5;
+ optional string gyroscope = 6;
+}
+
+/**
+ * Message describing the additional properties of a Daydream-ready headset that
+ * are not used for a normal cardboard viewer. These parameters are not intended
+ * to be used, or consumed, by developers and may or may not be supported or
+ * changed without notice on new releases of the Cardboard SDK or VR Toolkit.
+ */
+message DaydreamInternalParams {
+ // The version of the Daydream-ready specification to which this device
+ // conforms.
+ optional int32 version = 1;
+
+ // Optionally, specifies the collection of screen alignment markers in the
+ // headset.
+ repeated ScreenAlignmentMarker alignment_markers = 2;
+}
+
+/**
+ * Message describing a single screen alignment marker.
+ *
+ * A screen alignment marker is a capacitive touch point affixed to the headset
+ * which is capable of making contact with the screen. The location of the touch
+ * point is given in meters, measured along a horizontal axis which passes
+ * through the center of both lenses, and a vertical axis which is equidistant
+ * from the centers of the lenses. A positive vertical value indicates that the
+ * point lies above the horizontal axis, and a positive horizontal value
+ * indicates that the point lies to the right, as seen by a user of the headset,
+ * of the vertical axis. For example, if the following is a representation of a
+ * headset, viewed from the point of view of a user, with three points marked by
+ * the numbers 1, 2, and 3.
+ *
+ * *****************************************************************************
+ * * ^ *
+ * * _____ | _____ *
+ * * / \ 1 / \ *
+ * * / \ | / \ *
+ * * / \ | / \ *
+ * * / \ | / \ *
+ * * / \ | / \ *
+ * *---------|-------*-------|----------+------2---|-------*-------|---------->*
+ * * \ / | \ / *
+ * * \ / | \ / *
+ * * \ / 3 | \ / *
+ * * \ / | \ / *
+ * * \_____/ | \_____/ *
+ * * | *
+ * * | *
+ * *****************************************************************************
+ *
+ * Then the coordinates of point 1 could be horizontal = 0.0, vertical = 0.035;
+ * point 2 could be horizontal = 0.02; and point 3 could be horizontal = -0.01
+ * vertical = -0.012
+ */
+message ScreenAlignmentMarker {
+ // The horizontal coordinate of the touch point.
+ optional float horizontal = 1;
+
+ // The vertical coordinate of the touch point.
+ optional float vertical = 2;
+}
diff --git a/libs/vr/libgvr/dummy_gvr_ext.cpp b/libs/vr/libgvr/dummy_gvr_ext.cpp
new file mode 100644
index 0000000..c507038
--- /dev/null
+++ b/libs/vr/libgvr/dummy_gvr_ext.cpp
@@ -0,0 +1,29 @@
+#include <base/logging.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_ext.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+gvr_frame_schedule* gvr_frame_schedule_create() { return NULL; }
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** /* schedule */) {}
+
+uint32_t gvr_frame_schedule_get_vsync_count(
+ gvr_frame_schedule* /* schedule */) {
+ return 0;
+}
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+ uint32_t /* vsync_count */) {
+ LOG(FATAL) << "gvr_get_6dof_head_pose_in_start_space is not implemented. "
+ << "Use gvr_get_head_space_from_start_space_pose instead.";
+ return gvr_mat4f({{{1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}}});
+}
+
+void gvr_wait_next_frame(gvr_swap_chain* /* swap_chain */,
+ int64_t /* sched_offset_nanos */,
+ gvr_frame_schedule* /* out_next_frame_schedule */) {
+ LOG(FATAL) << "gvr_wait_next_frame is not implemented.";
+}
diff --git a/libs/vr/libgvr/exported_apis.lds b/libs/vr/libgvr/exported_apis.lds
new file mode 100644
index 0000000..2d19303
--- /dev/null
+++ b/libs/vr/libgvr/exported_apis.lds
@@ -0,0 +1,16 @@
+{
+ global:
+ # Export GVR APIs, both public and private.
+ gvr_*;
+
+ # Whitelist of DVR APIs required by VrCore for Ambrosia controller support.
+ dvrPoseCreate;
+ dvrPoseDestroy;
+ dvrPoseGet;
+ dvrPoseGetController;
+ dvrPoseGetVsyncCount;
+
+ local:
+ # Hide everything else.
+ *;
+};
diff --git a/libs/vr/libgvr/include/private/dvr/internal_types.h b/libs/vr/libgvr/include/private/dvr/internal_types.h
new file mode 100644
index 0000000..dafdb73
--- /dev/null
+++ b/libs/vr/libgvr/include/private/dvr/internal_types.h
@@ -0,0 +1,170 @@
+#ifndef ANDROID_DVR_INTERNAL_TYPES_H_
+#define ANDROID_DVR_INTERNAL_TYPES_H_
+
+#include <GLES2/gl2.h>
+#include <atomic>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+#include <dvr/graphics.h>
+#include <dvr/pose_client.h>
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_core.h>
+#include <private/dvr/display_client.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+#include <vr/gvr/capi/src/gvr_types_experimental.h>
+
+typedef struct gvr_user_prefs_ {
+} gvr_user_prefs;
+
+typedef struct gvr_context_ {
+ int32_t last_error_;
+ JNIEnv* jni_env_;
+ DvrPose* pose_client_;
+ std::unique_ptr<android::dvr::DisplayClient> display_client_;
+ android::dvr::SystemDisplayMetrics display_metrics_;
+ gvr_mat4f left_eye_viewport_transform_;
+ gvr_mat4f right_eye_viewport_transform_;
+ gvr_mat4f next_frame_6dof_pose_;
+ gvr_mat4f next_frame_controller_pose_[2];
+ gvr_user_prefs user_prefs_;
+ bool force_6dof_;
+ std::vector<gvr_swap_chain*> swap_chains_;
+
+ gvr_context_() :
+ last_error_(GVR_ERROR_NONE),
+ jni_env_(nullptr),
+ pose_client_(nullptr),
+ force_6dof_(false) {}
+
+ ~gvr_context_();
+} gvr_context;
+
+typedef struct gvr_buffer_spec_ {
+ gvr_sizei size;
+ int32_t msaa_samples;
+ int32_t color_format;
+ int32_t depth_stencil_format;
+ bool blur_behind;
+ bool initially_visible;
+ int z_order;
+
+ // The default values are configured to match SVR defaults
+ gvr_buffer_spec_()
+ : size{0, 0},
+ msaa_samples(0),
+ color_format(GVR_COLOR_FORMAT_RGBA_8888),
+ depth_stencil_format(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16),
+ blur_behind(true),
+ initially_visible(true),
+ z_order(0) {}
+} gvr_buffer_spec;
+
+// This isn't a public gvr type
+struct gvr_buffer {
+ gvr_buffer_spec spec;
+ GLuint frame_buffer;
+ GLuint color_render_buffer;
+ GLuint depth_stencil_render_buffer;
+
+ // requested_size is used for resizing. It will be {-1, -1} when no resize is
+ // requested. Any other value indicates the app changed the size.
+ gvr_sizei requested_size;
+
+ gvr_buffer();
+ // If creation fails frame_buffer will be 0
+ gvr_buffer(gvr_context* gvr, const gvr_buffer_spec& spec,
+ GLuint texture_id, GLenum texture_target);
+ ~gvr_buffer();
+
+ gvr_buffer(gvr_buffer&& other);
+ gvr_buffer& operator=(gvr_buffer&& other);
+ gvr_buffer(const gvr_buffer& other) = delete;
+ gvr_buffer& operator=(const gvr_buffer& other) = delete;
+
+ // Set default values. Doesn't free GL resources first.
+ void SetDefaults();
+
+ // Frees all GL resources associated with the buffer
+ void FreeGl();
+};
+
+typedef struct gvr_swap_chain_ {
+ gvr_context* context;
+ DvrGraphicsContext* graphics_context_;
+ std::vector<gvr_buffer> buffers_;
+ bool frame_acquired_;
+ bool wait_next_frame_called_by_app_;
+ std::atomic<int32_t> next_external_surface_id_;
+ std::unordered_map<int32_t, gvr_external_surface*> external_surfaces_;
+
+ explicit gvr_swap_chain_(gvr_context* context)
+ : context(context),
+ graphics_context_(nullptr),
+ frame_acquired_(false),
+ wait_next_frame_called_by_app_(false),
+ next_external_surface_id_(0) {}
+ ~gvr_swap_chain_();
+} gvr_swap_chain;
+
+typedef struct gvr_buffer_viewport_ {
+ int32_t buffer_index;
+ gvr_rectf uv;
+ gvr_mat4f transform;
+ int32_t eye;
+ int32_t external_surface_id;
+ gvr_reprojection reprojection;
+
+ gvr_buffer_viewport_()
+ : buffer_index(0),
+ uv{0, 0, 0, 0},
+ transform{{{1.f, 0.f, 0.f, 0.f},
+ {0.f, 1.f, 0.f, 0.f},
+ {0.f, 0.f, 1.f, 0.f},
+ {0.f, 0.f, 0.f, 1.f}}},
+ eye(0),
+ external_surface_id(-1),
+ reprojection(GVR_REPROJECTION_FULL) {}
+
+ gvr_buffer_viewport_(int32_t /* buffer_index */, gvr_rectf uv,
+ const gvr_mat4f& transform, int32_t eye,
+ int32_t external_surface_id,
+ gvr_reprojection reprojection)
+ : buffer_index(0),
+ uv(uv),
+ transform(transform),
+ eye(eye),
+ external_surface_id(external_surface_id),
+ reprojection(reprojection) {}
+
+ bool operator==(const gvr_buffer_viewport_& other) const;
+
+ bool operator!=(const gvr_buffer_viewport_& other) const {
+ return !operator==(other);
+ }
+} gvr_buffer_viewport;
+
+typedef struct gvr_buffer_viewport_list_ {
+ std::vector<gvr_buffer_viewport> viewports;
+} gvr_buffer_viewport_list;
+
+typedef struct gvr_frame_schedule_ {
+ uint32_t vsync_count;
+ gvr_clock_time_point scheduled_finish;
+
+ gvr_frame_schedule_() : vsync_count(0) {
+ scheduled_finish.monotonic_system_time_nanos = 0;
+ }
+} gvr_frame_schedule;
+
+typedef struct gvr_display_synchronizer_ {} gvr_display_synchronizer;
+
+typedef struct gvr_external_surface_ {
+ int32_t id;
+ gvr_swap_chain* swap_chain;
+ DvrVideoMeshSurface* video_surface;
+} gvr_external_surface;
+
+#endif // ANDROID_DVR_INTERNAL_TYPES_H_
diff --git a/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h
new file mode 100644
index 0000000..8af434f
--- /dev/null
+++ b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h
@@ -0,0 +1,119 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// Constants that represent GVR error codes.
+typedef enum {
+ // TODO(steventhomas): All errors should be switched to something more
+ // meaningful and this should eventually go away.
+ GVR_ERROR_INTERNAL = 9000,
+} gvr_error_ext;
+
+typedef struct gvr_frame_schedule_ gvr_frame_schedule;
+
+gvr_frame_schedule* gvr_frame_schedule_create();
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** schedule);
+
+uint32_t gvr_frame_schedule_get_vsync_count(gvr_frame_schedule* schedule);
+
+gvr_clock_time_point gvr_frame_schedule_get_scheduled_finish(
+ gvr_frame_schedule* schedule);
+
+/// Sleep until it's time to render the next frame.
+// |start_delay_ns| adjusts how long this function blocks the app from starting
+// its next frame. If |start_delay_ns| is 0, the function waits until the
+// scheduled frame finish time for the current frame, which gives the app one
+// full vsync period to render the next frame. If the app needs less than a full
+// vysnc period to render the frame, pass in a non-zero |start_delay_ns| to
+// delay the start of frame rendering further. For example, if the vsync period
+// is 11.1ms and the app takes 6ms to render a frame, consider setting this to
+// 5ms (note that the value is in nanoseconds, so 5,000,000ns) so that the app
+// finishes the frame closer to the scheduled frame finish time. Delaying the
+// start of rendering allows the app to use a more up-to-date pose for
+// rendering.
+// |start_delay_ns| must be a positive value or 0. If you're unsure what to set
+// for |start_delay_ns|, use 0.
+/// |out_next_frame_schedule| is an output parameter that will contain the
+/// schedule for the next frame. It can be null.
+void gvr_wait_next_frame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+ gvr_frame_schedule* out_next_frame_schedule);
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+ uint32_t vsync_count);
+
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+ gvr_context* gvr, const gvr_clock_time_point time);
+
+gvr_mat4f gvr_get_start_space_from_controller_space_pose(
+ gvr_context* gvr, int controller_id, const gvr_clock_time_point time);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+#include <utility>
+
+namespace gvr {
+
+/// Convenience C++ wrapper for gvr_frame_schedule. Frees the underlying
+/// gvr_frame_schedule on destruction.
+class FrameSchedule {
+ public:
+ FrameSchedule() { schedule_ = gvr_frame_schedule_create(); }
+
+ ~FrameSchedule() {
+ if (schedule_)
+ gvr_frame_schedule_destroy(&schedule_);
+ }
+
+ FrameSchedule(FrameSchedule&& other) {
+ std::swap(schedule_, other.schedule_);
+ }
+
+ FrameSchedule& operator=(FrameSchedule&& other) {
+ std::swap(schedule_, other.schedule_);
+ return *this;
+ }
+
+ gvr_frame_schedule* cobj() { return schedule_; }
+ const gvr_frame_schedule* cobj() const { return schedule_; }
+
+ uint32_t GetVsyncCount() const {
+ return gvr_frame_schedule_get_vsync_count(schedule_);
+ }
+
+ gvr_clock_time_point GetScheduledFinish() const {
+ return gvr_frame_schedule_get_scheduled_finish(schedule_);
+ }
+
+ private:
+ gvr_frame_schedule* schedule_;
+};
+
+} // namespace gvr
+#endif // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
diff --git a/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h
new file mode 100644
index 0000000..1fae611
--- /dev/null
+++ b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h
@@ -0,0 +1,123 @@
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
+
+#include <private/dvr/eigen.h>
+#include <private/dvr/numeric.h>
+#include <private/dvr/types.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+namespace android {
+namespace dvr {
+
+inline gvr_rectf FovRadiansToDegrees(const gvr_rectf& fov) {
+ return gvr_rectf{ToDeg(fov.left), ToDeg(fov.right), ToDeg(fov.bottom),
+ ToDeg(fov.top)};
+}
+
+inline gvr_rectf FovDegreesToRadians(const gvr_rectf& fov) {
+ return gvr_rectf{ToRad(fov.left), ToRad(fov.right), ToRad(fov.bottom),
+ ToRad(fov.top)};
+}
+
+inline FieldOfView GvrToDvrFov(const gvr_rectf& fov) {
+ gvr_rectf fov_rad = FovDegreesToRadians(fov);
+ return FieldOfView(fov_rad.left, fov_rad.right, fov_rad.bottom, fov_rad.top);
+}
+
+inline gvr_rectf DvrToGvrFov(const FieldOfView& fov) {
+ return FovRadiansToDegrees(
+ gvr_rectf{fov.GetLeft(), fov.GetRight(), fov.GetBottom(), fov.GetTop()});
+}
+
+inline gvr_mat4f GvrIdentityMatrix() {
+ gvr_mat4f identity;
+ memset(&identity.m, 0, sizeof(identity.m));
+ for (int i = 0; i < 4; i++)
+ identity.m[i][i] = 1;
+ return identity;
+}
+
+inline gvr_mat4f GvrTranslationMatrix(float x, float y, float z) {
+ gvr_mat4f trans = GvrIdentityMatrix();
+ trans.m[0][3] = x;
+ trans.m[1][3] = y;
+ trans.m[2][3] = z;
+ return trans;
+}
+
+inline gvr_mat4f EigenToGvrMatrix(const mat4& m) {
+ gvr_mat4f ret;
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < 4; ++j)
+ ret.m[i][j] = m(i, j);
+ return ret;
+}
+
+inline mat4 GvrToEigenMatrix(const gvr::Mat4f& m) {
+ mat4 ret;
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < 4; ++j)
+ ret(i, j) = m.m[i][j];
+ return ret;
+}
+
+inline quat GvrToEigenRotation(const gvr_mat4f& m) {
+ mat3 ret;
+ for (int r = 0; r < 3; ++r)
+ for (int c = 0; c < 3; ++c)
+ ret(r, c) = m.m[r][c];
+ return quat(ret.matrix());
+}
+
+inline vec3 GvrToEigenTranslation(const gvr_mat4f& m) {
+ return vec3(m.m[0][3], m.m[1][3], m.m[2][3]);
+}
+
+// Converts a DVR pose to 6DOF head transform as a GVR matrix.
+inline gvr_mat4f PosefToGvrMatrix(const Posef& pose) {
+ return EigenToGvrMatrix(pose.GetObjectFromReferenceMatrix());
+}
+
+// Converts a DVR pose to 3DOF head transform as a GVR matrix by stripping out
+// position translation.
+inline gvr_mat4f PosefTo3DofGvrMatrix(const Posef& pose) {
+ gvr_mat4f ret = PosefToGvrMatrix(pose);
+ ret.m[0][3] = 0;
+ ret.m[1][3] = 0;
+ ret.m[2][3] = 0;
+ return ret;
+}
+
+// Converts a GVR matrix to a DVR pose.
+inline Posef GvrMatrixToPosef(const gvr_mat4f& m) {
+ return Posef(GvrToEigenRotation(m), GvrToEigenTranslation(m)).Inverse();
+}
+
+// Calculates an transform with only the yaw and position components of |pose|.
+// The inverse of this matrix cancels yaw and position without affecting roll or
+// pitch.
+inline mat4 CalculateRecenterTransform(const mat4& pose) {
+ const vec4 z_axis = pose * vec4::UnitZ();
+ const float yaw = std::atan2(z_axis[0], z_axis[2]);
+ const vec3 position = pose.translation();
+ return mat4(Eigen::AngleAxis<float>(yaw, vec3::UnitY())).translate(position);
+}
+
+// Calculates a transform that negates the position component of |pose| and
+// offsets the pose by |position|. The inverse of this matrix cancels the
+// position component of pose and translates by |position| without affecting
+// orientation.
+inline mat4 CalculateOffsetTransform(const mat4& pose, const vec3& position) {
+ // Transform the origin by the pose matrix to produce the offset that cancels
+ // only the position of the pose.
+ // -1 T
+ // [ R | t ] [ 0 ] = -R * t
+ // [ 0 1 ] [ 1 ]
+ const vec3 position_offset = (pose.inverse() * vec4(0, 0, 0, 1)).head<3>();
+ return mat4(mat4::Identity()).translate(position - position_offset);
+}
+
+} // namespace dvr
+} // namespace android
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
diff --git a/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
new file mode 100644
index 0000000..5c5cc62
--- /dev/null
+++ b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
@@ -0,0 +1,32 @@
+package com.google.vr.gvr.platform;
+
+/**
+ * Auxiliary class to load the system implementation of the GVR API.
+ */
+public class Loader {
+
+ /**
+ * Opens a shared library containing the system implementation for the GVR
+ * API and returns the handle to it.
+ *
+ * @return A Long object describing the handle returned by dlopen.
+ */
+ public static Long loadLibrary() {
+ // Note: we cannot safely do caller verifications here, so instead we do
+ // them in the service side. This means that private API symbols will be
+ // visible to any app adding the appropriate <uses-library> in their
+ // manifest, but any requests to such APIs will fail if not done from a
+ // trusted package like VrCore.
+ //
+ // Trusted packages are defined by (package name, signature) pairs in within
+ // a system service, and both must match.
+
+ // Load a thin JNI library that runs dlopen on request.
+ System.loadLibrary("gvr_system_loader");
+
+ // Performs dlopen on the library and returns the handle.
+ return nativeLoadLibrary("libgvr_system.so");
+ }
+
+ private static native long nativeLoadLibrary(String library);
+}
diff --git a/libs/vr/libgvr/library_loader.cpp b/libs/vr/libgvr/library_loader.cpp
new file mode 100644
index 0000000..3cdc7d6
--- /dev/null
+++ b/libs/vr/libgvr/library_loader.cpp
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <jni.h>
+
+#include <string>
+
+extern "C" {
+
+JNIEXPORT jlong JNICALL
+Java_com_google_vr_gvr_platform_Loader_nativeLoadLibrary(
+ JNIEnv* env, jclass, jstring java_library) {
+ if (!java_library)
+ return 0;
+
+ // Convert the Java String object to a C++ null-terminated string.
+ const char* data = env->GetStringUTFChars(java_library, NULL);
+ size_t size = env->GetStringUTFLength(java_library);
+ std::string library(data, size);
+ env->ReleaseStringUTFChars(java_library, data);
+
+ // Return the handle to the requested library.
+ return reinterpret_cast<jlong>(
+ dlopen(library.c_str(), RTLD_NOW | RTLD_LOCAL));
+}
+
+} // extern "C"
diff --git a/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh b/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh
new file mode 100644
index 0000000..5d5076b
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+# Build and copy libgvr from Google3. Make sure that your local Google3 client
+# is up-to-date by running `p4 sync` before executing this script.
+#
+# Usage:
+# build_gvr_prebuilts.sh --google3_dir=<path_google3_client_root>
+
+source gbash.sh || exit
+
+DEFINE_string --required "google3_dir" "" \
+ "Path to the root directory of Google3 client"
+
+BLAZE_COMMON_OPTS=(
+ --compilation_mode=opt
+ --copt=-fdata-sections
+ --copt=-ffunction-sections
+ --define='prod=1'
+ --define='enable_experimental_sdk=1'
+ --linkopt=-Wl,--gc-sections
+)
+
+function copy_file() {
+ cp -v "${1}" ${CURRENT_DIR}/"${2}"
+}
+
+function copy_gvr_headers() {
+ echo "Copy GVR headers ..."
+
+ GVR_HEADER_DIR="include/vr/gvr/capi/include"
+ GVR_SOURCE_DIR="include/vr/gvr/capi/src"
+
+ # GVR public headers
+ copy_file "vr/gvr/capi/include/gvr.h" ${GVR_HEADER_DIR}
+ copy_file "vr/gvr/capi/include/gvr_audio.h" ${GVR_HEADER_DIR}
+ copy_file "vr/gvr/capi/include/gvr_controller.h" ${GVR_HEADER_DIR}
+ copy_file "vr/gvr/capi/include/gvr_types.h" ${GVR_HEADER_DIR}
+
+ # GVR private and experimental headers
+ copy_file "vr/gvr/capi/src/gvr_experimental.h" ${GVR_SOURCE_DIR}
+ copy_file "vr/gvr/capi/src/gvr_private.h" ${GVR_SOURCE_DIR}
+ copy_file "vr/gvr/capi/src/gvr_types_experimental.h" ${GVR_SOURCE_DIR}
+}
+
+function build_gvr_libs() {
+ echo "Build GVR libraries ..."
+
+ blaze build \
+ //java/com/google/vr/sdk/release:common_library.aar \
+ //vr/gvr/platform:libgvr.so \
+ //vr/gvr/platform:libgvr_audio.so \
+ ${BLAZE_COMMON_OPTS[@]} --config=android_arm --symlink_prefix blaze-arm-
+
+ blaze build \
+ //vr/gvr/platform:libgvr.so \
+ //vr/gvr/platform:libgvr_audio.so \
+ ${BLAZE_COMMON_OPTS[@]} --config=android_arm64 --symlink_prefix blaze-arm64-
+
+ copy_file "blaze-arm-genfiles/java/com/google/vr/sdk/release/common_library.aar" \
+ "lib/common_library.aar"
+ copy_file "blaze-arm-genfiles/vr/gvr/platform/libgvr.so" "lib/android_arm"
+ copy_file "blaze-arm-genfiles/vr/gvr/platform/libgvr_audio.so" "lib/android_arm"
+ copy_file "blaze-arm64-genfiles/vr/gvr/platform/libgvr.so" "lib/android_arm64"
+ copy_file "blaze-arm64-genfiles/vr/gvr/platform/libgvr_audio.so" "lib/android_arm64"
+}
+
+function main() {
+ set -ex
+
+ CURRENT_DIR=$(pwd)
+ GOOGLE3_DIR=${FLAGS_google3_dir}
+
+ cd ${GOOGLE3_DIR}
+ copy_gvr_headers
+ build_gvr_libs
+}
+
+gbash::init_google "$@"
+main "$@"
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h
new file mode 100644
index 0000000..5054ebd
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h
@@ -0,0 +1,1737 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_H_
+
+#ifdef __ANDROID__
+#include <jni.h>
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+#include <array>
+#include <memory>
+#include <vector>
+#endif
+
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup base Google VR Base C API
+/// @brief This is the Google VR C API. It supports clients writing VR
+/// experiences for head mounted displays that consist of a mobile phone and a
+/// VR viewer.
+///
+/// Example API usage:
+///
+/// #ifdef __ANDROID__
+/// // On Android, the gvr_context should almost always be obtained from
+/// // the Java GvrLayout object via
+/// // GvrLayout.getGvrApi().getNativeGvrContext().
+/// gvr_context* gvr = ...;
+/// #else
+/// gvr_context* gvr = gvr_create();
+/// #endif
+///
+/// gvr_initialize_gl(gvr);
+///
+/// gvr_buffer_viewport_list* viewport_list =
+/// gvr_buffer_viewport_list_create(gvr);
+/// gvr_get_recommended_buffer_viewports(gvr, viewport_list);
+/// gvr_buffer_viewport* left_eye_vp = gvr_buffer_viewport_create(gvr);
+/// gvr_buffer_viewport* right_eye_vp = gvr_buffer_viewport_create(gvr);
+/// gvr_buffer_viewport_list_get_item(viewport_list, 0, left_eye_vp);
+/// gvr_buffer_viewport_list_get_item(viewport_list, 1, right_eye_vp);
+///
+/// while (client_app_should_render) {
+/// // A client app should be ready for the render target size to change
+/// // whenever a new QR code is scanned, or a new viewer is paired.
+/// gvr_sizei render_target_size =
+/// gvr_get_maximum_effective_render_target_size(gvr);
+/// // The maximum effective render target size can be very large, most
+/// // applications need to scale down to compensate.
+/// render_target_size.width /= 2;
+/// render_target_size.height /= 2;
+/// gvr_swap_chain_resize_buffer(swap_chain, 0, render_target_size);
+///
+/// // This function will depend on your render loop's implementation.
+/// gvr_clock_time_point next_vsync = AppGetNextVsyncTime();
+///
+/// const gvr_mat4f head_view =
+/// gvr_get_head_space_from_start_space_rotation(gvr, next_vsync);
+/// const gvr_mat4f left_eye_view = MatrixMultiply(
+/// gvr_get_eye_from_head_matrix(gvr, GVR_LEFT_EYE), head_view);
+/// const gvr::Mat4f right_eye_view = MatrixMultiply(
+/// gvr_get_eye_from_head_matrix(gvr, GVR_RIGHT_EYE), head_view);
+///
+/// // Insert client rendering code here.
+///
+/// AppSetRenderTarget(offscreen_texture_id);
+///
+/// AppDoSomeRenderingForEye(
+/// gvr_buffer_viewport_get_source_uv(left_eye_view),
+/// left_eye_matrix);
+/// AppDoSomeRenderingForEye(
+/// gvr_buffer_viewport_get_source_uv(right_eye_view),
+/// right_eye_matrix);
+/// AppSetRenderTarget(primary_display);
+///
+/// gvr_frame_submit(&frame, viewport_list, head_matrix);
+/// }
+///
+/// // Cleanup memory.
+/// gvr_buffer_viewport_list_destroy(&viewport_list);
+/// gvr_buffer_viewport_destroy(&left_eye_vp);
+/// gvr_buffer_viewport_destroy(&right_eye_vp);
+///
+/// #ifdef __ANDROID__
+/// // On Android, The Java GvrLayout owns the gvr_context.
+/// #else
+/// gvr_destroy(gvr);
+/// #endif
+///
+/// Head tracking is enabled by default, and will begin as soon as the
+/// gvr_context is created. The client should call gvr_pause_tracking() and
+/// gvr_resume_tracking() when the app is paused and resumed, respectively.
+///
+/// Note: Unless otherwise noted, the functions in this API may not be
+/// thread-safe with respect to the gvr_context, and it is up the caller to use
+/// the API in a thread-safe manner.
+///
+/// @{
+
+/// Creates a new gvr instance.
+///
+/// The instance must remain valid as long as any GVR object is in use. When
+/// the application no longer needs to use the GVR SDK, call gvr_destroy().
+///
+///
+/// On Android, the gvr_context should *almost always* be obtained from the Java
+/// GvrLayout object, rather than explicitly created here. The GvrLayout should
+/// live in the app's View hierarchy, and its use is required to ensure
+/// consistent behavior across all varieties of GVR-compatible viewers. See
+/// the Java GvrLayout and GvrApi documentation for more details.
+///
+#ifdef __ANDROID__
+/// @param env The JNIEnv associated with the current thread.
+/// @param app_context The Android application context. This must be the
+/// application context, NOT an Activity context (Note: from any Android
+/// Activity in your app, you can call getApplicationContext() to
+/// retrieve the application context).
+/// @param class_loader The class loader to use when loading Java classes.
+/// This must be your app's main class loader (usually accessible through
+/// activity.getClassLoader() on any of your Activities).
+///
+/// @return Pointer to the created gvr instance, NULL on failure.
+gvr_context* gvr_create(JNIEnv* env, jobject app_context, jobject class_loader);
+#else
+/// @return Pointer to the created gvr instance, NULL on failure.
+gvr_context* gvr_create();
+#endif // #ifdef __ANDROID__
+
+/// Gets the current GVR runtime version.
+///
+/// Note: This runtime version may differ from the version against which the
+/// client app is compiled, as defined by the semantic version components in
+/// gvr_version.h.
+///
+/// @return The version as a gvr_version.
+gvr_version gvr_get_version();
+
+/// Gets a string representation of the current GVR runtime version. This is of
+/// the form "MAJOR.MINOR.PATCH".
+///
+/// Note: This runtime version may differ from the version against which the
+/// client app is compiled, as defined in gvr_version.h by
+/// GVR_SDK_VERSION_STRING.
+///
+/// @return The version as a static char pointer.
+const char* gvr_get_version_string();
+
+/// Gets the current GVR error code, or GVR_ERROR_NONE if there is no error.
+/// This function doesn't clear the error code; see gvr_clear_error().
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return The current gvr_error code, or GVR_ERROR_NONE if no error has
+/// occurred.
+int32_t gvr_get_error(gvr_context* gvr);
+
+/// Clears the current GVR error code, and returns the error code that was
+/// cleared.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return The gvr_error code that was cleared by this function, or
+/// GVR_ERROR_NONE if no error has occurred.
+int32_t gvr_clear_error(gvr_context* gvr);
+
+/// Gets a human-readable string representing the given error code.
+///
+/// @param error_code The gvr_error code.
+/// @return A human-readable string representing the error code.
+const char* gvr_get_error_string(int32_t error_code);
+
+/// Returns an opaque struct containing information about user preferences.
+///
+/// The returned struct will remain valid as long as the context is valid.
+/// The returned struct may be updated when the user changes their preferences,
+/// so this function only needs to be called once, and calling it multiple
+/// times will return the same object each time.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return An opaque struct containing information about user preferences.
+const gvr_user_prefs* gvr_get_user_prefs(gvr_context* gvr);
+
+/// Returns the controller handedness of the given gvr_user_prefs struct.
+///
+/// @param user_prefs Pointer to the gvr_user_prefs object returned by
+/// gvr_get_user_prefs.
+/// @return Either GVR_CONTROLLER_RIGHT_HANDED or GVR_CONTROLLER_LEFT_HANDED
+/// depending on which hand the user holds the controller in.
+int32_t gvr_user_prefs_get_controller_handedness(
+ const gvr_user_prefs* user_prefs);
+
+/// Destroys a gvr_context instance. The parameter will be nulled by this
+/// operation. Once this function is called, the behavior of any subsequent
+/// call to a GVR SDK function that references objects created from this
+/// context is undefined.
+///
+/// @param gvr Pointer to a pointer to the gvr instance to be destroyed and
+/// nulled.
+void gvr_destroy(gvr_context** gvr);
+
+/// Initializes necessary GL-related objects and uses the current thread and
+/// GL context for rendering. Please make sure that a valid GL context is
+/// available when this function is called. This should never be called more
+/// than once on the same GL context (doing so would cause resource leaks).
+///
+/// @param gvr Pointer to the gvr instance to be initialized.
+void gvr_initialize_gl(gvr_context* gvr);
+
+/// Gets whether asynchronous reprojection is currently enabled.
+///
+/// If enabled, frames will be collected by the rendering system and
+/// asynchronously re-projected in sync with the scanout of the display. This
+/// feature may not be available on every platform, and requires a
+/// high-priority render thread with special extensions to function properly.
+///
+/// Note: On Android, this feature can be enabled solely via the GvrLayout Java
+/// instance which (indirectly) owns this gvr_context. The corresponding
+/// method call is GvrLayout.setAsyncReprojectionEnabled().
+///
+/// Note: Because of the above requirements, asynchronous reprojection is only
+/// currently available on Daydream-ready Android devices. This function will
+/// always return false on other devices.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return Whether async reprojection is enabled. Defaults to false.
+bool gvr_get_async_reprojection_enabled(const gvr_context* gvr);
+
+/// Gets the recommended buffer viewport configuration, populating a previously
+/// allocated gvr_buffer_viewport_list object. The updated values include the
+/// per-eye recommended viewport and field of view for the target.
+///
+/// When the recommended viewports are used for distortion rendering, this
+/// method should always be called after calling refresh_viewer_profile(). That
+/// will ensure that the populated viewports reflect the currently paired
+/// viewer.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewports.
+/// @param viewport_list Pointer to a previously allocated viewport list. This
+/// will be populated with the recommended buffer viewports and resized if
+/// necessary.
+void gvr_get_recommended_buffer_viewports(
+ const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list);
+
+/// Gets the screen (non-distorted) buffer viewport configuration, populating a
+/// previously allocated gvr_buffer_viewport_list object. The updated values
+/// include the per-eye recommended viewport and field of view for the target.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewports.
+/// @param viewport_list Pointer to a previously allocated viewport list. This
+/// will be populated with the screen buffer viewports and resized if
+/// necessary.
+void gvr_get_screen_buffer_viewports(const gvr_context* gvr,
+ gvr_buffer_viewport_list* viewport_list);
+
+/// Returns the maximum effective size for the client's render target, given the
+/// parameters of the head mounted device selected. At this resolution, we have
+/// a 1:1 ratio between source pixels and screen pixels in the most magnified
+/// region of the screen. Applications should rarely, if ever, need to render
+/// to a larger target, as it will simply result in sampling artifacts.
+///
+/// Note that this is probably too large for most applications to use as a
+/// render target size. Applications should scale this value to be appropriate
+/// to their graphical load.
+///
+/// @param gvr Pointer to the gvr instance from which to get the size.
+///
+/// @return Maximum effective size for the target render target.
+gvr_sizei gvr_get_maximum_effective_render_target_size(const gvr_context* gvr);
+
+/// Returns a non-distorted size for the screen, given the parameters
+/// of the phone and/or the head mounted device selected.
+///
+/// @param gvr Pointer to the gvr instance from which to get the size.
+///
+/// @return Screen (non-distorted) size for the render target.
+gvr_sizei gvr_get_screen_target_size(const gvr_context* gvr);
+
+// Sets the size of the underlying render surface.
+//
+// By default, it is assumed that the display size matches the surface
+// size. If that is the case for the client app, this method need never be
+// called. However, in certain cases (e.g., hardware scaling), this will not
+// always hold, in which case the distortion pass must be informed of the
+// custom surface size.
+//
+// Note that the caller is responsible for resizing any BufferSpec objects
+// created before this function is called. Otherwise there will be rendering
+// artifacts, such as edges appearing pixelated. This function will change the
+// result of get_maximum_effective_render_target_size(), so that function can be
+// used to compute the appropriate size for buffers.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param surface_size_pixels The size in pixels of the display surface. If
+// non-empty, this will be used in conjunction with the current display to
+// perform properly scaled distortion. If empty, it is assumed that the
+// rendering surface dimensions match that of the active display.
+void gvr_set_surface_size(gvr_context* gvr, gvr_sizei surface_size_pixels);
+
+/// Performs postprocessing, including lens distortion, on the contents of the
+/// passed texture and shows the result on the screen. Lens distortion is
+/// determined by the parameters of the viewer encoded in its QR code. The
+/// passed texture is not modified.
+///
+/// If the application does not call gvr_initialize_gl() before calling this
+/// function, the results are undefined.
+///
+/// @deprecated This function exists only to support legacy rendering pathways
+/// for Cardboard devices. It is incompatible with the low-latency
+/// experiences supported by async reprojection. Use the swap chain API
+/// instead.
+///
+/// @param gvr Pointer to the gvr instance which will do the distortion.
+/// @param texture_id The OpenGL ID of the texture that contains the next frame
+/// to be displayed.
+/// @param viewport_list Rendering parameters.
+/// @param head_space_from_start_space This parameter is ignored.
+/// @param target_presentation_time This parameter is ignored.
+void gvr_distort_to_screen(gvr_context* gvr, int32_t texture_id,
+ const gvr_buffer_viewport_list* viewport_list,
+ gvr_mat4f head_space_from_start_space,
+ gvr_clock_time_point target_presentation_time);
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Viewports and viewport lists
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup viewport Viewports and viewport lists
+/// @brief Objects to define the mapping between the application's rendering
+/// output and the user's field of view.
+/// @{
+
+/// Creates a gvr_buffer_viewport instance.
+gvr_buffer_viewport* gvr_buffer_viewport_create(gvr_context* gvr);
+
+/// Frees a gvr_buffer_viewport instance and clears the pointer.
+void gvr_buffer_viewport_destroy(gvr_buffer_viewport** viewport);
+
+/// Gets the UV coordinates specifying where the output buffer is sampled.
+///
+/// @param viewport The buffer viewport.
+/// @return UV coordinates as a rectangle.
+gvr_rectf gvr_buffer_viewport_get_source_uv(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the UV coordinates specifying where the output buffer should be
+/// sampled when compositing the final distorted image.
+///
+/// @param viewport The buffer viewport.
+/// @param uv The new UV coordinates for sampling. The coordinates must be
+/// valid, that is, left <= right and bottom <= top. Otherwise an empty
+/// source region is set, which will result in no output for this viewport.
+void gvr_buffer_viewport_set_source_uv(gvr_buffer_viewport* viewport,
+ gvr_rectf uv);
+
+/// Retrieves the field of view for the referenced buffer region.
+///
+/// This is a helper that converts the stored projection matrix to a field of
+/// view. Note that if the previously set projection matrix cannot be expressed
+/// as a view frustum aligned with the eye's optical axis, the result will be
+/// incorrect.
+///
+/// @param viewport The buffer viewport.
+/// @return The field of view of the rendered image, in degrees.
+gvr_rectf gvr_buffer_viewport_get_source_fov(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the field of view for the viewport contents.
+///
+/// This is a helper that sets the projection matrix in such a way that the
+/// viewport's contents fill the specified FOV around the eye's optical axis.
+///
+/// @param viewport The buffer viewport.
+/// @param fov The field of view to use when compositing the rendered image,
+/// in degrees.
+void gvr_buffer_viewport_set_source_fov(gvr_buffer_viewport* viewport,
+ gvr_rectf fov);
+
+/// Gets the matrix that positions the viewport in eye space.
+///
+/// @param viewport The buffer viewport.
+/// @return Matrix that transforms a quad with vertices (-1, -1, 0), (1, -1, 0),
+/// (-1, 1, 0), (1, 1, 0) representing the viewport contents to its desired
+/// eye space position for the target eye.
+gvr_mat4f gvr_buffer_viewport_get_transform(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the matrix that positions the viewport in eye space.
+///
+/// @param viewport The buffer viewport.
+/// @param transform Matrix that transforms a quad with vertices (-1, -1, 0),
+/// (1, -1, 0), (-1, 1, 0), (1, 1, 0) representing the viewport contents to
+/// its desired eye space position for the target eye.
+void gvr_buffer_viewport_set_transform(gvr_buffer_viewport* viewport,
+ gvr_mat4f transform);
+
+/// Gets the target logical eye for the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @return Index of the target logical eye for this viewport.
+int32_t gvr_buffer_viewport_get_target_eye(const gvr_buffer_viewport* viewport);
+
+/// Sets the target logical eye for the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @param index Index of the target logical eye.
+void gvr_buffer_viewport_set_target_eye(gvr_buffer_viewport* viewport,
+ int32_t index);
+
+/// Gets the index of the source buffer from which the viewport reads its
+/// undistorted pixels.
+///
+/// @param viewport The buffer viewport.
+/// @return Index of the source buffer. This corresponds to the index in the
+/// list of buffer specs that was passed to gvr_swap_chain_create().
+int32_t gvr_buffer_viewport_get_source_buffer_index(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the buffer from which the viewport reads its undistorted pixels.
+///
+/// To use the contents of the external surface as buffer contents, associate an
+/// external surface with the viewport by calling
+/// gvr_buffer_viewport_set_external_surface_id(), then call this function and
+/// pass GVR_BUFFER_INDEX_EXTERNAL_SURFACE.
+///
+/// @param viewport The buffer viewport.
+/// @param buffer_index The index of the source buffer. This is either an index
+/// in the list of buffer specs that was passed to
+/// gvr_swap_chain_create(), or GVR_BUFFER_INDEX_EXTERNAL_SURFACE.
+void gvr_buffer_viewport_set_source_buffer_index(
+ gvr_buffer_viewport* viewport, int32_t buffer_index);
+
+/// Gets the ID of the externally-managed Surface texture from which this
+/// viewport reads undistored pixels.
+///
+/// @param viewport The buffer viewport.
+/// @return ID of the externally-managed Surface of undistorted pixels.
+int32_t gvr_buffer_viewport_get_external_surface_id(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the ID of the externally-managed Surface texture from which this
+/// viewport reads. The ID is issued by GvrLayout.
+///
+/// @param viewport The buffer viewport.
+/// @param external_surface_id The ID of the surface to read from.
+void gvr_buffer_viewport_set_external_surface_id(
+ gvr_buffer_viewport* viewport, int32_t external_surface_id);
+
+/// Gets the type of reprojection to perform on the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @return Type of reprojection that is applied to the viewport.
+int32_t gvr_buffer_viewport_get_reprojection(
+ const gvr_buffer_viewport* viewport);
+
+/// Sets the type of reprojection to perform on the specified viewport.
+/// Viewports that display world content should use full reprojection.
+/// Viewports that display head-locked UI should disable reprojection to avoid
+/// excessive judder. The default is to perform full reprojection.
+///
+/// @param viewport The buffer viewport.
+/// @param reprojection Type of reprojection that will be applied to the passed
+/// viewport.
+void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport,
+ int32_t reprojection);
+
+/// Compares two gvr_buffer_viewport instances and returns true if they specify
+/// the same view mapping.
+///
+/// @param a Instance of a buffer viewport.
+/// @param b Another instance of a buffer viewport.
+/// @return True if the passed viewports are the same.
+bool gvr_buffer_viewport_equal(const gvr_buffer_viewport* a,
+ const gvr_buffer_viewport* b);
+
+/// Creates a new, empty list of viewports. The viewport list defines how the
+/// application's rendering output should be transformed into the stabilized,
+/// lens-distorted image that is sent to the screen.
+///
+/// The caller should populate the returned viewport using one of:
+/// - gvr_get_recommended_buffer_viewports()
+/// - gvr_get_screen_buffer_viewports()
+/// - gvr_buffer_viewport_list_set_item()
+///
+/// @param gvr Pointer the gvr instance from which to allocate the viewport
+/// list.
+/// @return Pointer to an allocated gvr_buffer_viewport_list object. The caller
+// is responsible for calling gvr_buffer_viewport_list_destroy() on the
+/// returned object when it is no longer needed.
+gvr_buffer_viewport_list* gvr_buffer_viewport_list_create(
+ const gvr_context* gvr);
+
+/// Destroys a gvr_buffer_viewport_list instance. The parameter will be nulled
+/// by this operation.
+///
+/// @param viewport_list Pointer to a pointer to the viewport list instance to
+/// be destroyed and nulled.
+void gvr_buffer_viewport_list_destroy(gvr_buffer_viewport_list** viewport_list);
+
+/// Returns the size of the given viewport list.
+///
+/// @param viewport_list Pointer to a viewport list.
+/// @return The number of entries in the viewport list.
+size_t gvr_buffer_viewport_list_get_size(
+ const gvr_buffer_viewport_list* viewport_list);
+
+/// Retrieve a buffer viewport entry from a list.
+///
+/// @param viewport_list Pointer to the previously allocated viewport list.
+/// @param index Zero-based index of the viewport entry to query. Must be
+/// smaller than the list size.
+/// @param viewport The buffer viewport structure that will be populated with
+/// retrieved data.
+void gvr_buffer_viewport_list_get_item(
+ const gvr_buffer_viewport_list* viewport_list, size_t index,
+ gvr_buffer_viewport* viewport);
+
+/// Update an element of the viewport list or append a new one at the end.
+///
+/// @param viewport_list Pointer to a previously allocated viewport list.
+/// @param index Index of the buffer viewport entry to update. If the
+/// `viewport_list` size is equal to the index, a new viewport entry will be
+/// added. The `viewport_list` size must *not* be less than the index value.
+/// @param viewport A pointer to the buffer viewport object.
+void gvr_buffer_viewport_list_set_item(gvr_buffer_viewport_list* viewport_list,
+ size_t index,
+ const gvr_buffer_viewport* viewport);
+
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Swapchains and frames
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup swap_chain Swap chains and frames
+/// @brief Functions to create a swap chain, manipulate it and submit frames
+/// for lens distortion and presentation on the screen.
+/// @{
+
+/// Creates a default buffer specification.
+gvr_buffer_spec* gvr_buffer_spec_create(gvr_context* gvr);
+
+/// Destroy the buffer specification and null the pointer.
+void gvr_buffer_spec_destroy(gvr_buffer_spec** spec);
+
+/// Gets the size of the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @return Size of the pixel buffer. The default is equal to the recommended
+/// render target size at the time when the specification was created.
+gvr_sizei gvr_buffer_spec_get_size(const gvr_buffer_spec* spec);
+
+/// Sets the size of the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @param size The size. Width and height must both be greater than zero.
+/// Otherwise, the application is aborted.
+void gvr_buffer_spec_set_size(gvr_buffer_spec* spec, gvr_sizei size);
+
+/// Gets the number of samples per pixel in the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @return Value >= 1 giving the number of samples. 1 means multisampling is
+/// disabled. Negative values and 0 are never returned.
+int32_t gvr_buffer_spec_get_samples(const gvr_buffer_spec* spec);
+
+/// Sets the number of samples per pixel in the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @param num_samples The number of samples. Negative values are an error.
+/// The values 0 and 1 are treated identically and indicate that
+// multisampling should be disabled.
+void gvr_buffer_spec_set_samples(gvr_buffer_spec* spec, int32_t num_samples);
+
+/// Sets the color format for the buffer to be created. Default format is
+/// GVR_COLOR_FORMAT_RGBA_8888.
+///
+/// @param spec Buffer specification.
+/// @param color_format The color format for the buffer. Valid formats are in
+/// the gvr_color_format_type enum.
+void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec,
+ int32_t color_format);
+
+/// Sets the depth and stencil format for the buffer to be created. Currently,
+/// only packed stencil formats are supported. Default format is
+/// GVR_DEPTH_STENCIL_FORMAT_DEPTH_16.
+///
+/// @param spec Buffer specification.
+/// @param depth_stencil_format The depth and stencil format for the buffer.
+/// Valid formats are in the gvr_depth_stencil_format_type enum.
+void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec,
+ int32_t depth_stencil_format);
+
+/// Creates a swap chain from the given buffer specifications.
+/// This is a potentially time-consuming operation. All frames within the
+/// swapchain will be allocated. Once rendering is stopped, call
+/// gvr_swap_chain_destroy() to free GPU resources. The passed gvr_context must
+/// not be destroyed until then.
+///
+/// Swap chains can have no buffers. This is useful when only displaying
+/// external surfaces. When `count` is zero, `buffers` must be null.
+///
+/// @param gvr GVR instance for which a swap chain will be created.
+/// @param buffers Array of pixel buffer specifications. Each frame in the
+/// swap chain will be composed of these buffers.
+/// @param count Number of buffer specifications in the array.
+/// @return Opaque handle to the newly created swap chain.
+gvr_swap_chain* gvr_swap_chain_create(gvr_context* gvr,
+ const gvr_buffer_spec** buffers,
+ int32_t count);
+
+/// Destroys the swap chain and nulls the pointer.
+void gvr_swap_chain_destroy(gvr_swap_chain** swap_chain);
+
+/// Gets the number of buffers in each frame of the swap chain.
+int32_t gvr_swap_chain_get_buffer_count(const gvr_swap_chain* swap_chain);
+
+/// Retrieves the size of the specified pixel buffer. Note that if the buffer
+/// was resized while the current frame was acquired, the return value will be
+/// different than the value obtained from the equivalent function for the
+/// current frame.
+///
+/// @param swap_chain The swap chain.
+/// @param index Index of the pixel buffer.
+/// @return Size of the specified pixel buffer in frames that will be returned
+/// from gvr_swap_chain_acquire_frame().
+gvr_sizei gvr_swap_chain_get_buffer_size(gvr_swap_chain* swap_chain,
+ int32_t index);
+
+/// Resizes the specified pixel buffer to the given size. The frames are resized
+/// when they are unused, so the currently acquired frame will not be resized
+/// immediately.
+///
+/// @param swap_chain The swap chain.
+/// @param index Index of the pixel buffer to resize.
+/// @param size New size for the specified pixel buffer.
+void gvr_swap_chain_resize_buffer(gvr_swap_chain* swap_chain, int32_t index,
+ gvr_sizei size);
+
+/// Acquires a frame from the swap chain for rendering. Buffers that are part of
+/// the frame can then be bound with gvr_frame_bind_buffer(). Once the frame
+/// is finished and all its constituent buffers are ready, call
+/// gvr_frame_submit() to display it while applying lens distortion.
+///
+/// @param swap_chain The swap chain.
+/// @return Handle to the acquired frame. NULL if the swap chain is invalid,
+/// or if acquire has already been called on this swap chain.
+gvr_frame* gvr_swap_chain_acquire_frame(gvr_swap_chain* swap_chain);
+
+/// Binds a pixel buffer that is part of the frame to the OpenGL framebuffer.
+///
+/// @param frame Frame handle acquired from the swap chain.
+/// @param index Index of the pixel buffer to bind. This corresponds to the
+/// index in the buffer spec list that was passed to
+/// gvr_swap_chain_create().
+void gvr_frame_bind_buffer(gvr_frame* frame, int32_t index);
+
+/// Unbinds any buffers bound from this frame and binds the default OpenGL
+/// framebuffer.
+void gvr_frame_unbind(gvr_frame* frame);
+
+/// Returns the dimensions of the pixel buffer with the specified index. Note
+/// that a frame that was acquired before resizing a swap chain buffer will not
+/// be resized until it is submitted to the swap chain.
+///
+/// @param frame Frame handle.
+/// @param index Index of the pixel buffer to inspect.
+/// @return Dimensions of the specified pixel buffer.
+gvr_sizei gvr_frame_get_buffer_size(const gvr_frame* frame, int32_t index);
+
+/// Gets the name (ID) of the framebuffer object associated with the specified
+/// buffer. The OpenGL state is not modified.
+///
+/// @param frame Frame handle.
+/// @param index Index of a pixel buffer.
+/// @return OpenGL object name (ID) of a framebuffer object which can be used
+/// to render into the buffer. The ID is valid only until the frame is
+/// submitted.
+int32_t gvr_frame_get_framebuffer_object(const gvr_frame* frame, int32_t index);
+
+/// Submits the frame for distortion and display on the screen. The passed
+/// pointer is nulled to prevent reuse.
+///
+/// @param frame The frame to submit.
+/// @param list Buffer view configuration to be used for this frame.
+/// @param head_space_from_start_space Transform from start space (space with
+/// head at the origin at last tracking reset) to head space (space with
+/// head at the origin and axes aligned to the view vector).
+void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list,
+ gvr_mat4f head_space_from_start_space);
+
+/// Resets the OpenGL framebuffer binding to what it was at the time the
+/// passed gvr_context was created.
+void gvr_bind_default_framebuffer(gvr_context* gvr);
+
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head tracking
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup Headtracking Head tracking
+/// @brief Functions for managing head tracking.
+/// @{
+
+/// Gets the current monotonic system time.
+///
+/// @return The current monotonic system time.
+gvr_clock_time_point gvr_get_time_point_now();
+
+/// Gets the rotation from start space to head space. The head space is a
+/// space where the head is at the origin and faces the -Z direction.
+///
+/// @param gvr Pointer to the gvr instance from which to get the pose.
+/// @param time The time at which to get the head pose. The time should be in
+/// the future. If the time is not in the future, it will be clamped to now.
+/// @return A matrix representation of the rotation from start space (the space
+/// where the head was last reset) to head space (the space with the head
+/// at the origin, and the axes aligned to the view vector).
+gvr_mat4f gvr_get_head_space_from_start_space_rotation(
+ const gvr_context* gvr, const gvr_clock_time_point time);
+
+/// Applies a simple neck model translation based on the rotation of the
+/// provided head pose.
+///
+/// Note: Neck model application may not be appropriate for all tracking
+/// scenarios, e.g., when tracking is non-biological.
+///
+/// @param gvr Pointer to the context instance from which the pose was obtained.
+/// @param head_rotation_in_start_space The head rotation as returned by
+/// gvr_get_head_space_from_start_space_rotation().
+/// @param factor A scaling factor for the neck model offset, clamped from 0 to
+/// 1. This should be 1 for most scenarios, while 0 will effectively disable
+/// neck model application. This value can be animated to smoothly
+/// interpolate between alternative (client-defined) neck models.
+/// @return The new head pose with the neck model applied.
+gvr_mat4f gvr_apply_neck_model(const gvr_context* gvr,
+ gvr_mat4f head_space_from_start_space_rotation,
+ float factor);
+
+/// Pauses head tracking, disables all sensors (to save power).
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be paused and
+/// sensors disabled.
+void gvr_pause_tracking(gvr_context* gvr);
+
+/// Resumes head tracking, re-enables all sensors.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be resumed.
+void gvr_resume_tracking(gvr_context* gvr);
+
+/// Resets head tracking.
+///
+/// This API call is deprecated. Use gvr_recenter_tracking instead, which
+/// accomplishes the same effects but avoids the undesirable side-effects of
+/// a full reset (temporary loss of tracking quality).
+///
+/// Only to be used by Cardboard apps. Daydream apps must not call this. On the
+/// Daydream platform, recentering is handled automatically and should never
+/// be triggered programatically by applications. Hybrid apps that support both
+/// Cardboard and Daydream must only call this function when in Cardboard mode
+/// (that is, when the phone is paired with a Cardboard viewer), never in
+/// Daydream mode.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be reseted.
+/// @deprecated Calls to this method can be safely replaced by calls to
+// gvr_recenter_tracking.
+void gvr_reset_tracking(gvr_context* gvr);
+
+/// Recenters the head orientation (resets the yaw to zero, leaving pitch and
+/// roll unmodified).
+///
+/// Only to be used by Cardboard apps. Daydream apps must not call this. On the
+/// Daydream platform, recentering is handled automatically and should never
+/// be triggered programatically by applications. Hybrid apps that support both
+/// Cardboard and Daydream must only call this function when in Cardboard mode
+/// (that is, when the phone is paired with a Cardboard viewer), never in
+/// Daydream mode.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be
+/// recentered.
+void gvr_recenter_tracking(gvr_context* gvr);
+
+/// @}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Head mounted display.
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup HMD Head Mounted Display
+/// @brief Functions for managing viewer information.
+/// @{
+
+/// Sets the default viewer profile specified by viewer_profile_uri.
+/// The viewer_profile_uri that is passed in will be ignored if a valid
+/// viewer profile has already been stored on the device that the app
+/// is running on.
+///
+/// Note: This function has the potential of blocking for up to 30 seconds for
+/// each redirect if a shortened URI is passed in as argument. It will try to
+/// unroll the shortened URI for a maximum number of 5 times if the redirect
+/// continues. In that case, it is recommended to create a separate thread to
+/// call this function so that other tasks like rendering will not be blocked
+/// on this. The blocking can be avoided if a standard URI is passed in.
+///
+/// @param gvr Pointer to the gvr instance which to set the profile on.
+/// @param viewer_profile_uri A string that contains either the shortened URI or
+/// the standard URI representing the viewer profile that the app should be
+/// using. If the valid viewer profile can be found on the device, the URI
+/// that is passed in will be ignored and nothing will happen. Otherwise,
+/// gvr will look for the viewer profile specified by viewer_profile_uri,
+/// and it will be stored if found. Also, the values will be applied to gvr.
+/// A valid standard URI can be generated from this page:
+/// https://www.google.com/get/cardboard/viewerprofilegenerator/
+/// @return True if the viewer profile specified by viewer_profile_uri was
+/// successfully stored and applied, false otherwise.
+bool gvr_set_default_viewer_profile(gvr_context* gvr,
+ const char* viewer_profile_uri);
+
+/// Refreshes gvr_context with the viewer profile that is stored on the device.
+/// If it can not find the viewer profile, nothing will happen.
+///
+/// @param gvr Pointer to the gvr instance to refresh the profile on.
+void gvr_refresh_viewer_profile(gvr_context* gvr);
+
+/// Gets the name of the viewer vendor.
+///
+/// @param gvr Pointer to the gvr instance from which to get the vendor.
+/// @return A pointer to the vendor name. May be NULL if no viewer is paired.
+/// WARNING: This method guarantees the validity of the returned pointer
+/// only until the next use of the `gvr` context. The string should be
+/// copied immediately if persistence is required.
+const char* gvr_get_viewer_vendor(const gvr_context* gvr);
+
+/// Gets the name of the viewer model.
+///
+/// @param gvr Pointer to the gvr instance from which to get the name.
+/// @return A pointer to the model name. May be NULL if no viewer is paired.
+/// WARNING: This method guarantees the validity of the returned pointer
+/// only until the next use of the `gvr` context. The string should be
+/// copied immediately if persistence is required.
+const char* gvr_get_viewer_model(const gvr_context* gvr);
+
+/// Gets the type of the viewer, as defined by gvr_viewer_type.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewer type.
+/// @return The gvr_viewer_type of the currently paired viewer.
+int32_t gvr_get_viewer_type(const gvr_context* gvr);
+
+/// Gets the transformation matrix to convert from Head Space to Eye Space for
+/// the given eye.
+///
+/// @param gvr Pointer to the gvr instance from which to get the matrix.
+/// @param eye Selected gvr_eye type.
+/// @return Transformation matrix from Head Space to selected Eye Space.
+gvr_mat4f gvr_get_eye_from_head_matrix(const gvr_context* gvr,
+ const int32_t eye);
+
+/// Gets the window bounds.
+///
+/// @param gvr Pointer to the gvr instance from which to get the bounds.
+///
+/// @return Window bounds in physical pixels.
+gvr_recti gvr_get_window_bounds(const gvr_context* gvr);
+
+/// Computes the distorted point for a given point in a given eye. The
+/// distortion inverts the optical distortion caused by the lens for the eye.
+/// Due to chromatic aberration, the distortion is different for each
+/// color channel.
+///
+/// @param gvr Pointer to the gvr instance which will do the computing.
+/// @param eye The gvr_eye type (left or right).
+/// @param uv_in A point in screen eye Viewport Space in [0,1]^2 with (0, 0)
+/// in the lower left corner of the eye's viewport and (1, 1) in the
+/// upper right corner of the eye's viewport.
+/// @param uv_out A pointer to an array of (at least) 3 elements, with each
+/// element being a Point2f representing a point in render texture eye
+/// Viewport Space in [0,1]^2 with (0, 0) in the lower left corner of the
+/// eye's viewport and (1, 1) in the upper right corner of the eye's
+/// viewport.
+/// `uv_out[0]` is the corrected position of `uv_in` for the red channel
+/// `uv_out[1]` is the corrected position of `uv_in` for the green channel
+/// `uv_out[2]` is the corrected position of `uv_in` for the blue channel
+void gvr_compute_distorted_point(const gvr_context* gvr, const int32_t eye,
+ const gvr_vec2f uv_in, gvr_vec2f uv_out[3]);
+
+/// @}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+namespace gvr {
+
+/// Convenience C++ wrapper for gvr_user_prefs.
+class UserPrefs {
+ public:
+ /// Creates a C++ wrapper for a gvr_user_prefs object. Note that unlike most
+ /// of the C++ wrappers in the API, this does not take ownership, as the
+ /// gvr_user_prefs will remain valid for the lifetime of the GVR context.
+ explicit UserPrefs(const gvr_user_prefs* user_prefs)
+ : user_prefs_(user_prefs) {}
+
+ UserPrefs(UserPrefs&& other) : user_prefs_(nullptr) {
+ std::swap(user_prefs_, other.user_prefs_);
+ }
+
+ UserPrefs& operator=(UserPrefs&& other) {
+ std::swap(user_prefs_, other.user_prefs_);
+ return *this;
+ }
+
+ /// For more information, see gvr_user_prefs_get_controller_handedness().
+ ControllerHandedness GetControllerHandedness() const {
+ return static_cast<ControllerHandedness>(
+ gvr_user_prefs_get_controller_handedness(user_prefs_));
+ }
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ const gvr_user_prefs* cobj() const { return user_prefs_; }
+
+ private:
+ const gvr_user_prefs* user_prefs_;
+
+ // Disallow copy and assign.
+ UserPrefs(const UserPrefs&);
+ void operator=(const UserPrefs&);
+};
+
+/// Convenience C++ wrapper for the opaque gvr_buffer_viewport type.
+/// The constructor allocates memory, so when used in tight loops, instances
+/// should be reused.
+class BufferViewport {
+ public:
+ BufferViewport(BufferViewport&& other)
+ : viewport_(nullptr) {
+ std::swap(viewport_, other.viewport_);
+ }
+
+ BufferViewport& operator=(BufferViewport&& other) {
+ std::swap(viewport_, other.viewport_);
+ return *this;
+ }
+
+ ~BufferViewport() {
+ if (viewport_) gvr_buffer_viewport_destroy(&viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_source_fov().
+ Rectf GetSourceFov() const {
+ return gvr_buffer_viewport_get_source_fov(viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_source_fov().
+ void SetSourceFov(const Rectf& fov) {
+ gvr_buffer_viewport_set_source_fov(viewport_, fov);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_transform().
+ Mat4f GetTransform() const {
+ return gvr_buffer_viewport_get_transform(viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_transform().
+ void SetTransform(const Mat4f& transform) {
+ gvr_buffer_viewport_set_transform(viewport_, transform);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_source_uv().
+ Rectf GetSourceUv() const {
+ return gvr_buffer_viewport_get_source_uv(viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_source_uv().
+ void SetSourceUv(const Rectf& uv) {
+ gvr_buffer_viewport_set_source_uv(viewport_, uv);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_target_eye().
+ Eye GetTargetEye() const {
+ return static_cast<Eye>(gvr_buffer_viewport_get_target_eye(viewport_));
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_target_eye().
+ void SetTargetEye(Eye eye) {
+ gvr_buffer_viewport_set_target_eye(viewport_, eye);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_source_buffer_index().
+ int32_t GetSourceBufferIndex() const {
+ return gvr_buffer_viewport_get_source_buffer_index(viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_source_buffer_index().
+ void SetSourceBufferIndex(int32_t buffer_index) {
+ gvr_buffer_viewport_set_source_buffer_index(viewport_, buffer_index);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_external_surface_id().
+ int32_t GetExternalSurfaceId() const {
+ return gvr_buffer_viewport_get_external_surface_id(viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_set_external_surface_id().
+ void SetExternalSurfaceId(const int32_t external_surface_id) {
+ gvr_buffer_viewport_set_external_surface_id(viewport_, external_surface_id);
+ }
+
+ /// For more information, see gvr_buffer_viewport_get_reprojection().
+ gvr_reprojection GetReprojection() const {
+ return static_cast<gvr_reprojection>(
+ gvr_buffer_viewport_get_reprojection(viewport_));
+ }
+ /// For more information, see gvr_buffer_viewport_set_reprojection().
+ void SetReprojection(gvr_reprojection reprojection) {
+ gvr_buffer_viewport_set_reprojection(viewport_, reprojection);
+ }
+
+ /// For more information, see gvr_buffer_viewport_equal().
+ bool operator==(const BufferViewport& other) const {
+ return gvr_buffer_viewport_equal(viewport_, other.viewport_) ? true : false;
+ }
+ bool operator!=(const BufferViewport& other) const {
+ return !(*this == other);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit BufferViewport(gvr_buffer_viewport* viewport)
+ : viewport_(viewport) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_buffer_viewport* cobj() { return viewport_; }
+ const gvr_buffer_viewport* cobj() const { return viewport_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_buffer_viewport* release() {
+ auto result = viewport_;
+ viewport_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ friend class GvrApi;
+ friend class BufferViewportList;
+
+ explicit BufferViewport(gvr_context* gvr)
+ : viewport_(gvr_buffer_viewport_create(gvr)) {}
+
+ gvr_buffer_viewport* viewport_;
+};
+
+/// Convenience C++ wrapper for the opaque gvr_buffer_viewport_list type. This
+/// class will automatically release the wrapped gvr_buffer_viewport_list upon
+/// destruction. It can only be created via a `GvrApi` instance, and its
+/// validity is tied to the lifetime of that instance.
+class BufferViewportList {
+ public:
+ BufferViewportList(BufferViewportList&& other)
+ : context_(nullptr), viewport_list_(nullptr) {
+ std::swap(context_, other.context_);
+ std::swap(viewport_list_, other.viewport_list_);
+ }
+
+ BufferViewportList& operator=(BufferViewportList&& other) {
+ std::swap(context_, other.context_);
+ std::swap(viewport_list_, other.viewport_list_);
+ return *this;
+ }
+
+ ~BufferViewportList() {
+ if (viewport_list_) {
+ gvr_buffer_viewport_list_destroy(&viewport_list_);
+ }
+ }
+
+ /// For more information, see gvr_get_recommended_buffer_viewports().
+ void SetToRecommendedBufferViewports() {
+ gvr_get_recommended_buffer_viewports(context_, viewport_list_);
+ }
+
+ /// For more information, see gvr_get_screen_buffer_viewports().
+ void SetToScreenBufferViewports() {
+ gvr_get_screen_buffer_viewports(context_, viewport_list_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_list_set_item().
+ void SetBufferViewport(size_t index, const BufferViewport& viewport) {
+ gvr_buffer_viewport_list_set_item(viewport_list_, index,
+ viewport.viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_list_get_item().
+ void GetBufferViewport(size_t index, BufferViewport* viewport) const {
+ gvr_buffer_viewport_list_get_item(viewport_list_, index,
+ viewport->viewport_);
+ }
+
+ /// For more information, see gvr_buffer_viewport_list_get_size().
+ size_t GetSize() const {
+ return gvr_buffer_viewport_list_get_size(viewport_list_);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ BufferViewportList(gvr_buffer_viewport_list* viewport_list,
+ gvr_context* context)
+ : context_(context),
+ viewport_list_(viewport_list) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_buffer_viewport_list* cobj() { return viewport_list_; }
+ const gvr_buffer_viewport_list* cobj() const { return viewport_list_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_buffer_viewport_list* release() {
+ auto result = viewport_list_;
+ viewport_list_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ friend class Frame;
+ friend class GvrApi;
+ friend class SwapChain;
+
+ explicit BufferViewportList(gvr_context* context)
+ : context_(context),
+ viewport_list_(gvr_buffer_viewport_list_create(context)) {}
+
+ const gvr_context* context_;
+ gvr_buffer_viewport_list* viewport_list_;
+
+ // Disallow copy and assign.
+ BufferViewportList(const BufferViewportList&) = delete;
+ void operator=(const BufferViewportList&) = delete;
+};
+
+/// Convenience C++ wrapper for gvr_buffer_spec, an opaque pixel buffer
+/// specification. Frees the underlying gvr_buffer_spec on destruction.
+class BufferSpec {
+ public:
+ BufferSpec(BufferSpec&& other)
+ : spec_(nullptr) {
+ std::swap(spec_, other.spec_);
+ }
+
+ BufferSpec& operator=(BufferSpec&& other) {
+ std::swap(spec_, other.spec_);
+ return *this;
+ }
+
+ ~BufferSpec() {
+ if (spec_) gvr_buffer_spec_destroy(&spec_);
+ }
+
+ /// Gets the buffer's size. The default value is the recommended render
+ /// target size. For more information, see gvr_buffer_spec_get_size().
+ Sizei GetSize() const {
+ return gvr_buffer_spec_get_size(spec_);
+ }
+
+ /// Sets the buffer's size. For more information, see
+ /// gvr_buffer_spec_set_size().
+ void SetSize(const Sizei& size) {
+ gvr_buffer_spec_set_size(spec_, size);
+ }
+
+ /// Sets the buffer's size to the passed width and height. For more
+ /// information, see gvr_buffer_spec_set_size().
+ ///
+ /// @param width The width in pixels. Must be greater than 0.
+ /// @param height The height in pixels. Must be greater than 0.
+ void SetSize(int32_t width, int32_t height) {
+ gvr_sizei size{width, height};
+ gvr_buffer_spec_set_size(spec_, size);
+ }
+
+ /// Gets the number of samples per pixel in the buffer. For more
+ /// information, see gvr_buffer_spec_get_samples().
+ int32_t GetSamples() const { return gvr_buffer_spec_get_samples(spec_); }
+
+ /// Sets the number of samples per pixel. For more information, see
+ /// gvr_buffer_spec_set_samples().
+ void SetSamples(int32_t num_samples) {
+ gvr_buffer_spec_set_samples(spec_, num_samples);
+ }
+
+ /// Sets the color format for this buffer. For more information, see
+ /// gvr_buffer_spec_set_color_format().
+ void SetColorFormat(ColorFormat color_format) {
+ gvr_buffer_spec_set_color_format(spec_, color_format);
+ }
+
+ /// Sets the depth and stencil format for this buffer. For more
+ /// information, see gvr_buffer_spec_set_depth_stencil_format().
+ void SetDepthStencilFormat(DepthStencilFormat depth_stencil_format) {
+ gvr_buffer_spec_set_depth_stencil_format(spec_, depth_stencil_format);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit BufferSpec(gvr_buffer_spec* spec) : spec_(spec) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_buffer_spec* cobj() { return spec_; }
+ const gvr_buffer_spec* cobj() const { return spec_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_buffer_spec* release() {
+ auto result = spec_;
+ spec_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ friend class GvrApi;
+ friend class SwapChain;
+
+ explicit BufferSpec(gvr_context* gvr) {
+ spec_ = gvr_buffer_spec_create(gvr);
+ }
+
+ gvr_buffer_spec* spec_;
+};
+
+/// Convenience C++ wrapper for gvr_frame, which represents a single frame
+/// acquired for rendering from the swap chain.
+class Frame {
+ public:
+ Frame(Frame&& other) : frame_(nullptr) {
+ std::swap(frame_, other.frame_);
+ }
+
+ Frame& operator=(Frame&& other) {
+ std::swap(frame_, other.frame_);
+ return *this;
+ }
+
+ ~Frame() {
+ // The swap chain owns the frame, so no clean-up is required.
+ }
+
+ /// For more information, see gvr_frame_get_buffer_size().
+ Sizei GetBufferSize(int32_t index) const {
+ return gvr_frame_get_buffer_size(frame_, index);
+ }
+
+ /// For more information, see gvr_frame_bind_buffer().
+ void BindBuffer(int32_t index) {
+ gvr_frame_bind_buffer(frame_, index);
+ }
+
+ /// For more information, see gvr_frame_unbind().
+ void Unbind() {
+ gvr_frame_unbind(frame_);
+ }
+
+ /// For more information, see gvr_frame_get_framebuffer_object().
+ int32_t GetFramebufferObject(int32_t index) {
+ return gvr_frame_get_framebuffer_object(frame_, index);
+ }
+
+ /// For more information, see gvr_frame_submit().
+ void Submit(const BufferViewportList& viewport_list,
+ const Mat4f& head_space_from_start_space) {
+ gvr_frame_submit(&frame_, viewport_list.viewport_list_,
+ head_space_from_start_space);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit Frame(gvr_frame* frame) : frame_(frame) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_frame* cobj() { return frame_; }
+ const gvr_frame* cobj() const { return frame_; }
+
+ /// Returns whether the wrapped gvr_frame reference is valid.
+ bool is_valid() const { return frame_ != nullptr; }
+ explicit operator bool const() { return is_valid(); }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_frame* release() {
+ auto result = frame_;
+ frame_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ friend class SwapChain;
+
+ gvr_frame* frame_;
+};
+
+/// Convenience C++ wrapper for gvr_swap_chain, which represents a queue of
+/// frames. The GvrApi object must outlive any SwapChain objects created from
+/// it.
+class SwapChain {
+ public:
+ SwapChain(SwapChain&& other)
+ : swap_chain_(nullptr) {
+ std::swap(swap_chain_, other.swap_chain_);
+ }
+
+ SwapChain& operator=(SwapChain&& other) {
+ std::swap(swap_chain_, other.swap_chain_);
+ return *this;
+ }
+
+ ~SwapChain() {
+ if (swap_chain_) gvr_swap_chain_destroy(&swap_chain_);
+ }
+
+ /// For more information, see gvr_swap_chain_get_buffer_count().
+ int32_t GetBufferCount() const {
+ return gvr_swap_chain_get_buffer_count(swap_chain_);
+ }
+
+ /// For more information, see gvr_swap_chain_get_buffer_size().
+ Sizei GetBufferSize(int32_t index) const {
+ return gvr_swap_chain_get_buffer_size(swap_chain_, index);
+ }
+
+ /// For more information, see gvr_swap_chain_resize_buffer().
+ void ResizeBuffer(int32_t index, Sizei size) {
+ gvr_swap_chain_resize_buffer(swap_chain_, index, size);
+ }
+
+ /// For more information, see gvr_swap_chain_acquire_frame().
+ /// Note that if Frame acquisition fails, the returned Frame may not be valid.
+ /// The caller should inspect the returned Frame's validity before using,
+ /// and reschedule frame acquisition upon failure.
+ Frame AcquireFrame() {
+ Frame result(gvr_swap_chain_acquire_frame(swap_chain_));
+ return result;
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit SwapChain(gvr_swap_chain* swap_chain) : swap_chain_(swap_chain) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_swap_chain* cobj() { return swap_chain_; }
+ const gvr_swap_chain* cobj() const { return swap_chain_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_swap_chain* release() {
+ auto result = swap_chain_;
+ swap_chain_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ friend class GvrApi;
+
+ SwapChain(gvr_context* gvr, const std::vector<BufferSpec>& specs) {
+ std::vector<const gvr_buffer_spec*> c_specs;
+ for (const auto& spec : specs)
+ c_specs.push_back(spec.spec_);
+ swap_chain_ = gvr_swap_chain_create(gvr, c_specs.data(),
+ static_cast<int32_t>(c_specs.size()));
+ }
+
+ gvr_swap_chain* swap_chain_;
+
+ // Disallow copy and assign.
+ SwapChain(const SwapChain&);
+ void operator=(const SwapChain&);
+};
+
+/// This is a convenience C++ wrapper for the Google VR C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+/// Example API usage:
+///
+/// // Functionality supplied by the application in the example below has
+/// // the "app-" prefix.
+/// #ifdef __ANDROID__
+/// // On Android, the gvr_context should almost always be obtained from the
+/// // Java GvrLayout object via
+/// // GvrLayout.getGvrApi().getNativeGvrContext().
+/// std::unique_ptr<GvrApi> gvr = GvrApi::WrapNonOwned(gvr_context);
+/// #else
+/// std::unique_ptr<GvrApi> gvr = GvrApi::Create();
+/// #endif
+///
+/// gvr->InitializeGl();
+///
+/// gvr::BufferViewportList viewport_list =
+/// gvr->CreateEmptyBufferViewportList();
+/// gvr->GetRecommendedBufferViewports(&viewport_list);
+/// gvr::BufferViewport left_eye_viewport = gvr->CreateBufferViewport();
+/// gvr::BufferViewport right_eye_viewport = gvr->CreateBufferViewport();
+/// viewport_list.Get(0, &left_eye_view);
+/// viewport_list.Get(1, &right_eye_view);
+///
+/// std::vector<gvr::BufferSpec> specs;
+/// specs.push_back(gvr->CreateBufferSpec());
+/// specs[0].SetSamples(app_samples);
+/// gvr::SwapChain swap_chain = gvr->CreateSwapChain(specs);
+///
+/// while (client_app_should_render) {
+/// // A client app should be ready for the render target size to change
+/// // whenever a new QR code is scanned, or a new viewer is paired.
+/// gvr::Sizei render_target_size =
+/// gvr->GetRecommendedRenderTargetSize();
+/// swap_chain.ResizeBuffer(0, render_target_size);
+/// gvr::Frame frame = swap_chain.AcquireFrame();
+/// while (!frame) {
+/// std::this_thread::sleep_for(2ms);
+/// frame = swap_chain.AcquireFrame();
+/// }
+///
+/// // This function will depend on your render loop's implementation.
+/// gvr::ClockTimePoint next_vsync = AppGetNextVsyncTime();
+///
+/// const gvr::Mat4f head_view =
+/// gvr->GetHeadSpaceFromStartSpaceRotation(next_vsync);
+/// const gvr::Mat4f left_eye_view = MatrixMultiply(
+/// gvr->GetEyeFromHeadMatrix(kLeftEye), head_view);
+/// const gvr::Mat4f right_eye_view = MatrixMultiply(
+/// gvr->GetEyeFromHeadMatrix(kRightEye), head_view);
+///
+/// frame.BindBuffer(0);
+/// // App does its rendering to the current framebuffer here.
+/// AppDoSomeRenderingForEye(
+/// left_eye_viewport.GetSourceUv(), left_eye_view);
+/// AppDoSomeRenderingForEye(
+/// right_eye_viewport.GetSourceUv(), right_eye_view);
+/// frame.Unbind();
+/// frame.Submit(viewport_list, head_matrix);
+/// }
+///
+class GvrApi {
+ public:
+#ifdef __ANDROID__
+ /// Instantiates and returns a GvrApi instance that owns a gvr_context.
+ ///
+ /// @param env The JNIEnv associated with the current thread.
+ /// @param app_context The Android application context. This must be the
+ /// application context, NOT an Activity context (Note: from any Android
+ /// Activity in your app, you can call getApplicationContext() to
+ /// retrieve the application context).
+ /// @param class_loader The class loader to use when loading Java classes.
+ /// This must be your app's main class loader (usually accessible through
+ /// activity.getClassLoader() on any of your Activities).
+ /// @return unique_ptr to the created GvrApi instance, nullptr on failure.
+ static std::unique_ptr<GvrApi> Create(JNIEnv* env, jobject app_context,
+ jobject class_loader) {
+ gvr_context* context = gvr_create(env, app_context, class_loader);
+ if (!context) {
+ return nullptr;
+ }
+ return std::unique_ptr<GvrApi>(new GvrApi(context, true /* owned */));
+ }
+#else
+ /// Instantiates and returns a GvrApi instance that owns a gvr_context.
+ ///
+ /// @return unique_ptr to the created GvrApi instance, nullptr on failure.
+ static std::unique_ptr<GvrApi> Create() {
+ gvr_context* context = gvr_create();
+ if (!context) {
+ return nullptr;
+ }
+ return std::unique_ptr<GvrApi>(new GvrApi(context, true /* owned */));
+ }
+#endif // #ifdef __ANDROID__
+
+ ~GvrApi() {
+ if (context_ && owned_) {
+ gvr_destroy(&context_);
+ }
+ }
+
+ /// @name Error handling
+ /// @{
+
+ /// For more information, see gvr_get_error().
+ Error GetError() { return static_cast<Error>(gvr_get_error(context_)); }
+
+ /// For more information, see gvr_clear_error().
+ Error ClearError() { return static_cast<Error>(gvr_clear_error(context_)); }
+
+ /// For more information, see gvr_get_error_string().
+ static const char* GetErrorString(Error error_code) {
+ return gvr_get_error_string(error_code);
+ }
+
+ /// For more information, see gvr_get_user_prefs().
+ UserPrefs GetUserPrefs() { return UserPrefs(gvr_get_user_prefs(context_)); }
+
+ /// @}
+
+ /// @name Rendering
+ /// @{
+
+ /// For more information, see gvr_initialize_gl().
+ void InitializeGl() { gvr_initialize_gl(context_); }
+
+ /// For more information, see gvr_get_async_reprojection_enabled().
+ bool GetAsyncReprojectionEnabled() const {
+ return gvr_get_async_reprojection_enabled(context_);
+ }
+
+ /// Constructs a C++ wrapper for a gvr_buffer_viewport object. For more
+ /// information, see gvr_buffer_viewport_create().
+ ///
+ /// @return A new BufferViewport instance with memory allocated for an
+ /// underlying gvr_buffer_viewport.
+ BufferViewport CreateBufferViewport() const {
+ return BufferViewport(context_);
+ }
+
+ /// Constructs a C++ wrapper for a gvr_buffer_viewport_list object.
+ /// For more information, see gvr_buffer_viewport_list_create().
+ ///
+ /// @return A new, empty BufferViewportList instance.
+ /// Note: The validity of the returned object is closely tied to the
+ /// lifetime of the member gvr_context. The caller is responsible for
+ /// ensuring correct usage accordingly.
+ BufferViewportList CreateEmptyBufferViewportList() const {
+ return BufferViewportList(context_);
+ }
+
+ /// For more information, see gvr_get_maximum_effective_render_target_size().
+ Sizei GetMaximumEffectiveRenderTargetSize() const {
+ return gvr_get_maximum_effective_render_target_size(context_);
+ }
+
+ /// For more information, see gvr_get_screen_target_size().
+ Sizei GetScreenTargetSize() const {
+ return gvr_get_screen_target_size(context_);
+ }
+
+ /// For more information, see gvr_set_surface_size().
+ void SetSurfaceSize(Sizei surface_size_pixels) {
+ gvr_set_surface_size(context_, surface_size_pixels);
+ }
+
+ /// For more information, see gvr_distort_to_screen().
+ void DistortToScreen(int32_t texture_id,
+ const BufferViewportList& viewport_list,
+ const Mat4f& rendered_head_pose_in_start_space_matrix,
+ const ClockTimePoint& texture_presentation_time) {
+ gvr_distort_to_screen(context_, texture_id, viewport_list.viewport_list_,
+ rendered_head_pose_in_start_space_matrix,
+ texture_presentation_time);
+ }
+
+ /// For more information, see gvr_buffer_spec_create().
+ BufferSpec CreateBufferSpec() {
+ return BufferSpec(context_);
+ }
+
+ /// For more information, see gvr_swap_chain_create().
+ SwapChain CreateSwapChain(const std::vector<BufferSpec>& specs) {
+ return SwapChain(context_, specs);
+ }
+
+ /// For more information, see gvr_bind_default_framebuffer().
+ void BindDefaultFramebuffer() {
+ gvr_bind_default_framebuffer(context_);
+ }
+ /// @}
+
+ /// @name Head tracking
+ /// @{
+
+ /// For more information see gvr_get_head_space_from_start_space_rotation.
+ ///
+ /// @param time_point The time at which to calculate the head pose in start
+ /// space.
+ /// @return The matrix representation of the rotation from start space
+ /// (the space with the head pose at the last tracking reset at origin) to
+ /// head space (the space with the head at origin and axes aligned to the
+ /// view vector).
+ Mat4f GetHeadSpaceFromStartSpaceRotation(const ClockTimePoint& time_point) {
+ return gvr_get_head_space_from_start_space_rotation(context_, time_point);
+ }
+
+ /// For more information, see gvr_apply_neck_model().
+ Mat4f ApplyNeckModel(const Mat4f& head_pose_in_start_space, float factor) {
+ return gvr_apply_neck_model(context_, head_pose_in_start_space, factor);
+ }
+
+ /// For more information, see gvr_pause_tracking().
+ void PauseTracking() { gvr_pause_tracking(context_); }
+
+ /// For more information, see gvr_resume_tracking().
+ void ResumeTracking() { gvr_resume_tracking(context_); }
+
+ /// For more information, see gvr_reset_tracking().
+ void ResetTracking() { gvr_reset_tracking(context_); }
+
+ // For more information, see gvr_recenter_tracking().
+ void RecenterTracking() { gvr_recenter_tracking(context_); }
+
+ /// For more information, see gvr_get_time_point_now().
+ static ClockTimePoint GetTimePointNow() { return gvr_get_time_point_now(); }
+ /// @}
+
+ /// @name Viewer parameters
+ /// @{
+
+ /// For more information, see gvr_set_default_viewer_profile().
+ bool SetDefaultViewerProfile(const char* viewer_profile_uri) {
+ return gvr_set_default_viewer_profile(context_, viewer_profile_uri);
+ }
+
+ /// For more information, see gvr_refresh_viewer_profile().
+ void RefreshViewerProfile() { gvr_refresh_viewer_profile(context_); }
+
+ /// For more information, see gvr_get_viewer_vendor().
+ const char* GetViewerVendor() const {
+ return gvr_get_viewer_vendor(context_);
+ }
+
+ /// For more information, see gvr_get_viewer_model().
+ const char* GetViewerModel() const { return gvr_get_viewer_model(context_); }
+
+ /// For more information, see gvr_get_viewer_type().
+ ViewerType GetViewerType() const {
+ return static_cast<ViewerType>(gvr_get_viewer_type(context_));
+ }
+
+ /// For more information, see gvr_get_eye_from_head_matrix().
+ Mat4f GetEyeFromHeadMatrix(Eye eye) const {
+ return gvr_get_eye_from_head_matrix(context_, eye);
+ }
+
+ /// For more information, see gvr_get_window_bounds().
+ Recti GetWindowBounds() const { return gvr_get_window_bounds(context_); }
+
+ /// For more information, see gvr_compute_distorted_point().
+ std::array<Vec2f, 3> ComputeDistortedPoint(Eye eye, const Vec2f& uv_in) {
+ std::array<Vec2f, 3> uv_out = {{{}}};
+ gvr_compute_distorted_point(context_, eye, uv_in, uv_out.data());
+ return uv_out;
+ }
+ /// @}
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and optionally takes ownership.
+ ///
+ /// @param context C object to wrap.
+ /// @param owned Whether the wrapper will own the underlying C object.
+ explicit GvrApi(gvr_context* context, bool owned = true)
+ : context_(context), owned_(owned) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_context* cobj() { return context_; }
+ const gvr_context* cobj() const { return context_; }
+
+ /// @deprecated Use cobj() instead.
+ gvr_context* GetContext() { return context_; }
+ /// @deprecated Use cobj() instead.
+ const gvr_context* GetContext() const { return context_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_context* release() {
+ auto result = context_;
+ context_ = nullptr;
+ return result;
+ }
+
+ /// Instantiates a GvrApi instance that wraps a *non-owned* gvr_context.
+ ///
+ /// Ownership of the provided `context` remains with the caller, and they
+ /// are responsible for ensuring proper disposal of the context.
+ ///
+ /// @param context Pointer to a non-null, non-owned gvr_context instance.
+ /// @return unique_ptr to the created GvrApi instance. Never null.
+ static std::unique_ptr<GvrApi> WrapNonOwned(gvr_context* context) {
+ return std::unique_ptr<GvrApi>(new GvrApi(context, false /* owned */));
+ }
+ /// @}
+
+ private:
+ gvr_context* context_;
+
+ // Whether context_ is owned by the GvrApi instance. If owned, the context
+ // will be released upon destruction.
+ const bool owned_;
+
+ // Disallow copy and assign.
+ GvrApi(const GvrApi&);
+ void operator=(const GvrApi&);
+};
+
+} // namespace gvr
+#endif // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h
new file mode 100644
index 0000000..eee3d0c
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h
@@ -0,0 +1,854 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
+
+#if __ANDROID__
+#include <jni.h>
+#endif // __ANDROID__
+
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr.h"
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/// @defgroup Audio Spatial Audio API
+/// @brief This is the GVR Audio C API, a spatial audio rendering engine,
+/// optimized for mobile VR.
+///
+/// It allows the user to spatialize sound sources in 3D space, including
+/// distance and elevation cues. Specifically, the API is capable of playing
+/// back spatial sound in three ways:
+///
+/// - **Sound object rendering**: This allows the user to create a virtual sound
+/// source in 3D space. These sources, while spatialized, are fed with mono
+/// audio data.
+///
+/// - **Ambisonic soundfields**: Ambisonic recordings are multi-channel audio
+/// files which are spatialized all around the listener in 360 degrees. These
+/// can be thought of as recorded or pre-baked soundfields. They can be of
+/// great use for background effects which sound perfectly spatial. Examples
+/// include rain noise, crowd noise or even the sound of the ocean off to one
+/// side.
+///
+/// - **Stereo Sounds**: This allows the user to directly play back
+/// non-spatialized mono or stereo audio files. This is useful for music and
+/// other such audio.
+///
+/// **Initialization**
+///
+/// gvr_audio_context* gvr_audio_create(int32_t rendering_mode);
+///
+/// The rendering_mode argument corresponds to a `gvr_audio_rendering_mode` enum
+/// value, which specifies a rendering configuration setting:
+///
+/// - `GVR_AUDIO_RENDERING_STEREO_PANNING`:
+/// Stereo panning of all sound objects. This disables HRTF-based rendering.
+/// - `GVR_AUDIO_RENDERING_BINAURAL_LOW_QUALITY`:
+/// This renders sound objects over a virtual array of 8 loudspeakers arranged
+/// in a cube configuration around the listener’s head. HRTF-based rendering
+/// is enabled.
+/// - `GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY`:
+/// This renders sound objects over a virtual array of 16 loudspeakers
+/// arranged in an approximate equidistribution about the listener’s
+/// head. HRTF-based rendering is enabled.
+///
+/// For most modern phones, the high quality mode offers a good balance between
+/// performance and audio quality. To optimize the rendering performance for
+/// headphones *and* speaker playback, the stereo speaker mode can be enabled
+/// which automatically switches to stereo panning when no headphone is plugin.
+/// Note that this can lead to varying CPU usage based on headphone and speaker
+/// playback.
+///
+/// **Sound engine control**
+///
+/// Audio playback on the default audio device can be started and stopped by
+/// calling the following two methods:
+///
+/// void gvr_audio_pause(gvr_audio_context* api);
+/// void gvr_audio_resume(gvr_audio_context* api);
+///
+/// Note that:
+///
+/// void gvr_audio_update(gvr_audio_context* api);
+///
+/// must be called from the main thread at a regular rate. It is used to execute
+/// background operations outside of the audio thread.
+///
+/// **Listener position and rotation**
+///
+/// To ensure that the audio in your application reacts to listener head
+/// movement, it is important to update the listener's head orientation in the
+/// graphics callback using the head orientation matrix.
+///
+/// The following methods can be used to control the listener’s head position
+/// and orientation with the audio engine:
+///
+/// void gvr_audio_set_head_position(gvr_audio_context* api, float x,
+/// float y, float z);
+/// or
+///
+/// void gvr_audio_set_head_position_gvr(gvr_audio_context* api,
+/// const gvr_vec3f& position);
+///
+/// and
+///
+/// void gvr_audio_set_head_rotation(gvr_audio_context* api,
+/// float x, float y, float z, float w);
+/// or
+///
+/// void gvr_audio_set_head_rotation_gvr(gvr_audio_context* api,
+/// const gvr_quatf& rotation);
+///
+/// **Preloading Sounds**
+///
+/// Both mono sound files for use with Sound Objects and multi-channel Ambisonic
+/// soundfield files can be preloaded into memory before playback or
+/// alternatively streamed during playback. Preloading can be useful to reduce
+/// CPU usage especially if the same audio clip is likely to be played back many
+/// times. In this case playback latency is also reduced.
+///
+/// Sound files can be preloaded into memory by calling:
+///
+/// bool gvr_audio_preload_soundfile(gvr_audio_context* api,
+/// const char* filename);
+///
+/// Unused sound files can be unloaded with a call to:
+///
+/// void gvr_audio_unload_soundfile(gvr_audio_context* api,
+/// const char* filename);
+///
+/// NOTE: If a sound object, soundfield or stereo sound is created with a file
+/// that has not been preloaded, that audio will be streamed.
+///
+/// **Spatializtion of sound objects**
+///
+/// The GVR Audio System allows the user to create virtual sound objects which
+/// can be placed anywhere in space around the listener.
+///
+/// To create a new sound object, call:
+///
+/// gvr_audio_source_id
+/// gvr_audio_create_sound_object(gvr_audio_context* api,
+/// const char* filename);
+///
+/// This returns a handle that can be used to set properties such as the
+/// position and the volume of the sound object via calls to the following two
+/// functions:
+///
+/// void
+/// gvr_audio_set_sound_object_position(gvr_audio_context* api,
+/// gvr_audio_source_id sound_object_id,
+/// float x, float y, float z);
+///
+/// void
+/// gvr_audio_set_sound_volume(gvr_audio_context* api,
+/// gvr_audio_source_id source_id, float volume);
+///
+/// The behavior of Sound Objects with respect to their distance from the
+/// listener can be controlled via calls to the following method:
+///
+/// void gvr_audio_set_sound_object_distance_rolloff_model(
+/// gvr_audio_context* api, gvr_audio_source_id sound_object_id,
+/// int32_t rolloff_model, float min_distance, float max_distance);
+///
+/// This enables a user to choose between logarithmic and linear distance
+/// rolloff methods, or to completely disable distance rolloff effects.
+///
+///
+/// The spatialized playback of a sound object can be triggered with a call to:
+///
+/// void gvr_audio_play_sound(gvr_audio_context* api,
+/// gvr_audio_source_id source_id,
+/// bool looping_enabled);
+///
+/// and stopped with a call to:
+///
+/// void gvr_audio_stop_sound(gvr_audio_context* api,
+/// gvr_audio_source_id source_id);
+///
+/// Note that the sound object handle destroys itself at the moment the sound
+/// playback has stopped. This way, no clean up of sound object handles is
+/// needed. On subsequent calls to this function the corresponding
+/// gvr_audio_source_id no longer refers to a valid sound object.
+///
+/// The following function can be used to check if a sound object is currently
+/// active:
+///
+/// bool gvr_audio_is_sound_playing(const gvr_audio_context* api,
+/// gvr_audio_source_id source_id);
+///
+/// **Rendering of ambisonic soundfields**
+///
+/// The GVR Audio System also provides the user with the ability to play back
+/// ambisonic soundfields. Ambisonic soundfields are captured or pre-rendered
+/// 360 degree recordings. It is best to think of them as equivalent to 360
+/// degree video. While they envelop and surround the listener, they only react
+/// to the listener's rotational movement. That is, one cannot walk towards
+/// features in the soundfield. Soundfields are ideal for accompanying 360
+/// degree video playback, for introducing background and environmental effects
+/// such as rain or crowd noise, or even for pre baking 3D audio to reduce
+/// rendering costs. The GVR Audio System supports full 3D First Order
+/// Ambisonic recordings using ACN channel ordering and SN3D normalization. For
+/// more information please see our Spatial Audio specification at:
+/// https://github.com/google/spatial-media/blob/master/docs/spatial-audio-rfc.md#semantics
+///
+/// Note that Soundfield playback is directly streamed from the sound file and
+/// no sound file preloading is needed.
+///
+/// To obtain a soundfield handler, call:
+///
+/// gvr_audio_source_id gvr_audio_create_soundfield(gvr_audio_context* api,
+/// const char* filename);
+///
+/// This returns a gvr_audio_source_id handle that allows the user to begin
+/// playback of the soundfield, to alter the soundfield’s volume or to stop
+/// soundfield playback and as such destroy the object. These actions can be
+/// achieved with calls to the following functions:
+///
+/// void gvr_audio_play_sound(gvr_audio_context* api,
+/// gvr_audio_source_id source_id,
+/// bool looping_enabled);
+///
+/// void gvr_audio_set_sound_volume(gvr_audio_context* api,
+/// gvr_audio_source_id source_id,
+/// float volume);
+///
+/// void gvr_audio_stop_sound(gvr_audio_context* api,
+/// gvr_audio_source_id source_id);
+///
+/// Ambisonic soundfields can also be rotated about the listener's head in order
+/// to align the components of the soundfield with the visuals of the game/app.
+///
+/// void gvr_audio_set_soundfield_rotation(gvr_audio_context* api,
+/// gvr_audio_source_id soundfield_id,
+/// const gvr_quatf&
+/// soundfield_rotation);
+///
+/// **Direct Playback of Stereo or Mono Sounds**
+///
+/// The GVR Audio System allows the direct non-spatialized playback of both
+/// stereo and mono audio. Such audio is often used for music or sound effects
+/// that should not be spatialized.
+///
+/// A stereo sound can be created with a call to:
+///
+/// gvr_audio_source_id gvr_audio_create_stereo_sound(gvr_audio_context* api,
+/// const char* filename);
+///
+/// **Paused Sounds and Stopped Sounds**
+///
+/// When using sound sources of any of the above types, the user can ensure that
+/// the given source is currently playing before calling.
+///
+/// bool gvr_audio_is_sound_playing(gvr_audio_source_id source_id);
+///
+/// This method will return false if the source has been either paused or
+/// stopped, and true if the source is currently playing.
+///
+/// Once one is finished with a Sound Object and wish to remove it, a call can
+/// be placed to:
+///
+/// void gvr_audio_stop_sound(gvr_audio_source_id source_id);
+///
+/// Once a source has been stopped it is destroyed and the corresponding
+/// gvr_audio_source_id will be invalid. Sources which have been played with the
+/// |looping_enabled| parameter disabled will also be destroyed once playback
+/// of the full audio clip has completed.
+///
+/// To check whether a given gvr_audio_source_id corresponds to a valid source
+/// which exists and is in a playable state, a call can be made to:
+///
+/// bool gvr_audio_is_source_id_valid(gvr_audio_source_id source_id);
+///
+/// By using this pair of methods a user can differentiate between sources which
+/// have been paused and those which have ceased.
+///
+/// **Room effects**
+///
+/// The GVR Audio System provides a powerful reverb engine which can be used to
+/// create customized room effects by specifying the size of a room and a
+/// material for each surface of the room from the gvr_audio_material_name enum.
+/// Each of these surface materials has unique absorption properties which
+/// differ with frequency. The room created will be centered around the
+/// listener. Note that the Google VR Audio System uses meters as the unit of
+/// distance throughout.
+///
+/// The following methods are used to control room effects:
+///
+/// void gvr_audio_enable_room(gvr_audio_context* api, bool enable);
+///
+/// enables or disables room effects with smooth transitions.
+///
+/// and
+///
+/// void
+/// gvr_audio_set_room_properties(gvr_audio_context* api, float size_x,
+/// float size_y, float size_z,
+/// gvr_audio_material_name wall_material,
+/// gvr_audio_material_name ceiling_material,
+/// gvr_audio_material_name floor_material);
+///
+/// allows the user to describe the room based on its dimensions and its surface
+/// properties. For example, one can expect very large rooms to be more
+/// reverberant than smaller rooms, and a room with with hard surface materials
+/// such as brick to be more reverberant than one with soft absorbent materials
+/// such as heavy curtains on every surface.
+///
+/// Note that when a sound source is located outside of the listener's room,
+/// it will sound different from sources located within the room due to
+/// attenuation of both the direct sound and the reverb on that source. Sources
+/// located far outside of the listener's room will not be audible to the
+/// listener.
+///
+/// The following method can be used to subtly adjust the reverb in a room by
+/// changing the gain/attenuation on the reverb, setting a multiplier on the
+/// reverberation time to control the reverb's length, or adjusting the balance
+/// between the low and high frequency components of the reverb.
+///
+/// void gvr_audio_set_room_reverb_adjustments(gvr_audio_context* api,
+/// float gain,
+/// float time_adjust,
+/// float brightness_adjust);
+///
+/// If you are writing C++ code, you might prefer to use the C++ wrapper
+/// rather than implement this C API directly.
+///
+/// **Example usage (C++ API)**
+///
+/// Construction:
+///
+/// std::unique_ptr<gvr::AudioApi> gvr_audio_api(new gvr::AudioApi);
+/// gvr_audio_api->Init(GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY);
+///
+/// Update head rotation in DrawFrame():
+///
+/// head_pose_ = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time);
+/// gvr_audio_api_->SetHeadPose(head_pose_);
+/// gvr_audio_api_->Update();
+///
+/// Preload sound file, create sound handle and start playback:
+///
+/// gvr_audio_api->PreloadSoundfile(kSoundFile);
+/// AudioSourceId source_id =
+/// gvr_audio_api_->CreateSoundObject("sound.wav");
+/// gvr_audio_api->SetSoundObjectPosition(source_id,
+/// position_x,
+/// position_y,
+/// position_z);
+/// gvr_audio_api->PlaySound(source_id, true /* looped playback */);
+///
+
+/// @{
+
+typedef struct gvr_audio_context_ gvr_audio_context;
+
+/// Creates and initializes a gvr_audio_context. This call also initializes
+/// the audio interface and starts the audio engine. Note that the returned
+/// instance must be deleted with gvr_audio_destroy.
+///
+#ifdef __ANDROID__
+/// @param env The JNI Env associated with the current thread.
+/// @param android_context The Android application context. This must be the
+/// application context, NOT an Activity context (Note: from any Android
+/// Activity in your app, you can call getApplicationContext() to
+/// retrieve the application context).
+/// @param class_loader The class loader to use when loading Java
+/// classes. This must be your app's main class loader (usually
+/// accessible through activity.getClassLoader() on any of your Activities).
+/// @param rendering_mode The gvr_audio_rendering_mode value which determines
+/// the rendering configuration preset. This is passed as an int32_t to
+/// ensure API compatibility.
+/// @return gvr_audio_context instance.
+gvr_audio_context* gvr_audio_create(JNIEnv* env, jobject android_context,
+ jobject class_loader,
+ int32_t rendering_mode);
+#else
+/// @param rendering_mode The gvr_audio_rendering_mode value which determines
+/// the rendering configuration preset. This is passed as an int32_t to
+/// ensure API compatibility.
+/// @return gvr_audio_context instance.
+gvr_audio_context* gvr_audio_create(int32_t rendering_mode);
+#endif // #ifdef __ANDROID__
+
+/// Destroys a gvr_audio_context that was previously created with
+/// gvr_audio_create or gvr_audio_create_android.
+///
+/// @param api Pointer to a pointer to a gvr_audio_context. The pointer
+/// will be set to NULL after destruction.
+void gvr_audio_destroy(gvr_audio_context** api);
+
+/// Resumes the VR Audio system.
+/// Call this when your app/game loses focus.
+/// Calling this when not paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_resume(gvr_audio_context* api);
+
+/// Pauses the VR Audio system.
+/// Calling this when already paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_pause(gvr_audio_context* api);
+
+/// This method must be called from the main thread at a regular rate. It is
+/// used to execute background operations outside of the audio thread.
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_update(gvr_audio_context* api);
+
+/// Preloads a local sound file. Note that the local file access method
+/// depends on the target platform.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename Name of the file, used as identifier.
+/// @return True on success or if file has already been preloaded.
+bool gvr_audio_preload_soundfile(gvr_audio_context* api, const char* filename);
+
+/// Unloads a previously preloaded sample from memory. Note that if the sample
+/// is currently used, the memory is freed at the moment playback stops.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename Name of the file, used as identifier.
+void gvr_audio_unload_soundfile(gvr_audio_context* api, const char* filename);
+
+/// Returns a new sound object. Note that the sample should only contain a
+/// single audio channel (stereo sources are automatically downmixed to mono).
+/// The handle automatically destroys itself at the moment the sound playback
+/// has stopped.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played.
+/// @return Id of new sound object. Returns kInvalidId if the sound file has not
+/// been preloaded or if the number of input channels is > 1.
+gvr_audio_source_id gvr_audio_create_sound_object(gvr_audio_context* api,
+ const char* filename);
+
+/// Returns a new ambisonic sound field. Note that the sample needs to be
+/// preloaded and must have 4 separate audio channels. The handle automatically
+/// destroys itself at the moment the sound playback has stopped.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played.
+/// @return Id of new soundfield. Returns kInvalidId if the sound file has not
+/// been preloaded or if the number of input channels does not match that
+/// required.
+gvr_audio_source_id gvr_audio_create_soundfield(gvr_audio_context* api,
+ const char* filename);
+
+/// Returns a new stereo non-spatialized source, which directly plays back mono
+/// or stereo audio. Note the sample needs to be preloaded and may contain only
+/// one (mono) or two (stereo) audio channels.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played..
+/// @return Id of new stereo non-spatialized source. Returns kInvalidId if the
+/// sound file has not been preloaded or if the number of input channels is
+/// > 2;
+gvr_audio_source_id gvr_audio_create_stereo_sound(gvr_audio_context* api,
+ const char* filename);
+
+/// Starts the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be stopped.
+/// @param looping_enabled Enables looped audio playback.
+void gvr_audio_play_sound(gvr_audio_context* api, gvr_audio_source_id source_id,
+ bool looping_enabled);
+
+/// Pauses the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be paused.
+void gvr_audio_pause_sound(gvr_audio_context* api,
+ gvr_audio_source_id source_id);
+
+/// Resumes the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be resumed.
+void gvr_audio_resume_sound(gvr_audio_context* api,
+ gvr_audio_source_id source_id);
+
+/// Stops the playback of a sound and destroys the corresponding sound object
+/// or Soundfield.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be stopped.
+void gvr_audio_stop_sound(gvr_audio_context* api,
+ gvr_audio_source_id source_id);
+
+/// Checks if a sound is playing.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be checked.
+/// @return True if the sound is being played.
+bool gvr_audio_is_sound_playing(const gvr_audio_context* api,
+ gvr_audio_source_id source_id);
+
+/// Checks if a |source_id| is valid, and that the corresponding source is in a
+/// playable state. Sources that have been stopped will be reported as invalid.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be checked.
+/// @return True if the source exists and is in a playable state.
+bool gvr_audio_is_source_id_valid(const gvr_audio_context* api,
+ gvr_audio_source_id source_id);
+
+/// Repositions an existing sound object.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param sound_object_id Id of the sound object to be moved.
+/// @param x X coordinate the sound will be placed at.
+/// @param y Y coordinate the sound will be placed at.
+/// @param z Z coordinate the sound will be placed at.
+void gvr_audio_set_sound_object_position(gvr_audio_context* api,
+ gvr_audio_source_id sound_object_id,
+ float x, float y, float z);
+
+/// Sets the given ambisonic soundfields's rotation.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param soundfield_id Id of the soundfield source to be rotated.
+/// @param soundfield_rotation Quaternion representing the soundfield rotation.
+void gvr_audio_set_soundfield_rotation(gvr_audio_context* api,
+ gvr_audio_source_id soundfield_id,
+ const gvr_quatf& soundfield_rotation);
+
+/// Sets the given sound object source's distance attenuation method with
+/// minimum and maximum distances. Maximum distance must be greater than the
+/// minimum distance for the method to be set.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param sound_object_id Id of sound object source.
+/// @param rolloff_model Linear or logarithmic distance rolloff models. Note
+/// setting the rolloff model to |GVR_AUDIO_ROLLOFF_NONE| will allow
+/// distance attenuation values to be set manually.
+/// @param min_distance Minimum distance to apply distance attenuation method.
+/// @param max_distance Maximum distance to apply distance attenuation method.
+void gvr_audio_set_sound_object_distance_rolloff_model(
+ gvr_audio_context* api, gvr_audio_source_id sound_object_id,
+ int32_t rolloff_model, float min_distance, float max_distance);
+
+
+/// Changes the master volume.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param volume Volume value. Should range from 0 (mute) to 1 (max).
+void gvr_audio_set_master_volume(gvr_audio_context* api, float volume);
+
+/// Changes the volume of an existing sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be modified.
+/// @param volume Volume value. Should range from 0 (mute) to 1 (max).
+void gvr_audio_set_sound_volume(gvr_audio_context* api,
+ gvr_audio_source_id source_id, float volume);
+
+/// Sets the head pose from a matrix representation of the same.
+///
+/// @param api Pointer to a gvr_audio_context on which to set the pose.
+/// @param head_pose_matrix Matrix representing the head transform to be set.
+void gvr_audio_set_head_pose(gvr_audio_context* api,
+ const gvr_mat4f& head_pose_matrix);
+
+/// Turns on/off the room reverberation effect.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param enable True to enable room effect.
+void gvr_audio_enable_room(gvr_audio_context* api, bool enable);
+
+/// Sets the room properties describing the dimensions and surface materials of
+/// a given room.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param size_x Dimension along X axis.
+/// @param size_y Dimension along Y axis.
+/// @param size_z Dimension along Z axis.
+/// @param wall_material Surface gvr_audio_material_type for the four walls.
+/// @param ceiling_material Surface gvr_audio_material_type for the ceiling.
+/// @param floor_material Surface gvr_audio_material_type for the floor.
+void gvr_audio_set_room_properties(gvr_audio_context* api, float size_x,
+ float size_y, float size_z,
+ int32_t wall_material,
+ int32_t ceiling_material,
+ int32_t floor_material);
+
+/// Adjusts the properties of the current reverb, allowing changes to the
+/// reverb's gain, duration and low/high frequency balance.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param gain Reverb volume (linear) adjustment in range [0, 1] for
+/// attenuation, range [1, inf) for gain boost.
+/// @param time_adjust Reverb time adjustment multiplier to scale the
+/// reverberation tail length. This value should be >= 0.
+/// @param brightness_adjust Reverb brightness adjustment that controls the
+/// reverberation ratio across low and high frequency bands.
+void gvr_audio_set_room_reverb_adjustments(gvr_audio_context* api, float gain,
+ float time_adjust,
+ float brightness_adjust);
+
+/// Enables the stereo speaker mode. It enforces stereo-panning when headphones
+/// are *not* plugged into the phone. This helps to avoid HRTF-based coloring
+/// effects and reduces computational complexity when speaker playback is
+/// active. By default the stereo speaker mode optimization is disabled.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param enable True to enable the stereo speaker mode.
+void gvr_audio_enable_stereo_speaker_mode(gvr_audio_context* api, bool enable);
+
+/// @}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// Convenience C++ wrapper.
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#include <memory>
+#include <string>
+
+namespace gvr {
+/// This is a convenience C++ wrapper for the Audio C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+///
+/// THREADING: this class is thread-safe and reentrant after initialized
+/// with Init().
+class AudioApi {
+ public:
+ /// Creates an (uninitialized) ControllerApi object. You must initialize
+ /// it by calling Init() before interacting with it.
+ AudioApi() : context_(nullptr) {}
+
+ ~AudioApi() {
+ if (context_) {
+ gvr_audio_destroy(&context_);
+ }
+ }
+
+/// Creates and initializes a gvr_audio_context.
+/// For more information, see gvr_audio_create().
+#ifdef __ANDROID__
+ bool Init(JNIEnv* env, jobject android_context, jobject class_loader,
+ AudioRenderingMode rendering_mode) {
+ context_ =
+ gvr_audio_create(env, android_context, class_loader, rendering_mode);
+ return context_ != nullptr;
+ }
+#else
+ bool Init(AudioRenderingMode rendering_mode) {
+ context_ = gvr_audio_create(rendering_mode);
+ return context_ != nullptr;
+ }
+#endif // #ifdef __ANDROID__
+
+ /// Pauses the audio engine.
+ /// For more information, see gvr_audio_pause().
+ void Pause() { gvr_audio_pause(context_); }
+
+ /// Resumes the audio engine.
+ /// For more information, see gvr_audio_resume().
+ void Resume() { gvr_audio_resume(context_); }
+
+ /// For more information, see gvr_audio_update().
+ void Update() { gvr_audio_update(context_); }
+
+ /// Preloads a local sound file.
+ /// For more information, see gvr_audio_preload_soundfile().
+ bool PreloadSoundfile(const std::string& filename) {
+ return gvr_audio_preload_soundfile(context_, filename.c_str());
+ }
+
+ /// Unloads a previously preloaded sample from memory.
+ /// For more information, see gvr_audio_preload_soundfile().
+ void UnloadSoundfile(const std::string& filename) {
+ gvr_audio_unload_soundfile(context_, filename.c_str());
+ }
+
+ /// Returns a new sound object.
+ /// For more information, see gvr_audio_create_sound_object().
+ AudioSourceId CreateSoundObject(const std::string& filename) {
+ return gvr_audio_create_sound_object(context_, filename.c_str());
+ }
+
+ /// Returns a new sound field.
+ /// For more information, see gvr_audio_create_soundfield().
+ AudioSourceId CreateSoundfield(const std::string& filename) {
+ return gvr_audio_create_soundfield(context_, filename.c_str());
+ }
+
+ /// Returns a new stereo soound.
+ /// For more information, see gvr_audio_create_stereo_sound().
+ AudioSourceId CreateStereoSound(const std::string& filename) {
+ return gvr_audio_create_stereo_sound(context_, filename.c_str());
+ }
+
+ /// Starts the playback of a sound.
+ /// For more information, see gvr_audio_play_sound().
+ void PlaySound(AudioSourceId source_id, bool looping_enabled) {
+ gvr_audio_play_sound(context_, source_id, looping_enabled);
+ }
+
+ /// Pauses the playback of a sound.
+ /// For more information, see gvr_audio_pause_sound().
+ void PauseSound(AudioSourceId source_id) {
+ gvr_audio_pause_sound(context_, source_id);
+ }
+
+ /// Resumes the playback of a sound.
+ /// For more information, see gvr_audio_resume_sound().
+ void ResumeSound(AudioSourceId source_id) {
+ gvr_audio_resume_sound(context_, source_id);
+ }
+
+ /// Stops the playback of a sound.
+ /// For more information, see gvr_audio_stop_sound().
+ void StopSound(AudioSourceId source_id) {
+ gvr_audio_stop_sound(context_, source_id);
+ }
+
+ /// Checks if a sound is playing.
+ /// For more information, see gvr_audio_is_sound_playing().
+ bool IsSoundPlaying(AudioSourceId source_id) const {
+ return gvr_audio_is_sound_playing(context_, source_id);
+ }
+
+ /// Checks if a source is in a valid playable state.
+ /// For more information, see gvr_audio_is_source_id_valid().
+ bool IsSourceIdValid(AudioSourceId source_id) {
+ return gvr_audio_is_source_id_valid(context_, source_id);
+ }
+
+ /// Repositions an existing sound object.
+ /// For more information, see gvr_audio_set_sound_object_position().
+ void SetSoundObjectPosition(AudioSourceId sound_object_id, float x, float y,
+ float z) {
+ gvr_audio_set_sound_object_position(context_, sound_object_id, x, y, z);
+ }
+
+ void SetSoundObjectDistanceRolloffModel(
+ AudioSourceId sound_object_id,
+ gvr_audio_distance_rolloff_type rolloff_model, float min_distance,
+ float max_distance) {
+ gvr_audio_set_sound_object_distance_rolloff_model(
+ context_, sound_object_id, rolloff_model, min_distance, max_distance);
+ }
+
+ /// Rotates an existing soundfield.
+ /// For more information, see gvr_audio_set_soundfield_rotation().
+ void SetSoundfieldRotation(AudioSourceId soundfield_id,
+ const Quatf& soundfield_rotation) {
+ gvr_audio_set_soundfield_rotation(context_, soundfield_id,
+ soundfield_rotation);
+ }
+
+ /// Changes the master volume.
+ /// For more information, see gvr_audio_set_master_volume().
+ void SetMasterVolume(float volume) {
+ gvr_audio_set_master_volume(context_, volume);
+ }
+
+ /// Changes the volume of an existing sound.
+ /// For more information, see gvr_audio_set_sound_volume().
+ void SetSoundVolume(AudioSourceId source_id, float volume) {
+ gvr_audio_set_sound_volume(context_, source_id, volume);
+ }
+
+ /// Sets the head position from a matrix representation.
+ /// For more information, see gvr_audio_set_head_pose().
+ void SetHeadPose(const Mat4f& head_pose_matrix) {
+ gvr_audio_set_head_pose(context_, head_pose_matrix);
+ }
+
+ /// Turns on/off the room reverberation effect.
+ /// For more information, see gvr_audio_enable_room().
+ void EnableRoom(bool enable) { gvr_audio_enable_room(context_, enable); }
+
+ /// Sets the room properties describing the dimensions and surface materials
+ /// of a given room. For more information, see
+ /// gvr_audio_set_room_properties().
+ void SetRoomProperties(float size_x, float size_y, float size_z,
+ gvr_audio_material_type wall_material,
+ gvr_audio_material_type ceiling_material,
+ gvr_audio_material_type floor_material) {
+ gvr_audio_set_room_properties(context_, size_x, size_y, size_z,
+ wall_material, ceiling_material,
+ floor_material);
+ }
+
+ /// Adjusts the properties of the current reverb, allowing changes to the
+ /// reverb's gain, duration and low/high frequency balance. For more
+ /// information see gvr_audio_set_room_reverb_adjustments().
+ void SetRoomReverbAdjustments(float gain, float time_adjust,
+ float brightness_adjust) {
+ gvr_audio_set_room_reverb_adjustments(context_, gain, time_adjust,
+ brightness_adjust);
+ }
+
+ /// Enables the stereo speaker mode. For more information see
+ /// gvr_audio_enable_stereo_speaker_mode().
+ void EnableStereoSpeakerMode(bool enable) {
+ gvr_audio_enable_stereo_speaker_mode(context_, enable);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit AudioApi(gvr_audio_context* context)
+ : context_(context) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_audio_context* cobj() { return context_; }
+ const gvr_audio_context* cobj() const { return context_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_audio_context* Release() {
+ auto result = context_;
+ context_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ gvr_audio_context* context_;
+
+ // Disallow copy and assign:
+ AudioApi(const AudioApi&);
+ void operator=(const AudioApi&);
+};
+
+} // namespace gvr
+#endif // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h
new file mode 100644
index 0000000..a67502f
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h
@@ -0,0 +1,752 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
+
+#ifdef __ANDROID__
+#include <jni.h>
+#endif
+
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr.h"
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup Controller Controller API
+/// @brief This is the Controller C API, which allows access to a VR controller.
+///
+/// If you are writing C++ code, you might prefer to use the C++ wrapper rather
+/// than implement this C API directly.
+///
+/// Typical initialization example:
+///
+/// // Get your gvr_context* pointer from GvrLayout:
+/// gvr_context* gvr = ......; // (get from GvrLayout in Java)
+///
+/// // Set up the API features:
+/// int32_t options = gvr_controller_get_default_options();
+///
+/// // Enable non-default options, if needed:
+/// options |= GVR_CONTROLLER_ENABLE_GYRO | GVR_CONTROLLER_ENABLE_ACCEL;
+///
+/// // Create and init:
+/// gvr_controller_context* context =
+/// gvr_controller_create_and_init(options, gvr);
+///
+/// // Check if init was successful.
+/// if (!context) {
+/// // Handle error.
+/// return;
+/// }
+///
+/// gvr_controller_state* state = gvr_controller_state_create();
+///
+/// // Resume:
+/// gvr_controller_resume(api);
+///
+/// Usage:
+///
+/// void DrawFrame() {
+/// gvr_controller_state_update(context, 0, state);
+/// // ... process controller state ...
+/// }
+///
+/// // When your application gets paused:
+/// void OnPause() {
+/// gvr_controller_pause(context);
+/// }
+///
+/// // When your application gets resumed:
+/// void OnResume() {
+/// gvr_controller_resume(context);
+/// }
+///
+/// To conserve battery, be sure to call gvr_controller_pause and
+/// gvr_controller_resume when your app gets paused and resumed, respectively.
+///
+/// THREADING: unless otherwise noted, all functions are thread-safe, so
+/// you can operate on the same gvr_controller_context object from multiple
+/// threads.
+/// @{
+
+/// Represents a Daydream Controller API object, used to invoke the
+/// Daydream Controller API.
+typedef struct gvr_controller_context_ gvr_controller_context;
+
+/// Returns the default features for the controller API.
+///
+/// @return The set of default features, as bit flags (an OR'ed combination of
+/// the GVR_CONTROLLER_ENABLE_* feature flags).
+int32_t gvr_controller_get_default_options();
+
+/// Creates and initializes a gvr_controller_context instance which can be used
+/// to invoke the Daydream Controller API functions. Important: after creation
+/// the API will be in the paused state (the controller will be inactive).
+/// You must call gvr_controller_resume() explicitly (typically, in your Android
+/// app's onResume() callback).
+///
+/// @param options The API options. To get the defaults, use
+/// gvr_controller_get_default_options().
+/// @param context The GVR Context object to sync with (optional).
+/// This can be nullptr. If provided, the context's state will
+/// be synchronized with the controller's state where possible. For
+/// example, when the user recenters the controller, this will
+/// automatically recenter head tracking as well.
+/// WARNING: the caller is responsible for making sure the pointer
+/// remains valid for the lifetime of this object.
+/// @return A pointer to the initialized API, or NULL if an error occurs.
+gvr_controller_context* gvr_controller_create_and_init(
+ int32_t options, gvr_context* context);
+
+#ifdef __ANDROID__
+/// Creates and initializes a gvr_controller_context instance with an explicit
+/// Android context and class loader.
+///
+/// @param env The JNI Env associated with the current thread.
+/// @param android_context The Android application context. This must be the
+/// application context, NOT an Activity context (Note: from any Android
+/// Activity in your app, you can call getApplicationContext() to
+/// retrieve the application context).
+/// @param class_loader The class loader to use when loading Java
+/// classes. This must be your app's main class loader (usually
+/// accessible through activity.getClassLoader() on any of your Activities).
+/// @param options The API options. To get the defaults, use
+/// gvr_controller_get_default_options().
+/// @param context The GVR Context object to sync with (optional).
+/// This can be nullptr. If provided, the context's state will
+/// be synchronized with the controller's state where possible. For
+/// example, when the user recenters the controller, this will
+/// automatically recenter head tracking as well.
+/// WARNING: the caller is responsible for making sure the pointer
+/// remains valid for the lifetime of this object.
+/// @return A pointer to the initialized API, or NULL if an error occurs.
+gvr_controller_context* gvr_controller_create_and_init_android(
+ JNIEnv *env, jobject android_context, jobject class_loader,
+ int32_t options, gvr_context* context);
+#endif // #ifdef __ANDROID__
+
+/// Destroys a gvr_controller_context that was previously created with
+/// gvr_controller_init.
+///
+/// @param api Pointer to a pointer to a gvr_controller_context. The pointer
+/// will be set to NULL after destruction.
+void gvr_controller_destroy(gvr_controller_context** api);
+
+/// Pauses the controller, possibly releasing resources.
+/// Call this when your app/game loses focus.
+/// Calling this when already paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+void gvr_controller_pause(gvr_controller_context* api);
+
+/// Resumes the controller. Call this when your app/game regains focus.
+/// Calling this when already resumed is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+void gvr_controller_resume(gvr_controller_context* api);
+
+/// Convenience to convert an API status code to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param status The gvr_controller_api_status to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_api_status_to_string(int32_t status);
+
+/// Convenience to convert an connection state to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param state The state to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_connection_state_to_string(int32_t state);
+
+/// Convenience to convert an connection state to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param button The gvr_controller_button to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_button_to_string(int32_t button);
+
+/// Creates a gvr_controller_state.
+gvr_controller_state* gvr_controller_state_create();
+
+/// Destroys a a gvr_controller_state that was previously created with
+/// gvr_controller_state_create.
+void gvr_controller_state_destroy(gvr_controller_state** state);
+
+/// Updates the controller state. Reading the controller state is not a
+/// const getter: it has side-effects. In particular, some of the
+/// gvr_controller_state fields (the ones documented as "transient") represent
+/// one-time events and will be true for only one read operation, and false
+/// in subsequente reads.
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+/// @param flags Optional flags reserved for future use. A value of 0 should be
+/// used until corresponding flag attributes are defined and documented.
+/// @param out_state A pointer where the controller's state
+/// is to be written. This must have been allocated with
+/// gvr_controller_state_create().
+void gvr_controller_state_update(gvr_controller_context* api, int32_t flags,
+ gvr_controller_state* out_state);
+
+/// Gets the API status of the controller state. Returns one of the
+/// gvr_controller_api_status variants, but returned as an int32_t for ABI
+/// compatibility.
+int32_t gvr_controller_state_get_api_status(const gvr_controller_state* state);
+
+/// Gets the connection state of the controller. Returns one of the
+/// gvr_controller_connection_state variants, but returned as an int32_t for ABI
+/// compatibility.
+int32_t gvr_controller_state_get_connection_state(
+ const gvr_controller_state* state);
+
+/// Returns the current controller orientation, in Start Space. The Start Space
+/// is the same space as the headset space and has these three axes
+/// (right-handed):
+///
+/// * The positive X axis points to the right.
+/// * The positive Y axis points upwards.
+/// * The positive Z axis points backwards.
+///
+/// The definition of "backwards" and "to the right" are based on the position
+/// of the controller when tracking started. For Daydream, this is when the
+/// controller was first connected in the "Connect your Controller" screen
+/// which is shown when the user enters VR.
+///
+/// The definition of "upwards" is given by gravity (away from the pull of
+/// gravity). This API may not work in environments without gravity, such
+/// as space stations or near the center of the Earth.
+///
+/// Since the coordinate system is right-handed, rotations are given by the
+/// right-hand rule. For example, rotating the controller counter-clockwise
+/// on a table top as seen from above means a positive rotation about the
+/// Y axis, while clockwise would mean negative.
+///
+/// Note that this is the Start Space for the *controller*, which initially
+/// coincides with the Start Space for the headset, but they may diverge over
+/// time due to controller/headset drift. A recentering operation will bring
+/// the two spaces back into sync.
+///
+/// Remember that a quaternion expresses a rotation. Given a rotation of theta
+/// radians about the (x, y, z) axis, the corresponding quaternion (in
+/// xyzw order) is:
+///
+/// (x * sin(theta/2), y * sin(theta/2), z * sin(theta/2), cos(theta/2))
+///
+/// Here are some examples of orientations of the controller and their
+/// corresponding quaternions, all given in xyzw order:
+///
+/// * Initial pose, pointing forward and lying flat on a surface: identity
+/// quaternion (0, 0, 0, 1). Corresponds to "no rotation".
+///
+/// * Flat on table, rotated 90 degrees counter-clockwise: (0, 0.7071, 0,
+/// 0.7071). Corresponds to a +90 degree rotation about the Y axis.
+///
+/// * Flat on table, rotated 90 degrees clockwise: (0, -0.7071, 0, 0.7071).
+/// Corresponds to a -90 degree rotation about the Y axis.
+///
+/// * Flat on table, rotated 180 degrees (pointing backwards): (0, 1, 0, 0).
+/// Corresponds to a 180 degree rotation about the Y axis.
+///
+/// * Pointing straight up towards the sky: (0.7071, 0, 0, 0.7071).
+/// Corresponds to a +90 degree rotation about the X axis.
+///
+/// * Pointing straight down towards the ground: (-0.7071, 0, 0, 0.7071).
+/// Corresponds to a -90 degree rotation about the X axis.
+///
+/// * Banked 90 degrees to the left: (0, 0, 0.7071, 0.7071). Corresponds
+/// to a +90 degree rotation about the Z axis.
+///
+/// * Banked 90 degrees to the right: (0, 0, -0.7071, 0.7071). Corresponds
+/// to a -90 degree rotation about the Z axis.
+gvr_quatf gvr_controller_state_get_orientation(
+ const gvr_controller_state* state);
+
+/// Returns the current controller gyro reading, in Start Space.
+///
+/// The gyro measures the controller's angular speed in radians per second.
+/// Note that this is an angular *speed*, so it reflects how fast the
+/// controller's orientation is changing with time.
+/// In particular, if the controller is not being rotated, the angular speed
+/// will be zero on all axes, regardless of the current pose.
+///
+/// The axes are in the controller's device space. Specifically:
+///
+/// * The X axis points to the right of the controller.
+/// * The Y axis points upwards perpendicular to the top surface of the
+/// controller.
+/// * The Z axis points backwards along the body of the controller,
+/// towards its rear, where the charging port is.
+///
+/// As usual in a right-handed coordinate system, the sign of the angular
+/// velocity is given by the right-hand rule. So, for example:
+///
+/// * If the controller is flat on a table top spinning counter-clockwise
+/// as seen from above, you will read a positive angular velocity
+/// about the Y axis. Clockwise would be negative.
+/// * If the controller is initially pointing forward and lying flat and
+/// is then gradually angled up so that its tip points towards the sky,
+/// it will report a positive angular velocity about the X axis during
+/// that motion. Likewise, angling it down will report a negative angular
+/// velocity about the X axis.
+/// * If the controller is banked (rolled) to the right, this will
+/// report a negative angular velocity about the Z axis during the
+/// motion (remember the Z axis points backwards along the controller).
+/// Banking to the left will report a positive angular velocity about
+/// the Z axis.
+gvr_vec3f gvr_controller_state_get_gyro(const gvr_controller_state* state);
+
+/// Current (latest) controller accelerometer reading, in Start Space.
+///
+/// The accelerometer indicates the direction in which the controller feels
+/// an acceleration, including gravity. The reading is given in meters
+/// per second squared (m/s^2). The axes are the same as for the gyro.
+/// To have an intuition for the signs used in the accelerometer, it is useful
+/// to imagine that, when at rest, the controller is being "pushed" by a
+/// force opposite to gravity. It is as if, by the equivalency princle, it were
+/// on a frame of reference that is accelerating in the opposite direction to
+/// gravity. For example:
+///
+/// * If the controller is lying flat on a table top, it will read a positive
+/// acceleration of about 9.8 m/s^2 along the Y axis, corresponding to
+/// the acceleration of gravity (as if the table were pushing the controller
+/// upwards at 9.8 m/s^2 to counteract gravity).
+/// * If, in that situation, the controller is now accelerated upwards at
+/// 3.0 m/s^2, then the reading will be 12.8 m/s^2 along the Y axis,
+/// since the controller will now feel a stronger acceleration corresponding
+/// to the 9.8 m/s^2 plus the upwards push of 3.0 m/s^2.
+/// * If, the controller is accelerated downwards at 5.0 m/s^2, then the
+/// reading will now be 4.8 m/s^2 along the Y axis, since the controller
+/// will now feel a weaker acceleration (as the acceleration is giving in
+/// to gravity).
+/// * If you were to give in to gravity completely, letting the controller
+/// free fall towards the ground, it will read 0 on all axes, as there
+/// will be no force acting on the controller. (Please do not put your
+/// controller in a free-fall situation. This is just a theoretical
+/// example.)
+gvr_vec3f gvr_controller_state_get_accel(const gvr_controller_state* state);
+
+/// Returns whether the user is touching the touchpad.
+bool gvr_controller_state_is_touching(const gvr_controller_state* state);
+
+/// If the user is touching the touchpad, this returns the touch position in
+/// normalized coordinates, where (0,0) is the top-left of the touchpad
+/// and (1,1) is the bottom right. If the user is not touching the touchpad,
+/// then this is the position of the last touch.
+gvr_vec2f gvr_controller_state_get_touch_pos(const gvr_controller_state* state);
+
+/// Returns true if user just started touching touchpad (this is a transient
+/// event:
+/// it is true for only one frame after the event).
+bool gvr_controller_state_get_touch_down(const gvr_controller_state* state);
+
+/// Returns true if user just stopped touching touchpad (this is a transient
+/// event:
+/// it is true for only one frame after the event).
+bool gvr_controller_state_get_touch_up(const gvr_controller_state* state);
+
+/// Returns true if a recenter operation just ended (this is a transient event:
+/// it is true only for one frame after the recenter ended). If this is
+/// true then the `orientation` field is already relative to the new center.
+bool gvr_controller_state_get_recentered(const gvr_controller_state* state);
+
+/// Returns whether the recenter flow is currently in progress.
+///
+/// @deprecated Use gvr_controller_state_get_recentered instead.
+bool gvr_controller_state_get_recentering(const gvr_controller_state* state);
+
+/// Returns whether the given button is currently pressed.
+bool gvr_controller_state_get_button_state(const gvr_controller_state* state,
+
+ int32_t button);
+
+/// Returns whether the given button was just pressed (transient).
+bool gvr_controller_state_get_button_down(const gvr_controller_state* state,
+ int32_t button);
+
+/// Returns whether the given button was just released (transient).
+bool gvr_controller_state_get_button_up(const gvr_controller_state* state,
+ int32_t button);
+
+/// Returns the timestamp (nanos) when the last orientation event was received.
+int64_t gvr_controller_state_get_last_orientation_timestamp(
+ const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last gyro event was received.
+int64_t gvr_controller_state_get_last_gyro_timestamp(
+ const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last accelerometer event was
+/// received.
+int64_t gvr_controller_state_get_last_accel_timestamp(
+ const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last touch event was received.
+int64_t gvr_controller_state_get_last_touch_timestamp(
+ const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last button event was received.
+int64_t gvr_controller_state_get_last_button_timestamp(
+ const gvr_controller_state* state);
+
+// Current (latest) controller simulated position for use with an elbow model.
+gvr_vec3f gvr_controller_state_get_position(const gvr_controller_state* state);
+
+// Returns the timestamp (nanos) when the last position event was received.
+int64_t gvr_controller_state_get_last_position_timestamp(
+ const gvr_controller_state* state);
+
+/// @}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+// Convenience C++ wrapper.
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#include <memory>
+
+namespace gvr {
+/// This is a convenience C++ wrapper for the Controller C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+/// Typical C++ initialization example:
+///
+/// std::unique_ptr<ControllerApi> controller_api(new ControllerApi);
+///
+/// // Your GVR context pointer (which can be obtained from GvrLayout)
+/// gvr_context* context = .....; // (get it from GvrLayout)
+///
+/// // Set up the options:
+/// int32_t options = ControllerApi::DefaultOptions();
+///
+/// // Enable non-default options, if you need them:
+/// options |= GVR_CONTROLLER_ENABLE_GYRO;
+///
+/// // Init the ControllerApi object:
+/// bool success = controller_api->Init(options, context);
+/// if (!success) {
+/// // Handle failure.
+/// // Do NOT call other methods (like Resume, etc) if init failed.
+/// return;
+/// }
+///
+/// // Resume the ControllerApi (if your app is on the foreground).
+/// controller_api->Resume();
+///
+/// ControllerState state;
+///
+/// Usage example:
+///
+/// void DrawFrame() {
+/// state.Update(*controller_api);
+/// // ... process controller state ...
+/// }
+///
+/// // When your application gets paused:
+/// void OnPause() {
+/// controller_api->Pause();
+/// }
+///
+/// // When your application gets resumed:
+/// void OnResume() {
+/// controller_api->Resume();
+/// }
+///
+/// To conserve battery, be sure to call Pause() and Resume() when your app
+/// gets paused and resumed, respectively. This will allow the underlying
+/// logic to unbind from the VR service and let the controller sleep when
+/// no apps are using it.
+///
+/// THREADING: this class is thread-safe and reentrant after initialized
+/// with Init().
+class ControllerApi {
+ public:
+ /// Creates an (uninitialized) ControllerApi object. You must initialize
+ /// it by calling Init() before interacting with it.
+ ControllerApi() : context_(nullptr) {}
+
+ /// Returns the default controller options.
+ static int32_t DefaultOptions() {
+ return gvr_controller_get_default_options();
+ }
+
+ // Deprecated factory-style create method.
+ // TODO(btco): remove this once no one is using it.
+ static std::unique_ptr<ControllerApi> Create() {
+ return std::unique_ptr<ControllerApi>(new ControllerApi);
+ }
+
+ /// Initializes the controller API.
+ ///
+ /// This method must be called exactly once in the lifetime of this object.
+ /// Other methods in this class may only be called after Init() returns true.
+ /// Note: this does not cause the ControllerApi to be resumed. You must call
+ /// Resume() explicitly in order to start using the controller.
+ ///
+ /// For more information see gvr_controller_create_and_init().
+ ///
+ /// @return True if initialization was successful, false if it failed.
+ /// Initialization may fail, for example, because invalid options were
+ /// supplied.
+ bool Init(int32_t options, gvr_context* context) {
+ context_ = gvr_controller_create_and_init(options, context);
+ return context_ != nullptr;
+ }
+
+#ifdef __ANDROID__
+ /// Overload of Init() with explicit Android context and class loader
+ /// (for Android only). For more information, see:
+ /// gvr_controller_create_and_init_android().
+ bool Init(JNIEnv *env, jobject android_context, jobject class_loader,
+ int32_t options, gvr_context* context) {
+ context_ = gvr_controller_create_and_init_android(
+ env, android_context, class_loader, options, context);
+ return context_ != nullptr;
+ }
+#endif // #ifdef __ANDROID__
+
+ /// Convenience overload that calls Init without a gvr_context.
+ // TODO(btco): remove once it is no longer being used.
+ bool Init(int32_t options) {
+ return Init(options, nullptr);
+ }
+
+ /// Pauses the controller.
+ /// For more information, see gvr_controller_pause().
+ void Pause() {
+ gvr_controller_pause(context_);
+ }
+
+ /// Resumes the controller.
+ /// For more information, see gvr_controller_resume().
+ void Resume() {
+ gvr_controller_resume(context_);
+ }
+
+ /// Destroys this ControllerApi instance.
+ ~ControllerApi() {
+ if (context_) gvr_controller_destroy(&context_);
+ }
+
+ /// Convenience functions to convert enums to strings.
+ /// For more information, see the corresponding functions in the C API.
+ static const char* ToString(ControllerApiStatus status) {
+ return gvr_controller_api_status_to_string(status);
+ }
+
+ static const char* ToString(ControllerConnectionState state) {
+ return gvr_controller_connection_state_to_string(state);
+ }
+
+ static const char* ToString(ControllerButton button) {
+ return gvr_controller_button_to_string(button);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit ControllerApi(gvr_controller_context* context)
+ : context_(context) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_controller_context* cobj() { return context_; }
+ const gvr_controller_context* cobj() const { return context_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_controller_context* release() {
+ auto result = context_;
+ context_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ protected:
+ gvr_controller_context* context_;
+
+ private:
+ friend class ControllerState;
+
+ // Disallow copy and assign:
+ ControllerApi(const ControllerApi&);
+ void operator=(const ControllerApi&);
+};
+
+/// Convenience C++ wrapper for the opaque gvr_controller_state type. See the
+/// gvr_controller_state functions for more information.
+class ControllerState {
+ public:
+ ControllerState() : state_(gvr_controller_state_create()) {}
+
+ ~ControllerState() {
+ if (state_) gvr_controller_state_destroy(&state_);
+ }
+
+ /// For more information, see gvr_controller_state_update().
+ void Update(const ControllerApi& api) {
+ gvr_controller_state_update(api.context_, 0, state_);
+ }
+
+ /// For more information, see gvr_controller_state_update().
+ void Update(const ControllerApi& api, int32_t flags) {
+ gvr_controller_state_update(api.context_, flags, state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_api_status().
+ ControllerApiStatus GetApiStatus() const {
+ return static_cast<ControllerApiStatus>(
+ gvr_controller_state_get_api_status(state_));
+ }
+
+ /// For more information, see gvr_controller_state_get_connection_state().
+ ControllerConnectionState GetConnectionState() const {
+ return static_cast<ControllerConnectionState>(
+ gvr_controller_state_get_connection_state(state_));
+ }
+
+ /// For more information, see gvr_controller_state_get_orientation().
+ gvr_quatf GetOrientation() const {
+ return gvr_controller_state_get_orientation(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_gyro().
+ gvr_vec3f GetGyro() const { return gvr_controller_state_get_gyro(state_); }
+
+ /// For more information, see gvr_controller_state_get_accel().
+ gvr_vec3f GetAccel() const { return gvr_controller_state_get_accel(state_); }
+
+ /// For more information, see gvr_controller_state_is_touching().
+ bool IsTouching() const { return gvr_controller_state_is_touching(state_); }
+
+ /// For more information, see gvr_controller_state_get_touch_pos().
+ gvr_vec2f GetTouchPos() const {
+ return gvr_controller_state_get_touch_pos(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_touch_down().
+ bool GetTouchDown() const {
+ return gvr_controller_state_get_touch_down(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_touch_up().
+ bool GetTouchUp() const { return gvr_controller_state_get_touch_up(state_); }
+
+ /// For more information, see gvr_controller_state_get_recentered().
+ bool GetRecentered() const {
+ return gvr_controller_state_get_recentered(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_recentering().
+ bool GetRecentering() const {
+ return gvr_controller_state_get_recentering(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_button_state().
+ bool GetButtonState(ControllerButton button) const {
+ return gvr_controller_state_get_button_state(state_, button);
+ }
+
+ /// For more information, see gvr_controller_state_get_button_down().
+ bool GetButtonDown(ControllerButton button) const {
+ return gvr_controller_state_get_button_down(state_, button);
+ }
+
+ /// For more information, see gvr_controller_state_get_button_up().
+ bool GetButtonUp(ControllerButton button) const {
+ return gvr_controller_state_get_button_up(state_, button);
+ }
+
+ /// For more information, see
+ /// gvr_controller_state_get_last_orientation_timestamp().
+ int64_t GetLastOrientationTimestamp() const {
+ return gvr_controller_state_get_last_orientation_timestamp(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_last_gyro_timestamp().
+ int64_t GetLastGyroTimestamp() const {
+ return gvr_controller_state_get_last_gyro_timestamp(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_last_accel_timestamp().
+ int64_t GetLastAccelTimestamp() const {
+ return gvr_controller_state_get_last_accel_timestamp(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_last_touch_timestamp().
+ int64_t GetLastTouchTimestamp() const {
+ return gvr_controller_state_get_last_touch_timestamp(state_);
+ }
+
+ /// For more information, see
+ /// gvr_controller_state_get_last_button_timestamp().
+ int64_t GetLastButtonTimestamp() const {
+ return gvr_controller_state_get_last_button_timestamp(state_);
+ }
+
+ /// For more information, see gvr_controller_state_get_position().
+ gvr_vec3f GetPosition() const {
+ return gvr_controller_state_get_position(state_);
+ }
+
+ /// For more information, see
+ /// gvr_controller_state_get_last_position_timestamp().
+ int64_t GetLastPositionTimestamp() const {
+ return gvr_controller_state_get_last_position_timestamp(state_);
+ }
+
+ /// @name Wrapper manipulation
+ /// @{
+ /// Creates a C++ wrapper for a C object and takes ownership.
+ explicit ControllerState(gvr_controller_state* state) : state_(state) {}
+
+ /// Returns the wrapped C object. Does not affect ownership.
+ gvr_controller_state* cobj() { return state_; }
+ const gvr_controller_state* cobj() const { return state_; }
+
+ /// Returns the wrapped C object and transfers its ownership to the caller.
+ /// The wrapper becomes invalid and should not be used.
+ gvr_controller_state* release() {
+ auto result = state_;
+ state_ = nullptr;
+ return result;
+ }
+ /// @}
+
+ private:
+ gvr_controller_state* state_;
+};
+
+} // namespace gvr
+#endif // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h
new file mode 100644
index 0000000..ff00863
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h
@@ -0,0 +1,575 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup types Google VR Types
+/// @brief Various types used in the Google VR NDK.
+/// @{
+
+/// Primary context for invoking Google VR APIs.
+typedef struct gvr_context_ gvr_context;
+
+/// An enum for the left and right eye.
+typedef enum {
+ GVR_LEFT_EYE = 0,
+ GVR_RIGHT_EYE,
+ GVR_NUM_EYES
+} gvr_eye;
+
+/// The type of VR viewer.
+typedef enum {
+ /// A Cardboard-compatible viewer. A typical Cardboard viewer supports a
+ /// simple touchscreen-based trigger input mechanism. On most platforms, this
+ // is the default viewer type if no viewer has been explicitly paired.
+ GVR_VIEWER_TYPE_CARDBOARD = 0,
+ /// A Daydream-compatible viewer. A typical Daydream viewer supports 3DOF
+ /// controller input (as defined in gvr_controller.h), and is intended only
+ /// for Daydream-ready platforms. It does *not* support touchscreen-based
+ /// input unless Cardboard emulation is explicitly enabled.
+ GVR_VIEWER_TYPE_DAYDREAM = 1,
+} gvr_viewer_type;
+
+/// @}
+
+/// Version information for the Google VR API.
+typedef struct gvr_version_ {
+ int32_t major;
+ int32_t minor;
+ int32_t patch;
+} gvr_version;
+
+/// An integral 2D size. Used for render target sizes.
+typedef struct gvr_sizei {
+ int32_t width;
+ int32_t height;
+} gvr_sizei;
+
+/// An integral 2D rect. Used for window bounds in pixels.
+typedef struct gvr_recti {
+ int32_t left;
+ int32_t right;
+ int32_t bottom;
+ int32_t top;
+} gvr_recti;
+
+/// A floating point 2D rect. Used for field of view, and also for ranges
+/// in texture space. When used for a field of view, all angles are in positive
+/// degrees from the optical axis.
+typedef struct gvr_rectf {
+ float left;
+ float right;
+ float bottom;
+ float top;
+} gvr_rectf;
+
+/// A floating point 2D vector.
+typedef struct gvr_vec2f {
+ float x;
+ float y;
+} gvr_vec2f;
+
+/// A floating point 3D vector.
+typedef struct gvr_vec3f {
+ float x;
+ float y;
+ float z;
+} gvr_vec3f;
+
+/// A floating point 4x4 matrix.
+typedef struct gvr_mat4f { float m[4][4]; } gvr_mat4f;
+
+/// A floating point quaternion, in JPL format.
+/// We use this simple struct in order not to impose a dependency on a
+/// particular math library. The user of this API is free to encapsulate this
+/// into any math library they want.
+typedef struct gvr_quatf {
+ /// qx, qy, qz are the vector component.
+ float qx;
+ float qy;
+ float qz;
+ /// qw is the linelar component.
+ float qw;
+} gvr_quatf;
+
+/// A *monotonic system time* representation. On Android, this is equivalent to
+/// System.nanoTime(), or clock_gettime(CLOCK_MONOTONIC). If there is any doubt
+/// about how to get the current time for the current platform, simply use
+/// gvr_get_time_point_now().
+typedef struct gvr_clock_time_point {
+ int64_t monotonic_system_time_nanos;
+} gvr_clock_time_point;
+
+/// A structure that ties together a region of a buffer, the field of view
+/// rendered into that region and a target eye index to define part of the
+/// user's field of view. The SDK implementation uses this information to
+/// transform the images generated by the app output into the final display that
+/// is sent to the screen.
+///
+/// A set of these structures will most often be generated by the API, via
+/// gvr_get_recommended_buffer_viewports() or
+/// gvr_get_screen_buffer_viewports(). However, the client may also customize
+/// these values via gvr_buffer_viewport_list_set(), constructing a custom
+/// gvr_buffer_viewport_list for use in the distortion pass.
+typedef struct gvr_buffer_viewport_ gvr_buffer_viewport;
+
+/// List of buffer viewports that completely specifies how to transform the
+/// frame's buffers into the image displayed on the screen.
+typedef struct gvr_buffer_viewport_list_ gvr_buffer_viewport_list;
+
+/// Specification of a pixel buffer. A pixel buffer can have color, depth and
+/// stencil attachments and mostly corresponds to the OpenGL concept of a
+/// framebuffer object. However, since there can be multiple such objects for
+/// each frame, we avoid calling them "framebuffers". Pixel buffers which are
+/// part of the currently acquired frame are immutable, i.e., they cannot be
+/// resized or otherwise reconfigured.
+typedef struct gvr_buffer_spec_ gvr_buffer_spec;
+
+/// Swap chain that contains some number of frames. Frames in the swap chain
+/// can be unused, in the process of being distorted and presented on the
+/// screen, or acquired and being rendered to by the application. The swap chain
+/// ensures that the most recent available frame is always shown and that the
+/// application never has to wait to render the next frame.
+typedef struct gvr_swap_chain_ gvr_swap_chain;
+
+/// A single frame acquired from the swap chain. Each frame is composed of one
+/// or more buffers, which are then lens distorted and composited into the final
+/// output. Buffers are identified by indices that correspond to the position
+/// of their gvr_buffer_spec in the list passed when constructing the swap
+/// chain.
+typedef struct gvr_frame_ gvr_frame;
+
+/// @addtogroup types
+/// @{
+
+/// Constants that represent GVR error codes.
+typedef enum {
+ GVR_ERROR_NONE = 0,
+ GVR_ERROR_CONTROLLER_CREATE_FAILED = 2,
+ GVR_ERROR_NO_FRAME_AVAILABLE = 3,
+} gvr_error;
+
+/// Controller API options (bit flags).
+enum {
+ /// Indicates that controller orientation data should be reported.
+ GVR_CONTROLLER_ENABLE_ORIENTATION = 1 << 0,
+ /// Indicates that controller touchpad data should be reported.
+ GVR_CONTROLLER_ENABLE_TOUCH = 1 << 1,
+ /// Indicates that controller gyroscope data should be reported.
+ GVR_CONTROLLER_ENABLE_GYRO = 1 << 2,
+ /// Indicates that controller accelerometer data should be reported.
+ GVR_CONTROLLER_ENABLE_ACCEL = 1 << 3,
+ /// Indicates that controller gestures should be reported.
+ GVR_CONTROLLER_ENABLE_GESTURES = 1 << 4,
+ /// Indicates that controller pose prediction should be enabled.
+ GVR_CONTROLLER_ENABLE_POSE_PREDICTION = 1 << 5,
+ /// Indicates that controller position data should be reported.
+ GVR_CONTROLLER_ENABLE_POSITION = 1 << 6,
+};
+
+/// Constants that represent the status of the controller API.
+typedef enum {
+ /// API is happy and healthy. This doesn't mean the controller itself
+ /// is connected, it just means that the underlying service is working
+ /// properly.
+ GVR_CONTROLLER_API_OK = 0,
+
+ /// Any other status represents a permanent failure that requires
+ /// external action to fix:
+
+ /// API failed because this device does not support controllers (API is too
+ /// low, or other required feature not present).
+ GVR_CONTROLLER_API_UNSUPPORTED = 1,
+ /// This app was not authorized to use the service (e.g., missing permissions,
+ /// the app is blacklisted by the underlying service, etc).
+ GVR_CONTROLLER_API_NOT_AUTHORIZED = 2,
+ /// The underlying VR service is not present.
+ GVR_CONTROLLER_API_UNAVAILABLE = 3,
+ /// The underlying VR service is too old, needs upgrade.
+ GVR_CONTROLLER_API_SERVICE_OBSOLETE = 4,
+ /// The underlying VR service is too new, is incompatible with current client.
+ GVR_CONTROLLER_API_CLIENT_OBSOLETE = 5,
+ /// The underlying VR service is malfunctioning. Try again later.
+ GVR_CONTROLLER_API_MALFUNCTION = 6,
+} gvr_controller_api_status;
+
+/// Constants that represent the state of the controller.
+typedef enum {
+ /// Controller is disconnected.
+ GVR_CONTROLLER_DISCONNECTED = 0,
+ /// Controller is scanning.
+ GVR_CONTROLLER_SCANNING = 1,
+ /// Controller is connecting.
+ GVR_CONTROLLER_CONNECTING = 2,
+ /// Controller is connected.
+ GVR_CONTROLLER_CONNECTED = 3,
+} gvr_controller_connection_state;
+
+/// Controller buttons.
+typedef enum {
+ GVR_CONTROLLER_BUTTON_NONE = 0,
+ GVR_CONTROLLER_BUTTON_CLICK = 1, ///< Touchpad Click.
+ GVR_CONTROLLER_BUTTON_HOME = 2,
+ GVR_CONTROLLER_BUTTON_APP = 3,
+ GVR_CONTROLLER_BUTTON_VOLUME_UP = 4,
+ GVR_CONTROLLER_BUTTON_VOLUME_DOWN = 5,
+
+ /// Note: there are 5 buttons on the controller, but the state arrays have
+ /// this many elements due to the inclusion of a dummy "none" button.
+ GVR_CONTROLLER_BUTTON_COUNT = 6,
+} gvr_controller_button;
+
+/// @}
+
+/// Opaque handle to controller state.
+typedef struct gvr_controller_state_ gvr_controller_state;
+
+/// @addtogroup types
+/// @{
+
+/// Rendering modes define CPU load / rendering quality balances.
+typedef enum {
+ /// Stereo panning of all Sound Objects. This disables HRTF-based rendering.
+ GVR_AUDIO_RENDERING_STEREO_PANNING = 0,
+ /// HRTF-based rendering over a virtual array of 8 loudspeakers arranged in
+ /// a cube configuration around the listener’s head.
+ GVR_AUDIO_RENDERING_BINAURAL_LOW_QUALITY = 1,
+ /// HRTF-based rendering over a virtual array of 16 loudspeakers arranged in
+ /// an approximate equidistribution about the around the listener’s head.
+ GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY = 2,
+} gvr_audio_rendering_mode;
+
+/// Room surface material names, used to set room properties.
+typedef enum {
+ /// Acoustically transparent material, reflects no sound.
+ GVR_AUDIO_MATERIAL_TRANSPARENT = 0,
+ /// Acoustic ceiling tiles, absorbs most frequencies.
+ GVR_AUDIO_MATERIAL_ACOUSTIC_CEILING_TILES = 1,
+ /// Bare brick, relatively reflective.
+ GVR_AUDIO_MATERIAL_BRICK_BARE = 2,
+ /// Painted brick
+ GVR_AUDIO_MATERIAL_BRICK_PAINTED = 3,
+ /// Coarse surface concrete block.
+ GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_COARSE = 4,
+ /// Painted concrete block.
+ GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_PAINTED = 5,
+ /// Heavy curtains.
+ GVR_AUDIO_MATERIAL_CURTAIN_HEAVY = 6,
+ /// Fiber glass insulation.
+ GVR_AUDIO_MATERIAL_FIBER_GLASS_INSULATION = 7,
+ /// Thin glass.
+ GVR_AUDIO_MATERIAL_GLASS_THIN = 8,
+ /// Thick glass.
+ GVR_AUDIO_MATERIAL_GLASS_THICK = 9,
+ /// Grass.
+ GVR_AUDIO_MATERIAL_GRASS = 10,
+ /// Linoleum on concrete.
+ GVR_AUDIO_MATERIAL_LINOLEUM_ON_CONCRETE = 11,
+ /// Marble.
+ GVR_AUDIO_MATERIAL_MARBLE = 12,
+ /// Galvanized sheet metal.
+ GVR_AUDIO_MATERIAL_METAL = 13,
+ /// Wooden parquet on concrete.
+ GVR_AUDIO_MATERIAL_PARQUET_ON_CONCRETE = 14,
+ /// Rough plaster surface.
+ GVR_AUDIO_MATERIAL_PLASTER_ROUGH = 15,
+ /// Smooth plaster surface.
+ GVR_AUDIO_MATERIAL_PLASTER_SMOOTH = 16,
+ /// Plywood panel.
+ GVR_AUDIO_MATERIAL_PLYWOOD_PANEL = 17,
+ /// Polished concrete OR tile surface.
+ GVR_AUDIO_MATERIAL_POLISHED_CONCRETE_OR_TILE = 18,
+ /// Sheet rock.
+ GVR_AUDIO_MATERIAL_SHEET_ROCK = 19,
+ /// Surface of water or ice.
+ GVR_AUDIO_MATERIAL_WATER_OR_ICE_SURFACE = 20,
+ /// Wooden ceiling.
+ GVR_AUDIO_MATERIAL_WOOD_CEILING = 21,
+ /// Wood paneling.
+ GVR_AUDIO_MATERIAL_WOOD_PANEL = 22,
+} gvr_audio_material_type;
+
+/// Distance rolloff models used for distance attenuation.
+typedef enum {
+ /// Logarithmic distance rolloff model.
+ GVR_AUDIO_ROLLOFF_LOGARITHMIC = 0,
+ /// Linear distance rolloff model.
+ GVR_AUDIO_ROLLOFF_LINEAR = 1,
+ /// No distance attenuation will be applied.
+ GVR_AUDIO_ROLLOFF_NONE = 2,
+} gvr_audio_distance_rolloff_type;
+
+/// Sound object and sound field identifier.
+typedef int32_t gvr_audio_source_id;
+
+/// Valid color formats for swap chain buffers.
+typedef enum {
+ /// Equivalent to GL_RGBA8
+ GVR_COLOR_FORMAT_RGBA_8888 = 0,
+ /// Equivalent to GL_RGB565
+ GVR_COLOR_FORMAT_RGB_565 = 1,
+} gvr_color_format_type;
+
+typedef enum {
+ /// No depth or stencil buffer.
+ GVR_DEPTH_STENCIL_FORMAT_NONE = 255,
+ /// Equivalent to GL_DEPTH_COMPONENT16.
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_16 = 0,
+ /// Equivalent to GL_DEPTH_COMPONENT24.
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_24 = 1,
+ /// Equivlaent to GL_DEPTH24_STENCIL8.
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8 = 2,
+ /// Equivalent to GL_DEPTH_COMPONENT32F.
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F = 3,
+ /// Equivalent to GL_DEPTH_32F_STENCIL8.
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8 = 4,
+ /// Equivalent to GL_STENCIL8.
+ GVR_DEPTH_STENCIL_FORMAT_STENCIL_8 = 5,
+} gvr_depth_stencil_format_type;
+
+/// Types of asynchronous reprojection.
+typedef enum {
+ /// Do not reproject.
+ GVR_REPROJECTION_NONE = 0,
+ /// Reproject in all dimensions.
+ GVR_REPROJECTION_FULL = 1,
+} gvr_reprojection;
+
+typedef enum {
+ GVR_CONTROLLER_RIGHT_HANDED = 0,
+ GVR_CONTROLLER_LEFT_HANDED = 1,
+} gvr_controller_handedness;
+
+typedef struct gvr_user_prefs_ gvr_user_prefs;
+
+// Anonymous enum for miscellaneous integer constants.
+enum {
+ /// Constant that represents a nonexistent external surface. Pass to
+ /// gvr_buffer_viewport_set_external_surface_id() to disable sampling from
+ /// an external surface.
+ GVR_EXTERNAL_SURFACE_ID_NONE = -1,
+ /// Special index for a source buffer that has the same contents as the
+ /// external surface attached to the given viewport. Pass this to
+ /// gvr_buffer_viewport_set_source_buffer_index() to use the external surface
+ /// as the buffer contents.
+ GVR_BUFFER_INDEX_EXTERNAL_SURFACE = -1,
+};
+
+/// @}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+// These typedefs convert the C-style names to C++-style names.
+
+namespace gvr {
+
+const int32_t kControllerEnableOrientation =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_ORIENTATION);
+const int32_t kControllerEnableTouch =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_TOUCH);
+const int32_t kControllerEnableGyro =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_GYRO);
+const int32_t kControllerEnableAccel =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_ACCEL);
+const int32_t kControllerEnableGestures =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_GESTURES);
+const int32_t kControllerEnablePosePrediction =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_POSE_PREDICTION);
+const int32_t kControllerEnablePosition =
+ static_cast<int32_t>(GVR_CONTROLLER_ENABLE_POSITION);
+
+typedef gvr_controller_api_status ControllerApiStatus;
+const ControllerApiStatus kControllerApiOk =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_OK);
+const ControllerApiStatus kControllerApiUnsupported =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_UNSUPPORTED);
+const ControllerApiStatus kControllerApiNotAuthorized =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_NOT_AUTHORIZED);
+const ControllerApiStatus kControllerApiUnavailable =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_UNAVAILABLE);
+const ControllerApiStatus kControllerApiServiceObsolete =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_SERVICE_OBSOLETE);
+const ControllerApiStatus kControllerApiClientObsolete =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_CLIENT_OBSOLETE);
+const ControllerApiStatus kControllerApiMalfunction =
+ static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_MALFUNCTION);
+
+typedef gvr_controller_connection_state ControllerConnectionState;
+const ControllerConnectionState kControllerDisconnected =
+ static_cast<ControllerConnectionState>(GVR_CONTROLLER_DISCONNECTED);
+const ControllerConnectionState kControllerScanning =
+ static_cast<ControllerConnectionState>(GVR_CONTROLLER_SCANNING);
+const ControllerConnectionState kControllerConnecting =
+ static_cast<ControllerConnectionState>(GVR_CONTROLLER_CONNECTING);
+const ControllerConnectionState kControllerConnected =
+ static_cast<ControllerConnectionState>(GVR_CONTROLLER_CONNECTED);
+
+typedef gvr_controller_button ControllerButton;
+const ControllerButton kControllerButtonNone =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_NONE);
+const ControllerButton kControllerButtonClick =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_CLICK);
+const ControllerButton kControllerButtonHome =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_HOME);
+const ControllerButton kControllerButtonApp =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_APP);
+const ControllerButton kControllerButtonVolumeUp =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_VOLUME_UP);
+const ControllerButton kControllerButtonVolumeDown =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_VOLUME_DOWN);
+const ControllerButton kControllerButtonCount =
+ static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_COUNT);
+
+/// An uninitialized external surface ID.
+const int32_t kUninitializedExternalSurface = GVR_BUFFER_INDEX_EXTERNAL_SURFACE;
+/// The default source buffer index for viewports.
+const int32_t kDefaultBufferIndex = 0;
+
+typedef gvr_eye Eye;
+
+typedef gvr_viewer_type ViewerType;
+const ViewerType kViewerTypeCardboard =
+ static_cast<ViewerType>(GVR_VIEWER_TYPE_CARDBOARD);
+const ViewerType kViewerTypeDaydream =
+ static_cast<ViewerType>(GVR_VIEWER_TYPE_DAYDREAM);
+
+typedef gvr_version Version;
+typedef gvr_sizei Sizei;
+typedef gvr_recti Recti;
+typedef gvr_rectf Rectf;
+typedef gvr_vec2f Vec2f;
+typedef gvr_vec3f Vec3f;
+typedef gvr_mat4f Mat4f;
+typedef gvr_quatf Quatf;
+typedef gvr_clock_time_point ClockTimePoint;
+
+typedef gvr_vec2f ControllerVec2;
+typedef gvr_vec3f ControllerVec3;
+typedef gvr_quatf ControllerQuat;
+
+typedef gvr_audio_rendering_mode AudioRenderingMode;
+typedef gvr_audio_material_type AudioMaterialName;
+typedef gvr_audio_distance_rolloff_type AudioRolloffMethod;
+typedef gvr_audio_source_id AudioSourceId;
+
+typedef gvr_color_format_type ColorFormat;
+const ColorFormat kColorFormatRgba8888 =
+ static_cast<ColorFormat>(GVR_COLOR_FORMAT_RGBA_8888);
+const ColorFormat kColorFormatRgb565 =
+ static_cast<ColorFormat>(GVR_COLOR_FORMAT_RGB_565);
+
+typedef gvr_depth_stencil_format_type DepthStencilFormat;
+const DepthStencilFormat kDepthStencilFormatNone =
+ static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_NONE);
+const DepthStencilFormat kDepthStencilFormatDepth16 =
+ static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16);
+const DepthStencilFormat kDepthStencilFormatDepth24 =
+ static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_24);
+const DepthStencilFormat kDepthStencilFormatDepth24Stencil8 =
+ static_cast<DepthStencilFormat>(
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8);
+const DepthStencilFormat kDepthStencilFormatDepth32f =
+ static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F);
+const DepthStencilFormat kDepthStencilFormatDepth32fStencil8 =
+ static_cast<DepthStencilFormat>(
+ GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8);
+const DepthStencilFormat kDepthStencilFormatStencil8 =
+ static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_STENCIL_8);
+
+typedef gvr_controller_handedness ControllerHandedness;
+const ControllerHandedness kControllerRightHanded =
+ static_cast<ControllerHandedness>(GVR_CONTROLLER_RIGHT_HANDED);
+const ControllerHandedness kControllerLeftHanded =
+ static_cast<ControllerHandedness>(GVR_CONTROLLER_LEFT_HANDED);
+
+typedef gvr_error Error;
+const Error kErrorNone = static_cast<Error>(GVR_ERROR_NONE);
+const Error kErrorControllerCreateFailed =
+ static_cast<Error>(GVR_ERROR_CONTROLLER_CREATE_FAILED);
+const Error kErrorNoFrameAvailable =
+ static_cast<Error>(GVR_ERROR_NO_FRAME_AVAILABLE);
+
+class AudioApi;
+class BufferSpec;
+class ControllerApi;
+class ControllerState;
+class Frame;
+class GvrApi;
+class BufferViewport;
+class BufferViewportList;
+class SwapChain;
+class UserPrefs;
+
+} // namespace gvr
+
+// Non-member equality operators for convenience. Since typedefs do not trigger
+// argument-dependent lookup, these operators have to be defined for the
+// underlying types.
+inline bool operator==(const gvr_vec2f& lhs, const gvr_vec2f& rhs) {
+ return lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+inline bool operator!=(const gvr_vec2f& lhs, const gvr_vec2f& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_vec3f& lhs, const gvr_vec3f& rhs) {
+ return lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+inline bool operator!=(const gvr_vec3f& lhs, const gvr_vec3f& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_recti& lhs, const gvr_recti& rhs) {
+ return lhs.left == rhs.left && lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom && lhs.top == rhs.top;
+}
+
+inline bool operator!=(const gvr_recti& lhs, const gvr_recti& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_rectf& lhs, const gvr_rectf& rhs) {
+ return lhs.left == rhs.left && lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom && lhs.top == rhs.top;
+}
+
+inline bool operator!=(const gvr_rectf& lhs, const gvr_rectf& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_sizei& lhs, const gvr_sizei& rhs) {
+ return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const gvr_sizei& lhs, const gvr_sizei& rhs) {
+ return !(lhs == rhs);
+}
+
+#endif // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif // VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h
new file mode 100644
index 0000000..6bc2b4e
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h
@@ -0,0 +1,240 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
+#define VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr_types.h"
+#include "vr/gvr/capi/src/gvr_types_experimental.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// NOTE: APIs added to this file are *not* part of the core GVR library, and
+// should only be used for prototyping or experimental projects. The idea is
+// that APIs added here can be used for testing and development, graduating to
+// the core API (gvr.h or gvr_private.h) after we're ready to commit to them
+// indefinitely.
+
+// ************************************************************************** //
+// * DaydreamOS experimental APIs * //
+// ************************************************************************** //
+
+/// Gets the position and rotation from start space to head space. The head
+/// space is a space where the head is at the origin and faces the -Z direction.
+///
+/// @param gvr Pointer to the gvr instance from which to get the pose.
+/// @param time The time at which to get the head pose. The time should be in
+/// the future. If the time is not in the future, it will be clamped to now.
+/// @return A matrix representation of the position and rotation from start
+// space (the space where the head was last reset) to head space (the space
+/// with the head at the origin, and the axes aligned to the view vector).
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+ gvr_context* gvr, const gvr_clock_time_point time);
+
+/// Sets the compositor z-order of the swap chain.
+///
+/// @param swap_chain the swap chain to change.
+/// @param z_order Z order, higher values are displayed on top of lower ones,
+/// the default value is 0.
+void gvr_swap_chain_set_z_order(const gvr_swap_chain* swap_chain, int z_order);
+
+/// Creates a gvr_external_surface instance.
+/// An external surface is mainly used to pass external content (such as video
+/// frames, pre-rendered 2D Android UI) into distortion pass for compositing.
+/// The method gvr_external_surface_get_surface can be used to bridge Android
+/// components with GVR distortion pass via a traditional Android Surface
+/// instance.
+///
+/// @param gvr Pointer to the gvr instance from which to create the external
+/// surface.
+/// @return Pointer to an allocated gvr_external_surface object. The caller
+// is responsible for calling gvr_external_surface_destroy() on the
+/// returned object when it is no longer needed.
+gvr_external_surface* gvr_external_surface_create(gvr_context* gvr);
+
+/// Frees a gvr_external_surface instance and clears the pointer.
+/// Note that once a gvr_external_surface is destroyed, the Java Surface object
+/// returned from gvr_external_surface_get_surface remains to be accessible and
+/// functioning. It's up to Java's garbage collection to release all resources
+/// behind the Java Surface object.
+///
+/// @param surface Pointer to a pointer to the gvr_external_surface instance to
+/// be destroyed and nulled.
+void gvr_external_surface_destroy(gvr_external_surface** surface);
+
+/// Get an Android Surface as a Java object from the gvr_external_surface. This
+/// API is mainly used by standalone display service (aka when
+/// gvr_using_vr_display_service returns true) to access an Android Surface.
+///
+/// @param surface The gvr_external_surface associated with the Android Surface.
+/// Note that this API has to be called within a JNIEnv and is using the
+/// JNIEnv passed in during gvr_create.
+/// @return A jobject that is an instance of the 'android/view/Surface' Java
+/// class, NULL on failure. Note that the return value is really an opaque
+/// handle to a Java object and the life cycle of that object is maintained
+/// by Java (i.e. it will get garbage collected eventually). Thus, there is
+/// no need for an explicit destroy call.
+void* gvr_external_surface_get_surface(const gvr_external_surface* surface);
+
+/// Get the Surface ID associated with the gvr_external_surface. Note that the
+/// returned ID is used for internal bookkeeping only and should not be used
+/// by the app itself for lookups.
+/// @param surface The gvr_external_surface to query the ID for.
+/// @return The external surface ID associated with the gvr_external_surface.
+int32_t gvr_external_surface_get_surface_id(
+ const gvr_external_surface* surface);
+
+/// Queries whether a particular GVR feature is supported by the underlying
+/// platform.
+///
+/// @param gvr The context to query against.
+/// @param feature The gvr_feature type being queried.
+/// @return true if feature is supported, false otherwise.
+bool gvr_experimental_is_feature_supported(const gvr_context* gvr,
+ int32_t feature);
+
+/// Sets the z order of the layer to be created.
+/// Note that this API is a short-term workaround for SysUI work and is never
+/// meant to graduate as is to either gvr.h or gvr_private.h. The proper
+/// solution is tracked in b/33946428 and probably involves setting the
+/// attribute on some data structure that represents a layer.
+///
+/// @param spec Buffer specification.
+/// @param z_order Z order, higher values are displayed on top of lower ones,
+/// the default value is 0.
+void gvr_buffer_spec_set_z_order(gvr_buffer_spec* spec, int z_order);
+
+/// Sets the initial visibility of the layer to be created.
+/// Note that this API is a short-term workaround for SysUI work and is never
+/// meant to graduate as is to either gvr.h or gvr_private.h. The proper
+/// solution is tracked in b/33946428 and probably involves setting the
+/// attribute on some data structure that represents a layer.
+///
+/// @param spec Buffer specification.
+/// @param visibility Initial visibility of the layer, defaults to GVR_VISIBLE.
+/// See enum gvr_visibility for possible values.
+void gvr_buffer_spec_set_visibility(gvr_buffer_spec* spec,
+ int32_t visibility);
+
+/// Sets whether to blur layers below the layer to be created.
+/// Blurring is applied only to visible layers and only when the layer is
+/// visible.
+/// Note that this API currently is only implemented by the DreamOS
+/// implementation of GVR and is a no-op in other implementations.
+/// TODO(b/33946428): investigate the proper way to surface this feature
+/// to SysUI.
+///
+/// @param spec Buffer specification.
+/// @param blur_behind whether to blur layers behind, defaults to
+/// GVR_BLUR_BEHIND_TRUE. See enum gvr_blur_behind for possible values.
+void gvr_buffer_spec_set_blur_behind(gvr_buffer_spec* spec,
+ int32_t blur_behind);
+
+// ************************************************************************** //
+// * Daydream PlexEng experimental APIs * //
+// ************************************************************************** //
+
+// Registers a new performance event listener that will be invoked on points
+// of interest. By default no event listener is attached. If multiple event
+// listeners are attached they will all be invoked. Failures can be checked
+// with gvr_get_error().
+// @param out_handle The pointer to memory where a successfully created handle
+// will be written.
+// @param gvr The context to register callbacks for.
+// @param user_data The pointer that will be passed back on callbacks for
+// user_data.
+// @param event_callback The callback to be invoked when an event is observed.
+// On performance events callback will be invoked with the
+// user_data passed here, the gvr_perf_event_callback_type, and a float
+// value (if applicable) or -1.f.
+// @return Returns GVR_EXPERIMENTAL_ERROR_NONE if a handle was created,
+// GVR_EXPERIMENTAL_ERROR_UNIMPLEMENTED if this feature is disabled,
+// or GVR_EXPERIMENTAL_ERROR_INVALID_ARGUMENT if a null pointer was passed.
+bool gvr_experimental_register_perf_event_callback(
+ gvr_context* gvr, int* out_handle, void* user_data,
+ void (*event_callback)(void*, int, float));
+
+// Unregisters a previously registered callback by its handle. Failures can be
+// checked with gvr_get_error().
+// @param handle The handle which was returned when registering the callback.
+// @return Returns GVR_EXPERIMENTAL_ERROR_NONE if callback was unregistered,
+// GVR_EXPERIMENTAL_ERROR_INVALID_ARGUMENT if the if the handle wasn't
+// previously
+// registered. If this feature is not enabled it will return
+// GVR_EXPERIMENTAL_ERROR_UNIMPLEMENTED.
+bool gvr_experimental_unregister_perf_event_callback(gvr_context* gvr,
+ int handle);
+
+// ************************************************************************** //
+// * GVR Analytics experimental APIs * //
+// ************************************************************************** //
+// TODO(b/31634289): These functions are experimental because their main client
+// case is the performance monitoring HUD, whose form and function is still
+// under development. Consequently, the analytics API may change as the HUD's
+// needs become clearer.
+//
+// These functions will be moved into the main API (probably gvr_private.h) once
+// the HUD is ready to be shipped as part of the SDK.
+//
+// Contacts: georgelu@
+
+/// Returns whether the "Performance Monitoring" developer option is enabled.
+///
+/// @param user_prefs Pointer to the gvr_user_prefs object returned by
+/// gvr_get_user_prefs.
+/// @return True if the "Performance Monitoring" developer option is enabled.
+bool gvr_user_prefs_get_performance_monitoring_enabled(
+ const gvr_user_prefs* user_prefs);
+
+// Opaque struct returned by gvr_get_analytics that can be queried through
+// gvr_analytics_get* functions.
+//
+// Note: The struct is never actually defined since gvr_analytics is actually
+// just a static_cast of a gvr_context, similar to how gvr_user_prefs works.
+typedef struct gvr_analytics_ gvr_analytics;
+
+// Returns an opaque struct that can be queried for analytics data. The returned
+// struct remains valid as long as the context is valid.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @return An opaque struct that can be queried through gvr_analytics_*
+// functions.
+const gvr_analytics* gvr_get_analytics(gvr_context* gvr);
+
+// If the "Performance Monitoring" developer option in VR settings is enabled,
+// returns a gvr_analytics_sample* containing analytics data. Caller is
+// responsible for calling gvr_analytics_destroy_sample on the returned object.
+//
+// @param analytics gvr_analytics* returned by gvr_get_analytics.
+// @return gvr_analytics_sample* containing analytics data.
+const gvr_analytics_sample* gvr_analytics_create_sample(
+ const gvr_analytics* analytics);
+
+// Returns pointer to a buffer containing a serialized AnalyticsSample proto.
+// The buffer is valid only for the lifetime of the gvr_analytics_sample.
+//
+// @param Pointer to a gvr_analytics_sample object.
+// @return Pointer to buffer.
+const char* gvr_analytics_sample_get_buffer(const gvr_analytics_sample* sample);
+
+// Returns the length of the buffer returned by gvr_analytics_sample_get_buffer.
+//
+// @param Pointer to a gvr_analytics_sample object.
+// @return Length of buffer.
+size_t gvr_analytics_sample_get_buffer_length(
+ const gvr_analytics_sample* sample);
+
+// Destroys a gvr_analytics_sample* previously created through
+// gvr_analytics_create_sample.
+//
+// @param sample Pointer to pointer that will be set to null and whose
+// underlying gvr_analytics_sample will be destroyed.
+void gvr_analytics_destroy_sample(const gvr_analytics_sample** sample);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h
new file mode 100644
index 0000000..0a9d30e
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h
@@ -0,0 +1,378 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
+#define VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
+
+#include <stddef.h>
+
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Opaque handle to gvr_tracker_state object containing serialized state.
+typedef struct gvr_tracker_state_ gvr_tracker_state;
+
+// Opaque handle to gvr_display_synchronizer object for display synchronization.
+typedef struct gvr_display_synchronizer_ gvr_display_synchronizer;
+
+// Internal Google VR C API methods. These methods are exposed only to internal
+// targets, but should follow all the same backwards-compatible restrictions
+// as the public C API.
+
+/// Sets whether asynchronous reprojection is currently enabled.
+///
+/// If enabled, frames will be collected by the rendering system and
+/// asynchronously re-projected in sync with the scanout of the display. This
+/// feature may not be available on every platform, and requires a
+/// high-priority render thread with special extensions to function properly.
+///
+/// Note: On Android, this feature can be enabled solely via the GvrLayout Java
+/// instance which (indirectly) owns this gvr_context. The corresponding
+/// method call is GvrLayout.setAsyncReprojectionEnabled().
+///
+/// @param gvr Pointer to the gvr instance.
+/// @Param enabled Whether to enable async reprojection.
+/// @return Whether the setting was succesfully applied.
+bool gvr_set_async_reprojection_enabled(gvr_context* gvr, bool enabled);
+
+// Initializes necessary GL-related objects and uses the current thread and
+// GL context for racing the scanline. This function should only be called
+// by the SDK itself, not by any application, unless that application is
+// providing a high-priority thread and GL context for async reprojection.
+//
+// Note: This method is private as it is intended for use solely by the
+// hidden async reprojection implementation in ScanlineRacingRenderer.java,
+// called in onSurfaceCreated().
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_on_surface_created_reprojection_thread(gvr_context* gvr);
+
+// Renders the scanline layer. This function should only be called
+// in the same thread that gvr_initialize_gl_projection_thread was called in.
+// This function should only be called by the SDK itself, not by any
+// application, unless that application is providing a high-priority
+// thread and GL context for async reprojection.
+//
+// Note: This method is private as it is intended for use solely by the
+// hidden async reprojection implementation in ScanlineRacingRenderer.java.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_render_reprojection_thread(gvr_context* gvr);
+
+// Signals to the reprojection thread that it is paused. This is necessary
+// in case the application render thread is blocked on pending work by the
+// reprojection thread. This function will abort any blocking.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_on_pause_reprojection_thread(gvr_context* gvr);
+
+// Sets the parameters for the external surface managed by the reprojection
+// thread.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param surface_id The ID of the external Surface managed by the reprojection
+// thread. The ID is issued by the SurfaceTextureManager.
+// @param texture_id The GL texture ID associated with the external Surface.
+// @param timestamp The timestamp of the most recent frame the Surface holds.
+// @param surface_transfrom Matrix that transforms homogeneous texture coords to
+// the external surface texture space.
+void gvr_update_surface_reprojection_thread(gvr_context* gvr,
+ int32_t surface_id, int32_t texture_id, gvr_clock_time_point timestamp,
+ gvr_mat4f surface_transform);
+
+// Removes all external surfaces managed by the reprojection thread. This does
+// not destoy the surfaces: it removes tracking by the reprojection thread.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_remove_all_surfaces_reprojection_thread(gvr_context* gvr);
+
+// Reconnects the sensors when the sensor producers are created internally.
+//
+// Note: This function is not thread-safe, and should be called only on the
+// rendering thread. It is intended to be used internally by GvrLayout when
+// the target presentation display changes.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_reconnect_sensors(gvr_context* gvr);
+
+// Sets VR viewer params for the current context.
+//
+// Note: This function does not update the viewer proto in the common storage
+// location. Rather, it overrides the viewer params solely for the provided
+// gvr_context.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param serialized_viewer_params A pointer to the payload containing the
+// serialized viewer params proto.
+// @param serialized_viewer_params_size_bytes The length in bytes of the
+// serialized viewer params payload.
+// @return Whether the serialized viewer params proto was successfully applied.
+bool gvr_set_viewer_params(gvr_context* gvr,
+ const void* serialized_viewer_params,
+ size_t serialized_viewer_params_size_bytes);
+
+// Sets the lens offset.
+//
+// @param offset The offset of the lens center from the expected location in
+// screen space.
+void gvr_set_lens_offset(gvr_context* gvr, gvr_vec2f offset);
+
+// Sets display metrics for the current context.
+//
+// Note: This function does not update the phone proto in the commom storage
+// location. Rather, it overrides the internal metrics solely for the provided
+// |gvr| context.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param size_pixels The dimensions in pixels of the active display.
+// @param meters_per_pixel The density of the current display in meters/pixel.
+// @param border_size_meters The size of the border around the display
+// in meters. When the device sits on a surface in the proper
+// orientation this is the distance from the surface to the edge
+// of the display.
+void gvr_set_display_metrics(gvr_context* gvr, gvr_sizei size_pixels,
+ gvr_vec2f meters_per_pixel,
+ float border_size_meters);
+
+// Sets the display rotation offset that is applied at distortion correction
+// time to take into account the device's display orientation.
+//
+// For instance, calling this with display_output_rotation set to 1 allows
+// clients to lock their phone orientation to portrait on an Android phone and
+// still get a correctly rendered VR mode with the two eyes stacked up along the
+// longer phone dimension.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param display_output_rotation Value encoding the rotation used when
+// performing distortion correction. Supported values are:
+// 0 - Default mode. Eye viewports are positioned side-by-side along the
+// "width" dimension, with left eye in the x < 0.5 half.
+// 1 - Applies a clock-wise rotation of 90 degrees on the display when
+// doing distortion correction. Eye viewports are positioned
+// side-by-side along the "height" dimension, with left eye in the
+// y > 0.5 half.
+// Rotation modes used when performing distortion correction.
+enum {
+ GVR_PRIVATE_DISPLAY_OUTPUT_ROTATION_0 = 0,
+ GVR_PRIVATE_DISPLAY_OUTPUT_ROTATION_90 = 1,
+};
+void gvr_set_display_output_rotation(gvr_context* gvr,
+ int32_t display_output_rotation);
+
+// Gets the size of the border around the display used by the given gvr_context.
+//
+// @param gvr Pointer to the gvr_context instance.
+float gvr_get_border_size_meters(const gvr_context* gvr);
+
+// Returns whether the surface size was changed since the last call to this
+// function (it's changed with gvr_set_surface_size()).
+//
+// @param gvr Pointer to the gvr_context instance.
+// @return Whether the surface size was changed.
+bool gvr_check_surface_size_changed(gvr_context* gvr);
+
+// Returns the current surface size in pixels, or (0, 0) if the surface size
+// matches that of the active display (which is the default).
+//
+// @param gvr Pointer to the gvr_context instance.
+// @return The current surface size in pixels.
+gvr_sizei gvr_get_surface_size(const gvr_context* gvr);
+
+// Sets a handler that is called back when the back gesture is detected,
+// which is when the phone changes from landscape to portrait orientation
+// within a few seconds.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param handler The event_handler callback. May be null to clear the
+// registered event_handler.
+// @param user_data An opaque pointer to user_data which will be supplied
+// as the callback argument. The caller is responsible for ensuring the
+// validity of this data for the duration of the handler registration.
+typedef void (*event_handler)(void* user_data);
+void gvr_set_back_gesture_event_handler(gvr_context* gvr, event_handler handler,
+ void* user_data);
+
+// Internal method to pause head tracking used by GvrLayout. Disables all
+// sensors (to save power) and gets the serialized tracker state.
+//
+// @param gvr Pointer to the gvr instance for which tracking will be paused and
+// sensors disabled.
+//
+// @return Pointer to a tracker_state object containing the serialized tracker
+// state. The caller is responsible for calling destroy on the returned
+// handle.
+gvr_tracker_state* gvr_pause_tracking_get_state(gvr_context* gvr);
+
+// Internal method to resume head tracking used by GvrLayout. Re-enables all
+// sensors and sets the tracker state.
+//
+// @param gvr Pointer to the gvr instance for which tracking will be resumed.
+// serialized tracker state object.
+// @param tracker_state Pointer to a tracker_state object containing the
+// serialized tracker state object.
+void gvr_resume_tracking_set_state(
+ gvr_context* gvr, gvr_tracker_state* tracker_state);
+
+// Sets the internal flag that ignores calls to the public API's
+// gvr_pause_tracking and gvr_resume_tracking.
+// When true, the tracker is handled through GvrLayout
+// gvr_pause_tracking_private / gvr_resume_tracking_private direct calls through
+// the GvrApi instance are ignored. This is workaround to temporarily support
+// clients using GvrLayout that manually call pause/ resume tracking.
+// TODO(b/30404822) : clean this up once all existing clients move away from the
+// obsolete behavior.
+//
+// @param gvr Pointer to the gvr instance.
+// @param should_ignore Whether manual pause / resume tracker should be ignored.
+void gvr_set_ignore_manual_tracker_pause_resume(gvr_context* gvr,
+ bool should_ignore);
+
+// Creates a new tracker state object from the serialized tracker state buffer.
+//
+// @param tracker_state_buffer Pointer to buffer containing the serialized
+// tracker state.
+// @param buf_size Size of the tracker state buffer.
+//
+// @return Pointer to a tracker_state object containing the serialized tracker
+// state string. The caller is responsible for calling destroy on the returned
+// handle.
+gvr_tracker_state* gvr_tracker_state_create(const char* tracker_state_buffer,
+ size_t buf_size);
+
+// Gets the size of the buffer that is required to hold the serialized
+// gvr_tracker_state.
+//
+// @param Pointer to a gvr_tracker_state object containing the serialized
+// tracker state.
+//
+// @return Size of the buffer,
+size_t gvr_tracker_state_get_buffer_size(gvr_tracker_state* tracker_state);
+
+// Gets the buffer that holds the serialized gvr_tracker_state.
+//
+// @param Pointer to a tracker_state object containing the serialized tracker
+// state.
+//
+// @return Pointer to the buffer.
+const char* gvr_tracker_state_get_buffer(gvr_tracker_state* tracker_state);
+
+// Destroys a gvr_tracker_state instance.
+//
+// @param tracker_state Pointer to a pointer of the gvr_tracker_state instance
+// to be destroyed and nulled.
+void gvr_tracker_state_destroy(gvr_tracker_state** tracker_state);
+
+// Creates a new synchronizer instance.
+//
+// @return synchronizer Pointer to the new gvr_display_synchronizer instance.
+gvr_display_synchronizer* gvr_display_synchronizer_create();
+
+// Destroy the synchonronizer instance and null the pointer.
+//
+// @param synchronizer Pointer to a pointer to the gvr_display_synchronizer
+// instance.
+void gvr_display_synchronizer_destroy(gvr_display_synchronizer** synchronizer);
+
+// Resets the synchronizer with updated vsync timing data.
+//
+// @param synchronizer Pointer to the new gvr_display_synchronizer instance.
+// @param expected_interval_nanos The expected average time between
+// synchronization times, in nanoseconds, or 0 if unknown.
+// @param vsync_offset_nanos The duration, in nanos, such that the current sync
+// time minus the display vsync offset is the time when the physical
+// scan-out hardware begins to read data from the frame buffer.
+void gvr_display_synchronizer_reset(gvr_display_synchronizer* synchronizer,
+ int64_t expected_interval_nanos,
+ int64_t vsync_offset_nanos);
+
+// Updates the synchronizer with dispplay data for a new frame.
+//
+// @param vsync_time The new frame's vsync time.
+// @param rotation_degrees The screen rotation from sensor space to display
+// space in degrees.
+void gvr_display_synchronizer_update(gvr_display_synchronizer* synchronizer,
+ gvr_clock_time_point vsync_time,
+ int32_t rotation);
+
+// Installs the display synchronizer into a GVR context.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param synchronizer Pointer to the gvr_display_synchronizer instance, to be
+// used by the context implementation during rendering.
+void gvr_set_display_synchronizer(gvr_context* gvr,
+ gvr_display_synchronizer* synchronizer);
+
+// Sets the current error code. Overwrites any existing error code.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param error_code The error code to set.
+void gvr_set_error(gvr_context* gvr, int32_t error_code);
+
+// Called by the platform layer to to indicate the application is paused. (e.g.
+// On Android, this function is called by GvrLayout.OnPause().)
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_pause(gvr_context* gvr);
+
+// Called by the platform layer to to indicate the application has resumed.
+// (e.g. On Android, this function is called by GvrLayout.OnResume().)
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_resume(gvr_context* gvr);
+
+// Dumps additional data to logcat or disk to be included in bug reports.
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_dump_debug_data(gvr_context* gvr);
+
+// Returns true if the libgvr implementation is using the dedicated VR display
+// service, false otherwise.
+//
+// @param gvr Pointer to the current gvr_context instance.
+bool gvr_using_vr_display_service(gvr_context* gvr);
+
+// Creates a new gvr_context using the supplied tracker, only for testing.
+//
+// Note: The pose returned is *in start space*. This is *not* the same space as
+// the pose normally returned by |gvr_get_head_space_from_start_space_rotation|.
+//
+// @param tracker The test pose tracker to use.
+// @param user_data An opaque pointer to user_data which will be supplied
+// as the callback argument. The caller is responsible for ensuring the
+// validity of this data for the duration of the handler registration.
+typedef gvr_mat4f (*gvr_test_pose_tracker)(void*, gvr_clock_time_point);
+gvr_context* gvr_create_with_tracker_for_testing(gvr_test_pose_tracker tracker,
+ void* user_data);
+
+// Request resource sharing between the application's OpenGL context and the
+// scanline racing context. This must be called before gvr_initialize_gl.
+// <p>
+// This is a best effort request rather than an explicit toggle; it is a no-op
+// if the client does not enable async reprojection, or if the platform does not
+// support resource sharing.
+// <p>
+// The only OpenGL resource that we need sharing for is the framebuffer texture
+// that the app renders to, and that distortion samples from. If resource
+// sharing is disabled, then we use an EGLImage so that it can be accessed from
+// both contexts.
+// <p>
+// Also sets a callback function that is called at the end of gvr_initialize_gl,
+// while the application's OpenGL context is still active on the current thread.
+// This is used internally to notify the scanline racing renderer that the
+// application's OpenGL context has been created.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param handler Callback that gets called when the app context becomes ready.
+// @param user_data An opaque pointer to user data which will be supplied
+// as the callback argument. The caller is responsible for ensuring the
+// validity of this data for the duration of the handler registration.
+typedef void (*gvr_egl_context_listener)(void*);
+void gvr_request_context_sharing(gvr_context* gvr,
+ gvr_egl_context_listener handler,
+ void* user_data);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h
new file mode 100644
index 0000000..1df2443
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h
@@ -0,0 +1,68 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
+#define VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
+
+#include <string>
+
+// ************************************************************************** //
+// * DaydreamOS experimental Types * //
+// ************************************************************************** //
+
+// Visibility of a layer.
+typedef enum {
+ GVR_INVISIBLE = 0,
+ GVR_VISIBLE = 1,
+} gvr_visibility;
+
+// Whether to blur layers behind a layer.
+typedef enum {
+ GVR_BLUR_BEHIND_FALSE = 0,
+ GVR_BLUR_BEHIND_TRUE = 1,
+} gvr_blur_behind;
+
+// GVR external surface
+typedef struct gvr_external_surface_ gvr_external_surface;
+
+// ************************************************************************** //
+// * Daydream PlexEng experimental Types * //
+// ************************************************************************** //
+
+// Types of events that can have callbacks registered.
+// If documented, type will return a payload value when called, or will
+// otherwise be invoked with -1.f.
+// This enum has to be duplicated because there is no way to include from
+// /vr/gvr/render/performance_registry.h. Duplicate changes made here there.
+typedef enum {
+ // Will be invoked with value -1.f.
+ GVR_ON_ASYNC_REPROJECTION_FRAME_START = 0,
+ // Will be invoked with value -1.f.
+ GVR_ON_ASYNC_REPROJECTION_FRAME_STOP = 1,
+ // When invoked will be called with how late in microseconds the frame was.
+ GVR_ON_ASYNC_REPROJECTION_FRAME_DROP = 2,
+ // The number of types of performance events you can have.
+ // Also note that this value is considered invalid.
+ GVR_NUM_PERF_EVENT_CALLBACK_TYPES = 3,
+} gvr_perf_event_callback_type;
+
+// Types of VR-specific features which may or may not be supported on the
+// underlying platform.
+typedef enum {
+ // Asynchronous reprojection warps the app's rendered frame using the most
+ // recent head pose just before pushing the frame to the display.
+ GVR_ASYNC_REPROJECTION = 0,
+ // Head tracking with 6 degrees of freedom (position & rotation)
+ GVR_6DOF_HEAD_POSE = 1,
+} gvr_feature;
+
+// ************************************************************************** //
+// * GVR Analytics experimental APIs * //
+// ************************************************************************** //
+
+// Opaque struct returned by gvr_analytics_create_sample, used to transmit an
+// AnaylticsSample proto across the native layer.
+typedef struct gvr_analytics_sample_ {
+ // Serialized AnalyticsSample proto. Note that this is not a C string, meaning
+ // it is not null-terminated and may contain non-terminating nulls.
+ std::string serialized_proto;
+} gvr_analytics_sample;
+
+#endif // VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so
new file mode 100644
index 0000000..1d0ba50
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so
new file mode 100644
index 0000000..905ca64
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so
new file mode 100644
index 0000000..d62f7ca
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so
new file mode 100644
index 0000000..e342f6a
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/common_library.aar b/libs/vr/libgvr/prebuilt/lib/common_library.aar
new file mode 100644
index 0000000..13147fe
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/common_library.aar
Binary files differ
diff --git a/libs/vr/libgvr/shim_gvr.cpp b/libs/vr/libgvr/shim_gvr.cpp
new file mode 100644
index 0000000..4b074e7
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr.cpp
@@ -0,0 +1,1358 @@
+#define LOG_TAG "libgvr_shim"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl31.h>
+#include <GLES3/gl3ext.h>
+#include <algorithm>
+#include <cmath>
+
+#ifdef __ARM_NEON
+#include <arm_neon.h>
+#else
+#ifndef __FLOAT32X4T_86
+#define __FLOAT32X4T_86
+typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
+typedef struct float32x4x4_t { float32x4_t val[4]; };
+#endif
+#endif
+
+#include <cutils/log.h>
+#include <dvr/graphics.h>
+#include <dvr/performance_client_api.h>
+#include <dvr/pose_client.h>
+#include <private/dvr/buffer_hub_queue_core.h>
+#include <private/dvr/buffer_hub_queue_producer.h>
+#include <private/dvr/clock_ns.h>
+#include <private/dvr/display_client.h>
+#include <private/dvr/graphics_private.h>
+#include <private/dvr/internal_types.h>
+#include <private/dvr/numeric.h>
+#include <private/dvr/types.h>
+#include <private/dvr/video_mesh_surface_client.h>
+#include <sys/system_properties.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_ext.h>
+#include <vr/gvr/capi/include/gvr_util.h>
+#include <vr/gvr/capi/src/gvr_experimental.h>
+#include <vr/gvr/capi/src/gvr_private.h>
+
+#include <android_runtime/android_view_Surface.h>
+#include <gui/Surface.h>
+
+using android::dvr::DisplayClient;
+using android::dvr::EigenToGvrMatrix;
+using android::dvr::FieldOfView;
+using android::dvr::FovRadiansToDegrees;
+using android::dvr::GetSystemClockNs;
+using android::dvr::GvrIdentityMatrix;
+using android::dvr::GvrMatrixToPosef;
+using android::dvr::GvrToDvrFov;
+using android::dvr::GvrToEigenMatrix;
+using android::dvr::GvrToEigenRotation;
+using android::dvr::GvrTranslationMatrix;
+using android::dvr::IsEqual;
+using android::dvr::PosefToGvrMatrix;
+using android::dvr::mat3;
+using android::dvr::mat4;
+using android::dvr::Posef;
+using android::dvr::quat;
+using android::dvr::vec3;
+
+namespace {
+
+constexpr static int32_t GVR_SDK_MAJOR_VERSION = 2;
+constexpr static int32_t GVR_SDK_MINOR_VERSION = 0;
+constexpr static int32_t GVR_SDK_PATCH_VERSION = 0;
+
+// The "DaydreamOS" part has been appended to make easier to see when VrCore
+// dynamic GVR API loading is effectively working.
+static const char* kVersionString = "2.0.0 DaydreamOS";
+static const char* kViewerVendor = "Google";
+static const char* kViewerModel = "Lucid";
+
+// Experimental system property used to provide 6DoF information on 3DoF APIs.
+static const char* kForce6DofProp = "experimental.force_6dof";
+
+static constexpr int kControllerCount = 2;
+
+gvr_frame* GetFrameFromSwapChain(gvr_swap_chain* swap_chain) {
+ return reinterpret_cast<gvr_frame*>(swap_chain);
+}
+
+gvr_swap_chain* GetSwapChainForFrame(gvr_frame* frame) {
+ return reinterpret_cast<gvr_swap_chain*>(frame);
+}
+
+const gvr_swap_chain* GetSwapChainForFrame(const gvr_frame* frame) {
+ return reinterpret_cast<const gvr_swap_chain*>(frame);
+}
+
+// Returns the world to head transform as a Posef.
+Posef ToPosef(const DvrPoseAsync& pose) {
+ return Posef(
+ quat(pose.orientation[3], pose.orientation[0], pose.orientation[1],
+ pose.orientation[2]),
+ vec3(pose.translation[0], pose.translation[1], pose.translation[2]));
+}
+
+// Returns the world to head transform, with 0 position, as a gvr matrix
+gvr_mat4f Gvr6dofTo3dof(const gvr_mat4f& pose) {
+ gvr_mat4f ret = pose;
+ ret.m[0][3] = 0;
+ ret.m[1][3] = 0;
+ ret.m[2][3] = 0;
+ return ret;
+}
+
+void GvrToDvrPose(gvr_mat4f world_to_head_transform,
+ /*out*/ float32x4_t* orientation,
+ /*out */ float32x4_t* translation) {
+ Posef pose = GvrMatrixToPosef(world_to_head_transform);
+ (*orientation)[0] = pose.GetRotation().x();
+ (*orientation)[1] = pose.GetRotation().y();
+ (*orientation)[2] = pose.GetRotation().z();
+ (*orientation)[3] = pose.GetRotation().w();
+ (*translation)[0] = pose.GetPosition().x();
+ (*translation)[1] = pose.GetPosition().y();
+ (*translation)[2] = pose.GetPosition().z();
+ (*translation)[3] = 0;
+}
+
+bool MatricesAlmostEqual(const gvr_mat4f& m1, const gvr_mat4f& m2,
+ float tolerance) {
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ if (!IsEqual(m1.m[row][col], m2.m[row][col], tolerance))
+ return false;
+ }
+ }
+ return true;
+}
+
+gvr_mat4f FovToViewportTransform(const gvr_rectf& fov) {
+ // Depth range (1 1000) is chosen to match gvr impl in google3, which is
+ // chosen to match Unity integration.
+ return EigenToGvrMatrix(
+ GvrToDvrFov(fov).GetProjectionMatrix(1.f, 1000.f).inverse());
+}
+
+gvr_rectf ViewportTransformToFov(const gvr_mat4f& transform) {
+ return DvrToGvrFov(
+ FieldOfView::FromProjectionMatrix(GvrToEigenMatrix(transform).inverse()));
+}
+
+bool GetGlColorFormat(int32_t gvr_color_format,
+ /*out*/ GLenum* gl_color_format) {
+ switch (gvr_color_format) {
+ case GVR_COLOR_FORMAT_RGBA_8888:
+ *gl_color_format = GL_RGBA8;
+ break;
+ case GVR_COLOR_FORMAT_RGB_565:
+ *gl_color_format = GL_RGB565;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool GetGlDepthFormat(int32_t gvr_depth_format,
+ /*out*/ GLenum* gl_depth_format) {
+ switch (gvr_depth_format) {
+ case GVR_DEPTH_STENCIL_FORMAT_DEPTH_16:
+ *gl_depth_format = GL_DEPTH_COMPONENT16;
+ break;
+ case GVR_DEPTH_STENCIL_FORMAT_DEPTH_24:
+ *gl_depth_format = GL_DEPTH_COMPONENT24;
+ break;
+ case GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8:
+ *gl_depth_format = GL_DEPTH24_STENCIL8;
+ break;
+ case GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F:
+ *gl_depth_format = GL_DEPTH_COMPONENT32F;
+ break;
+ case GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8:
+ *gl_depth_format = GL_DEPTH32F_STENCIL8;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Returns true on success, false on failure. If the swap_chain already has a
+// DvrGraphicsContext and gvr buffer, they'll be freed first. If creation fails,
+// the DvrGraphicsContext in the swap_chain will be set to null and the
+// corresponding gvr buffer will be freed.
+bool CreateDvrGraphicsContextAndGvrBuffer(gvr_swap_chain* swap_chain) {
+ if (swap_chain->buffers_.empty()) {
+ ALOGE("Can't create a graphics context for an empty swap chain");
+ return false;
+ }
+
+ // We currently only render the first gvr buffer. Create a DvrGraphicsContext
+ // for the first buffer only.
+ gvr_buffer& buf = swap_chain->buffers_[0];
+ buf.FreeGl();
+
+ bool visible;
+ int z_order;
+ if (swap_chain->graphics_context_ != nullptr) {
+ visible = dvrGraphicsSurfaceGetVisible(swap_chain->graphics_context_);
+ z_order = dvrGraphicsSurfaceGetZOrder(swap_chain->graphics_context_);
+ dvrGraphicsContextDestroy(swap_chain->graphics_context_);
+ swap_chain->graphics_context_ = nullptr;
+ } else {
+ visible = buf.spec.initially_visible;
+ z_order = buf.spec.z_order;
+ }
+
+ int width = 0, height = 0;
+ GLuint texture_id = 0;
+ GLenum texture_target = 0;
+ DvrSurfaceParameter surface_params[] = {
+ DVR_SURFACE_PARAMETER_IN(DISABLE_DISTORTION, false),
+ DVR_SURFACE_PARAMETER_IN(CREATE_GL_CONTEXT, 0),
+ DVR_SURFACE_PARAMETER_IN(WIDTH, buf.spec.size.width),
+ DVR_SURFACE_PARAMETER_IN(HEIGHT, buf.spec.size.height),
+ DVR_SURFACE_PARAMETER_IN(BLUR_BEHIND, buf.spec.blur_behind),
+ DVR_SURFACE_PARAMETER_IN(VISIBLE, visible),
+ DVR_SURFACE_PARAMETER_IN(Z_ORDER, z_order),
+ DVR_SURFACE_PARAMETER_OUT(SURFACE_WIDTH, &width),
+ DVR_SURFACE_PARAMETER_OUT(SURFACE_HEIGHT, &height),
+ DVR_SURFACE_PARAMETER_OUT(SURFACE_TEXTURE_TARGET_TYPE, &texture_target),
+ DVR_SURFACE_PARAMETER_OUT(SURFACE_TEXTURE_TARGET_ID, &texture_id),
+ DVR_SURFACE_PARAMETER_LIST_END,
+ };
+
+ DvrGraphicsContext* graphics_context;
+ int ret = dvrGraphicsContextCreate(surface_params, &graphics_context);
+ if (ret < 0) {
+ ALOGE("dvrGraphicsContextCreate failed: %d (%s)", ret, strerror(-ret));
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return false;
+ }
+
+ // Sanity check that the size of the buffer we allocated from the system is
+ // what we expect
+ if (buf.spec.size != gvr_sizei{width, height}) {
+ ALOGE(
+ "The created surface is the wrong size."
+ " Should be %dx%d, instead got %dx%d.",
+ buf.spec.size.width, buf.spec.size.height, width, height);
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ dvrGraphicsContextDestroy(graphics_context);
+ return false;
+ }
+
+ buf = gvr_buffer(swap_chain->context, buf.spec, texture_id, texture_target);
+ if (buf.frame_buffer == 0) {
+ dvrGraphicsContextDestroy(graphics_context);
+ return false;
+ }
+
+ swap_chain->graphics_context_ = graphics_context;
+ return true;
+}
+
+bool SwapChainResizeBuffer(gvr_swap_chain* swap_chain, int buffer_index) {
+ gvr_buffer& buf = swap_chain->buffers_[buffer_index];
+ buf.FreeGl();
+ gvr_sizei orig_size = buf.spec.size;
+ buf.spec.size = buf.requested_size;
+ bool resize_successful = false;
+ if (buffer_index == 0) {
+ resize_successful = CreateDvrGraphicsContextAndGvrBuffer(swap_chain);
+ } else {
+ buf = gvr_buffer(swap_chain->context, buf.spec, 0, GL_TEXTURE_2D);
+ resize_successful = buf.frame_buffer != 0;
+ }
+
+ if (resize_successful) {
+ // The resize was successful, so clear the resize request
+ buf.requested_size = {-1, -1};
+ } else {
+ ALOGE("Failed to resize buffer. orig_size=%dx%d requested_size=%dx%d.",
+ orig_size.width, orig_size.height, buf.requested_size.width,
+ buf.requested_size.height);
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ buf.spec.size = orig_size;
+ }
+
+ return resize_successful;
+}
+
+void WaitNextFrame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+ gvr_frame_schedule* out_next_frame_schedule,
+ bool called_by_app) {
+ if (called_by_app)
+ swap_chain->wait_next_frame_called_by_app_ = true;
+
+ DvrFrameSchedule dvr_schedule;
+ int ret = dvrGraphicsWaitNextFrame(swap_chain->graphics_context_,
+ start_delay_nanos, &dvr_schedule);
+ if (ret < 0) {
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+ if (out_next_frame_schedule) {
+ out_next_frame_schedule->vsync_count = dvr_schedule.vsync_count;
+ out_next_frame_schedule->scheduled_finish.monotonic_system_time_nanos =
+ dvr_schedule.scheduled_frame_finish_ns;
+ }
+
+ DvrPoseAsync pose;
+ ret = dvrPoseGet(swap_chain->context->pose_client_, dvr_schedule.vsync_count,
+ &pose);
+ if (ret < 0) {
+ ALOGW("dvrPoseGet failed: %d", ret);
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+
+ swap_chain->context->next_frame_6dof_pose_ = PosefToGvrMatrix(ToPosef(pose));
+
+ for (int i = 0; i < kControllerCount; ++i) {
+ ret = dvrPoseGetController(swap_chain->context->pose_client_, i,
+ dvr_schedule.vsync_count, &pose);
+ if (ret == 0) {
+ // Silently fail when there are no controllers.
+ swap_chain->context->next_frame_controller_pose_[i] =
+ PosefToGvrMatrix(ToPosef(pose).Inverse());
+ }
+ }
+}
+
+bool VerifyBufferIndex(const std::string& function_name,
+ const gvr_swap_chain* swap_chain, int index) {
+ if (index > static_cast<int32_t>(swap_chain->buffers_.size())) {
+ ALOGE("%s out of range buffer index. index=%d num_buffers=%zu.",
+ function_name.c_str(), index, swap_chain->buffers_.size());
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return false;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+gvr_context* gvr_create(JNIEnv* env, jobject /* app_context */,
+ jobject /* class_loader */) {
+ std::unique_ptr<gvr_context> context(new gvr_context);
+
+ // Set cpu set to avoid default scheduling randomness.
+ dvrSetCpuPartition(0, "/application/performance");
+
+ context->jni_env_ = env;
+ context->pose_client_ = dvrPoseCreate();
+ if (!context->pose_client_) {
+ ALOGE("Failed to create pose client");
+ return nullptr;
+ }
+
+ context->display_client_ = DisplayClient::Create();
+ if (!context->display_client_) {
+ ALOGE("Failed to create display client");
+ return nullptr;
+ }
+
+ int ret =
+ context->display_client_->GetDisplayMetrics(&context->display_metrics_);
+ if (ret < 0) {
+ ALOGE("Failed to get display metrics: %d (%s)", ret, strerror(-ret));
+ return nullptr;
+ }
+
+ const float* left_fov = context->display_metrics_.left_fov_lrbt.data();
+ context->left_eye_viewport_transform_ =
+ FovToViewportTransform(FovRadiansToDegrees(
+ gvr_rectf{left_fov[0], left_fov[1], left_fov[2], left_fov[3]}));
+
+ const float* right_fov = context->display_metrics_.right_fov_lrbt.data();
+ context->right_eye_viewport_transform_ =
+ FovToViewportTransform(FovRadiansToDegrees(
+ gvr_rectf{right_fov[0], right_fov[1], right_fov[2], right_fov[3]}));
+
+ context->next_frame_6dof_pose_ = GvrIdentityMatrix();
+
+ for (int i = 0; i < kControllerCount; ++i) {
+ context->next_frame_controller_pose_[i] = GvrIdentityMatrix();
+ }
+
+ // Check the system property to force 6DoF when requested 3DoF.
+ char prop_buffer[PROP_VALUE_MAX];
+ if (__system_property_get(kForce6DofProp, prop_buffer) &&
+ (!strncasecmp("1", prop_buffer, PROP_VALUE_MAX) ||
+ !strncasecmp("true", prop_buffer, PROP_VALUE_MAX))) {
+ context->force_6dof_ = true;
+ }
+
+ return context.release();
+}
+
+gvr_version gvr_get_version() {
+ gvr_version version = {};
+ version.major = GVR_SDK_MAJOR_VERSION;
+ version.minor = GVR_SDK_MINOR_VERSION;
+ version.patch = GVR_SDK_PATCH_VERSION;
+ return version;
+}
+
+const char* gvr_get_version_string() { return kVersionString; }
+
+int32_t gvr_get_error(gvr_context* gvr) { return gvr->last_error_; }
+
+int32_t gvr_clear_error(gvr_context* gvr) {
+ int32_t last_error = gvr->last_error_;
+ gvr->last_error_ = GVR_ERROR_NONE;
+ return last_error;
+}
+
+const char* gvr_get_error_string(int32_t error_code) {
+ switch (error_code) {
+ case GVR_ERROR_NONE:
+ return "No error";
+ case GVR_ERROR_CONTROLLER_CREATE_FAILED:
+ return "Creation of GVR controller context failed";
+ case GVR_ERROR_NO_FRAME_AVAILABLE:
+ return "No frame available in swap chain";
+ case GVR_ERROR_INTERNAL:
+ return "Internal error";
+ default:
+ return "(Internal error: unknown error code)";
+ }
+}
+
+const gvr_user_prefs* gvr_get_user_prefs(gvr_context* gvr) {
+ return &gvr->user_prefs_;
+}
+
+int32_t gvr_user_prefs_get_controller_handedness(
+ const gvr_user_prefs* /* user_prefs */) {
+ return GVR_CONTROLLER_RIGHT_HANDED;
+}
+
+gvr_context_::~gvr_context_() {
+ for (gvr_swap_chain* swap_chain : swap_chains_)
+ swap_chain->context = nullptr;
+ if (pose_client_)
+ dvrPoseDestroy(pose_client_);
+}
+
+void gvr_destroy(gvr_context** gvr) {
+ if (!gvr || !(*gvr)) {
+ ALOGW("gvr_destroy: Invalid gvr_context pointer.");
+ return;
+ }
+ delete *gvr;
+ *gvr = nullptr;
+}
+
+void gvr_initialize_gl(gvr_context* /* gvr */) {}
+
+bool gvr_get_async_reprojection_enabled(const gvr_context* /* gvr */) {
+ return true;
+}
+
+void gvr_get_recommended_buffer_viewports(
+ const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list) {
+ gvr_buffer_viewport left(
+ /*buffer_index*/ 0,
+ /*uv*/ {0, .5f, 0, 1}, gvr->left_eye_viewport_transform_, GVR_LEFT_EYE,
+ GVR_EXTERNAL_SURFACE_ID_NONE, GVR_REPROJECTION_FULL);
+
+ gvr_buffer_viewport right(
+ /*buffer_index*/ 0,
+ /*uv*/ {.5f, 1, 0, 1}, gvr->right_eye_viewport_transform_, GVR_RIGHT_EYE,
+ GVR_EXTERNAL_SURFACE_ID_NONE, GVR_REPROJECTION_FULL);
+
+ viewport_list->viewports.resize(2);
+ viewport_list->viewports[0] = left;
+ viewport_list->viewports[1] = right;
+}
+
+void gvr_get_screen_buffer_viewports(const gvr_context* gvr,
+ gvr_buffer_viewport_list* viewport_list) {
+ gvr_get_recommended_buffer_viewports(gvr, viewport_list);
+}
+
+gvr_sizei gvr_get_maximum_effective_render_target_size(const gvr_context* gvr) {
+ return gvr_sizei{
+ static_cast<int32_t>(gvr->display_metrics_.distorted_width),
+ static_cast<int32_t>(gvr->display_metrics_.distorted_height)};
+}
+
+gvr_sizei gvr_get_screen_target_size(const gvr_context* gvr) {
+ // DisplayMetrics returns native_width and native_height for the display in
+ // portrait orientation, which our device is never in. Swap the width and
+ // height to account for this.
+ return gvr_sizei{
+ static_cast<int32_t>(gvr->display_metrics_.display_native_height),
+ static_cast<int32_t>(gvr->display_metrics_.display_native_width)};
+}
+
+void gvr_set_surface_size(gvr_context* gvr,
+ gvr_sizei /* surface_size_pixels */) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_set_surface_size not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+void gvr_distort_to_screen(
+ gvr_context* gvr, int32_t /* texture_id */,
+ const gvr_buffer_viewport_list* /* viewport_list */,
+ gvr_mat4f /* head_space_from_start_space */,
+ gvr_clock_time_point /* target_presentation_time */) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_distort_to_screen not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Viewports and viewport lists
+/////////////////////////////////////////////////////////////////////////////
+
+bool gvr_buffer_viewport::operator==(const gvr_buffer_viewport_& other) const {
+ return buffer_index == other.buffer_index && uv == other.uv &&
+ eye == other.eye && external_surface_id == other.external_surface_id &&
+ reprojection == other.reprojection &&
+ MatricesAlmostEqual(transform, other.transform, 1e-5f);
+}
+
+gvr_buffer_viewport* gvr_buffer_viewport_create(gvr_context* /* gvr */) {
+ return new gvr_buffer_viewport;
+}
+
+void gvr_buffer_viewport_destroy(gvr_buffer_viewport** viewport) {
+ if (viewport) {
+ delete *viewport;
+ *viewport = nullptr;
+ }
+}
+
+gvr_rectf gvr_buffer_viewport_get_source_uv(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->uv;
+}
+
+void gvr_buffer_viewport_set_source_uv(gvr_buffer_viewport* viewport,
+ gvr_rectf uv) {
+ viewport->uv = uv;
+}
+
+gvr_rectf gvr_buffer_viewport_get_source_fov(
+ const gvr_buffer_viewport* viewport) {
+ return ViewportTransformToFov(viewport->transform);
+}
+
+void gvr_buffer_viewport_set_source_fov(gvr_buffer_viewport* viewport,
+ gvr_rectf fov) {
+ viewport->transform = FovToViewportTransform(fov);
+}
+
+gvr_mat4f gvr_buffer_viewport_get_transform(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->transform;
+}
+
+void gvr_buffer_viewport_set_transform(gvr_buffer_viewport* viewport,
+ gvr_mat4f transform) {
+ viewport->transform = transform;
+}
+
+int32_t gvr_buffer_viewport_get_target_eye(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->eye;
+}
+
+void gvr_buffer_viewport_set_target_eye(gvr_buffer_viewport* viewport,
+ int32_t index) {
+ viewport->eye = index;
+}
+
+int32_t gvr_buffer_viewport_get_source_buffer_index(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->buffer_index;
+}
+
+void gvr_buffer_viewport_set_source_buffer_index(gvr_buffer_viewport* viewport,
+ int32_t buffer_index) {
+ viewport->buffer_index = buffer_index;
+}
+
+int32_t gvr_buffer_viewport_get_external_surface_id(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->external_surface_id;
+}
+
+void gvr_buffer_viewport_set_external_surface_id(gvr_buffer_viewport* viewport,
+ int32_t external_surface_id) {
+ viewport->external_surface_id = external_surface_id;
+}
+
+int32_t gvr_buffer_viewport_get_reprojection(
+ const gvr_buffer_viewport* viewport) {
+ return viewport->reprojection;
+}
+
+void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport,
+ int32_t reprojection) {
+ viewport->reprojection = static_cast<gvr_reprojection>(reprojection);
+}
+
+bool gvr_buffer_viewport_equal(const gvr_buffer_viewport* a,
+ const gvr_buffer_viewport* b) {
+ return *a == *b;
+}
+
+gvr_buffer_viewport_list* gvr_buffer_viewport_list_create(
+ const gvr_context* /* gvr */) {
+ return new gvr_buffer_viewport_list;
+}
+
+void gvr_buffer_viewport_list_destroy(
+ gvr_buffer_viewport_list** viewport_list) {
+ if (!viewport_list || !(*viewport_list)) {
+ ALOGW("gvr_buffer_viewport_list_destroy: Invalid list pointer.");
+ return;
+ }
+ delete *viewport_list;
+ *viewport_list = nullptr;
+}
+
+size_t gvr_buffer_viewport_list_get_size(
+ const gvr_buffer_viewport_list* viewport_list) {
+ return viewport_list->viewports.size();
+}
+
+void gvr_buffer_viewport_list_get_item(
+ const gvr_buffer_viewport_list* viewport_list, size_t index,
+ gvr_buffer_viewport* viewport) {
+ *viewport = viewport_list->viewports[index];
+}
+
+void gvr_buffer_viewport_list_set_item(gvr_buffer_viewport_list* viewport_list,
+ size_t index,
+ const gvr_buffer_viewport* viewport) {
+ if (index < viewport_list->viewports.size())
+ viewport_list->viewports[index] = *viewport;
+ else
+ viewport_list->viewports.push_back(*viewport);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Swapchains and frames
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_buffer_spec* gvr_buffer_spec_create(gvr_context* /* gvr */) {
+ return new gvr_buffer_spec;
+}
+
+void gvr_buffer_spec_destroy(gvr_buffer_spec** spec) {
+ if (spec) {
+ delete *spec;
+ *spec = nullptr;
+ }
+}
+
+gvr_sizei gvr_buffer_spec_get_size(const gvr_buffer_spec* spec) {
+ return spec->size;
+}
+
+void gvr_buffer_spec_set_size(gvr_buffer_spec* spec, gvr_sizei size) {
+ spec->size = size;
+}
+
+int32_t gvr_buffer_spec_get_samples(const gvr_buffer_spec* spec) {
+ return spec->msaa_samples;
+}
+
+void gvr_buffer_spec_set_samples(gvr_buffer_spec* spec, int32_t num_samples) {
+ spec->msaa_samples = num_samples;
+}
+
+void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec,
+ int32_t color_format) {
+ spec->color_format = color_format;
+}
+
+void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec,
+ int32_t depth_stencil_format) {
+ spec->depth_stencil_format = depth_stencil_format;
+}
+
+void gvr_buffer_spec_set_z_order(gvr_buffer_spec* spec, int z_order) {
+ spec->z_order = z_order;
+}
+
+void gvr_buffer_spec_set_visibility(gvr_buffer_spec* spec,
+ int32_t visibility) {
+ spec->initially_visible = (visibility != GVR_INVISIBLE);
+}
+
+void gvr_buffer_spec_set_blur_behind(gvr_buffer_spec* spec,
+ int32_t blur_behind) {
+ spec->blur_behind = (blur_behind != GVR_BLUR_BEHIND_FALSE);
+}
+
+void gvr_buffer::SetDefaults() {
+ spec = gvr_buffer_spec();
+ frame_buffer = 0;
+ color_render_buffer = 0;
+ depth_stencil_render_buffer = 0;
+ requested_size = {-1, -1};
+}
+
+gvr_buffer::gvr_buffer() { SetDefaults(); }
+
+gvr_buffer::gvr_buffer(gvr_context* gvr, const gvr_buffer_spec& spec_in,
+ GLuint texture_id, GLenum texture_target) {
+ SetDefaults();
+ spec = spec_in;
+
+ glGetError(); // Clear error state
+ glGenFramebuffers(1, &frame_buffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);
+
+ if (texture_id == 0) {
+ GLenum gl_color_format;
+ if (!GetGlColorFormat(spec.color_format, &gl_color_format)) {
+ ALOGE("Unknown color format: %d", spec.color_format);
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ FreeGl();
+ return;
+ }
+
+ glGenRenderbuffers(1, &color_render_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, color_render_buffer);
+ if (spec.msaa_samples < 2) {
+ glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format, spec.size.width,
+ spec.size.height);
+ } else {
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, spec.msaa_samples,
+ gl_color_format, spec.size.width,
+ spec.size.height);
+ }
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, color_render_buffer);
+ } else {
+ if (spec.msaa_samples < 2) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texture_target, texture_id, 0);
+ } else {
+ glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texture_target, texture_id, 0,
+ spec.msaa_samples);
+ }
+ }
+
+ if (spec.depth_stencil_format != GVR_DEPTH_STENCIL_FORMAT_NONE) {
+ GLenum gl_depth_format;
+ if (!GetGlDepthFormat(spec.depth_stencil_format, &gl_depth_format)) {
+ ALOGE("Unknown depth/stencil format: %d", spec.depth_stencil_format);
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ FreeGl();
+ return;
+ }
+
+ glGenRenderbuffers(1, &depth_stencil_render_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_render_buffer);
+ if (spec.msaa_samples < 2) {
+ glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format, spec.size.width,
+ spec.size.height);
+ } else {
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, spec.msaa_samples,
+ gl_depth_format, spec.size.width,
+ spec.size.height);
+ }
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, depth_stencil_render_buffer);
+ }
+
+ GLenum gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ ALOGE("GL error after creating framebuffer: %d", gl_error);
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ FreeGl();
+ return;
+ }
+
+ GLenum framebuffer_complete_result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (framebuffer_complete_result != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Framebuffer setup failed. glCheckFramebufferStatus returned %d",
+ framebuffer_complete_result);
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ FreeGl();
+ return;
+ }
+}
+
+void gvr_buffer::FreeGl() {
+ if (frame_buffer != 0) {
+ glDeleteFramebuffers(1, &frame_buffer);
+ frame_buffer = 0;
+ }
+ if (color_render_buffer != 0) {
+ glDeleteRenderbuffers(1, &color_render_buffer);
+ color_render_buffer = 0;
+ }
+ if (depth_stencil_render_buffer != 0) {
+ glDeleteRenderbuffers(1, &depth_stencil_render_buffer);
+ depth_stencil_render_buffer = 0;
+ }
+}
+
+gvr_buffer::~gvr_buffer() { FreeGl(); }
+
+gvr_buffer::gvr_buffer(gvr_buffer&& other) {
+ spec = other.spec;
+ frame_buffer = other.frame_buffer;
+ color_render_buffer = other.color_render_buffer;
+ depth_stencil_render_buffer = other.depth_stencil_render_buffer;
+ requested_size = other.requested_size;
+ other.SetDefaults();
+}
+
+gvr_buffer& gvr_buffer::operator=(gvr_buffer&& other) {
+ if (this == &other)
+ return *this;
+ spec = other.spec;
+ frame_buffer = other.frame_buffer;
+ color_render_buffer = other.color_render_buffer;
+ depth_stencil_render_buffer = other.depth_stencil_render_buffer;
+ requested_size = other.requested_size;
+ other.SetDefaults();
+ return *this;
+}
+
+gvr_swap_chain* gvr_swap_chain_create(gvr_context* gvr,
+ const gvr_buffer_spec** buffers,
+ int32_t count) {
+ if (count == 0) {
+ ALOGE("At least one buffer must be requested");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return nullptr;
+ }
+
+ // We only support one buffer, but it's common for gvr apps to use more than
+ // one. Print an error to the log if the app requests more than one buffer,
+ // but continue on. We'll only render the first buffer in that case.
+ if (count > 1) {
+ ALOGE(
+ "Only one buffer is supported but the app requested %d."
+ " Only the first buffer will be rendered.",
+ count);
+ }
+
+ std::unique_ptr<gvr_swap_chain> swap_chain(new gvr_swap_chain(gvr));
+
+ // The first buffer gets a DvrGraphicsContext, which contains the surface we
+ // pass to displayd for rendering.
+ swap_chain->buffers_.push_back(gvr_buffer());
+ swap_chain->buffers_.back().spec = *buffers[0];
+ if (!CreateDvrGraphicsContextAndGvrBuffer(swap_chain.get()))
+ return nullptr;
+
+ // The rest of the buffers, which we don't render for now, get color render
+ // buffers.
+ for (int i = 1; i < count; ++i) {
+ swap_chain->buffers_.push_back(
+ gvr_buffer(gvr, *buffers[i], 0, GL_TEXTURE_2D));
+ if (swap_chain->buffers_.back().frame_buffer == 0)
+ return nullptr;
+ }
+
+ gvr->swap_chains_.push_back(swap_chain.get());
+ return swap_chain.release();
+}
+
+gvr_swap_chain_::~gvr_swap_chain_() {
+ if (context) {
+ auto iter = std::find(std::begin(context->swap_chains_),
+ std::end(context->swap_chains_), this);
+ if (iter != context->swap_chains_.end())
+ context->swap_chains_.erase(iter);
+ }
+ buffers_.clear();
+ if (graphics_context_ != nullptr)
+ dvrGraphicsContextDestroy(graphics_context_);
+}
+
+void gvr_swap_chain_destroy(gvr_swap_chain** swap_chain) {
+ if (!swap_chain || !(*swap_chain)) {
+ ALOGW("gvr_swap_chain_destroy: Invalid swap chain pointer.");
+ return;
+ }
+ delete *swap_chain;
+ *swap_chain = nullptr;
+}
+
+int32_t gvr_swap_chain_get_buffer_count(const gvr_swap_chain* swap_chain) {
+ return swap_chain ? static_cast<int32_t>(swap_chain->buffers_.size()) : 0;
+}
+
+gvr_sizei gvr_swap_chain_get_buffer_size(gvr_swap_chain* swap_chain,
+ int32_t index) {
+ if (!VerifyBufferIndex("gvr_swap_chain_get_buffer_size", swap_chain, index))
+ return gvr_sizei{0, 0};
+
+ gvr_buffer& buf = swap_chain->buffers_[index];
+ if (buf.requested_size != gvr_sizei{-1, -1})
+ return buf.requested_size;
+ else
+ return buf.spec.size;
+}
+
+void gvr_swap_chain_resize_buffer(gvr_swap_chain* swap_chain, int32_t index,
+ gvr_sizei size) {
+ if (!VerifyBufferIndex("gvr_swap_chain_resize_buffer", swap_chain, index))
+ return;
+
+ gvr_buffer& buf = swap_chain->buffers_[index];
+ if (size != buf.spec.size)
+ buf.requested_size = size;
+ else
+ buf.requested_size = {-1, -1};
+}
+
+gvr_frame* gvr_swap_chain_acquire_frame(gvr_swap_chain* swap_chain) {
+ if (!swap_chain)
+ return nullptr;
+
+ if (swap_chain->frame_acquired_) {
+ gvr_set_error(swap_chain->context, GVR_ERROR_NO_FRAME_AVAILABLE);
+ return nullptr;
+ }
+
+ // Resize buffers if necessary
+ for (int i = 0; i < static_cast<int>(swap_chain->buffers_.size()); ++i) {
+ gvr_buffer& buf = swap_chain->buffers_[i];
+ if (buf.requested_size != gvr_sizei{-1, -1}) {
+ if (!SwapChainResizeBuffer(swap_chain, i))
+ return nullptr;
+ }
+ }
+
+ // Only call gvr_wait_next_frame() if the app didn't call it already.
+ if (!swap_chain->wait_next_frame_called_by_app_)
+ WaitNextFrame(swap_chain, 0, nullptr, /*called_by_app*/ false);
+
+ int ret = dvrBeginRenderFrame(swap_chain->graphics_context_);
+ if (ret < 0) {
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return nullptr;
+ }
+
+ swap_chain->frame_acquired_ = true;
+ return GetFrameFromSwapChain(swap_chain);
+}
+
+void gvr_frame_bind_buffer(gvr_frame* frame, int32_t index) {
+ gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+ if (!VerifyBufferIndex("gvr_frame_bind_buffer", swap_chain, index))
+ return;
+ glBindFramebuffer(GL_FRAMEBUFFER, swap_chain->buffers_[index].frame_buffer);
+}
+
+void gvr_frame_unbind(gvr_frame* /* frame */) {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+gvr_sizei gvr_frame_get_buffer_size(const gvr_frame* frame, int32_t index) {
+ const gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+ if (!VerifyBufferIndex("gvr_frame_get_buffer_size", swap_chain, index))
+ return gvr_sizei{0, 0};
+ return swap_chain->buffers_[index].spec.size;
+}
+
+int32_t gvr_frame_get_framebuffer_object(const gvr_frame* frame,
+ int32_t index) {
+ const gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+ if (!VerifyBufferIndex("gvr_frame_get_framebuffer_object", swap_chain, index))
+ return 0;
+ return swap_chain->buffers_[index].frame_buffer;
+}
+
+void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list,
+ gvr_mat4f head_space_from_start_space) {
+ if (!frame)
+ return;
+
+ gvr_swap_chain* swap_chain = GetSwapChainForFrame(*frame);
+
+ if (!swap_chain->frame_acquired_) {
+ ALOGE("Frame was never acquired before being submitted");
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+
+ *frame = nullptr;
+ swap_chain->frame_acquired_ = false;
+
+ // Currently, support for arbitrary buffer viewport configs is very limited.
+ // We assume that the first two viewports have to be the recommended color
+ // buffer viewports, followed by pairs of external external buffer viewports
+ // for video rendering.
+ gvr_buffer_viewport_list supported_viewports;
+ gvr_get_recommended_buffer_viewports(swap_chain->context,
+ &supported_viewports);
+ for (size_t i = 0; i < supported_viewports.viewports.size(); ++i) {
+ if (i >= list->viewports.size() ||
+ supported_viewports.viewports[i] != list->viewports[i]) {
+ ALOGE("Custom viewport configurations are not fully supported.");
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+ }
+
+ for (size_t i = supported_viewports.viewports.size();
+ i < list->viewports.size(); ++i) {
+ int32_t external_surface_id = list->viewports[i].external_surface_id;
+ // Ignore additional custom buffer viewport for now, only those buffer
+ // viewports backed by external surfaces are supported.
+ // TODO(b/31442094, b/31771861, 28954457) Add full GVR buffer viewport
+ // support.
+ if (external_surface_id == GVR_EXTERNAL_SURFACE_ID_NONE)
+ continue;
+
+ auto surface_it = swap_chain->external_surfaces_.find(external_surface_id);
+ if (surface_it == swap_chain->external_surfaces_.end()) {
+ ALOGE("Cannot find external_surface by id: %d.", external_surface_id);
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+
+ // Pass the transfrom matrix of video mesh to displayd.
+ dvrGraphicsVideoMeshSurfacePresent(
+ swap_chain->graphics_context_, surface_it->second->video_surface,
+ list->viewports[i].eye,
+ GvrToEigenMatrix(list->viewports[i].transform).data());
+ }
+
+ float32x4_t pose_orientation, pose_translation;
+ GvrToDvrPose(head_space_from_start_space, &pose_orientation,
+ &pose_translation);
+ int ret = dvrSetEdsPose(swap_chain->graphics_context_, pose_orientation,
+ pose_translation);
+ if (ret < 0)
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+
+ ret = dvrPresent(swap_chain->graphics_context_);
+ if (ret < 0) {
+ gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+ return;
+ }
+}
+
+void gvr_bind_default_framebuffer(gvr_context* /* gvr */) {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head tracking
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_clock_time_point gvr_get_time_point_now() {
+ return gvr_clock_time_point{GetSystemClockNs()};
+}
+
+gvr_mat4f gvr_get_head_space_from_start_space_rotation(
+ const gvr_context* gvr, const gvr_clock_time_point /* time */) {
+ // TODO(steventhomas): Implement prediction according to the supplied time
+ // value.
+ return gvr->force_6dof_ ? gvr->next_frame_6dof_pose_
+ : Gvr6dofTo3dof(gvr->next_frame_6dof_pose_);
+}
+
+gvr_mat4f gvr_apply_neck_model(const gvr_context* /* gvr */,
+ gvr_mat4f head_space_from_start_space_rotation,
+ float /* factor */) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_apply_neck_model not implemented.");
+ return head_space_from_start_space_rotation;
+}
+
+// This is used to turn off sensors to save power. Not relevant for our all in
+// one device.
+void gvr_pause_tracking(gvr_context* /* gvr */) {}
+
+// This is used to turn on sensors. Not relevant for our all in one device.
+void gvr_resume_tracking(gvr_context* /* gvr */) {}
+
+void gvr_reset_tracking(gvr_context* gvr) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_reset_tracking not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+void gvr_recenter_tracking(gvr_context* gvr) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_recenter_tracking not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head mounted display
+/////////////////////////////////////////////////////////////////////////////
+
+bool gvr_set_default_viewer_profile(gvr_context* gvr,
+ const char* /* viewer_profile_uri */) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_set_default_viewer_profile not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return false;
+}
+
+void gvr_refresh_viewer_profile(gvr_context* /* gvr */) {}
+
+const char* gvr_get_viewer_vendor(const gvr_context* /* gvr */) {
+ return kViewerVendor;
+}
+
+const char* gvr_get_viewer_model(const gvr_context* /* gvr */) {
+ return kViewerModel;
+}
+
+int32_t gvr_get_viewer_type(const gvr_context* /* gvr */) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ // In this case, we will probably need to define a new viewer type that
+ // has 6DoF support.
+ return GVR_VIEWER_TYPE_DAYDREAM;
+}
+
+gvr_mat4f gvr_get_eye_from_head_matrix(const gvr_context* gvr,
+ const int32_t eye) {
+ float eye_mult = eye == GVR_LEFT_EYE ? 1 : -1;
+ return GvrTranslationMatrix(
+ .5f * eye_mult * gvr->display_metrics_.inter_lens_distance_m, 0, 0);
+}
+
+gvr_recti gvr_get_window_bounds(const gvr_context* gvr) {
+ // Our app windows are always full screen
+ gvr_sizei screen_size = gvr_get_screen_target_size(gvr);
+ return gvr_recti{0, screen_size.width, 0, screen_size.height};
+}
+
+void gvr_compute_distorted_point(const gvr_context* /* gvr */,
+ const int32_t /* eye */,
+ const gvr_vec2f /* uv_in */,
+ gvr_vec2f /* uv_out */[3]) {
+ // TODO(leandrogracia): this needs to be properly implemented.
+ ALOGE("gvr_compute_distorted_point not implemented.");
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GVR API extension (from gvr_ext.h)
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_frame_schedule* gvr_frame_schedule_create() {
+ return new gvr_frame_schedule;
+}
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** schedule) {
+ if (!schedule || !(*schedule)) {
+ ALOGW("gvr_frame_schedule_destroy: Invalid frame schedule pointer.");
+ return;
+ }
+ delete *schedule;
+ *schedule = nullptr;
+}
+
+uint32_t gvr_frame_schedule_get_vsync_count(gvr_frame_schedule* schedule) {
+ return schedule->vsync_count;
+}
+
+gvr_clock_time_point gvr_frame_schedule_get_scheduled_finish(
+ gvr_frame_schedule* schedule) {
+ return schedule->scheduled_finish;
+}
+
+void gvr_wait_next_frame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+ gvr_frame_schedule* out_next_frame_schedule) {
+ WaitNextFrame(swap_chain, start_delay_nanos, out_next_frame_schedule,
+ /*called_by_app*/ true);
+}
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+ uint32_t vsync_count) {
+ DvrPoseAsync pose;
+ int ret = dvrPoseGet(gvr->pose_client_, vsync_count, &pose);
+ if (ret < 0) {
+ ALOGW("dvrPoseGet failed: %d", ret);
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return GvrIdentityMatrix();
+ }
+
+ return PosefToGvrMatrix(ToPosef(pose));
+}
+
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+ gvr_context* gvr, const gvr_clock_time_point /* time */) {
+ // TODO(leandrogracia): implement prediction based on the provided time.
+ // We need to do the same for the 3dof version too.
+ return gvr->next_frame_6dof_pose_;
+}
+
+void gvr_swap_chain_set_z_order(const gvr_swap_chain* swap_chain, int z_order) {
+ dvrGraphicsSurfaceSetZOrder(swap_chain->graphics_context_, z_order);
+}
+
+bool gvr_experimental_is_feature_supported(const gvr_context* /* gvr */,
+ int32_t feature) {
+ switch (feature) {
+ case GVR_ASYNC_REPROJECTION:
+ case GVR_6DOF_HEAD_POSE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool gvr_experimental_register_perf_event_callback(
+ gvr_context* gvr, int* /* out_handle */, void* /* user_data */,
+ void (* /* event_callback */)(void*, int, float)) {
+ ALOGE("gvr_experimental_register_perf_event_callback not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return false;
+}
+
+bool gvr_experimental_unregister_perf_event_callback(gvr_context* gvr,
+ int /* handle */) {
+ ALOGE("gvr_experimental_unregister_perf_event_callback not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return false;
+}
+
+const gvr_analytics* gvr_get_analytics(gvr_context* gvr) {
+ ALOGE("gvr_get_analytics not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+ return nullptr;
+}
+
+const gvr_analytics_sample* gvr_analytics_create_sample(
+ const gvr_analytics* analytics) {
+ ALOGE("gvr_analytics_create_sample not implemented.");
+ return nullptr;
+}
+
+const char* gvr_analytics_sample_get_buffer(const gvr_analytics_sample* sample) {
+ ALOGE("gvr_analytics_sample_get_buffer not implemented.");
+ return nullptr;
+}
+
+size_t gvr_analytics_sample_get_buffer_length(
+ const gvr_analytics_sample* sample) {
+ ALOGE("gvr_analytics_sample_get_buffer_length not implemented.");
+ return 0;
+}
+
+void gvr_analytics_destroy_sample(const gvr_analytics_sample** sample) {
+ ALOGE("gvr_analytics_destroy_sample not implemented.");
+}
+
+bool gvr_user_prefs_get_performance_monitoring_enabled(
+ const gvr_user_prefs* /* user_prefs */) {
+ ALOGW("gvr_user_prefs_get_performance_monitoring_enabled not implemented.");
+ return false;
+}
+
+void gvr_enable_context_sharing(gvr_context* gvr,
+ gvr_egl_context_listener /* handler */,
+ void* /* user_data */) {
+ ALOGW("gvr_enable_context_sharing not implemented.");
+ gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+gvr_mat4f gvr_get_start_space_from_controller_space_pose(
+ gvr_context* gvr, int controller_id,
+ const gvr_clock_time_point /* time */) {
+ if (controller_id < 0 || controller_id >= kControllerCount) {
+ return GvrIdentityMatrix();
+ }
+
+ // TODO(leandrogracia): implement prediction based on the provided time.
+ // We need to do the same for the 3dof version too.
+ return gvr->next_frame_controller_pose_[controller_id];
+}
+
+gvr_external_surface* gvr_external_surface_create(gvr_context* context) {
+ // A |gvr_external_surface| is bound to a DVR Graphics context at the
+ // moment, which means we need an |gvr_swap_chain| created prior to the call
+ // of |gvr_external_surface_create|. Check whether the current GVR context
+ // has |gvr_swap_chain| created. Fail if there is no swap chain created
+ // already.
+ if (context->swap_chains_.empty()) {
+ ALOGE("gvr_external_surface_create: No swapchain has been created yet.");
+ return nullptr;
+ }
+
+ // In case there are multiple swap chains in the context, the first is
+ // implicitly chosen. Actually, this should not happen as current scanline
+ // racing based GVR implementation only supports single swap chain per GVR
+ // context.
+ if (context->swap_chains_.size() > 1) {
+ ALOGW("gvr_external_surface_create: Multiple swap chains detected. "
+ "Choosing the first one but this may yield unexpected results.");
+ }
+ gvr_swap_chain* swap_chain = context->swap_chains_[0];
+ DvrVideoMeshSurface* video_surface = dvrGraphicsVideoMeshSurfaceCreate(
+ swap_chain->graphics_context_);
+
+ if (video_surface == nullptr) {
+ ALOGE("gvr_external_surface_create: Failed to create video mesh surface.");
+ return nullptr;
+ }
+
+ gvr_external_surface* surface = new gvr_external_surface;
+ surface->id = swap_chain->next_external_surface_id_++;
+ surface->swap_chain = swap_chain;
+ surface->video_surface = video_surface;
+
+ // Insert the surface into a lookup table in swap_chain. This will be
+ // needed to by the external_surface_id in |gvr_buffer_viewport|.
+ swap_chain->external_surfaces_.insert({surface->id, surface});
+ return surface;
+}
+
+void gvr_external_surface_destroy(gvr_external_surface** surface) {
+ if (!surface || !(*surface)) {
+ ALOGW("gvr_external_surface_destroy: Invalid external surface pointer.");
+ return;
+ }
+
+ (*surface)->swap_chain->external_surfaces_.erase((*surface)->id);
+ if ((*surface)->video_surface != nullptr) {
+ dvrGraphicsVideoMeshSurfaceDestroy((*surface)->video_surface);
+ }
+
+ delete *surface;
+ *surface = nullptr;
+}
+
+void* gvr_external_surface_get_surface(const gvr_external_surface* surface) {
+ CHECK(surface->swap_chain != nullptr &&
+ surface->swap_chain->context != nullptr &&
+ surface->swap_chain->context->jni_env_ != nullptr)
+ << "gvr_external_surface_get_surface: Surface must be constructed within "
+ << "a JNIEnv. Check |gvr_create| call.";
+
+ CHECK(surface->video_surface != nullptr)
+ << "gvr_external_surface_get_surface: Invalid surface.";
+
+ std::shared_ptr<android::dvr::ProducerQueue> producer_queue =
+ surface->video_surface->client->GetProducerQueue();
+ std::shared_ptr<android::dvr::BufferHubQueueCore> core =
+ android::dvr::BufferHubQueueCore::Create(producer_queue);
+
+ return android_view_Surface_createFromIGraphicBufferProducer(
+ surface->swap_chain->context->jni_env_,
+ new android::dvr::BufferHubQueueProducer(core));
+}
+
+int32_t gvr_external_surface_get_surface_id(
+ const gvr_external_surface* surface) {
+ return surface->id;
+}
diff --git a/libs/vr/libgvr/shim_gvr_controller.cpp b/libs/vr/libgvr/shim_gvr_controller.cpp
new file mode 100644
index 0000000..54bc270
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr_controller.cpp
@@ -0,0 +1,168 @@
+#define LOG_TAG "libgvr_controller_shim"
+
+#include <cutils/log.h>
+#include <vr/gvr/capi/include/gvr_controller.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+gvr_controller_context* gvr_controller_create_and_init(int32_t options,
+ gvr_context* context) {
+ ALOGE("gvr_controller_create_and_init not implemented.");
+ return nullptr;
+}
+
+gvr_controller_context* gvr_controller_create_and_init_android(
+ JNIEnv* env, jobject android_context, jobject class_loader, int32_t options,
+ gvr_context* context) {
+ ALOGE("gvr_controller_create_and_init_android not implemented.");
+ return nullptr;
+}
+
+void gvr_controller_destroy(gvr_controller_context** api) {
+ ALOGE("gvr_controller_destroy not implemented.");
+}
+
+gvr_controller_state* gvr_controller_state_create() {
+ ALOGE("gvr_controller_state_create not implemented.");
+ return nullptr;
+}
+
+void gvr_controller_state_destroy(gvr_controller_state** state) {
+ ALOGE("gvr_controller_state_destroy not implemented.");
+}
+
+void gvr_controller_state_update(gvr_controller_context* api, int32_t flags,
+ gvr_controller_state* out_state) {
+ ALOGE("gvr_controller_state_update not implemented.");
+}
+
+int64_t gvr_controller_state_get_last_button_timestamp(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_last_button_timestamp not implemented.");
+ return 0;
+}
+
+bool gvr_controller_state_get_button_state(const gvr_controller_state* state,
+ int32_t button) {
+ ALOGE("gvr_controller_state_get_button_state not implemented.");
+ return false;
+}
+
+bool gvr_controller_state_get_button_down(const gvr_controller_state* state,
+ int32_t button) {
+ ALOGE("gvr_controller_state_get_button_down not implemented.");
+ return false;
+}
+
+bool gvr_controller_state_get_button_up(const gvr_controller_state* state,
+ int32_t button) {
+ ALOGE("gvr_controller_state_get_button_up not implemented.");
+ return false;
+}
+
+bool gvr_controller_state_is_touching(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_is_touching not implemented.");
+ return false;
+}
+
+gvr_vec2f gvr_controller_state_get_touch_pos(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_touch_pos not implemented.");
+ return {0.0f, 0.0f};
+}
+
+bool gvr_controller_state_get_touch_down(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_touch_down not implemented.");
+ return false;
+}
+
+bool gvr_controller_state_get_touch_up(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_touch_up not implemented.");
+ return false;
+}
+
+int64_t gvr_controller_state_get_last_touch_timestamp(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_last_touch_timestamp not implemented.");
+ return 0;
+}
+
+gvr_quatf gvr_controller_state_get_orientation(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_orientation not implemented.");
+ return {0.0f, 0.0f, 0.0f, 0.0f};
+}
+
+int64_t gvr_controller_state_get_last_orientation_timestamp(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_last_orientation_timestamp not implemented.");
+ return 0;
+}
+
+const char* gvr_controller_api_status_to_string(int32_t status) {
+ ALOGE("gvr_controller_api_status_to_string not implemented.");
+ return nullptr;
+}
+
+const char* gvr_controller_connection_state_to_string(int32_t state) {
+ ALOGE("gvr_controller_connection_state_to_string not implemented.");
+ return nullptr;
+}
+
+const char* gvr_controller_button_to_string(int32_t button) {
+ ALOGE("gvr_controller_button_to_string not implemented.");
+ return nullptr;
+}
+
+int32_t gvr_controller_get_default_options() {
+ ALOGE("gvr_controller_get_default_options not implemented.");
+ return 0;
+}
+
+void gvr_controller_pause(gvr_controller_context* api) {
+ ALOGE("gvr_controller_pause not implemented.");
+}
+
+void gvr_controller_resume(gvr_controller_context* api) {
+ ALOGE("gvr_controller_resume not implemented.");
+}
+
+int32_t gvr_controller_state_get_api_status(const gvr_controller_state* state) {
+ return GVR_CONTROLLER_API_OK;
+}
+
+int32_t gvr_controller_state_get_connection_state(
+ const gvr_controller_state* state) {
+ return GVR_CONTROLLER_CONNECTED;
+}
+
+gvr_vec3f gvr_controller_state_get_gyro(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_gyro not implemented.");
+ return {0.0, 0.0, 0.0};
+}
+
+gvr_vec3f gvr_controller_state_get_accel(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_accel not implemented.");
+ return {0.0, 0.0, 0.0};
+}
+
+int64_t gvr_controller_state_get_last_gyro_timestamp(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_last_gyro_timestamp not implemented.");
+ return 0;
+}
+
+int64_t gvr_controller_state_get_last_accel_timestamp(
+ const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_last_accel_timestamp not implemented.");
+ return 0;
+}
+
+bool gvr_controller_state_get_recentered(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_recentered not implemented.");
+ return false;
+}
+
+bool gvr_controller_state_get_recentering(const gvr_controller_state* state) {
+ ALOGE("gvr_controller_state_get_recentering not implemented.");
+ return false;
+}
diff --git a/libs/vr/libgvr/shim_gvr_private.cpp b/libs/vr/libgvr/shim_gvr_private.cpp
new file mode 100644
index 0000000..6ab6971
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr_private.cpp
@@ -0,0 +1,234 @@
+#define LOG_TAG "libgvr_shim_private"
+
+#include <cutils/log.h>
+#include <private/dvr/display_rpc.h>
+#include <private/dvr/internal_types.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/src/gvr_private.h>
+
+#include <pdx/rpc/remote_method.h>
+#include "deviceparams/CardboardDevice.nolite.pb.h"
+
+bool gvr_set_async_reprojection_enabled(gvr_context* /* gvr */,
+ bool /* enabled */) {
+ return true;
+}
+
+void gvr_on_surface_created_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_render_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_on_pause_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_update_surface_reprojection_thread(
+ gvr_context* /* gvr */, int32_t /* surface_id */, int32_t /* texture_id */,
+ gvr_clock_time_point /* timestamp */, gvr_mat4f /* surface_transform */) {
+ ALOGE("gvr_update_surface_reprojection_thread not implemented");
+}
+
+void gvr_remove_all_surfaces_reprojection_thread(gvr_context* /* gvr */) {
+ ALOGE("gvr_remove_all_surfaces_reprojection_thread not implemented");
+}
+
+void gvr_reconnect_sensors(gvr_context* /* gvr */) {
+ ALOGE("gvr_reconnect_sensors not implemented");
+}
+
+bool gvr_set_viewer_params(gvr_context* gvr,
+ const void* serialized_viewer_params,
+ size_t serialized_viewer_params_size_bytes) {
+ std::string serialized_device_params_string(
+ reinterpret_cast<const char*>(serialized_viewer_params),
+ serialized_viewer_params_size_bytes);
+ std::unique_ptr<proto::DeviceParams> device_params(new proto::DeviceParams);
+ if (!device_params->ParseFromString(serialized_device_params_string)) {
+ LOG(ERROR) << "Invalid serialized Cardboard DeviceParams";
+ return false;
+ }
+
+ android::dvr::ViewerParams viewer_params;
+
+ viewer_params.screen_to_lens_distance =
+ device_params->screen_to_lens_distance();
+ viewer_params.inter_lens_distance = device_params->inter_lens_distance();
+ for (int i = 0; i < device_params->left_eye_field_of_view_angles_size();
+ ++i) {
+ viewer_params.left_eye_field_of_view_angles.push_back(
+ device_params->left_eye_field_of_view_angles(i));
+ }
+
+ viewer_params.vertical_alignment =
+ static_cast<android::dvr::ViewerParams::VerticalAlignmentType>(
+ device_params->vertical_alignment());
+ viewer_params.tray_to_lens_distance = device_params->tray_to_lens_distance();
+
+ // TODO(hendrikw) Leave the g and b coefficients empty until we support
+ // chromatic aberration correction.
+ for (int i = 0; i < device_params->distortion_coefficients_size(); ++i) {
+ viewer_params.distortion_coefficients_r.push_back(
+ device_params->distortion_coefficients(i));
+ }
+
+ viewer_params.screen_center_to_lens_distance =
+ viewer_params.inter_lens_distance / 2.0;
+ if (device_params->has_internal()) {
+ for (int i = 0; i < device_params->internal().eye_orientations_size();
+ ++i) {
+ viewer_params.eye_orientations.push_back(
+ static_cast<android::dvr::ViewerParams::EyeOrientation>(
+ device_params->internal().eye_orientations(i)));
+ }
+
+ if (device_params->internal().has_screen_center_to_lens_distance())
+ viewer_params.screen_center_to_lens_distance =
+ device_params->internal().screen_center_to_lens_distance();
+ }
+
+ if (device_params->has_daydream_internal()) {
+ viewer_params.daydream_internal.version =
+ device_params->daydream_internal().version();
+ for (int i = 0;
+ i < device_params->daydream_internal().alignment_markers_size(); ++i) {
+ viewer_params.daydream_internal.alignment_markers.push_back(
+ {device_params->daydream_internal().alignment_markers(i).horizontal(),
+ device_params->daydream_internal().alignment_markers(i).vertical()});
+ }
+ }
+
+ gvr->display_client_->SetViewerParams(viewer_params);
+ return true;
+}
+
+void gvr_set_lens_offset(gvr_context* /* gvr */, gvr_vec2f /* offset */) {
+ ALOGE("gvr_set_lens_offset not implemented");
+}
+
+void gvr_set_display_metrics(gvr_context* /* gvr */,
+ gvr_sizei /* size_pixels */,
+ gvr_vec2f /* meters_per_pixel */,
+ float /* border_size_meters */) {
+ ALOGE("gvr_set_display_metrics not implemented");
+}
+
+void gvr_set_display_output_rotation(gvr_context* /* gvr */,
+ int /* display_output_rotation */) {
+ ALOGE("gvr_set_display_output_rotation not implemented");
+}
+
+float gvr_get_border_size_meters(const gvr_context* /* gvr */) {
+ ALOGE("gvr_get_border_size_meters not implemented");
+ return 0.0f;
+}
+
+bool gvr_check_surface_size_changed(gvr_context* /* gvr */) { return false; }
+
+gvr_sizei gvr_get_surface_size(const gvr_context* /* gvr */) {
+ ALOGE("gvr_get_surface_size not implemented");
+ return {0, 0};
+}
+
+void gvr_set_back_gesture_event_handler(gvr_context* /* gvr */,
+ event_handler /* handler */,
+ void* /* user_data */) {
+ ALOGE("gvr_set_back_gesture_event_handler not implemented");
+}
+
+gvr_tracker_state* gvr_pause_tracking_get_state(gvr_context* /* gvr */) {
+ ALOGE("gvr_pause_tracking_get_state not implemented");
+ return nullptr;
+}
+
+void gvr_resume_tracking_set_state(gvr_context* /* gvr */,
+ gvr_tracker_state* /* tracker_state */) {
+ ALOGE("gvr_resume_tracking_set_state not implemented");
+}
+
+void gvr_set_ignore_manual_tracker_pause_resume(gvr_context* /* gvr */,
+ bool /* should_ignore */) {
+ ALOGE("gvr_set_ignore_manual_tracker_pause_resume not implemented");
+}
+
+gvr_tracker_state* gvr_tracker_state_create(
+ const char* /* tracker_state_buffer */, size_t /* buf_size */) {
+ ALOGE("gvr_tracker_state_create not implemented");
+ return nullptr;
+}
+
+size_t gvr_tracker_state_get_buffer_size(
+ gvr_tracker_state* /* tracker_state */) {
+ ALOGE("gvr_tracker_state_get_buffer_size not implemented");
+ return 0;
+}
+
+const char* gvr_tracker_state_get_buffer(
+ gvr_tracker_state* /* tracker_state */) {
+ ALOGE("gvr_tracker_state_get_buffer not implemented");
+ return nullptr;
+}
+
+void gvr_tracker_state_destroy(gvr_tracker_state** /* tracker_state */) {
+ ALOGE("gvr_tracker_state_destroy not implemented");
+}
+
+gvr_display_synchronizer* gvr_display_synchronizer_create() {
+ // We don't actually support (or need) any of the synchronizer functionality,
+ // but if we return null here the gvr setup code in the app fails. Instead
+ // return a dummy object that does nothing, which allows gvr apps to work.
+ return new gvr_display_synchronizer;
+}
+
+void gvr_display_synchronizer_destroy(gvr_display_synchronizer** synchronizer) {
+ if (synchronizer) {
+ delete *synchronizer;
+ *synchronizer = nullptr;
+ }
+}
+
+void gvr_display_synchronizer_reset(
+ gvr_display_synchronizer* /* synchronizer */,
+ int64_t /* expected_interval_nanos */, int64_t /* vsync_offset_nanos */) {}
+
+void gvr_display_synchronizer_update(
+ gvr_display_synchronizer* /* synchronizer */,
+ gvr_clock_time_point /* vsync_time */, int32_t /* rotation */) {}
+
+void gvr_set_display_synchronizer(
+ gvr_context* /* gvr */, gvr_display_synchronizer* /* synchronizer */) {}
+
+void gvr_set_error(gvr_context* gvr, int32_t error_code) {
+ if (gvr->last_error_ != GVR_ERROR_NONE) {
+ ALOGW("Overwriting existing error code: %d (%s)", gvr->last_error_,
+ gvr_get_error_string(gvr->last_error_));
+ }
+ gvr->last_error_ = error_code;
+}
+
+void gvr_pause(gvr_context* gvr) {
+ if (gvr == nullptr) {
+ ALOGW("gvr_pause called with a null gvr_context. This is a bug.");
+ return;
+ }
+ for (gvr_swap_chain* swap_chain : gvr->swap_chains_) {
+ if (swap_chain->graphics_context_)
+ dvrGraphicsSurfaceSetVisible(swap_chain->graphics_context_, 0);
+ }
+}
+
+void gvr_resume(gvr_context* gvr) {
+ if (gvr == nullptr) {
+ ALOGW("gvr_resume called with a null gvr_context. This is a bug.");
+ return;
+ }
+ for (gvr_swap_chain* swap_chain : gvr->swap_chains_) {
+ if (swap_chain->graphics_context_)
+ dvrGraphicsSurfaceSetVisible(swap_chain->graphics_context_, 1);
+ }
+}
+
+void gvr_dump_debug_data(gvr_context* /* gvr */) {}
+
+bool gvr_using_vr_display_service(gvr_context* /* gvr */) { return true; }
+
+void gvr_request_context_sharing(gvr_context* /* gvr */,
+ gvr_egl_context_listener /* handler */,
+ void* /* user_data */) {}