mono/SkiaSharp

Targetting linux-arm - and Linux in general.

maitredede opened this issue · 15 comments

Hi,

I was reading the issue about System.Drawing for dotnet core, and someone suggested to use SkiaSharp for it.
So I have looked at SkiaSharp for a possible usage in my code, on a Raspberry Pi.

Does SkiaSharp run on linux-arm target ? I am writing apps on netstandard2.0 running on RaspberryPi.

It should, but you will need to compile the unmanaged library yourself

Hijacking this bug to discuss a possible approach for Linux.

It is unlikely that we will be able to get NuGet to properly support all the ways to distribute the native payloads. I think that we should go ahead and create .deb and .rpm definition files and use something like https://build.opensuse.org/ to build those packages.

We would then require users of Skiasharp to install the separate payload on their systems.

@migueldeicaza I don't quite understand why it's not viable to statically link everything except glibc and libfontconfig. We had some success with this approach in our package with x64 binaries (I've compiled it against glibc 2.14), it works quite well across the Linux distros. The only downside is that some distros like Alpine are using different C library, but there are compatibility layers available.
The same could be done for ARM, the only problem is the lack of prebuilt depot tools, so cross-compilation is needed.

The answer is that the devil is in the details, and without a full infrastructure to test every part of the stack, and to test on every distribution, we might end up with just slightly broken code in some places which is very hard to debug and rectify.

We have been down this path in the Linux world many years ago, and we rather err on the side of safety and find a safe way of plugging the payload in a native way there.

As I mentioned on #18 before, I was able after lots of hackery (really A LOT) with @mattleibow to build it using a cross compiler and linking by hand lots of .a to finally get SkiaSharp native built.

I just tried now to build again (lost the "docs" we had) and doomed again. The bootstrapper.sh script is completely ignoring the cross compiler and all variables passed to it, even GYP_DEFINES.

@galvesribeiro The new version no longer uses gyp, but gn instead. You can check out what I am doing here: https://github.com/mono/SkiaSharp/blob/master/cake/BuildExternals.cake#L715

What I really now do is just build Linux as Google specifies as a static archive, and then I create a dynamic library that links out everything except what SkiaSharp uses - ie: just the public C API is preserved.

@mattleibow yeah, I noticed that... Still, it is ignoring the compiler and arch parameters we pass to it. There are a bunch of hardcoded params there. For example, the compiler params are not forwarded to the dependencies (including skia) and they try to compile for the host arch, not the target one.

After change a lot of files, the closest I got was:

========================================
externals-linux
========================================
Executing task: externals-linux
[0212/190217.034905:ERROR:process_posix.cc(192)] Not implemented reached in bool (anonymous namespace)::WaitForExitWithTimeoutImpl(base::ProcessHandle, int *, base::TimeDelta)
[0212/190217.207897:ERROR:process_posix.cc(192)] Not implemented reached in bool (anonymous namespace)::WaitForExitWithTimeoutImpl(base::ProcessHandle, int *, base::TimeDelta)
[0212/190217.501813:ERROR:process_posix.cc(192)] Not implemented reached in bool (anonymous namespace)::WaitForExitWithTimeoutImpl(base::ProcessHandle, int *, base::TimeDelta)
Done. Made 32 targets from 20 files in 713ms
ninja: Entering directory `out/linux/arm'
[35/684] compile ../../../src/effects/SkEmbossMask.cpp
FAILED: obj/src/effects/effects.SkEmbossMask.o
arm-arm1176jzs-linux-gnueabi-c++ -MMD -MF obj/src/effects/effects.SkEmbossMask.o.d -DNDEBUG -DSK_SAMPLES_FOR_X -DSK_SUPPORT_GPU=0 -DSK_GAMMA_APPLY_TO_A8 -DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=0 -DSKIA_IMPLEMENTATION=1 -I../../../include/android -I../../../include/c -I../../../include/codec -I../../../include/config -I../../../include/core -I../../../include/effects -I../../../include/encode -I../../../include/gpu -I../../../include/gpu/gl -I../../../include/pathops -I../../../include/ports -I../../../include/svg -I../../../include/utils -I../../../include/utils/mac -I../../../third_party/vulkan -I../../../include/private -I../../../src/c -I../../../src/codec -I../../../src/core -I../../../src/effects -I../../../src/effects/gradients -I../../../src/fonts -I../../../src/image -I../../../src/images -I../../../src/lazy -I../../../src/opts -I../../../src/pathops -I../../../src/pdf -I../../../src/ports -I../../../src/sfnt -I../../../src/sksl -I../../../src/utils -I../../../src/utils/win -I../../../src/xml -I../../../third_party/gif -fstrict-aliasing -fPIC -fvisibility=hidden -Werror -march=armv6j -Wall -Wextra -Winit-self -Wpointer-arith -Wsign-compare -Wvla -Wno-deprecated-declarations -Wno-maybe-uninitialized -Wno-unused-parameter -Os -fdata-sections -ffunction-sections -march=armv6j -msoft-float -mfpu=vfp -mfloat-abi=soft -DSKIA_C_DLL -funwind-tables -std=c++11 -fno-threadsafe-statics -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Wnon-virtual-dtor -c ../../../src/effects/SkEmbossMask.cpp -o obj/src/effects/effects.SkEmbossMask.o
In file included from ../../../src/effects/SkEmbossMask.cpp:10:0:
../../../include/private/SkFixed.h: In static member function 'static void SkEmbossMask::Emboss(SkMask*, const SkEmbossMaskFilter::Light&)':
../../../include/private/SkFixed.h:106:49: error: inconsistent operand constraints in an 'asm'
         asm("vcvt.s32.f32 %0, %0, #16": "+w"(x));
                                                 ^
../../../include/private/SkFixed.h:106:49: error: inconsistent operand constraints in an 'asm'
         asm("vcvt.s32.f32 %0, %0, #16": "+w"(x));
                                                 ^
../../../include/private/SkFixed.h:106:49: error: inconsistent operand constraints in an 'asm'
         asm("vcvt.s32.f32 %0, %0, #16": "+w"(x));
                                                 ^
[44/684] compile ../../../src/effects/SkLightingImageFilter.cpp
ninja: build stopped: subcommand failed.
An error occurred when executing task 'externals-linux'.
Error: One or more errors occurred.
        Process '/mnt/c/dev/repos/skiaprojects/SkiaSharp/externals/depot_tools/ninja' failed with error: 1

Hmm. I really need to get an arm linxu device.
But, while browsing for Tizen, I found this guy did something for Rasberry Pi:
https://github.com/terwoord/skiasharp-raspberry

Note the extra_asmflags... I see your error has something to do with assembly bits, maybe you need something like this? This is for an older version of Skia, but it may be something.

I will try and get an ARM Linux device for testing as soon as possible.

Actually, you don't need an ARM device. You can build on x86/x64 linux using a cross compiler toolchain and you will have that effect. My device can't build it (even if it could would take months!) so I have to crosscompile.

I can give you my toolchain if you want to. Ping me on Gitter and I can send the .tar.gz.

Just asking this question in multiple places:

Right now I have a x64 build for Linux that was compiled on Ubuntu 14.04. I am thinking of adding a few more to help the average dev use SkiaSharp without having to build their own. What other distros or CPUs would be helpful?

Leave a comment on this issue and track progress: #453

@mattleibow if you get it to build with the dependencies embedded(static linked), you can build for armv6 (no FPU) and armv7+ (with FPU). That way you would attend a wide range of ARM devices without depend on the specific distro.

@galvesribeiro What should the host be for the arm builds? Can I use Ubuntu 14.04 or is there a better one?

Yeah, you can use Ubuntu 16.04 as a build host.

What matters is have a toolchain to crosscompile capable of generate 2 builds, one for armv6 (for legacy and very embedded devices) and other for armv7+ which cover the majority of Android devices nowadays and PI2+ and its variants.

To make life easier for everyone, I moved code around and added a new target to the GN files. Now, the native libSkiaSharp build is done with GN and ninja directly: https://github.com/mono/SkiaSharp/wiki/Building-on-Linux

Closing this issue as the Linux topic is getting a bit duplicated.