From 12eeb9524aa9421c03f253ab6161634bec66793b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 27 Apr 2014 14:00:33 -0400 Subject: gl: Make drawing faster by using a better pixel format. --- dimension/preview.py | 2 +- libdimension/Makefile.am | 4 +- libdimension/canvas.c | 14 ++++++ libdimension/dimension-internal.h | 2 +- libdimension/dimension/canvas.h | 11 +++++ libdimension/gl.c | 26 ++++++------ libdimension/png.c | 30 ++++++------- libdimension/rgba.c | 89 +++++++++++++++++++++++++++++++++++++++ libdimension/rgba.h | 38 +++++++++++++++++ libdimension/rgba16.c | 62 --------------------------- libdimension/rgba16.h | 31 -------------- 11 files changed, 183 insertions(+), 126 deletions(-) create mode 100644 libdimension/rgba.c create mode 100644 libdimension/rgba.h delete mode 100644 libdimension/rgba16.c delete mode 100644 libdimension/rgba16.h diff --git a/dimension/preview.py b/dimension/preview.py index aa4d032..dcc38f1 100644 --- a/dimension/preview.py +++ b/dimension/preview.py @@ -53,7 +53,7 @@ class PreviewWindow(QtGui.QMainWindow): self.render_timer = QtCore.QTimer(self) self.render_timer.timeout.connect(self.update_preview) - self.render_timer.start(0) + self.render_timer.start(20) @QtCore.pyqtSlot() def update_preview(self): diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index 3e3cb86..06fa7b8 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -106,8 +106,8 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \ ray_trace.c \ refcount-internal.h \ reflection.c \ - rgba16.c \ - rgba16.h \ + rgba.c \ + rgba.h \ scene.c \ solid_pigment.c \ sphere.c \ diff --git a/libdimension/canvas.c b/libdimension/canvas.c index c7c1994..1ee68e2 100644 --- a/libdimension/canvas.c +++ b/libdimension/canvas.c @@ -66,6 +66,20 @@ dmnsn_canvas_optimize(dmnsn_canvas *canvas, 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_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { + if (i->optimizer_fn == optimizer_fn) { + return i; + } + } + + return NULL; +} + /* Set the value of a pixel */ void dmnsn_canvas_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, diff --git a/libdimension/dimension-internal.h b/libdimension/dimension-internal.h index c8d728e..a0bbe61 100644 --- a/libdimension/dimension-internal.h +++ b/libdimension/dimension-internal.h @@ -36,6 +36,6 @@ #include "threads.h" #include "bvh.h" #include "prtree.h" -#include "rgba16.h" +#include "rgba.h" #endif /* DIMENSION_INTERNAL_H */ diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h index 2000141..ba549ad 100644 --- a/libdimension/dimension/canvas.h +++ b/libdimension/dimension/canvas.h @@ -83,6 +83,17 @@ void dmnsn_delete_canvas(dmnsn_canvas *canvas); void dmnsn_canvas_optimize(dmnsn_canvas *canvas, const dmnsn_canvas_optimizer *optimizer); +/** + * Find a canvas optimizer by its callback. + * @param[in] canvas The canvas to check. + * @param[in] optimizer_fn The callback to search for for. + * @return A pointer to the canvas optimizer with the callback \p optimizer_fn, + * or NULL if none is found. + */ +dmnsn_canvas_optimizer * +dmnsn_canvas_find_optimizer(const dmnsn_canvas *canvas, + dmnsn_canvas_optimizer_fn *optimizer_fn); + /* Pixel accessors */ /** diff --git a/libdimension/gl.c b/libdimension/gl.c index e2d222c..0b6b0b0 100644 --- a/libdimension/gl.c +++ b/libdimension/gl.c @@ -32,7 +32,7 @@ int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) { - dmnsn_rgba16_optimize_canvas(canvas); + dmnsn_rgba8_optimize_canvas(canvas); return 0; } @@ -44,33 +44,33 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) size_t height = canvas->height; /* Check if we can optimize this */ - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { - if (i->optimizer_fn == dmnsn_rgba16_optimizer_fn) { - glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, i->ptr); - return glGetError() == GL_NO_ERROR ? 0 : 1; - } + 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); + return glGetError() == GL_NO_ERROR ? 0 : 1; } /* We couldn't, so transform the canvas to RGB now */ - GLushort *pixels = dmnsn_malloc(4*width*height*sizeof(GLushort)); + GLubyte *pixels = dmnsn_malloc(4*width*height*sizeof(GLubyte)); for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { - GLushort *pixel = pixels + 4*(y*width + x); + GLubyte *pixel = pixels + 4*(y*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); tcolor = dmnsn_tcolor_saturate(tcolor); - pixel[0] = lround(tcolor.c.R*UINT16_MAX); - pixel[1] = lround(tcolor.c.G*UINT16_MAX); - pixel[2] = lround(tcolor.c.B*UINT16_MAX); - pixel[3] = lround(tcolor.T*UINT16_MAX); + pixel[0] = lround(tcolor.c.R*UINT8_MAX); + pixel[1] = lround(tcolor.c.G*UINT8_MAX); + pixel[2] = lround(tcolor.c.B*UINT8_MAX); + pixel[3] = lround(tcolor.T*UINT8_MAX); } } - glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels); + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); dmnsn_free(pixels); return glGetError() == GL_NO_ERROR ? 0 : 1; diff --git a/libdimension/png.c b/libdimension/png.c index cc8b34f..ab5ea5c 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -175,23 +175,21 @@ dmnsn_png_write_canvas_thread(void *ptr) } /* Check if we can optimize this */ - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, - payload->canvas->optimizers) - { - if (i->optimizer_fn == dmnsn_rgba16_optimizer_fn) { - for (size_t y = 0; y < height; ++y) { - /* Invert the rows. PNG coordinates are fourth quadrant. */ - uint16_t *row_opt = (uint16_t *)i->ptr + 4*(height - y - 1)*width; - png_write_row(png_ptr, (png_bytep)row_opt); - dmnsn_future_increment(payload->future); - } - - /* Finish the PNG file */ - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - dmnsn_free(payload); - return 0; + dmnsn_canvas_optimizer *optimizer = + dmnsn_canvas_find_optimizer(payload->canvas, dmnsn_rgba16_optimizer_fn); + if (optimizer) { + 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; + png_write_row(png_ptr, (png_bytep)row_opt); + dmnsn_future_increment(payload->future); } + + /* Finish the PNG file */ + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + dmnsn_free(payload); + return 0; } /* Allocate the temporary row of RGBA values */ diff --git a/libdimension/rgba.c b/libdimension/rgba.c new file mode 100644 index 0000000..6df124e --- /dev/null +++ b/libdimension/rgba.c @@ -0,0 +1,89 @@ +/************************************************************************* + * Copyright (C) 2010-2011 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * 16-bit RGBA canvas optimizer. + */ + +#include "dimension-internal.h" +#include + +void +dmnsn_rgba8_optimize_canvas(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)); + + dmnsn_canvas_optimize(canvas, &optimizer); +} + +void +dmnsn_rgba16_optimize_canvas(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)); + + dmnsn_canvas_optimize(canvas, &optimizer); +} + +void +dmnsn_rgba8_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, + size_t x, size_t y) +{ + uint8_t *pixel = (uint8_t *)ptr + 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); + tcolor = dmnsn_tcolor_saturate(tcolor); + + pixel[0] = lround(tcolor.c.R*UINT8_MAX); + pixel[1] = lround(tcolor.c.G*UINT8_MAX); + pixel[2] = lround(tcolor.c.B*UINT8_MAX); + pixel[3] = lround(tcolor.T*UINT8_MAX); +} + +void +dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, + size_t x, size_t y) +{ + uint16_t *pixel = (uint16_t *)ptr + 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); + tcolor = dmnsn_tcolor_saturate(tcolor); + + pixel[0] = lround(tcolor.c.R*UINT16_MAX); + pixel[1] = lround(tcolor.c.G*UINT16_MAX); + pixel[2] = lround(tcolor.c.B*UINT16_MAX); + pixel[3] = lround(tcolor.T*UINT16_MAX); +} diff --git a/libdimension/rgba.h b/libdimension/rgba.h new file mode 100644 index 0000000..21d5044 --- /dev/null +++ b/libdimension/rgba.h @@ -0,0 +1,38 @@ +/************************************************************************* + * Copyright (C) 2010-2011 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * RGBA canvas optimizer interface, used by image optimizers. + */ + +/** Apply the RGBA8 optimizer to a canvas. */ +DMNSN_INTERNAL void dmnsn_rgba8_optimize_canvas(dmnsn_canvas *canvas); +/** Apply the RGBA16 optimizer to a canvas. */ +DMNSN_INTERNAL void dmnsn_rgba16_optimize_canvas(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); +/** RGBA16 optimizer callback. */ +DMNSN_INTERNAL void dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, + void *ptr, + size_t x, size_t y); diff --git a/libdimension/rgba16.c b/libdimension/rgba16.c deleted file mode 100644 index 2198677..0000000 --- a/libdimension/rgba16.c +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -/** - * @file - * 16-bit RGBA canvas optimizer. - */ - -#include "dimension-internal.h" -#include - -void -dmnsn_rgba16_optimize_canvas(dmnsn_canvas *canvas) -{ - /* Check if we've already optimized this canvas */ - DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { - if (i->optimizer_fn == 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)); - - dmnsn_canvas_optimize(canvas, &optimizer); -} - -/* RGBA16 optimizer callback */ -void -dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, - size_t x, size_t y) -{ - uint16_t *pixel = (uint16_t *)ptr + 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); - tcolor = dmnsn_tcolor_saturate(tcolor); - - pixel[0] = lround(tcolor.c.R*UINT16_MAX); - pixel[1] = lround(tcolor.c.G*UINT16_MAX); - pixel[2] = lround(tcolor.c.B*UINT16_MAX); - pixel[3] = lround(tcolor.T*UINT16_MAX); -} diff --git a/libdimension/rgba16.h b/libdimension/rgba16.h deleted file mode 100644 index 86f5bf7..0000000 --- a/libdimension/rgba16.h +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -/** - * @file - * 16-bit RGBA canvas optimizer interface, used by image optimizers. - */ - -/** Apply the rgba16 optimizer to a canvas. */ -void dmnsn_rgba16_optimize_canvas(dmnsn_canvas *canvas); - -/** RGBA16 optimizer callback. */ -void dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas, void *ptr, - size_t x, size_t y); -- cgit v1.2.3