Skip to content

Commit

Permalink
Enable Oculus Fixed Foveated Rendering (#1064)
Browse files Browse the repository at this point in the history
- Option to change value added to the developer
  settings UI.
- Default with a value of 2 (0 = none, 3 = max).
  • Loading branch information
MortimerGoro authored and bluemarvin committed Apr 9, 2019
1 parent a18a4fe commit ef9c090
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 2 deletions.
Expand Up @@ -191,6 +191,7 @@ protected void onCreate(Bundle savedInstanceState) {
final String tempPath = getCacheDir().getAbsolutePath();
queueRunnable(() -> setTemporaryFilePath(tempPath));
setCylinderDensity(SettingsStore.getInstance(this).getCylinderDensity());
updateFoveatedLevel();
initializeWorld();

// Setup the search engine
Expand Down Expand Up @@ -961,6 +962,13 @@ public void updateEnvironment() {
queueRunnable(() -> updateEnvironmentNative());
}

@Override
public void updateFoveatedLevel() {
final int appLevel = SettingsStore.getInstance(this).getFoveatedLevelApp();
final int webVRLevel = SettingsStore.getInstance(this).getFoveatedLevelWebVR();
queueRunnable(() -> updateFoveatedLevelNative(appLevel, webVRLevel));
}

@Override
public void updatePointerColor() {
queueRunnable(() -> updatePointerColorNative());
Expand Down Expand Up @@ -1029,4 +1037,5 @@ public void setCylinderDensity(final float aDensity) {
private native void runCallbackNative(long aCallback);
private native void setCylinderDensityNative(float aDensity);
private native void setIsServo(boolean aIsServo);
private native void updateFoveatedLevelNative(int appLevel, int webVRLevel);
}
Expand Up @@ -58,6 +58,8 @@ SettingsStore getInstance(final @NonNull Context aContext) {
public final static int MSAA_DEFAULT_LEVEL = 1;
public final static boolean AUDIO_ENABLED = false;
public final static float CYLINDER_DENSITY_ENABLED_DEFAULT = 4680.0f;
public final static int FOVEATED_APP_DEFAULT_LEVEL = 1;
public final static int FOVEATED_WEBVR_DEFAULT_LEVEL = 0;

// Enable telemetry by default (opt-out).
private final static boolean enableCrashReportingByDefault = false;
Expand Down Expand Up @@ -360,7 +362,6 @@ public void setMSAALevel(int level) {
editor.commit();
}


public boolean getLayersEnabled() {
if (BuildConfig.FLAVOR_platform.equalsIgnoreCase("oculusvr")) {
return true;
Expand Down Expand Up @@ -404,6 +405,28 @@ public float getCylinderDensity() {
public void setCylinderDensity(float aDensity) {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putFloat(mContext.getString(R.string.settings_key_cylinder_density), aDensity);
}

public int getFoveatedLevelApp() {
return mPrefs.getInt(
mContext.getString(R.string.settings_key_foveated_app), FOVEATED_APP_DEFAULT_LEVEL);
}

public int getFoveatedLevelWebVR() {
return mPrefs.getInt(
mContext.getString(R.string.settings_key_foveated_webvr), FOVEATED_WEBVR_DEFAULT_LEVEL);
}

public void setFoveatedLevelApp(int level) {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putInt(mContext.getString(R.string.settings_key_foveated_app), level);
editor.commit();
}

public void setFoveatedLevelWebVR(int level) {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putInt(mContext.getString(R.string.settings_key_foveated_webvr), level);
editor.commit();
}
}

Expand Up @@ -121,6 +121,10 @@ public void setOnCheckedChangeListener(OnCheckedChangeListener aListener) {
mRadioGroupListener = aListener;
}

public OnCheckedChangeListener getOnCheckdChangeListener() {
return mRadioGroupListener;
}

public Object getValueForId(@IdRes int checkId) {
return mValues[checkId];
}
Expand Down
Expand Up @@ -42,6 +42,7 @@ interface WorldClickListener {
void setIsServoSession(boolean aIsServo);
void keyboardDismissed();
void updateEnvironment();
void updateFoveatedLevel();
void updatePointerColor();
void showVRVideo(int aWindowHandle, @VideoProjectionMenuWidget.VideoProjectionFlags int aVideoProjection);
void hideVRVideo();
Expand Down
Expand Up @@ -9,12 +9,15 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.audio.AudioEngine;
import org.mozilla.vrbrowser.browser.SessionStore;
import org.mozilla.vrbrowser.browser.SettingsStore;
import org.mozilla.vrbrowser.BuildConfig;
import org.mozilla.vrbrowser.audio.AudioEngine;
import org.mozilla.vrbrowser.ui.views.UIButton;
import org.mozilla.vrbrowser.ui.views.settings.ButtonSetting;
import org.mozilla.vrbrowser.ui.views.settings.DoubleEditSetting;
Expand All @@ -36,6 +39,8 @@ public class DisplayOptionsWidget extends UIWidget implements
private SwitchSetting mCurvedDisplaySwitch;
private RadioGroupSetting mUaModeRadio;
private RadioGroupSetting mMSAARadio;
private RadioGroupSetting mFoveatedAppRadio;
private RadioGroupSetting mFoveatedWebVRRadio;

private SingleEditSetting mDensityEdit;
private SingleEditSetting mDpiEdit;
Expand Down Expand Up @@ -97,6 +102,21 @@ private void initialize(Context aContext) {
mMSAARadio.setOnCheckedChangeListener(mMSSAChangeListener);
setMSAAMode(mMSAARadio.getIdForValue(msaaLevel), false);

mFoveatedAppRadio = findViewById(R.id.foveated_app_radio);
mFoveatedWebVRRadio = findViewById(R.id.foveated_webvr_radio);
if (BuildConfig.FLAVOR_platform == "oculusvr") {
mFoveatedAppRadio.setVisibility(View.VISIBLE);
// Uncomment this when Foveated Rendering for WebVR makes more sense
//mFoveatedWebVRRadio.setVisibility(View.VISIBLE);
int level = SettingsStore.getInstance(getContext()).getFoveatedLevelApp();
setFoveatedLevel(mFoveatedAppRadio, mFoveatedAppRadio.getIdForValue(level), false);
mFoveatedAppRadio.setOnCheckedChangeListener((compoundButton, checkedId, apply) -> setFoveatedLevel(mFoveatedAppRadio, checkedId, apply));

level = SettingsStore.getInstance(getContext()).getFoveatedLevelWebVR();
setFoveatedLevel(mFoveatedWebVRRadio, mFoveatedWebVRRadio.getIdForValue(level), false);
mFoveatedWebVRRadio.setOnCheckedChangeListener((compoundButton, checkedId, apply) -> setFoveatedLevel(mFoveatedWebVRRadio, checkedId, apply));
}

mDensityEdit = findViewById(R.id.density_edit);
mDensityEdit.setHint1(String.valueOf(SettingsStore.DISPLAY_DENSITY_DEFAULT));
mDensityEdit.setDefaultFirstValue(String.valueOf(SettingsStore.DISPLAY_DENSITY_DEFAULT));
Expand Down Expand Up @@ -224,7 +244,6 @@ private void onRestartDialogDismissed() {
show();
}


private RadioGroupSetting.OnCheckedChangeListener mUaModeListener = (radioGroup, checkedId, doApply) -> {
setUaMode(checkedId, true);
};
Expand Down Expand Up @@ -292,6 +311,14 @@ private void onRestartDialogDismissed() {
if (!mMSAARadio.getValueForId(mMSAARadio.getCheckedRadioButtonId()).equals(SettingsStore.MSAA_DEFAULT_LEVEL)) {
setMSAAMode(mMSAARadio.getIdForValue(SettingsStore.MSAA_DEFAULT_LEVEL), true);
}
if (BuildConfig.FLAVOR_platform == "oculusvr") {
if (!mFoveatedAppRadio.getValueForId(mFoveatedAppRadio.getCheckedRadioButtonId()).equals(SettingsStore.FOVEATED_APP_DEFAULT_LEVEL)) {
setFoveatedLevel(mFoveatedAppRadio, mFoveatedAppRadio.getIdForValue(SettingsStore.FOVEATED_APP_DEFAULT_LEVEL), true);
}
if (!mFoveatedWebVRRadio.getValueForId(mFoveatedWebVRRadio.getCheckedRadioButtonId()).equals(SettingsStore.FOVEATED_WEBVR_DEFAULT_LEVEL)) {
setFoveatedLevel(mFoveatedWebVRRadio, mFoveatedWebVRRadio.getIdForValue(SettingsStore.FOVEATED_WEBVR_DEFAULT_LEVEL), true);
}
}

restart = restart | setDisplayDensity(SettingsStore.DISPLAY_DENSITY_DEFAULT);
restart = restart | setDisplayDpi(SettingsStore.DISPLAY_DPI_DEFAULT);
Expand Down Expand Up @@ -332,6 +359,25 @@ private void setMSAAMode(int checkedId, boolean doApply) {
}
}

private void setFoveatedLevel(RadioGroupSetting aSetting, int checkedId, boolean doApply) {
RadioGroupSetting.OnCheckedChangeListener listener = aSetting.getOnCheckdChangeListener();
aSetting.setOnCheckedChangeListener(null);
aSetting.setChecked(checkedId, doApply);
aSetting.setOnCheckedChangeListener(listener);

int level = (Integer)aSetting.getValueForId(checkedId);

if (aSetting == mFoveatedAppRadio) {
SettingsStore.getInstance(getContext()).setFoveatedLevelApp(level);
} else {
SettingsStore.getInstance(getContext()).setFoveatedLevelWebVR(level);
}

if (doApply) {
mWidgetManager.updateFoveatedLevel();
}
}

private boolean setDisplayDensity(float newDensity) {
mDensityEdit.setOnClickListener(null);
boolean restart = false;
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/cpp/BrowserWorld.cpp
Expand Up @@ -670,6 +670,12 @@ BrowserWorld::UpdateEnvironment() {
CreateSkyBox(env.c_str(), "");
}

void
BrowserWorld::UpdateFoveatedLevel(const int aAppLevel, const int aWebVRLevel) {
ASSERT_ON_RENDER_THREAD();
m.device->SetFoveatedLevel(aAppLevel, aWebVRLevel);
}

void
BrowserWorld::UpdatePointerColor() {
ASSERT_ON_RENDER_THREAD();
Expand Down Expand Up @@ -1297,6 +1303,11 @@ JNI_METHOD(void, updateEnvironmentNative)
crow::BrowserWorld::Instance().UpdateEnvironment();
}

JNI_METHOD(void, updateFoveatedLevelNative)
(JNIEnv *aEnv, jobject, jint aAppLevel, jint aWebVRLevel) {
crow::BrowserWorld::Instance().UpdateFoveatedLevel(aAppLevel, aWebVRLevel);
}

JNI_METHOD(void, updatePointerColorNative)
(JNIEnv* aEnv, jobject) {
crow::BrowserWorld::Instance().UpdatePointerColor();
Expand Down
1 change: 1 addition & 0 deletions app/src/main/cpp/BrowserWorld.h
Expand Up @@ -40,6 +40,7 @@ class BrowserWorld {
void Draw();
void SetTemporaryFilePath(const std::string& aPath);
void UpdateEnvironment();
void UpdateFoveatedLevel(const int aAppLevel, const int aWebVRLevel);
void UpdatePointerColor();
void SetSurfaceTexture(const std::string& aName, jobject& aSurface);
void AddWidget(int32_t aHandle, const WidgetPlacementPtr& placement);
Expand Down
1 change: 1 addition & 0 deletions app/src/main/cpp/DeviceDelegate.h
Expand Up @@ -56,6 +56,7 @@ class DeviceDelegate {
virtual void SetClearColor(const vrb::Color& aColor) = 0;
virtual void SetClipPlanes(const float aNear, const float aFar) = 0;
virtual void SetControllerDelegate(ControllerDelegatePtr& aController) = 0;
virtual void SetFoveatedLevel(const int32_t aAppLevel, const int32_t aWebVRLevel) {};
virtual void ReleaseControllerDelegate() = 0;
virtual int32_t GetControllerModelCount() const = 0;
virtual const std::string GetControllerModelName(const int32_t aModelIndex) const = 0;
Expand Down
18 changes: 18 additions & 0 deletions app/src/main/res/layout/options_display.xml
Expand Up @@ -67,6 +67,24 @@
app:options="@array/developer_options_msaa"
app:values="@array/developer_options_ua_mode_values" />

<org.mozilla.vrbrowser.ui.views.settings.RadioGroupSetting
android:id="@+id/foveated_app_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:description="@string/developer_options_foveated_app"
android:visibility="gone"
app:options="@array/developer_options_foveated_options"
app:values="@array/developer_options_foveated_values" />

<org.mozilla.vrbrowser.ui.views.settings.RadioGroupSetting
android:id="@+id/foveated_webvr_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:description="@string/developer_options_foveated_webvr"
android:visibility="gone"
app:options="@array/developer_options_foveated_options"
app:values="@array/developer_options_foveated_values" />

<org.mozilla.vrbrowser.ui.views.settings.SingleEditSetting
android:id="@+id/density_edit"
android:layout_width="match_parent"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/non_L10n.xml
Expand Up @@ -28,6 +28,8 @@
<string name="settings_key_audio" translatable="false">settings_audio</string>
<string name="settings_key_voice_search_language" translatable="false">settings_voice_search_language</string>
<string name="settings_key_cylinder_density" translatable="false">settings_cylinder_density</string>
<string name="settings_key_foveated_app" translatable="false">settings_foveated_app</string>
<string name="settings_key_foveated_webvr" translatable="false">settings_foveated_webvr</string>
<string name="private_browsing_support_url" translatable="false">https://support.mozilla.org/kb/private-mode-firefox-reality</string>
<string name="settings_key_browser_world_width" translatable="false">settings_browser_world_width</string>
<string name="settings_key_browser_world_height" translatable="false">settings_browser_world_height</string>
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/res/values/options_values.xml
Expand Up @@ -66,6 +66,21 @@
<item>@string/developer_options_msaa_4</item>
</string-array>

<!-- Foveated Levels -->
<string-array name="developer_options_foveated_options" translatable="false">
<item>@string/developer_options_foveated_disabled</item>
<item>@string/developer_options_foveated_1</item>
<item>@string/developer_options_foveated_2</item>
<item>@string/developer_options_foveated_3</item>
</string-array>

<integer-array name="developer_options_foveated_values" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</integer-array>

<!-- Language Options -->
<string-array name="developer_options_voice_search_languages" translatable="false">
<item>@string/language_en_US</item>
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/res/values/strings.xml
Expand Up @@ -254,6 +254,26 @@
<!-- This string is used to label the 'VR' radio button of the 'User-Agent Mode' settings option. -->
<string name="developer_options_ua_vr">VR</string>

<!-- This string is used to label radio buttons for setting fixed-foveated-rendering (FFR) level.
Higher values of this option result in larger parts of the peripheral vision being rendered
at lower resolutions than the content in the center of the view. These higher values reduce
quality to increase performance. The Oculus implementation of fixed-foveated-rendering is
described in more detail here:
https://developer.oculus.com/blog/optimizing-oculus-go-for-performance/-->
<string name="developer_options_foveated_app">Foveation Level (App)</string>
<!-- This string is used to label radio buttons for setting foveated level for WebVR immersive experiences -->
<string name="developer_options_foveated_webvr">Foveation Level (WebVR)</string>
<!-- This string is used to label the Foveated radio button that disables fixed-foveated-rendering in immersive mode. -->
<string name="developer_options_foveated_disabled">Disabled</string>
<!-- This string is used to label the Foveated radio button that enables low-level fixed-foveated-rendering. -->
<string name="developer_options_foveated_1">1</string>
<!-- This string is used to label the Foveated radio button that enables medium-level fixed-foveated-rendering. -->
<string name="developer_options_foveated_2">2</string>
<!-- This string is used to label the Foveated radio button that enables high-level fixed-foveated-rendering. -->
<string name="developer_options_foveated_3">3</string>
<!-- This string is used to label a set of radio buttons that allow the user to
change the user-agent (UA) string of the browser. -->

<!-- This string is used to label a set of radio buttons that allow the user to change the
scroll direction of the remote controller. -->
<string name="developer_options_scroll_direction">Scroll Direction</string>
Expand Down
22 changes: 22 additions & 0 deletions app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp
Expand Up @@ -609,6 +609,8 @@ struct DeviceDelegateOculusVR::State {
ovrTracking2 predictedTracking = {};
uint32_t renderWidth = 0;
uint32_t renderHeight = 0;
int32_t standaloneFoveatedLevel = 0;
int32_t immersiveFoveatedLevel = 0;
vrb::Color clearColor;
float near = 0.1f;
float far = 100.f;
Expand Down Expand Up @@ -688,6 +690,17 @@ struct DeviceDelegateOculusVR::State {
}
}

void UpdateFoveatedLevel() {
if (!ovr) {
return;
}
if (renderMode == device::RenderMode::StandAlone) {
vrapi_SetPropertyInt(&java, VRAPI_FOVEATION_LEVEL, standaloneFoveatedLevel);
} else {
vrapi_SetPropertyInt(&java, VRAPI_FOVEATION_LEVEL, immersiveFoveatedLevel);
}
}

void AddUILayer(const OculusLayerPtr& aLayer, VRLayerSurface::SurfaceType aSurfaceType) {
if (ovr) {
vrb::RenderContextPtr ctx = context.lock();
Expand Down Expand Up @@ -972,6 +985,7 @@ DeviceDelegateOculusVR::SetRenderMode(const device::RenderMode aMode) {
}

m.UpdateTrackingMode();
m.UpdateFoveatedLevel();

// Reset reorient when exiting or entering immersive
m.reorientMatrix = vrb::Matrix::Identity();
Expand Down Expand Up @@ -1048,6 +1062,13 @@ DeviceDelegateOculusVR::ReleaseControllerDelegate() {
m.controller = nullptr;
}

void
DeviceDelegateOculusVR::SetFoveatedLevel(const int32_t aAppLevel, const int32_t aWebVRLevel) {
m.standaloneFoveatedLevel = aAppLevel;
m.immersiveFoveatedLevel = aWebVRLevel;
m.UpdateFoveatedLevel();
}

int32_t
DeviceDelegateOculusVR::GetControllerModelCount() const {
if (m.IsOculusQuest()) {
Expand Down Expand Up @@ -1425,6 +1446,7 @@ DeviceDelegateOculusVR::EnterVR(const crow::BrowserEGLContext& aEGLContext) {
vrapi_SetPerfThread(m.ovr, VRAPI_PERF_THREAD_TYPE_MAIN, gettid());
vrapi_SetPerfThread(m.ovr, VRAPI_PERF_THREAD_TYPE_RENDERER, gettid());
m.UpdateTrackingMode();
m.UpdateFoveatedLevel();
}

// Reset reorientation after Enter VR
Expand Down
1 change: 1 addition & 0 deletions app/src/oculusvr/cpp/DeviceDelegateOculusVR.h
Expand Up @@ -35,6 +35,7 @@ class DeviceDelegateOculusVR : public DeviceDelegate {
void SetClipPlanes(const float aNear, const float aFar) override;
void SetControllerDelegate(ControllerDelegatePtr& aController) override;
void ReleaseControllerDelegate() override;
void SetFoveatedLevel(const int32_t aAppLevel, const int32_t aWebVRLevel) override;
int32_t GetControllerModelCount() const override;
const std::string GetControllerModelName(const int32_t aModelIndex) const override;
void ProcessEvents() override;
Expand Down

0 comments on commit ef9c090

Please sign in to comment.