From 86e71e03e1024d58cde098a68b8721c1fc0bc626 Mon Sep 17 00:00:00 2001 From: HW Date: Fri, 1 Nov 2013 18:00:07 +0100 Subject: [PATCH 01/21] add FFI linux framebuffer interface --- {include => ffi-cdecl/include}/README | 0 {include => ffi-cdecl/include}/einkfb.h | 0 {include => ffi-cdecl/include}/mxcfb.h | 21 ++- ffi-cdecl/linux_fb_decl.c | 45 ++++++ ffi-cdecl/posix_decl.c | 73 +++++++++ ffi/framebuffer.lua | 8 + ffi/framebuffer_linux.lua | 199 ++++++++++++++++++++++++ ffi/linux_fb_h.lua | 142 +++++++++++++++++ ffi/posix_h.lua | 72 +++++++++ ffi/util.lua | 31 +--- 10 files changed, 557 insertions(+), 34 deletions(-) rename {include => ffi-cdecl/include}/README (100%) rename {include => ffi-cdecl/include}/einkfb.h (100%) rename {include => ffi-cdecl/include}/mxcfb.h (91%) create mode 100644 ffi-cdecl/linux_fb_decl.c create mode 100644 ffi-cdecl/posix_decl.c create mode 100644 ffi/framebuffer.lua create mode 100644 ffi/framebuffer_linux.lua create mode 100644 ffi/linux_fb_h.lua create mode 100644 ffi/posix_h.lua diff --git a/include/README b/ffi-cdecl/include/README similarity index 100% rename from include/README rename to ffi-cdecl/include/README diff --git a/include/einkfb.h b/ffi-cdecl/include/einkfb.h similarity index 100% rename from include/einkfb.h rename to ffi-cdecl/include/einkfb.h diff --git a/include/mxcfb.h b/ffi-cdecl/include/mxcfb.h similarity index 91% rename from include/mxcfb.h rename to ffi-cdecl/include/mxcfb.h index f2ded99ab..3393b37c6 100644 --- a/include/mxcfb.h +++ b/ffi-cdecl/include/mxcfb.h @@ -9,6 +9,7 @@ * from Kindle 5.3.0 firmware. Thanks to eureka@mobileread. * http://www.mobileread.com/forums/showpost.php?p=2337118&postcount=818 * + * - Modified so that Kobo specifics are now in separately named structs * * The code contained herein is licensed under the GNU Lesser General * Public License. You may obtain a copy of the GNU Lesser General @@ -108,10 +109,14 @@ struct mxcfb_rect { #define FB_TEMP_AUTO_UPDATE_DISABLE -1 struct mxcfb_alt_buffer_data { -#ifdef KOBO_PLATFORM + __u32 phys_addr; + __u32 width; /* width of entire buffer */ + __u32 height; /* height of entire buffer */ + struct mxcfb_rect alt_update_region; /* region within buffer to update */ +}; +struct mxcfb_alt_buffer_data_kobo { /* virt_addr is not included in amazon's source */ void *virt_addr; -#endif __u32 phys_addr; __u32 width; /* width of entire buffer */ __u32 height; /* height of entire buffer */ @@ -123,16 +128,24 @@ struct mxcfb_update_data { __u32 waveform_mode; __u32 update_mode; __u32 update_marker; -#ifndef KOBO_PLATFORM /* these two fields have been added by amazon */ __u32 hist_bw_waveform_mode; __u32 hist_gray_waveform_mode; -#endif int temp; uint flags; struct mxcfb_alt_buffer_data alt_buffer_data; }; typedef struct mxcfb_update_data mxcfb_update_data; +struct mxcfb_update_data_kobo { + struct mxcfb_rect update_region; + __u32 waveform_mode; + __u32 update_mode; + __u32 update_marker; + int temp; + uint flags; + struct mxcfb_alt_buffer_data_kobo alt_buffer_data; +}; +typedef struct mxcfb_update_data mxcfb_update_data_kobo; /* this is only used in kindle firmware 5.0, later version (5.1) has changed * the struct to mxcfb_update_data (see above) */ diff --git a/ffi-cdecl/linux_fb_decl.c b/ffi-cdecl/linux_fb_decl.c new file mode 100644 index 000000000..ef0751561 --- /dev/null +++ b/ffi-cdecl/linux_fb_decl.c @@ -0,0 +1,45 @@ +// standard Linux framebuffer headers +#include + +#include +// specialized eink framebuffer headers +typedef unsigned int u_int; +typedef unsigned long u_long; +#include "include/einkfb.h" +typedef unsigned int uint; +#include "include/mxcfb.h" + +#include "cdecl.h" + +cdecl_const(FBIOGET_FSCREENINFO) +cdecl_const(FBIOGET_VSCREENINFO) + +cdecl_const(FB_TYPE_PACKED_PIXELS) + +cdecl_struct(fb_bitfield) +cdecl_struct(fb_fix_screeninfo) +cdecl_struct(fb_var_screeninfo) + +// einkfb: + +cdecl_enum(fx_type) +cdecl_struct(update_area_t) +cdecl_enum(orientation_t) + +cdecl_enum(einkfb_events_t) +cdecl_struct(einkfb_event_t) + +cdecl_const(FBIO_EINK_UPDATE_DISPLAY) +cdecl_const(FBIO_EINK_UPDATE_DISPLAY_AREA) +cdecl_const(FBIO_EINK_SET_DISPLAY_ORIENTATION) +cdecl_const(FBIO_EINK_GET_DISPLAY_ORIENTATION) + +// mxcfb: + +cdecl_struct(mxcfb_rect) +cdecl_struct(mxcfb_alt_buffer_data) +cdecl_struct(mxcfb_alt_buffer_data_kobo) +cdecl_struct(mxcfb_update_data) +cdecl_struct(mxcfb_update_data_kobo) + +cdecl_const(MXCFB_SEND_UPDATE) diff --git a/ffi-cdecl/posix_decl.c b/ffi-cdecl/posix_decl.c new file mode 100644 index 000000000..9dcb1088b --- /dev/null +++ b/ffi-cdecl/posix_decl.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdecl.h" + +cdecl_type(size_t) +cdecl_type(off_t) + +cdecl_struct(timeval) +cdecl_struct(statvfs) + +cdecl_func(pipe) +cdecl_func(fork) +cdecl_func(dup) +cdecl_func(dup2) + +cdecl_const(O_RDWR) +cdecl_const(O_RDONLY) +cdecl_const(O_NONBLOCK) +cdecl_func(open) +cdecl_func(close) +cdecl_func(fcntl) +cdecl_func(execl) +cdecl_func(execlp) +cdecl_func(execv) +cdecl_func(execvp) +cdecl_func(write) +cdecl_func(read) +cdecl_func(kill) +cdecl_func(waitpid) + +cdecl_struct(pollfd) +cdecl_const(POLLIN) +cdecl_const(POLLOUT) +cdecl_const(POLLERR) +cdecl_const(POLLHUP) +cdecl_func(poll) + +cdecl_const(PROT_READ) +cdecl_const(PROT_WRITE) +cdecl_const(MAP_SHARED) +cdecl_const(MAP_FAILED) +cdecl_func(mmap) + +cdecl_func(ioctl) +cdecl_func(sleep) +cdecl_func(usleep) +cdecl_func(statvfs) +cdecl_func(gettimeofday) +cdecl_func(realpath) + +cdecl_func(malloc) +cdecl_func(free) + +cdecl_func(strdup) +cdecl_func(strndup) + +cdecl_func(fopen) +cdecl_func(fclose) +cdecl_func(printf) +cdecl_func(sprintf) +cdecl_func(fprintf) +cdecl_func(fputc) diff --git a/ffi/framebuffer.lua b/ffi/framebuffer.lua new file mode 100644 index 000000000..59b7494cf --- /dev/null +++ b/ffi/framebuffer.lua @@ -0,0 +1,8 @@ +local util = require("ffi/util") + +if util.isEmulated() then + return require("ffi/framebuffer_SDL") +else + return require("ffi/framebuffer_linux") +end + diff --git a/ffi/framebuffer_linux.lua b/ffi/framebuffer_linux.lua new file mode 100644 index 000000000..ba3f298f1 --- /dev/null +++ b/ffi/framebuffer_linux.lua @@ -0,0 +1,199 @@ +local ffi = require("ffi") +local bit = require("bit") +local BB = require("ffi/blitbuffer") + +local dummy = require("ffi/linux_fb_h") +local dummy = require("ffi/posix_h") + +local framebuffer = {} +local framebuffer_mt = {__index={}} + +local function einkfb_update(fb, refreshtype, waveform_mode, x, y, w, h) + local refarea = ffi.new("struct update_area_t[1]") + + refarea[0].x1 = x or 0 + refarea[0].y1 = y or 0 + refarea[0].x2 = x + (w or fb.vinfo.xres) + refarea[0].y2 = y + (h or fb.vinfo.yres) + refarea[0].buffer = nil + if refreshtype == 1 then + refarea[0].which_fx = ffi.C.fx_update_partial + else + refarea[0].which_fx = ffi.C.fx_update_full + end + + ioctl(fb.fd, ffi.C.FBIO_EINK_UPDATE_DISPLAY_AREA, refarea); +end + +local function mxc_update(fb, refarea, refreshtype, waveform_mode, x, y, w, h) + refarea[0].update_mode = refreshtype or 1 + refarea[0].waveform_mode = waveform_mode or 2 + refarea[0].update_region.left = x or 0 + refarea[0].update_region.top = y or 0 + refarea[0].update_region.width = w or fb.vinfo.xres + refarea[0].update_region.height = h or fb.vinfo.yres + refarea[0].update_marker = 1 + refarea[0].temp = 0x1000 + -- TODO make the flag configurable from UI, + -- this flag invert all the pixels on display 09.01 2013 (houqp) + refarea[0].flags = 0 + refarea[0].alt_buffer_data.phys_addr = 0 + refarea[0].alt_buffer_data.width = 0 + refarea[0].alt_buffer_data.height = 0 + refarea[0].alt_buffer_data.alt_update_region.top = 0 + refarea[0].alt_buffer_data.alt_update_region.left = 0 + refarea[0].alt_buffer_data.alt_update_region.width = 0 + refarea[0].alt_buffer_data.alt_update_region.height = 0 + + ffi.C.ioctl(fb.fd, ffi.C.MXCFB_SEND_UPDATE, refarea) +end + +local function k51_update(fb, refreshtype, waveform_mode, x, y, w, h) + local refarea = ffi.new("struct mxcfb_update_data[1]") + -- only for Amazon's driver: + refarea[0].hist_bw_waveform_mode = 0 + refarea[0].hist_gray_waveform_mode = 0 + + return mxc_update(fb, refarea, refreshtype, waveform_mode, x, y, w, h) +end + +local function kobo_update(fb, refreshtype, waveform_mode, x, y, w, h) + local refarea = ffi.new("struct mxcfb_update_data_kobo[1]") + -- only for Kobo driver: + refarea[0].alt_buffer_data.virt_addr = nil + + return mxc_update(fb, refarea, refreshtype, waveform_mode, x, y, w, h) +end + +function framebuffer.open(device) + local fb = { + fd = -1, + finfo = ffi.new("struct fb_fix_screeninfo"), + vinfo = ffi.new("struct fb_var_screeninfo"), + fb_size = -1, + einkUpdateFunc = nil, + bb = nil, + data = nil + } + setmetatable(fb, framebuffer_mt) + + fb.fd = ffi.C.open(device, ffi.C.O_RDWR) + assert(fb.fd ~= -1, "cannot open framebuffer") + + -- Get fixed screen information + assert(ffi.C.ioctl(fb.fd, ffi.C.FBIOGET_FSCREENINFO, fb.finfo) == 0, + "cannot get screen info") + + assert(ffi.C.ioctl(fb.fd, ffi.C.FBIOGET_VSCREENINFO, fb.vinfo) == 0, + "cannot get variable screen info") + + assert(fb.finfo.type == ffi.C.FB_TYPE_PACKED_PIXELS, + "video type not supported") + + assert(fb.vinfo.grayscale ~= 0, "only grayscale is supported but framebuffer says it isn't") + assert(fb.vinfo.xres > 0 and fb.vinfo.yres > 0, "invalid framebuffer resolution") + + -- it seems that fb.finfo.smem_len is unreliable on kobo + -- Figure out the size of the screen in bytes + fb.fb_size = fb.vinfo.xres_virtual * fb.vinfo.yres_virtual * fb.vinfo.bits_per_pixel / 8 + + fb.data = ffi.C.mmap(nil, fb.fb_size, bit.bor(ffi.C.PROT_READ, ffi.C.PROT_WRITE), ffi.C.MAP_SHARED, fb.fd, 0) + assert(fb.data ~= ffi.C.MAP_FAILED, "can not mmap() framebuffer") + + if ffi.string(fb.finfo.id, 11) == "mxc_epdc_fb" then + -- TODO: check for Kobo + -- Kindle PaperWhite and KT with 5.1 or later firmware + fb.einkUpdateFunc = k51_update + + if fb.vinfo.bits_per_pixel == 16 then + fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual*2, fb.data, 16, false):invert() + elseif fb.vinfo.bits_per_pixel == 8 then + fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual, fb.data, 8, false):invert() + else + error("unknown bpp value for the mxc eink driver") + end + elseif ffi.string(fb.finfo.id, 7) == "eink_fb" then + fb.einkUpdateFunc = einkfb_update + + if fb.vinfo.bits_per_pixel == 8 then + fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual, fb.data, 8, false) + elseif fb.vinfo.bits_per_pixel == 4 then + fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual/2, fb.data, 4, false) + else + error("unknown bpp value for the classic eink driver") + end + else + error("eink model not supported"); + end + + return fb +end + +function framebuffer_mt:getOrientation() + local mode = ffi.new("int[1]") + ffi.C.ioctl(self.fd, ffi.C.FBIO_EINK_GET_DISPLAY_ORIENTATION, mode) + + -- adjust ioctl's rotate mode definition to KPV's + -- refer to screen.lua + if mode == 2 then + return 1 + elseif mode == 1 then + return 2 + end + return mode +end + +function framebuffer_mt:setOrientation(mode) + mode = ffi.cast("int", mode or 0) + if mode < 0 or mode > 3 then + error("Wrong rotation mode given!") + end + + --[[ + ioctl has a different definition for rotation mode. + 1 + +--------------+ + | +----------+ | + | | | | + | | Freedom! | | + | | | | + | | | | + 3 | | | | 2 + | | | | + | | | | + | +----------+ | + | | + | | + +--------------+ + 0 + --]] + if mode == 1 then + mode = 2 + elseif mode == 2 then + mode = 1 + end + + ffi.C.ioctl(self.fd, ffi.C.FBIO_EINK_SET_DISPLAY_ORIENTATION, mode) +end + +function framebuffer_mt.__index:refresh(refreshtype, waveform_mode, x, y, w, h) + self:einkUpdateFunc(refreshtype, waveform_mode, x, y, w, h) +end + +function framebuffer_mt.__index:getSize() + return self.bb.w, self.bb.h +end + +function framebuffer_mt.__index:getPitch() + return self.bb.pitch +end + +function framebuffer_mt.__index:close() + ffi.C.munmap(self.data, self.fb_size) + ffi.C.close(self.fd) + self.fd = -1 + self.data = nil + self.bb = nil +end + +return framebuffer diff --git a/ffi/linux_fb_h.lua b/ffi/linux_fb_h.lua new file mode 100644 index 000000000..3ce50ac31 --- /dev/null +++ b/ffi/linux_fb_h.lua @@ -0,0 +1,142 @@ +local ffi = require("ffi") +ffi.cdef[[ +static const int FBIOGET_FSCREENINFO = 17922; +static const int FBIOGET_VSCREENINFO = 17920; +static const int FB_TYPE_PACKED_PIXELS = 0; +struct fb_bitfield { + unsigned int offset; + unsigned int length; + unsigned int msb_right; +}; +struct fb_fix_screeninfo { + char id[16]; + long unsigned int smem_start; + unsigned int smem_len; + unsigned int type; + unsigned int type_aux; + unsigned int visual; + short unsigned int xpanstep; + short unsigned int ypanstep; + short unsigned int ywrapstep; + unsigned int line_length; + long unsigned int mmio_start; + unsigned int mmio_len; + unsigned int accel; + short unsigned int capabilities; + short unsigned int reserved[2]; +}; +struct fb_var_screeninfo { + unsigned int xres; + unsigned int yres; + unsigned int xres_virtual; + unsigned int yres_virtual; + unsigned int xoffset; + unsigned int yoffset; + unsigned int bits_per_pixel; + unsigned int grayscale; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + unsigned int nonstd; + unsigned int activate; + unsigned int height; + unsigned int width; + unsigned int accel_flags; + unsigned int pixclock; + unsigned int left_margin; + unsigned int right_margin; + unsigned int upper_margin; + unsigned int lower_margin; + unsigned int hsync_len; + unsigned int vsync_len; + unsigned int sync; + unsigned int vmode; + unsigned int rotate; + unsigned int colorspace; + unsigned int reserved[4]; +}; +enum fx_type { + fx_mask = 11, + fx_buf_is_mask = 14, + fx_none = -1, + fx_flash = 20, + fx_invert = 21, + fx_update_partial = 0, + fx_update_full = 1, +}; +struct update_area_t { + int x1; + int y1; + int x2; + int y2; + enum fx_type which_fx; + unsigned char *buffer; +}; +enum orientation_t { + orientation_portrait = 0, + orientation_portrait_upside_down = 1, + orientation_landscape = 2, + orientation_landscape_upside_down = 3, +}; +enum einkfb_events_t { + einkfb_event_update_display = 0, + einkfb_event_update_display_area = 1, + einkfb_event_blank_display = 2, + einkfb_event_rotate_display = 3, + einkfb_event_null = -1, +}; +struct einkfb_event_t { + enum einkfb_events_t event; + enum fx_type update_mode; + int x1; + int y1; + int x2; + int y2; + enum orientation_t orientation; +}; +static const int FBIO_EINK_UPDATE_DISPLAY = 18139; +static const int FBIO_EINK_UPDATE_DISPLAY_AREA = 18141; +static const int FBIO_EINK_SET_DISPLAY_ORIENTATION = 18160; +static const int FBIO_EINK_GET_DISPLAY_ORIENTATION = 18161; +struct mxcfb_rect { + unsigned int top; + unsigned int left; + unsigned int width; + unsigned int height; +}; +struct mxcfb_alt_buffer_data { + unsigned int phys_addr; + unsigned int width; + unsigned int height; + struct mxcfb_rect alt_update_region; +}; +struct mxcfb_alt_buffer_data_kobo { + void *virt_addr; + unsigned int phys_addr; + unsigned int width; + unsigned int height; + struct mxcfb_rect alt_update_region; +}; +struct mxcfb_update_data { + struct mxcfb_rect update_region; + unsigned int waveform_mode; + unsigned int update_mode; + unsigned int update_marker; + unsigned int hist_bw_waveform_mode; + unsigned int hist_gray_waveform_mode; + int temp; + unsigned int flags; + struct mxcfb_alt_buffer_data alt_buffer_data; +}; +struct mxcfb_update_data_kobo { + struct mxcfb_rect update_region; + unsigned int waveform_mode; + unsigned int update_mode; + unsigned int update_marker; + int temp; + unsigned int flags; + struct mxcfb_alt_buffer_data_kobo alt_buffer_data; +}; +static const int MXCFB_SEND_UPDATE = 1078478382; +]] diff --git a/ffi/posix_h.lua b/ffi/posix_h.lua new file mode 100644 index 000000000..0d0f7b5ac --- /dev/null +++ b/ffi/posix_h.lua @@ -0,0 +1,72 @@ +local ffi = require("ffi") +ffi.cdef[[ +typedef long unsigned int size_t; +typedef long int off_t; +struct timeval { + long int tv_sec; + long int tv_usec; +}; +struct statvfs { + long unsigned int f_bsize; + long unsigned int f_frsize; + long unsigned int f_blocks; + long unsigned int f_bfree; + long unsigned int f_bavail; + long unsigned int f_files; + long unsigned int f_ffree; + long unsigned int f_favail; + long unsigned int f_fsid; + long unsigned int f_flag; + long unsigned int f_namemax; + int __f_spare[6]; +}; +int pipe(int *) __attribute__((__nothrow__, __leaf__)); +int fork(void) __attribute__((nothrow)); +int dup(int) __attribute__((__nothrow__, __leaf__)); +int dup2(int, int) __attribute__((__nothrow__, __leaf__)); +static const int O_RDWR = 2; +static const int O_RDONLY = 0; +static const int O_NONBLOCK = 2048; +int open(const char *, int, ...); +int close(int); +int fcntl(int, int, ...); +int execl(const char *, const char *, ...) __attribute__((__nothrow__, __leaf__)); +int execlp(const char *, const char *, ...) __attribute__((__nothrow__, __leaf__)); +int execv(const char *, char *const *) __attribute__((__nothrow__, __leaf__)); +int execvp(const char *, char *const *) __attribute__((__nothrow__, __leaf__)); +long int write(int, const void *, long unsigned int); +long int read(int, void *, long unsigned int); +int kill(int, int) __attribute__((__nothrow__, __leaf__)); +int waitpid(int, int *, int); +struct pollfd { + int fd; + short int events; + short int revents; +}; +static const int POLLIN = 1; +static const int POLLOUT = 4; +static const int POLLERR = 8; +static const int POLLHUP = 16; +int poll(struct pollfd *, long unsigned int, int); +static const int PROT_READ = 1; +static const int PROT_WRITE = 2; +static const int MAP_SHARED = 1; +static const int MAP_FAILED = -1; +void *mmap(void *, long unsigned int, int, int, int, long int) __attribute__((__nothrow__, __leaf__)); +int ioctl(int, long unsigned int, ...) __attribute__((__nothrow__, __leaf__)); +unsigned int sleep(unsigned int); +int usleep(unsigned int); +int statvfs(const char *restrict, struct statvfs *restrict) __attribute__((__nothrow__, __leaf__)); +int gettimeofday(struct timeval *restrict, struct timezone *restrict) __attribute__((__nothrow__, __leaf__)); +char *realpath(const char *restrict, char *restrict) __attribute__((__nothrow__, __leaf__)); +void *malloc(long unsigned int) __attribute__((malloc, leaf, nothrow)); +void free(void *) __attribute__((__nothrow__, __leaf__)); +char *strdup(const char *) __attribute__((malloc, leaf, nothrow)); +char *strndup(const char *, long unsigned int) __attribute__((malloc, leaf, nothrow)); +struct _IO_FILE *fopen(const char *restrict, const char *restrict); +int fclose(struct _IO_FILE *); +int printf(const char *, ...); +int sprintf(char *, const char *, ...) __attribute__((nothrow)); +int fprintf(struct _IO_FILE *restrict, const char *restrict, ...); +int fputc(int, struct _IO_FILE *); +]] diff --git a/ffi/util.lua b/ffi/util.lua index f6a9ef69a..80bfef26e 100644 --- a/ffi/util.lua +++ b/ffi/util.lua @@ -5,36 +5,7 @@ Module for various utility functions local ffi = require "ffi" local bit = require "bit" -ffi.cdef[[ -struct timeval { - long int tv_sec; - long int tv_usec; -}; -int gettimeofday(struct timeval *restrict, struct timezone *restrict) __attribute__((__nothrow__, __leaf__)); - -unsigned int sleep(unsigned int); -int usleep(unsigned int); - -struct statvfs { - long unsigned int f_bsize; - long unsigned int f_frsize; - long unsigned int f_blocks; - long unsigned int f_bfree; - long unsigned int f_bavail; - long unsigned int f_files; - long unsigned int f_ffree; - long unsigned int f_favail; - long unsigned int f_fsid; - int __f_unused; - long unsigned int f_flag; - long unsigned int f_namemax; - int __f_spare[6]; -}; -int statvfs(const char *restrict, struct statvfs *restrict) __attribute__((__nothrow__, __leaf__)); -char *realpath(const char *restrict, char *restrict) __attribute__((__nothrow__)); -void *malloc(unsigned int) __attribute__((malloc, leaf, nothrow)); -void free(void *) __attribute__((nothrow)); -]] +require("ffi/posix_h") local util = {} From 220143e58b955942bd6b1c621c40756751692c66 Mon Sep 17 00:00:00 2001 From: HW Date: Fri, 1 Nov 2013 18:10:25 +0100 Subject: [PATCH 02/21] remove RGB16 we won't likely use it, it is full of bitops, thus pretty slow --- ffi/blitbuffer.lua | 105 +++++---------------------------------------- 1 file changed, 11 insertions(+), 94 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 045d89120..68a08a5a9 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -39,13 +39,6 @@ typedef struct BlitBuffer16 { uint8_t *data; uint8_t allocated; } BlitBuffer16; -typedef struct BlitBufferRGB16 { - int w; - int h; - int pitch; - uint8_t *data; - uint8_t allocated; -} BlitBufferRGB16; typedef struct BlitBufferRGB24 { int w; int h; @@ -67,15 +60,12 @@ typedef struct Color4L { typedef struct Color4U { uint8_t a; } Color4U; -typedef union Color8 { +typedef struct Color8 { uint8_t a; } Color8; typedef struct Color16 { uint16_t a; } Color16; -typedef struct ColorRGB16 { - uint16_t v; -} ColorRGB16; typedef struct ColorRGB24 { uint8_t r; uint8_t g; @@ -103,24 +93,13 @@ local Color4U = ffi.typeof("Color4U") local Color4L = ffi.typeof("Color4L") local Color8 = ffi.typeof("Color8") local Color16 = ffi.typeof("Color16") -local ColorRGB16 = ffi.typeof("ColorRGB16") local ColorRGB24 = ffi.typeof("ColorRGB24") local ColorRGB32 = ffi.typeof("ColorRGB32") --- color value pointer types -local P_Color4U = ffi.typeof("Color4U*") -local P_Color4L = ffi.typeof("Color4L*") -local P_Color8 = ffi.typeof("Color8*") -local P_Color16 = ffi.typeof("Color16*") -local P_ColorRGB16 = ffi.typeof("ColorRGB16*") -local P_ColorRGB24 = ffi.typeof("ColorRGB24*") -local P_ColorRGB32 = ffi.typeof("ColorRGB32*") - -- metatables for BlitBuffer objects: local BB4_mt = {__index={}} local BB8_mt = {__index={}} local BB16_mt = {__index={}} -local BBRGB16_mt = {__index={}} local BBRGB24_mt = {__index={}} local BBRGB32_mt = {__index={}} @@ -142,7 +121,6 @@ local Color4L_mt = {__index={}} local Color4U_mt = {__index={}} local Color8_mt = {__index={}} local Color16_mt = {__index={}} -local ColorRGB16_mt = {__index={}} local ColorRGB24_mt = {__index={}} local ColorRGB32_mt = {__index={}} @@ -164,10 +142,6 @@ function BB16_mt.__index:getPixelP(x, y) self:checkCoordinates(x, y) return ffi.cast(P_Color16, self.data + self.pitch*y + lshift(x,1)) end -function BBRGB16_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) - return ffi.cast(P_ColorRGB16, self.data + self.pitch*y + lshift(x,1)) -end function BBRGB24_mt.__index:getPixelP(x, y) self:checkCoordinates(x, y) return ffi.cast(P_ColorRGB24, self.data + self.pitch*y + x*3) @@ -219,22 +193,20 @@ http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale L = 0.299*Red + 0.587*Green + 0.114*Blue --]] -function ColorRGB16_mt.__index:getColor4L() - return Color4L(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 18)) +function ColorRGB24_mt.__index:getColor4L() + return Color4L(rshift(4897*self.r + 9617*self.g + 1868*self.b, 18)) end -ColorRGB24_mt.__index.getColor4L = ColorRGB16_mt.__index.getColor4L -ColorRGB32_mt.__index.getColor4L = ColorRGB16_mt.__index.getColor4L +ColorRGB32_mt.__index.getColor4L = ColorRGB24_mt.__index.getColor4L -- to Color4U: function Color4L_mt.__index:getColor4U() return Color4U(lshift(self.a, 4)) end function Color4U_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end function Color8_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end function Color16_mt.__index:getColor4U() return Color4U(band(rshift(self.a,8),0xF0)) end -function ColorRGB16_mt.__index:getColor4U() - return Color4U(band(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14), 0xF0)) +function ColorRGB24_mt.__index:getColor4U() + return Color4U(band(rshift(4897*self.r + 9617*self.g + 1868*self.b, 14), 0xF0)) end -ColorRGB24_mt.__index.getColor4U = ColorRGB16_mt.__index.getColor4U -ColorRGB32_mt.__index.getColor4U = ColorRGB16_mt.__index.getColor4U +ColorRGB32_mt.__index.getColor4U = ColorRGB24_mt.__index.getColor4U -- to Color8: function Color4L_mt.__index:getColor8() @@ -247,11 +219,10 @@ function Color4U_mt.__index:getColor8() end function Color8_mt.__index:getColor8() return self end function Color16_mt.__index:getColor8() return Color8(self.a) end -function ColorRGB16_mt.__index:getColor8() +function ColorRGB24_mt.__index:getColor8() return Color8(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) end -ColorRGB24_mt.__index.getColor8 = ColorRGB16_mt.__index.getColor8 -ColorRGB32_mt.__index.getColor8 = ColorRGB16_mt.__index.getColor8 +ColorRGB32_mt.__index.getColor8 = ColorRGB24_mt.__index.getColor8 -- to Color16: function Color4L_mt.__index:getColor16() @@ -261,33 +232,9 @@ end Color4U_mt.__index.getColor16 = Color4L_mt.__index.getColor16 Color8_mt.__index.getColor16 = Color4L_mt.__index.getColor16 function Color16_mt.__index.getColor16() return self end -ColorRGB16_mt.__index.getColor16 = Color4L_mt.__index.getColor16 ColorRGB24_mt.__index.getColor16 = Color4L_mt.__index.getColor16 ColorRGB32_mt.__index.getColor16 = Color4L_mt.__index.getColor16 --- to ColorRGB16: -function Color4L_mt.__index:getColorRGB16() - local v = band(self.a, 0x0F) - return ColorRGB16(lshift(v,11)+lshift(v,6)+lshift(v,1)) -end -function Color4U_mt.__index:getColorRGB16() - local v = band(self.a, 0xF0) - return ColorRGB16(lshift(v,7)+lshift(v,2)+rshift(v,3)) -end -function Color8_mt.__index:getColorRGB16() - local v = rshift(self.a, 3) - return ColorRGB16(lshift(v,10)+lshift(v,5)+v) -end -function Color16_mt.__index:getColorRGB16() - local v = rshift(self.a, 11) - return ColorRGB16(lshift(v,10)+lshift(v,5)+v) -end -function ColorRGB16_mt.__index:getColorRGB16() return self end -function ColorRGB24_mt.__index:getColorRGB16() - return ColorRGB16(lshift(rshift(self.r,3),10) + lshift(rshift(self.g,3),5) + rshift(self.b,3)) -end -ColorRGB32_mt.__index.getColorRGB16 = ColorRGB24_mt.__index.getColorRGB16 - -- to ColorRGB24: function Color4L_mt.__index:getColorRGB24() local v = self:getColor8() @@ -296,9 +243,6 @@ end Color4U_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color8_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color16_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 -function ColorRGB16_mt.__index:getColorRGB24() - return ColorRGB24(self:getR(), self:getG(), self:getB()) -end function ColorRGB24_mt.__index:getColorRGB24() return self end function ColorRGB32_mt.__index:getColorRGB24() return ColorRGB24(self.r, self.g, self.b) end @@ -310,9 +254,6 @@ end Color4U_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color8_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color16_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 -function ColorRGB16_mt.__index:getColorRGB32() - return ColorRGB32(self:getR(), self:getG(), self:getB(), 0) -end function ColorRGB24_mt.__index:getColorRGB32() return ColorRGB32(self.r, self.g, self.b) end function ColorRGB32_mt.__index:getColorRGB32() return self end @@ -329,9 +270,6 @@ Color8_mt.__index.getB = Color8_mt.__index.getColor8 Color16_mt.__index.getR = Color16_mt.__index.getColor8 Color16_mt.__index.getG = Color16_mt.__index.getColor8 Color16_mt.__index.getB = Color16_mt.__index.getColor8 -function ColorRGB16_mt.__index:getR() return lshift(band(self.v, 0x001F),3) end -function ColorRGB16_mt.__index:getG() return rshift(band(self.v, 0x03E0),2) end -function ColorRGB16_mt.__index:getB() return rshift(band(self.v, 0x7C00),7) end function ColorRGB24_mt.__index:getR() return self.r end function ColorRGB24_mt.__index:getG() return self.g end function ColorRGB24_mt.__index:getB() return self.b end @@ -345,7 +283,6 @@ function Color4L_mt.__index:invert() return Color4L(bxor(self.a, 0x0F)) end function Color4U_mt.__index:invert() return Color4U(bxor(self.a, 0xF0)) end function Color8_mt.__index:invert() return Color8(bxor(self.a, 0xFF)) end function Color16_mt.__index:invert() return Color16(bxor(self.a, 0xFFFF)) end -function ColorRGB16_mt.__index:invert() return ColorRGB16(bxor(self.v, 0x7FFF)) end function ColorRGB24_mt.__index:invert() return ColorRGB24(bxor(self.r, 0xFF), bxor(self.g, 0xFF), bxor(self.b, 0xFF)) end @@ -380,9 +317,6 @@ function ColorRGB24_mt.__index:add(color, intensity) if b > 255 then b = 255 end return ColorRGB24(r, g, b) end -function ColorRGB16_mt.__index:add(color, intensity) - return ColorRGB24_mt.__index.add(self, color, intensity):getColorRGB16() -end function ColorRGB32_mt.__index:add(color, intensity) return ColorRGB24_mt.__index.add(self, color, intensity):getColorRGB32() end @@ -393,7 +327,6 @@ end Color4U_mt.__index.dim = Color4L_mt.__index.dim Color8_mt.__index.dim = Color4L_mt.__index.dim Color16_mt.__index.dim = Color4L_mt.__index.dim -ColorRGB16_mt.__index.dim = Color4L_mt.__index.dim ColorRGB24_mt.__index.dim = Color4L_mt.__index.dim ColorRGB32_mt.__index.dim = Color4L_mt.__index.dim -- lighten up @@ -406,7 +339,6 @@ end Color4U_mt.__index.lighten = Color4L_mt.__index.lighten Color8_mt.__index.lighten = Color4L_mt.__index.lighten Color16_mt.__index.lighten = Color4L_mt.__index.lighten -ColorRGB16_mt.__index.lighten = Color4L_mt.__index.lighten ColorRGB24_mt.__index.lighten = Color4L_mt.__index.lighten ColorRGB32_mt.__index.lighten = Color4L_mt.__index.lighten -- masking @@ -416,7 +348,6 @@ end Color4U_mt.__index.mask = Color4L_mt.__index.mask Color8_mt.__index.mask = Color4L_mt.__index.mask Color16_mt.__index.mask = Color4L_mt.__index.mask -ColorRGB16_mt.__index.mask = Color4L_mt.__index.mask ColorRGB24_mt.__index.mask = Color4L_mt.__index.mask ColorRGB32_mt.__index.mask = Color4L_mt.__index.mask @@ -435,9 +366,6 @@ end function BB16_mt.__index:setPixel(x, y, color) self:getPixelP(x, y)[0].a = color:getColor16() end -function BBRGB16_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0].v = color:getColorRGB16() -end function BBRGB24_mt.__index:setPixel(x, y, color) self:getPixelP(x, y)[0] = color:getColorRGB24() end @@ -480,7 +408,6 @@ end function BB4_mt.__index:getBpp() return 4 end function BB8_mt.__index:getBpp() return 8 end function BB16_mt.__index:getBpp() return 16 end -function BBRGB16_mt.__index:getBpp() return 16 end function BBRGB24_mt.__index:getBpp() return 24 end function BBRGB32_mt.__index:getBpp() return 32 end function BB_rotated_mt.__index:getBpp() return self.bb:getBpp() end @@ -490,7 +417,6 @@ function BB_masked_mt.__index:getBpp() return self.bb:getBpp() end function BB4_mt.__index:isRGB() return false end function BB8_mt.__index:isRGB() return false end function BB16_mt.__index:isRGB() return false end -function BBRGB16_mt.__index:isRGB() return true end function BBRGB24_mt.__index:isRGB() return true end function BBRGB32_mt.__index:isRGB() return true end function BB_rotated_mt.__index:isRGB() return self.bb:isRGB() end @@ -1024,7 +950,6 @@ for name, func in pairs(BB_mt.__index) do if not BB4_mt.__index[name] then BB4_mt.__index[name] = func end if not BB8_mt.__index[name] then BB8_mt.__index[name] = func end if not BB16_mt.__index[name] then BB16_mt.__index[name] = func end - if not BBRGB16_mt.__index[name] then BBRGB16_mt.__index[name] = func end if not BBRGB24_mt.__index[name] then BBRGB24_mt.__index[name] = func end if not BBRGB32_mt.__index[name] then BBRGB32_mt.__index[name] = func end if not BB_rotated_mt.__index[name] then BB_rotated_mt.__index[name] = func end @@ -1036,7 +961,6 @@ end local BlitBuffer4 = ffi.metatype("BlitBuffer4", BB4_mt) local BlitBuffer8 = ffi.metatype("BlitBuffer8", BB8_mt) local BlitBuffer16 = ffi.metatype("BlitBuffer16", BB16_mt) -local BlitBufferRGB16 = ffi.metatype("BlitBufferRGB16", BBRGB16_mt) local BlitBufferRGB24 = ffi.metatype("BlitBufferRGB24", BBRGB24_mt) local BlitBufferRGB32 = ffi.metatype("BlitBufferRGB32", BBRGB32_mt) @@ -1045,7 +969,6 @@ ffi.metatype("Color4L", Color4L_mt) ffi.metatype("Color4U", Color4U_mt) ffi.metatype("Color8", Color8_mt) ffi.metatype("Color16", Color16_mt) -ffi.metatype("ColorRGB16", ColorRGB16_mt) ffi.metatype("ColorRGB24", ColorRGB24_mt) ffi.metatype("ColorRGB32", ColorRGB32_mt) @@ -1067,12 +990,10 @@ function BB.new(width, height, pitch, buffer, bpp, is_rgb) ffi.fill(buffer, pitch * height) allocated = 1 end - if bpp == 4 then + if bpp == 4 and is_rgb == false then return BlitBuffer4(width, height, pitch, buffer, allocated) - elseif bpp == 8 then + elseif bpp == 8 and is_rgb == false then return BlitBuffer8(width, height, pitch, buffer, allocated) - elseif bpp == 16 and is_rgb == true then - return BlitBufferRGB16(width, height, pitch, buffer, allocated) elseif bpp == 16 and is_rgb == false then return BlitBuffer16(width, height, pitch, buffer, allocated) elseif bpp == 24 and is_rgb == true then @@ -1094,7 +1015,6 @@ BB.Color4L = Color4L BB.Color4U = Color4U BB.Color8 = Color8 BB.Color16 = Color16 -BB.ColorRGB16 = ColorRGB16 BB.ColorRGB24 = ColorRGB24 BB.ColorRGB32 = ColorRGB32 @@ -1102,7 +1022,6 @@ BB.ColorRGB32 = ColorRGB32 BB.BlitBuffer4 = BlitBuffer4 BB.BlitBuffer8 = BlitBuffer8 BB.BlitBuffer16 = BlitBuffer16 -BB.BlitBufferRGB16 = BlitBufferRGB16 BB.BlitBufferRGB24 = BlitBufferRGB24 BB.BlitBufferRGB32 = BlitBufferRGB32 @@ -1128,13 +1047,11 @@ function BB.test() local cRGB24 = ColorRGB24(0xFF, 0xAA, 0x55) local cRGB24_32 = cRGB32:getColorRGB24() - local cRGB16_32 = cRGB32:getColorRGB16() local c16_32 = cRGB32:getColor16() local c8_32 = cRGB32:getColor8() local c4l_32 = cRGB32:getColor4L() local c4u_32 = cRGB32:getColor4U() - assert(cRGB16_32.v == 0x7EAA, "conversion failure RGB32 -> RGB16") assert(c16_32.a == 0xAAAA, "conversion failure RGB32 -> gray16") assert(c8_32.a == 0xAA, "conversion failure RGB32 -> gray8") assert(c4l_32.a == 0x0A, "conversion failure RGB32 -> gray4 (lower nibble)") From 0dab4f9fc6af14d1b6932d0ac6ad3fb4429a79cf Mon Sep 17 00:00:00 2001 From: HW Date: Fri, 1 Nov 2013 19:27:31 +0100 Subject: [PATCH 03/21] fix accidentally deleted types --- ffi/blitbuffer.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 68a08a5a9..32b3516d5 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -96,6 +96,15 @@ local Color16 = ffi.typeof("Color16") local ColorRGB24 = ffi.typeof("ColorRGB24") local ColorRGB32 = ffi.typeof("ColorRGB32") +-- color value pointer types +local P_Color4U = ffi.typeof("Color4U*") +local P_Color4L = ffi.typeof("Color4L*") +local P_Color8 = ffi.typeof("Color8*") +local P_Color16 = ffi.typeof("Color16*") +local P_ColorRGB16 = ffi.typeof("ColorRGB16*") +local P_ColorRGB24 = ffi.typeof("ColorRGB24*") +local P_ColorRGB32 = ffi.typeof("ColorRGB32*") + -- metatables for BlitBuffer objects: local BB4_mt = {__index={}} local BB8_mt = {__index={}} From 097fbb1b00f07a247a19d2995560de50a8235015 Mon Sep 17 00:00:00 2001 From: HW Date: Fri, 1 Nov 2013 19:27:58 +0100 Subject: [PATCH 04/21] one type deleted that really is gone now --- ffi/blitbuffer.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 32b3516d5..884d528dd 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -101,7 +101,6 @@ local P_Color4U = ffi.typeof("Color4U*") local P_Color4L = ffi.typeof("Color4L*") local P_Color8 = ffi.typeof("Color8*") local P_Color16 = ffi.typeof("Color16*") -local P_ColorRGB16 = ffi.typeof("ColorRGB16*") local P_ColorRGB24 = ffi.typeof("ColorRGB24*") local P_ColorRGB32 = ffi.typeof("ColorRGB32*") From f38e223ac4989cee2136fb7ebfd29e16f3cd30aa Mon Sep 17 00:00:00 2001 From: HW Date: Fri, 1 Nov 2013 19:32:18 +0100 Subject: [PATCH 05/21] bugfix for value setting --- ffi/blitbuffer.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 884d528dd..fbb900afe 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -369,10 +369,10 @@ function BB4_mt.__index:setPixel(x, y, color) end end function BB8_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0].a = color:getColor8() + self:getPixelP(x, y)[0] = color:getColor8() end function BB16_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0].a = color:getColor16() + self:getPixelP(x, y)[0] = color:getColor16() end function BBRGB24_mt.__index:setPixel(x, y, color) self:getPixelP(x, y)[0] = color:getColorRGB24() From 8e358fc532a4a2b1d35eccf6d6e798c97bed2359 Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 11 Nov 2013 14:31:52 +0100 Subject: [PATCH 06/21] factor out POSIX API --- ffi/posix_h.lua | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ ffi/util.lua | 31 +-------------------- 2 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 ffi/posix_h.lua diff --git a/ffi/posix_h.lua b/ffi/posix_h.lua new file mode 100644 index 000000000..0d0f7b5ac --- /dev/null +++ b/ffi/posix_h.lua @@ -0,0 +1,72 @@ +local ffi = require("ffi") +ffi.cdef[[ +typedef long unsigned int size_t; +typedef long int off_t; +struct timeval { + long int tv_sec; + long int tv_usec; +}; +struct statvfs { + long unsigned int f_bsize; + long unsigned int f_frsize; + long unsigned int f_blocks; + long unsigned int f_bfree; + long unsigned int f_bavail; + long unsigned int f_files; + long unsigned int f_ffree; + long unsigned int f_favail; + long unsigned int f_fsid; + long unsigned int f_flag; + long unsigned int f_namemax; + int __f_spare[6]; +}; +int pipe(int *) __attribute__((__nothrow__, __leaf__)); +int fork(void) __attribute__((nothrow)); +int dup(int) __attribute__((__nothrow__, __leaf__)); +int dup2(int, int) __attribute__((__nothrow__, __leaf__)); +static const int O_RDWR = 2; +static const int O_RDONLY = 0; +static const int O_NONBLOCK = 2048; +int open(const char *, int, ...); +int close(int); +int fcntl(int, int, ...); +int execl(const char *, const char *, ...) __attribute__((__nothrow__, __leaf__)); +int execlp(const char *, const char *, ...) __attribute__((__nothrow__, __leaf__)); +int execv(const char *, char *const *) __attribute__((__nothrow__, __leaf__)); +int execvp(const char *, char *const *) __attribute__((__nothrow__, __leaf__)); +long int write(int, const void *, long unsigned int); +long int read(int, void *, long unsigned int); +int kill(int, int) __attribute__((__nothrow__, __leaf__)); +int waitpid(int, int *, int); +struct pollfd { + int fd; + short int events; + short int revents; +}; +static const int POLLIN = 1; +static const int POLLOUT = 4; +static const int POLLERR = 8; +static const int POLLHUP = 16; +int poll(struct pollfd *, long unsigned int, int); +static const int PROT_READ = 1; +static const int PROT_WRITE = 2; +static const int MAP_SHARED = 1; +static const int MAP_FAILED = -1; +void *mmap(void *, long unsigned int, int, int, int, long int) __attribute__((__nothrow__, __leaf__)); +int ioctl(int, long unsigned int, ...) __attribute__((__nothrow__, __leaf__)); +unsigned int sleep(unsigned int); +int usleep(unsigned int); +int statvfs(const char *restrict, struct statvfs *restrict) __attribute__((__nothrow__, __leaf__)); +int gettimeofday(struct timeval *restrict, struct timezone *restrict) __attribute__((__nothrow__, __leaf__)); +char *realpath(const char *restrict, char *restrict) __attribute__((__nothrow__, __leaf__)); +void *malloc(long unsigned int) __attribute__((malloc, leaf, nothrow)); +void free(void *) __attribute__((__nothrow__, __leaf__)); +char *strdup(const char *) __attribute__((malloc, leaf, nothrow)); +char *strndup(const char *, long unsigned int) __attribute__((malloc, leaf, nothrow)); +struct _IO_FILE *fopen(const char *restrict, const char *restrict); +int fclose(struct _IO_FILE *); +int printf(const char *, ...); +int sprintf(char *, const char *, ...) __attribute__((nothrow)); +int fprintf(struct _IO_FILE *restrict, const char *restrict, ...); +int fputc(int, struct _IO_FILE *); +]] diff --git a/ffi/util.lua b/ffi/util.lua index f6a9ef69a..80bfef26e 100644 --- a/ffi/util.lua +++ b/ffi/util.lua @@ -5,36 +5,7 @@ Module for various utility functions local ffi = require "ffi" local bit = require "bit" -ffi.cdef[[ -struct timeval { - long int tv_sec; - long int tv_usec; -}; -int gettimeofday(struct timeval *restrict, struct timezone *restrict) __attribute__((__nothrow__, __leaf__)); - -unsigned int sleep(unsigned int); -int usleep(unsigned int); - -struct statvfs { - long unsigned int f_bsize; - long unsigned int f_frsize; - long unsigned int f_blocks; - long unsigned int f_bfree; - long unsigned int f_bavail; - long unsigned int f_files; - long unsigned int f_ffree; - long unsigned int f_favail; - long unsigned int f_fsid; - int __f_unused; - long unsigned int f_flag; - long unsigned int f_namemax; - int __f_spare[6]; -}; -int statvfs(const char *restrict, struct statvfs *restrict) __attribute__((__nothrow__, __leaf__)); -char *realpath(const char *restrict, char *restrict) __attribute__((__nothrow__)); -void *malloc(unsigned int) __attribute__((malloc, leaf, nothrow)); -void free(void *) __attribute__((nothrow)); -]] +require("ffi/posix_h") local util = {} From c883db4f7fc9f282e9e3ece779ddbc2110225750 Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 11 Nov 2013 14:32:17 +0100 Subject: [PATCH 07/21] blitbuffer with much more optimized blitting this introduces the ability to implement n:m bpp optimized blitting. This allows for a major speedup. Comes with implementation especially for from/to 4bpp blitbuffer blitting. --- ffi/blitbuffer.lua | 543 +++++++++++++++++++++++++++++++-------------- 1 file changed, 372 insertions(+), 171 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index fbb900afe..9460a7bf1 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -13,6 +13,8 @@ local bor = bit.bor local bxor = bit.bxor local intt = ffi.typeof("int") +local uint32pt = ffi.typeof("uint32_t*") +local posix = require("ffi/posix_h") -- the following definitions are redundant. -- they need to be since only this way we can set @@ -32,6 +34,13 @@ typedef struct BlitBuffer8 { uint8_t *data; uint8_t allocated; } BlitBuffer8; +typedef struct BlitBufferA8 { + int w; + int h; + int pitch; + uint8_t *data; + uint8_t allocated; +} BlitBufferA8; typedef struct BlitBuffer16 { int w; int h; @@ -63,6 +72,10 @@ typedef struct Color4U { typedef struct Color8 { uint8_t a; } Color8; +typedef struct ColorA8 { + uint8_t a; + uint8_t dummy; // only support pre-multiplied for now +} ColorA8; typedef struct Color16 { uint16_t a; } Color16; @@ -92,6 +105,7 @@ local BBtype = ffi.typeof("BlitBuffer4*") local Color4U = ffi.typeof("Color4U") local Color4L = ffi.typeof("Color4L") local Color8 = ffi.typeof("Color8") +local ColorA8 = ffi.typeof("ColorA8") local Color16 = ffi.typeof("Color16") local ColorRGB24 = ffi.typeof("ColorRGB24") local ColorRGB32 = ffi.typeof("ColorRGB32") @@ -100,6 +114,7 @@ local ColorRGB32 = ffi.typeof("ColorRGB32") local P_Color4U = ffi.typeof("Color4U*") local P_Color4L = ffi.typeof("Color4L*") local P_Color8 = ffi.typeof("Color8*") +local P_ColorA8 = ffi.typeof("ColorA8*") local P_Color16 = ffi.typeof("Color16*") local P_ColorRGB24 = ffi.typeof("ColorRGB24*") local P_ColorRGB32 = ffi.typeof("ColorRGB32*") @@ -107,12 +122,14 @@ local P_ColorRGB32 = ffi.typeof("ColorRGB32*") -- metatables for BlitBuffer objects: local BB4_mt = {__index={}} local BB8_mt = {__index={}} +local BBA8_mt = {__index={}} local BB16_mt = {__index={}} local BBRGB24_mt = {__index={}} local BBRGB32_mt = {__index={}} -- virtual blitbuffers: local BB_rotated_mt = {__index={}} +local BB4_rotated_mt = {__index={}} local BB_inverted_mt = {__index={}} local BB_masked_mt = {__index={}} @@ -128,13 +145,14 @@ local BB_mt = {__index={}} local Color4L_mt = {__index={}} local Color4U_mt = {__index={}} local Color8_mt = {__index={}} +local ColorA8_mt = {__index={}} local Color16_mt = {__index={}} local ColorRGB24_mt = {__index={}} local ColorRGB32_mt = {__index={}} -- getPixelP (pointer) routines function BB4_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) + --self:checkCoordinates(x, y) local p = self.data + self.pitch*y + rshift(x, 1) if band(x, 1) == 0 then return ffi.cast(P_Color4U, p) @@ -143,21 +161,35 @@ function BB4_mt.__index:getPixelP(x, y) end end function BB8_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) + --self:checkCoordinates(x, y) return ffi.cast(P_Color8, self.data + self.pitch*y + x) end +function BBA8_mt.__index:getPixelP(x, y) + --self:checkCoordinates(x, y) + return ffi.cast(P_ColorA8, self.data + self.pitch*y + lshift(x,1)) +end function BB16_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) + --self:checkCoordinates(x, y) return ffi.cast(P_Color16, self.data + self.pitch*y + lshift(x,1)) end function BBRGB24_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) + --self:checkCoordinates(x, y) return ffi.cast(P_ColorRGB24, self.data + self.pitch*y + x*3) end function BBRGB32_mt.__index:getPixelP(x, y) - self:checkCoordinates(x, y) + --self:checkCoordinates(x, y) return ffi.cast(P_ColorRGB32, self.data + self.pitch*y + lshift(x,2)) end +function BB_rotated_mt.__index:getPixelP(x, y) + if self.degree == 90 then + return self.bb:getPixelP(self.bb.w - y - 1, x) + elseif self.degree == 180 then + return self.bb:getPixelP(self.bb.w - x - 1, self.bb.h - y - 1) + elseif self.degree == 270 then + return self.bb:getPixelP(y, self.bb.h - x - 1) + end +end +BB4_rotated_mt.__index.getPixelP = BB_rotated_mt.__index.getPixelP -- coordinate checking --function BB_mt.__index:checkCoordinates(x, y) end @@ -168,32 +200,15 @@ function BB_mt.__index:checkCoordinates(x, y) assert(y < self.h, "y coordinate < height") end --- getPixel routines function BB_mt.__index:getPixel(x, y) return self:getPixelP(x, y)[0] end - -function BB_rotated_mt.__index:getPixelP(x, y) - if self.degree == 90 then - return self.bb:getPixelP(self.h - y - 1, x) - elseif self.degree == 180 then - return self.bb:getPixelP(self.w - x - 1, self.h - y - 1) - elseif self.degree == 270 then - return self.bb:getPixelP(y, self.w - x - 1) - end -end - -function BB_inverted_mt.__index:getPixel(x, y) - return self.bb:getPixel(x, y):invert() -end - -function BB_masked_mt.__index:getPixel(x, y) - return self.bb:getPixel(x, y):mask(self.fg, self.bg) -end +function BB_inverted_mt.__index:getPixel(x, y) return self:getPixelP(x, y)[0]:invert() end -- color conversions: -- to Color4L: function Color4L_mt.__index:getColor4L() return Color4L(band(self.a, 0x0F)) end function Color4U_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end function Color8_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end +function ColorA8_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end function Color16_mt.__index:getColor4L() return Color4L(rshift(self.a, 12)) end --[[ Uses luminance match for approximating the human perception of colour, as per @@ -210,6 +225,7 @@ ColorRGB32_mt.__index.getColor4L = ColorRGB24_mt.__index.getColor4L function Color4L_mt.__index:getColor4U() return Color4U(lshift(self.a, 4)) end function Color4U_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end function Color8_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end +function ColorA8_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end function Color16_mt.__index:getColor4U() return Color4U(band(rshift(self.a,8),0xF0)) end function ColorRGB24_mt.__index:getColor4U() return Color4U(band(rshift(4897*self.r + 9617*self.g + 1868*self.b, 14), 0xF0)) @@ -226,12 +242,30 @@ function Color4U_mt.__index:getColor8() return Color8(bor(rshift(v, 4), v)) end function Color8_mt.__index:getColor8() return self end +function ColorA8_mt.__index:getColor8() return Color8(self.a) end function Color16_mt.__index:getColor8() return Color8(self.a) end function ColorRGB24_mt.__index:getColor8() return Color8(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) end ColorRGB32_mt.__index.getColor8 = ColorRGB24_mt.__index.getColor8 +-- to ColorA8: +function Color4L_mt.__index:getColorA8() + local v = band(self.a, 0x0F) + return ColorA8(v*0x11) +end +function Color4U_mt.__index:getColorA8() + local v = band(self.a, 0xF0) + return ColorA8(bor(rshift(v, 4), v)) +end +function Color8_mt.__index:getColorA8() return ColorA8(self.a) end +function ColorA8_mt.__index:getColorA8() return self end +function Color16_mt.__index:getColorA8() return ColorA8(self.a) end +function ColorRGB24_mt.__index:getColorA8() + return ColorA8(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) +end +ColorRGB32_mt.__index.getColorA8 = ColorRGB24_mt.__index.getColorA8 + -- to Color16: function Color4L_mt.__index:getColor16() local v = self:getColor8().a @@ -239,6 +273,7 @@ function Color4L_mt.__index:getColor16() end Color4U_mt.__index.getColor16 = Color4L_mt.__index.getColor16 Color8_mt.__index.getColor16 = Color4L_mt.__index.getColor16 +ColorA8_mt.__index.getColor16 = Color4L_mt.__index.getColor16 function Color16_mt.__index.getColor16() return self end ColorRGB24_mt.__index.getColor16 = Color4L_mt.__index.getColor16 ColorRGB32_mt.__index.getColor16 = Color4L_mt.__index.getColor16 @@ -250,6 +285,7 @@ function Color4L_mt.__index:getColorRGB24() end Color4U_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color8_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 +ColorA8_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color16_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 function ColorRGB24_mt.__index:getColorRGB24() return self end function ColorRGB32_mt.__index:getColorRGB24() return ColorRGB24(self.r, self.g, self.b) end @@ -261,6 +297,7 @@ function Color4L_mt.__index:getColorRGB32() end Color4U_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color8_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 +ColorA8_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color16_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 function ColorRGB24_mt.__index:getColorRGB32() return ColorRGB32(self.r, self.g, self.b) end function ColorRGB32_mt.__index:getColorRGB32() return self end @@ -275,6 +312,9 @@ Color4U_mt.__index.getB = Color4U_mt.__index.getColor8 Color8_mt.__index.getR = Color8_mt.__index.getColor8 Color8_mt.__index.getG = Color8_mt.__index.getColor8 Color8_mt.__index.getB = Color8_mt.__index.getColor8 +ColorA8_mt.__index.getR = ColorA8_mt.__index.getColor8 +ColorA8_mt.__index.getG = ColorA8_mt.__index.getColor8 +ColorA8_mt.__index.getB = ColorA8_mt.__index.getColor8 Color16_mt.__index.getR = Color16_mt.__index.getColor8 Color16_mt.__index.getG = Color16_mt.__index.getColor8 Color16_mt.__index.getB = Color16_mt.__index.getColor8 @@ -290,11 +330,14 @@ ColorRGB32_mt.__index.getB = ColorRGB24_mt.__index.getB function Color4L_mt.__index:invert() return Color4L(bxor(self.a, 0x0F)) end function Color4U_mt.__index:invert() return Color4U(bxor(self.a, 0xF0)) end function Color8_mt.__index:invert() return Color8(bxor(self.a, 0xFF)) end +function ColorA8_mt.__index:invert() return ColorA8(bxor(self.a, 0xFF)) end function Color16_mt.__index:invert() return Color16(bxor(self.a, 0xFFFF)) end function ColorRGB24_mt.__index:invert() return ColorRGB24(bxor(self.r, 0xFF), bxor(self.g, 0xFF), bxor(self.b, 0xFF)) end -ColorRGB32_mt.__index.invert = ColorRGB24_mt.__index.invert +function ColorRGB32_mt.__index:invert() + return ColorRGB32(bxor(self.r, 0xFF), bxor(self.g, 0xFF), bxor(self.b, 0xFF)) +end -- adding two colors: function Color4L_mt.__index:add(color, intensity) local value = tonumber(self.a) * intensity + tonumber(color:getColor4L().a) * (1-intensity) @@ -302,15 +345,20 @@ function Color4L_mt.__index:add(color, intensity) return Color4L(value) end function Color4U_mt.__index:add(color, intensity) - local value = tonumber(self.a) * intensity + tonumber(color:getColor4U().a) * (1-intensity) + local orig = band(self.a, 0xF0) + local value = tonumber(orig) * intensity + tonumber(color:getColor4U().a) * (1-intensity) if value > 0xF0 then value = 0xF0 end - return Color4U(band(ffi.cast("uint8_t", value), 0xF0)) + --return Color4U(band(ffi.cast("uint8_t", value), 0xF0)) + return Color4U(band(value, 0xF0)) end function Color8_mt.__index:add(color, intensity) local value = tonumber(self.a) * intensity + tonumber(color:getColor8().a) * (1-intensity) if value > 0xFF then value = 0xFF end return Color8(value) end +function ColorA8_mt.__index:add(color, intensity) + return self:getColor8():add(color, intensity):getColorA8() +end function Color16_mt.__index:add(color, intensity) local value = tonumber(self.a) * intensity + tonumber(color:getColor16().a) * (1-intensity) if value > 0xFFFF then value = 0xFFFF end @@ -334,6 +382,7 @@ function Color4L_mt.__index:dim() end Color4U_mt.__index.dim = Color4L_mt.__index.dim Color8_mt.__index.dim = Color4L_mt.__index.dim +ColorA8_mt.__index.dim = Color4L_mt.__index.dim Color16_mt.__index.dim = Color4L_mt.__index.dim ColorRGB24_mt.__index.dim = Color4L_mt.__index.dim ColorRGB32_mt.__index.dim = Color4L_mt.__index.dim @@ -346,6 +395,7 @@ function Color4L_mt.__index:lighten(low) end Color4U_mt.__index.lighten = Color4L_mt.__index.lighten Color8_mt.__index.lighten = Color4L_mt.__index.lighten +ColorA8_mt.__index.lighten = Color4L_mt.__index.lighten Color16_mt.__index.lighten = Color4L_mt.__index.lighten ColorRGB24_mt.__index.lighten = Color4L_mt.__index.lighten ColorRGB32_mt.__index.lighten = Color4L_mt.__index.lighten @@ -355,55 +405,156 @@ function Color4L_mt.__index:mask(fg, bg) end Color4U_mt.__index.mask = Color4L_mt.__index.mask Color8_mt.__index.mask = Color4L_mt.__index.mask +ColorA8_mt.__index.mask = Color4L_mt.__index.mask Color16_mt.__index.mask = Color4L_mt.__index.mask ColorRGB24_mt.__index.mask = Color4L_mt.__index.mask ColorRGB32_mt.__index.mask = Color4L_mt.__index.mask --- set pixel values -function BB4_mt.__index:setPixel(x, y, color) - local p = self:getPixelP(x, y) - if band(x, 1) == 0 then - p[0].a = bor(band(p[0].a, 0x0F), color:getColor4U().a) +function BB4_mt.__index.getMyColor(color) return color:getColor4L() end +function BB8_mt.__index.getMyColor(color) return color:getColor8() end +function BBA8_mt.__index.getMyColor(color) return color:getColorA8() end +function BB16_mt.__index.getMyColor(color) return color:getColor16() end +function BBRGB24_mt.__index.getMyColor(color) return color:getColorRGB24() end +function BBRGB32_mt.__index.getMyColor(color) return color:getColorRGB32() end + +function BB_mt.__index:isInverted() return false end +function BB_inverted_mt.__index:isInverted() return true end +function BB_mt.__index:invert() + if self:isInverted() then return self.bb end + local bb = { + bb = self, + w = self.w, + h = self.h, + pitch = self.pitch, + data = self.data, + blitfunc = self.blitfunc, + getMyColor = self.getMyColor, + getPixelP = self.getPixelP + } + setmetatable(bb, BB_inverted_mt) + return bb +end +function BB_mt.__index:isRotated() return false end +function BB_rotated_mt.__index:isRotated() return true end +function BB_mt.__index:rotate(degree) + local backing_bb = self + if self:isRotated() then + -- combine rotations + degree = (degree + self.degree) % 360 + if degree == 0 then return self.bb end + backing_bb = self.bb + end + local bb = { + bb = backing_bb, + w = self.w, + h = self.h, + degree = degree, + pitch = self.pitch, + data = self.data, + blitfunc = self.blitfunc, + getMyColor = self.getMyColor + } + if degree == 90 or degree == 270 then + bb.w = self.h + bb.h = self.w + end + if self:getBpp() == 4 then + setmetatable(bb, BB4_rotated_mt) else - p[0].a = bor(band(p[0].a, 0xF0), color:getColor4L().a) + setmetatable(bb, BB_rotated_mt) end + return bb end -function BB8_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0] = color:getColor8() +function BB_mt.__index:getBpp() return self.bb:getBpp() end +function BB_mt.__index:isRGB() return self.bb:isRGB() end + +-- set pixel values +function BB_mt.__index:setPixel(x, p, color) + if x then p = self:getPixelP(x, p) end + p[0] = self.getMyColor(color) +end +-- two-pixel setting for 4bpp mode +function BB4_mt.__index:setPixel(x, p, color, dummy, color2) + if x then + p = self:getPixelP(x, p) + if band(x, 1) == 1 then + color2 = color + color = nil + end + end + if color and color2 then + p[0].a = bor(color:getColor4U().a, color2:getColor4L().a) + elseif color2 then + p[0].a = bor(band(p[0].a, 0xF0), color2:getColor4L().a) + else + p[0].a = bor(band(p[0].a, 0x0F), color:getColor4U().a) + end end -function BB16_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0] = color:getColor16() +BB4_rotated_mt.__index.setPixel = BB4_mt.__index.setPixel +function BB_inverted_mt.__index:setPixel(x, p, color, dummy, color2) + -- this will work for both 4bpp and other modes + self.bb:setPixelInverted(x, p, color, dummy, color2) end -function BBRGB24_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0] = color:getColorRGB24() + +function BB_mt.__index:setPixelInverted(x, p, color) + if x then p = self:getPixelP(x, p) end + p[0] = self.getMyColor(color):invert() end -function BBRGB32_mt.__index:setPixel(x, y, color) - self:getPixelP(x, y)[0] = color:getColorRGB32() +function BB4_mt.__index:setPixelInverted(x, p, color, dummy, color2) + if x then + p = self:getPixelP(x, p) + if band(x, 1) == 1 then + color2 = color + color = nil + end + end + if color and color2 then + p[0].a = bxor(bor(color:getColor4U().a, color2:getColor4L().a), 0xFF) + elseif color2 then + p[0].a = bor(band(p[0].a, 0xF0), bxor(color2:getColor4L().a, 0x0F)) + else + p[0].a = bor(band(p[0].a, 0x0F), bxor(color:getColor4U().a, 0xF0)) + end end --- special case for 4bpp blitbuffers: -function BB4_mt.__index:setPixel2(x, y, color1, color2) - local p = self:getPixelP(x, y) - p[0].a = bor(color1:getColor4U().a, color2:getColor4L().a) +function BB_inverted_mt.__index:setPixelInverted(x, p, color, dummy, color2) + -- this will work for both 4bpp and other modes + self.bb:setPixel(x, p, color, dummy, color2) end --- virtual Blitbuffer pixel setting: -function BB_rotated_mt.__index:setPixel(x, y, color) - if self.degree == 90 then - return self.bb:setPixel(self.y, self.x, color) - elseif self.degree == 180 then - return self.bb:setPixel(self.w - x - 1, self.h - y - 1, color) - elseif self.degree == 270 then - return self.bb:setPixel(self.h - y - 1, self.w - x - 1, color) +function BB_mt.__index:setPixelAdd(x, p, color, intensity) + if x then p = self:getPixelP(x, p) end + p[0] = self.getMyColor(color):add(p[0], intensity) +end +function BB4_mt.__index:setPixelAdd(x, p, color, intensity, color2) + if x then + p = self:getPixelP(x, p) + if band(x, 1) == 1 then + color2 = color + color = nil + end + end + local v1 = band(p[0].a, 0xF0) + local v2 = band(p[0].a, 0x0F) + if color then + v1 = tonumber(v1) * (1-intensity) + tonumber(color:getColor4U().a) * intensity + if v1 > 0xF0 then v1 = 0xF0 end + v1 = band(v1, 0xF0) end + if color2 then + v2 = tonumber(v2) * (1-intensity) + tonumber(color2:getColor4L().a) * intensity + if v2 > 0x0F then v2 = 0x0F end + end + p[0].a = bor(v1, v2) end -function BB_inverted_mt.__index:setPixel(x, y, color) - self.bb:setPixel(x, y, color:invert()) +function BB_mt.__index:setPixelDim(x, p, color, dummy, color2) + -- this will work for both 4bpp and other modes + self:setPixel(x, p, color and color:dim(), dummy, color2 and color2:dim()) end -function BB_masked_mt.__index:setPixel(x, y, color) - -- just pass it through, masking only on read - self.bb:setPixel(x, y, color) +function BB_mt.__index:setPixelLighten(x, p, color, low, color2) + -- this will work for both 4bpp and other modes + self:setPixel(x, p, color and color:lighten(low), dummy, color2 and color2:lighten(low)) end -- checked Pixel setting: @@ -415,26 +566,30 @@ end function BB4_mt.__index:getBpp() return 4 end function BB8_mt.__index:getBpp() return 8 end +function BBA8_mt.__index:getBpp() return 16 end function BB16_mt.__index:getBpp() return 16 end function BBRGB24_mt.__index:getBpp() return 24 end function BBRGB32_mt.__index:getBpp() return 32 end -function BB_rotated_mt.__index:getBpp() return self.bb:getBpp() end -function BB_inverted_mt.__index:getBpp() return self.bb:getBpp() end -function BB_masked_mt.__index:getBpp() return self.bb:getBpp() end function BB4_mt.__index:isRGB() return false end function BB8_mt.__index:isRGB() return false end +function BBA8_mt.__index:isRGB() return false end function BB16_mt.__index:isRGB() return false end function BBRGB24_mt.__index:isRGB() return true end function BBRGB32_mt.__index:isRGB() return true end -function BB_rotated_mt.__index:isRGB() return self.bb:isRGB() end -function BB_inverted_mt.__index:isRGB() return self.bb:isRGB() end -function BB_masked_mt.__index:isRGB() return self.bb:isRGB() end -- compatibility functions for accessing dimensions function BB_mt.__index:getWidth() return self.w end function BB_mt.__index:getHeight() return self.h end +-- names of optimized blitting routines +BB4_mt.__index.blitfunc = "blitTo4" +BB8_mt.__index.blitfunc = "blitTo8" +BBA8_mt.__index.blitfunc = "blitToA8" +BB16_mt.__index.blitfunc = "blitTo16" +BBRGB24_mt.__index.blitfunc = "blitToRGB24" +BBRGB32_mt.__index.blitfunc = "blitToRGB32" + --[[ generic boundary check for copy operations @@ -478,25 +633,39 @@ local function checkBounds(length, target_offset, source_offset, target_size, so end end +-- no optimized blitting by default: +function BB_mt.__index:blitTo4() return false end +BB_mt.__index.blitTo8 = BB_mt.__index.blitTo4 +BB_mt.__index.blitToA8 = BB_mt.__index.blitTo4 +BB_mt.__index.blitTo16 = BB_mt.__index.blitTo4 +BB_mt.__index.blitToRGB24 = BB_mt.__index.blitTo4 +BB_mt.__index.blitToRGB32 = BB_mt.__index.blitTo4 -function BB_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, colormod, mod_param) +function BB_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) + -- test if an optimized version exists/succeeds: + if source[self.blitfunc](source, self, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) then + return + end + -- slow default variant: + local dest = self local o_y = offs_y for y = dest_y, dest_y+height-1 do local o_x = offs_x for x = dest_x, dest_x+width-1 do - self:setPixel(x, y, colormod(source:getPixel(o_x, o_y), mod_param, self, x, y)) + setter(dest, x, y, source:getPixel(o_x, o_y), set_param) o_x = o_x + 1 end o_y = o_y + 1 end end -function BB4_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, colormod, mod_param) +-- slightly optimized default routine for blitting to 4bpp buffers +function BB_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) local o_y = offs_y if band(dest_x, 1) == 1 then -- one "odd" column to process first for y = dest_y, dest_y+height-1 do - self:setPixel(dest_x, y, colormod(source:getPixel(offs_x, o_y), mod_param, self, dest_x, y)) + setter(dest, dest_x, y, self:getPixel(offs_x, o_y), set_param) o_y = o_y + 1 end dest_x = dest_x + 1 @@ -509,7 +678,7 @@ function BB4_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, local x = dest_x + width - 1 local o_x = offs_x + width - 1 for y = dest_y, dest_y+height-1 do - self:setPixel(x, y, colormod(source:getPixel(o_x, o_y), mod_param, self, x, y)) + setter(dest, x, y, self:getPixel(o_x, o_y), set_param) o_y = o_y + 1 end width = width - 1 @@ -520,106 +689,150 @@ function BB4_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, for y = dest_y, dest_y+height-1 do local o_x = offs_x for x = dest_x, dest_x+width-2, 2 do - self:setPixel2(x, y, - colormod(source:getPixel(o_x, o_y), mod_param, self, x, y), - colormod(source:getPixel(o_x+1, o_y), mod_param, self, x+1, y)) + setter(dest, x, y, self:getPixel(o_x, o_y), set_param, self:getPixel(o_x+1, o_y)) o_x = o_x + 2 end o_y = o_y + 1 end + return true end -local function no_color_mod(value) return value end - -function BB.modInvert(value) - return value:invert() -end - -function BB.modAddBlit(value, intensity, orig, x, y) - return value:add(orig:getPixel(x, y), intensity) -end - -function BB.modDim(value) - return value:dim() +-- optimized 4bpp to 4bpp blitting +function BB4_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) + local o_y = offs_y + for y = dest_y, dest_y+height-1 do + local w = width + local dest_p = dest:getPixelP(dest_x, y) + local source_p = self:getPixelP(offs_x, o_y) + if band(offs_x, 1) == 1 then + -- odd source x coordinate + local nv = source_p[0] + source_p = source_p + 1 + if band(dest_x, 1) == 1 then + -- ... and odd destination x coordinate + setter(dest, nil, dest_p, nil, set_param, nv) + dest_p = dest_p + 1 + w = w - 1 + while w > 1 do + nv = source_p[0] + setter(dest, nil, dest_p, Color4U(nv.a), set_param, nv) + source_p = source_p + 1 + dest_p = dest_p + 1 + w = w - 2 + end + if w > 0 then + setter(dest, nil, dest_p, Color4U(source_p[0].a), set_param, nil) + end + else + -- even destination coordinate + while w > 1 do + local v = source_p[0] + setter(dest, nil, dest_p, Color4L(nv.a), set_param, Color4U(v.a)) + nv = v + source_p = source_p + 1 + dest_p = dest_p + 1 + w = w - 2 + end + if w > 0 then + setter(dest, nil, dest_p, Color4L(nv.a), set_param, nil) + end + end + else + -- even source x coordinate + if band(dest_x, 1) == 1 then + -- ..but odd destination x coordinate + local nv = source_p[0] + source_p = source_p + 1 + setter(dest, nil, dest_p, nil, set_param, nv) + dest_p = dest_p + 1 + w = w - 1 + while w > 1 do + local v = source_p[0] + setter(dest, nil, dest_p, Color4L(nv.a), set_param, v) + nv = v + source_p = source_p + 1 + dest_p = dest_p + 1 + w = w - 2 + end + if w > 0 then + setter(dest, nil, dest_p, Color4L(nv.a), set_param, nil) + end + else + -- even destination x coordinate + while w > 1 do + local v = source_p[0] + setter(dest, nil, dest_p, v, set_param, Color4L(v.a)) + source_p = source_p + 1 + dest_p = dest_p + 1 + w = w - 2 + end + if w > 0 then + setter(dest, nil, dest_p, source_p[0], set_param, nil) + end + end + end + o_y = o_y + 1 + end + return true end -function BB.modLighten(value, low) - return value:lighten(low) +function BB4_mt.__index:blitTo8(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) + local o_y = offs_y + for y = dest_y, dest_y+height-1 do + local w = width + local dest_p = dest:getPixelP(dest_x, y) + local source_p = self:getPixelP(offs_x, o_y) + if band(offs_x, 1) == 1 then + local v = source_p[0].a + local l = band(v, 0x0F) + setter(dest, nil, dest_p, Color8(bor(l, lshift(l, 4))), set_param) + dest_p = dest_p + 1 + source_p = source_p + 1 + w = w - 1 + end + while w > 1 do + local v = source_p[0].a + local u = band(v, 0xF0) + local l = band(v, 0x0F) + setter(dest, nil, dest_p, Color8(bor(u, rshift(u, 4))), set_param) + dest_p = dest_p + 1 + setter(dest, nil, dest_p, Color8(bor(l, lshift(l, 4))), set_param) + dest_p = dest_p + 1 + source_p = source_p + 1 + w = w - 2 + end + if w > 0 then + local v = source_p[0].a + local u = band(v, 0xF0) + setter(dest, nil, dest_p, Color8(bor(u, rshift(u, 4))), set_param) + end + o_y = o_y + 1 + end + return true end +BB4_mt.__index.blitToA8 = BB4_mt.__index.blitTo8 +BB4_mt.__index.blitTo16 = BB4_mt.__index.blitTo8 +BB4_mt.__index.blitToRGB24 = BB4_mt.__index.blitTo8 +BB4_mt.__index.blitToRGB32 = BB4_mt.__index.blitTo8 -function BB_mt.__index:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, colormod, mod_param) +function BB_mt.__index:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) width, height = width or source.w, height or source.h - if not colormod then colormod = no_color_mod end width, dest_x, offs_x = checkBounds(width, dest_x or 0, offs_x or 0, self.w, source.w) height, dest_y, offs_y = checkBounds(height, dest_y or 0, offs_y or 0, self.h, source.h) + if not setter then setter = self.setPixel end if width <= 0 or height <= 0 then return end - return self:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, colormod, mod_param) + return self:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) end BB_mt.__index.blitFullFrom = BB_mt.__index.blitFrom function BB_mt.__index:addblitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, intensity) - self:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, BB.modAdd, intensity) -end - ---[[ -rotation via virtual blitbuffer ---]] -function BB_mt.__index:rotateBy(degree) - if degree % 360 == 0 then return self end - while degree < 0 do degree = degree + 360 end - degree = degree % 360 - assert(degree % 90 == 0, "rotation only by multiples of 90°") - local BB_rotated = { - degree = degree, - bb = self, - w = self.h, - h = self.w - } - if degree % 180 == 0 then - -- "upside down" - width and height stay the same - BB_rotated.w = self.w - BB_rotated.h = self.h - end - setmetatable(BB_rotated, BB_rotated_mt) - return BB_rotated -end -function BB_rotated_mt.__index:rotateBy(degree) - -- just do a new rotateBy() on our original Blitbuffer - return self.bb:rotateBy(self.degree + degree) -end - -function BB_mt.__index:invert() - local BB_inverted = { - bb = self, - w = self.w, - h = self.h - } - setmetatable(BB_inverted, BB_inverted_mt) - return BB_inverted -end -function BB_inverted_mt.__index:invert() - return self.bb + self:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, self.setPixelAdd, intensity) end -function BB_mt.__index:mask(fg, bg) - local BB_masked = { - bb = self, - w = self.w, - h = self.h, - fg = fg, - bg = bg - } - setmetatable(BB_masked, BB_masked_mt) - return BB_masked -end - ---[[ -compatibility method for a "rotated blitting" -..]] function BB_mt.__index:blitFromRotate(source, degree) - self:blitFrom(source:rotateBy(-degree)) + self:rotate(degree):blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, self.setPixel, intensity) end --[[ @@ -635,13 +848,6 @@ function BB_mt.__index:free() end end --- a NOP for virtual blitbuffers --- note that we can *not* free resources of the underlying --- blitbuffer as that might be referenced elsewhere! -function BB_rotated_mt.__index:free() return end -BB_inverted_mt.__index.free = BB_rotated_mt.__index.free -BB_masked_mt.__index.free = BB_rotated_mt.__index.free - --[[ memory management --]] @@ -661,7 +867,7 @@ invert a rectangle within the buffer @param h height --]] function BB_mt.__index:invertRect(x, y, w, h) - self:blitFrom(self, x, y, x, y, w, h, BB.modInvert) + self:blitFrom(self, x, y, x, y, w, h, self.setPixelInverted) end --[[ @@ -918,7 +1124,7 @@ dim color values in rectangular area @param h height --]] function BB_mt.__index:dimRect(x, y, w, h) - self:blitFrom(self, x, y, x, y, w, h, BB.modDim) + self:blitFrom(self, x, y, x, y, w, h, self.setPixelDim) end --[[ @@ -930,37 +1136,29 @@ lighten color values in rectangular area @param h height --]] function BB_mt.__index:lightenRect(x, y, w, h, low) - self:blitFrom(self, x, y, x, y, w, h, BB.modLighten, low) + self:blitFrom(self, x, y, x, y, w, h, self.setPixelLighten, low) end function BB_mt.__index:copy() - local copy = BB.new(self.w, self.h, self.pitch, nil, self:getBpp(), self:isRGB()) - ffi.copy(copy.data, self.data, self.pitch * self.h) - return copy -end - -function BB_rotated_mt.__index:copy() - return self.bb:copy():rotateBy(self.degree) + local mytype = ffi.typeof(self) + local buffer = ffi.C.malloc(self.pitch * self.h) + assert(buffer, "cannot allocate buffer") + ffi.copy(buffer, self.data, self.pitch * self.h) + return mytype(self.w, self.h, self.pitch, buffer, 1) end -function BB_inverted_mt.__index:copy() - return self.bb:copy():invert() -end -function BB_inverted_mt.__index:copy() - return self.bb:copy():mask(self.fg, self.bg) -end - - -- if no special case in BB???_mt exists, use function from BB_mt -- (we do not use BB_mt as metatable for BB???_mt since this causes -- a major slowdown and would not get properly JIT-compiled) for name, func in pairs(BB_mt.__index) do if not BB4_mt.__index[name] then BB4_mt.__index[name] = func end if not BB8_mt.__index[name] then BB8_mt.__index[name] = func end + if not BBA8_mt.__index[name] then BBA8_mt.__index[name] = func end if not BB16_mt.__index[name] then BB16_mt.__index[name] = func end if not BBRGB24_mt.__index[name] then BBRGB24_mt.__index[name] = func end if not BBRGB32_mt.__index[name] then BBRGB32_mt.__index[name] = func end if not BB_rotated_mt.__index[name] then BB_rotated_mt.__index[name] = func end + if not BB4_rotated_mt.__index[name] then BB4_rotated_mt.__index[name] = func end if not BB_inverted_mt.__index[name] then BB_inverted_mt.__index[name] = func end if not BB_masked_mt.__index[name] then BB_masked_mt.__index[name] = func end end @@ -968,6 +1166,7 @@ end -- set metatables for the BlitBuffer types local BlitBuffer4 = ffi.metatype("BlitBuffer4", BB4_mt) local BlitBuffer8 = ffi.metatype("BlitBuffer8", BB8_mt) +local BlitBufferA8 = ffi.metatype("BlitBufferA8", BBA8_mt) local BlitBuffer16 = ffi.metatype("BlitBuffer16", BB16_mt) local BlitBufferRGB24 = ffi.metatype("BlitBufferRGB24", BBRGB24_mt) local BlitBufferRGB32 = ffi.metatype("BlitBufferRGB32", BBRGB32_mt) @@ -976,6 +1175,7 @@ local BlitBufferRGB32 = ffi.metatype("BlitBufferRGB32", BBRGB32_mt) ffi.metatype("Color4L", Color4L_mt) ffi.metatype("Color4U", Color4U_mt) ffi.metatype("Color8", Color8_mt) +ffi.metatype("ColorA8", ColorA8_mt) ffi.metatype("Color16", Color16_mt) ffi.metatype("ColorRGB24", ColorRGB24_mt) ffi.metatype("ColorRGB32", ColorRGB32_mt) @@ -1029,6 +1229,7 @@ BB.ColorRGB32 = ColorRGB32 -- accessors for Blitbuffer types BB.BlitBuffer4 = BlitBuffer4 BB.BlitBuffer8 = BlitBuffer8 +BB.BlitBufferA8 = BlitBufferA8 BB.BlitBuffer16 = BlitBuffer16 BB.BlitBufferRGB24 = BlitBufferRGB24 BB.BlitBufferRGB32 = BlitBufferRGB32 From e738d11044b1635bd8d21ab5dc5c4d603b3cd34e Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 11 Nov 2013 14:34:04 +0100 Subject: [PATCH 08/21] use blitbuffer API for conversion now that blitbuffer API for A8 format exists, we can use the output of mupdf directly. --- ffi/mupdfimg.lua | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ffi/mupdfimg.lua b/ffi/mupdfimg.lua index dd39cfa3f..e985c2afd 100644 --- a/ffi/mupdfimg.lua +++ b/ffi/mupdfimg.lua @@ -34,13 +34,7 @@ function Image:toBlitBuffer() mupdf.fz_convert_pixmap(self.context, self.pixmap, pixmap); mupdf.fz_drop_pixmap(self.context, pixmap); end - self.bb = Blitbuffer.new(self.pixmap.w, self.pixmap.h) - for y = 0, self.pixmap.h - 1 do - for x = 0, self.pixmap.w - 1 do - local pix = self.pixmap.samples[(x + y*self.pixmap.w)*2] - self.bb:setPixel(x, y, Blitbuffer.Color4(bit.rshift(0xFF - pix, 4))) - end - end + self.bb = Blitbuffer.BlitBufferA8(self.pixmap.w, self.pixmap.h, bit.lshift(self.pixmap.w, 1), self.pixmap.samples, 0):copy() end function Image:freeContext() @@ -59,7 +53,7 @@ function Image:fromPNG(filename) self:loadPNGData(self:_getFileData(filename)) self:toBlitBuffer() self:freeContext() - return self.bb + return self.bb:invert() end return Image From 81b7f08980a8e97d78333427425230b326cb3a1a Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 11 Nov 2013 14:38:31 +0100 Subject: [PATCH 09/21] adapt blitbuffer API test to deletion of RGB16 format RGB16 was dropped since it won't likely be used. Reflect this by removing the according test routine. --- spec/unit/blitbuffer_spec.lua | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/unit/blitbuffer_spec.lua b/spec/unit/blitbuffer_spec.lua index 8c25bf559..d3d63df65 100644 --- a/spec/unit/blitbuffer_spec.lua +++ b/spec/unit/blitbuffer_spec.lua @@ -12,11 +12,6 @@ describe("Blitbuffer unit tests", function() assert.are.equals(0xB9B9, c16_32.a) end) - it("should convert RGB32 to RGB16", function() - local cRGB16_32 = cRGB32:getColorRGB16() - assert.are.equals(0x7EAA, cRGB16_32.v) - end) - it("should convert RGB32 to gray8", function() local c8_32 = cRGB32:getColor8() assert.are.equals(0xB9, c8_32.a) From f42960e86bcfcfa9ee6f498db06b13e3584bb670 Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 18 Nov 2013 17:19:59 +0100 Subject: [PATCH 10/21] fix for rotation modes 4bpp handling was a bit adapted so rotated 4bpp can now be handled easier --- ffi/blitbuffer.lua | 120 ++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 66 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 9460a7bf1..51f40aa4d 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -129,7 +129,6 @@ local BBRGB32_mt = {__index={}} -- virtual blitbuffers: local BB_rotated_mt = {__index={}} -local BB4_rotated_mt = {__index={}} local BB_inverted_mt = {__index={}} local BB_masked_mt = {__index={}} @@ -155,9 +154,9 @@ function BB4_mt.__index:getPixelP(x, y) --self:checkCoordinates(x, y) local p = self.data + self.pitch*y + rshift(x, 1) if band(x, 1) == 0 then - return ffi.cast(P_Color4U, p) + return ffi.cast(P_Color4U, p), true else - return ffi.cast(P_Color4L, p) + return ffi.cast(P_Color4L, p), false end end function BB8_mt.__index:getPixelP(x, y) @@ -188,8 +187,11 @@ function BB_rotated_mt.__index:getPixelP(x, y) elseif self.degree == 270 then return self.bb:getPixelP(y, self.bb.h - x - 1) end + error("could not get pixel pointer for this rotation") +end +function BB_inverted_mt.__index:getPixelP(x, y) + return self.bb:getPixelP(x, y) end -BB4_rotated_mt.__index.getPixelP = BB_rotated_mt.__index.getPixelP -- coordinate checking --function BB_mt.__index:checkCoordinates(x, y) end @@ -428,8 +430,7 @@ function BB_mt.__index:invert() pitch = self.pitch, data = self.data, blitfunc = self.blitfunc, - getMyColor = self.getMyColor, - getPixelP = self.getPixelP + getMyColor = self.getMyColor } setmetatable(bb, BB_inverted_mt) return bb @@ -440,31 +441,37 @@ function BB_mt.__index:rotate(degree) local backing_bb = self if self:isRotated() then -- combine rotations - degree = (degree + self.degree) % 360 - if degree == 0 then return self.bb end + degree = (degree + self.degree) backing_bb = self.bb end + degree = degree % 360 + if degree == 0 then return self.bb end local bb = { bb = backing_bb, w = self.w, h = self.h, degree = degree, - pitch = self.pitch, - data = self.data, - blitfunc = self.blitfunc, - getMyColor = self.getMyColor + pitch = backing_bb.pitch, + data = backing_bb.data, + getMyColor = backing_bb.getMyColor, + select_y_upper = 2, + select_x_upper = 2 } if degree == 90 or degree == 270 then - bb.w = self.h - bb.h = self.w + bb.w = backing_bb.h + bb.h = backing_bb.w end - if self:getBpp() == 4 then - setmetatable(bb, BB4_rotated_mt) - else - setmetatable(bb, BB_rotated_mt) + if degree == 90 then bb.select_y_upper = 1 + elseif degree == 180 then bb.select_x_upper = 1 + elseif degree == 270 then bb.select_y_upper = 0 end + setmetatable(bb, BB_rotated_mt) return bb end +BB_mt.__index.rotateAbsolute = BB_mt.__index.rotate +function BB_rotated_mt.__index:rotateAbsolute(degree) + return self:rotate(degree - self.degree) +end function BB_mt.__index:getBpp() return self.bb:getBpp() end function BB_mt.__index:isRGB() return self.bb:isRGB() end @@ -474,47 +481,33 @@ function BB_mt.__index:setPixel(x, p, color) p[0] = self.getMyColor(color) end -- two-pixel setting for 4bpp mode -function BB4_mt.__index:setPixel(x, p, color, dummy, color2) +function BB4_mt.__index:setPixel(x, y, color, dummy, color2) if x then - p = self:getPixelP(x, p) - if band(x, 1) == 1 then - color2 = color - color = nil + local p, is_upper = self:getPixelP(x, y) + if is_upper then + p[0].a = bor(band(p[0].a, 0x0F), color:getColor4U().a) + else + p[0].a = bor(band(p[0].a, 0xF0), color:getColor4L().a) end - end - if color and color2 then - p[0].a = bor(color:getColor4U().a, color2:getColor4L().a) - elseif color2 then - p[0].a = bor(band(p[0].a, 0xF0), color2:getColor4L().a) else - p[0].a = bor(band(p[0].a, 0x0F), color:getColor4U().a) + local p = y + p[0].a = bor( + (color and color:getColor4U().a) or band(p[0].a, 0xF0), + (color2 and color2:getColor4L().a) or band(p[0].a, 0x0F) + ) end end -BB4_rotated_mt.__index.setPixel = BB4_mt.__index.setPixel + function BB_inverted_mt.__index:setPixel(x, p, color, dummy, color2) -- this will work for both 4bpp and other modes self.bb:setPixelInverted(x, p, color, dummy, color2) end function BB_mt.__index:setPixelInverted(x, p, color) - if x then p = self:getPixelP(x, p) end - p[0] = self.getMyColor(color):invert() + self:setPixel(x, p, color:invert()) end function BB4_mt.__index:setPixelInverted(x, p, color, dummy, color2) - if x then - p = self:getPixelP(x, p) - if band(x, 1) == 1 then - color2 = color - color = nil - end - end - if color and color2 then - p[0].a = bxor(bor(color:getColor4U().a, color2:getColor4L().a), 0xFF) - elseif color2 then - p[0].a = bor(band(p[0].a, 0xF0), bxor(color2:getColor4L().a, 0x0F)) - else - p[0].a = bor(band(p[0].a, 0x0F), bxor(color:getColor4U().a, 0xF0)) - end + self:setPixel(x, p, color and color:invert(), dummy, color2 and color2:invert()) end function BB_inverted_mt.__index:setPixelInverted(x, p, color, dummy, color2) -- this will work for both 4bpp and other modes @@ -583,6 +576,7 @@ function BB_mt.__index:getWidth() return self.w end function BB_mt.__index:getHeight() return self.h end -- names of optimized blitting routines +BB_mt.__index.blitfunc = "blitDefault" -- not optimized BB4_mt.__index.blitfunc = "blitTo4" BB8_mt.__index.blitfunc = "blitTo8" BBA8_mt.__index.blitfunc = "blitToA8" @@ -633,31 +627,25 @@ local function checkBounds(length, target_offset, source_offset, target_size, so end end --- no optimized blitting by default: -function BB_mt.__index:blitTo4() return false end -BB_mt.__index.blitTo8 = BB_mt.__index.blitTo4 -BB_mt.__index.blitToA8 = BB_mt.__index.blitTo4 -BB_mt.__index.blitTo16 = BB_mt.__index.blitTo4 -BB_mt.__index.blitToRGB24 = BB_mt.__index.blitTo4 -BB_mt.__index.blitToRGB32 = BB_mt.__index.blitTo4 - -function BB_mt.__index:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) - -- test if an optimized version exists/succeeds: - if source[self.blitfunc](source, self, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) then - return - end +function BB_mt.__index:blitDefault(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) -- slow default variant: - local dest = self local o_y = offs_y for y = dest_y, dest_y+height-1 do local o_x = offs_x for x = dest_x, dest_x+width-1 do - setter(dest, x, y, source:getPixel(o_x, o_y), set_param) + setter(dest, x, y, self:getPixel(o_x, o_y), set_param) o_x = o_x + 1 end o_y = o_y + 1 end end +-- no optimized blitting by default: +BB_mt.__index.blitTo4 = BB_mt.__index.blitDefault +BB_mt.__index.blitTo8 = BB_mt.__index.blitDefault +BB_mt.__index.blitToA8 = BB_mt.__index.blitDefault +BB_mt.__index.blitTo16 = BB_mt.__index.blitDefault +BB_mt.__index.blitToRGB24 = BB_mt.__index.blitDefault +BB_mt.__index.blitToRGB32 = BB_mt.__index.blitDefault -- slightly optimized default routine for blitting to 4bpp buffers function BB_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) @@ -688,8 +676,10 @@ function BB_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, heig -- now do the "doubles" in between for y = dest_y, dest_y+height-1 do local o_x = offs_x - for x = dest_x, dest_x+width-2, 2 do - setter(dest, x, y, self:getPixel(o_x, o_y), set_param, self:getPixel(o_x+1, o_y)) + local p = dest:getPixelP(dest_x, y) + for x = 0, width-2, 2 do + setter(dest, nil, p, self:getPixel(o_x, o_y), set_param, self:getPixel(o_x+1, o_y)) + p = p + 1 o_x = o_x + 2 end o_y = o_y + 1 @@ -822,8 +812,7 @@ function BB_mt.__index:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, h if not setter then setter = self.setPixel end if width <= 0 or height <= 0 then return end - - return self:blitFromChecked(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) + return source[self.blitfunc](source, self, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) end BB_mt.__index.blitFullFrom = BB_mt.__index.blitFrom @@ -1158,7 +1147,6 @@ for name, func in pairs(BB_mt.__index) do if not BBRGB24_mt.__index[name] then BBRGB24_mt.__index[name] = func end if not BBRGB32_mt.__index[name] then BBRGB32_mt.__index[name] = func end if not BB_rotated_mt.__index[name] then BB_rotated_mt.__index[name] = func end - if not BB4_rotated_mt.__index[name] then BB4_rotated_mt.__index[name] = func end if not BB_inverted_mt.__index[name] then BB_inverted_mt.__index[name] = func end if not BB_masked_mt.__index[name] then BB_masked_mt.__index[name] = func end end From 7d1693a6670f9a4ea6373a1eed5ebd300b427b63 Mon Sep 17 00:00:00 2001 From: HW Date: Wed, 20 Nov 2013 17:00:07 +0100 Subject: [PATCH 11/21] remove test function from blitbuffer.lua tests are now in our test suite --- ffi/blitbuffer.lua | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 51f40aa4d..0e677c71f 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -1222,41 +1222,4 @@ BB.BlitBuffer16 = BlitBuffer16 BB.BlitBufferRGB24 = BlitBufferRGB24 BB.BlitBufferRGB32 = BlitBufferRGB32 - --- tests: --- (run as "luajit -e 'require("blitbuffer").test()'" - -function BB.test() - local function print_bits(value) - local function print_iter(value) - if value > 0 then - print_iter(rshift(value, 1)) - if band(value, 1) == 1 then io.stdout:write("1") else io.stdout:write("0") end - else - io.stdout:write("0b0") - end - end - print_iter(value) - io.stdout:write("\n") - end - - local cRGB32 = ColorRGB32(0xFF, 0xAA, 0x55, 0) - local cRGB24 = ColorRGB24(0xFF, 0xAA, 0x55) - - local cRGB24_32 = cRGB32:getColorRGB24() - local c16_32 = cRGB32:getColor16() - local c8_32 = cRGB32:getColor8() - local c4l_32 = cRGB32:getColor4L() - local c4u_32 = cRGB32:getColor4U() - - assert(c16_32.a == 0xAAAA, "conversion failure RGB32 -> gray16") - assert(c8_32.a == 0xAA, "conversion failure RGB32 -> gray8") - assert(c4l_32.a == 0x0A, "conversion failure RGB32 -> gray4 (lower nibble)") - assert(c4u_32.a == 0xA0, "conversion failure RGB32 -> gray4 (upper nibble)") - - -- more tests to be done - - print("test: OK!") -end - return BB From 4bfb3176f29742a1ebc3187f1b9cb726bedc3ca0 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:09:45 +0100 Subject: [PATCH 12/21] Add FFI implementation of drawcontext Drawcontext was a bunch of accessor methods to a C struct. We can do this easily with FFI. --- drawcontext.c | 117 -------------------------------------------- ffi/drawcontext.lua | 40 +++++++++++++++ 2 files changed, 40 insertions(+), 117 deletions(-) delete mode 100644 drawcontext.c create mode 100644 ffi/drawcontext.lua diff --git a/drawcontext.c b/drawcontext.c deleted file mode 100644 index 9a4ac5d5f..000000000 --- a/drawcontext.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - KindlePDFViewer: a DC abstraction - Copyright (C) 2012 Hans-Werner Hilse - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program 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 - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "drawcontext.h" - -static int newDrawContext(lua_State *L) { - int rotate = luaL_optint(L, 1, 0); - double zoom = luaL_optnumber(L, 2, (double) 1.0); - int offset_x = luaL_optint(L, 3, 0); - int offset_y = luaL_optint(L, 4, 0); - double gamma = luaL_optnumber(L, 5, (double) -1.0); - - DrawContext *dc = (DrawContext*) lua_newuserdata(L, sizeof(DrawContext)); - dc->rotate = rotate; - dc->zoom = zoom; - dc->offset_x = offset_x; - dc->offset_y = offset_y; - dc->gamma = gamma; - - luaL_getmetatable(L, "drawcontext"); - lua_setmetatable(L, -2); - - return 1; -} - -static int dcSetOffset(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - dc->offset_x = luaL_checkint(L, 2); - dc->offset_y = luaL_checkint(L, 3); - return 0; -} - -static int dcGetOffset(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - lua_pushinteger(L, dc->offset_x); - lua_pushinteger(L, dc->offset_y); - return 2; -} - -static int dcSetRotate(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - dc->rotate = luaL_checkint(L, 2); - return 0; -} - -static int dcSetZoom(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - dc->zoom = luaL_checknumber(L, 2); - return 0; -} - -static int dcGetRotate(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - lua_pushinteger(L, dc->rotate); - return 1; -} - -static int dcGetZoom(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - lua_pushnumber(L, dc->zoom); - return 1; -} - -static int dcSetGamma(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - dc->gamma = luaL_checknumber(L, 2); - return 0; -} - -static int dcGetGamma(lua_State *L) { - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); - lua_pushnumber(L, dc->gamma); - return 1; -} - -static const struct luaL_Reg drawcontext_meth[] = { - {"setRotate", dcSetRotate}, - {"getRotate", dcGetRotate}, - {"setZoom", dcSetZoom}, - {"getZoom", dcGetZoom}, - {"setOffset", dcSetOffset}, - {"getOffset", dcGetOffset}, - {"setGamma", dcSetGamma}, - {"getGamma", dcGetGamma}, - {NULL, NULL} -}; - -static const struct luaL_Reg drawcontext_func[] = { - {"new", newDrawContext}, - {NULL, NULL} -}; - -int luaopen_drawcontext(lua_State *L) { - luaL_newmetatable(L, "drawcontext"); - lua_pushstring(L, "__index"); - lua_pushvalue(L, -2); - lua_settable(L, -3); - luaL_register(L, NULL, drawcontext_meth); - lua_pop(L, 1); - luaL_register(L, "DrawContext", drawcontext_func); - return 1; -} diff --git a/ffi/drawcontext.lua b/ffi/drawcontext.lua new file mode 100644 index 000000000..1886cbeac --- /dev/null +++ b/ffi/drawcontext.lua @@ -0,0 +1,40 @@ +--[[ +Drawcontext structure + +FFI frontend +]] + +local ffi = require "ffi" + +ffi.cdef[[ +typedef struct DrawContext { + int rotate; + double zoom; + double gamma; + int offset_x; + int offset_y; +} DrawContext; +]] + +local DC = {} +local DC_mt = {__index={}} + +function DC_mt.__index:setRotate(rotate) self.rotate = rotate end +function DC_mt.__index:getRotate() return self.rotate end +function DC_mt.__index:setZoom(zoom) self.zoom = zoom end +function DC_mt.__index:getZoom() return self.zoom end +function DC_mt.__index:setOffset(x, y) + self.offset_x = x or 0 + self.offset_y = y or 0 +end +function DC_mt.__index:getOffset() return self.offset_x, self.offset_y end +function DC_mt.__index:setGamma(gamma) self.gamma = gamma end +function DC_mt.__index:getGamma() return self.gamma end + +local dctype = ffi.metatype("DrawContext", DC_mt) + +function DC.new(rotate, zoom, x, y, gamma) + return dctype(rotate or 0, zoom or 1.0, gamma or -1.0, x or 0, y or 0) +end + +return DC From e3adb632a3b863083779b7366a6b20f6f5d7ef5a Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:11:22 +0100 Subject: [PATCH 13/21] Switch method to get drawcontext struct pointers from Lua This change is backwards compatible - it will still work for the old way of passing Lua userdata objects. --- djvu.c | 4 ++-- pdf.c | 4 ++-- pic.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/djvu.c b/djvu.c index 9b806a562..1ce0fa8e7 100644 --- a/djvu.c +++ b/djvu.c @@ -238,7 +238,7 @@ static int openPage(lua_State *L) { /* get page size after zoomed */ static int getPageSize(lua_State *L) { DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); lua_pushnumber(L, dc->zoom * page->info.width); lua_pushnumber(L, dc->zoom * page->info.height); @@ -665,7 +665,7 @@ static int drawReflowedPage(lua_State *L) { static int drawPage(lua_State *L) { DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); BlitBuffer *bb = (BlitBuffer*) lua_topointer(L, 3); ddjvu_render_mode_t djvu_render_mode = (int) luaL_checkint(L, 6); unsigned char adjusted_low[16], adjusted_high[16]; diff --git a/pdf.c b/pdf.c index 3e6869f9c..4c33b3527 100644 --- a/pdf.c +++ b/pdf.c @@ -625,7 +625,7 @@ static int getPageSize(lua_State *L) { fz_rect bounds; fz_irect bbox; PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); fz_bound_page(page->doc->xref, page->page, &bounds); fz_scale(&tmp1, dc->zoom, dc->zoom); @@ -923,7 +923,7 @@ static int drawPage(lua_State *L) { fz_irect bbox; PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); BlitBuffer *bb = (BlitBuffer*) lua_topointer(L, 3); bbox.x0 = luaL_checkint(L, 4); bbox.y0 = luaL_checkint(L, 5); diff --git a/pic.c b/pic.c index 31438962b..2b6d5a63d 100644 --- a/pic.c +++ b/pic.c @@ -144,7 +144,7 @@ static void scaleImage(uint8_t *result, uint8_t *image, int width, int height, i static int drawPage(lua_State *L) { PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); BlitBuffer *bb = (BlitBuffer*) lua_topointer(L, 3); int x_offset = MAX(0, dc->offset_x); int y_offset = MAX(0, dc->offset_y); @@ -205,7 +205,7 @@ static int cleanCache(lua_State *L) { static int getPageSize(lua_State *L) { PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage"); - DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + DrawContext *dc = (DrawContext*) lua_topointer(L, 2); lua_pushnumber(L, dc->zoom * page->width); lua_pushnumber(L, dc->zoom * page->height); From c8cd5d341b4df4b169cd2371bfdfaece52b30938 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:13:28 +0100 Subject: [PATCH 14/21] remove Lua header inclusion from drawcontext.h drawcontext.h now only serves to provide the declaration of the drawcontext struct. --- drawcontext.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drawcontext.h b/drawcontext.h index c8440afb5..f601de148 100644 --- a/drawcontext.h +++ b/drawcontext.h @@ -18,10 +18,6 @@ #ifndef _DRAWCONTEXT_H #define _DRAWCONTEXT_H -#include -#include -#include - typedef struct DrawContext { int rotate; double zoom; @@ -30,6 +26,5 @@ typedef struct DrawContext { int offset_y; } DrawContext; -int luaopen_drawcontext(lua_State *L); #endif From 42fd834a9d0218845d34a481d666a9c031c46f98 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:14:51 +0100 Subject: [PATCH 15/21] Major rework of blitbuffer.lua (again...) Optimized blitting is removed for now. 4bpp buffer handling is greatly simplified by using Color4{L,U}:set(...) methods. Inversion and rotation are now done by setting according flags for blitbuffers. Flag storage is done in the "allocated" uint8_t struct variable of the classic blitbuffer struct which is still unchanged (and thus compatible to "classic" C blitbuffers as they were before going to FFI). It is quite fast even without optimized blitting routines. Nevertheless, the method to implement optimized routines is still present, so optimized routines could be created later on. It is probably not wise, though, to focus on 4bpp to much now that we can work with other formats, too. For a lot of rendering, we still do 24bpp or 8bpp to 4bpp conversion in C land, then another 4bpp to 8bpp or 16bpp conversion in Lua/FFI when blitting to the framebuffer. This could further be reduced to one conversion (if at all). --- ffi/blitbuffer.lua | 962 ++++++++++++++++++--------------------------- 1 file changed, 388 insertions(+), 574 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 0e677c71f..54feafbf9 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -14,203 +14,206 @@ local bxor = bit.bxor local intt = ffi.typeof("int") local uint32pt = ffi.typeof("uint32_t*") +local uint8pt = ffi.typeof("uint8_t*") local posix = require("ffi/posix_h") -- the following definitions are redundant. -- they need to be since only this way we can set -- different metatables for them. ffi.cdef[[ +typedef struct Color4L { + uint8_t a; +} Color4L; +typedef struct Color4U { + uint8_t a; +} Color4U; +typedef struct Color8 { + uint8_t a; +} Color8; +typedef struct Color8A { + uint8_t a; + uint8_t dummy; // only support pre-multiplied for now +} Color8A; +typedef struct Color16 { + uint16_t a; +} Color16; +typedef struct ColorRGB24 { + uint8_t r; + uint8_t g; + uint8_t b; +} ColorRGB24; +typedef struct ColorRGB32 { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} ColorRGB32; + typedef struct BlitBuffer4 { int w; int h; int pitch; uint8_t *data; - uint8_t allocated; + uint8_t config; } BlitBuffer4; typedef struct BlitBuffer8 { int w; int h; int pitch; - uint8_t *data; - uint8_t allocated; + Color8 *data; + uint8_t config; } BlitBuffer8; -typedef struct BlitBufferA8 { +typedef struct BlitBuffer8A { int w; int h; int pitch; - uint8_t *data; - uint8_t allocated; -} BlitBufferA8; + Color8A *data; + uint8_t config; +} BlitBuffer8A; typedef struct BlitBuffer16 { int w; int h; int pitch; - uint8_t *data; - uint8_t allocated; + Color16 *data; + uint8_t config; } BlitBuffer16; typedef struct BlitBufferRGB24 { int w; int h; int pitch; - uint8_t *data; - uint8_t allocated; + ColorRGB24 *data; + uint8_t config; } BlitBufferRGB24; typedef struct BlitBufferRGB32 { int w; int h; int pitch; - uint8_t *data; - uint8_t allocated; + ColorRGB32 *data; + uint8_t config; } BlitBufferRGB32; -typedef struct Color4L { - uint8_t a; -} Color4L; -typedef struct Color4U { - uint8_t a; -} Color4U; -typedef struct Color8 { - uint8_t a; -} Color8; -typedef struct ColorA8 { - uint8_t a; - uint8_t dummy; // only support pre-multiplied for now -} ColorA8; -typedef struct Color16 { - uint16_t a; -} Color16; -typedef struct ColorRGB24 { - uint8_t r; - uint8_t g; - uint8_t b; -} ColorRGB24; -typedef struct ColorRGB32 { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -} ColorRGB32; - void *malloc(int size); void free(void *ptr); void *memset(void *s, int c, int n); ]] -local BB = {} - --- this is only needed for casting userdata from the Lua/C API: -local BBtype = ffi.typeof("BlitBuffer4*") - -- color value types local Color4U = ffi.typeof("Color4U") local Color4L = ffi.typeof("Color4L") local Color8 = ffi.typeof("Color8") -local ColorA8 = ffi.typeof("ColorA8") +local Color8A = ffi.typeof("Color8A") local Color16 = ffi.typeof("Color16") local ColorRGB24 = ffi.typeof("ColorRGB24") local ColorRGB32 = ffi.typeof("ColorRGB32") +-- metatables for color pointers +local P_Color4U_mt = {__index={}} + +function P_Color4U_mt.__index:set(color) +end + -- color value pointer types local P_Color4U = ffi.typeof("Color4U*") local P_Color4L = ffi.typeof("Color4L*") local P_Color8 = ffi.typeof("Color8*") -local P_ColorA8 = ffi.typeof("ColorA8*") +local P_Color8A = ffi.typeof("Color8A*") local P_Color16 = ffi.typeof("Color16*") local P_ColorRGB24 = ffi.typeof("ColorRGB24*") local P_ColorRGB32 = ffi.typeof("ColorRGB32*") --- metatables for BlitBuffer objects: -local BB4_mt = {__index={}} -local BB8_mt = {__index={}} -local BBA8_mt = {__index={}} -local BB16_mt = {__index={}} -local BBRGB24_mt = {__index={}} -local BBRGB32_mt = {__index={}} - --- virtual blitbuffers: -local BB_rotated_mt = {__index={}} -local BB_inverted_mt = {__index={}} -local BB_masked_mt = {__index={}} - --- this is like a metatable for the others, --- but we don't make it a metatable because LuaJIT --- doesn't cope well with ctype metatables with --- metatables on them --- we just replicate what's in the following table --- when we set the other metatables for their types -local BB_mt = {__index={}} - -- metatables for color types: local Color4L_mt = {__index={}} local Color4U_mt = {__index={}} local Color8_mt = {__index={}} -local ColorA8_mt = {__index={}} +local Color8A_mt = {__index={}} local Color16_mt = {__index={}} local ColorRGB24_mt = {__index={}} local ColorRGB32_mt = {__index={}} --- getPixelP (pointer) routines -function BB4_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - local p = self.data + self.pitch*y + rshift(x, 1) - if band(x, 1) == 0 then - return ffi.cast(P_Color4U, p), true - else - return ffi.cast(P_Color4L, p), false - end +-- color setting +function Color4L_mt.__index:set(color) + self.a = bor(band(0xF0, self.a), color:getColor4L().a) end -function BB8_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - return ffi.cast(P_Color8, self.data + self.pitch*y + x) +function Color4U_mt.__index:set(color) + self.a = bor(band(0x0F, self.a), color:getColor4U().a) end -function BBA8_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - return ffi.cast(P_ColorA8, self.data + self.pitch*y + lshift(x,1)) +function Color8_mt.__index:set(color) self.a = color:getColor8().a end +function Color8A_mt.__index:set(color) self.a = color:getColor8A().a end +function Color16_mt.__index:set(color) self.a = color:getColor16().a end +function ColorRGB24_mt.__index:set(color) + local c = color:getColorRGB24() + self.r = c.r + self.g = c.g + self.b = c.b end -function BB16_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - return ffi.cast(P_Color16, self.data + self.pitch*y + lshift(x,1)) +function ColorRGB32_mt.__index:set(color) + local c = color:getColorRGB32() + self.r = c.r + self.g = c.g + self.b = c.b end -function BBRGB24_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - return ffi.cast(P_ColorRGB24, self.data + self.pitch*y + x*3) +-- adding two colors: +function Color4L_mt.__index:add(color, intensity) + local value = tonumber(self.a) * (1-intensity) + tonumber(color:getColor4L().a) * intensity + if value > 0x0F then value = 0x0F end + self:set(Color4L(value)) end -function BBRGB32_mt.__index:getPixelP(x, y) - --self:checkCoordinates(x, y) - return ffi.cast(P_ColorRGB32, self.data + self.pitch*y + lshift(x,2)) -end -function BB_rotated_mt.__index:getPixelP(x, y) - if self.degree == 90 then - return self.bb:getPixelP(self.bb.w - y - 1, x) - elseif self.degree == 180 then - return self.bb:getPixelP(self.bb.w - x - 1, self.bb.h - y - 1) - elseif self.degree == 270 then - return self.bb:getPixelP(y, self.bb.h - x - 1) - end - error("could not get pixel pointer for this rotation") +function Color4U_mt.__index:add(color, intensity) + local orig = band(self.a, 0xF0) + local value = tonumber(orig) * (1-intensity) + tonumber(color:getColor4U().a) * intensity + if value > 0xF0 then value = 0xF0 end + self:set(Color4U(band(0xF0, value))) end -function BB_inverted_mt.__index:getPixelP(x, y) - return self.bb:getPixelP(x, y) +function Color8_mt.__index:add(color, intensity) + local value = tonumber(self.a) * (1-intensity) + tonumber(color:getColor8().a) * intensity + if value > 0xFF then value = 0xFF end + self:set(Color8(value)) end - --- coordinate checking ---function BB_mt.__index:checkCoordinates(x, y) end -function BB_mt.__index:checkCoordinates(x, y) - assert(x >= 0, "x coordinate >= 0") - assert(y >= 0, "y coordinate >= 0") - assert(x < self.w, "x coordinate < width") - assert(y < self.h, "y coordinate < height") +Color8A_mt.__index.add = Color8_mt.__index.add +function Color16_mt.__index:add(color, intensity) + local value = tonumber(self.a) * (1-intensity) + tonumber(color:getColor16().a) * intensity + if value > 0xFFFF then value = 0xFFFF end + self:set(Color16(value)) end - -function BB_mt.__index:getPixel(x, y) return self:getPixelP(x, y)[0] end -function BB_inverted_mt.__index:getPixel(x, y) return self:getPixelP(x, y)[0]:invert() end +function ColorRGB24_mt.__index:add(color, intensity) + local r = tonumber(self:getR()) * (1-intensity) + tonumber(color:getR()) * intensity + if r > 255 then r = 255 end + local g = tonumber(self:getG()) * (1-intensity) + tonumber(color:getG()) * intensity + if g > 255 then g = 255 end + local b = tonumber(self:getB()) * (1-intensity) + tonumber(color:getB()) * intensity + if b > 255 then b = 255 end + self:set(ColorRGB24(r, g, b)) +end +ColorRGB32_mt.__index.add = ColorRGB24_mt.__index.add +-- dimming +function Color4L_mt.__index:dim() + self:set(Color8(rshift(self:getColor8().a, 1))) +end +Color4U_mt.__index.dim = Color4L_mt.__index.dim +Color8_mt.__index.dim = Color4L_mt.__index.dim +Color8A_mt.__index.dim = Color4L_mt.__index.dim +Color16_mt.__index.dim = Color4L_mt.__index.dim +ColorRGB24_mt.__index.dim = Color4L_mt.__index.dim +ColorRGB32_mt.__index.dim = Color4L_mt.__index.dim +-- lighten up +function Color4L_mt.__index:lighten(low) + local value = self:getColor4L().a + low = low * 0x0F + if value < low then self:set(Color4L(low)) end +end +Color4U_mt.__index.lighten = Color4L_mt.__index.lighten +Color8_mt.__index.lighten = Color4L_mt.__index.lighten +Color8A_mt.__index.lighten = Color4L_mt.__index.lighten +Color16_mt.__index.lighten = Color4L_mt.__index.lighten +ColorRGB24_mt.__index.lighten = Color4L_mt.__index.lighten +ColorRGB32_mt.__index.lighten = Color4L_mt.__index.lighten -- color conversions: -- to Color4L: -function Color4L_mt.__index:getColor4L() return Color4L(band(self.a, 0x0F)) end +function Color4L_mt.__index:getColor4L() return Color4L(band(0x0F, self.a)) end function Color4U_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end function Color8_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end -function ColorA8_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end +function Color8A_mt.__index:getColor4L() return Color4L(rshift(self.a, 4)) end function Color16_mt.__index:getColor4L() return Color4L(rshift(self.a, 12)) end --[[ Uses luminance match for approximating the human perception of colour, as per @@ -225,48 +228,48 @@ ColorRGB32_mt.__index.getColor4L = ColorRGB24_mt.__index.getColor4L -- to Color4U: function Color4L_mt.__index:getColor4U() return Color4U(lshift(self.a, 4)) end -function Color4U_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end -function Color8_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end -function ColorA8_mt.__index:getColor4U() return Color4U(band(self.a, 0xF0)) end -function Color16_mt.__index:getColor4U() return Color4U(band(rshift(self.a,8),0xF0)) end +function Color4U_mt.__index:getColor4U() return Color4U(band(0xF0, self.a)) end +function Color8_mt.__index:getColor4U() return Color4U(band(0xF0, self.a)) end +function Color8A_mt.__index:getColor4U() return Color4U(band(0xF0, self.a)) end +function Color16_mt.__index:getColor4U() return Color4U(band(0xF0, rshift(self.a,8))) end function ColorRGB24_mt.__index:getColor4U() - return Color4U(band(rshift(4897*self.r + 9617*self.g + 1868*self.b, 14), 0xF0)) + return Color4U(band(0xF0, rshift(4897*self.r + 9617*self.g + 1868*self.b, 14))) end ColorRGB32_mt.__index.getColor4U = ColorRGB24_mt.__index.getColor4U -- to Color8: function Color4L_mt.__index:getColor8() - local v = band(self.a, 0x0F) + local v = band(0x0F, self.a) return Color8(v*0x11) end function Color4U_mt.__index:getColor8() - local v = band(self.a, 0xF0) + local v = band(0xF0, self.a) return Color8(bor(rshift(v, 4), v)) end function Color8_mt.__index:getColor8() return self end -function ColorA8_mt.__index:getColor8() return Color8(self.a) end +function Color8A_mt.__index:getColor8() return Color8(self.a) end function Color16_mt.__index:getColor8() return Color8(self.a) end function ColorRGB24_mt.__index:getColor8() return Color8(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) end ColorRGB32_mt.__index.getColor8 = ColorRGB24_mt.__index.getColor8 --- to ColorA8: -function Color4L_mt.__index:getColorA8() - local v = band(self.a, 0x0F) - return ColorA8(v*0x11) +-- to Color8A: +function Color4L_mt.__index:getColor8A() + local v = band(0x0F, self.a) + return Color8A(v*0x11) end -function Color4U_mt.__index:getColorA8() - local v = band(self.a, 0xF0) - return ColorA8(bor(rshift(v, 4), v)) +function Color4U_mt.__index:getColor8A() + local v = band(0xF0, self.a) + return Color8A(bor(rshift(v, 4), v)) end -function Color8_mt.__index:getColorA8() return ColorA8(self.a) end -function ColorA8_mt.__index:getColorA8() return self end -function Color16_mt.__index:getColorA8() return ColorA8(self.a) end -function ColorRGB24_mt.__index:getColorA8() - return ColorA8(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) +function Color8_mt.__index:getColor8A() return Color8A(self.a) end +function Color8A_mt.__index:getColor8A() return self end +function Color16_mt.__index:getColor8A() return Color8A(self.a) end +function ColorRGB24_mt.__index:getColor8A() + return Color8A(rshift(4897*self:getR() + 9617*self:getG() + 1868*self:getB(), 14)) end -ColorRGB32_mt.__index.getColorA8 = ColorRGB24_mt.__index.getColorA8 +ColorRGB32_mt.__index.getColor8A = ColorRGB24_mt.__index.getColor8A -- to Color16: function Color4L_mt.__index:getColor16() @@ -275,7 +278,7 @@ function Color4L_mt.__index:getColor16() end Color4U_mt.__index.getColor16 = Color4L_mt.__index.getColor16 Color8_mt.__index.getColor16 = Color4L_mt.__index.getColor16 -ColorA8_mt.__index.getColor16 = Color4L_mt.__index.getColor16 +Color8A_mt.__index.getColor16 = Color4L_mt.__index.getColor16 function Color16_mt.__index.getColor16() return self end ColorRGB24_mt.__index.getColor16 = Color4L_mt.__index.getColor16 ColorRGB32_mt.__index.getColor16 = Color4L_mt.__index.getColor16 @@ -287,7 +290,7 @@ function Color4L_mt.__index:getColorRGB24() end Color4U_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color8_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 -ColorA8_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 +Color8A_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 Color16_mt.__index.getColorRGB24 = Color4L_mt.__index.getColorRGB24 function ColorRGB24_mt.__index:getColorRGB24() return self end function ColorRGB32_mt.__index:getColorRGB24() return ColorRGB24(self.r, self.g, self.b) end @@ -299,27 +302,27 @@ function Color4L_mt.__index:getColorRGB32() end Color4U_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color8_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 -ColorA8_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 +Color8A_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 Color16_mt.__index.getColorRGB32 = Color4L_mt.__index.getColorRGB32 function ColorRGB24_mt.__index:getColorRGB32() return ColorRGB32(self.r, self.g, self.b) end function ColorRGB32_mt.__index:getColorRGB32() return self end -- RGB getters (special case for 4bpp mode) -Color4L_mt.__index.getR = Color4L_mt.__index.getColor8 -Color4L_mt.__index.getG = Color4L_mt.__index.getColor8 -Color4L_mt.__index.getB = Color4L_mt.__index.getColor8 -Color4U_mt.__index.getR = Color4U_mt.__index.getColor8 -Color4U_mt.__index.getG = Color4U_mt.__index.getColor8 -Color4U_mt.__index.getB = Color4U_mt.__index.getColor8 -Color8_mt.__index.getR = Color8_mt.__index.getColor8 -Color8_mt.__index.getG = Color8_mt.__index.getColor8 -Color8_mt.__index.getB = Color8_mt.__index.getColor8 -ColorA8_mt.__index.getR = ColorA8_mt.__index.getColor8 -ColorA8_mt.__index.getG = ColorA8_mt.__index.getColor8 -ColorA8_mt.__index.getB = ColorA8_mt.__index.getColor8 -Color16_mt.__index.getR = Color16_mt.__index.getColor8 -Color16_mt.__index.getG = Color16_mt.__index.getColor8 -Color16_mt.__index.getB = Color16_mt.__index.getColor8 +function Color4L_mt.__index:getR() return self:getColor8().a end +Color4L_mt.__index.getG = Color4L_mt.__index.getR +Color4L_mt.__index.getB = Color4L_mt.__index.getR +Color4U_mt.__index.getR = Color4L_mt.__index.getR +Color4U_mt.__index.getG = Color4L_mt.__index.getR +Color4U_mt.__index.getB = Color4L_mt.__index.getR +Color8_mt.__index.getR = Color4L_mt.__index.getR +Color8_mt.__index.getG = Color4L_mt.__index.getR +Color8_mt.__index.getB = Color4L_mt.__index.getR +Color8A_mt.__index.getR = Color4L_mt.__index.getR +Color8A_mt.__index.getG = Color4L_mt.__index.getR +Color8A_mt.__index.getB = Color4L_mt.__index.getR +Color16_mt.__index.getR = Color4L_mt.__index.getR +Color16_mt.__index.getG = Color4L_mt.__index.getR +Color16_mt.__index.getB = Color4L_mt.__index.getR function ColorRGB24_mt.__index:getR() return self.r end function ColorRGB24_mt.__index:getG() return self.g end function ColorRGB24_mt.__index:getB() return self.b end @@ -332,7 +335,7 @@ ColorRGB32_mt.__index.getB = ColorRGB24_mt.__index.getB function Color4L_mt.__index:invert() return Color4L(bxor(self.a, 0x0F)) end function Color4U_mt.__index:invert() return Color4U(bxor(self.a, 0xF0)) end function Color8_mt.__index:invert() return Color8(bxor(self.a, 0xFF)) end -function ColorA8_mt.__index:invert() return ColorA8(bxor(self.a, 0xFF)) end +function Color8A_mt.__index:invert() return Color8A(bxor(self.a, 0xFF)) end function Color16_mt.__index:invert() return Color16(bxor(self.a, 0xFFFF)) end function ColorRGB24_mt.__index:invert() return ColorRGB24(bxor(self.r, 0xFF), bxor(self.g, 0xFF), bxor(self.b, 0xFF)) @@ -340,246 +343,195 @@ end function ColorRGB32_mt.__index:invert() return ColorRGB32(bxor(self.r, 0xFF), bxor(self.g, 0xFF), bxor(self.b, 0xFF)) end --- adding two colors: -function Color4L_mt.__index:add(color, intensity) - local value = tonumber(self.a) * intensity + tonumber(color:getColor4L().a) * (1-intensity) - if value > 0x0F then value = 0x0F end - return Color4L(value) -end -function Color4U_mt.__index:add(color, intensity) - local orig = band(self.a, 0xF0) - local value = tonumber(orig) * intensity + tonumber(color:getColor4U().a) * (1-intensity) - if value > 0xF0 then value = 0xF0 end - --return Color4U(band(ffi.cast("uint8_t", value), 0xF0)) - return Color4U(band(value, 0xF0)) -end -function Color8_mt.__index:add(color, intensity) - local value = tonumber(self.a) * intensity + tonumber(color:getColor8().a) * (1-intensity) - if value > 0xFF then value = 0xFF end - return Color8(value) + + + + +local MASK_ALLOCATED = 0x01 +local SHIFT_ALLOCATED = 0 +local MASK_INVERSE = 0x02 +local SHIFT_INVERSE = 1 +local MASK_ROTATED = 0x0C +local SHIFT_ROTATED = 2 +local MASK_TYPE = 0xF0 +local SHIFT_TYPE = 4 + +local TYPE_BB4 = 0 +local TYPE_BB8 = 1 +local TYPE_BB8A = 2 +local TYPE_BB16 = 3 +local TYPE_BBRGB24 = 4 +local TYPE_BBRGB32 = 5 + +local BB = {} + +-- metatables for BlitBuffer objects: +local BB4_mt = {__index={}} +local BB8_mt = {__index={}} +local BB8A_mt = {__index={}} +local BB16_mt = {__index={}} +local BBRGB24_mt = {__index={}} +local BBRGB32_mt = {__index={}} + +-- this is like a metatable for the others, +-- but we don't make it a metatable because LuaJIT +-- doesn't cope well with ctype metatables with +-- metatables on them +-- we just replicate what's in the following table +-- when we set the other metatables for their types +local BB_mt = {__index={}} + +function BB_mt.__index:getRotation() + return rshift(band(MASK_ROTATED, self.config), SHIFT_ROTATED) end -function ColorA8_mt.__index:add(color, intensity) - return self:getColor8():add(color, intensity):getColorA8() +function BB_mt.__index:setRotation(rotation_mode) + self.config = bor(band(self.config, bxor(MASK_ROTATED, 0xFF)), lshift(rotation_mode, SHIFT_ROTATED)) end -function Color16_mt.__index:add(color, intensity) - local value = tonumber(self.a) * intensity + tonumber(color:getColor16().a) * (1-intensity) - if value > 0xFFFF then value = 0xFFFF end - return Color16(value) +function BB_mt.__index:rotateAbsolute(degree) + local mode = (degree % 360) / 90 + self:setRotation(mode) + return self end -function ColorRGB24_mt.__index:add(color, intensity) - local r = tonumber(self:getR()) * intensity + tonumber(color:getR()) * (1-intensity) - if r > 255 then r = 255 end - local g = tonumber(self:getG()) * intensity + tonumber(color:getG()) * (1-intensity) - if g > 255 then g = 255 end - local b = tonumber(self:getB()) * intensity + tonumber(color:getB()) * (1-intensity) - if b > 255 then b = 255 end - return ColorRGB24(r, g, b) +function BB_mt.__index:rotate(degree) + degree = degree + self:getRotation()*90 + return self:rotateAbsolute(degree) end -function ColorRGB32_mt.__index:add(color, intensity) - return ColorRGB24_mt.__index.add(self, color, intensity):getColorRGB32() +function BB_mt.__index:getInverse() + return rshift(band(MASK_INVERSE, self.config), SHIFT_INVERSE) end --- dimming -function Color4L_mt.__index:dim() - return Color8(rshift(self:getColor8().a, 1)) +function BB_mt.__index:setInverse(inverse) + self.config = bor(band(self.config, bxor(MASK_INVERSE, 0xFF)), lshift(inverse, SHIFT_INVERSE)) end -Color4U_mt.__index.dim = Color4L_mt.__index.dim -Color8_mt.__index.dim = Color4L_mt.__index.dim -ColorA8_mt.__index.dim = Color4L_mt.__index.dim -Color16_mt.__index.dim = Color4L_mt.__index.dim -ColorRGB24_mt.__index.dim = Color4L_mt.__index.dim -ColorRGB32_mt.__index.dim = Color4L_mt.__index.dim --- lighten up -function Color4L_mt.__index:lighten(low) - local value = self:getColor4L().a - low = low * 0x0F - if value < low then return Color4L(low) end +function BB_mt.__index:invert() + self:setInverse((self:getInverse() + 1) % 2) return self end -Color4U_mt.__index.lighten = Color4L_mt.__index.lighten -Color8_mt.__index.lighten = Color4L_mt.__index.lighten -ColorA8_mt.__index.lighten = Color4L_mt.__index.lighten -Color16_mt.__index.lighten = Color4L_mt.__index.lighten -ColorRGB24_mt.__index.lighten = Color4L_mt.__index.lighten -ColorRGB32_mt.__index.lighten = Color4L_mt.__index.lighten --- masking -function Color4L_mt.__index:mask(fg, bg) - return fg:add(bg, tonumber(self:getColor8().a) / 0xFF) +function BB_mt.__index:getAllocated() + return rshift(band(MASK_ALLOCATED, self.config), SHIFT_ALLOCATED) end -Color4U_mt.__index.mask = Color4L_mt.__index.mask -Color8_mt.__index.mask = Color4L_mt.__index.mask -ColorA8_mt.__index.mask = Color4L_mt.__index.mask -Color16_mt.__index.mask = Color4L_mt.__index.mask -ColorRGB24_mt.__index.mask = Color4L_mt.__index.mask -ColorRGB32_mt.__index.mask = Color4L_mt.__index.mask - -function BB4_mt.__index.getMyColor(color) return color:getColor4L() end -function BB8_mt.__index.getMyColor(color) return color:getColor8() end -function BBA8_mt.__index.getMyColor(color) return color:getColorA8() end -function BB16_mt.__index.getMyColor(color) return color:getColor16() end -function BBRGB24_mt.__index.getMyColor(color) return color:getColorRGB24() end -function BBRGB32_mt.__index.getMyColor(color) return color:getColorRGB32() end - -function BB_mt.__index:isInverted() return false end -function BB_inverted_mt.__index:isInverted() return true end -function BB_mt.__index:invert() - if self:isInverted() then return self.bb end - local bb = { - bb = self, - w = self.w, - h = self.h, - pitch = self.pitch, - data = self.data, - blitfunc = self.blitfunc, - getMyColor = self.getMyColor - } - setmetatable(bb, BB_inverted_mt) - return bb +function BB_mt.__index:setAllocated(allocated) + self.config = bor(band(self.config, bxor(MASK_ALLOCATED, 0xFF)), lshift(allocated, SHIFT_ALLOCATED)) end -function BB_mt.__index:isRotated() return false end -function BB_rotated_mt.__index:isRotated() return true end -function BB_mt.__index:rotate(degree) - local backing_bb = self - if self:isRotated() then - -- combine rotations - degree = (degree + self.degree) - backing_bb = self.bb - end - degree = degree % 360 - if degree == 0 then return self.bb end - local bb = { - bb = backing_bb, - w = self.w, - h = self.h, - degree = degree, - pitch = backing_bb.pitch, - data = backing_bb.data, - getMyColor = backing_bb.getMyColor, - select_y_upper = 2, - select_x_upper = 2 - } - if degree == 90 or degree == 270 then - bb.w = backing_bb.h - bb.h = backing_bb.w +function BB_mt.__index:getType() + return rshift(band(MASK_TYPE, self.config), SHIFT_TYPE) +end +function BB4_mt.__index:getBpp() return 4 end +function BB8_mt.__index:getBpp() return 8 end +function BB8A_mt.__index:getBpp() return 8 end +function BB16_mt.__index:getBpp() return 16 end +function BBRGB24_mt.__index:getBpp() return 24 end +function BBRGB32_mt.__index:getBpp() return 32 end +function BB_mt.__index:isRGB() + local bb_type = self:getType() + if bb_type == TYPE_BBRGB24 then + return true + elseif bb_type == TYPE_BBRGB32 then + return true end - if degree == 90 then bb.select_y_upper = 1 - elseif degree == 180 then bb.select_x_upper = 1 - elseif degree == 270 then bb.select_y_upper = 0 + return false +end +function BB_mt.__index:setType(type_id) + self.config = bor(band(self.config, bxor(MASK_TYPE, 0xFF)), lshift(type_id, SHIFT_TYPE)) +end +function BB_mt.__index:getPhysicalCoordinates(x, y) + local rotation = self:getRotation() + if rotation == 0 then + return x, y + elseif rotation == 1 then + return self.w - y - 1, x + elseif rotation == 2 then + return self.w - x - 1, self.h - y - 1 + elseif rotation == 3 then + return y, self.h - x - 1 end - setmetatable(bb, BB_rotated_mt) - return bb end -BB_mt.__index.rotateAbsolute = BB_mt.__index.rotate -function BB_rotated_mt.__index:rotateAbsolute(degree) - return self:rotate(degree - self.degree) +function BB_mt.__index:getPhysicalRect(x, y, w, h) + local px1, py1 = self:getPhysicalCoordinates(x, y) + local px2, py2 = self:getPhysicalCoordinates(x+w, y+h) + return math.min(px1, px2), math.min(py1, py2), w, h end -function BB_mt.__index:getBpp() return self.bb:getBpp() end -function BB_mt.__index:isRGB() return self.bb:isRGB() end --- set pixel values -function BB_mt.__index:setPixel(x, p, color) - if x then p = self:getPixelP(x, p) end - p[0] = self.getMyColor(color) -end --- two-pixel setting for 4bpp mode -function BB4_mt.__index:setPixel(x, y, color, dummy, color2) - if x then - local p, is_upper = self:getPixelP(x, y) - if is_upper then - p[0].a = bor(band(p[0].a, 0x0F), color:getColor4U().a) - else - p[0].a = bor(band(p[0].a, 0xF0), color:getColor4L().a) - end +-- physical coordinate checking +function BB_mt.__index:checkCoordinates(x, y) + assert(x >= 0, "x coordinate >= 0") + assert(y >= 0, "y coordinate >= 0") + assert(x < self.w, "x coordinate < width") + assert(y < self.h, "y coordinate < height") +end + +-- getPixelP (pointer) routines, working on physical coordinates +function BB_mt.__index:getPixelP(x, y) + --self:checkCoordinates(x, y) + return ffi.cast(self.data, ffi.cast(uint8pt, self.data) + self.pitch*y) + x +end +function BB4_mt.__index:getPixelP(x, y) + --self:checkCoordinates(x, y) + local p = self.data + self.pitch*y + rshift(x, 1) + if band(x, 1) == 0 then + return ffi.cast(P_Color4U, p) else - local p = y - p[0].a = bor( - (color and color:getColor4U().a) or band(p[0].a, 0xF0), - (color2 and color2:getColor4L().a) or band(p[0].a, 0x0F) - ) + return ffi.cast(P_Color4L, p) end end -function BB_inverted_mt.__index:setPixel(x, p, color, dummy, color2) - -- this will work for both 4bpp and other modes - self.bb:setPixelInverted(x, p, color, dummy, color2) +function BB_mt.__index:getPixel(x, y) + local px, py = self:getPhysicalCoordinates(x, y) + local color = self:getPixelP(px, py)[0] + if self:getInverse() == 1 then color = color:invert() end + return color end -function BB_mt.__index:setPixelInverted(x, p, color) - self:setPixel(x, p, color:invert()) -end -function BB4_mt.__index:setPixelInverted(x, p, color, dummy, color2) - self:setPixel(x, p, color and color:invert(), dummy, color2 and color2:invert()) -end -function BB_inverted_mt.__index:setPixelInverted(x, p, color, dummy, color2) - -- this will work for both 4bpp and other modes - self.bb:setPixel(x, p, color, dummy, color2) -end +-- blitbuffer specific color conversions +function BB4_mt.__index.getMyColor(color) return color:getColor4L() end +function BB8_mt.__index.getMyColor(color) return color:getColor8() end +function BB8A_mt.__index.getMyColor(color) return color:getColor8A() end +function BB16_mt.__index.getMyColor(color) return color:getColor16() end +function BBRGB24_mt.__index.getMyColor(color) return color:getColorRGB24() end +function BBRGB32_mt.__index.getMyColor(color) return color:getColorRGB32() end -function BB_mt.__index:setPixelAdd(x, p, color, intensity) - if x then p = self:getPixelP(x, p) end - p[0] = self.getMyColor(color):add(p[0], intensity) -end -function BB4_mt.__index:setPixelAdd(x, p, color, intensity, color2) - if x then - p = self:getPixelP(x, p) - if band(x, 1) == 1 then - color2 = color - color = nil - end - end - local v1 = band(p[0].a, 0xF0) - local v2 = band(p[0].a, 0x0F) - if color then - v1 = tonumber(v1) * (1-intensity) + tonumber(color:getColor4U().a) * intensity - if v1 > 0xF0 then v1 = 0xF0 end - v1 = band(v1, 0xF0) - end - if color2 then - v2 = tonumber(v2) * (1-intensity) + tonumber(color2:getColor4L().a) * intensity - if v2 > 0x0F then v2 = 0x0F end - end - p[0].a = bor(v1, v2) +-- set pixel values +function BB_mt.__index:setPixel(x, y, color) + local px, py = self:getPhysicalCoordinates(x, y) + if self:getInverse() == 1 then color = color:invert() end + self:getPixelP(px, py)[0]:set(color) end - -function BB_mt.__index:setPixelDim(x, p, color, dummy, color2) - -- this will work for both 4bpp and other modes - self:setPixel(x, p, color and color:dim(), dummy, color2 and color2:dim()) +function BB_mt.__index:setPixelAdd(x, y, color, intensity) + local px, py = self:getPhysicalCoordinates(x, y) + if self:getInverse() == 1 then color = color:invert() end + self:getPixelP(px, py)[0]:add(color, intensity) end - -function BB_mt.__index:setPixelLighten(x, p, color, low, color2) - -- this will work for both 4bpp and other modes - self:setPixel(x, p, color and color:lighten(low), dummy, color2 and color2:lighten(low)) +function BB_mt.__index:setPixelInverted(x, y, color) + self:setPixel(x, y, color:invert()) end -- checked Pixel setting: function BB_mt.__index:setPixelClamped(x, y, color) - if x >= 0 and x < self.w and y >= 0 and y < self.h then + if x >= 0 and x < self:getWidth() and y >= 0 and y < self:getHeight() then self:setPixel(x, y, color) end end -function BB4_mt.__index:getBpp() return 4 end -function BB8_mt.__index:getBpp() return 8 end -function BBA8_mt.__index:getBpp() return 16 end -function BB16_mt.__index:getBpp() return 16 end -function BBRGB24_mt.__index:getBpp() return 24 end -function BBRGB32_mt.__index:getBpp() return 32 end - -function BB4_mt.__index:isRGB() return false end -function BB8_mt.__index:isRGB() return false end -function BBA8_mt.__index:isRGB() return false end -function BB16_mt.__index:isRGB() return false end -function BBRGB24_mt.__index:isRGB() return true end -function BBRGB32_mt.__index:isRGB() return true end - --- compatibility functions for accessing dimensions -function BB_mt.__index:getWidth() return self.w end -function BB_mt.__index:getHeight() return self.h end +-- functions for accessing dimensions +function BB_mt.__index:getWidth() + if 0 == bit.band(1, self:getRotation()) then + return self.w + else + return self.h + end +end +function BB_mt.__index:getHeight() + if 0 == bit.band(1, self:getRotation()) then + return self.h + else + return self.w + end +end -- names of optimized blitting routines BB_mt.__index.blitfunc = "blitDefault" -- not optimized BB4_mt.__index.blitfunc = "blitTo4" BB8_mt.__index.blitfunc = "blitTo8" -BBA8_mt.__index.blitfunc = "blitToA8" +BB8A_mt.__index.blitfunc = "blitTo8A" BB16_mt.__index.blitfunc = "blitTo16" BBRGB24_mt.__index.blitfunc = "blitToRGB24" BBRGB32_mt.__index.blitfunc = "blitToRGB32" @@ -597,7 +549,7 @@ generic boundary check for copy operations @return adapted target offset, guaranteed within range 0..(target_size-1) @return adapted source offset, guaranteed within range 0..(source_size-1) --]] -local function checkBounds(length, target_offset, source_offset, target_size, source_size) +function BB.checkBounds(length, target_offset, source_offset, target_size, source_size) -- deal with negative offsets if target_offset < 0 then length = length + target_offset @@ -642,173 +594,15 @@ end -- no optimized blitting by default: BB_mt.__index.blitTo4 = BB_mt.__index.blitDefault BB_mt.__index.blitTo8 = BB_mt.__index.blitDefault -BB_mt.__index.blitToA8 = BB_mt.__index.blitDefault +BB_mt.__index.blitTo8A = BB_mt.__index.blitDefault BB_mt.__index.blitTo16 = BB_mt.__index.blitDefault BB_mt.__index.blitToRGB24 = BB_mt.__index.blitDefault BB_mt.__index.blitToRGB32 = BB_mt.__index.blitDefault --- slightly optimized default routine for blitting to 4bpp buffers -function BB_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) - local o_y = offs_y - if band(dest_x, 1) == 1 then - -- one "odd" column to process first - for y = dest_y, dest_y+height-1 do - setter(dest, dest_x, y, self:getPixel(offs_x, o_y), set_param) - o_y = o_y + 1 - end - dest_x = dest_x + 1 - offs_x = offs_x + 1 - width = width - 1 - o_y = offs_y - end - if band(width, 1) == 1 then - -- one "odd" column at the end of each line - local x = dest_x + width - 1 - local o_x = offs_x + width - 1 - for y = dest_y, dest_y+height-1 do - setter(dest, x, y, self:getPixel(o_x, o_y), set_param) - o_y = o_y + 1 - end - width = width - 1 - o_y = offs_y - end - if width == 0 then return end - -- now do the "doubles" in between - for y = dest_y, dest_y+height-1 do - local o_x = offs_x - local p = dest:getPixelP(dest_x, y) - for x = 0, width-2, 2 do - setter(dest, nil, p, self:getPixel(o_x, o_y), set_param, self:getPixel(o_x+1, o_y)) - p = p + 1 - o_x = o_x + 2 - end - o_y = o_y + 1 - end - return true -end - --- optimized 4bpp to 4bpp blitting -function BB4_mt.__index:blitTo4(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) - local o_y = offs_y - for y = dest_y, dest_y+height-1 do - local w = width - local dest_p = dest:getPixelP(dest_x, y) - local source_p = self:getPixelP(offs_x, o_y) - if band(offs_x, 1) == 1 then - -- odd source x coordinate - local nv = source_p[0] - source_p = source_p + 1 - if band(dest_x, 1) == 1 then - -- ... and odd destination x coordinate - setter(dest, nil, dest_p, nil, set_param, nv) - dest_p = dest_p + 1 - w = w - 1 - while w > 1 do - nv = source_p[0] - setter(dest, nil, dest_p, Color4U(nv.a), set_param, nv) - source_p = source_p + 1 - dest_p = dest_p + 1 - w = w - 2 - end - if w > 0 then - setter(dest, nil, dest_p, Color4U(source_p[0].a), set_param, nil) - end - else - -- even destination coordinate - while w > 1 do - local v = source_p[0] - setter(dest, nil, dest_p, Color4L(nv.a), set_param, Color4U(v.a)) - nv = v - source_p = source_p + 1 - dest_p = dest_p + 1 - w = w - 2 - end - if w > 0 then - setter(dest, nil, dest_p, Color4L(nv.a), set_param, nil) - end - end - else - -- even source x coordinate - if band(dest_x, 1) == 1 then - -- ..but odd destination x coordinate - local nv = source_p[0] - source_p = source_p + 1 - setter(dest, nil, dest_p, nil, set_param, nv) - dest_p = dest_p + 1 - w = w - 1 - while w > 1 do - local v = source_p[0] - setter(dest, nil, dest_p, Color4L(nv.a), set_param, v) - nv = v - source_p = source_p + 1 - dest_p = dest_p + 1 - w = w - 2 - end - if w > 0 then - setter(dest, nil, dest_p, Color4L(nv.a), set_param, nil) - end - else - -- even destination x coordinate - while w > 1 do - local v = source_p[0] - setter(dest, nil, dest_p, v, set_param, Color4L(v.a)) - source_p = source_p + 1 - dest_p = dest_p + 1 - w = w - 2 - end - if w > 0 then - setter(dest, nil, dest_p, source_p[0], set_param, nil) - end - end - end - o_y = o_y + 1 - end - return true -end - -function BB4_mt.__index:blitTo8(dest, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) - local o_y = offs_y - for y = dest_y, dest_y+height-1 do - local w = width - local dest_p = dest:getPixelP(dest_x, y) - local source_p = self:getPixelP(offs_x, o_y) - if band(offs_x, 1) == 1 then - local v = source_p[0].a - local l = band(v, 0x0F) - setter(dest, nil, dest_p, Color8(bor(l, lshift(l, 4))), set_param) - dest_p = dest_p + 1 - source_p = source_p + 1 - w = w - 1 - end - while w > 1 do - local v = source_p[0].a - local u = band(v, 0xF0) - local l = band(v, 0x0F) - setter(dest, nil, dest_p, Color8(bor(u, rshift(u, 4))), set_param) - dest_p = dest_p + 1 - setter(dest, nil, dest_p, Color8(bor(l, lshift(l, 4))), set_param) - dest_p = dest_p + 1 - source_p = source_p + 1 - w = w - 2 - end - if w > 0 then - local v = source_p[0].a - local u = band(v, 0xF0) - setter(dest, nil, dest_p, Color8(bor(u, rshift(u, 4))), set_param) - end - o_y = o_y + 1 - end - return true -end -BB4_mt.__index.blitToA8 = BB4_mt.__index.blitTo8 -BB4_mt.__index.blitTo16 = BB4_mt.__index.blitTo8 -BB4_mt.__index.blitToRGB24 = BB4_mt.__index.blitTo8 -BB4_mt.__index.blitToRGB32 = BB4_mt.__index.blitTo8 - function BB_mt.__index:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, setter, set_param) - width, height = width or source.w, height or source.h - width, dest_x, offs_x = checkBounds(width, dest_x or 0, offs_x or 0, self.w, source.w) - height, dest_y, offs_y = checkBounds(height, dest_y or 0, offs_y or 0, self.h, source.h) + width, height = width or source:getWidth(), height or source:getHeight() + width, dest_x, offs_x = BB.checkBounds(width, dest_x or 0, offs_x or 0, self:getWidth(), source:getWidth()) + height, dest_y, offs_y = BB.checkBounds(height, dest_y or 0, offs_y or 0, self:getHeight(), source:getHeight()) if not setter then setter = self.setPixel end if width <= 0 or height <= 0 then return end @@ -821,7 +615,9 @@ function BB_mt.__index:addblitFrom(source, dest_x, dest_y, offs_x, offs_y, width end function BB_mt.__index:blitFromRotate(source, degree) - self:rotate(degree):blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, self.setPixel, intensity) + self:rotate(degree) + self:blitFrom(source, dest_x, dest_y, offs_x, offs_y, width, height, self.setPixel, intensity) + self:rotate(-degree) end --[[ @@ -831,8 +627,8 @@ will free resources immediately this is also called upon garbage collection --]] function BB_mt.__index:free() - if self.allocated ~= 0 then - self.allocated = 0 + if band(lshift(1, SHIFT_ALLOCATED), self.config) ~= 0 then + self.config = band(self.config, bxor(0xFF, lshift(1, SHIFT_ALLOCATED))) ffi.C.free(self.data) end end @@ -862,25 +658,24 @@ end --[[ paint a rectangle onto this buffer -@param x1 X coordinate -@param y1 Y coordinate +@param x X coordinate +@param y Y coordinate @param w width @param h height @param value color value --]] -function BB_mt.__index:paintRect(x1, y1, w, h, value) +function BB_mt.__index:paintRect(x, y, w, h, value) -- compatibility: if type(value) == "number" then value = Color4L(value) end if w <= 0 or h <= 0 then return end - w, x1 = checkBounds(w, x1, 0, self.w, 0xFFFF) - h, y1 = checkBounds(h, y1, 0, self.h, 0xFFFF) - for y = y1, y1+h-1 do - for x = x1, x1+w-1 do + w, x = BB.checkBounds(w, x, 0, self:getWidth(), 0xFFFF) + h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF) + for y = y, y+h-1 do + for x = x, x+w-1 do self:setPixel(x, y, value) end end end -BB4_mt.__index.paintRect = BB_mt.__index.paintRect --[[ paint a circle onto this buffer @@ -1113,7 +908,15 @@ dim color values in rectangular area @param h height --]] function BB_mt.__index:dimRect(x, y, w, h) - self:blitFrom(self, x, y, x, y, w, h, self.setPixelDim) + if w <= 0 or h <= 0 then return end + w, x = BB.checkBounds(w, x, 0, self:getWidth(), 0xFFFF) + h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF) + x, y, w, h = self:getPhysicalRect(x, y, w, h) + for y = y, y+h-1 do + for x = x, x+w-1 do + self:getPixelP(x, y)[0]:dim() + end + end end --[[ @@ -1125,7 +928,15 @@ lighten color values in rectangular area @param h height --]] function BB_mt.__index:lightenRect(x, y, w, h, low) - self:blitFrom(self, x, y, x, y, w, h, self.setPixelLighten, low) + if w <= 0 or h <= 0 then return end + w, x = BB.checkBounds(w, x, 0, self:getWidth(), 0xFFFF) + h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF) + x, y, w, h = self:getPhysicalRect(x, y, w, h) + for y = y, y+h-1 do + for x = x, x+w-1 do + self:getPixelP(x, y)[0]:lighten(low) + end + end end function BB_mt.__index:copy() @@ -1133,7 +944,9 @@ function BB_mt.__index:copy() local buffer = ffi.C.malloc(self.pitch * self.h) assert(buffer, "cannot allocate buffer") ffi.copy(buffer, self.data, self.pitch * self.h) - return mytype(self.w, self.h, self.pitch, buffer, 1) + local copy = mytype(self.w, self.h, self.pitch, buffer, self.config) + copy:setAllocated(1) + return copy end -- if no special case in BB???_mt exists, use function from BB_mt @@ -1142,19 +955,16 @@ end for name, func in pairs(BB_mt.__index) do if not BB4_mt.__index[name] then BB4_mt.__index[name] = func end if not BB8_mt.__index[name] then BB8_mt.__index[name] = func end - if not BBA8_mt.__index[name] then BBA8_mt.__index[name] = func end + if not BB8A_mt.__index[name] then BB8A_mt.__index[name] = func end if not BB16_mt.__index[name] then BB16_mt.__index[name] = func end if not BBRGB24_mt.__index[name] then BBRGB24_mt.__index[name] = func end if not BBRGB32_mt.__index[name] then BBRGB32_mt.__index[name] = func end - if not BB_rotated_mt.__index[name] then BB_rotated_mt.__index[name] = func end - if not BB_inverted_mt.__index[name] then BB_inverted_mt.__index[name] = func end - if not BB_masked_mt.__index[name] then BB_masked_mt.__index[name] = func end end -- set metatables for the BlitBuffer types local BlitBuffer4 = ffi.metatype("BlitBuffer4", BB4_mt) local BlitBuffer8 = ffi.metatype("BlitBuffer8", BB8_mt) -local BlitBufferA8 = ffi.metatype("BlitBufferA8", BBA8_mt) +local BlitBuffer8A = ffi.metatype("BlitBuffer8A", BB8A_mt) local BlitBuffer16 = ffi.metatype("BlitBuffer16", BB16_mt) local BlitBufferRGB24 = ffi.metatype("BlitBufferRGB24", BBRGB24_mt) local BlitBufferRGB32 = ffi.metatype("BlitBufferRGB32", BBRGB32_mt) @@ -1163,42 +973,40 @@ local BlitBufferRGB32 = ffi.metatype("BlitBufferRGB32", BBRGB32_mt) ffi.metatype("Color4L", Color4L_mt) ffi.metatype("Color4U", Color4U_mt) ffi.metatype("Color8", Color8_mt) -ffi.metatype("ColorA8", ColorA8_mt) +ffi.metatype("Color8A", Color8A_mt) ffi.metatype("Color16", Color16_mt) ffi.metatype("ColorRGB24", ColorRGB24_mt) ffi.metatype("ColorRGB32", ColorRGB32_mt) --- combined function for Blitbuffer creation -function BB.new(width, height, pitch, buffer, bpp, is_rgb) - -- defaults: - bpp = bpp or 4 - is_rgb = is_rgb or false - - local allocated = 0 - if buffer == nil then - if pitch == nil then - local bits = width * bpp - pitch = bit.rshift(bits, 3) - if bits % 8 > 0 then pitch = pitch + 1 end +function BB.new(width, height, buffertype, dataptr, pitch) + local bb = nil + buffertype = buffertype or TYPE_BB4 + if pitch == nil then + if buffertype == TYPE_BB4 then pitch = band(1, width) + rshift(width, 1) + elseif buffertype == TYPE_BB8 then pitch = width + elseif buffertype == TYPE_BB8A then pitch = lshift(width, 1) + elseif buffertype == TYPE_BB16 then pitch = lshift(width, 1) + elseif buffertype == TYPE_BBRGB24 then pitch = width * 3 + elseif buffertype == TYPE_BBRGB32 then pitch = lshift(width, 2) end - buffer = ffi.C.malloc(pitch * height) - assert(buffer, "cannot allocate buffer") - ffi.fill(buffer, pitch * height) - allocated = 1 end - if bpp == 4 and is_rgb == false then - return BlitBuffer4(width, height, pitch, buffer, allocated) - elseif bpp == 8 and is_rgb == false then - return BlitBuffer8(width, height, pitch, buffer, allocated) - elseif bpp == 16 and is_rgb == false then - return BlitBuffer16(width, height, pitch, buffer, allocated) - elseif bpp == 24 and is_rgb == true then - return BlitBufferRGB24(width, height, pitch, buffer, allocated) - elseif bpp == 32 and is_rgb == true then - return BlitBufferRGB32(width, height, pitch, buffer, allocated) - else - error("unsupported format") + if buffertype == TYPE_BB4 then bb = BlitBuffer4(width, height, pitch, nil, 0) + elseif buffertype == TYPE_BB8 then bb = BlitBuffer8(width, height, pitch, nil, 0) + elseif buffertype == TYPE_BB8A then bb = BlitBuffer8A(width, height, pitch, nil, 0) + elseif buffertype == TYPE_BB16 then bb = BlitBuffer16(width, height, pitch, nil, 0) + elseif buffertype == TYPE_BBRGB24 then bb = BlitBufferRGB24(width, height, pitch, nil, 0) + elseif buffertype == TYPE_BBRGB32 then bb = BlitBufferRGB32(width, height, pitch, nil, 0) + else error("unknown blitbuffer type") end + bb:setType(buffertype) + if dataptr == nil then + dataptr = ffi.C.malloc(pitch * height) + assert(dataptr, "cannot allocate memory for blitbuffer") + ffi.fill(dataptr, pitch*height) + bb:setAllocated(1) + end + bb.data = ffi.cast(bb.data, dataptr) + return bb end function BB.compat(oldbuffer) @@ -1217,9 +1025,15 @@ BB.ColorRGB32 = ColorRGB32 -- accessors for Blitbuffer types BB.BlitBuffer4 = BlitBuffer4 BB.BlitBuffer8 = BlitBuffer8 -BB.BlitBufferA8 = BlitBufferA8 +BB.BlitBuffer8A = BlitBuffer8A BB.BlitBuffer16 = BlitBuffer16 BB.BlitBufferRGB24 = BlitBufferRGB24 BB.BlitBufferRGB32 = BlitBufferRGB32 +BB.TYPE_BB4 = TYPE_BB4 +BB.TYPE_BB8 = TYPE_BB8 +BB.TYPE_BB8A = TYPE_BB8A +BB.TYPE_BB16 = TYPE_BB16 +BB.TYPE_BBRGB24 = TYPE_BBRGB24 +BB.TYPE_BBRGB32 = TYPE_BBRGB32 return BB From e65a0815dc4411dc777f5cfc930c9c28b89a2022 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:20:09 +0100 Subject: [PATCH 16/21] Adaptions and bugfixes for SDL framebuffer emulation Now properly does rotation. --- ffi/framebuffer_SDL.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ffi/framebuffer_SDL.lua b/ffi/framebuffer_SDL.lua index 953f3b173..a51c1488c 100644 --- a/ffi/framebuffer_SDL.lua +++ b/ffi/framebuffer_SDL.lua @@ -13,8 +13,9 @@ function fb.open() -- we present this buffer to the outside fb.bb = BB.new(SDL.screen.w, SDL.screen.h) - fb.real_bb = BB.new(SDL.screen.w, SDL.screen.h, SDL.screen.pitch, - SDL.screen.pixels, 32, true):invert() + fb.real_bb = BB.new(SDL.screen.w, SDL.screen.h, BB.TYPE_BBRGB32, + SDL.screen.pixels, SDL.screen.pitch) + fb.real_bb:invert() fb:refresh() @@ -48,8 +49,9 @@ end function fb:refresh(refreshtype, waveform_mode, x1, y1, w, h) if x1 == nil then x1 = 0 end if y1 == nil then y1 = 0 end - if w == nil then w = SDL.screen.w - x1 end - if h == nil then h = SDL.screen.h - y1 end + + -- adapt to possible rotation changes + self.real_bb:setRotation(self.bb:getRotation()) if SDL.SDL.SDL_LockSurface(SDL.screen) < 0 then error("Locking screen surface") From eb9e5de05a95ddfd39f0fc3329c21669064e83cd Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:21:21 +0100 Subject: [PATCH 17/21] proper refresh handling, adaptions to new Blitbuffer initialization --- ffi/framebuffer_linux.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/ffi/framebuffer_linux.lua b/ffi/framebuffer_linux.lua index ba3f298f1..d29085414 100644 --- a/ffi/framebuffer_linux.lua +++ b/ffi/framebuffer_linux.lua @@ -13,8 +13,8 @@ local function einkfb_update(fb, refreshtype, waveform_mode, x, y, w, h) refarea[0].x1 = x or 0 refarea[0].y1 = y or 0 - refarea[0].x2 = x + (w or fb.vinfo.xres) - refarea[0].y2 = y + (h or fb.vinfo.yres) + refarea[0].x2 = x + (w or (fb.vinfo.xres-x)) + refarea[0].y2 = y + (h or (fb.vinfo.yres-y)) refarea[0].buffer = nil if refreshtype == 1 then refarea[0].which_fx = ffi.C.fx_update_partial @@ -91,7 +91,7 @@ function framebuffer.open(device) "video type not supported") assert(fb.vinfo.grayscale ~= 0, "only grayscale is supported but framebuffer says it isn't") - assert(fb.vinfo.xres > 0 and fb.vinfo.yres > 0, "invalid framebuffer resolution") + assert(fb.vinfo.xres_virtual > 0 and fb.vinfo.yres_virtual > 0, "invalid framebuffer resolution") -- it seems that fb.finfo.smem_len is unreliable on kobo -- Figure out the size of the screen in bytes @@ -106,9 +106,11 @@ function framebuffer.open(device) fb.einkUpdateFunc = k51_update if fb.vinfo.bits_per_pixel == 16 then - fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual*2, fb.data, 16, false):invert() + fb.bb = BB.new(fb.vinfo.xres, fb.vinfo.yres, BB.TYPE_BB16, fb.data, fb.finfo.line_length) + fb.bb:invert() elseif fb.vinfo.bits_per_pixel == 8 then - fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual, fb.data, 8, false):invert() + fb.bb = BB.new(fb.vinfo.xres, fb.vinfo.yres, BB.TYPE_BB8, fb.data, fb.finfo.line_length) + fb.bb:invert() else error("unknown bpp value for the mxc eink driver") end @@ -116,9 +118,9 @@ function framebuffer.open(device) fb.einkUpdateFunc = einkfb_update if fb.vinfo.bits_per_pixel == 8 then - fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual, fb.data, 8, false) + fb.bb = BB.new(fb.vinfo.xres, fb.vinfo.yres, BB.TYPE_BB8, fb.data, fb.finfo.line_length) elseif fb.vinfo.bits_per_pixel == 4 then - fb.bb = BB.new(fb.vinfo.xres_virtual, fb.vinfo.yres_virtual, fb.vinfo.xres_virtual/2, fb.data, 4, false) + fb.bb = BB.new(fb.vinfo.xres, fb.vinfo.yres, BB.TYPE_BB4, fb.data, fb.finfo.line_length) else error("unknown bpp value for the classic eink driver") end @@ -177,11 +179,14 @@ function framebuffer_mt:setOrientation(mode) end function framebuffer_mt.__index:refresh(refreshtype, waveform_mode, x, y, w, h) - self:einkUpdateFunc(refreshtype, waveform_mode, x, y, w, h) + w, x = BB.checkBounds(w or self.bb:getWidth(), x or 0, 0, self.bb:getWidth(), 0xFFFF) + h, y = BB.checkBounds(h or self.bb:getHeight(), y or 0, 0, self.bb:getHeight(), 0xFFFF) + local px, py = self.bb:getPhysicalRect(x, y, w, h) + self:einkUpdateFunc(refreshtype, waveform_mode, px, py, w, h) end function framebuffer_mt.__index:getSize() - return self.bb.w, self.bb.h + return self.bb:getWidth(), self.bb:getHeight() end function framebuffer_mt.__index:getPitch() From d7414cfef105ba1c3436c2ba67e10278a4f9390b Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:21:52 +0100 Subject: [PATCH 18/21] Adaptions to new blitbuffer initialization --- ffi/mupdfimg.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ffi/mupdfimg.lua b/ffi/mupdfimg.lua index e985c2afd..39e0db2d8 100644 --- a/ffi/mupdfimg.lua +++ b/ffi/mupdfimg.lua @@ -34,7 +34,9 @@ function Image:toBlitBuffer() mupdf.fz_convert_pixmap(self.context, self.pixmap, pixmap); mupdf.fz_drop_pixmap(self.context, pixmap); end - self.bb = Blitbuffer.BlitBufferA8(self.pixmap.w, self.pixmap.h, bit.lshift(self.pixmap.w, 1), self.pixmap.samples, 0):copy() + self.bb = Blitbuffer.new(self.pixmap.w, self.pixmap.h, Blitbuffer.TYPE_BB8A, self.pixmap.samples) + self.bb:invert() -- our blitbuffers have reversed b->w scale + self.bb = self.bb:copy() -- we make a copy so mupdf can drop the memory end function Image:freeContext() @@ -53,7 +55,7 @@ function Image:fromPNG(filename) self:loadPNGData(self:_getFileData(filename)) self:toBlitBuffer() self:freeContext() - return self.bb:invert() + return self.bb end return Image From bc00e464a1eec9719c7a5937445215a4c17ce3ac Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:45:16 +0100 Subject: [PATCH 19/21] fix dimRect()/lightenRect() both methods didn't take inversion into account. Now their implementation respects inversion. --- ffi/blitbuffer.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ffi/blitbuffer.lua b/ffi/blitbuffer.lua index 54feafbf9..935ebbf6f 100644 --- a/ffi/blitbuffer.lua +++ b/ffi/blitbuffer.lua @@ -185,9 +185,10 @@ function ColorRGB24_mt.__index:add(color, intensity) self:set(ColorRGB24(r, g, b)) end ColorRGB32_mt.__index.add = ColorRGB24_mt.__index.add + -- dimming function Color4L_mt.__index:dim() - self:set(Color8(rshift(self:getColor8().a, 1))) + return Color8(rshift(self:getColor8().a, 1)) end Color4U_mt.__index.dim = Color4L_mt.__index.dim Color8_mt.__index.dim = Color4L_mt.__index.dim @@ -199,7 +200,11 @@ ColorRGB32_mt.__index.dim = Color4L_mt.__index.dim function Color4L_mt.__index:lighten(low) local value = self:getColor4L().a low = low * 0x0F - if value < low then self:set(Color4L(low)) end + if value < low then + return Color4L(low) + else + return self + end end Color4U_mt.__index.lighten = Color4L_mt.__index.lighten Color8_mt.__index.lighten = Color4L_mt.__index.lighten @@ -911,10 +916,9 @@ function BB_mt.__index:dimRect(x, y, w, h) if w <= 0 or h <= 0 then return end w, x = BB.checkBounds(w, x, 0, self:getWidth(), 0xFFFF) h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF) - x, y, w, h = self:getPhysicalRect(x, y, w, h) for y = y, y+h-1 do for x = x, x+w-1 do - self:getPixelP(x, y)[0]:dim() + self:setPixel(x, y, self:getPixel(x, y):dim()) end end end @@ -934,7 +938,7 @@ function BB_mt.__index:lightenRect(x, y, w, h, low) x, y, w, h = self:getPhysicalRect(x, y, w, h) for y = y, y+h-1 do for x = x, x+w-1 do - self:getPixelP(x, y)[0]:lighten(low) + self:setPixel(x, y, self:getPixel(x, y):lighten(low)) end end end From 5105979cbb1351caf879e691b4c5fa26638bfb23 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:46:23 +0100 Subject: [PATCH 20/21] use new FFI implementations do not build old einkfb, blitbuffer and drawcontext modules use the FFI implementations in koreader-base wrapper --- Makefile | 13 ------------- koreader-base | 11 ++--------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 3e9f0de94..89327caee 100644 --- a/Makefile +++ b/Makefile @@ -181,9 +181,6 @@ libs: \ $(OUTPUT_DIR)/libs/libkoreader-luagettext.so \ $(OUTPUT_DIR)/libs/libkoreader-kobolight.so \ $(OUTPUT_DIR)/libs/libkoreader-input.so \ - $(OUTPUT_DIR)/libs/libkoreader-einkfb.so \ - $(OUTPUT_DIR)/libs/libkoreader-drawcontext.so \ - $(OUTPUT_DIR)/libs/libkoreader-blitbuffer.so \ $(OUTPUT_DIR)/libs/libkoreader-lfs.so \ $(OUTPUT_DIR)/libs/libkoreader-koptcontext.so \ $(OUTPUT_DIR)/libs/libkoreader-pic.so \ @@ -205,16 +202,6 @@ $(OUTPUT_DIR)/libs/libkoreader-input.so: input.c \ $(CC) $(DYNLIB_CFLAGS) $(EMU_CFLAGS) \ -o $@ $< $(POPEN_NOSHELL_LIB) $(EMU_LDFLAGS) -$(OUTPUT_DIR)/libs/libkoreader-einkfb.so: einkfb.c - $(CC) -Iinclude/ $(DYNLIB_CFLAGS) $(EMU_CFLAGS)\ - -o $@ $< $(EMU_LDFLAGS) - -$(OUTPUT_DIR)/libs/libkoreader-drawcontext.so: drawcontext.c - $(CC) $(DYNLIB_CFLAGS) -o $@ $< - -$(OUTPUT_DIR)/libs/libkoreader-blitbuffer.so: blitbuffer.c - $(CC) $(DYNLIB_CFLAGS) -o $@ $< - $(OUTPUT_DIR)/libs/libkoreader-lfs.so: luafilesystem/src/lfs.c $(CC) $(DYNLIB_CFLAGS) -o $@ $< diff --git a/koreader-base b/koreader-base index 7977ab24c..3f2d7362c 100755 --- a/koreader-base +++ b/koreader-base @@ -6,10 +6,8 @@ this replaces the former standalone binary which invoked the Lua interpreter/com now, we use the "default" interpreter/compiler ]]-- -require "libs/libkoreader-blitbuffer" require "libs/libkoreader-cre" require "libs/libkoreader-djvu" -require "libs/libkoreader-drawcontext" require "libs/libkoreader-input" require "libs/libkoreader-koptcontext" require "libs/libkoreader-lfs" @@ -19,17 +17,12 @@ require "libs/libkoreader-luagettext" require "libs/libkoreader-kobolight" -- libraries converted to FFI: +DrawContext = require("ffi/drawcontext") Blitbuffer = require("ffi/blitbuffer") freetype = require("ffi/freetype") Image = require("ffi/mupdfimg") util = require("ffi/util") - --- transition modules -if util.isEmulated() then - einkfb = require("ffi/framebuffer_SDL") -else - require "libs/libkoreader-einkfb" -end +einkfb = require("ffi/framebuffer") if not arg[1] then error("you must give the name of the main lua executable as the first argument") From 3c80d60ef8df2265295216e194912392194d96cf Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 26 Nov 2013 16:51:38 +0100 Subject: [PATCH 21/21] adaption to pic module test: FFI drawcontext implementation --- spec/unit/pic_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/pic_spec.lua b/spec/unit/pic_spec.lua index 08f8d0999..ccf1f3baf 100644 --- a/spec/unit/pic_spec.lua +++ b/spec/unit/pic_spec.lua @@ -1,4 +1,4 @@ -require "libs/libkoreader-drawcontext" +local DrawContext = require("ffi/drawcontext") --require "libs/libkoreader-pic" --local Pic = pic