This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, generate has been updated
via bf71ed549471116331486980f67e4f64b840640d (commit)
via 4d19114d20f531cd49c79158af4263ea4af98109 (commit)
from d291a122c53ce9d70a5777b380ae9ca82978987b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/bf71ed549471116331486980f67e4f64b840…
commit bf71ed549471116331486980f67e4f64b840640d
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Oct 6 19:28:37 2011 +0200
Attempt to fix the aligned pixel access.
* The Get/PutPixel is now full of special cases
Beware that the code wasn't tested to work yet.
diff --git a/include/core/GP_Common.h b/include/core/GP_Common.h
index 23e5527..cae989e 100644
--- a/include/core/GP_Common.h
+++ b/include/core/GP_Common.h
@@ -140,51 +140,6 @@
a = tmp; } while (0)
-/*
- * Helper macros to read/write parts of words
- *
- * Return (shifted) count bits at offset of value
- * Note: operates with value types same as val
- */
-#define GP_GET_BITS(offset, count, val) - ( ( (val)>>(offset) ) & ( ((((typeof(val))1)<<(count)) - 1) ) )
-
-/*
- * Debugging version, evaluates args twice.
- */
-#define GP_GET_BITS_DBG(offset, count, val) - ( printf("GET_BITS(%d, %d, 0x%x)=%d", offset, count, val, - GP_GET_BITS(offset, count, val)), GP_GET_BITS(offset, count, val))
-
-/*
- * Set count bits of dest at ofset to val (shifted by offset)
- *
- * Does not check val for overflow
- * Operates on 8, 16, and 32 bit values, depending on the type of dest,
- * this should be unsigned
- *
- * GP_SET_BITS_OR anly sets (|=) the bits, assuming these are clear beforehand
- * GP_CLEAR_BITS sets the target bits to zero
- * GP_SET_BITS does both
- */
-#define GP_CLEAR_BITS(offset, count, dest) - ( (dest) &= ~(((((typeof(dest))1) << (count)) - 1) << (offset)) )
-
-#define GP_SET_BITS_OR(offset, dest, val) ( (dest) |= ((val)<<(offset)) )
-
-#define GP_SET_BITS(offset, count, dest, val) do { - GP_CLEAR_BITS(offset, count, dest); - GP_SET_BITS_OR(offset, dest, val); -} while (0)
-
-/*
- * Debugging version, evaluates args twice.
- */
-#define GP_SET_BITS_DBG(offset, count, dest, val) do { - GP_SET_BITS(offset, count, dest, val); - printf("SET_BITS(%d, %d, p, %d)n", offset, count, val); -} while (0)
-
/* Determines the sign of the integer value; it is +1 if value is positive,
* -1 if negative, and 0 if it is zero.
diff --git a/include/core/GP_Convert.gen.h.t b/include/core/GP_Convert.gen.h.t
index 56759ee..760eb74 100644
--- a/include/core/GP_Convert.gen.h.t
+++ b/include/core/GP_Convert.gen.h.t
@@ -45,7 +45,7 @@
%% block body
-#include "GP_Common.h"
+#include "GP_GetSetBits.h"
#include "GP_Context.h"
#include "GP_Pixel.h"
diff --git a/include/core/GP_GetPutPixel.gen.h.t b/include/core/GP_GetPutPixel.gen.h.t
index ee1ea90..2a8529b 100644
--- a/include/core/GP_GetPutPixel.gen.h.t
+++ b/include/core/GP_GetPutPixel.gen.h.t
@@ -7,7 +7,49 @@ Do not include directly, use GP_Pixel.h
%% block body
-#include "GP_Common.h"
+
+ /*
+
+ Note about byte aligment
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Unaligned acces happens when instruction that works with multiple byte value
+ gets an address that is not divideable by the size of the value. Eg. if 32
+ bit integer instruction gets an address that is not a multiple of 4. On
+ intel cpus this type of acces works and is supported however the C standard
+ defines this as undefined behavior. This fails to work ARM and most of the
+ non intel cpus. So some more trickery must be done in order to write
+ unaligned multibyte values. First of all we must compute offset and number of
+ bytes to be accessed (which is cruicial for speed as we are going to read the
+ pixel value byte by byte.
+
+ The offsets (starting with the first one eg. pixel_size mod 8) forms subgroup
+ in the mod 8 cyclic group. The maximal count of bits, from the start of the
+ byte, then will be max from this subgroup + pixel_size. If this number is
+ less or equal to 8 * N, we could write such pixel by writing N bytes.
+
+ For example the offsets of 16 BPP forms subgroup only with {0} so we only
+ need 2 bytes to write it. As a matter of fact the 16 and 32 BPP are special
+ cases that are always aligned and together with the 8 BPP (which is aligned
+ trivially). These three are coded as special cases which yields to faster
+ operations in case of 16 and 32 BPP. The 24 BPP is not aligned as there are
+ no instruction to operate 3 byte long numbers.
+
+ For second example take offsets of 20 BPP that forms subgroup {4, 0}
+ so the max + pixel_size = 24 and indeed we fit into 3 bytes.
+
+ If pixel_size is coprime to 8, the offsets generates whole group and so
+ the max + pixel_size = 7 + pixel_size. The 17 BPP fits into 24 bits and
+ so also 3 bytes are needed. The 19 BPP fits into 26 bits and because of
+ that 4 bytes are needed.
+
+ Once we figure maximal number of bytes and the offset all that is to be done
+ is to fetch first and last byte to combine it together with given pixel value
+ and write the result back to the bitmap.
+
+ */
+
+#include "GP_GetSetBits.h"
#include "GP_Context.h"
%% for ps in pixelsizes
@@ -44,12 +86,73 @@ Do not include directly, use GP_Pixel.h
*/
static inline GP_Pixel GP_GetPixel_Raw_{{ ps.suffix }}(const GP_Context *c, int x, int y)
{
-{# Special case to prevent some of the "overflow" warnings -#}
-%% if ps.size == config.pixel_size
- return *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y));
+%% if ps.size == 32
+ /*
+ * 32 BPP is expected to have aligned pixels
+ */
+ return *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
+%% elif ps.size == 16
+ /*
+ * 16 BPP is expected to have aligned pixels
+ */
+ return *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
+%% elif ps.size == 8
+ /*
+ * 8 BPP is byte aligned
+ */
+ return *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
+%% elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8
+ /*
+ * Whole pixel is stored only and only in one byte
+ *
+ * The full list = {1, 2, 4, 8}
+ */
+ return GP_GET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
+%% elif ps.size <= 10 or ps.size == 12 or ps.size == 16
+ /*
+ * The pixel is stored in one or two bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 16
+ *
+ * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ return GP_GET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
+%% elif ps.size <= 18 or ps.size == 20 or ps.size == 24
+ /*
+ * The pixel is stored in two or three bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 24
+ *
+ * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ return GP_GET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
+%% elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32
+ /*
+ * The pixel is stored in three or four bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 32
+ *
+ * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ return GP_GET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
%% else
- return GP_GET_BITS(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
- *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y)));
+ #error not implemented
%% endif
}
@@ -58,12 +161,73 @@ static inline GP_Pixel GP_GetPixel_Raw_{{ ps.suffix }}(const GP_Context *c, int
*/
static inline void GP_PutPixel_Raw_{{ ps.suffix }}(GP_Context *c, int x, int y, GP_Pixel p)
{
-{# Special case to prevent some of the "overflow" warnings -#}
-%% if ps.size == config.pixel_size
- *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y)) = p;
+%% if ps.size == 32
+ /*
+ * 32 BPP is expected to have aligned pixels
+ */
+ *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
+%% elif ps.size == 16
+ /*
+ * 16 BPP is expected to have aligned pixels
+ */
+ *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
+%% elif ps.size == 8
+ /*
+ * 8 BPP is byte aligned
+ */
+ *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
+%% elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8
+ /*
+ * Whole pixel is stored only and only in one byte
+ *
+ * The full list = {1, 2, 4, 8}
+ */
+ GP_SET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
+%% elif ps.size <= 10 or ps.size == 12 or ps.size == 16
+ /*
+ * The pixel is stored in one or two bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 16
+ *
+ * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ GP_SET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
+%% elif ps.size <= 18 or ps.size == 20 or ps.size == 24
+ /*
+ * The pixel is stored in two or three bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 24
+ *
+ * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ GP_SET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
+%% elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32
+ /*
+ * The pixel is stored in three or four bytes
+ *
+ * The max from subgroup (of mod 8 factor group) generated by
+ * pixel_size mod 8 + pixel_size <= 32
+ *
+ * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
+ *
+ * Hint: If the pixel size is coprime to 8 the group is generated by
+ * pixel_size mod 8 and maximal size thus is pixel_size + 7
+ */
+ GP_SET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
+ GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
%% else
- GP_SET_BITS(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
- *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y)), p);
+ #error not implemented
%% endif
}
diff --git a/include/core/GP_GetSetBits.h b/include/core/GP_GetSetBits.h
new file mode 100644
index 0000000..bd55fe2
--- /dev/null
+++ b/include/core/GP_GetSetBits.h
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim 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 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim 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 gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2011 Tomas Gavenciak <gavento(a)ucw.cz> *
+ * Copyright (C) 2011 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ The macros are taking generally three arguments
+
+ */
+
+#ifndef GP_GET_SET_BITS_H
+#define GP_GET_SET_BITS_H
+
+/*
+ * Helper macros to read/write parts of words
+ *
+ * Return (shifted) count bits at offset of value
+ * Note: operates with value types same as val
+ */
+#define GP_GET_BITS(offset, len, val) + ( ( (val)>>(offset) ) & ( ((((typeof(val))1)<<(len)) - 1) ) )
+
+/*
+ * Align-safe getbits
+ *
+ * TODO: Fix big endian
+ */
+#define GP_GET_BITS4_ALIGNED(offset, len, val) ({ + uint32_t v; + v = ((uint8_t *)&val)[0]; + v |= ((uint8_t *)&val)[1]<<8; + v |= ((uint8_t *)&val)[2]<<16; + v |= ((uint8_t *)&val)[3]<<24; + + GP_GET_BITS(offset, len, v); +})
+
+#define GP_GET_BITS3_ALIGNED(offset, len, val) ({ + uint32_t v; + v = ((uint8_t *)&val)[0]; + v |= ((uint8_t *)&val)[1]<<8; + v |= ((uint8_t *)&val)[2]<<16; + + GP_GET_BITS(offset, len, v); +})
+
+#define GP_GET_BITS2_ALIGNED(offset, len, val) ({ + uint16_t v; + v = ((uint8_t *)&val)[0]; + v |= ((uint8_t *)&val)[1]<<8; + + GP_GET_BITS(offset, len, v); +})
+
+#define GP_GET_BITS1_ALIGNED(offset, len, val) ({ + uint8_t v; + v = ((uint8_t *)&val)[0]; + + GP_GET_BITS(offset, len, v); +})
+
+/*
+ * Set count bits of dest at ofset to val (shifted by offset)
+ *
+ * Does not check val for overflow
+ * Operates on 8, 16, and 32 bit values, depending on the type of dest,
+ * this should be unsigned
+ *
+ * GP_SET_BITS_OR anly sets (|=) the bits, assuming these are clear beforehand
+ * GP_CLEAR_BITS sets the target bits to zero
+ * GP_SET_BITS does both
+ */
+#define GP_CLEAR_BITS(offset, len, dest) + ( (dest) &= ~(((((typeof(dest))1) << (len)) - 1) << (offset)) )
+
+#define GP_SET_BITS_OR(offset, dest, val) ( (dest) |= ((val)<<(offset)) )
+
+#define GP_SET_BITS(offset, len, dest, val) do { + GP_CLEAR_BITS(offset, len, dest); + GP_SET_BITS_OR(offset, dest, val); +} while (0)
+
+/*
+ * Align-safe setbits
+ */
+#define GP_SET_BITS1_ALIGNED(offset, len, dest, val) do { + uint8_t v = ((uint8_t *)dest)[0]; + GP_SET_BITS(offset, len, v, val); + ((uint8_t *)dest)[0] = v; +} while (0)
+
+#define GP_SET_BITS2_ALIGNED(offset, len, dest, val) do { + uint16_t v; + v = ((uint8_t *)dest)[0]; + v |= ((uint8_t *)dest)[1]<<8; + + GP_SET_BITS(offset, len, v, val); + + ((uint8_t *)dest)[0] = 0xff & v; + ((uint8_t *)dest)[1] = 0xff & (v >> 8); +} while (0)
+
+#define GP_SET_BITS3_ALIGNED(offset, len, dest, val) do { + uint32_t v; + v = ((uint8_t *)dest)[0]; + v |= ((uint8_t *)dest)[2]<<16; + + GP_SET_BITS(offset, len, v, val); + + ((uint8_t *)dest)[0] = 0xff & v; + ((uint8_t *)dest)[1] = 0xff & (v >> 8); + ((uint8_t *)dest)[2] = 0xff & (v >> 16); +} while (0)
+
+#define GP_SET_BITS4_ALIGNED(offset, len, dest, val) do { + uint32_t v; + v = ((uint8_t *)dest)[0]; + v |= ((uint8_t *)dest)[3]<<24; + + GP_SET_BITS(offset, len, v, val); + + ((uint8_t *)dest)[0] = 0xff & v; + ((uint8_t *)dest)[1] = 0xff & (v >> 8); + ((uint8_t *)dest)[2] = 0xff & (v >> 16); + ((uint8_t *)dest)[3] = 0xff & (v >> 24); +} while (0)
+
+
+#endif /* GP_GET_SET_BITS_H */
diff --git a/libs/core/GP_Pixel.gen.c.t b/libs/core/GP_Pixel.gen.c.t
index e0cf7c0..f41625b 100644
--- a/libs/core/GP_Pixel.gen.c.t
+++ b/libs/core/GP_Pixel.gen.c.t
@@ -8,6 +8,7 @@ Do not include directly, use GP_Pixel.h
%% block body
#include <stdio.h>
#include "GP_Pixel.h"
+#include "GP_GetSetBits.h"
/*
* Description of all known pixel types
@@ -29,6 +30,8 @@ const GP_PixelTypeDescription const GP_PixelTypes [] = {
%% endfor
};
+#warning FIXME: do generic get set bit for pixel printing
+
%% for pt in pixeltypes
%% if not pt.is_unknown()
/*
diff --git a/tests/SDL/shapetest.c b/tests/SDL/shapetest.c
index 57cca2d..3c61629 100644
--- a/tests/SDL/shapetest.c
+++ b/tests/SDL/shapetest.c
@@ -485,6 +485,8 @@ int main(int argc, char ** argv)
}
}
+ GP_SetDebugLevel(10);
+
/* Initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
fprintf(stderr, "Could not initialize SDL: %sn", SDL_GetError());
http://repo.or.cz/w/gfxprim.git/commit/4d19114d20f531cd49c79158af4263ea4af9…
commit 4d19114d20f531cd49c79158af4263ea4af98109
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Oct 6 18:15:08 2011 +0200
Remove the compression from the 'make tar' target.
The compression of .git repository data is too slow
and takes several minutes, which is bad, when you are
about to leave the train, but the data needs to be
backed up.
diff --git a/Makefile b/Makefile
index 5c4d45f..acc8543 100644
--- a/Makefile
+++ b/Makefile
@@ -35,4 +35,4 @@ endif
tar:
$(MAKE) clean
- cd .. && tar cjf gfxprim-`date +%Y-%b-%d-%HH%MM`.tar.bz2 gfxprim
+ cd .. && tar cf gfxprim-`date +%Y-%b-%d-%HH%MM`.tar gfxprim
-----------------------------------------------------------------------
Summary of changes:
Makefile | 2 +-
include/core/GP_Common.h | 45 ---------
include/core/GP_Convert.gen.h.t | 2 +-
include/core/GP_GetPutPixel.gen.h.t | 186 ++++++++++++++++++++++++++++++++--
include/core/GP_GetSetBits.h | 148 ++++++++++++++++++++++++++++
libs/core/GP_Pixel.gen.c.t | 3 +
tests/SDL/shapetest.c | 2 +
7 files changed, 330 insertions(+), 58 deletions(-)
create mode 100644 include/core/GP_GetSetBits.h
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, generate has been updated
via d291a122c53ce9d70a5777b380ae9ca82978987b (commit)
via 2754045bba9b30539121e3a860de208463511fe3 (commit)
via a26979d8c8abdbf13131422e59e055e4abf39918 (commit)
via 871fb9ebb0895f698f22e2ad4cbe983e78d5c194 (commit)
from b51b045c4d615a275513234d727bb99d90ecfa80 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/d291a122c53ce9d70a5777b380ae9ca82978…
commit d291a122c53ce9d70a5777b380ae9ca82978987b
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Oct 4 20:14:27 2011 +0200
Make grinder parameter parsing little more robust.
diff --git a/demos/grinder/grinder.c b/demos/grinder/grinder.c
index a0e8f2c..26d6d0d 100644
--- a/demos/grinder/grinder.c
+++ b/demos/grinder/grinder.c
@@ -428,11 +428,11 @@ static const char *app_help = {
" n"
" <<<<<<<<<< Bitmap Grinder >>>>>>>>>>> n"
" n"
- " +-+-----+ n"
- " / | +-+| .11. n"
+ " +~+-----+ n"
+ " /| | +-+| .11. n"
" +-{ D| |010101011. n"
- " | \ | +-.0100101. n"
- " O=+ +-+-----+ .10110101. n"
+ " | \| | +-.0100101. n"
+ " O=+ +~+-----+ .10110101. n"
" .010101. n"
" .1. n"
" n"
@@ -481,7 +481,16 @@ int main(int argc, char *argv[])
return 0;
break;
case 'v':
- GP_SetDebugLevel(atoi(optarg));
+ i = atoi(optarg);
+
+ if (i == 0) {
+ fprintf(stderr, "ERROR: invalid debug level "
+ "'%s', expected number > 0n",
+ optarg);
+ return 1;
+ }
+
+ GP_SetDebugLevel(i);
break;
case 'f':
add_filter(optarg);
@@ -496,8 +505,7 @@ int main(int argc, char *argv[])
}
if (optind >= argc) {
- fprintf(stderr, "Expected bitmap filenamesn");
- print_help();
+ fprintf(stderr, "ERROR: Expected bitmap filenamesn");
return 1;
}
http://repo.or.cz/w/gfxprim.git/commit/2754045bba9b30539121e3a860de20846351…
commit 2754045bba9b30539121e3a860de208463511fe3
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Oct 4 20:09:24 2011 +0200
Fixed error value from GP_LoadImage.
Fixed error value from GP_LoadImage
in case file doesn't exist/user has
no permisssion to read it.
diff --git a/libs/loaders/GP_Loaders.c b/libs/loaders/GP_Loaders.c
index 72e2a31..63f1da5 100644
--- a/libs/loaders/GP_Loaders.c
+++ b/libs/loaders/GP_Loaders.c
@@ -27,6 +27,10 @@
*/
#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <GP_Debug.h>
#include "GP_Loaders.h"
@@ -35,6 +39,12 @@ GP_RetCode GP_LoadImage(const char *src_path, GP_Context **res)
int len = strlen(src_path);
GP_RetCode ret = GP_ENOIMPL;
+ if (access(src_path, R_OK)) {
+ GP_DEBUG(1, "Failed to access file '%s' : %s",
+ src_path, strerror(errno));
+ return GP_EBADFILE;
+ }
+
switch (src_path[len - 1]) {
/* PNG, JPG, JPEG */
case 'g':
http://repo.or.cz/w/gfxprim.git/commit/a26979d8c8abdbf13131422e59e055e4abf3…
commit a26979d8c8abdbf13131422e59e055e4abf39918
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Oct 4 19:48:39 2011 +0200
Added some more info to grinder README.
diff --git a/demos/grinder/README b/demos/grinder/README
index 749485f..ad2c2e7 100644
--- a/demos/grinder/README
+++ b/demos/grinder/README
@@ -10,3 +10,35 @@ grinder -f filter_name:filter_params... -f filter_name:filter_params... -f filte
Which will apply pipeline of filters to each image and store results to out_X.ppm
see grinder -h for list of filters and options
+
+
+COOL EFECTS
+~~~~~~~~~~~
+
+Pixelize yourself
+-----------------
+
+This filter creates pixelated image of the input (for example photograph of your head).
+
+grinder -p -f resize:ratio=0.2 -f blur:sigma=4 -f resize:ratio=0.1 -f resize:alg=nn:ratio=4 head.png
+
+And now, what it does:
+
+* The first resize just resizes down the image as the images that gets out a
+ digital camera are usually too big and too noisy. This only prepares the
+ image so it has reasonable size. Ideally there should be a low-pass filter
+ (eg. gaussian blur) before each downscaling but as we are scaling the image
+ further, we don't care now.
+
+* The blur does low-pass filter (cuts off all high frequencies). If you are not
+ familiar with digital signal processing, think of this just as smoothing the
+ image after the interpolation (which works only on a few neighbour pixels so
+ on downscaling some of the pixels may not be used for the interpolation at
+ all).
+
+* The second resize resizes the image to be really small (and the result is
+ quite good looking as we used low-pass filter beforhand).
+
+* The last resize scales the image up, but this time we used nearest neighbour
+ interpolation, which just picks up one pixel which is nearest to the
+ interpolated value. This actually creates the 'pixel' effect.
http://repo.or.cz/w/gfxprim.git/commit/871fb9ebb0895f698f22e2ad4cbe983e78d5…
commit 871fb9ebb0895f698f22e2ad4cbe983e78d5c194
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Oct 4 19:45:57 2011 +0200
Optimized convolution, made it non static.
* Optimized convolution for separable filters
- that leads to 10-30% faster gaussian blur
* Made the convolution declarations public
diff --git a/include/filters/GP_Linear.h b/include/filters/GP_Linear.h
index ae0debd..3194cb8 100644
--- a/include/filters/GP_Linear.h
+++ b/include/filters/GP_Linear.h
@@ -36,7 +36,10 @@
*
* The sigma parameters defines the blur radii in horizontal and vertical
* direction.
- *
+ *
+ * Internaly this is implemented as separable linear filter (calls vertical and
+ * horizontal convolution with generated gaussian kernel).
+ *
* This variant could work in-place so it's perectly okay to call
*
* GP_FilterGaussianBlur_Raw(context, context, ...);
@@ -49,4 +52,41 @@ GP_Context *GP_FilterGaussianBlur(GP_Context *src,
GP_ProgressCallback *callback,
float sigma_x, float sigma_y);
+/*
+ * Linear convolution.
+ *
+ * The kernel is array of kw * kh floats and is indexed as two directional array.
+ *
+ * To define 3x3 average filter
+ *
+ * kernel[] = {
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * };
+ *
+ * kw = kh = 3
+ *
+ * This function works also in-place.
+ */
+void GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kw, uint32_t kh);
+
+/*
+ * Special cases for convolution only in horizontal/vertical direction.
+ *
+ * These are about 10-30% faster than the generic implementation (depending on
+ * the kernel size, bigger kernel == more savings).
+ *
+ * Both works also in-place.
+ */
+void GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kw);
+
+void GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kh);
+
#endif /* GP_LINEAR_H */
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index 48dc0ee..8f7c2a3 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -29,10 +29,6 @@
#include <GP_Linear.h>
-static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *res,
- GP_ProgressCallback *callback,
- float kernel[], uint32_t kw, uint32_t kh);
-
static inline unsigned int gaussian_kernel_size(float sigma)
{
int center = 3 * sigma;
@@ -83,21 +79,25 @@ void GP_FilterGaussianBlur_Raw(GP_Context *src, GP_Context *res,
if (callback != NULL)
new_callback = &gaussian_callback;
- /* compute kernel and apply on horizontal direction */
+ /* compute kernel and apply in horizontal direction */
if (sigma_x > 0) {
float kernel_x[size_x];
gaussian_kernel_init(sigma_x, kernel_x);
- GP_FilterLinearConvolution(src, res, new_callback, kernel_x, size_x, 1);
+
+ GP_FilterHLinearConvolution_Raw(src, res, new_callback,
+ kernel_x, size_x);
}
if (new_callback != NULL)
new_callback->callback = gaussian_callback_2;
- /* compute kernel and apply on vertical direction */
+ /* compute kernel and apply in vertical direction */
if (sigma_y > 0) {
float kernel_y[size_y];
gaussian_kernel_init(sigma_y, kernel_y);
- GP_FilterLinearConvolution(res, res, new_callback, kernel_y, 1, size_y);
+
+ GP_FilterVLinearConvolution_Raw(res, res, new_callback,
+ kernel_y, size_y);
}
GP_ProgressCallbackDone(callback);
@@ -124,9 +124,220 @@ GP_Context *GP_FilterGaussianBlur(GP_Context *src,
return res;
}
-static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *res,
- GP_ProgressCallback *callback,
- float kernel[], uint32_t kw, uint32_t kh)
+void GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kw)
+{
+ float kernel_sum = 0;
+ GP_Coord x, y;
+ uint32_t i;
+
+ GP_DEBUG(1, "Horizontal linear convolution kernel width %i image %ux%u",
+ kw, src->w, src->h);
+
+ /* count kernel sum for normalization */
+ for (i = 0; i < kw; i++)
+ kernel_sum += kernel[i];
+
+ /* do linear convolution */
+ for (y = 0; y < (GP_Coord)res->h; y++) {
+ GP_Pixel pix;
+ uint32_t R[kw], G[kw], B[kw];
+
+ /* prefill the buffer on the start */
+ for (i = 0; i < kw - 1; i++) {
+ int cx = i - kw/2;
+
+ if (cx < 0)
+ cx = 0;
+
+ pix = GP_GetPixel_Raw_24BPP(src, cx, y);
+
+ R[i] = GP_Pixel_GET_R_RGB888(pix);
+ G[i] = GP_Pixel_GET_G_RGB888(pix);
+ B[i] = GP_Pixel_GET_B_RGB888(pix);
+ }
+
+ int idx = kw - 1;
+
+ for (x = 0; x < (GP_Coord)res->w; x++) {
+ float r = 0, g = 0, b = 0;
+
+ int cx = x + kw/2;
+
+ if (cx >= (int)src->w)
+ cx = src->w - 1;
+
+ pix = GP_GetPixel_Raw_24BPP(src, cx, y);
+
+ R[idx] = GP_Pixel_GET_R_RGB888(pix);
+ G[idx] = GP_Pixel_GET_G_RGB888(pix);
+ B[idx] = GP_Pixel_GET_B_RGB888(pix);
+
+ /* count the pixel value from neighbours weighted by kernel */
+ for (i = 0; i < kw; i++) {
+ int k;
+
+ if ((int)i < idx + 1)
+ k = kw - idx - 1 + i;
+ else
+ k = i - idx - 1;
+
+ r += R[i] * kernel[k];
+ g += G[i] * kernel[k];
+ b += B[i] * kernel[k];
+ }
+
+ /* normalize the result */
+ r /= kernel_sum;
+ g /= kernel_sum;
+ b /= kernel_sum;
+
+ /* and clamp just to be extra sure */
+ if (r > 255)
+ r = 255;
+ if (r < 0)
+ r = 0;
+ if (g > 255)
+ g = 255;
+ if (g < 0)
+ g = 0;
+ if (b > 255)
+ b = 255;
+ if (b < 0)
+ b = 0;
+
+ pix = GP_Pixel_CREATE_RGB888((uint32_t)r, (uint32_t)g, (uint32_t)b);
+
+ GP_PutPixel_Raw_24BPP(res, x, y, pix);
+
+ idx++;
+
+ if (idx >= (int)kw)
+ idx = 0;
+ }
+
+ if (callback != NULL && y % 100 == 0)
+ GP_ProgressCallbackReport(callback, 100.00 * y/res->h);
+ }
+
+ GP_ProgressCallbackDone(callback);
+}
+
+/*
+ * Special case for vertical only kernel (10-30% faster).
+ *
+ * Can be used in-place.
+ */
+void GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kh)
+{
+ float kernel_sum = 0;
+ GP_Coord x, y;
+ uint32_t i;
+
+ GP_DEBUG(1, "Vertical linear convolution kernel width %i image %ux%u",
+ kh, src->w, src->h);
+
+ /* count kernel sum for normalization */
+ for (i = 0; i < kh; i++)
+ kernel_sum += kernel[i];
+
+ /* do linear convolution */
+ for (x = 0; x < (GP_Coord)res->w; x++) {
+ GP_Pixel pix;
+ uint32_t R[kh], G[kh], B[kh];
+
+ /* prefill the buffer on the start */
+ for (i = 0; i < kh - 1; i++) {
+ int cy = i - kh/2;
+
+ if (cy < 0)
+ cy = 0;
+
+ pix = GP_GetPixel_Raw_24BPP(src, x, cy);
+
+ R[i] = GP_Pixel_GET_R_RGB888(pix);
+ G[i] = GP_Pixel_GET_G_RGB888(pix);
+ B[i] = GP_Pixel_GET_B_RGB888(pix);
+ }
+
+ int idx = kh - 1;
+
+ for (y = 0; y < (GP_Coord)res->h; y++) {
+ float r = 0, g = 0, b = 0;
+
+ int cy = y + kh/2;
+
+ if (cy >= (int)src->h)
+ cy = src->h - 1;
+
+ pix = GP_GetPixel_Raw_24BPP(src, x, cy);
+
+ R[idx] = GP_Pixel_GET_R_RGB888(pix);
+ G[idx] = GP_Pixel_GET_G_RGB888(pix);
+ B[idx] = GP_Pixel_GET_B_RGB888(pix);
+
+ /* count the pixel value from neighbours weighted by kernel */
+ for (i = 0; i < kh; i++) {
+ int k;
+
+ if ((int)i < idx + 1)
+ k = kh - idx - 1 + i;
+ else
+ k = i - idx - 1;
+
+ r += R[i] * kernel[k];
+ g += G[i] * kernel[k];
+ b += B[i] * kernel[k];
+ }
+
+ /* normalize the result */
+ r /= kernel_sum;
+ g /= kernel_sum;
+ b /= kernel_sum;
+
+ /* and clamp just to be extra sure */
+ if (r > 255)
+ r = 255;
+ if (r < 0)
+ r = 0;
+ if (g > 255)
+ g = 255;
+ if (g < 0)
+ g = 0;
+ if (b > 255)
+ b = 255;
+ if (b < 0)
+ b = 0;
+
+ pix = GP_Pixel_CREATE_RGB888((uint32_t)r, (uint32_t)g, (uint32_t)b);
+
+ GP_PutPixel_Raw_24BPP(res, x, y, pix);
+
+ idx++;
+
+ if (idx >= (int)kh)
+ idx = 0;
+ }
+
+ if (callback != NULL && x % 100 == 0)
+ GP_ProgressCallbackReport(callback, 100.00 * x/res->w);
+ }
+
+ GP_ProgressCallbackDone(callback);
+}
+
+
+/*
+ * Linear convolution.
+ *
+ * Can be used in-place.
+ */
+void GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *res,
+ GP_ProgressCallback *callback,
+ float kernel[], uint32_t kw, uint32_t kh)
{
float kernel_sum = 0;
GP_Coord x, y;
@@ -216,10 +427,16 @@ static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *res,
/* and clamp just to be extra sure */
if (r > 255)
r = 255;
+ if (r < 0)
+ r = 0;
if (g > 255)
g = 255;
+ if (g < 0)
+ g = 0;
if (b > 255)
b = 255;
+ if (b < 0)
+ b = 0;
pix = GP_Pixel_CREATE_RGB888((uint32_t)r, (uint32_t)g, (uint32_t)b);
-----------------------------------------------------------------------
Summary of changes:
demos/grinder/README | 32 ++++++
demos/grinder/grinder.c | 22 +++--
include/filters/GP_Linear.h | 42 ++++++++-
libs/filters/GP_Linear.c | 239 +++++++++++++++++++++++++++++++++++++++++--
libs/loaders/GP_Loaders.c | 10 ++
5 files changed, 326 insertions(+), 19 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, generate has been updated
via bc1b6594de0de8e6f717e824e3ded14e95b95870 (commit)
from 108607fa657f1e25d17ee497bfc1b840f5e9ac0c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/bc1b6594de0de8e6f717e824e3ded14e95b9…
commit bc1b6594de0de8e6f717e824e3ded14e95b95870
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Oct 2 17:46:59 2011 +0200
Some small fixes for grinder.
diff --git a/demos/grinder/grinder.c b/demos/grinder/grinder.c
index 8da1833..a2f6d4d 100644
--- a/demos/grinder/grinder.c
+++ b/demos/grinder/grinder.c
@@ -164,11 +164,17 @@ static GP_RetCode scale(GP_Context **c, const char *params)
&alg, &w, &h))
return GP_EINVAL;
- if (w == -1 || h == -1) {
+ if (w == -1 && h == -1) {
print_error("scale: w and/or h missing");
return GP_EINVAL;
}
+ if (w == -1)
+ w = (*c)->w * (1.00 * h/(*c)->h) + 0.5;
+
+ if (h == -1)
+ h = (*c)->h * (1.00 * w/(*c)->w) + 0.5;
+
GP_Context *res = NULL;
res = GP_FilterResize(*c, progress_callback, alg, w, h);
@@ -304,15 +310,8 @@ static GP_RetCode blur(GP_Context **c, const char *params)
return GP_EINVAL;
}
- GP_Context *res = NULL;
+ GP_FilterGaussianBlur_Raw(*c, *c, progress_callback, sigma, sigma);
- res = GP_FilterGaussianBlur(*c, progress_callback, sigma, sigma);
-
- if (res == NULL)
- return GP_EINVAL;
-
- GP_ContextFree(*c);
- *c = res;
return GP_ESUCCESS;
}
-----------------------------------------------------------------------
Summary of changes:
demos/grinder/grinder.c | 17 ++++++++---------
1 files changed, 8 insertions(+), 9 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, generate has been updated
via 4c68110cd82c373fe1d0c19ca01362edb452a0ad (commit)
from 96956ac4fbd2c35d57c122ecd44a88c352153a5e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/4c68110cd82c373fe1d0c19ca01362edb452…
commit 4c68110cd82c373fe1d0c19ca01362edb452a0ad
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Oct 1 15:48:36 2011 +0200
Fix linear convolution corner cases at the corners.
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index bf41660..764d6b6 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -101,7 +101,7 @@ static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *dst,
if (cy >= (int)src->h)
cy = src->h - 1;
-
+
pix = GP_GetPixel_Raw_24BPP(src, cx, cy);
R[i][j] = GP_Pixel_GET_R_RGB888(pix);
@@ -117,14 +117,18 @@ static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *dst,
for (j = 0; j < kh; j++) {
int cy = y + j - kh/2;
-
+ int cx = x + kw/2;
+
if (cy < 0)
cy = 0;
-
+
if (cy >= (int)src->h)
cy = src->h - 1;
- pix = GP_GetPixel_Raw_24BPP(src, x, cy);
+ if (cx >= (int)src->w)
+ cx = src->w - 1;
+
+ pix = GP_GetPixel_Raw_24BPP(src, cx, cy);
R[idx][j] = GP_Pixel_GET_R_RGB888(pix);
G[idx][j] = GP_Pixel_GET_G_RGB888(pix);
@@ -133,10 +137,12 @@ static void GP_FilterLinearConvolution(const GP_Context *src, GP_Context *dst,
/* count the pixel value from neighbours weighted by kernel */
for (i = 0; i < kw; i++) {
- int k = i - idx;
-
- if (k < 0)
- k += kw;
+ int k;
+
+ if ((int)i < idx + 1)
+ k = kw - idx - 1 + i;
+ else
+ k = i - idx - 1;
for (j = 0; j < kh; j++) {
r += R[i][j] * kernel[k + j * kw];
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_Linear.c | 22 ++++++++++++++--------
1 files changed, 14 insertions(+), 8 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")