Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ Add Lynx headset support #1823

Merged
merged 2 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This is a fork of [ALVR](https://github.com/polygraphene/ALVR).
| Pico 4/Neo 3 | :heavy_check_mark: |
| Vive Focus 3/XR Elite | :heavy_check_mark: |
| YVR 1/2 | :heavy_check_mark: |
| Lynx R1 | :heavy_check_mark: |
| Google Cardboard | :heavy_check_mark: ([PhoneVR](https://github.com/PhoneVR-Developers/PhoneVR)) |
| Smartphone/Monado | :construction: * |
| GearVR | :construction: * (maybe) |
Expand Down
1 change: 1 addition & 0 deletions alvr/client_core/cpp/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct FfiStreamConfig {
float foveationCenterShiftY;
float foveationEdgeRatioX;
float foveationEdgeRatioY;
unsigned int enableSrgbCorrection;
};

// gltf_model.h
Expand Down
76 changes: 46 additions & 30 deletions alvr/client_core/cpp/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ typedef struct {
enum ovrProgramType {
STREAMER_PROG,
LOBBY_PROG,
MAX_PROGS // Not to be used as a type, just a placeholder for len
MAX_PROGS // Not to be used as a type, just a placeholder for len
};

typedef struct {
Expand Down Expand Up @@ -95,12 +95,11 @@ typedef struct {
} ovrVertexAttribute;

ovrVertexAttribute ProgramVertexAttributes[] = {
{VERTEX_ATTRIBUTE_LOCATION_POSITION, "vertexPosition", {true, true }},
{VERTEX_ATTRIBUTE_LOCATION_COLOR, "vertexColor", {true, false}},
{VERTEX_ATTRIBUTE_LOCATION_UV, "vertexUv", {true, true }},
{VERTEX_ATTRIBUTE_LOCATION_TRANSFORM, "vertexTransform", {false, false}},
{VERTEX_ATTRIBUTE_LOCATION_NORMAL, "vertexNormal", {false, true }}
};
{VERTEX_ATTRIBUTE_LOCATION_POSITION, "vertexPosition", {true, true}},
{VERTEX_ATTRIBUTE_LOCATION_COLOR, "vertexColor", {true, false}},
{VERTEX_ATTRIBUTE_LOCATION_UV, "vertexUv", {true, true}},
{VERTEX_ATTRIBUTE_LOCATION_TRANSFORM, "vertexTransform", {false, false}},
{VERTEX_ATTRIBUTE_LOCATION_NORMAL, "vertexNormal", {false, true}}};

enum E1test {
UNIFORM_VIEW_ID,
Expand Down Expand Up @@ -428,7 +427,10 @@ void ovrGeometry_DestroyVAO(ovrGeometry *geometry) {

static const char *programVersion = "#version 300 es\n";

bool ovrProgram_Create(ovrProgram *program, const char *vertexSource, const char *fragmentSource, ovrProgramType progType) {
bool ovrProgram_Create(ovrProgram *program,
const char *vertexSource,
const char *fragmentSource,
ovrProgramType progType) {
GLint r;

LOGI("Compiling shaders.");
Expand Down Expand Up @@ -468,12 +470,16 @@ bool ovrProgram_Create(ovrProgram *program, const char *vertexSource, const char
// Bind the vertex attribute locations.
for (size_t i = 0; i < sizeof(ProgramVertexAttributes) / sizeof(ProgramVertexAttributes[0]);
i++) {
// Only bind vertex attributes which are used/active in shader else causes uncessary bugs via compiler optimization/aliasing
// Only bind vertex attributes which are used/active in shader else causes uncessary bugs
// via compiler optimization/aliasing
if (ProgramVertexAttributes[i].usedInProg[progType]) {
GL(glBindAttribLocation(program->streamProgram,
ProgramVertexAttributes[i].location,
ProgramVertexAttributes[i].name));
LOGD("Binding ProgramVertexAttribute [id.%d] %s to location %d", i, ProgramVertexAttributes[i].name, ProgramVertexAttributes[i].location);
ProgramVertexAttributes[i].location,
ProgramVertexAttributes[i].name));
LOGD("Binding ProgramVertexAttribute [id.%d] %s to location %d",
i,
ProgramVertexAttributes[i].name,
ProgramVertexAttributes[i].location);
}
}

Expand Down Expand Up @@ -551,19 +557,22 @@ void ovrRenderer_Create(ovrRenderer *renderer,
int hudTexture,
std::vector<GLuint> textures[2],
FFRData ffrData,
bool isLobby) {
bool isLobby,
bool enableSrgbCorrection) {
if (!isLobby) {
renderer->srgbCorrectionPass = std::make_unique<SrgbCorrectionPass>(streamTexture);
renderer->enableFFR = ffrData.enabled;
if (renderer->enableFFR) {
FoveationVars fv = CalculateFoveationVars(ffrData);
renderer->srgbCorrectionPass->Initialize(fv.optimizedEyeWidth, fv.optimizedEyeHeight);
renderer->srgbCorrectionPass->Initialize(
fv.optimizedEyeWidth, fv.optimizedEyeHeight, !enableSrgbCorrection);
renderer->ffr = std::make_unique<FFR>(renderer->srgbCorrectionPass->GetOutputTexture());
renderer->ffr->Initialize(fv);
renderer->streamRenderTexture = renderer->ffr->GetOutputTexture()->GetGLTexture();
} else {
renderer->srgbCorrectionPass->Initialize(width, height);
renderer->streamRenderTexture = renderer->srgbCorrectionPass->GetOutputTexture()->GetGLTexture();
renderer->srgbCorrectionPass->Initialize(width, height, !enableSrgbCorrection);
renderer->streamRenderTexture =
renderer->srgbCorrectionPass->GetOutputTexture()->GetGLTexture();
}
}

Expand All @@ -580,7 +589,8 @@ void ovrRenderer_Create(ovrRenderer *renderer,

ovrProgram_Create(&renderer->streamProgram, VERTEX_SHADER, FRAGMENT_SHADER, STREAMER_PROG);

ovrProgram_Create(&renderer->lobbyProgram, LOBBY_VERTEX_SHADER, LOBBY_FRAGMENT_SHADER, LOBBY_PROG);
ovrProgram_Create(
&renderer->lobbyProgram, LOBBY_VERTEX_SHADER, LOBBY_FRAGMENT_SHADER, LOBBY_PROG);

ovrGeometry_CreatePanel(&renderer->Panel);
ovrGeometry_CreateVAO(&renderer->Panel);
Expand Down Expand Up @@ -734,7 +744,7 @@ void initGraphicsNative() {
g_ctx.streamTexture = std::make_unique<Texture>(false, 0, true);
g_ctx.hudTexture = std::make_unique<Texture>(
false, 0, false, 1280, 720, GL_RGBA8, GL_RGBA, std::vector<uint8_t>(1280 * 720 * 4, 0));

const GLubyte *sVendor, *sRenderer, *sVersion, *sExts;

GL(sVendor = glGetString(GL_VENDOR));
Expand All @@ -747,10 +757,14 @@ void initGraphicsNative() {
}

void destroyGraphicsNative() {
LOGV("Resetting stream texture and hud texture %p, %p", g_ctx.streamTexture.get(), g_ctx.hudTexture.get());
LOGV("Resetting stream texture and hud texture %p, %p",
g_ctx.streamTexture.get(),
g_ctx.hudTexture.get());
g_ctx.streamTexture.reset();
g_ctx.hudTexture.reset();
LOGV("Resetted stream texture and hud texture to %p, %p", g_ctx.streamTexture.get(), g_ctx.hudTexture.get());
LOGV("Resetted stream texture and hud texture to %p, %p",
g_ctx.streamTexture.get(),
g_ctx.hudTexture.get());
}

// on resume
Expand All @@ -774,7 +788,8 @@ void prepareLobbyRoom(int viewWidth,
g_ctx.hudTexture->GetGLTexture(),
g_ctx.lobbySwapchainTextures,
{false},
true);
true,
false);
}

// on pause
Expand Down Expand Up @@ -819,7 +834,8 @@ void streamStartNative(FfiStreamConfig config) {
config.foveationCenterShiftY,
config.foveationEdgeRatioX,
config.foveationEdgeRatioY},
false);
false,
config.enableSrgbCorrection);
}

void updateLobbyHudTexture(const unsigned char *data) {
Expand All @@ -838,14 +854,14 @@ void renderLobbyNative(const FfiViewInput eyeInputs[2]) {
if (!g_ctx.hudTextureBitmap.empty()) {
GL(glBindTexture(GL_TEXTURE_2D, g_ctx.hudTexture->GetGLTexture()));
GL(glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
HUD_TEXTURE_WIDTH,
HUD_TEXTURE_HEIGHT,
GL_RGBA,
GL_UNSIGNED_BYTE,
&g_ctx.hudTextureBitmap[0]));
0,
0,
0,
HUD_TEXTURE_WIDTH,
HUD_TEXTURE_HEIGHT,
GL_RGBA,
GL_UNSIGNED_BYTE,
&g_ctx.hudTextureBitmap[0]));
}
g_ctx.hudTextureBitmap.clear();
}
Expand Down
20 changes: 17 additions & 3 deletions alvr/client_core/cpp/srgb_correction_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,29 @@ const string SRGB_CORRECTION_FRAGMENT_SHADER = R"glsl(#version 300 es
color.rgb = condition * lowValues + (1.0 - condition) * highValues;
}
)glsl";
}
const string PASSTHOUGH_FRAGMENT_SHADER = R"glsl(#version 300 es
#extension GL_OES_EGL_image_external_essl3 : enable
precision mediump float;

uniform samplerExternalOES tex0;
in vec2 uv;
out vec4 color;

void main()
{
color = texture(tex0, uv);
}
)glsl";
} // namespace

SrgbCorrectionPass::SrgbCorrectionPass(Texture *inputSurface) : mInputSurface(inputSurface) {}

void SrgbCorrectionPass::Initialize(uint32_t width, uint32_t height) {
void SrgbCorrectionPass::Initialize(uint32_t width, uint32_t height, bool passthrough) {
mOutputTexture.reset(new Texture(false, 0, false, width * 2, height));
mOutputTextureState = make_unique<RenderState>(mOutputTexture.get());

auto fragmentShader = SRGB_CORRECTION_FRAGMENT_SHADER;
auto fragmentShader =
passthrough ? PASSTHOUGH_FRAGMENT_SHADER : SRGB_CORRECTION_FRAGMENT_SHADER;
mStagingPipeline = unique_ptr<RenderPipeline>(
new RenderPipeline({mInputSurface}, QUAD_2D_VERTEX_SHADER, fragmentShader));
}
Expand Down
2 changes: 1 addition & 1 deletion alvr/client_core/cpp/srgb_correction_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class SrgbCorrectionPass {
public:
SrgbCorrectionPass(gl_render_utils::Texture *inputSurface);

void Initialize(uint32_t width, uint32_t height);
void Initialize(uint32_t width, uint32_t height, bool passthrough);

void Render() const;

Expand Down
7 changes: 6 additions & 1 deletion alvr/client_core/src/c_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,12 @@ pub unsafe extern "C" fn alvr_start_stream_opengl(config: AlvrStreamConfig) {
edge_ratio_y: config.foveation_edge_ratio_y,
});

opengl::start_stream(view_resolution, swapchain_textures, foveated_rendering);
opengl::start_stream(
view_resolution,
swapchain_textures,
foveated_rendering,
true,
);
}

#[no_mangle]
Expand Down
2 changes: 2 additions & 0 deletions alvr/client_core/src/opengl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub fn start_stream(
view_resolution: UVec2,
swapchain_textures: [Vec<u32>; 2],
foveated_rendering: Option<FoveatedRenderingConfig>,
enable_srgb_correction: bool,
) {
#[cfg(target_os = "android")]
unsafe {
Expand Down Expand Up @@ -107,6 +108,7 @@ pub fn start_stream(
.as_ref()
.map(|f| f.edge_ratio_y)
.unwrap_or_default(),
enableSrgbCorrection: enable_srgb_correction as u32,
};

streamStartNative(config);
Expand Down
10 changes: 9 additions & 1 deletion alvr/client_openxr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,12 @@ value = "1"
# Yvr entries
[[package.metadata.android.application.meta_data]]
name = "com.yvr.intent.category.VR"
value = "vr_only"
value = "vr_only"

# Lynx entries
[[package.metadata.android.queries.intent]]
actions = ["org.khronos.openxr.OpenXRRuntimeService"]
[[package.metadata.android.queries.package]]
name = "com.ultraleap.tracking.service"
[[package.metadata.android.queries.package]]
name = "com.ultraleap.openxr.api_layer"
2 changes: 1 addition & 1 deletion alvr/client_openxr/src/interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub fn initialize_hands_interaction(
Platform::Pico4 => PICO4_CONTROLLER_PROFILE_PATH,
Platform::Focus3 => FOCUS3_CONTROLLER_PROFILE_PATH,
Platform::Yvr => YVR_CONTROLLER_PROFILE_PATH,
Platform::Other => QUEST_CONTROLLER_PROFILE_PATH,
_ => QUEST_CONTROLLER_PROFILE_PATH,
};
let interaction_profile_id = alvr_common::hash_string(interaction_profile_path);

Expand Down
33 changes: 18 additions & 15 deletions alvr/client_openxr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub enum Platform {
Pico4,
Focus3,
Yvr,
Lynx,
Other,
}

Expand Down Expand Up @@ -350,29 +351,30 @@ fn update_streaming_input(ctx: &mut StreamingInputContext) {
pub fn entry_point() {
alvr_client_core::init_logging();

let platform = match (
alvr_client_core::manufacturer_name().as_str(),
alvr_client_core::device_model().as_str(),
) {
let manufacturer_name = alvr_client_core::manufacturer_name();
let device_model = alvr_client_core::device_model();

info!("Manufacturer: {manufacturer_name}, device model: {device_model}");

let platform = match (manufacturer_name.as_str(), device_model.as_str()) {
("Oculus", _) => Platform::Quest,
("Pico", "Pico Neo 3") => Platform::PicoNeo3,
("Pico", _) => Platform::Pico4,
("HTC", _) => Platform::Focus3,
("YVR", _) => Platform::Yvr,
("Lynx Mixed Reality", _) => Platform::Lynx,
_ => Platform::Other,
};

let xr_entry = match platform {
Platform::Quest => unsafe {
xr::Entry::load_from(Path::new("libopenxr_loader_quest.so")).unwrap()
},
Platform::PicoNeo3 | Platform::Pico4 => unsafe {
xr::Entry::load_from(Path::new("libopenxr_loader_pico.so")).unwrap()
},
Platform::Yvr => unsafe {
xr::Entry::load_from(Path::new("libopenxr_loader_yvr.so")).unwrap()
},
_ => unsafe { xr::Entry::load().unwrap() },
let loader_suffix = match platform {
Platform::Quest => "quest",
Platform::PicoNeo3 | Platform::Pico4 => "pico",
Platform::Yvr => "yvr",
Platform::Lynx => "lynx",
_ => "generic",
};
let xr_entry = unsafe {
xr::Entry::load_from(Path::new(&format!("libopenxr_loader_{loader_suffix}.so"))).unwrap()
};

#[cfg(target_os = "android")]
Expand Down Expand Up @@ -784,6 +786,7 @@ pub fn entry_point() {
.collect(),
],
settings.video.foveated_rendering.into_option(),
platform != Platform::Lynx,
);

alvr_client_core::send_playspace(
Expand Down
11 changes: 4 additions & 7 deletions alvr/xtask/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,16 @@ pub fn download(sh: &Shell, url: &str, destination: &Path) -> Result<(), xshell:
cmd!(sh, "curl -L -o {destination} --url {url}").run()
}

pub fn download_and_extract_zip(
sh: &Shell,
url: &str,
destination: &Path,
) -> Result<(), xshell::Error> {
pub fn download_and_extract_zip(url: &str, destination: &Path) -> Result<(), xshell::Error> {
let sh = Shell::new().unwrap();
let temp_dir_guard = sh.create_temp_dir()?;

let zip_file = temp_dir_guard.path().join("temp_download.zip");
download(sh, url, &zip_file)?;
download(&sh, url, &zip_file)?;

sh.remove_path(destination).ok();
sh.create_dir(destination)?;
unzip(sh, &zip_file, destination)
unzip(&sh, &zip_file, destination)
}

pub fn date_utc_yyyymmdd(sh: &Shell) -> Result<String, xshell::Error> {
Expand Down