| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- #include <VrApi.h>
- #include <VrApi_Helpers.h>
- #include <EGL/egl.h>
- #include <EGL/eglext.h>
- #include <GLES3/gl3.h>
- #include <GLES3/gl3ext.h>
- #include <android/log.h>
- #include <android_native_app_glue.h>
- #include <string.h>
- static struct {
- bool initialized;
- uint32_t width;
- uint32_t height;
- uint32_t msaa;
- GLuint framebuffers[3];
- GLuint textures[3];
- GLuint depthBuffer;
- } gl;
- typedef void (GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);
- // matrices holds the two view matrices followed by two projection matrices (column major)
- // index is the current swapchain index (used to select texture, framebuffer, etc.)
- static void render(float* matrices[4], uint32_t index) {
- if (!gl.initialized) {
- gl.initialized = true;
- gl.msaa = 4;
- PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) eglGetProcAddress( "glFramebufferTextureMultisampleMultiviewOVR" );
- glGenTextures(1, &gl.depthBuffer);
- glBindTexture(GL_TEXTURE_2D_ARRAY, gl.depthBuffer);
- glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH24_STENCIL8, gl.width, gl.height, 2);
- glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
- glGenFramebuffers(3, gl.framebuffers);
- for (uint32_t i = 0; i < 3; i++) {
- glBindFramebuffer(GL_FRAMEBUFFER, gl.framebuffers[i]);
- glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, gl.depthBuffer, 0, gl.msaa, 0, 2);
- glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.textures[i], 0, gl.msaa, 0, 2);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- }
- glBindFramebuffer(GL_FRAMEBUFFER, gl.framebuffers[index]);
- glClearBufferfv(GL_COLOR, 0, (float[]) { .05f, 0.f, .22f, 1.f });
- glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.f, 0);
- //
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- static struct {
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- ovrJava java;
- ovrMobile* session;
- ovrTextureSwapChain* swapchain;
- uint32_t frameIndex;
- ANativeWindow* window;
- bool resumed;
- } state;
- static void onAppCmd(struct android_app* app, int32_t cmd) {
- switch (cmd) {
- case APP_CMD_RESUME: state.resumed = true; break;
- case APP_CMD_PAUSE: state.resumed = false; break;
- case APP_CMD_INIT_WINDOW: state.window = app->window; break;
- case APP_CMD_TERM_WINDOW: state.window = NULL; break;
- default: break;
- }
- if (!state.session && state.window && state.resumed) {
- ovrModeParms parms = vrapi_DefaultModeParms(&state.java);
- parms.Flags &= ~VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN;
- parms.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW;
- parms.Flags |= VRAPI_MODE_FLAG_FRONT_BUFFER_SRGB;
- parms.Display = (size_t) state.display;
- parms.WindowSurface = (size_t) state.window;
- parms.ShareContext = (size_t) state.context;
- state.session = vrapi_EnterVrMode(&parms);
- state.frameIndex = 0;
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "in vr mode");
- } else if (state.session && (!state.window || !state.resumed)) {
- vrapi_LeaveVrMode(state.session);
- state.session = NULL;
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "out of vr mode");
- }
- }
- void android_main(struct android_app* app) {
- app->onAppCmd = onAppCmd;
- // EGL //
- if (!(state.display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) || !eglInitialize(state.display, NULL, NULL)) {
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize display");
- return;
- }
- EGLConfig configs[1024];
- EGLint configCount;
- if (!eglGetConfigs(state.display, configs, sizeof(configs) / sizeof(configs[0]), &configCount)) {
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not get EGL configs");
- return;
- }
- const EGLint attributes[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLES, 0, EGL_NONE };
- const EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
- const EGLint surfaceAttributes[] = { EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE };
- EGLConfig config = 0;
- for (EGLint i = 0; i < configCount && !config; i++) {
- EGLint value, mask;
- EGLint rmask = EGL_OPENGL_ES3_BIT_KHR;
- EGLint smask = EGL_PBUFFER_BIT | EGL_WINDOW_BIT;
- if (!eglGetConfigAttrib(state.display, configs[i], EGL_RENDERABLE_TYPE, &value) || (value & rmask) != rmask) { continue; }
- if (!eglGetConfigAttrib(state.display, configs[i], EGL_SURFACE_TYPE, &value) || (value & smask) != smask) { continue; }
- for (int a = 0; a < sizeof(attributes) / sizeof(attributes[0]); a += 2) {
- if (attributes[a] == EGL_NONE) { config = configs[i]; break; }
- if (!eglGetConfigAttrib(state.display, configs[i], attributes[a], &value) || value != attributes[a + 1]) { break; }
- }
- }
- state.context = eglCreateContext(state.display, config, EGL_NO_CONTEXT, contextAttributes);
- state.surface = eglCreatePbufferSurface(state.display, config, surfaceAttributes);
- if (!state.context || !state.surface) {
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize context");
- return;
- }
- eglMakeCurrent(state.display, state.surface, state.surface, state.context);
- // VRAPI //
- state.java.Vm = app->activity->vm;
- state.java.ActivityObject = app->activity->clazz;
- (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &state.java.Env, NULL);
- ovrInitParms parms = vrapi_DefaultInitParms(&state.java);
- parms.GraphicsAPI = VRAPI_GRAPHICS_API_OPENGL_ES_3;
- if (vrapi_Initialize(&parms) != VRAPI_INITIALIZE_SUCCESS) {
- __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize vrapi");
- }
- uint32_t width = vrapi_GetSystemPropertyInt(&state.java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH);
- uint32_t height = vrapi_GetSystemPropertyInt(&state.java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT);
- state.swapchain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D_ARRAY, GL_SRGB8_ALPHA8, width, height, 1, 3);
- gl.width = width;
- gl.height = height;
- for (uint32_t i = 0; i < 3; i++) {
- gl.textures[i] = vrapi_GetTextureSwapChainHandle(state.swapchain, i);
- }
- // LOOP //
- while (!app->destroyRequested) {
- int events;
- struct android_poll_source* source;
- while (ALooper_pollAll(state.session ? 0 : -1, NULL, &events, (void**) &source) >= 0) {
- if (source) {
- source->process(app, source);
- }
- }
- if (!state.session) {
- continue;
- }
- double t = vrapi_GetPredictedDisplayTime(state.session, state.frameIndex);
- ovrTracking2 tracking = vrapi_GetPredictedTracking2(state.session, t);
- ovrMatrix4f ms[] = {
- [0] = ovrMatrix4f_Transpose(&tracking.Eye[0].ViewMatrix),
- [1] = ovrMatrix4f_Transpose(&tracking.Eye[1].ViewMatrix),
- [2] = ovrMatrix4f_Transpose(&tracking.Eye[0].ProjectionMatrix),
- [3] = ovrMatrix4f_Transpose(&tracking.Eye[1].ProjectionMatrix)
- };
- float* matrices[4] = { &ms[0].M[0][0], &ms[1].M[0][0], &ms[2].M[0][0], &ms[3].M[0][0] };
- render(matrices, state.frameIndex % 3);
- ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
- layer.HeadPose = tracking.HeadPose;
- layer.Textures[0].ColorSwapChain = state.swapchain;
- layer.Textures[0].SwapChainIndex = state.frameIndex % 3;
- layer.Textures[0].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[0].ProjectionMatrix);
- memcpy(&layer.Textures[1], &layer.Textures[0], sizeof(layer.Textures[0]));
- layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
- vrapi_SubmitFrame2(state.session, &(ovrSubmitFrameDescription2) {
- .FrameIndex = state.frameIndex++,
- .DisplayTime = t,
- .LayerCount = 1,
- .Layers = (const ovrLayerHeader2*[1]) { &layer.Header }
- });
- }
- // BYE //
- vrapi_DestroyTextureSwapChain(state.swapchain);
- vrapi_Shutdown();
- (*app->activity->vm)->DetachCurrentThread(app->activity->vm);
- eglMakeCurrent(state.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(state.display, state.surface);
- eglDestroyContext(state.display, state.context);
- eglTerminate(state.display);
- }
|