aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2018-10-17 23:31:22 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2018-10-17 23:31:22 +0200
commit0b048ab5f9abb717707a6c2c279ef927f23b4c87 (patch)
treec54cd2f94e0ba54018e90ba8f1303f92d7f539da
parentf91b14bbb0b6f3b5833ca5bb308ee1917f3abb10 (diff)
downloadd2tk-0b048ab5f9abb717707a6c2c279ef927f23b4c87.tar.xz
fbdev: prototype graphical part of fbdev frontend.
-rw-r--r--VERSION2
-rw-r--r--d2tk/frontend_fbdev.h58
-rw-r--r--example/d2tk_fbdev.c67
-rw-r--r--example/d2tk_pugl.c73
-rw-r--r--example/example.c (renamed from d2tk.c)81
-rw-r--r--example/example.h34
-rw-r--r--meson.build30
-rw-r--r--src/frontend_fbdev.c271
8 files changed, 542 insertions, 74 deletions
diff --git a/VERSION b/VERSION
index 50d744d..0dc7062 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.369
+0.1.371
diff --git a/d2tk/frontend_fbdev.h b/d2tk/frontend_fbdev.h
new file mode 100644
index 0000000..291c03d
--- /dev/null
+++ b/d2tk/frontend_fbdev.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#ifndef _D2TK_FRONTEND_FBDEV_H
+#define _D2TK_FRONTEND_FBDEV_H
+
+#include <d2tk/base.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*d2tk_fbdev_expose_t)(void *data, d2tk_coord_t w, d2tk_coord_t h);
+
+typedef struct _d2tk_fbdev_t d2tk_fbdev_t;
+typedef struct _d2tk_fbdev_config_t d2tk_fbdev_config_t;
+
+struct _d2tk_fbdev_config_t {
+ const char *device;
+ const char *bundle_path;
+ d2tk_fbdev_expose_t expose;
+ void *data;
+};
+
+D2TK_API d2tk_fbdev_t *
+d2tk_fbdev_new(const d2tk_fbdev_config_t *config);
+
+D2TK_API void
+d2tk_fbdev_free(d2tk_fbdev_t *dfbdev);
+
+D2TK_API int
+d2tk_fbdev_step(d2tk_fbdev_t *dfbdev);
+
+D2TK_API void
+d2tk_fbdev_run(d2tk_fbdev_t *dfbdev);
+
+D2TK_API d2tk_base_t *
+d2tk_fbdev_get_base(d2tk_fbdev_t *dfbdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _D2TK_FRONTEND_FBDEV_H
diff --git a/example/d2tk_fbdev.c b/example/d2tk_fbdev.c
new file mode 100644
index 0000000..17876fb
--- /dev/null
+++ b/example/d2tk_fbdev.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <d2tk/frontend_fbdev.h>
+#include "example/example.h"
+
+typedef struct _app_t app_t;
+
+struct _app_t {
+ d2tk_fbdev_t *fbdev;
+};
+
+static inline int
+_expose(void *data, d2tk_coord_t w, d2tk_coord_t h)
+{
+ app_t *app = data;
+ d2tk_fbdev_t *fbdev = app->fbdev;
+ d2tk_base_t *base = d2tk_fbdev_get_base(fbdev);
+
+ d2tk_example(base, w, h);
+
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+ static app_t app;
+ int ret = EXIT_FAILURE;
+
+ const d2tk_fbdev_config_t config = {
+ .device = "/dev/fb0",
+ .bundle_path = "./",
+ .expose = _expose,
+ .data = &app
+ };
+
+ app.fbdev = d2tk_fbdev_new(&config);
+ if(app.fbdev)
+ {
+ d2tk_fbdev_run(app.fbdev);
+
+ d2tk_fbdev_free(app.fbdev);
+
+ ret = EXIT_SUCCESS;
+ }
+
+ return ret;
+}
diff --git a/example/d2tk_pugl.c b/example/d2tk_pugl.c
new file mode 100644
index 0000000..3878b51
--- /dev/null
+++ b/example/d2tk_pugl.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <d2tk/frontend_pugl.h>
+#include "example/example.h"
+
+typedef struct _app_t app_t;
+
+struct _app_t {
+ d2tk_pugl_t *dpugl;
+};
+
+static int
+_expose(void *data, d2tk_coord_t w, d2tk_coord_t h)
+{
+ app_t *app = data;
+ d2tk_pugl_t *dpugl = app->dpugl;
+ d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
+
+ d2tk_example(base, w, h);
+
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+ static app_t app;
+ int ret = EXIT_FAILURE;
+
+ const d2tk_pugl_config_t config = {
+ .parent = 0,
+ .bundle_path = "./",
+ .min_w = 640,
+ .min_h = 360,
+ .w = 1280,
+ .h = 720,
+ .fixed_size = false,
+ .fixed_aspect = false,
+ .expose = _expose,
+ .data = &app
+ };
+
+ app.dpugl = d2tk_pugl_new(&config, NULL);
+ if(app.dpugl)
+ {
+ d2tk_pugl_run(app.dpugl);
+
+ d2tk_pugl_free(app.dpugl);
+
+ ret = EXIT_SUCCESS;
+ }
+
+ return ret;
+}
diff --git a/d2tk.c b/example/example.c
index 8bdc555..c9953dc 100644
--- a/d2tk.c
+++ b/example/example.c
@@ -20,8 +20,8 @@
#include <inttypes.h>
#include <d2tk/frontend_pugl.h>
+#include "example/example.h"
-typedef struct _app_t app_t;
typedef union _val_t val_t;
union _val_t {
@@ -33,10 +33,6 @@ union _val_t {
char s [32];
};
-struct _app_t {
- d2tk_pugl_t *dpugl;
-};
-
typedef enum _bar_t {
BAR_MIX,
BAR_SEQ,
@@ -55,13 +51,11 @@ static const char *bar_lbl [BAR_MAX] = {
};
static inline void
-_render_c_mix(app_t *app, const d2tk_rect_t *rect)
+_render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
{
#define N 12
#define M 24
static val_t value [N*M];
- d2tk_pugl_t *dpugl = app->dpugl;
- d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
D2TK_BASE_TABLE(rect, N, M, tab)
{
@@ -193,13 +187,11 @@ _render_c_mix(app_t *app, const d2tk_rect_t *rect)
}
static inline void
-_render_c_seq(app_t *app, const d2tk_rect_t *rect)
+_render_c_seq(d2tk_base_t *base, const d2tk_rect_t *rect)
{
#define N (8*12)
const unsigned M = N * rect->h / rect->w;
static val_t value [N*N];
- d2tk_pugl_t *dpugl = app->dpugl;
- d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
d2tk_style_t style = *d2tk_base_get_default_style();
style.border_width = 1;
@@ -244,14 +236,12 @@ _render_c_seq(app_t *app, const d2tk_rect_t *rect)
}
static inline void
-_render_c_scroll(app_t *app, const d2tk_rect_t *rect)
+_render_c_scroll(d2tk_base_t *base, const d2tk_rect_t *rect)
{
#define N 12 // number of columns
#define N_2 (N / 2) // number of visible columns
#define M 512// total elements
#define O 24 // elements per page
- d2tk_pugl_t *dpugl = app->dpugl;
- d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
d2tk_style_t style = *d2tk_base_get_default_style();
@@ -308,11 +298,8 @@ _render_c_scroll(app_t *app, const d2tk_rect_t *rect)
}
static inline void
-_render_c_pane(app_t *app, const d2tk_rect_t *rect)
+_render_c_pane(d2tk_base_t *base, const d2tk_rect_t *rect)
{
- d2tk_pugl_t *dpugl = app->dpugl;
- d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
-
D2TK_BASE_PANE(base, rect, D2TK_ID, D2TK_FLAG_PANE_X, 0.1f, 0.9f, hpane)
{
const d2tk_rect_t *hrect_1st = d2tk_pane_get_rect_1st(hpane);
@@ -342,13 +329,9 @@ _render_c_pane(app_t *app, const d2tk_rect_t *rect)
}
}
-static inline void
-_render_c(void *data, d2tk_coord_t w, d2tk_coord_t h)
+void
+d2tk_example(d2tk_base_t *base, d2tk_coord_t w, d2tk_coord_t h)
{
- app_t *app = data;
- d2tk_pugl_t *dpugl = app->dpugl;
- d2tk_base_t *base = d2tk_pugl_get_base(dpugl);
-
const d2tk_coord_t bw = w / BAR_MAX;
const d2tk_coord_t bh = h / 20;
@@ -372,19 +355,19 @@ _render_c(void *data, d2tk_coord_t w, d2tk_coord_t h)
{
case BAR_MIX:
{
- _render_c_mix(app, &rect);
+ _render_c_mix(base, &rect);
} break;
case BAR_SEQ:
{
- _render_c_seq(app, &rect);
+ _render_c_seq(base, &rect);
} break;
case BAR_SCROLL:
{
- _render_c_scroll(app, &rect);
+ _render_c_scroll(base, &rect);
} break;
case BAR_PANE:
{
- _render_c_pane(app, &rect);
+ _render_c_pane(base, &rect);
} break;
case BAR_MAX:
@@ -396,45 +379,3 @@ _render_c(void *data, d2tk_coord_t w, d2tk_coord_t h)
}
}
}
-
-static inline int
-_expose(void *data, d2tk_coord_t w, d2tk_coord_t h)
-{
- app_t *app = data;
-
- _render_c(app, w, h);
-
- return EXIT_SUCCESS;
-}
-
-int
-main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
-{
- static app_t app;
- int ret = EXIT_FAILURE;
-
- const d2tk_pugl_config_t config = {
- .parent = 0,
- .bundle_path = "./",
- .min_w = 640,
- .min_h = 360,
- .w = 1280,
- .h = 720,
- .fixed_size = false,
- .fixed_aspect = false,
- .expose = _expose,
- .data = &app
- };
-
- app.dpugl = d2tk_pugl_new(&config, NULL);
- if(app.dpugl)
- {
- d2tk_pugl_run(app.dpugl);
-
- d2tk_pugl_free(app.dpugl);
-
- ret = EXIT_SUCCESS;
- }
-
- return ret;
-}
diff --git a/example/example.h b/example/example.h
new file mode 100644
index 0000000..477b386
--- /dev/null
+++ b/example/example.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#ifndef _D2TK_EXAMPLE_H
+#define _D2TK_EXAMPLE_H
+
+#include <d2tk/base.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+d2tk_example(d2tk_base_t *base, d2tk_coord_t w, d2tk_coord_t h);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _D2TK_EXAMPLE_H
diff --git a/meson.build b/meson.build
index 28aa6f4..8a820c7 100644
--- a/meson.build
+++ b/meson.build
@@ -45,9 +45,20 @@ lib_srcs = [
join_paths('src', 'core.c'),
join_paths('src', 'base.c'),
join_paths('src', 'frontend_pugl.c'),
+ join_paths('src', 'frontend_fbdev.c'),
]
-bin_srcs = 'd2tk.c'
+bin_srcs = [
+ join_paths('example', 'example.c')
+]
+
+pugl_srcs = [
+ join_paths('example', 'd2tk_pugl.c')
+]
+
+fbdev_srcs = [
+ join_paths('example', 'd2tk_fbdev.c')
+]
cp = find_program('cp')
clone = [cp, '@INPUT@', '@OUTPUT@']
@@ -86,7 +97,20 @@ if pixman_dep.found() and cairo_dep.found() and (host_machine.system() == 'linux
link_args : links,
sources : cairo_srcs)
- executable('d2tk.cairo', bin_srcs,
+ executable('d2tk.cairo', [bin_srcs, pugl_srcs],
+ c_args : c_args,
+ include_directories : inc_dir,
+ dependencies: d2tk_cairo,
+ install : true,
+ install_dir : get_option('bindir'))
+
+ d2tk_fbdev = declare_dependency(
+ include_directories : inc_dir,
+ dependencies : [deps, pixman_dep, cairo_dep],
+ link_args : links,
+ sources : cairo_srcs)
+
+ executable('d2tk.fbdev', [bin_srcs, fbdev_srcs],
c_args : c_args,
include_directories : inc_dir,
dependencies: d2tk_cairo,
@@ -106,7 +130,7 @@ d2tk_nanovg = declare_dependency(
link_args : links,
sources : nanovg_srcs)
-executable('d2tk.nanovg', bin_srcs,
+executable('d2tk.nanovg', [bin_srcs, pugl_srcs],
c_args : c_args,
include_directories : inc_dir,
dependencies: d2tk_nanovg,
diff --git a/src/frontend_fbdev.c b/src/frontend_fbdev.c
new file mode 100644
index 0000000..08e6e7a
--- /dev/null
+++ b/src/frontend_fbdev.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <fcntl.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stropts.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include <cairo/cairo.h>
+
+#include "core_internal.h"
+#include <d2tk/frontend_fbdev.h>
+
+#include <d2tk/backend.h>
+
+struct _d2tk_fbdev_t {
+ const d2tk_fbdev_config_t *config;
+ bool done;
+ int fd;
+ uint8_t *data;
+ size_t screensize;
+ struct fb_var_screeninfo vinfo;
+ struct fb_fix_screeninfo finfo;
+ d2tk_base_t *base;
+ void *ctx;
+};
+
+static int
+_d2tk_fbdev_sync(d2tk_fbdev_t *fbdev)
+{
+ int dummy = 0;
+
+ if(ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &dummy))
+ {
+ fprintf(stderr, "Error waiting for VSYNC\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+_d2tk_fbdev_destroy(void *data)
+{
+ d2tk_fbdev_t *fbdev = data;
+
+ if(fbdev == NULL)
+ {
+ return;
+ }
+
+ munmap(fbdev->data, fbdev->screensize);
+ fbdev->data = NULL;
+
+ close(fbdev->fd);
+ fbdev->fd = -1;
+}
+
+static cairo_surface_t *
+_d2tk_fbdev_create(d2tk_fbdev_t *fbdev, const char *name)
+{
+ cairo_surface_t *surface;
+
+ // Open the file for reading and writing
+ fbdev->fd = open(name, O_RDWR);
+ if (fbdev->fd == -1) {
+ perror("Error: cannot open framebuffer fbdev");
+ goto handle_allocate_error;
+ }
+
+ // Get variable screen information
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->vinfo) == -1) {
+ perror("Error: reading variable information");
+ goto handle_ioctl_error;
+ }
+
+ // Get fixed screen information
+ if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo) == -1) {
+ perror("Error reading fixed information");
+ goto handle_ioctl_error;
+ }
+
+ // Map the fbdev to memory
+ fbdev->data = (uint8_t *)mmap(0, fbdev->finfo.smem_len,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fbdev->fd, 0);
+ if ((intptr_t)fbdev->data == -1) {
+ perror("Error: failed to map framebuffer fbdev to memory");
+ goto handle_ioctl_error;
+ }
+
+
+ /* Create the cairo surface which will be used to draw to */
+ surface = cairo_image_surface_create_for_data(fbdev->data,
+ CAIRO_FORMAT_RGB24,
+ fbdev->vinfo.xres_virtual,
+ fbdev->vinfo.yres_virtual,
+ fbdev->finfo.smem_len / fbdev->vinfo.yres_virtual);
+
+ cairo_surface_set_user_data(surface, NULL, fbdev,
+ &_d2tk_fbdev_destroy);
+
+ return surface;
+
+handle_ioctl_error:
+ close(fbdev->fd);
+handle_allocate_error:
+ free(fbdev);
+ exit(1);
+}
+
+static inline void
+_d2tk_fbdev_close(d2tk_fbdev_t *fbdev)
+{
+ fbdev->done = true;
+}
+
+static inline void
+_d2tk_fbdev_expose(d2tk_fbdev_t *fbdev)
+{
+ d2tk_base_t *base = fbdev->base;
+
+ d2tk_coord_t w;
+ d2tk_coord_t h;
+ d2tk_base_get_dimensions(base, &w, &h);
+
+ d2tk_base_pre(base);
+
+ fbdev->config->expose(fbdev->config->data, w, h);
+
+ d2tk_base_post(base);
+
+ if(d2tk_base_get_again(base))
+ {
+ //FIXME
+ }
+
+ _d2tk_fbdev_sync(fbdev);
+}
+
+D2TK_API int
+d2tk_fbdev_step(d2tk_fbdev_t *fbdev)
+{
+ _d2tk_fbdev_expose(fbdev);
+
+ return fbdev->done;
+}
+
+D2TK_API void
+d2tk_fbdev_run(d2tk_fbdev_t *fbdev)
+{
+ const unsigned step = 1000000000 / 24;
+ struct timespec to;
+ clock_gettime(CLOCK_MONOTONIC, &to);
+
+ while(true)
+ {
+ if(clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, NULL))
+ {
+ continue;
+ }
+
+ to.tv_nsec += step;
+ while(to.tv_nsec >= 1000000000)
+ {
+ to.tv_sec += 1;
+ to.tv_nsec -= 1000000000;
+ }
+
+ if(d2tk_fbdev_step(fbdev))
+ {
+ break;
+ }
+ }
+}
+
+D2TK_API void
+d2tk_fbdev_free(d2tk_fbdev_t *fbdev)
+{
+ if(fbdev->ctx)
+ {
+ if(fbdev->base)
+ {
+ d2tk_base_free(fbdev->base);
+ }
+ d2tk_core_driver.free(fbdev->ctx);
+ }
+
+ //FIXME fbdevDestroy(fbdev->view);
+
+ free(fbdev);
+}
+
+D2TK_API d2tk_fbdev_t *
+d2tk_fbdev_new(const d2tk_fbdev_config_t *config)
+{
+ d2tk_fbdev_t *fbdev = calloc(1, sizeof(d2tk_fbdev_t));
+ if(!fbdev)
+ {
+ goto fail;
+ }
+
+ fbdev->config = config;
+
+ cairo_surface_t *surf = _d2tk_fbdev_create(fbdev, fbdev->config->device);
+ cairo_t *ctx = cairo_create(surf);
+
+ //FIXME
+ //cairo_destroy(ctx);
+ //cairo_surface_destroy(surf);
+
+ fbdev->ctx = d2tk_core_driver.new(config->bundle_path, ctx);
+
+ if(!fbdev->ctx)
+ {
+ goto fail;
+ }
+
+ fbdev->base = d2tk_base_new(&d2tk_core_driver, fbdev->ctx);
+ if(!fbdev->base)
+ {
+ goto fail;
+ }
+
+ d2tk_base_set_dimensions(fbdev->base, 1280, 1024); //FIXME
+
+ return fbdev;
+
+fail:
+ if(fbdev)
+ {
+ if(fbdev->ctx)
+ {
+ d2tk_core_driver.free(fbdev->ctx);
+ }
+
+ //FIXME
+
+ free(fbdev);
+ }
+
+ return NULL;
+}
+
+D2TK_API d2tk_base_t *
+d2tk_fbdev_get_base(d2tk_fbdev_t *fbdev)
+{
+ return fbdev->base;
+}