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

Default cairo #55

Merged
merged 12 commits into from
Oct 21, 2023
Merged
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
key: ${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }}

- name: Install build-deps
run: sudo apt update && sudo apt-get install -y build-essential libglfw3 libglfw3-dev libglew2.2 libglew-dev
run: sudo apt update && sudo apt-get install -y build-essential libgtk-3-0 libgtk-3-dev libsystemd-dev libwebp-dev libzstd-dev

- name: Install Dependencies
run: |
Expand Down
130 changes: 54 additions & 76 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,36 +1,7 @@
# Variables to override
#
# CC C compiler
# CROSSCOMPILE crosscompiler prefix, if any
# CFLAGS compiler flags for compiling all C files
# ERL_CFLAGS additional compiler flags for files using Erlang header files
# ERL_EI_INCLUDE_DIR include path to ei.h (Required for crosscompile)
# ERL_EI_LIBDIR path to libei.a (Required for crosscompile)
# LDFLAGS linker flags for linking all binaries
# ERL_LDFLAGS additional linker flags for projects referencing Erlang libraries


MIX = mix
PREFIX = $(MIX_APP_PATH)/priv
DEFAULT_TARGETS ?= $(PREFIX) $(PREFIX)/scenic_driver_local

# # Look for the EI library and header files
# # For crosscompiled builds, ERL_EI_INCLUDE_DIR and ERL_EI_LIBDIR must be
# # passed into the Makefile.
# ifeq ($(ERL_EI_INCLUDE_DIR),)
# ERL_ROOT_DIR = $(shell erl -eval "io:format(\"~s~n\", [code:root_dir()])" -s init stop -noshell)
# ifeq ($(ERL_ROOT_DIR),)
# $(error Could not find the Erlang installation. Check to see that 'erl' is in your PATH)
# endif
# ERL_EI_INCLUDE_DIR = "$(ERL_ROOT_DIR)/usr/include"
# ERL_EI_LIBDIR = "$(ERL_ROOT_DIR)/usr/lib"
# endif

# # Set Erlang-specific compile and linker flags
# ERL_CFLAGS ?= -I$(ERL_EI_INCLUDE_DIR)
# ERL_LDFLAGS ?= -L$(ERL_EI_LIBDIR) -lei


$(info SCENIC_LOCAL_TARGET: $(SCENIC_LOCAL_TARGET))
ifdef SCENIC_LOCAL_GL
$(info SCENIC_LOCAL_GL: $(SCENIC_LOCAL_GL))
Expand Down Expand Up @@ -61,6 +32,7 @@ NVG_COMMON_SRCS = \
c_src/device/nvg/nanovg/nanovg.c \
c_src/device/nvg/nvg_font_ops.c \
c_src/device/nvg/nvg_image_ops.c \
c_src/device/nvg/nvg_scenic.c \
c_src/device/nvg/nvg_script_ops.c

CAIRO_COMMON_SRCS = \
Expand All @@ -69,7 +41,47 @@ CAIRO_COMMON_SRCS = \
c_src/device/cairo/cairo_image_ops.c \
c_src/device/cairo/cairo_script_ops.c

ifeq ($(SCENIC_LOCAL_TARGET),glfw)
ifeq ($(SCENIC_LOCAL_TARGET),cairo-gtk)
CFLAGS = -O3 -std=gnu99

ifndef MIX_ENV
MIX_ENV = dev
endif

ifdef DEBUG
CFLAGS += -O0 -pedantic -Wall -Wextra -Wno-unused-parameter
endif

ifeq ($(MIX_ENV),dev)
CFLAGS += -g
endif

LDFLAGS += `pkg-config --static --libs freetype2 cairo gtk+-3.0`
CFLAGS += `pkg-config --static --cflags freetype2 cairo gtk+-3.0`
LDFLAGS += -lm

DEVICE_SRCS += \
$(CAIRO_COMMON_SRCS) \
c_src/device/cairo/cairo_gtk.c

else ifeq ($(SCENIC_LOCAL_TARGET),cairo-fb)
LDFLAGS += `pkg-config --static --libs freetype2 cairo`
CFLAGS += `pkg-config --static --cflags freetype2 cairo`
LDFLAGS += -lm
CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
CFLAGS += -std=gnu99

DEVICE_SRCS += \
$(CAIRO_COMMON_SRCS) \
c_src/device/cairo/cairo_fb.c

else ifeq ($(SCENIC_LOCAL_TARGET),glfw)
$(info )
$(info **********************************************************************************)
$(info SCENIC_LOCAL_TARGET=glfw is deprecated. Please use `SCENIC_LOCAL_TARGET=cairo-gtk`)
$(info **********************************************************************************)
$(info )

CFLAGS = -O3 -std=c99

ifndef MIX_ENV
Expand Down Expand Up @@ -102,6 +114,12 @@ ifeq ($(SCENIC_LOCAL_TARGET),glfw)
c_src/device/nvg/glfw.c

else ifeq ($(SCENIC_LOCAL_TARGET),bcm)
$(info )
$(info ********************************************************************************)
$(info SCENIC_LOCAL_TARGET=bcm is deprecated. Please use `SCENIC_LOCAL_TARGET=cairo-fb`)
$(info ********************************************************************************)
$(info )

LDFLAGS += -lGLESv2 -lEGL -lm -lvchostif -lbcm_host
CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
CFLAGS += -std=gnu99
Expand All @@ -117,7 +135,12 @@ else ifeq ($(SCENIC_LOCAL_TARGET),bcm)
endif

else ifeq ($(SCENIC_LOCAL_TARGET),drm)
# drm is the forward looking default
$(info )
$(info ********************************************************************************)
$(info SCENIC_LOCAL_TARGET=drm is deprecated. Please use `SCENIC_LOCAL_TARGET=cairo-fb`)
$(info ********************************************************************************)
$(info )

LDFLAGS += -lGLESv2 -lEGL -lm -lvchostif -ldrm -lgbm
CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
CFLAGS += -std=gnu99
Expand All @@ -133,53 +156,8 @@ else ifeq ($(SCENIC_LOCAL_TARGET),drm)
CFLAGS += -DSCENIC_GLES3
endif

else ifeq ($(SCENIC_LOCAL_TARGET),cairo-fb)
LDFLAGS += `pkg-config --static --libs freetype2 cairo`
CFLAGS += `pkg-config --static --cflags freetype2 cairo`
LDFLAGS += -lm
CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
CFLAGS += -std=gnu99

DEVICE_SRCS += \
$(CAIRO_COMMON_SRCS) \
c_src/device/cairo/cairo_fb.c

else ifeq ($(SCENIC_LOCAL_TARGET),cairo-gtk)
LDFLAGS += `pkg-config --static --libs freetype2 cairo gtk+-3.0`
CFLAGS += `pkg-config --static --cflags freetype2 cairo gtk+-3.0`
LDFLAGS += -lm
CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
CFLAGS += -std=gnu99

DEVICE_SRCS += \
$(CAIRO_COMMON_SRCS) \
c_src/device/cairo/cairo_gtk.c
else
$(info ------ no SCENIC_LOCAL_TARGET set ------)
$(info If you get here, then you are probably using a custom Nerves system)
$(info Please export/set SCENIC_LOCAL_TARGET to one of [glfw, bcm, drm])
$(info If you are running on a desktop machine, pick: glfw)
$(info For any varient of rpi <= 3, pick: bcm)
$(info For any varient of rpi >= 4, pick: drm)
$(info For any varient of bbb, pick: drm)
$(info example for a custom rpi3 build system:)
$(info export SCENIC_LOCAL_TARGET=bcm)
$(info For bbb, you also need to set SCENIC_LOCAL_GL=gles2)
$(info For >= rpi4, you also need to set SCENIC_LOCAL_GL=gles3)
$(info ----------------------------------------)
endif

# ifeq ($(SCENIC_LOCAL_TARGET),drm_gles3)
# LDFLAGS += -lGLESv2 -lEGL -lm -lvchostif -ldrm -lgbm
# CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter -pedantic
# CFLAGS += -std=gnu99

# CFLAGS += -fPIC -I$(NERVES_SDK_SYSROOT)/usr/include/drm

# SRCS = c_src/device/drm_gles3.c
# endif

# $(info $(shell printenv))
CFLAGS += \
-Ic_src \
-Ic_src/device \
Expand Down
64 changes: 14 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,75 +37,39 @@ There are quite a few new options as well. It uses `NimbleOptions` to confirm th

## Targets

This driver does its best to figure out what underlying graphics technology to use depending on what your MIX_TARGET is set to.
This driver figures out what underlying graphics technology to use depending on what your MIX_TARGET is set to.

For example, for apps running on a Mac/PC/Linux, it is usually set to `host`, which causes the driver to use `glfw` as the underlying tech.
For example, for apps running on a Mac/PC/Linux, it is usually set to `host`, which causes the driver to use `cairo-gtk` as the underlying tech.

If you are building for Nerves, it will use `bcm` (Broadcom Manager) for any of `rpi`, `rpi0`, `rip2`, `rpi3`, and `rpi3a`.
If you are building for Nerves, it will use `cairo-fb`

### Cairo
There is now a rendering backend to use `cairo`. You can set SCENIC_LOCAL_TARGET to `cairo-fb` which renders to `/dev/fb0` on an embedded device or `cairo-gtk` which renders to a window on a host (as an alternative to `glfw`).
Previous versions of `scenic_driver_local` would use `bcm` (Broadcom Manager) for any of `rpi`, `rpi0`, `rip2`, `rpi3`, and `rpi3a` and `drm` for `bbb` and `rpi4`.
You can explicitly use thes by setting `SCENIC_LOCAL_TARGET=bcm` or `SCENIC_LOCAL_TARGET=drm`, **but these options are being deprecated**.
Please try the default of `SCENIC_LOCAL_TARGET=cairo-fb` as this should work universally on any Nerves target.

`cairo-fb` will require that your `nerves_system_*` has the `cairo` library selected.

### Nerves rpi4 & bbb Need Work / Help
`Scenic.Driver.Local` uses `drm` (Direct Render Manager) for the `rpi4` and `bbb`. It currently renders on the rpi4, but is __very slow__. I haven't figured out why yet and if anyone wants to dig in, that would be appreciated. It should be really fast, so is probably a hardware configuration issue.

The `bbb` doesn't work (is close in theory??) as the Nerves `bbb` system doesn't have the needed graphics support in it yet. There are others who have gotten SGX support working for the `bbb` and I could use some help from them.

Please try using `cairo-fb` to see if it will work for you on `rpi4` or `bbb`.

### Custom Nerves Targets
For custom systems (example - figuring out how to add SGX support to the `bbb`) You will need to set SCENIC_LOCAL_TARGET manually. You may also need to set the SCENIC_LOCAL_GL as well.

example in your command line

```
export SCENIC_LOCAL_TARGET=drm
export SCENIC_LOCAL_GL=gles3
```

These options may change, especially as we sort out the issues on the `rpi4` and the `bbb`. If SCENIC_LOCAL_TARGET isn't set, then look in the build output for instructions.


## Prerequisites

This driver requires Scenic v0.11 or up.

### Installing on MacOS

The easiest way to install on MacOS is to use Homebrew. Just run the following in a terminal:

```bash
brew update
brew install glfw3 glew pkg-config
```
You will need to install [XQuartz](https://www.xquartz.org/) on macOS.


Once these components have been installed, you should be able to build the `scenic_driver_local` driver.

### Installing on Ubuntu 18.04

The easiest way to install on Ubuntu is to use apt-get. Just run the following:
The easiest way to install needed build time dependencies on MacOS is to use Homebrew. Just run the following in a terminal:

```bash
apt-get update
apt-get install pkgconf libglfw3 libglfw3-dev libglew2.0 libglew-dev
brew update
brew install gtk+3 cairo pkg-config
```

Once these components have been installed, you should be able to build the `scenic_driver_local` driver.

### Installing on Ubuntu 20.04
### Installing on Ubuntu

The easiest way to install on Ubuntu is to use apt-get. Just run the following:

For `glfw`:
```bash
apt-get update
apt-get install pkgconf libglfw3 libglfw3-dev libglew2.1 libglew-dev
```

For `cairo-gtk`:
```bash
apt-get update
apt-get install pkgconf libgtk-3-0 libgtk-3-dev libsystemd-dev libwebp-dev libzstd-dev
Expand All @@ -120,13 +84,13 @@ The easiest way to install on Arch Linux is to use pacman. Just run the followin

```bash
pacman -Syu
sudo pacman -S glfw-x11 glew
sudo pacman -S cairo gtk3
```

If you're using Wayland, you'll probably need `glfw-wayland` instead of `glfw-x11` and `glew-wayland` instead of `glew`

### Installing on Windows

**This section needs help updating for cairo support**

First, make sure to have installed Visual Studio with its "Desktop development with C++" package.

Next, you need to download the Windows binaries for [GLFW](https://www.glfw.org/download.html) and [GLEW](http://glew.sourceforge.net/index.html) manually.
Expand Down
6 changes: 6 additions & 0 deletions c_src/device/cairo/cairo_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "comms.h"
#include "device.h"
#include "fontstash.h"
#include "scenic_ops.h"

const char* device = "/dev/fb0";

Expand Down Expand Up @@ -328,3 +329,8 @@ void device_end_render(driver_data_t* p_data)
render_cairo_surface_to_fb(p_ctx);
}

void device_loop(driver_data_t* p_data)
{
scenic_loop(p_data);
}

23 changes: 11 additions & 12 deletions c_src/device/cairo/cairo_gtk.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
Expand All @@ -14,6 +13,7 @@
#include "comms.h"
#include "device.h"
#include "fontstash.h"
#include "scenic_ops.h"
#include "script_ops.h"

typedef struct {
Expand All @@ -29,14 +29,6 @@ cairo_gtk_t g_cairo_gtk;
extern device_info_t g_device_info;
extern device_opts_t g_opts;

static gpointer cairo_gtk_main(gpointer user_data)
{
gtk_widget_show_all((GtkWidget*)g_cairo_gtk.window);
gtk_main();

return NULL;
}

static gboolean on_draw(GtkWidget* widget,
cairo_t* cr,
gpointer data)
Expand Down Expand Up @@ -155,8 +147,6 @@ int device_init(const device_opts_t* p_opts,
gtk_container_add(GTK_CONTAINER(g_cairo_gtk.window), (GtkWidget*)drawing_area);
g_signal_connect((GtkWidget*)drawing_area, "draw", G_CALLBACK(on_draw), p_ctx);

g_cairo_gtk.main = g_thread_new("gtk_main", cairo_gtk_main, NULL);

return 0;
}

Expand All @@ -168,8 +158,9 @@ int device_close(device_info_t* p_info)

scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)p_info->v_ctx;
gtk_main_quit();
g_thread_join(g_cairo_gtk.main);
scenic_cairo_fini(p_ctx);

return 0;
}

void device_poll()
Expand Down Expand Up @@ -211,3 +202,11 @@ void device_end_render(driver_data_t* p_data)

g_idle_add((GSourceFunc)gtk_widget_queue_draw, (void*)g_cairo_gtk.window);
}

void device_loop(driver_data_t* p_data)
{
g_cairo_gtk.main = g_thread_new("scenic_loop", scenic_loop, p_data);

gtk_widget_show_all((GtkWidget*)g_cairo_gtk.window);
gtk_main();
}
Loading