app/tile.c app/tile.h app/tile_manager.c app/tile_pvt.h

Sun May  9 16:23:47 BST 1999  Adam D. Moss  <adam@gimp.org>

	* app/tile.c
	* app/tile.h
	* app/tile_manager.c
	* app/tile_pvt.h
	* app/paint_funcs.c:

	Added Tile Row Hinting to the GIMP tile structure.  Tiles
	now have cheap per-row hints indicating whether each row is
	all-transparent, all-opaque, a mixture, or other properties.

	These hints are automatically invalidated when the tile is checked
	in as dirty, and are re-evaluated on demand.

	Currently only the layer compositing routines take advantage
	of these hints, though there is opportunity to use them to
	advantage in numerous other places.

	The whole layer compositing process is typically 2x-4x faster
	now, especially on subsequent renders of data which has already
	had its hints calculated.

	See tile.h for the explicit TileRowHint query/set interface.
	The procedure to re-evaluate tile hints currently resides in
	paint_funcs.c but may be exposed to other parts of the core
	if necessary.

	This is experimental.  Please report mis-rendering problems.
This commit is contained in:
BST 1999 Adam D. Moss 1999-05-09 15:45:37 +00:00 committed by Adam D. Moss
parent def83c2941
commit 928dd48af7
11 changed files with 928 additions and 274 deletions

View File

@ -1,3 +1,33 @@
Sun May 9 16:23:47 BST 1999 Adam D. Moss <adam@gimp.org>
* app/tile.c
* app/tile.h
* app/tile_manager.c
* app/tile_pvt.h
* app/paint_funcs.c:
Added Tile Row Hinting to the GIMP tile structure. Tiles
now have cheap per-row hints indicating whether each row is
all-transparent, all-opaque, a mixture, or other properties.
These hints are automatically invalidated when the tile is checked
in as dirty, and are re-evaluated on demand.
Currently only the layer compositing routines take advantage
of these hints, though there is opportunity to use them to
advantage in numerous other places.
The whole layer compositing process is typically 2x-4x faster
now, especially on subsequent renders of data which has already
had its hints calculated.
See tile.h for the explicit TileRowHint query/set interface.
The procedure to re-evaluate tile hints currently resides in
paint_funcs.c but may be exposed to other parts of the core
if necessary.
This is experimental. Please report mis-rendering problems.
Sat May 8 22:38:03 MEST 1999 Sven Neumann <sven@gimp.org>
* gimp1_1_splash.ppm: new splash_screen ...

View File

@ -173,18 +173,25 @@ tile_manager_get (TileManager *tm,
newtile->ewidth = (*tile_ptr)->ewidth;
newtile->eheight = (*tile_ptr)->eheight;
newtile->valid = (*tile_ptr)->valid;
newtile->data = g_new (guchar, tile_size (newtile));
i = newtile->eheight;
while (i--)
{
newtile->rowhint[i] = (*tile_ptr)->rowhint[i];
}
if ((*tile_ptr)->data != NULL)
{
newtile->data = g_new (guchar, tile_size (newtile));
memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
}
else
{
tile_lock (*tile_ptr);
newtile->data = g_new (guchar, tile_size (newtile));
memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
tile_release (*tile_ptr, FALSE);
}
tile_detach (*tile_ptr, tm, tile_num);
TILE_MUTEX_LOCK (newtile);
tile_attach (newtile, tm, tile_num);

View File

@ -10,6 +10,7 @@
#include <glib.h>
#include "config.h"
#include "tile.h"
typedef struct _TileLink TileLink;
@ -39,6 +40,9 @@ struct _Tile
guint dirty : 1; /* is the tile dirty? has it been modified? */
guint valid : 1; /* is the tile valid? */
/* An array of hints for rendering purposes */
TileRowHint rowhint[TILE_HEIGHT];
guchar *data; /* the data for the tile. this may be NULL in which
* case the tile data is on disk.
*/

View File

@ -13,10 +13,43 @@ static void tile_destroy (Tile *tile);
int tile_count = 0;
TileRowHint
tile_get_rowhint (Tile *tile, int yoff)
{
#ifdef HINTS_SANITY
if (yoff < tile_eheight(tile) && yoff>=0)
{
return tile->rowhint[yoff];
}
else
g_error("GET_ROWHINT OUT OF RANGE");
/* return TILEROWHINT_OUTOFRANGE; */
#else
return tile->rowhint[yoff];
#endif
}
void
tile_set_rowhint (Tile *tile, int yoff, TileRowHint rowhint)
{
#ifdef HINTS_SANITY
if (yoff < tile_eheight(tile) && yoff>=0)
{
tile->rowhint[yoff] = rowhint;
}
else
g_error("SET_ROWHINT OUT OF RANGE");
#else
tile->rowhint[yoff] = rowhint;
#endif
}
void
tile_init (Tile *tile,
int bpp)
{
int y;
tile->ref_count = 0;
tile->write_count = 0;
tile->share_count = 0;
@ -31,6 +64,12 @@ tile_init (Tile *tile,
tile->tlink = NULL;
tile->next = tile->prev = NULL;
tile->listhead = NULL;
for (y=0; y<TILE_HEIGHT; y++)
{
tile->rowhint[y] = TILEROWHINT_UNKNOWN;
}
#ifdef USE_PTHREADS
{
pthread_mutex_init(&tile->mutex, NULL);
@ -101,7 +140,16 @@ tile_release (Tile *tile, int dirty)
/* Decrement write ref count if dirtying
*/
if (dirty)
tile->write_count -= 1;
{
int y;
tile->write_count -= 1;
for (y = 0; y < tile->eheight; y++)
{
tile->rowhint[y] = TILEROWHINT_UNKNOWN;
}
}
if (tile->ref_count == 0)
{

View File

@ -9,7 +9,8 @@
#define TILE_DEBUG
*/
/* sanity checking on new tile hinting code */
/* #define HINTS_SANITY */
#include <sys/types.h>
#include <glib.h>
@ -18,6 +19,17 @@
typedef struct _Tile Tile;
typedef enum
{
TILEROWHINT_BROKEN = 0,
TILEROWHINT_OPAQUE,
TILEROWHINT_TRANSPARENT,
TILEROWHINT_MIXED,
TILEROWHINT_OUTOFRANGE,
TILEROWHINT_UNDEFINED,
TILEROWHINT_UNKNOWN
} TileRowHint;
/* Initializes the fields of a tile to "good" values.
*/
@ -53,6 +65,10 @@ int tile_is_valid (Tile *tile);
void tile_mark_valid (Tile *tile);
/* DOCUMENT ME -- adm */
TileRowHint tile_get_rowhint (Tile *tile, int yoff);
void tile_set_rowhint (Tile *tile, int yoff, TileRowHint rowhint);
void *tile_data_pointer (Tile *tile, int xoff, int yoff);
/* tile_attach attaches a tile to a tile manager: this function

View File

@ -19,6 +19,7 @@
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
@ -37,8 +38,6 @@
#include "libgimp/gimpintl.h"
#include <stdio.h>
#define STD_BUF_SIZE 1021
#define MAXDIFF 195076
#define HASH_TABLE_SIZE 1021
@ -132,6 +131,189 @@ static void apply_layer_mode_replace (unsigned char *, unsigned char *,
int, int, int, int *);
void
update_tile_rowhints (Tile* tile, int ymin, int ymax)
{
int bpp, ewidth, eheight;
int x,y;
guchar* ptr;
guchar alpha;
TileRowHint thishint;
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
bpp = tile_bpp (tile);
ewidth = tile_ewidth (tile);
eheight = tile_eheight (tile);
if (bpp == 1 || bpp == 3)
{
for (y=ymin; y<=ymax; y++)
tile_set_rowhint (tile, y, TILEROWHINT_OPAQUE);
return;
}
if (bpp == 4)
{
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
ptr = tile_data_pointer (tile, 0, ymin);
#ifdef HINTS_SANITY
g_assert(ptr!=NULL);
#endif
for (y = ymin; y <= ymax; y++)
{
thishint = tile_get_rowhint (tile, y);
#ifdef HINTS_SANITY
if (thishint==TILEROWHINT_BROKEN)
g_error("BROKEN y=%d",y);
if (thishint==TILEROWHINT_OUTOFRANGE)
g_error("OOR y=%d",y);
if (thishint==TILEROWHINT_UNDEFINED)
g_error("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
#endif
#ifdef HINTS_SANITY
if (thishint == TILEROWHINT_TRANSPARENT ||
thishint == TILEROWHINT_MIXED ||
thishint == TILEROWHINT_OPAQUE)
{
goto next_row4;
}
if (thishint != TILEROWHINT_UNKNOWN)
{
g_error("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
}
#endif
if (thishint == TILEROWHINT_UNKNOWN)
{
alpha = ptr[3];
/* row is all-opaque or all-transparent? */
if (alpha == 0 || alpha == 255)
{
if (ewidth > 1)
{
for (x = 1; x < ewidth; x++)
{
if (ptr[x*4 + 3] != alpha)
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
goto next_row4;
}
}
}
tile_set_rowhint (tile, y,
(alpha == 0) ?
TILEROWHINT_TRANSPARENT :
TILEROWHINT_OPAQUE);
}
else
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
}
}
next_row4:
ptr += 4 * ewidth;
}
return;
}
if (bpp == 2)
{
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
ptr = tile_data_pointer (tile, 0, ymin);
#ifdef HINTS_SANITY
g_assert(ptr!=NULL);
#endif
for (y = ymin; y <= ymax; y++)
{
thishint = tile_get_rowhint (tile, y);
#ifdef HINTS_SANITY
if (thishint==TILEROWHINT_BROKEN)
g_error("BROKEN y=%d",y);
if (thishint==TILEROWHINT_OUTOFRANGE)
g_error("OOR y=%d",y);
if (thishint==TILEROWHINT_UNDEFINED)
g_error("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
#endif
#ifdef HINTS_SANITY
if (thishint == TILEROWHINT_TRANSPARENT ||
thishint == TILEROWHINT_MIXED ||
thishint == TILEROWHINT_OPAQUE)
{
goto next_row2;
}
if (thishint != TILEROWHINT_UNKNOWN)
{
g_error("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
}
#endif
if (thishint == TILEROWHINT_UNKNOWN)
{
alpha = ptr[1];
/* row is all-opaque or all-transparent? */
if (alpha == 0 || alpha == 255)
{
if (ewidth > 1)
{
for (x = 1; x < ewidth; x++)
{
if (ptr[x*2 + 1] != alpha)
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
goto next_row2;
}
}
}
tile_set_rowhint (tile, y,
(alpha == 0) ?
TILEROWHINT_TRANSPARENT :
TILEROWHINT_OPAQUE);
}
else
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
}
}
next_row2:
ptr += 2 * ewidth;
}
return;
}
g_warning ("update_tile_rowhints: Don't know about tiles with bpp==%d", bpp);
}
static unsigned char *
paint_funcs_get_buffer (int size)
{
@ -3358,10 +3540,6 @@ gaussian_blur_region (PixelRegion *srcR,
int alpha;
int initial_p, initial_m;
total = 0;
start = 0;
end = 0;
if (radius_x == 0.0 && radius_y == 0.0) return; /* zero blur is a no-op */
/* allocate the result buffer */
@ -3377,6 +3555,8 @@ gaussian_blur_region (PixelRegion *srcR,
buf = g_malloc (sizeof (int) * MAXIMUM (width, height) * 2);
total = sum[length] - sum[-length];
if (radius_y != 0.0)
{
std_dev = sqrt (-(radius_y * radius_y) / (2 * log (1.0 / 255.0)));
@ -4949,6 +5129,8 @@ combine_sub_region(struct combine_regions_struct *st,
unsigned char * s, * s1, * s2;
unsigned char * d, * m;
unsigned char buf[512];
gboolean opacity_quickskip_possible;
TileRowHint hint;
opacity = st->opacity;
mode = st->mode;
@ -4963,150 +5145,205 @@ combine_sub_region(struct combine_regions_struct *st,
d = dest->data;
m = (mask) ? mask->data : NULL;
/* cheap and easy when the row of src2 is completely opaque */
opacity_quickskip_possible = ((!m) && (opacity==255));
/* if (src2->tiles)
s2 = tile_data_pointer(src2->curtile,
src2->offx,
src2->offy);*/
if (src1->w > 128)
g_error("combine_sub_region::src1->w = %d\n", src1->w);
for (h = 0; h < src1->h; h++)
{
s = buf;
/* apply the paint mode based on the combination type & mode */
switch (type)
if (src2->tiles)
{
case COMBINE_INTEN_A_INDEXED_A:
case COMBINE_INTEN_A_CHANNEL_MASK:
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine = type;
break;
case COMBINE_INDEXED_INDEXED:
case COMBINE_INDEXED_INDEXED_A:
case COMBINE_INDEXED_A_INDEXED_A:
/* Now, apply the paint mode--for indexed images */
combine = apply_indexed_layer_mode (s1, s2, &s, mode, has_alpha1, has_alpha2);
break;
case COMBINE_INTEN_INTEN_A:
case COMBINE_INTEN_A_INTEN:
case COMBINE_INTEN_INTEN:
case COMBINE_INTEN_A_INTEN_A:
/* Now, apply the paint mode */
combine = apply_layer_mode (s1, s2, &s, src1->x, src1->y + h, opacity, src1->w, mode,
src1->bytes, src2->bytes, has_alpha1, has_alpha2, &mode_affect);
break;
default:
g_warning ("combine_sub_region: unhandled combine-type.");
break;
#ifdef HINTS_SANITY
if (src1->h != src2->h)
g_error("HEIGHTS SUCK!!");
if (src1->offy != dest->offy)
g_error("SRC1 OFFSET != DEST OFFSET");
#endif
update_tile_rowhints (src2->curtile,
src2->offy, src2->offy + (src1->h - 1));
}
/* else it's probably a brush-composite */
/* based on the type of the initial image... */
switch (combine)
for (h = 0; h < src1->h; h++)
{
case COMBINE_INDEXED_INDEXED:
combine_indexed_and_indexed_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
hint = TILEROWHINT_UNDEFINED;
case COMBINE_INDEXED_INDEXED_A:
combine_indexed_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
if (src2->tiles &&
((hint = tile_get_rowhint (src2->curtile, (src2->offy + h))) ==
TILEROWHINT_TRANSPARENT))
{
goto next_row;
}
s = buf;
case COMBINE_INDEXED_A_INDEXED_A:
combine_indexed_a_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
/* apply the paint mode based on the combination type & mode */
switch (type)
{
case COMBINE_INTEN_A_INDEXED_A:
case COMBINE_INTEN_A_CHANNEL_MASK:
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine = type;
break;
case COMBINE_INTEN_A_INDEXED_A:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_indexed_a_pixels (s1, s2, d, m, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INDEXED_INDEXED:
case COMBINE_INDEXED_INDEXED_A:
case COMBINE_INDEXED_A_INDEXED_A:
/* Now, apply the paint mode--for indexed images */
combine = apply_indexed_layer_mode (s1, s2, &s, mode, has_alpha1, has_alpha2);
break;
case COMBINE_INTEN_A_CHANNEL_MASK:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_channel_mask_pixels (s1, s2, d, data, opacity,
case COMBINE_INTEN_INTEN_A:
case COMBINE_INTEN_A_INTEN:
case COMBINE_INTEN_INTEN:
case COMBINE_INTEN_A_INTEN_A:
/* Now, apply the paint mode */
combine = apply_layer_mode (s1, s2, &s, src1->x, src1->y + h, opacity, src1->w, mode,
src1->bytes, src2->bytes, has_alpha1, has_alpha2, &mode_affect);
break;
default:
g_warning ("combine_sub_region: unhandled combine-type.");
break;
}
/* based on the type of the initial image... */
switch (combine)
{
case COMBINE_INDEXED_INDEXED:
combine_indexed_and_indexed_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INDEXED_INDEXED_A:
combine_indexed_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INDEXED_A_INDEXED_A:
combine_indexed_a_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INTEN_A_INDEXED_A:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_indexed_a_pixels (s1, s2, d, m, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine_inten_a_and_channel_selection_pixels (s1, s2, d, data, opacity,
src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN:
combine_inten_and_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN_A:
combine_inten_and_inten_a_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN:
combine_inten_a_and_inten_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN_A:
combine_inten_a_and_inten_a_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w, src1->bytes);
break;
case BEHIND_INTEN:
behind_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case BEHIND_INDEXED:
behind_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INTEN:
replace_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INDEXED:
replace_indexed_pixels (s1, s, d, m, opacity,
break;
case COMBINE_INTEN_A_CHANNEL_MASK:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_channel_mask_pixels (s1, s2, d, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine_inten_a_and_channel_selection_pixels (s1, s2, d, data,
opacity,
src1->w,
src1->bytes);
break;
case COMBINE_INTEN_INTEN:
if ((hint == TILEROWHINT_OPAQUE) &&
opacity_quickskip_possible)
{
memcpy (d, s, dest->w * dest->bytes);
}
else
combine_inten_and_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN_A:
combine_inten_and_inten_a_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN:
combine_inten_a_and_inten_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w,
src1->bytes);
break;
case COMBINE_INTEN_A_INTEN_A:
if ((hint == TILEROWHINT_OPAQUE) &&
opacity_quickskip_possible)
{
memcpy (d, s, dest->w * dest->bytes);
}
else
combine_inten_a_and_inten_a_pixels (s1, s, d, m, opacity,
affect, mode_affect,
src1->w, src1->bytes);
break;
case BEHIND_INTEN:
behind_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case ERASE_INTEN:
erase_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case ERASE_INDEXED:
erase_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case NO_COMBINATION:
break;
default:
break;
break;
case BEHIND_INDEXED:
behind_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INTEN:
replace_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INDEXED:
replace_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case ERASE_INTEN:
erase_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case ERASE_INDEXED:
erase_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case NO_COMBINATION:
g_warning("NO_COMBINATION");
break;
default:
g_warning("UNKNOWN COMBINATION");
break;
}
next_row:
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
if (mask)
m += mask->rowstride;
}
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
if (mask)
m += mask->rowstride;
}
}
void
combine_regions (PixelRegion *src1,
PixelRegion *src2,

View File

@ -19,6 +19,7 @@
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
@ -37,8 +38,6 @@
#include "libgimp/gimpintl.h"
#include <stdio.h>
#define STD_BUF_SIZE 1021
#define MAXDIFF 195076
#define HASH_TABLE_SIZE 1021
@ -132,6 +131,189 @@ static void apply_layer_mode_replace (unsigned char *, unsigned char *,
int, int, int, int *);
void
update_tile_rowhints (Tile* tile, int ymin, int ymax)
{
int bpp, ewidth, eheight;
int x,y;
guchar* ptr;
guchar alpha;
TileRowHint thishint;
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
bpp = tile_bpp (tile);
ewidth = tile_ewidth (tile);
eheight = tile_eheight (tile);
if (bpp == 1 || bpp == 3)
{
for (y=ymin; y<=ymax; y++)
tile_set_rowhint (tile, y, TILEROWHINT_OPAQUE);
return;
}
if (bpp == 4)
{
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
ptr = tile_data_pointer (tile, 0, ymin);
#ifdef HINTS_SANITY
g_assert(ptr!=NULL);
#endif
for (y = ymin; y <= ymax; y++)
{
thishint = tile_get_rowhint (tile, y);
#ifdef HINTS_SANITY
if (thishint==TILEROWHINT_BROKEN)
g_error("BROKEN y=%d",y);
if (thishint==TILEROWHINT_OUTOFRANGE)
g_error("OOR y=%d",y);
if (thishint==TILEROWHINT_UNDEFINED)
g_error("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
#endif
#ifdef HINTS_SANITY
if (thishint == TILEROWHINT_TRANSPARENT ||
thishint == TILEROWHINT_MIXED ||
thishint == TILEROWHINT_OPAQUE)
{
goto next_row4;
}
if (thishint != TILEROWHINT_UNKNOWN)
{
g_error("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
}
#endif
if (thishint == TILEROWHINT_UNKNOWN)
{
alpha = ptr[3];
/* row is all-opaque or all-transparent? */
if (alpha == 0 || alpha == 255)
{
if (ewidth > 1)
{
for (x = 1; x < ewidth; x++)
{
if (ptr[x*4 + 3] != alpha)
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
goto next_row4;
}
}
}
tile_set_rowhint (tile, y,
(alpha == 0) ?
TILEROWHINT_TRANSPARENT :
TILEROWHINT_OPAQUE);
}
else
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
}
}
next_row4:
ptr += 4 * ewidth;
}
return;
}
if (bpp == 2)
{
#ifdef HINTS_SANITY
g_assert(tile!=NULL);
#endif
ptr = tile_data_pointer (tile, 0, ymin);
#ifdef HINTS_SANITY
g_assert(ptr!=NULL);
#endif
for (y = ymin; y <= ymax; y++)
{
thishint = tile_get_rowhint (tile, y);
#ifdef HINTS_SANITY
if (thishint==TILEROWHINT_BROKEN)
g_error("BROKEN y=%d",y);
if (thishint==TILEROWHINT_OUTOFRANGE)
g_error("OOR y=%d",y);
if (thishint==TILEROWHINT_UNDEFINED)
g_error("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
#endif
#ifdef HINTS_SANITY
if (thishint == TILEROWHINT_TRANSPARENT ||
thishint == TILEROWHINT_MIXED ||
thishint == TILEROWHINT_OPAQUE)
{
goto next_row2;
}
if (thishint != TILEROWHINT_UNKNOWN)
{
g_error("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
y,bpp,ewidth,eheight);
}
#endif
if (thishint == TILEROWHINT_UNKNOWN)
{
alpha = ptr[1];
/* row is all-opaque or all-transparent? */
if (alpha == 0 || alpha == 255)
{
if (ewidth > 1)
{
for (x = 1; x < ewidth; x++)
{
if (ptr[x*2 + 1] != alpha)
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
goto next_row2;
}
}
}
tile_set_rowhint (tile, y,
(alpha == 0) ?
TILEROWHINT_TRANSPARENT :
TILEROWHINT_OPAQUE);
}
else
{
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
}
}
next_row2:
ptr += 2 * ewidth;
}
return;
}
g_warning ("update_tile_rowhints: Don't know about tiles with bpp==%d", bpp);
}
static unsigned char *
paint_funcs_get_buffer (int size)
{
@ -3358,10 +3540,6 @@ gaussian_blur_region (PixelRegion *srcR,
int alpha;
int initial_p, initial_m;
total = 0;
start = 0;
end = 0;
if (radius_x == 0.0 && radius_y == 0.0) return; /* zero blur is a no-op */
/* allocate the result buffer */
@ -3377,6 +3555,8 @@ gaussian_blur_region (PixelRegion *srcR,
buf = g_malloc (sizeof (int) * MAXIMUM (width, height) * 2);
total = sum[length] - sum[-length];
if (radius_y != 0.0)
{
std_dev = sqrt (-(radius_y * radius_y) / (2 * log (1.0 / 255.0)));
@ -4949,6 +5129,8 @@ combine_sub_region(struct combine_regions_struct *st,
unsigned char * s, * s1, * s2;
unsigned char * d, * m;
unsigned char buf[512];
gboolean opacity_quickskip_possible;
TileRowHint hint;
opacity = st->opacity;
mode = st->mode;
@ -4963,150 +5145,205 @@ combine_sub_region(struct combine_regions_struct *st,
d = dest->data;
m = (mask) ? mask->data : NULL;
/* cheap and easy when the row of src2 is completely opaque */
opacity_quickskip_possible = ((!m) && (opacity==255));
/* if (src2->tiles)
s2 = tile_data_pointer(src2->curtile,
src2->offx,
src2->offy);*/
if (src1->w > 128)
g_error("combine_sub_region::src1->w = %d\n", src1->w);
for (h = 0; h < src1->h; h++)
{
s = buf;
/* apply the paint mode based on the combination type & mode */
switch (type)
if (src2->tiles)
{
case COMBINE_INTEN_A_INDEXED_A:
case COMBINE_INTEN_A_CHANNEL_MASK:
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine = type;
break;
case COMBINE_INDEXED_INDEXED:
case COMBINE_INDEXED_INDEXED_A:
case COMBINE_INDEXED_A_INDEXED_A:
/* Now, apply the paint mode--for indexed images */
combine = apply_indexed_layer_mode (s1, s2, &s, mode, has_alpha1, has_alpha2);
break;
case COMBINE_INTEN_INTEN_A:
case COMBINE_INTEN_A_INTEN:
case COMBINE_INTEN_INTEN:
case COMBINE_INTEN_A_INTEN_A:
/* Now, apply the paint mode */
combine = apply_layer_mode (s1, s2, &s, src1->x, src1->y + h, opacity, src1->w, mode,
src1->bytes, src2->bytes, has_alpha1, has_alpha2, &mode_affect);
break;
default:
g_warning ("combine_sub_region: unhandled combine-type.");
break;
#ifdef HINTS_SANITY
if (src1->h != src2->h)
g_error("HEIGHTS SUCK!!");
if (src1->offy != dest->offy)
g_error("SRC1 OFFSET != DEST OFFSET");
#endif
update_tile_rowhints (src2->curtile,
src2->offy, src2->offy + (src1->h - 1));
}
/* else it's probably a brush-composite */
/* based on the type of the initial image... */
switch (combine)
for (h = 0; h < src1->h; h++)
{
case COMBINE_INDEXED_INDEXED:
combine_indexed_and_indexed_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
hint = TILEROWHINT_UNDEFINED;
case COMBINE_INDEXED_INDEXED_A:
combine_indexed_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
if (src2->tiles &&
((hint = tile_get_rowhint (src2->curtile, (src2->offy + h))) ==
TILEROWHINT_TRANSPARENT))
{
goto next_row;
}
s = buf;
case COMBINE_INDEXED_A_INDEXED_A:
combine_indexed_a_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w, src1->bytes);
break;
/* apply the paint mode based on the combination type & mode */
switch (type)
{
case COMBINE_INTEN_A_INDEXED_A:
case COMBINE_INTEN_A_CHANNEL_MASK:
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine = type;
break;
case COMBINE_INTEN_A_INDEXED_A:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_indexed_a_pixels (s1, s2, d, m, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INDEXED_INDEXED:
case COMBINE_INDEXED_INDEXED_A:
case COMBINE_INDEXED_A_INDEXED_A:
/* Now, apply the paint mode--for indexed images */
combine = apply_indexed_layer_mode (s1, s2, &s, mode, has_alpha1, has_alpha2);
break;
case COMBINE_INTEN_A_CHANNEL_MASK:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_channel_mask_pixels (s1, s2, d, data, opacity,
case COMBINE_INTEN_INTEN_A:
case COMBINE_INTEN_A_INTEN:
case COMBINE_INTEN_INTEN:
case COMBINE_INTEN_A_INTEN_A:
/* Now, apply the paint mode */
combine = apply_layer_mode (s1, s2, &s, src1->x, src1->y + h, opacity, src1->w, mode,
src1->bytes, src2->bytes, has_alpha1, has_alpha2, &mode_affect);
break;
default:
g_warning ("combine_sub_region: unhandled combine-type.");
break;
}
/* based on the type of the initial image... */
switch (combine)
{
case COMBINE_INDEXED_INDEXED:
combine_indexed_and_indexed_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INDEXED_INDEXED_A:
combine_indexed_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INDEXED_A_INDEXED_A:
combine_indexed_a_and_indexed_a_pixels (s1, s2, d, m, opacity,
affect, src1->w,
src1->bytes);
break;
case COMBINE_INTEN_A_INDEXED_A:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_indexed_a_pixels (s1, s2, d, m, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine_inten_a_and_channel_selection_pixels (s1, s2, d, data, opacity,
src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN:
combine_inten_and_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN_A:
combine_inten_and_inten_a_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN:
combine_inten_a_and_inten_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN_A:
combine_inten_a_and_inten_a_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w, src1->bytes);
break;
case BEHIND_INTEN:
behind_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case BEHIND_INDEXED:
behind_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INTEN:
replace_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INDEXED:
replace_indexed_pixels (s1, s, d, m, opacity,
break;
case COMBINE_INTEN_A_CHANNEL_MASK:
/* assume the data passed to this procedure is the
* indexed layer's colormap
*/
combine_inten_a_and_channel_mask_pixels (s1, s2, d, data, opacity,
src1->w, dest->bytes);
break;
case COMBINE_INTEN_A_CHANNEL_SELECTION:
combine_inten_a_and_channel_selection_pixels (s1, s2, d, data,
opacity,
src1->w,
src1->bytes);
break;
case COMBINE_INTEN_INTEN:
if ((hint == TILEROWHINT_OPAQUE) &&
opacity_quickskip_possible)
{
memcpy (d, s, dest->w * dest->bytes);
}
else
combine_inten_and_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_INTEN_A:
combine_inten_and_inten_a_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case COMBINE_INTEN_A_INTEN:
combine_inten_a_and_inten_pixels (s1, s, d, m, opacity,
affect, mode_affect, src1->w,
src1->bytes);
break;
case COMBINE_INTEN_A_INTEN_A:
if ((hint == TILEROWHINT_OPAQUE) &&
opacity_quickskip_possible)
{
memcpy (d, s, dest->w * dest->bytes);
}
else
combine_inten_a_and_inten_a_pixels (s1, s, d, m, opacity,
affect, mode_affect,
src1->w, src1->bytes);
break;
case BEHIND_INTEN:
behind_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case ERASE_INTEN:
erase_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case ERASE_INDEXED:
erase_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case NO_COMBINATION:
break;
default:
break;
break;
case BEHIND_INDEXED:
behind_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INTEN:
replace_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case REPLACE_INDEXED:
replace_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes,
src2->bytes, has_alpha1, has_alpha2);
break;
case ERASE_INTEN:
erase_inten_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case ERASE_INDEXED:
erase_indexed_pixels (s1, s, d, m, opacity,
affect, src1->w, src1->bytes);
break;
case NO_COMBINATION:
g_warning("NO_COMBINATION");
break;
default:
g_warning("UNKNOWN COMBINATION");
break;
}
next_row:
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
if (mask)
m += mask->rowstride;
}
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
if (mask)
m += mask->rowstride;
}
}
void
combine_regions (PixelRegion *src1,
PixelRegion *src2,

View File

@ -13,10 +13,43 @@ static void tile_destroy (Tile *tile);
int tile_count = 0;
TileRowHint
tile_get_rowhint (Tile *tile, int yoff)
{
#ifdef HINTS_SANITY
if (yoff < tile_eheight(tile) && yoff>=0)
{
return tile->rowhint[yoff];
}
else
g_error("GET_ROWHINT OUT OF RANGE");
/* return TILEROWHINT_OUTOFRANGE; */
#else
return tile->rowhint[yoff];
#endif
}
void
tile_set_rowhint (Tile *tile, int yoff, TileRowHint rowhint)
{
#ifdef HINTS_SANITY
if (yoff < tile_eheight(tile) && yoff>=0)
{
tile->rowhint[yoff] = rowhint;
}
else
g_error("SET_ROWHINT OUT OF RANGE");
#else
tile->rowhint[yoff] = rowhint;
#endif
}
void
tile_init (Tile *tile,
int bpp)
{
int y;
tile->ref_count = 0;
tile->write_count = 0;
tile->share_count = 0;
@ -31,6 +64,12 @@ tile_init (Tile *tile,
tile->tlink = NULL;
tile->next = tile->prev = NULL;
tile->listhead = NULL;
for (y=0; y<TILE_HEIGHT; y++)
{
tile->rowhint[y] = TILEROWHINT_UNKNOWN;
}
#ifdef USE_PTHREADS
{
pthread_mutex_init(&tile->mutex, NULL);
@ -101,7 +140,16 @@ tile_release (Tile *tile, int dirty)
/* Decrement write ref count if dirtying
*/
if (dirty)
tile->write_count -= 1;
{
int y;
tile->write_count -= 1;
for (y = 0; y < tile->eheight; y++)
{
tile->rowhint[y] = TILEROWHINT_UNKNOWN;
}
}
if (tile->ref_count == 0)
{

View File

@ -9,7 +9,8 @@
#define TILE_DEBUG
*/
/* sanity checking on new tile hinting code */
/* #define HINTS_SANITY */
#include <sys/types.h>
#include <glib.h>
@ -18,6 +19,17 @@
typedef struct _Tile Tile;
typedef enum
{
TILEROWHINT_BROKEN = 0,
TILEROWHINT_OPAQUE,
TILEROWHINT_TRANSPARENT,
TILEROWHINT_MIXED,
TILEROWHINT_OUTOFRANGE,
TILEROWHINT_UNDEFINED,
TILEROWHINT_UNKNOWN
} TileRowHint;
/* Initializes the fields of a tile to "good" values.
*/
@ -53,6 +65,10 @@ int tile_is_valid (Tile *tile);
void tile_mark_valid (Tile *tile);
/* DOCUMENT ME -- adm */
TileRowHint tile_get_rowhint (Tile *tile, int yoff);
void tile_set_rowhint (Tile *tile, int yoff, TileRowHint rowhint);
void *tile_data_pointer (Tile *tile, int xoff, int yoff);
/* tile_attach attaches a tile to a tile manager: this function

View File

@ -173,18 +173,25 @@ tile_manager_get (TileManager *tm,
newtile->ewidth = (*tile_ptr)->ewidth;
newtile->eheight = (*tile_ptr)->eheight;
newtile->valid = (*tile_ptr)->valid;
newtile->data = g_new (guchar, tile_size (newtile));
i = newtile->eheight;
while (i--)
{
newtile->rowhint[i] = (*tile_ptr)->rowhint[i];
}
if ((*tile_ptr)->data != NULL)
{
newtile->data = g_new (guchar, tile_size (newtile));
memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
}
else
{
tile_lock (*tile_ptr);
newtile->data = g_new (guchar, tile_size (newtile));
memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
tile_release (*tile_ptr, FALSE);
}
tile_detach (*tile_ptr, tm, tile_num);
TILE_MUTEX_LOCK (newtile);
tile_attach (newtile, tm, tile_num);

View File

@ -10,6 +10,7 @@
#include <glib.h>
#include "config.h"
#include "tile.h"
typedef struct _TileLink TileLink;
@ -39,6 +40,9 @@ struct _Tile
guint dirty : 1; /* is the tile dirty? has it been modified? */
guint valid : 1; /* is the tile valid? */
/* An array of hints for rendering purposes */
TileRowHint rowhint[TILE_HEIGHT];
guchar *data; /* the data for the tile. this may be NULL in which
* case the tile data is on disk.
*/