diff --git a/src/lib/ector/ector_buffer.h b/src/lib/ector/ector_buffer.h index f4a5f9df8c..0e12c79f68 100644 --- a/src/lib/ector/ector_buffer.h +++ b/src/lib/ector/ector_buffer.h @@ -35,7 +35,6 @@ typedef struct _Ector_Software_Buffer_Base_Data } internal; Eina_Bool writable : 1; // pixels can be written to Eina_Bool nofree : 1; // pixel data should not be free()'ed - Eina_Bool span_free : 1; // FIXME } Ector_Software_Buffer_Base_Data; #endif diff --git a/src/lib/ector/ector_generic_buffer.eo b/src/lib/ector/ector_generic_buffer.eo index 8f98108bfa..6e735b3428 100644 --- a/src/lib/ector/ector_generic_buffer.eo +++ b/src/lib/ector/ector_generic_buffer.eo @@ -40,17 +40,21 @@ mixin Ector.Generic.Buffer } map { [[Map a region of this buffer for read or write access by the CPU, - fetch data from the GPU if needed. + fetch data from the GPU if needed. This operation may be slow if + cpu_readable_fast or cpu_writeable_fast are not true, or if the + required colorspace is different from the internal one. ]] params { - @out length: uint; [[Accessible buffer size in bytes]] - @in mode: Ector.Buffer.Access_Flag; - @in x: uint; - @in y: uint; + @out length: uint; [[Accessible buffer size in bytes, should not be $null.]] + @in mode: Ector.Buffer.Access_Flag; [[Specifies whether to map for read-only, + write-only or read-write access (OR combinaison of flags).]] + @in x: uint; [[X position of the top-left pixel to map]] + @in y: uint; [[Y position of the top-left pixel to map]] @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]] + @in cspace: Efl.Gfx.Colorspace; [[Requested colorspace. If differen from the internal cspace, + map should try to convert the data into a new buffer]] + @out stride: uint @optional; [[Returns the length in bytes of a mapped line]] } return: void* @warn_unused; [[Pointer to the top-left pixel data. Returns $null in case of failure]] } @@ -58,7 +62,7 @@ mixin Ector.Generic.Buffer [[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 length: uint; + @in length: uint; [[Must be the same as returned } } pixels_set { diff --git a/src/lib/ector/software/ector_software_buffer.c b/src/lib/ector/software/ector_software_buffer.c index 1783258a95..e64234d4de 100644 --- a/src/lib/ector/software/ector_software_buffer.c +++ b/src/lib/ector/software/ector_software_buffer.c @@ -16,7 +16,7 @@ typedef struct _Ector_Software_Buffer_Map { EINA_INLIST; void *ptr; - unsigned int len; + unsigned int size; // in bytes Eina_Bool allocated; } Ector_Software_Buffer_Map; @@ -142,8 +142,11 @@ _ector_software_buffer_base_ector_generic_buffer_map(Eo *obj EINA_UNUSED, Ector_ unsigned int x, unsigned int y, unsigned int w, unsigned int h, Efl_Gfx_Colorspace cspace EINA_UNUSED, unsigned int *stride) { - Ector_Software_Buffer_Map *map; - int off; + Ector_Software_Buffer_Map *map = NULL; + unsigned int off, k; + + if (!w) w = pd->generic->w; + if (!h) h = pd->generic->h; if (!pd->pixels.u8 || !pd->stride) fail("Buffer has no pixel data yet"); @@ -153,20 +156,46 @@ _ector_software_buffer_base_ector_generic_buffer_map(Eo *obj EINA_UNUSED, Ector_ fail("Invalid region requested: wanted %u,%u %ux%u but image is %ux%u", x, y, w, h, pd->generic->w, pd->generic->h); if ((mode & ECTOR_BUFFER_ACCESS_FLAG_WRITE) && !pd->writable) - fail("can not map a read-only buffer for writing"); + fail("Can not map a read-only buffer for writing"); + + map = calloc(1, sizeof(*map)); + if (!map) fail("Out of memory"); off = _min_stride_calc(x + pd->generic->l, pd->generic->cspace) + (pd->stride * (y + pd->generic->t)); - map = calloc(1, sizeof(*map)); - map->len = (pd->stride * h) - off; - map->ptr = pd->pixels.u8 + off; - pd->internal.maps = eina_inlist_append(pd->internal.maps, EINA_INLIST_GET(map)); + if (cspace != pd->generic->cspace) + { + // convert on the fly + map->size = _min_stride_calc(w, cspace) * h; + map->allocated = EINA_TRUE; + map->ptr = malloc(map->size); + if (!map->ptr) fail("Out of memory"); + if (stride) *stride = _min_stride_calc(w, cspace); - if (length) *length = map->len; - if (stride) *stride = pd->stride; + if (cspace == EFL_GFX_COLORSPACE_ARGB8888) + { + for (k = 0; k < h; k++) + _pixels_gry8_to_argb_convert((uint32_t *) map->ptr + (k * w), pd->pixels.u8 + off + (k * pd->stride), w); + } + else + { + for (k = 0; k < h; k++) + _pixels_argb_to_gry8_convert((uint8_t *) map->ptr + (k * w), (uint32_t *) (pd->pixels.u8 + off + (k * pd->stride)), w); + } + } + else + { + map->size = (pd->stride * h) - off; + map->ptr = pd->pixels.u8 + off; + if (stride) *stride = pd->stride; + } + + pd->internal.maps = eina_inlist_prepend(pd->internal.maps, EINA_INLIST_GET(map)); + if (length) *length = map->size; return map->ptr; on_fail: + free(map); if (length) *length = 0; if (stride) *stride = 0; return NULL; @@ -181,9 +210,11 @@ _ector_software_buffer_base_ector_generic_buffer_unmap(Eo *obj EINA_UNUSED, Ecto EINA_INLIST_FOREACH(pd->internal.maps, map) { - if ((map->ptr == data) && (map->len == length)) + if ((map->ptr == data) && ((map->size == length) || (length == (unsigned int) -1))) { pd->internal.maps = eina_inlist_remove(pd->internal.maps, EINA_INLIST_GET(map)); + if (map->allocated) + free(map->ptr); free(map); return; } @@ -193,62 +224,22 @@ _ector_software_buffer_base_ector_generic_buffer_unmap(Eo *obj EINA_UNUSED, Ecto } EOLIAN static uint8_t * -_ector_software_buffer_base_ector_generic_buffer_span_get(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Base_Data *pd, +_ector_software_buffer_base_ector_generic_buffer_span_get(Eo *obj, Ector_Software_Buffer_Base_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; + // ector_buffer_map + return _ector_software_buffer_base_ector_generic_buffer_map + (obj, pd, length, ECTOR_BUFFER_ACCESS_FLAG_READ, x, y, w, 1, cspace, NULL); } EOLIAN static void -_ector_software_buffer_base_ector_generic_buffer_span_free(Eo *obj EINA_UNUSED, Ector_Software_Buffer_Base_Data *pd, +_ector_software_buffer_base_ector_generic_buffer_span_free(Eo *obj, Ector_Software_Buffer_Base_Data *pd, uint8_t *data) { - if (pd->span_free) free(data); - pd->span_free = EINA_FALSE; + // ector_buffer_unmap + return _ector_software_buffer_base_ector_generic_buffer_unmap + (obj, pd, data, (unsigned int) -1); } EOLIAN static Ector_Buffer_Flag