main.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include <VrApi.h>
  2. #include <VrApi_Helpers.h>
  3. #include <EGL/egl.h>
  4. #include <EGL/eglext.h>
  5. #include <GLES3/gl3.h>
  6. #include <GLES3/gl3ext.h>
  7. #include <android/log.h>
  8. #include <android_native_app_glue.h>
  9. #include <string.h>
  10. static struct {
  11. bool initialized;
  12. uint32_t width;
  13. uint32_t height;
  14. uint32_t msaa;
  15. GLuint framebuffers[3];
  16. GLuint textures[3];
  17. GLuint depthBuffer;
  18. } gl;
  19. typedef void (GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);
  20. // matrices holds the two view matrices followed by two projection matrices (column major)
  21. // index is the current swapchain index (used to select texture, framebuffer, etc.)
  22. static void render(float* matrices[4], uint32_t index) {
  23. if (!gl.initialized) {
  24. gl.initialized = true;
  25. gl.msaa = 4;
  26. PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) eglGetProcAddress( "glFramebufferTextureMultisampleMultiviewOVR" );
  27. glGenTextures(1, &gl.depthBuffer);
  28. glBindTexture(GL_TEXTURE_2D_ARRAY, gl.depthBuffer);
  29. glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH24_STENCIL8, gl.width, gl.height, 2);
  30. glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
  31. glGenFramebuffers(3, gl.framebuffers);
  32. for (uint32_t i = 0; i < 3; i++) {
  33. glBindFramebuffer(GL_FRAMEBUFFER, gl.framebuffers[i]);
  34. glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, gl.depthBuffer, 0, gl.msaa, 0, 2);
  35. glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.textures[i], 0, gl.msaa, 0, 2);
  36. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  37. }
  38. }
  39. glBindFramebuffer(GL_FRAMEBUFFER, gl.framebuffers[index]);
  40. glClearBufferfv(GL_COLOR, 0, (float[]) { .05f, 0.f, .22f, 1.f });
  41. glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.f, 0);
  42. //
  43. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  44. }
  45. static struct {
  46. EGLDisplay display;
  47. EGLContext context;
  48. EGLSurface surface;
  49. ovrJava java;
  50. ovrMobile* session;
  51. ovrTextureSwapChain* swapchain;
  52. uint32_t frameIndex;
  53. ANativeWindow* window;
  54. bool resumed;
  55. } state;
  56. static void onAppCmd(struct android_app* app, int32_t cmd) {
  57. switch (cmd) {
  58. case APP_CMD_RESUME: state.resumed = true; break;
  59. case APP_CMD_PAUSE: state.resumed = false; break;
  60. case APP_CMD_INIT_WINDOW: state.window = app->window; break;
  61. case APP_CMD_TERM_WINDOW: state.window = NULL; break;
  62. default: break;
  63. }
  64. if (!state.session && state.window && state.resumed) {
  65. ovrModeParms parms = vrapi_DefaultModeParms(&state.java);
  66. parms.Flags &= ~VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN;
  67. parms.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW;
  68. parms.Flags |= VRAPI_MODE_FLAG_FRONT_BUFFER_SRGB;
  69. parms.Display = (size_t) state.display;
  70. parms.WindowSurface = (size_t) state.window;
  71. parms.ShareContext = (size_t) state.context;
  72. state.session = vrapi_EnterVrMode(&parms);
  73. state.frameIndex = 0;
  74. __android_log_print(ANDROID_LOG_DEBUG, "APP", "in vr mode");
  75. } else if (state.session && (!state.window || !state.resumed)) {
  76. vrapi_LeaveVrMode(state.session);
  77. state.session = NULL;
  78. __android_log_print(ANDROID_LOG_DEBUG, "APP", "out of vr mode");
  79. }
  80. }
  81. void android_main(struct android_app* app) {
  82. app->onAppCmd = onAppCmd;
  83. // EGL //
  84. if (!(state.display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) || !eglInitialize(state.display, NULL, NULL)) {
  85. __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize display");
  86. return;
  87. }
  88. EGLConfig configs[1024];
  89. EGLint configCount;
  90. if (!eglGetConfigs(state.display, configs, sizeof(configs) / sizeof(configs[0]), &configCount)) {
  91. __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not get EGL configs");
  92. return;
  93. }
  94. 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 };
  95. const EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
  96. const EGLint surfaceAttributes[] = { EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE };
  97. EGLConfig config = 0;
  98. for (EGLint i = 0; i < configCount && !config; i++) {
  99. EGLint value, mask;
  100. EGLint rmask = EGL_OPENGL_ES3_BIT_KHR;
  101. EGLint smask = EGL_PBUFFER_BIT | EGL_WINDOW_BIT;
  102. if (!eglGetConfigAttrib(state.display, configs[i], EGL_RENDERABLE_TYPE, &value) || (value & rmask) != rmask) { continue; }
  103. if (!eglGetConfigAttrib(state.display, configs[i], EGL_SURFACE_TYPE, &value) || (value & smask) != smask) { continue; }
  104. for (int a = 0; a < sizeof(attributes) / sizeof(attributes[0]); a += 2) {
  105. if (attributes[a] == EGL_NONE) { config = configs[i]; break; }
  106. if (!eglGetConfigAttrib(state.display, configs[i], attributes[a], &value) || value != attributes[a + 1]) { break; }
  107. }
  108. }
  109. state.context = eglCreateContext(state.display, config, EGL_NO_CONTEXT, contextAttributes);
  110. state.surface = eglCreatePbufferSurface(state.display, config, surfaceAttributes);
  111. if (!state.context || !state.surface) {
  112. __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize context");
  113. return;
  114. }
  115. eglMakeCurrent(state.display, state.surface, state.surface, state.context);
  116. // VRAPI //
  117. state.java.Vm = app->activity->vm;
  118. state.java.ActivityObject = app->activity->clazz;
  119. (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &state.java.Env, NULL);
  120. ovrInitParms parms = vrapi_DefaultInitParms(&state.java);
  121. parms.GraphicsAPI = VRAPI_GRAPHICS_API_OPENGL_ES_3;
  122. if (vrapi_Initialize(&parms) != VRAPI_INITIALIZE_SUCCESS) {
  123. __android_log_print(ANDROID_LOG_DEBUG, "APP", "Could not initialize vrapi");
  124. }
  125. uint32_t width = vrapi_GetSystemPropertyInt(&state.java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH);
  126. uint32_t height = vrapi_GetSystemPropertyInt(&state.java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT);
  127. state.swapchain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D_ARRAY, GL_SRGB8_ALPHA8, width, height, 1, 3);
  128. gl.width = width;
  129. gl.height = height;
  130. for (uint32_t i = 0; i < 3; i++) {
  131. gl.textures[i] = vrapi_GetTextureSwapChainHandle(state.swapchain, i);
  132. }
  133. // LOOP //
  134. while (!app->destroyRequested) {
  135. int events;
  136. struct android_poll_source* source;
  137. while (ALooper_pollAll(state.session ? 0 : -1, NULL, &events, (void**) &source) >= 0) {
  138. if (source) {
  139. source->process(app, source);
  140. }
  141. }
  142. if (!state.session) {
  143. continue;
  144. }
  145. double t = vrapi_GetPredictedDisplayTime(state.session, state.frameIndex);
  146. ovrTracking2 tracking = vrapi_GetPredictedTracking2(state.session, t);
  147. ovrMatrix4f ms[] = {
  148. [0] = ovrMatrix4f_Transpose(&tracking.Eye[0].ViewMatrix),
  149. [1] = ovrMatrix4f_Transpose(&tracking.Eye[1].ViewMatrix),
  150. [2] = ovrMatrix4f_Transpose(&tracking.Eye[0].ProjectionMatrix),
  151. [3] = ovrMatrix4f_Transpose(&tracking.Eye[1].ProjectionMatrix)
  152. };
  153. float* matrices[4] = { &ms[0].M[0][0], &ms[1].M[0][0], &ms[2].M[0][0], &ms[3].M[0][0] };
  154. render(matrices, state.frameIndex % 3);
  155. ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
  156. layer.HeadPose = tracking.HeadPose;
  157. layer.Textures[0].ColorSwapChain = state.swapchain;
  158. layer.Textures[0].SwapChainIndex = state.frameIndex % 3;
  159. layer.Textures[0].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[0].ProjectionMatrix);
  160. memcpy(&layer.Textures[1], &layer.Textures[0], sizeof(layer.Textures[0]));
  161. layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
  162. vrapi_SubmitFrame2(state.session, &(ovrSubmitFrameDescription2) {
  163. .FrameIndex = state.frameIndex++,
  164. .DisplayTime = t,
  165. .LayerCount = 1,
  166. .Layers = (const ovrLayerHeader2*[1]) { &layer.Header }
  167. });
  168. }
  169. // BYE //
  170. vrapi_DestroyTextureSwapChain(state.swapchain);
  171. vrapi_Shutdown();
  172. (*app->activity->vm)->DetachCurrentThread(app->activity->vm);
  173. eglMakeCurrent(state.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  174. eglDestroySurface(state.display, state.surface);
  175. eglDestroyContext(state.display, state.context);
  176. eglTerminate(state.display);
  177. }