Skip to content

Commit

Permalink
feat: ✨ Add Lynx headset support (#1823)
Browse files Browse the repository at this point in the history
* feat: ✨ Add Lynx headset support

* Disable srgb correction
  • Loading branch information
zarik5 committed Sep 7, 2023
1 parent 2e92891 commit 057fce4
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 119 deletions.
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

0 comments on commit 057fce4

Please sign in to comment.