servo/components/webrender_surfman/lib.rs
Mukilan Thiyagarajan d7de206dbd
Preliminary Android build support (#31086)
* Android build

* Fixes
* More fixes
  - Still failing in the linking step
* More work on getting linking working

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: use mozjs with ndk r25c. loads servo.org

more android build fixes.

* fix ./mach run for android and make it follow logs

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* add experimental logic for compositor pause/resume

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* pass DPI from android to simpleservo

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* ci: add android workflow

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* switch to ANDROID_SDK_ROOT and ANDROID_NDK_ROOT vars

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade gradle to 4.10.1

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade to gradle 5.1.1

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade to gradle 8 and agp 8

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* make compositing work again with external present

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: improve mach support for non-NixOS and CI

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fix sampler compilation bug introduced in #30490

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* ci: add android build to main workflow

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* gradle: set MinSdk = targetSdk = 30

NDK requires we compile against the minSdk API level
which is 30 in our case.

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* add instructions for android in README.md

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: move servosurface to servoview

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: uncomment the mediasession callbacks on MainActivity

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: fix crash on MainAtivity.onDestroy

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: drop VR, arm 5 and unused code

This commit drops:
* support for google, oculusvr
* support for arm5 architecture

and also removes
* fakeld scripts
* unused java code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* cleanup shell.nix

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: add FIXMEs for gstreamer code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: remove commented code and debug logs

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* cleanup ServoView.java

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* mach: comment call to download gstreamer deps for android

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* disable bluetooth for jniapi as blurdroid is broken

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fixup! README.md

* fixup! remove change in Cargo.toml

* fixup! move shell variables together

* fixup! cleanup jniapi/Cargo.toml comments

* delete commented gstreamer related android code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* remove unused config variable in servbuild

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: more cleanup

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* force no_static_freetype only for android

* use actions to manage sdk, ndk and java

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* rename embedder event names to be more clear.

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* link to startup crash issue

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fix lint issues

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade env_logger to 0.10 with duplicate exception

libservo and android_logger can use env_logger 0.10
but quickcheck is still stuck on 0.8 and has not seen
any activity in the last 2 years. This commit adds
a duplicate exception until the quickcheck dependency
can be upgraded (or replaced)

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: fix comments

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* disable jemalloc on android

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fixup! replace linux with android in cfg

---------

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-01-22 13:00:15 +00:00

243 lines
8.8 KiB
Rust

/* 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 https://mozilla.org/MPL/2.0/. */
#![deny(unsafe_code)]
use std::cell::RefCell;
use std::ffi::c_void;
use std::rc::Rc;
use euclid::default::Size2D;
use surfman::chains::{PreserveBuffer, SwapChain};
use surfman::{
Adapter, Connection, Context, ContextAttributeFlags, ContextAttributes, Device, Error, GLApi,
GLVersion, NativeContext, NativeDevice, NativeWidget, Surface, SurfaceAccess, SurfaceInfo,
SurfaceTexture, SurfaceType,
};
/// A bridge between webrender and surfman
// TODO: move this into a different crate so that script doesn't depend on surfman
#[derive(Clone)]
pub struct WebrenderSurfman(Rc<WebrenderSurfmanData>);
struct WebrenderSurfmanData {
device: RefCell<Device>,
context: RefCell<Context>,
// We either render to a swap buffer or to a native widget
swap_chain: Option<SwapChain<Device>>,
}
impl Drop for WebrenderSurfmanData {
fn drop(&mut self) {
let ref mut device = self.device.borrow_mut();
let ref mut context = self.context.borrow_mut();
if let Some(ref swap_chain) = self.swap_chain {
let _ = swap_chain.destroy(device, context);
}
let _ = device.destroy_context(context);
}
}
impl WebrenderSurfman {
pub fn create(
connection: &Connection,
adapter: &Adapter,
surface_type: SurfaceType<NativeWidget>,
) -> Result<Self, Error> {
let mut device = connection.create_device(&adapter)?;
let flags = ContextAttributeFlags::ALPHA |
ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL;
let version = match connection.gl_api() {
GLApi::GLES => GLVersion { major: 3, minor: 0 },
GLApi::GL => GLVersion { major: 3, minor: 2 },
};
let context_attributes = ContextAttributes { flags, version };
let context_descriptor = device.create_context_descriptor(&context_attributes)?;
let mut context = device.create_context(&context_descriptor, None)?;
let surface_access = SurfaceAccess::GPUOnly;
let headless = match surface_type {
SurfaceType::Widget { .. } => false,
SurfaceType::Generic { .. } => true,
};
let surface = device.create_surface(&context, surface_access, surface_type)?;
device
.bind_surface_to_context(&mut context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(&mut context, &mut surface);
err
})?;
device.make_context_current(&context)?;
let swap_chain = if headless {
Some(SwapChain::create_attached(
&mut device,
&mut context,
surface_access,
)?)
} else {
None
};
let device = RefCell::new(device);
let context = RefCell::new(context);
let data = WebrenderSurfmanData {
device,
context,
swap_chain,
};
Ok(WebrenderSurfman(Rc::new(data)))
}
pub fn create_surface_texture(
&self,
surface: Surface,
) -> Result<SurfaceTexture, (Error, Surface)> {
let ref device = self.0.device.borrow();
let ref mut context = self.0.context.borrow_mut();
device.create_surface_texture(context, surface)
}
pub fn destroy_surface_texture(
&self,
surface_texture: SurfaceTexture,
) -> Result<Surface, (Error, SurfaceTexture)> {
let ref device = self.0.device.borrow();
let ref mut context = self.0.context.borrow_mut();
device.destroy_surface_texture(context, surface_texture)
}
pub fn make_gl_context_current(&self) -> Result<(), Error> {
let ref device = self.0.device.borrow();
let ref context = self.0.context.borrow();
device.make_context_current(context)
}
pub fn swap_chain(&self) -> Result<&SwapChain<Device>, Error> {
self.0.swap_chain.as_ref().ok_or(Error::WidgetAttached)
}
pub fn resize(&self, size: Size2D<i32>) -> Result<(), Error> {
let ref mut device = self.0.device.borrow_mut();
let ref mut context = self.0.context.borrow_mut();
if let Some(swap_chain) = self.0.swap_chain.as_ref() {
return swap_chain.resize(device, context, size);
}
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.resize_surface(context, &mut surface, size)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
}
pub fn present(&self) -> Result<(), Error> {
let ref mut device = self.0.device.borrow_mut();
let ref mut context = self.0.context.borrow_mut();
if let Some(ref swap_chain) = self.0.swap_chain {
return swap_chain.swap_buffers(device, context, PreserveBuffer::No);
}
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.present_surface(context, &mut surface)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
}
/// Invoke a closure with the surface associated with the current front buffer.
/// This can be used to create a surfman::SurfaceTexture to blit elsewhere.
pub fn with_front_buffer<F: FnMut(&Device, Surface) -> Surface>(&self, mut f: F) {
let ref mut device = self.0.device.borrow_mut();
let ref mut context = self.0.context.borrow_mut();
let surface = device
.unbind_surface_from_context(context)
.unwrap()
.unwrap();
let surface = f(device, surface);
device.bind_surface_to_context(context, surface).unwrap();
}
pub fn device(&self) -> std::cell::Ref<Device> {
self.0.device.borrow()
}
pub fn connection(&self) -> Connection {
let ref device = self.0.device.borrow();
device.connection()
}
pub fn adapter(&self) -> Adapter {
let ref device = self.0.device.borrow();
device.adapter()
}
pub fn native_context(&self) -> NativeContext {
let ref device = self.0.device.borrow();
let ref context = self.0.context.borrow();
device.native_context(context)
}
pub fn native_device(&self) -> NativeDevice {
let ref device = self.0.device.borrow();
device.native_device()
}
pub fn context_attributes(&self) -> ContextAttributes {
let ref device = self.0.device.borrow();
let ref context = self.0.context.borrow();
let ref descriptor = device.context_descriptor(context);
device.context_descriptor_attributes(descriptor)
}
pub fn context_surface_info(&self) -> Result<Option<SurfaceInfo>, Error> {
let ref device = self.0.device.borrow();
let ref context = self.0.context.borrow();
device.context_surface_info(context)
}
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
let ref device = self.0.device.borrow();
device.surface_info(surface)
}
pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 {
let ref device = self.0.device.borrow();
device.surface_texture_object(surface)
}
pub fn get_proc_address(&self, name: &str) -> *const c_void {
let ref device = self.0.device.borrow();
let ref context = self.0.context.borrow();
device.get_proc_address(context, name)
}
pub fn unbind_native_surface_from_context(&self) -> Result<(), Error> {
let device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut();
let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap();
let _ = device.destroy_surface(&mut context, &mut surface)?;
Ok(())
}
pub fn bind_native_surface_to_context(&self, native_widget: NativeWidget) -> Result<(), Error> {
let mut device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut();
let surface_access = SurfaceAccess::GPUOnly;
let surface_type = SurfaceType::Widget { native_widget };
let surface = device.create_surface(&context, surface_access, surface_type)?;
device
.bind_surface_to_context(&mut context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(&mut context, &mut surface);
err
})?;
device.make_context_current(&context)?;
Ok(())
}
}