From 0cf5719e526b17bb6ad03f05643a760edf389e98 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 18 Nov 2015 19:29:23 +0900 Subject: [PATCH] Ector: Implement pixel buffer support The objective of this patch is to propose a standardized format for pixel buffers to use within Ector and Evas. The basic EO API provided here is not meant to be the fastest path for all operations, simply the most convenient to generalize. Performance will be achieved by implementing (or porting) custom draw functions. This implements support for: - Generic pixel buffers - Generic buffer renderer to draw images with ector - Software engine pixel buffers, ie. malloc buffers - Software buffer renderer Cairo support has not been implemented yet. The only renderer is still extremely limited, as it does not support Fill modes, Scaling, etc... yet. Not a single line from this patch has been tested yet. It compiles. That's pretty damn good for a start! @feature --- src/Makefile_Ector.am | 9 + src/lib/ector/ector_generic_buffer.c | 50 +++++ src/lib/ector/ector_generic_buffer.eo | 132 +++++++++++ src/lib/ector/ector_private.h | 40 +++- src/lib/ector/ector_renderer.h | 1 + src/lib/ector/ector_renderer_base.c | 2 +- src/lib/ector/ector_renderer_generic_buffer.c | 68 ++++++ src/lib/ector/ector_renderer_generic_buffer.eo | 22 ++ src/lib/ector/ector_renderer_shape.c | 6 +- src/lib/ector/ector_surface.h | 1 + src/lib/ector/software/Ector_Software.h | 2 + .../software/ector_renderer_software_buffer.c | 72 ++++++ .../software/ector_renderer_software_buffer.eo | 19 ++ src/lib/ector/software/ector_software_buffer.c | 248 +++++++++++++++++++++ src/lib/ector/software/ector_software_buffer.eo | 19 ++ src/lib/ector/software/ector_software_private.h | 19 +- src/lib/ector/software/ector_software_rasterizer.c | 60 ++++- src/lib/ector/software/ector_software_surface.c | 3 + src/lib/efl/interfaces/efl_gfx_base.eo | 5 + 19 files changed, 767 insertions(+), 11 deletions(-) create mode 100644 src/lib/ector/ector_generic_buffer.c create mode 100644 src/lib/ector/ector_generic_buffer.eo create mode 100644 src/lib/ector/ector_renderer_generic_buffer.c create mode 100644 src/lib/ector/ector_renderer_generic_buffer.eo create mode 100644 src/lib/ector/software/ector_renderer_software_buffer.c create mode 100644 src/lib/ector/software/ector_renderer_software_buffer.eo create mode 100644 src/lib/ector/software/ector_software_buffer.c create mode 100644 src/lib/ector/software/ector_software_buffer.eo diff --git a/src/Makefile_Ector.am b/src/Makefile_Ector.am index f6fe1e1..b6cda51 100644 --- a/src/Makefile_Ector.am +++ b/src/Makefile_Ector.am @@ -2,8 +2,10 @@ ### Library ector_eolian_files_generic = \ lib/ector/ector_generic_surface.eo \ + lib/ector/ector_generic_buffer.eo \ lib/ector/ector_renderer_generic_base.eo \ lib/ector/ector_renderer_generic_shape.eo \ + lib/ector/ector_renderer_generic_buffer.eo \ lib/ector/ector_renderer_generic_gradient.eo \ lib/ector/ector_renderer_generic_gradient_radial.eo \ lib/ector/ector_renderer_generic_gradient_linear.eo @@ -21,8 +23,10 @@ ector_eolian_cairo_h = $(ector_eolian_files_cairo:%.eo=%.eo.h) # Handle default software backend ector_eolian_files_software = \ lib/ector/software/ector_software_surface.eo \ + lib/ector/software/ector_software_buffer.eo \ lib/ector/software/ector_renderer_software_base.eo \ lib/ector/software/ector_renderer_software_shape.eo \ + lib/ector/software/ector_renderer_software_buffer.eo \ lib/ector/software/ector_renderer_software_gradient_radial.eo \ lib/ector/software/ector_renderer_software_gradient_linear.eo ector_eolian_software_h = $(ector_eolian_files_software:%.eo=%.eo.h) @@ -64,8 +68,10 @@ lib/ector/software/Ector_Software.h lib_ector_libector_la_SOURCES = \ lib/ector/ector_main.c \ lib/ector/ector_surface.c \ +lib/ector/ector_generic_buffer.c \ lib/ector/ector_renderer_shape.c \ lib/ector/ector_renderer_base.c \ +lib/ector/ector_renderer_generic_buffer.c \ lib/ector/ector_renderer_gradient.c \ lib/ector/ector_renderer_gradient_radial.c \ lib/ector/ector_renderer_gradient_linear.c @@ -89,9 +95,11 @@ lib_ector_libector_la_SOURCES += \ lib/ector/software/ector_renderer_software_gradient_linear.c \ lib/ector/software/ector_renderer_software_gradient_radial.c \ lib/ector/software/ector_renderer_software_shape.c \ +lib/ector/software/ector_renderer_software_buffer.c \ lib/ector/software/ector_software_gradient.c \ lib/ector/software/ector_software_rasterizer.c \ lib/ector/software/ector_software_surface.c \ +lib/ector/software/ector_software_buffer.c \ static_libs/freetype/sw_ft_math.c \ static_libs/freetype/sw_ft_raster.c \ static_libs/freetype/sw_ft_stroker.c \ @@ -150,6 +158,7 @@ endif EXTRA_DIST += \ lib/ector/ector_private.h \ +lib/ector/ector_buffer.h \ lib/ector/cairo/ector_cairo_private.h \ lib/ector/software/ector_drawhelper_private.h \ lib/ector/software/ector_software_private.h \ diff --git a/src/lib/ector/ector_generic_buffer.c b/src/lib/ector/ector_generic_buffer.c new file mode 100644 index 0000000..ba5955b --- /dev/null +++ b/src/lib/ector/ector_generic_buffer.c @@ -0,0 +1,50 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EFL_BETA_API_SUPPORT +#endif + +#include +#include "ector_private.h" +#include "ector_generic_buffer.eo.h" + +#define MY_CLASS ECTOR_GENERIC_BUFFER_CLASS + +EOLIAN static Efl_Gfx_Colorspace +_ector_generic_buffer_cspace_get(Eo *obj EINA_UNUSED, Ector_Generic_Buffer_Data *pd) +{ + return pd->cspace; +} + +EOLIAN static void +_ector_generic_buffer_border_get(Eo *obj EINA_UNUSED, Ector_Generic_Buffer_Data *pd EINA_UNUSED, int *l, int *r, int *t, int *b) +{ + if (l) *l = pd->l; + if (r) *r = pd->r; + if (t) *t = pd->t; + if (b) *b = pd->b; +} + +EOLIAN static void +_ector_generic_buffer_size_get(Eo *obj EINA_UNUSED, Ector_Generic_Buffer_Data *pd, int *w, int *h) +{ + if (w) *w = pd->w; + if (h) *h = pd->h; +} + +EOLIAN static Ector_Buffer_Flag +_ector_generic_buffer_flags_get(Eo *obj EINA_UNUSED, Ector_Generic_Buffer_Data *pd EINA_UNUSED) +{ + return ECTOR_BUFFER_FLAG_NONE; +} + +EOLIAN static Eo_Base * +_ector_generic_buffer_eo_base_constructor(Eo *obj, Ector_Generic_Buffer_Data *pd) +{ + eo_do_super(obj, MY_CLASS, obj = eo_constructor()); + pd->eo = obj; + + return obj; +} + +#include "ector_generic_buffer.eo.c" diff --git a/src/lib/ector/ector_generic_buffer.eo b/src/lib/ector/ector_generic_buffer.eo new file mode 100644 index 0000000..f0f1566 --- /dev/null +++ b/src/lib/ector/ector_generic_buffer.eo @@ -0,0 +1,132 @@ +enum Ector.Buffer.Flag { + none = 0x00, [[Buffer may not have any backing]] + cpu_readable = 0x01, [[Can be read from the CPU after map. Reading may still be very slow.]] + cpu_writable = 0x02, [[Can be written to by the CPU after map. Writing may still be very slow.]] + renderable = 0x04, [[Can be rendered to, ie CPU memory for SW rendering, or an FBO for GL engine]] + cpu_readable_fast = 0x08, [[Can be read by the CPU at high speed, ie no need for glReadPixels]] + cpu_writable_fast = 0x0A, [[Can be written by the CPU at high speed, ie no need for GPU texture upload]] + uncached = 0x10, [[Backed by uncached memory, ie. slow-ish reads but faster than glReadPixels]] +/* non_coherent = 0x20, [[Memory may be mapped but will not be coherent between GPU and CPU. Call flush or invalidate to synchronize it.]] */ +} + +enum Ector.Buffer.Access_Flag { + none = 0x0, + read = 0x1, + write = 0x2, +} + +abstract Ector.Generic.Buffer (Eo.Base) +{ + [[2D pixel buffer interface for Ector + @since 1.17 + ]] + eo_prefix: ector_buffer; + legacy_prefix: null; + methods { + @property size { + get { + [[Retrieves the (rectangular) size of the pixel buffer.]] + } + values { + w: int; + h: int; + } + } + @property cspace { + get {} + values { + cspace: Efl.Gfx.Colorspace; + } + } + map { + [[Map a region of this buffer for read or write access by the CPU, + fetch data from the GPU if needed. + ]] + params { + @out offset: int; [[Byte offset to the first requested pixel]] + @out length: uint; [[Accessible buffer size in bytes]] + @in mode: Ector.Buffer.Access_Flag; + @in x: uint; + @in y: uint; + @in w: uint; [[If 0, defaults to the buffer width]] + @in h: uint; [[If 0, defaults to the buffer height]] + @in cspace: Efl.Gfx.Colorspace; [[Requested colorspace. If difference from the internal cspace, map may either fail or convert slowly]] + @out stride: uint; [[Optional]] + } + return: uint8* @warn_unused; [[Top-left pixel is at offset bytes after this address. Returns $null in case of failure]] + } + unmap { + [[Unmap a region of this buffer, and upload data to the GPU (if needed).]] + params { + @in data: void*; [[Data pointer returned by a previous call to map]] + @in offset: int; + @in length: uint; + } + } + pixels_set { + [[Set the source pixels for this buffer, or allocate a new memory region]] + params { + @in pixels: void*; [[If $null, allocates an empty buffer]] + @in width: int; + @in height: int; + @in stride: int; [[Can be 0]] + @in cspace: Efl.Gfx.Colorspace; + @in writable: bool; + @in l: ubyte; [[Left border pixels, usually 0 or 1]] + @in r: ubyte; [[Right border pixels, usually 0 or 1]] + @in t: ubyte; [[Top border pixels, usually 0 or 1]] + @in b: ubyte; [[Bottom border pixels, usually 0 or 1]] + } + return: bool; + } + span_get { + [[Get a single horizontal span of length w starting from (x,y) + + Call span_free() to release it. This function will try not to + allocate any new buffer, whenever possible. This means the data + might be mapped directly from the backing memory buffer. + ]] + params { + @in x: int; [[Ranges from -l to w+r-1]] + @in y: int; [[Ranges from -t to h+b-1]] + @in w: uint; [[Ranges from 1 to w+l+r]] + @in cspace: Efl.Gfx.Colorspace; [[Requested colorspace, may trigger conversion on the fly.]] + @out length: uint; [[Length in bytes of the returned buffer]] + } + return: uint8*; [[A temporary memory buffer containing the pixels requested.]] + } + span_free { + [[Must be called as soon as possible after span_get]] + params { + data: uint8*; + } + } + @property flags { + get { [[Get the capabilities of this buffer]] } + values { + flag: Ector.Buffer.Flag; [[A bitmask of capability flags]] + } + } + @property border { + [[Duplicated pixel borders of this buffer, used for GL scaling]] + get {} + values { + l: int; + r: int; + t: int; + b: int; + } + } + } + events { + detached; [[Emitted whenever the previously attached pixels are detached during pixels_set]] + } + implements { + Eo.Base.constructor; + @virtual .pixels_set; + @virtual .span_get; + @virtual .span_free; + @virtual .map; + @virtual .unmap; + } +} diff --git a/src/lib/ector/ector_private.h b/src/lib/ector/ector_private.h index 8d0b9fe..13cfc7e 100644 --- a/src/lib/ector/ector_private.h +++ b/src/lib/ector/ector_private.h @@ -1,6 +1,8 @@ #ifndef ECTOR_PRIVATE_H_ #define ECTOR_PRIVATE_H_ +#include "Ector.h" + /* * variable and macros used for the eina_log module */ @@ -65,13 +67,22 @@ typedef unsigned short DATA16; #define ARGB_JOIN(a,r,g,b) \ (((a) << 24) + ((r) << 16) + ((g) << 8) + (b)) -static inline void -_ector_renderer_replace(Ector_Renderer **d, const Ector_Renderer *s) +static inline Eo * +_eo_refplace(Eo **d, const Eo *s) { - Ector_Renderer *tmp = *d; - + Eo *tmp = *d; *d = eo_ref(s); - eo_unref(tmp); + if (tmp) eo_unref(tmp); + return *d; +} + +static inline Eo * +_eo_xrefplace(Eo **d, Eo *s, const Eo *ref_obj) +{ + Eo *tmp = *d; + *d = eo_xref(s, ref_obj); + if (tmp) eo_xunref(tmp, ref_obj); + return *d; } typedef struct _Ector_Renderer_Generic_Base_Data Ector_Renderer_Generic_Base_Data; @@ -79,6 +90,8 @@ typedef struct _Ector_Renderer_Generic_Gradient_Data Ector_Renderer_Generic_Grad typedef struct _Ector_Renderer_Generic_Gradient_Linear_Data Ector_Renderer_Generic_Gradient_Linear_Data; typedef struct _Ector_Renderer_Generic_Gradient_Radial_Data Ector_Renderer_Generic_Gradient_Radial_Data; typedef struct _Ector_Renderer_Generic_Shape_Data Ector_Renderer_Generic_Shape_Data; +typedef struct _Ector_Renderer_Generic_Buffer_Data Ector_Renderer_Generic_Buffer_Data; +typedef struct _Ector_Generic_Buffer_Data Ector_Generic_Buffer_Data; struct _Ector_Renderer_Generic_Base_Data { @@ -132,6 +145,23 @@ struct _Ector_Renderer_Generic_Shape_Data } stroke; }; +struct _Ector_Generic_Buffer_Data +{ + Eo *eo; + unsigned int w, h; + unsigned char l, r, t, b; + Efl_Gfx_Colorspace cspace; +}; + +struct _Ector_Renderer_Generic_Buffer_Data +{ + Ector_Generic_Buffer *eo_buffer; + struct { + Efl_Gfx_Fill_Spread spread; + int x, y, w, h; + } fill; +}; + static inline unsigned int _renderer_crc_get(Eo *obj, unsigned int crc) { diff --git a/src/lib/ector/ector_renderer.h b/src/lib/ector/ector_renderer.h index 4c69a41..30b9bd2 100644 --- a/src/lib/ector/ector_renderer.h +++ b/src/lib/ector/ector_renderer.h @@ -3,6 +3,7 @@ #include "ector_renderer_generic_base.eo.h" #include "ector_renderer_generic_shape.eo.h" +#include "ector_renderer_generic_buffer.eo.h" #include "ector_renderer_generic_gradient.eo.h" #include "ector_renderer_generic_gradient_linear.eo.h" #include "ector_renderer_generic_gradient_radial.eo.h" diff --git a/src/lib/ector/ector_renderer_base.c b/src/lib/ector/ector_renderer_base.c index b2b08c5..2b9a594 100644 --- a/src/lib/ector/ector_renderer_base.c +++ b/src/lib/ector/ector_renderer_base.c @@ -114,7 +114,7 @@ _ector_renderer_generic_base_mask_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Base_Data *pd, Ector_Renderer *r) { - _ector_renderer_replace(&pd->mask, r); + _eo_refplace(&pd->mask, r); } static Ector_Renderer * diff --git a/src/lib/ector/ector_renderer_generic_buffer.c b/src/lib/ector/ector_renderer_generic_buffer.c new file mode 100644 index 0000000..0814ded --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_buffer.c @@ -0,0 +1,68 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EFL_BETA_API_SUPPORT +#endif + +#include +#include "ector_private.h" +#include "ector_renderer_generic_buffer.eo.h" + +#define MY_CLASS ECTOR_RENDERER_GENERIC_BUFFER_MIXIN + +EOLIAN static Efl_Gfx_Fill_Spread +_ector_renderer_generic_buffer_efl_gfx_fill_fill_spread_get(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd) +{ + return pd->fill.spread; +} + +EOLIAN static void +_ector_renderer_generic_buffer_efl_gfx_fill_fill_spread_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd, Efl_Gfx_Fill_Spread spread) +{ + pd->fill.spread = spread; +} + +EOLIAN static void +_ector_renderer_generic_buffer_efl_gfx_fill_fill_get(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd, int *x, int *y, int *w, int *h) +{ + if (x) *x = pd->fill.x; + if (y) *y = pd->fill.y; + if (w) *w = pd->fill.w; + if (h) *h = pd->fill.h; +} + +EOLIAN static void +_ector_renderer_generic_buffer_efl_gfx_fill_fill_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd, int x, int y, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + pd->fill.x = x; + pd->fill.y = y; + pd->fill.w = w; + pd->fill.h = h; +} + +EOLIAN static void +_ector_renderer_generic_buffer_buffer_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd, Ector_Generic_Buffer *buf) +{ + _eo_xrefplace(&pd->eo_buffer, buf, obj); +} + +EOLIAN static Ector_Generic_Buffer * +_ector_renderer_generic_buffer_buffer_get(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Buffer_Data *pd) +{ + return pd->eo_buffer; +} + +EOLIAN static Eo_Base * +_ector_renderer_generic_buffer_eo_base_constructor(Eo *obj, Ector_Renderer_Generic_Buffer_Data *pd) +{ + Eo_Base *ret; + + eo_do_super(obj, MY_CLASS, ret = eo_constructor()); + pd->fill.spread = EFL_GFX_FILL_REPEAT; + + return ret; +} + +#include "ector_renderer_generic_buffer.eo.c" diff --git a/src/lib/ector/ector_renderer_generic_buffer.eo b/src/lib/ector/ector_renderer_generic_buffer.eo new file mode 100644 index 0000000..94e1ef2 --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_buffer.eo @@ -0,0 +1,22 @@ +mixin Ector.Renderer.Generic.Buffer (Eo.Base, Efl.Gfx.Fill) +{ + [[Ector buffers have a default fill set to repeat]] + eo_prefix: ector_renderer_buffer; + legacy_prefix: null; + methods { + @property buffer { + set {} + get {} + values { + buf: Ector.Generic.Buffer*; + } + } + } + implements { + Eo.Base.constructor; + Efl.Gfx.Fill.fill_spread.get; + Efl.Gfx.Fill.fill_spread.set; + Efl.Gfx.Fill.fill.get; + Efl.Gfx.Fill.fill.set; + } +} diff --git a/src/lib/ector/ector_renderer_shape.c b/src/lib/ector/ector_renderer_shape.c index c5b09e0..76e67bb 100644 --- a/src/lib/ector/ector_renderer_shape.c +++ b/src/lib/ector/ector_renderer_shape.c @@ -12,7 +12,7 @@ _ector_renderer_generic_shape_fill_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Shape_Data *pd, const Ector_Renderer *r) { - _ector_renderer_replace(&pd->fill, r); + _eo_refplace(&pd->fill, r); } static const Ector_Renderer * @@ -27,7 +27,7 @@ _ector_renderer_generic_shape_stroke_fill_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Shape_Data *pd, const Ector_Renderer *r) { - _ector_renderer_replace(&pd->stroke.fill, r); + _eo_refplace(&pd->stroke.fill, r); } static const Ector_Renderer * @@ -42,7 +42,7 @@ _ector_renderer_generic_shape_stroke_marker_set(Eo *obj EINA_UNUSED, Ector_Renderer_Generic_Shape_Data *pd, const Ector_Renderer *r) { - _ector_renderer_replace(&pd->stroke.marker, r); + _eo_refplace(&pd->stroke.marker, r); } static const Ector_Renderer * diff --git a/src/lib/ector/ector_surface.h b/src/lib/ector/ector_surface.h index 424726a..0cc5a32 100644 --- a/src/lib/ector/ector_surface.h +++ b/src/lib/ector/ector_surface.h @@ -1,6 +1,7 @@ #ifndef ECTOR_SURFACE_H #define ECTOR_SURFACE_H +#include "ector_generic_buffer.eo.h" #include "ector_generic_surface.eo.h" #endif diff --git a/src/lib/ector/software/Ector_Software.h b/src/lib/ector/software/Ector_Software.h index ec074be..8e2a921 100644 --- a/src/lib/ector/software/Ector_Software.h +++ b/src/lib/ector/software/Ector_Software.h @@ -13,8 +13,10 @@ typedef Eo Ector_Software_Surface; typedef struct _Software_Rasterizer Software_Rasterizer; #include "software/ector_software_surface.eo.h" +#include "software/ector_software_buffer.eo.h" #include "software/ector_renderer_software_base.eo.h" #include "software/ector_renderer_software_shape.eo.h" +#include "software/ector_renderer_software_buffer.eo.h" #include "software/ector_renderer_software_gradient_linear.eo.h" #include "software/ector_renderer_software_gradient_radial.eo.h" diff --git a/src/lib/ector/software/ector_renderer_software_buffer.c b/src/lib/ector/software/ector_renderer_software_buffer.c new file mode 100644 index 0000000..2cda712 --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_buffer.c @@ -0,0 +1,72 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EFL_BETA_API_SUPPORT +#endif + +#include +#include "Ector_Software.h" +#include "ector_private.h" +#include "ector_software_private.h" + +#define MY_CLASS ECTOR_RENDERER_SOFTWARE_BUFFER_CLASS + +typedef struct +{ + Ector_Renderer_Generic_Base_Data *base; + Software_Rasterizer *surface; + Ector_Generic_Buffer *eo_buffer; +} Ector_Renderer_Software_Buffer_Data; + + +EOLIAN static void +_ector_renderer_software_buffer_buffer_set(Eo *obj, Ector_Renderer_Software_Buffer_Data *pd, Ector_Generic_Buffer *buf) +{ + _eo_xrefplace(&pd->eo_buffer, buf, obj); +} + +EOLIAN static Ector_Generic_Buffer * +_ector_renderer_software_buffer_buffer_get(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Buffer_Data *pd) +{ + return pd->eo_buffer; +} + +EOLIAN static Eina_Bool +_ector_renderer_software_buffer_ector_renderer_software_base_fill(Eo *obj, Ector_Renderer_Software_Buffer_Data *pd) +{ + Ector_Software_Buffer *buffer = eo_data_scope_get(obj, ECTOR_SOFTWARE_BUFFER_CLASS); + ector_software_rasterizer_buffer_set(pd->surface, buffer); + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_ector_renderer_software_buffer_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Software_Buffer_Data *pd) +{ + if (!pd->surface) + pd->surface = eo_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj); + + return EINA_TRUE; +} + +EOLIAN static unsigned int +_ector_renderer_software_buffer_ector_renderer_generic_base_crc_get(Eo *obj, Ector_Renderer_Software_Buffer_Data *pd) +{ + Ector_Software_Buffer_Data *buffer = eo_data_scope_get(pd->eo_buffer, ECTOR_SOFTWARE_BUFFER_CLASS); + unsigned int crc; + + eo_do_super(obj, MY_CLASS, crc = ector_renderer_crc_get()); + crc = eina_crc((const char *) buffer, sizeof(*buffer), crc, EINA_FALSE); + if (pd->surface) + crc = eina_crc((const char *) pd->surface, sizeof(*pd->surface), crc, EINA_FALSE); + + return crc; +} + +EOLIAN static void +_ector_renderer_software_buffer_eo_base_destructor(Eo *obj, Ector_Renderer_Software_Buffer_Data *pd) +{ + eo_data_xunref(pd->base->surface, pd->surface, obj); + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +#include "ector_renderer_software_buffer.eo.c" diff --git a/src/lib/ector/software/ector_renderer_software_buffer.eo b/src/lib/ector/software/ector_renderer_software_buffer.eo new file mode 100644 index 0000000..14c45ad --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_buffer.eo @@ -0,0 +1,19 @@ +class Ector.Renderer.Software.Buffer (Ector.Renderer.Software.Base, Ector.Renderer.Generic.Buffer) +{ + legacy_prefix: null; + methods { + @property buffer { + set {} + get {} + values { + buf: Ector.Generic.Buffer *; + } + } + } + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.crc.get; + Ector.Renderer.Software.Base.fill; + Eo.Base.destructor; + } +} diff --git a/src/lib/ector/software/ector_software_buffer.c b/src/lib/ector/software/ector_software_buffer.c new file mode 100644 index 0000000..4fdbcde --- /dev/null +++ b/src/lib/ector/software/ector_software_buffer.c @@ -0,0 +1,248 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EFL_BETA_API_SUPPORT +#endif + +#include +#include "Ector_Software.h" +#include "ector_private.h" +#include "ector_software_private.h" +#include "ector_generic_buffer.eo.h" + +#define fail(fmt, ...) do { ERR(fmt, ##__VA_ARGS__); goto on_fail; } while (0) + +static inline int +_min_stride_calc(int width, Efl_Gfx_Colorspace cspace) +{ + switch (cspace) + { + case EFL_GFX_COLORSPACE_ARGB8888: return width * 4; + case EFL_GFX_COLORSPACE_GRY8: return width; + default: return 0; + } +} + +/* FIXME: Conversion routines don't belong here */ +static inline void +_pixels_argb_to_gry8_convert(uint8_t *dst, const uint32_t *src, int len) +{ + int k; + for (k = 0; k < len; k++) + { + const uint32_t *s = src++; + *dst++ = A_VAL(s); + } +} + +static inline void +_pixels_gry8_to_argb_convert(uint32_t *dst, const uint8_t *src, int len) +{ + int k; + for (k = 0; k < len; k++) + { + uint8_t s = *src++; + *dst++ = ARGB_JOIN(s, s, s, s); + } +} + +EOLIAN static void +_ector_software_buffer_pixels_clear(Eo *obj, Ector_Software_Buffer_Data *pd) +{ + if (!pd->pixels.u8) + return; + + eo_do(obj, eo_event_callback_call(ECTOR_GENERIC_BUFFER_EVENT_DETACHED, pd->pixels.u8)); + if (!pd->nofree) + { + free(pd->pixels.u8); + } + pd->pixels.u8 = NULL; + pd->nofree = EINA_FALSE; +} + +EOLIAN static Eina_Bool +_ector_software_buffer_ector_generic_buffer_pixels_set(Eo *obj, Ector_Software_Buffer_Data *pd, + void *pixels, int width, int height, int stride, + Efl_Gfx_Colorspace cspace, Eina_Bool writable, + unsigned char l, unsigned char r, + unsigned char t, unsigned char b) +{ + // safety check + unsigned px = _min_stride_calc(1, cspace); + if (px && ((unsigned long long)(uintptr_t)pixels) & (px - 1)) + ERR("Pixel data is not aligned to %u bytes!", px); + + if ((cspace != EFL_GFX_COLORSPACE_ARGB8888) && + (cspace != EFL_GFX_COLORSPACE_GRY8)) + { + ERR("Unsupported colorspace: %u", cspace); + return EINA_FALSE; + } + + if (!stride) + stride = _min_stride_calc(width + l + r, cspace); + else if (stride < _min_stride_calc(width + l + r, cspace)) + { + ERR("Invalid stride %u for width %u (+%u+%u) cspace %u. pixels_set failed.", + stride, width, l, r, cspace); + _ector_software_buffer_pixels_clear(obj, pd); + return EINA_FALSE; + } + + if (pd->pixels.u8 && (pd->pixels.u8 != pixels)) + _ector_software_buffer_pixels_clear(obj, pd); + + if (pixels) + { + pd->pixels.u8 = pixels; + pd->nofree = EINA_TRUE; + pd->writable = !!writable; + } + else + { + pd->pixels.u8 = malloc(stride * (height + t + b)); + pd->nofree = EINA_FALSE; + pd->writable = EINA_TRUE; + } + pd->generic.w = width; + pd->generic.h = height; + pd->generic.l = l; + pd->generic.r = r; + pd->generic.t = t; + pd->generic.b = b; + pd->generic.cspace = cspace; + pd->stride = stride; + return EINA_TRUE; +} + +EOLIAN static uint8_t * +_ector_software_buffer_ector_generic_buffer_map(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Data *pd, + int *offset, unsigned int *length, + Ector_Buffer_Access_Flag mode EINA_UNUSED, + unsigned int x, unsigned int y, unsigned int w, unsigned int h, + Efl_Gfx_Colorspace cspace EINA_UNUSED, unsigned int *stride) +{ + int off; + + if (!pd->pixels.u8 || !pd->stride) + fail("Buffer has no pixel data yet"); + if (cspace != pd->generic.cspace) + fail("Invalid colorspace"); + if (!w || !h || ((x + w) > pd->generic.w) || (y + h > pd->generic.h)) + fail("Invalid region requested: wanted %u,%u %ux%u but image is %ux%u", + x, y, w, h, pd->generic.w, pd->generic.h); + + pd->map_count++; + off = _min_stride_calc(x + pd->generic.l, pd->generic.cspace) + (pd->stride * (y + pd->generic.t)); + if (offset) *offset = off; + if (length) *length = (pd->stride * pd->generic.h) - off; + if (stride) *stride = pd->stride; + return pd->pixels.u8; + +on_fail: + if (offset) *offset = 0; + if (length) *length = 0; + if (stride) *stride = 0; + return NULL; +} + +EOLIAN static void +_ector_software_buffer_ector_generic_buffer_unmap(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Data *pd, void *data, int offset EINA_UNUSED, unsigned int length EINA_UNUSED) +{ + if (!data) return; + if (data != pd->pixels.u8) + { + CRI("Trying to unmap a non-mapped region!"); + return; + } + if (pd->map_count == 0) + { + CRI("Unmapped too many times! Check your code!"); + return; + } + pd->map_count--; +} + +EOLIAN uint8_t * +_ector_software_buffer_ector_generic_buffer_span_get(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Data *pd, + int x, int y, unsigned int w, Efl_Gfx_Colorspace cspace, + unsigned int *length) +{ + uint8_t *src; + int len, px; + + if (!pd->pixels.u8) + fail("No pixel data"); + if ((x < -pd->generic.l) || (y < -pd->generic.t) || + ((unsigned) x > pd->generic.w) || ((unsigned) y > pd->generic.h)) + fail("Out of bounds"); + if (((unsigned) x + w) > (pd->generic.w + pd->generic.l + pd->generic.r)) + fail("Requested span too large"); + + px = _min_stride_calc(1, pd->generic.cspace); + len = _min_stride_calc(w, cspace); + if (length) *length = len; + + src = pd->pixels.u8 + ((pd->generic.t + y) * pd->stride) + (px * (pd->generic.l + x)); + + if (cspace == pd->generic.cspace) + { + pd->span_free = EINA_FALSE; + return src; + } + else if ((cspace == EFL_GFX_COLORSPACE_ARGB8888) && + (pd->generic.cspace == EFL_GFX_COLORSPACE_GRY8)) + { + uint32_t *buf = malloc(len); + _pixels_gry8_to_argb_convert(buf, src, w); + pd->span_free = EINA_TRUE; + return (uint8_t *) buf; + } + else if ((cspace == EFL_GFX_COLORSPACE_GRY8) && + (pd->generic.cspace == EFL_GFX_COLORSPACE_ARGB8888)) + { + uint8_t *buf = malloc(len); + _pixels_argb_to_gry8_convert(buf, (uint32_t *) src, w); + pd->span_free = EINA_TRUE; + return buf; + } + else + fail("Unsupported colorspace %u", cspace); + +on_fail: + if (length) *length = 0; + return NULL; +} + +EOLIAN void +_ector_software_buffer_ector_generic_buffer_span_free(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Data *pd, + uint8_t *data) +{ + if (pd->span_free) free(data); + pd->span_free = EINA_FALSE; +} + +EOLIAN static Ector_Buffer_Flag +_ector_software_buffer_ector_generic_buffer_flags_get(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Data *pd) +{ + return ECTOR_BUFFER_FLAG_CPU_READABLE | + ECTOR_BUFFER_FLAG_CPU_READABLE_FAST | + ECTOR_BUFFER_FLAG_RENDERABLE | + (pd->writable ? (ECTOR_BUFFER_FLAG_CPU_WRITABLE | + ECTOR_BUFFER_FLAG_CPU_WRITABLE_FAST) + : 0); +} + +EOLIAN static void +_ector_software_buffer_eo_base_destructor(Eo *obj, Ector_Software_Buffer_Data *pd) +{ + _ector_software_buffer_pixels_clear(obj, pd); + eo_do_super(obj, ECTOR_SOFTWARE_BUFFER_CLASS, eo_destructor()); + if (pd->map_count) + { + ERR("Pixel data is still mapped during destroy! Check your code!"); + } +} + +#include "ector_software_buffer.eo.c" diff --git a/src/lib/ector/software/ector_software_buffer.eo b/src/lib/ector/software/ector_software_buffer.eo new file mode 100644 index 0000000..a2e365a --- /dev/null +++ b/src/lib/ector/software/ector_software_buffer.eo @@ -0,0 +1,19 @@ +class Ector.Software.Buffer (Ector.Generic.Buffer) +{ + [[A buffer in Ector Software is a readable & optionally writable image]] + legacy_prefix: null; + methods { + pixels_clear @protected { + [[Clear internal pixel buffer]] + } + } + implements { + Eo.Base.destructor; + Ector.Generic.Buffer.flags.get; + Ector.Generic.Buffer.pixels_set; + Ector.Generic.Buffer.span_get; + Ector.Generic.Buffer.span_free; + Ector.Generic.Buffer.map; + Ector.Generic.Buffer.unmap; + } +} diff --git a/src/lib/ector/software/ector_software_private.h b/src/lib/ector/software/ector_software_private.h index a4d1221..d0ec132 100644 --- a/src/lib/ector/software/ector_software_private.h +++ b/src/lib/ector/software/ector_software_private.h @@ -3,6 +3,7 @@ #include "sw_ft_raster.h" #include "sw_ft_stroker.h" +#include "../ector_private.h" #ifndef DATA32 typedef unsigned int DATA32; @@ -48,6 +49,7 @@ typedef struct _Ector_Renderer_Software_Gradient_Data // Rasterizer related structure +// FIXME: Merge with Ector_Software_Buffer typedef struct _Raster_Buffer { int width; @@ -55,6 +57,20 @@ typedef struct _Raster_Buffer DATA32 *buffer; } Raster_Buffer; +typedef struct _Ector_Software_Buffer_Data +{ + Ector_Generic_Buffer_Data generic; + union { + unsigned int *u32; + unsigned char *u8; + } pixels; + unsigned int stride; + unsigned int map_count; + Eina_Bool writable : 1; + Eina_Bool nofree : 1; // pixel data should not be free()'ed + Eina_Bool span_free : 1; +} Ector_Software_Buffer_Data; + typedef struct _Shape_Rle_Data { Eina_Rectangle bbox; @@ -98,7 +114,7 @@ typedef struct _Span_Data union { DATA32 color; Ector_Renderer_Software_Gradient_Data *gradient; - //ImageData texture; + Ector_Software_Buffer_Data *buffer; }; } Span_Data; @@ -131,6 +147,7 @@ void ector_software_rasterizer_transform_set(Software_Rasterizer *rasterizer, Ei void ector_software_rasterizer_color_set(Software_Rasterizer *rasterizer, int r, int g, int b, int a); void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *linear); void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *radial); +void ector_software_rasterizer_buffer_set(Software_Rasterizer *rasterizer, Ector_Software_Buffer *image); void ector_software_rasterizer_clip_rect_set(Software_Rasterizer *rasterizer, Eina_Array *clips); void ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, Shape_Rle_Data *clip); diff --git a/src/lib/ector/software/ector_software_rasterizer.c b/src/lib/ector/software/ector_software_rasterizer.c index eb6ba8c..e58d611 100644 --- a/src/lib/ector/software/ector_software_rasterizer.c +++ b/src/lib/ector/software/ector_software_rasterizer.c @@ -74,6 +74,54 @@ _blend_gradient(int count, const SW_FT_Span *spans, void *user_data) } } +static void +_blend_image_gry8(int count, const SW_FT_Span *spans, void *user_data) +{ + Span_Data *data = user_data; + +#warning Need drawhelper here (no alpha support yet) + + while (count--) + { + spans++; + } +} + +static void +_blend_image_argb(int count, const SW_FT_Span *spans, void *user_data) +{ + Span_Data *data = user_data; + RGBA_Comp_Func comp_func; + DATA32 *buffer, *target; + DATA8 *src8; + unsigned int l, length, sy = 0; + +#warning FIXME: Image scaling, anyone? +#warning FIXME: Optimize eo call with early call resolution + + comp_func = ector_comp_func_span_get(data->op, data->mul_col, EINA_TRUE); + + buffer = data->raster_buffer.buffer + ((data->raster_buffer.width * data->offy) + data->offx); + + while (count--) + { + target = buffer + ((data->raster_buffer.width * spans->y) + spans->x); + length = spans->len; + while (length) + { + l = MIN(length, data->buffer->generic.w); + eo_do(data->buffer->generic.eo, src8 = ector_buffer_span_get(0, sy, l, EFL_GFX_COLORSPACE_ARGB8888, NULL)); + comp_func(target, (DATA32 *) src8, l, data->mul_col, spans->coverage); + eo_do(data->buffer->generic.eo, ector_buffer_span_free(src8)); + target += l; + length -= l; + } + ++spans; + ++sy; + if (sy >= data->buffer->generic.h) + sy = 0; + } +} /*! \internal @@ -279,7 +327,10 @@ _adjust_span_fill_methods(Span_Data *spdata) spdata->unclipped_blend = &_blend_gradient; break; case Image: - spdata->unclipped_blend = 0;//&_blend_image; + if (spdata->buffer->generic.cspace == EFL_GFX_COLORSPACE_GRY8) + spdata->unclipped_blend = &_blend_image_gry8; + else + spdata->unclipped_blend = &_blend_image_argb; break; } @@ -516,6 +567,13 @@ void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasteriz rasterizer->fill_data.type = RadialGradient; } +void ector_software_rasterizer_buffer_set(Software_Rasterizer *rasterizer, + Ector_Software_Buffer *buffer) +{ + rasterizer->fill_data.buffer = eo_data_scope_get(buffer, ECTOR_SOFTWARE_BUFFER_CLASS); + rasterizer->fill_data.type = Image; +} + void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer, int x, int y, uint mul_col, Ector_Rop op, Shape_Rle_Data* rle) diff --git a/src/lib/ector/software/ector_software_surface.c b/src/lib/ector/software/ector_software_surface.c index 0422920..4767e4e 100644 --- a/src/lib/ector/software/ector_software_surface.c +++ b/src/lib/ector/software/ector_software_surface.c @@ -27,6 +27,9 @@ _ector_software_surface_ector_generic_surface_renderer_factory_new(Eo *obj, else if (type == ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN) return eo_add(ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, NULL, ector_renderer_surface_set(obj)); + else if (type == ECTOR_RENDERER_GENERIC_BUFFER_MIXIN) + return eo_add(ECTOR_RENDERER_SOFTWARE_BUFFER_CLASS, NULL, + ector_renderer_surface_set(obj)); ERR("Couldn't find class for type: %s\n", eo_class_name_get(type)); return NULL; } diff --git a/src/lib/efl/interfaces/efl_gfx_base.eo b/src/lib/efl/interfaces/efl_gfx_base.eo index 8142533..566ef4f 100644 --- a/src/lib/efl/interfaces/efl_gfx_base.eo +++ b/src/lib/efl/interfaces/efl_gfx_base.eo @@ -1,3 +1,8 @@ +enum Efl.Gfx.Colorspace { + argb8888 = 0, [[ARGB 32 bits per pixel, high-byte is Alpha, accessed one 32-bit word at a time]] + gry8 = 4, [[8-bit gray image, or alpha only]] +} + interface Efl.Gfx.Base { legacy_prefix: null; eo_prefix: efl_gfx; -- 2.7.4