From e39f2e09698556e7895b084b7addb88d3e7ea58d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 19 Jun 2014 16:58:14 -0400 Subject: canvas: Kill optimizers' ->ptr field. --- libdimension-python/dimension.pxd | 4 ++-- libdimension-python/dimension.pyx | 4 ++-- libdimension/canvas.c | 37 +++++++++++--------------------- libdimension/dimension/canvas.h | 25 +++++++++++++--------- libdimension/dimension/gl.h | 3 ++- libdimension/dimension/png.h | 3 ++- libdimension/gl-stubs.c | 2 +- libdimension/gl.c | 11 +++++----- libdimension/png-stubs.c | 2 +- libdimension/png.c | 11 +++++----- libdimension/rgba.c | 44 ++++++++++++++++++++++----------------- libdimension/rgba.h | 28 +++++++++++++++++-------- libdimension/tests/gl.c | 2 +- libdimension/tests/png.c | 2 +- libdimension/tests/render.c | 4 ++-- 15 files changed, 95 insertions(+), 87 deletions(-) diff --git a/libdimension-python/dimension.pxd b/libdimension-python/dimension.pxd index f002125..df291a6 100644 --- a/libdimension-python/dimension.pxd +++ b/libdimension-python/dimension.pxd @@ -219,13 +219,13 @@ cdef extern from "../libdimension/dimension.h": void dmnsn_canvas_clear(dmnsn_canvas *canvas, dmnsn_tcolor tcolor) - int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) + int dmnsn_png_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) int dmnsn_png_write_canvas(dmnsn_canvas *canvas, FILE *file) dmnsn_future *dmnsn_png_write_canvas_async(dmnsn_canvas *canvas, FILE *file) dmnsn_canvas *dmnsn_png_read_canvas(dmnsn_pool *pool, FILE *file) dmnsn_future *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, dmnsn_pool *pool, FILE *file) - int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) + int dmnsn_gl_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) int dmnsn_gl_write_canvas(dmnsn_canvas *canvas) ############ diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx index 58b68e2..2bdcc64 100644 --- a/libdimension-python/dimension.pyx +++ b/libdimension-python/dimension.pyx @@ -666,12 +666,12 @@ cdef class Canvas: def optimize_PNG(self): """Optimize a canvas for PNG output.""" - if dmnsn_png_optimize_canvas(self._canvas) != 0: + if dmnsn_png_optimize_canvas(_get_pool(), self._canvas) != 0: _raise_OSError() def optimize_GL(self): """Optimize a canvas for OpenGL output.""" - if dmnsn_gl_optimize_canvas(self._canvas) != 0: + if dmnsn_gl_optimize_canvas(_get_pool(), self._canvas) != 0: _raise_OSError() def clear(self, c): diff --git a/libdimension/canvas.c b/libdimension/canvas.c index b605108..2aade47 100644 --- a/libdimension/canvas.c +++ b/libdimension/canvas.c @@ -25,50 +25,37 @@ #include "dimension-internal.h" -/// cleanup_fn for canvases. -static void dmnsn_canvas_cleanup(void *ptr); - dmnsn_canvas * dmnsn_new_canvas(dmnsn_pool *pool, size_t width, size_t height) { - dmnsn_canvas *canvas = DMNSN_PALLOC_TIDY(pool, dmnsn_canvas, dmnsn_canvas_cleanup); + dmnsn_canvas *canvas = DMNSN_PALLOC(pool, dmnsn_canvas); canvas->width = width; canvas->height = height; - canvas->optimizers = DMNSN_NEW_ARRAY(dmnsn_canvas_optimizer); + canvas->optimizers = DMNSN_PALLOC_ARRAY(pool, dmnsn_canvas_optimizer *); canvas->pixels = dmnsn_palloc(pool, sizeof(dmnsn_tcolor)*width*height); return canvas; } void -dmnsn_canvas_cleanup(void *ptr) +dmnsn_init_canvas_optimizer(dmnsn_canvas_optimizer *optimizer) { - dmnsn_canvas *canvas = ptr; - - // Free the optimizers - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { - if (i->free_fn) { - i->free_fn(i->ptr); - } - } - dmnsn_delete_array(canvas->optimizers); + optimizer->optimizer_fn = NULL; } // Set a canvas optimizer void -dmnsn_canvas_optimize(dmnsn_canvas *canvas, - const dmnsn_canvas_optimizer *optimizer) +dmnsn_canvas_optimize(dmnsn_canvas *canvas, const dmnsn_canvas_optimizer *optimizer) { - dmnsn_array_push(canvas->optimizers, optimizer); + dmnsn_array_push(canvas->optimizers, &optimizer); } // Find an optimizer if it's already installed dmnsn_canvas_optimizer * -dmnsn_canvas_find_optimizer(const dmnsn_canvas *canvas, - dmnsn_canvas_optimizer_fn *optimizer_fn) +dmnsn_canvas_find_optimizer(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer_fn *optimizer_fn) { - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { - if (i->optimizer_fn == optimizer_fn) { - return i; + DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer **, i, canvas->optimizers) { + if ((*i)->optimizer_fn == optimizer_fn) { + return *i; } } @@ -88,8 +75,8 @@ dmnsn_canvas_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, canvas->pixels[y*canvas->width + x] = tcolor; // Call the optimizers - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { - i->optimizer_fn(canvas, i->ptr, x, y); + DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer **, i, canvas->optimizers) { + (*i)->optimizer_fn(*i, canvas, x, y); } } diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h index d03a37e..e325364 100644 --- a/libdimension/dimension/canvas.h +++ b/libdimension/dimension/canvas.h @@ -41,23 +41,22 @@ typedef struct dmnsn_canvas { dmnsn_tcolor *pixels; } dmnsn_canvas; +/* Forward-declare dmnsn_canvas_optimizer. */ +typedef struct dmnsn_canvas_optimizer dmnsn_canvas_optimizer; + /** * Canvas optimizer callback type. + * @param[in] optimizer The canvas optimizer. * @param[in] canvas The canvas that was just updated. - * @param[in] ptr The canvas optimizer's data pointer. - * @param[in] x The x-coordinate that was just updated. - * @param[in] y The y-coordinate that was just updated. + * @param[in] x The x-coordinate that was just updated. + * @param[in] y The y-coordinate that was just updated. */ -typedef void dmnsn_canvas_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, - size_t x, size_t y); +typedef void dmnsn_canvas_optimizer_fn(dmnsn_canvas_optimizer *optimizer, const dmnsn_canvas *canvas, size_t x, size_t y); /** Canvas optimizer. */ -typedef struct dmnsn_canvas_optimizer { +struct dmnsn_canvas_optimizer { dmnsn_canvas_optimizer_fn *optimizer_fn; /**< Optimizer callback. */ - dmnsn_free_fn *free_fn; /**< Destructor callback. */ - - void *ptr; /**< Generic pointer. */ -} dmnsn_canvas_optimizer; +}; /** * Allocate a new canvas. @@ -68,6 +67,12 @@ typedef struct dmnsn_canvas_optimizer { */ dmnsn_canvas *dmnsn_new_canvas(dmnsn_pool *pool, size_t width, size_t height); +/** + * Initialize a dmnsn_canvas_optimizer field + * @param[in] optimizer The optimizer to initialize. + */ +void dmnsn_init_canvas_optimizer(dmnsn_canvas_optimizer *optimizer); + /** * Set a canvas optimizer * @param[in,out] canvas The canvas to optimize. diff --git a/libdimension/dimension/gl.h b/libdimension/dimension/gl.h index 8e64ba6..284a248 100644 --- a/libdimension/dimension/gl.h +++ b/libdimension/dimension/gl.h @@ -25,10 +25,11 @@ /** * Optimize a canvas for GL drawing + * @param[in] pool The memory pool to allocate from. * @param[in,out] canvas The canvas to optimize. * @return Whether the canvas was successfully optimized. */ -int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas); +int dmnsn_gl_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas); /** * Write canvas to GL framebuffer. diff --git a/libdimension/dimension/png.h b/libdimension/dimension/png.h index c45a9bf..f4d2c1e 100644 --- a/libdimension/dimension/png.h +++ b/libdimension/dimension/png.h @@ -27,10 +27,11 @@ /** * Optimize a canvas for PNG exporting + * @param[in] pool The memory pool to allocate from. * @param[in,out] canvas The canvas to optimize. * @return Whether the canvas was successfully optimized. */ -int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas); +int dmnsn_png_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas); /** * Write a canvas to a file in PNG format. diff --git a/libdimension/gl-stubs.c b/libdimension/gl-stubs.c index ca17056..df31308 100644 --- a/libdimension/gl-stubs.c +++ b/libdimension/gl-stubs.c @@ -27,7 +27,7 @@ #include int -dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_gl_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { errno = ENOSYS; return -1; diff --git a/libdimension/gl.c b/libdimension/gl.c index 2800484..dd707a9 100644 --- a/libdimension/gl.c +++ b/libdimension/gl.c @@ -30,9 +30,9 @@ // Optimize canvas for GL drawing int -dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_gl_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { - dmnsn_rgba8_optimize_canvas(canvas); + dmnsn_rgba8_optimize_canvas(pool, canvas); return 0; } @@ -44,10 +44,9 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) size_t height = canvas->height; // Check if we can optimize this - dmnsn_canvas_optimizer *optimizer = - dmnsn_canvas_find_optimizer(canvas, dmnsn_rgba8_optimizer_fn); - if (optimizer) { - glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, optimizer->ptr); + dmnsn_rgba8_optimizer *rgba8 = (dmnsn_rgba8_optimizer *)dmnsn_canvas_find_optimizer(canvas, dmnsn_rgba8_optimizer_fn); + if (rgba8) { + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba8->data); return glGetError() == GL_NO_ERROR ? 0 : 1; } diff --git a/libdimension/png-stubs.c b/libdimension/png-stubs.c index d68b543..9c752a5 100644 --- a/libdimension/png-stubs.c +++ b/libdimension/png-stubs.c @@ -27,7 +27,7 @@ #include int -dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_png_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { errno = ENOSYS; return -1; diff --git a/libdimension/png.c b/libdimension/png.c index 24f8afa..faca080 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -31,9 +31,9 @@ #include int -dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_png_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { - dmnsn_rgba16_optimize_canvas(canvas); + dmnsn_rgba16_optimize_canvas(pool, canvas); return 0; } @@ -171,12 +171,11 @@ dmnsn_png_write_canvas_thread(void *ptr) } // Check if we can optimize this - dmnsn_canvas_optimizer *optimizer = - dmnsn_canvas_find_optimizer(payload->canvas, dmnsn_rgba16_optimizer_fn); - if (optimizer) { + dmnsn_rgba16_optimizer *rgba16 = (dmnsn_rgba16_optimizer *)dmnsn_canvas_find_optimizer(payload->canvas, dmnsn_rgba16_optimizer_fn); + if (rgba16) { for (size_t y = 0; y < height; ++y) { // Invert the rows. PNG coordinates are fourth quadrant. - uint16_t *row_opt = (uint16_t *)optimizer->ptr + 4*(height - y - 1)*width; + uint16_t *row_opt = rgba16->data + 4*(height - y - 1)*width; png_write_row(png_ptr, (png_bytep)row_opt); dmnsn_future_increment(payload->future); } diff --git a/libdimension/rgba.c b/libdimension/rgba.c index 6df124e..367927f 100644 --- a/libdimension/rgba.c +++ b/libdimension/rgba.c @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * + * Copyright (C) 2010-2014 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -27,40 +27,45 @@ #include void -dmnsn_rgba8_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_rgba8_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { if (dmnsn_canvas_find_optimizer(canvas, dmnsn_rgba8_optimizer_fn)) { return; } - dmnsn_canvas_optimizer optimizer; - optimizer.optimizer_fn = dmnsn_rgba8_optimizer_fn; - optimizer.free_fn = dmnsn_free; - optimizer.ptr = dmnsn_malloc(4*canvas->width*canvas->height*sizeof(uint8_t)); + size_t ndata = 4*canvas->width*canvas->height; + dmnsn_rgba8_optimizer *rgba8 = dmnsn_palloc(pool, sizeof(dmnsn_rgba8_optimizer) + ndata*sizeof(uint8_t)); - dmnsn_canvas_optimize(canvas, &optimizer); + dmnsn_canvas_optimizer *optimizer = &rgba8->optimizer; + dmnsn_init_canvas_optimizer(optimizer); + optimizer->optimizer_fn = dmnsn_rgba8_optimizer_fn; + + dmnsn_canvas_optimize(canvas, optimizer); } void -dmnsn_rgba16_optimize_canvas(dmnsn_canvas *canvas) +dmnsn_rgba16_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas) { if (dmnsn_canvas_find_optimizer(canvas, dmnsn_rgba16_optimizer_fn)) { return; } - dmnsn_canvas_optimizer optimizer; - optimizer.optimizer_fn = dmnsn_rgba16_optimizer_fn; - optimizer.free_fn = dmnsn_free; - optimizer.ptr = dmnsn_malloc(4*canvas->width*canvas->height*sizeof(uint16_t)); + size_t ndata = 4*canvas->width*canvas->height; + dmnsn_rgba16_optimizer *rgba16 = dmnsn_palloc(pool, sizeof(dmnsn_rgba16_optimizer) + ndata*sizeof(uint16_t)); + + dmnsn_canvas_optimizer *optimizer = &rgba16->optimizer; + dmnsn_init_canvas_optimizer(optimizer); + optimizer->optimizer_fn = dmnsn_rgba16_optimizer_fn; - dmnsn_canvas_optimize(canvas, &optimizer); + dmnsn_canvas_optimize(canvas, optimizer); } void -dmnsn_rgba8_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, - size_t x, size_t y) +dmnsn_rgba8_optimizer_fn(dmnsn_canvas_optimizer *optimizer, const dmnsn_canvas *canvas, size_t x, size_t y) { - uint8_t *pixel = (uint8_t *)ptr + 4*(y*canvas->width + x); + dmnsn_rgba8_optimizer *rgba8 = (dmnsn_rgba8_optimizer *)optimizer; + + uint8_t *pixel = rgba8->data + 4*(y*canvas->width + x); dmnsn_tcolor tcolor = dmnsn_canvas_get_pixel(canvas, x, y); tcolor = dmnsn_tcolor_remove_filter(tcolor); tcolor.c = dmnsn_color_to_sRGB(tcolor.c); @@ -73,10 +78,11 @@ dmnsn_rgba8_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, } void -dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, - size_t x, size_t y) +dmnsn_rgba16_optimizer_fn(dmnsn_canvas_optimizer *optimizer, const dmnsn_canvas *canvas, size_t x, size_t y) { - uint16_t *pixel = (uint16_t *)ptr + 4*(y*canvas->width + x); + dmnsn_rgba16_optimizer *rgba16 = (dmnsn_rgba16_optimizer *)optimizer; + + uint16_t *pixel = rgba16->data + 4*(y*canvas->width + x); dmnsn_tcolor tcolor = dmnsn_canvas_get_pixel(canvas, x, y); tcolor = dmnsn_tcolor_remove_filter(tcolor); tcolor.c = dmnsn_color_to_sRGB(tcolor.c); diff --git a/libdimension/rgba.h b/libdimension/rgba.h index a67caf2..b43ca3f 100644 --- a/libdimension/rgba.h +++ b/libdimension/rgba.h @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * + * Copyright (C) 2010-2014 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -23,16 +23,26 @@ * RGBA canvas optimizer interface, used by image optimizers. */ +#include + +/// RGBA8 optimizer type. +typedef struct dmnsn_rgba8_optimizer { + dmnsn_canvas_optimizer optimizer; + uint8_t data[]; +} dmnsn_rgba8_optimizer; + +/// RGBA16 optimizer type. +typedef struct dmnsn_rgba16_optimizer { + dmnsn_canvas_optimizer optimizer; + uint16_t data[]; +} dmnsn_rgba16_optimizer; + /// Apply the RGBA8 optimizer to a canvas. -DMNSN_INTERNAL void dmnsn_rgba8_optimize_canvas(dmnsn_canvas *canvas); +DMNSN_INTERNAL void dmnsn_rgba8_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas); /// Apply the RGBA16 optimizer to a canvas. -DMNSN_INTERNAL void dmnsn_rgba16_optimize_canvas(dmnsn_canvas *canvas); +DMNSN_INTERNAL void dmnsn_rgba16_optimize_canvas(dmnsn_pool *pool, dmnsn_canvas *canvas); /// RGBA8 optimizer callback. -DMNSN_INTERNAL void dmnsn_rgba8_optimizer_fn(const dmnsn_canvas *canvas, - void *ptr, - size_t x, size_t y); +DMNSN_INTERNAL void dmnsn_rgba8_optimizer_fn(dmnsn_canvas_optimizer *optimizer, const dmnsn_canvas *canvas, size_t x, size_t y); /// RGBA16 optimizer callback. -DMNSN_INTERNAL void dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, - void *ptr, - size_t x, size_t y); +DMNSN_INTERNAL void dmnsn_rgba16_optimizer_fn(dmnsn_canvas_optimizer *optimizer, const dmnsn_canvas *canvas, size_t x, size_t y); diff --git a/libdimension/tests/gl.c b/libdimension/tests/gl.c index 262fecf..1546d6c 100644 --- a/libdimension/tests/gl.c +++ b/libdimension/tests/gl.c @@ -56,7 +56,7 @@ main(void) */ // Optimize the canvas for GL drawing - if (dmnsn_gl_optimize_canvas(canvas) != 0) { + if (dmnsn_gl_optimize_canvas(pool, canvas) != 0) { dmnsn_delete_pool(pool); fprintf(stderr, "--- Couldn't optimize canvas for GL! ---\n"); return EXIT_FAILURE; diff --git a/libdimension/tests/png.c b/libdimension/tests/png.c index 1feff72..7311e43 100644 --- a/libdimension/tests/png.c +++ b/libdimension/tests/png.c @@ -34,7 +34,7 @@ main(void) dmnsn_canvas *canvas = dmnsn_new_canvas(pool, 768, 480); // Optimize the canvas for PNG export - if (dmnsn_png_optimize_canvas(canvas) != 0) { + if (dmnsn_png_optimize_canvas(pool, canvas) != 0) { fprintf(stderr, "--- Couldn't optimize canvas for PNG! ---\n"); ret = EXIT_FAILURE; goto exit; diff --git a/libdimension/tests/render.c b/libdimension/tests/render.c index 866df2d..56a80d3 100644 --- a/libdimension/tests/render.c +++ b/libdimension/tests/render.c @@ -316,7 +316,7 @@ main(void) // Optimize the canvas for PNG export bool have_png = true; errno = 0; - if (dmnsn_png_optimize_canvas(scene->canvas) != 0) { + if (dmnsn_png_optimize_canvas(pool, scene->canvas) != 0) { if (errno == ENOSYS) { have_png = false; } else { @@ -328,7 +328,7 @@ main(void) // Optimize the canvas for GL drawing bool have_gl = true; errno = 0; - if (dmnsn_gl_optimize_canvas(scene->canvas) != 0) { + if (dmnsn_gl_optimize_canvas(pool, scene->canvas) != 0) { if (errno == ENOSYS) { have_gl = false; } else { -- cgit v1.2.3