This repository has been archived by the owner on Jul 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from MozillaReality/android_egl
Implement native EGL render loop
- Loading branch information
Showing
12 changed files
with
517 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
app/src/common/nativeactivity/org/mozilla/vrbrowser/VRBrowserActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.vrbrowser; | ||
|
||
import android.app.NativeActivity; | ||
import android.content.Intent; | ||
import android.net.Uri; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
import android.graphics.SurfaceTexture; | ||
import android.view.Surface; | ||
import android.view.SurfaceView; | ||
|
||
import org.mozilla.gecko.GeckoSession; | ||
|
||
public class VRBrowserActivity extends NativeActivity { | ||
static String LOGTAG = "VRBrowser"; | ||
static final String DEFAULT_URL = "https://mozvr.com"; | ||
// Used to load the 'native-lib' library on application startup. | ||
static { | ||
System.loadLibrary("native-lib"); | ||
} | ||
|
||
private SurfaceView mSurfaceView; | ||
private static GeckoSession mSession; | ||
private static Surface mBrowserSurface; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
Log.e(LOGTAG,"in onCreate"); | ||
super.onCreate(savedInstanceState); | ||
if (mSession == null) { | ||
mSession = new GeckoSession(); | ||
} | ||
getWindow().takeSurface(null); | ||
SurfaceView surfaceView = new SurfaceView(this); | ||
surfaceView.getHolder().addCallback(this); | ||
|
||
setContentView(surfaceView); | ||
loadFromIntent(getIntent()); | ||
} | ||
|
||
@Override | ||
protected void onNewIntent(final Intent intent) { | ||
Log.e(LOGTAG,"In onNewIntent"); | ||
super.onNewIntent(intent); | ||
setIntent(intent); | ||
final String action = intent.getAction(); | ||
if (Intent.ACTION_VIEW.equals(action)) { | ||
if (intent.getData() != null) { | ||
loadFromIntent(intent); | ||
} | ||
} | ||
} | ||
|
||
private void loadFromIntent(final Intent intent) { | ||
final Uri uri = intent.getData(); | ||
Log.e(LOGTAG, "Load URI from intent: " + (uri != null ? uri.toString() : DEFAULT_URL)); | ||
String uriValue = (uri != null ? uri.toString() : DEFAULT_URL); | ||
mSession.loadUri(uriValue); | ||
} | ||
|
||
@Override | ||
protected void onPause() { | ||
Log.e(LOGTAG, "In onPause"); | ||
super.onPause(); | ||
} | ||
|
||
@Override | ||
protected void onResume() { | ||
Log.e(LOGTAG, "in onResume"); | ||
super.onResume(); | ||
} | ||
|
||
@Override | ||
protected void onDestroy() { | ||
super.onDestroy(); | ||
} | ||
|
||
private void setSurfaceTexture(String aName, final SurfaceTexture aTexture, final int aWidth, final int aHeight) { | ||
runOnUiThread(new Runnable() { | ||
public void run() { | ||
createBrowser(aTexture, aWidth, aHeight); | ||
} | ||
}); | ||
} | ||
|
||
private void createBrowser(SurfaceTexture aTexture, int aWidth, int aHeight) { | ||
if (aTexture != null) { | ||
Log.e(LOGTAG,"In createBrowser"); | ||
aTexture.setDefaultBufferSize(aWidth, aHeight); | ||
mBrowserSurface = new Surface(aTexture); | ||
mSession.acquireDisplay().surfaceChanged(mBrowserSurface, aWidth, aHeight); | ||
mSession.openWindow(this); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "BrowserEGLContext.h" | ||
#include "vrb/Logger.h" | ||
#include <EGL/eglext.h> | ||
#include <android_native_app_glue.h> | ||
|
||
BrowserEGLContext::BrowserEGLContext() | ||
: mMajorVersion(0), mMinorVersion(0), mDisplay(0), mConfig(0), mSurface(0), mContext(0), | ||
mNativeWindow(nullptr) { | ||
} | ||
|
||
BrowserEGLContextPtr | ||
BrowserEGLContext::Create() { | ||
return std::make_shared<BrowserEGLContext>(); | ||
} | ||
|
||
bool | ||
BrowserEGLContext::Initialize(ANativeWindow *aNativeWindow) { | ||
mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); | ||
if (eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion) == EGL_FALSE) { | ||
VRB_LOG("eglInitialize() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
|
||
// Do NOT use eglChooseConfig, because the Android EGL code pushes in multisample | ||
// flags in eglChooseConfig if the user has selected the "force 4x MSAA" option in | ||
// settings, and that is completely wasted for the time warp renderer. | ||
const int MAX_CONFIGS = 1024; | ||
|
||
EGLConfig configs[MAX_CONFIGS]; | ||
EGLint numConfigs = 0; | ||
if (eglGetConfigs(mDisplay, configs, MAX_CONFIGS, &numConfigs) == EGL_FALSE) { | ||
VRB_LOG("eglGetConfigs() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
|
||
const EGLint configAttribs[] = { | ||
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 | ||
}; | ||
|
||
for (int i = 0; i < numConfigs; ++i) { | ||
EGLint value = 0; | ||
|
||
eglGetConfigAttrib(mDisplay, configs[i], EGL_RENDERABLE_TYPE, &value); | ||
|
||
// Check EGL Client Version | ||
if ((value & EGL_OPENGL_ES3_BIT_KHR) != EGL_OPENGL_ES3_BIT_KHR) { | ||
continue; | ||
} | ||
|
||
// EGL_WINDOW_BIT is required so it can share textures with the window context. | ||
eglGetConfigAttrib(mDisplay, configs[i], EGL_SURFACE_TYPE, &value); | ||
if ((value & (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)) != (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)) { | ||
continue; | ||
} | ||
|
||
int j = 0; | ||
for (; configAttribs[j] != EGL_NONE; j += 2) { | ||
eglGetConfigAttrib(mDisplay, configs[i], configAttribs[j], &value); | ||
if (value != configAttribs[j + 1]) { | ||
break; | ||
} | ||
} | ||
if (configAttribs[j] == EGL_NONE) { | ||
mConfig = configs[i]; | ||
break; | ||
} | ||
} | ||
|
||
if (mConfig == 0) { | ||
VRB_LOG("eglChooseConfig() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
|
||
|
||
//Reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. | ||
mNativeWindow = aNativeWindow; | ||
EGLint format; | ||
eglGetConfigAttrib(mDisplay, mConfig, EGL_NATIVE_VISUAL_ID, &format); | ||
ANativeWindow_setBuffersGeometry(aNativeWindow, 0, 0, format); | ||
|
||
EGLint contextAttribs[] = { | ||
EGL_CONTEXT_CLIENT_VERSION, 3, | ||
EGL_NONE | ||
}; | ||
|
||
mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs); | ||
if (mContext == EGL_NO_CONTEXT) { | ||
VRB_LOG("eglCreateContext() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
|
||
mSurface = eglCreateWindowSurface(mDisplay, mConfig, mNativeWindow, nullptr); | ||
|
||
if (mSurface == EGL_NO_SURFACE) { | ||
VRB_LOG("eglCreateWindowSurface() failed: %s", ErrorToString(eglGetError())); | ||
eglDestroyContext(mDisplay, mContext); | ||
mContext = EGL_NO_CONTEXT; | ||
return false; | ||
} | ||
|
||
if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE) { | ||
VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); | ||
eglDestroySurface(mDisplay, mSurface); | ||
eglDestroyContext(mDisplay, mContext); | ||
mContext = EGL_NO_CONTEXT; | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void | ||
BrowserEGLContext::Destroy() { | ||
if (mDisplay) { | ||
if (eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) { | ||
VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
} | ||
if (mContext != EGL_NO_CONTEXT) { | ||
if (eglDestroyContext(mDisplay, mContext) == EGL_FALSE) { | ||
VRB_LOG("eglDestroyContext() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
mContext = EGL_NO_CONTEXT; | ||
} | ||
if (mSurface != EGL_NO_SURFACE) { | ||
if (eglDestroySurface(mDisplay, mSurface) == EGL_FALSE) { | ||
VRB_LOG("eglDestroySurface() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
mSurface = EGL_NO_SURFACE; | ||
} | ||
if (mDisplay) { | ||
if (eglTerminate(mDisplay) == EGL_FALSE) { | ||
VRB_LOG("eglTerminate() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
mDisplay = 0; | ||
} | ||
} | ||
|
||
|
||
// Handle Android Life Cycle. | ||
// Android has started the activity or sent it to foreground. | ||
// Create a new surface and attach it to the recreated ANativeWindow. | ||
// Restore the EGLContext. | ||
void | ||
BrowserEGLContext::SurfaceChanged(ANativeWindow *aWindow) { | ||
if (mSurface != EGL_NO_SURFACE) { | ||
return; | ||
} | ||
mNativeWindow = aWindow; | ||
mSurface = eglCreateWindowSurface(mDisplay, mConfig, aWindow, nullptr); | ||
if (mSurface == EGL_NO_SURFACE) { | ||
VRB_LOG("eglCreateWindowSurface() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
} | ||
|
||
// Handle Android Life Cycle. | ||
// Android has stopped the activity or sent it to background. | ||
// Release the surface attached to the destroyed ANativeWindow. | ||
// The EGLContext is not destroyed so it can be restored later. | ||
void | ||
BrowserEGLContext::SurfaceDestroyed() { | ||
if (mSurface != EGL_NO_SURFACE) { | ||
if (eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) { | ||
VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
if (eglDestroySurface(mDisplay, mSurface) == EGL_FALSE) { | ||
VRB_LOG("eglDestroySurface() failed: %s", ErrorToString(eglGetError())); | ||
} | ||
mSurface = EGL_NO_SURFACE; | ||
} | ||
} | ||
|
||
bool | ||
BrowserEGLContext::IsSurfaceReady() const { | ||
return mSurface != EGL_NO_SURFACE; | ||
} | ||
|
||
bool | ||
BrowserEGLContext::MakeCurrent() { | ||
if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE) { | ||
VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
bool | ||
BrowserEGLContext::SwapBuffers() { | ||
if (eglSwapBuffers(mDisplay, mSurface) == EGL_FALSE) { | ||
VRB_LOG("SwapBuffers() failed: %s", ErrorToString(eglGetError())); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
const char * | ||
BrowserEGLContext::ErrorToString(EGLint error) { | ||
switch (error) { | ||
case EGL_SUCCESS: | ||
return "EGL_SUCCESS"; | ||
case EGL_NOT_INITIALIZED: | ||
return "EGL_NOT_INITIALIZED"; | ||
case EGL_BAD_ACCESS: | ||
return "EGL_BAD_ACCESS"; | ||
case EGL_BAD_ALLOC: | ||
return "EGL_BAD_ALLOC"; | ||
case EGL_BAD_ATTRIBUTE: | ||
return "EGL_BAD_ATTRIBUTE"; | ||
case EGL_BAD_CONTEXT: | ||
return "EGL_BAD_CONTEXT"; | ||
case EGL_BAD_CONFIG: | ||
return "EGL_BAD_CONFIG"; | ||
case EGL_BAD_CURRENT_SURFACE: | ||
return "EGL_BAD_CURRENT_SURFACE"; | ||
case EGL_BAD_DISPLAY: | ||
return "EGL_BAD_DISPLAY"; | ||
case EGL_BAD_SURFACE: | ||
return "EGL_BAD_SURFACE"; | ||
case EGL_BAD_MATCH: | ||
return "EGL_BAD_MATCH"; | ||
case EGL_BAD_PARAMETER: | ||
return "EGL_BAD_PARAMETER"; | ||
case EGL_BAD_NATIVE_PIXMAP: | ||
return "EGL_BAD_NATIVE_PIXMAP"; | ||
case EGL_BAD_NATIVE_WINDOW: | ||
return "EGL_BAD_NATIVE_WINDOW"; | ||
case EGL_CONTEXT_LOST: | ||
return "EGL_CONTEXT_LOST"; | ||
default: | ||
return "Unknown Error"; | ||
} | ||
} |
Oops, something went wrong.