Skip to content

Commit

Permalink
Merge branch 'main' into standard-loader
Browse files Browse the repository at this point in the history
  • Loading branch information
svillar authored Sep 13, 2024
2 parents 2eec227 + 3066aa0 commit 0f60c0b
Show file tree
Hide file tree
Showing 55 changed files with 866 additions and 127 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
path = app/src/main/cpp/tinygltf
url = https://github.com/Igalia/tinygltf.git
branch = igalia.com/wolvic
[submodule "app/src/KTX-Software"]
path = app/src/main/cpp/KTX-Software
url = https://github.com/KhronosGroup/KTX-Software.git
branch = 4.2
6 changes: 6 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ add_library( # Sets the name of the library.
src/main/cpp/Pointer.cpp
src/main/cpp/Skybox.cpp
src/main/cpp/SplashAnimation.cpp
src/main/cpp/TrackedKeyboardRenderer.cpp
src/main/cpp/VRBrowser.cpp
src/main/cpp/VRVideo.cpp
src/main/cpp/VRLayer.cpp
Expand Down Expand Up @@ -181,6 +182,11 @@ target_sources(native-lib PUBLIC
include_directories(
${CMAKE_SOURCE_DIR}/../app/src/main/cpp/tinygltf)

# Add dependency on KTX-Software
add_subdirectory(${CMAKE_SOURCE_DIR}/src/main/cpp/KTX-Software)
target_link_libraries(native-lib ktx_read)
target_include_directories(native-lib PRIVATE ${CMAKE_SOURCE_DIR}/src/main/cpp/KTX-Software/include)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ dependencies {
// chromium
if (isChromiumAvailable()) {
chromiumImplementation fileTree(dir: gradle."localProperties.chromium_aar", include: ['*.aar'])
chromiumImplementation 'androidx.fragment:fragment:1.8.2'
chromiumImplementation 'androidx.fragment:fragment:1.8.3'
}

// webkit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ public void confirm(@NonNull Login login) {
public WResult<PromptResponse> onLoginSelect(@NonNull WSession session, final @NonNull AutocompleteRequest<WAutocomplete.LoginSelectOption> autocompleteRequest) {
final WResult<PromptResponse> result = WResult.create();

if (autocompleteRequest.options().length > 1 && SettingsStore.getInstance(mContext).isAutoFillEnabled()) {
if (autocompleteRequest.options().length > 0 && SettingsStore.getInstance(mContext).isAutoFillEnabled()) {
List<Login> logins = Arrays.stream(autocompleteRequest.options()).map(item -> LoginDelegateWrapper.toLogin(item.value)).collect(Collectors.toList());
if (mSelectLoginPrompt == null) {
mSelectLoginPrompt = new SelectLoginPromptWidget(mContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ object EngineProvider {
.build())
builder.displayDensityOverride(settingsStore.displayDensity)
builder.displayDpiOverride(settingsStore.displayDpi)
// This calculation ensures that screen.width and screen.height are always greater or
// equal than window.innerWidth and window.innerHeight, even with different densities.
builder.screenSizeOverride(
(settingsStore.maxWindowWidth * settingsStore.displayDensity).toInt(),
(settingsStore.maxWindowHeight * settingsStore.displayDensity).toInt()
(settingsStore.maxWindowWidth * settingsStore.displayDpi / 100.0).toInt(),
(settingsStore.maxWindowHeight * settingsStore.displayDpi / 100.0).toInt()
)
builder.enterpriseRootsEnabled(settingsStore.isSystemRootCAEnabled)
builder.inputAutoZoomEnabled(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,11 @@ public void exitImmersiveMode() {
}
}
}

// Chromium does fullscreen windows when entering immersive-ar sessions. We have to restore
// the fullscreen window when exiting.
if (mFullscreenWindow != null)
mFullscreenWindow.getSession().exitFullScreen();
}

private void closeLibraryPanelInFocusedWindowIfNeeded() {
Expand Down
27 changes: 14 additions & 13 deletions app/src/common/shared/com/igalia/wolvic/utils/EnvironmentUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class EnvironmentUtils {

public static final String ENVS_FOLDER = "envs";
public static final String BUILTIN_ENVS_PREFIX = "cubemap/";
public static String[] SUPPORTED_ENV_EXTENSIONS = (DeviceType.isPicoXR() || DeviceType.isOculusBuild()) ?
new String[]{".jpg", ".png"} : new String[]{".ktx", ".jpg", ".png"};

/**
* Gets the ouput path for a given environment id.
Expand Down Expand Up @@ -84,28 +86,26 @@ public static String getBuiltinEnvPath(@NonNull String envId) {
}

/**
* Check wether or not an external environment is ready to be used. Checks is the ouput directory exists
* and if it contains 6 items. We make an assumption that those items are the right images and that they
* follow the naming convention.
* Check whether or not an external environment is ready to be used. Checks if the directory exists
* and if it contains at least 6 supported files. We make an assumption that those files are the
* right images and that they follow the naming convention.
* @param context An activity context.
* @param envId The environment id. This maps to the Remote properties JSON "value" environment property.
* @return true is the environment is ready, false otherwise
*/
public static boolean isExternalEnvReady(@NonNull Context context, @NonNull String envId) {
boolean isEnvReady = false;
String envOutputPath = getExternalEnvPath(context, envId);
if (envOutputPath != null) {
File file = new File(envOutputPath);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length == 6) {
isEnvReady = true;
}
File envDirectory = new File(envOutputPath);
if (envDirectory.exists() && envDirectory.isDirectory()) {
File[] envFiles = envDirectory.listFiles(file -> {
String fileName = file.getName().toLowerCase();
return file.isFile() && Arrays.stream(SUPPORTED_ENV_EXTENSIONS).anyMatch(fileName::endsWith);
});
return envFiles != null && envFiles.length >= 6;
}
}

return isEnvReady;
return false;
}

/**
Expand Down Expand Up @@ -209,9 +209,10 @@ public static Environment getExternalEnvironmentById(@NonNull Context context, @
*/
@Nullable
public static String getEnvironmentPayload(Environment env) {
// Pico4x and Meta Quest (after v69) do not support compressed textures for the cubemap.
if (DeviceType.isPicoXR() || DeviceType.isOculusBuild()) {
String payload = env.getPayload();
String format = DeviceType.isOculusBuild() ? "_ktx" : "_misc"; // Pico4x doesn't support 'ktx'
String format = "_misc";
int at = payload.lastIndexOf(".");
return payload.substring(0, at) + format + "_srgb" + payload.substring(at);
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
android:name="com.igalia.wolvic.VRBrowserActivity"
android:launchMode="singleInstance"
android:exported="false"
android:configChanges="density|keyboardHidden|navigation|orientation|screenSize|uiMode|locale|layoutDirection"
android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenSize|uiMode|locale|layoutDirection"
android:windowSoftInputMode="stateAlwaysHidden">
<!-- Declares Wolvic as a browser app -->
<intent-filter>
Expand Down
Binary file modified app/src/main/assets/cubemap/cyberpunk/negx.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/negx_srgb.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/negy.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/negy_srgb.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/negz.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/negz_srgb.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posx.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posx_srgb.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posy.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posy_srgb.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posz.ktx
Binary file not shown.
Binary file modified app/src/main/assets/cubemap/cyberpunk/posz_srgb.ktx
Binary file not shown.
33 changes: 33 additions & 0 deletions app/src/main/cpp/Assertions.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
#pragma once

#include <string>

// MACROS to define to-string and logging function utils
#define STRINGIFY(x) #x
#define FILE_AND_LINE_INTERNAL(LINE) __FILE__ ":" STRINGIFY(LINE)
#define FILE_AND_LINE FILE_AND_LINE_INTERNAL(__LINE__)

inline std::string Fmt(const char* fmt, ...) {
va_list vl;
va_start(vl, fmt);
int size = vsnprintf(nullptr, 0, fmt, vl);
va_end(vl);

if (size != -1) {
std::unique_ptr<char[]> buffer(new char[size + 1]);

va_start(vl, fmt);
size = vsnprintf(buffer.get(), size + 1, fmt, vl);
va_end(vl);
if (size != -1) {
return std::string(buffer.get(), size);
}
}

throw std::runtime_error("Unexpected vsnprintf failure");
}

[[noreturn]] inline void Throw(std::string failureMessage, const char* originator = nullptr, const char* sourceLocation = nullptr) {
if (originator != nullptr) {
failureMessage += Fmt("\n Origin: %s", originator);
}
if (sourceLocation != nullptr) {
failureMessage += Fmt("\n Source: %s", sourceLocation);
}

throw std::logic_error(failureMessage);
}

#define THROW(msg) Throw(msg, nullptr, FILE_AND_LINE);

#define CHECK(exp) \
Expand Down
60 changes: 53 additions & 7 deletions app/src/main/cpp/BrowserWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ExternalVR.h"
#include "Skybox.h"
#include "SplashAnimation.h"
#include "TrackedKeyboardRenderer.h"
#include "Pointer.h"
#include "Widget.h"
#include "WidgetMover.h"
Expand Down Expand Up @@ -215,6 +216,7 @@ struct BrowserWorld::State {
#elif defined(OCULUSVR) && defined(STORE_BUILD)
bool isApplicationEntitled = false;
#endif
TrackedKeyboardRendererPtr trackedKeyboardRenderer;

State() : paused(true), glInitialized(false), modelsLoaded(false), env(nullptr), cylinderDensity(0.0f), nearClip(0.1f),
farClip(300.0f), activity(nullptr), windowsInitialized(false), exitImmersiveRequested(false), loaderDelay(0) {
Expand Down Expand Up @@ -255,6 +257,7 @@ struct BrowserWorld::State {
void ChangeControllerFocus(const Controller& aController);
void UpdateGazeModeState();
void UpdateControllers(bool& aRelayoutWidgets);
void UpdateTrackedKeyboard();
void SimulateBack();
void ClearWebXRControllerData();
void HandleControllerScroll(Controller& controller, int handle);
Expand Down Expand Up @@ -676,6 +679,31 @@ BrowserWorld::State::UpdateControllers(bool& aRelayoutWidgets) {
}
}

void
BrowserWorld::State::UpdateTrackedKeyboard() {
DeviceDelegate::TrackedKeyboardInfo keyboardInfo;
if (!device->PopulateTrackedKeyboardInfo(keyboardInfo)) {
// No keyboard being tracked
if (trackedKeyboardRenderer != nullptr) {
trackedKeyboardRenderer.reset();
trackedKeyboardRenderer = nullptr;
}
return;
}

// A tracked keyboard exists, lazily create the renderer
if (trackedKeyboardRenderer == nullptr)
trackedKeyboardRenderer = TrackedKeyboardRenderer::Create(create);

// Update keyboard model if new buffer is available
if (keyboardInfo.modelBuffer.size() > 0)
trackedKeyboardRenderer->LoadKeyboardMesh(keyboardInfo.modelBuffer);

trackedKeyboardRenderer->SetVisible(keyboardInfo.isActive);
if (keyboardInfo.isActive)
trackedKeyboardRenderer->SetTransform(keyboardInfo.transform);
}

void
BrowserWorld::State::HandleControllerScroll(Controller& controller, int handle) {
if ((controller.scrollDeltaX != 0.0f) || controller.scrollDeltaY != 0.0f) {
Expand Down Expand Up @@ -1065,6 +1093,11 @@ BrowserWorld::ShutdownGL() {
if (!m.glInitialized) {
return;
}
if (m.trackedKeyboardRenderer) {
m.trackedKeyboardRenderer.reset();
m.trackedKeyboardRenderer = nullptr;
}

if (m.loader) {
m.loader->ShutdownGL();
}
Expand Down Expand Up @@ -1155,15 +1188,24 @@ BrowserWorld::StartFrame() {
m.controllers->SetFrameId(frameId);
m.CheckExitImmersive();

auto createPassthroughLayerIfNeeded = [this]() {
if (!m.device->IsPassthroughEnabled() || !m.device->usesPassthroughCompositorLayer() || m.layerPassthrough)
return;
m.layerPassthrough = m.device->CreateLayerPassthrough();
m.rootPassthroughParent->AddNode(VRLayerNode::Create(m.create, m.layerPassthrough));
};

if (m.splashAnimation) {
TickSplashAnimation();
} else if (m.externalVR->IsPresenting()) {
m.CheckBackButton();
createPassthroughLayerIfNeeded();
TickImmersive();
} else {
bool relayoutWidgets = false;
m.UpdateGazeModeState();
m.UpdateControllers(relayoutWidgets);
m.UpdateTrackedKeyboard();
if (m.inHeadLockMode) {
OnReorient();
m.device->Reorient();
Expand All @@ -1173,10 +1215,7 @@ BrowserWorld::StartFrame() {
if (relayoutWidgets) {
UpdateVisibleWidgets();
}
if (m.device->IsPassthroughEnabled() && m.device->usesPassthroughCompositorLayer() && !m.layerPassthrough) {
m.layerPassthrough = m.device->CreateLayerPassthrough();
m.rootPassthroughParent->AddNode(VRLayerNode::Create(m.create, m.layerPassthrough));
}
createPassthroughLayerIfNeeded();
TickWorld();
m.externalVR->PushSystemState();
}
Expand Down Expand Up @@ -1798,6 +1837,10 @@ BrowserWorld::DrawWorld(device::Eye aEye) {
m.device->DrawHandMesh(controller.index, *camera);
}

// Draw tracked keyboard, if any
if (m.trackedKeyboardRenderer != nullptr)
m.trackedKeyboardRenderer->Draw(*camera);

// Draw controllers
m.drawList->Reset();
m.rootController->Cull(*m.cullVisitor, *m.drawList);
Expand All @@ -1813,6 +1856,8 @@ void
BrowserWorld::TickImmersive() {
m.externalVR->SetCompositorEnabled(false);
m.device->SetRenderMode(device::RenderMode::Immersive);
m.device->SetImmersiveBlendMode(m.externalVR->GetImmersiveBlendMode());
m.device->SetImmersiveXRSessionType(m.externalVR->GetImmersiveXRSessionType());

// We must clear the passthrough layer when entering immersive mode even if we are not adding it
// to the list of layers to render. See https://github.com/Igalia/wolvic/issues/1351
Expand Down Expand Up @@ -1886,7 +1931,7 @@ BrowserWorld::TickImmersive() {

void
BrowserWorld::resetPassthroughLayerIfNeeded() {
if (!m.layerPassthrough)
if (!m.layerPassthrough || (m.externalVR->IsPresenting() && m.externalVR->GetImmersiveXRSessionType() == DeviceDelegate::ImmersiveXRSessionType::AR))
return;

ASSERT(m.rootPassthroughParent->GetNodeCount() == 1);
Expand Down Expand Up @@ -1984,8 +2029,9 @@ BrowserWorld::CreateSkyBox(const std::string& aBasePath, const std::string& aExt
const std::string extension = aExtension.empty() ? ".png" : aExtension;
GLenum glFormat = GL_SRGB8_ALPHA8;
#elif OCULUSVR
const std::string extension = aExtension.empty() ? ".ktx" : aExtension;
GLenum glFormat = extension == ".ktx" ? GL_COMPRESSED_SRGB8_ETC2 : GL_SRGB8_ALPHA8;
// Meta Quest (after v69) does not support compressed textures for the cubemap.
const std::string extension = aExtension.empty() ? ".png" : aExtension;
GLenum glFormat = GL_SRGB8_ALPHA8;
#else
const std::string extension = aExtension.empty() ? ".ktx" : aExtension;
GLenum glFormat = extension == ".ktx" ? GL_COMPRESSED_RGB8_ETC2 : GL_RGBA8;
Expand Down
1 change: 1 addition & 0 deletions app/src/main/cpp/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const CapabilityFlags GripSpacePosition = 1u << 13u;
enum class Eye { Left, Right };
enum class RenderMode { StandAlone, Immersive };
enum class CPULevel { Normal = 0, High };
enum class BlendMode { Opaque, AlphaBlend, Additive };
const int32_t EyeCount = 2;
inline int32_t EyeIndex(const Eye aEye) { return aEye == Eye::Left ? 0 : 1; }
// The type values need to match those defined in DeviceType.java
Expand Down
Loading

0 comments on commit 0f60c0b

Please sign in to comment.