From: Brian Date: Fri, 28 Mar 2008 20:53:47 +0000 (-0600) Subject: gallium: implement a glBitmap cache X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c62b197b528293abb56b099503344e3cdd7d6c40;p=mesa.git gallium: implement a glBitmap cache The bitmap cache attempts to accumulate a series of glBitmap calls in a buffer to effectively render a whole bunch of bitmaps at once. The cache can be disabled, if needed, by setting UseBitmapCache=GL_FALSE. --- diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c index 0e22a2fa6e7..40e4142631b 100644 --- a/src/mesa/state_tracker/st_atom.c +++ b/src/mesa/state_tracker/st_atom.c @@ -32,6 +32,7 @@ #include "pipe/p_defines.h" #include "st_context.h" #include "st_atom.h" +#include "st_cb_bitmap.h" #include "st_program.h" @@ -147,6 +148,8 @@ void st_validate_state( struct st_context *st ) struct st_state_flags *state = &st->dirty; GLuint i; + st_flush_bitmap_cache(st); + check_program_state( st ); if (state->st == 0) diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index 64b18824245..e46dcbf6610 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -59,6 +59,31 @@ +/** + * The bitmap cache attempts to accumulate multiple glBitmap calls in a + * buffer which is then rendered en mass upon a flush, state change, etc. + * A wide, short buffer is used to target the common case of a series + * of glBitmap calls being used to draw text. + */ +static GLboolean UseBitmapCache = 0*GL_TRUE; + + +#define BITMAP_CACHE_WIDTH 512 +#define BITMAP_CACHE_HEIGHT 32 + +struct bitmap_cache +{ + /** An I8 texture image: */ + GLubyte buffer[BITMAP_CACHE_HEIGHT][BITMAP_CACHE_WIDTH]; + GLboolean empty; + /** Window pos to render the cached image */ + GLint xpos, ypos; + struct pipe_texture *texture; +}; + + + + /** * Make fragment program for glBitmap: * Sample the texture and kill the fragment if the bit is 0. @@ -390,16 +415,18 @@ setup_bitmap_vertex_data(struct st_context *st, static void draw_bitmap_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, - struct pipe_texture *pt, - struct st_fragment_program *stfp) + struct pipe_texture *pt) { struct st_context *st = ctx->st; struct pipe_context *pipe = ctx->st->pipe; struct cso_context *cso = ctx->st->cso_context; + struct st_fragment_program *stfp; GLuint maxSize; + stfp = combined_bitmap_fragment_program(ctx); + /* limit checks */ - /* XXX if DrawPixels image is larger than max texture size, break + /* XXX if the bitmap is larger than the max texture size, break * it up into chunks. */ maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); @@ -467,18 +494,185 @@ draw_bitmap_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, +static void +init_bitmap_cache(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + enum pipe_format format; + + st->bitmap.cache = CALLOC_STRUCT(bitmap_cache); + if (!st->bitmap.cache) + return; + + /* find a usable texture format */ + if (screen->is_format_supported(screen, PIPE_FORMAT_U_I8, PIPE_TEXTURE)) { + format = PIPE_FORMAT_U_I8; + } + else { + /* XXX support more formats */ + assert(0); + } + + st->bitmap.cache->texture + = st_texture_create(st, PIPE_TEXTURE_2D, format, 0, + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, 1, 0); + if (!st->bitmap.cache->texture) { + FREE(st->bitmap.cache); + st->bitmap.cache = NULL; + return; + } + + st->bitmap.cache->empty = GL_TRUE; +} + + +/** + * If there's anything in the bitmap cache, draw/flush it now. + */ +void +st_flush_bitmap_cache(struct st_context *st) +{ + if (!st->bitmap.cache->empty) { + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surf; + void *dest; + + /* update the texture map image */ + surf = screen->get_tex_surface(screen, st->bitmap.cache->texture, 0, 0, 0); + dest = pipe_surface_map(surf); + memcpy(dest, st->bitmap.cache->buffer, sizeof(st->bitmap.cache->buffer)); + pipe_surface_unmap(surf); + pipe_surface_reference(&surf, NULL); + + pipe->texture_update(pipe, st->bitmap.cache->texture, 0, 0x1); + + draw_bitmap_quad(st->ctx, + st->bitmap.cache->xpos, + st->bitmap.cache->ypos, + st->ctx->Current.RasterPos[2], + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, + st->bitmap.cache->texture); + + memset(st->bitmap.cache->buffer, 0, sizeof(st->bitmap.cache->buffer)); + st->bitmap.cache->empty = GL_TRUE; + } +} + + +/** + * Try to accumulate this glBitmap call in the bitmap cache. + * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc. + */ +static GLboolean +accum_bitmap(struct st_context *st, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap ) +{ + int row, col; + int px = -999, py; + + if (width > BITMAP_CACHE_WIDTH || + height > BITMAP_CACHE_HEIGHT) + return GL_FALSE; /* too big to cache */ + + if (!st->bitmap.cache->empty) { + px = x - st->bitmap.cache->xpos; /* pos in buffer */ + py = y - st->bitmap.cache->ypos; + if (px < 0 || px + width > BITMAP_CACHE_WIDTH || + py < 0 || py + height > BITMAP_CACHE_HEIGHT) { + /* This bitmap would extend beyond cache bounds, + * so flush and continue. + */ + st_flush_bitmap_cache(st); + } + } + + if (st->bitmap.cache->empty) { + /* Initialize. Center bitmap vertically in the buffer. */ + px = 0; + py = (BITMAP_CACHE_HEIGHT - height) / 2; + st->bitmap.cache->xpos = x; + st->bitmap.cache->ypos = y - py; + st->bitmap.cache->empty = GL_FALSE; + } + + assert(px != -999); + + /* XXX try to combine this code with code in make_bitmap_texture() */ +#define SET_PIXEL(COL, ROW) \ + st->bitmap.cache->buffer[py + (ROW)][px + (COL)] = 0xff; + + for (row = 0; row < height; row++) { + const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, + bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); + + if (unpack->LsbFirst) { + /* Lsb first */ + GLubyte mask = 1U << (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 128U) { + src++; + mask = 1U; + } + else { + mask = mask << 1; + } + } + + /* get ready for next row */ + if (mask != 1) + src++; + } + else { + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 1U) { + src++; + mask = 128U; + } + else { + mask = mask >> 1; + } + } + + /* get ready for next row */ + if (mask != 128) + src++; + } + + } /* row */ + + return GL_TRUE; /* accumulated */ +} + + + +/** + * Called via ctx->Driver.Bitmap() + */ static void st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { - struct st_fragment_program *stfp; struct st_context *st = ctx->st; struct pipe_texture *pt; st_validate_state(st); - stfp = combined_bitmap_fragment_program(ctx); - if (!st->bitmap.vs) { /* create pass-through vertex shader now */ const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, @@ -491,26 +685,36 @@ st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, &st->bitmap.vert_shader); } - st_validate_state(st); + if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap)) + return; pt = make_bitmap_texture(ctx, width, height, unpack, bitmap); if (pt) { assert(pt->target == PIPE_TEXTURE_2D); draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2], - width, height, - pt, stfp); + width, height, pt); pipe_texture_reference(&pt, NULL); } } - -void st_init_bitmap_functions(struct dd_function_table *functions) +/** Per-context init */ +void +st_init_bitmap_functions(struct dd_function_table *functions) { functions->Bitmap = st_Bitmap; } +/** Per-context init */ +void +st_init_bitmap(struct st_context *st) +{ + init_bitmap_cache(st); +} + + +/** Per-context tear-down */ void st_destroy_bitmap(struct st_context *st) { @@ -528,9 +732,15 @@ st_destroy_bitmap(struct st_context *st) pipe->delete_vs_state(pipe, st->bitmap.vs); st->bitmap.vs = NULL; } + if (st->bitmap.vbuf) { pipe->winsys->buffer_destroy(pipe->winsys, st->bitmap.vbuf); st->bitmap.vbuf = NULL; } -} + if (st->bitmap.cache) { + pipe_texture_release(&st->bitmap.cache->texture); + FREE(st->bitmap.cache); + st->bitmap.cache = NULL; + } +} diff --git a/src/mesa/state_tracker/st_cb_bitmap.h b/src/mesa/state_tracker/st_cb_bitmap.h index ac19e0ebb12..aae11d34c92 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.h +++ b/src/mesa/state_tracker/st_cb_bitmap.h @@ -33,9 +33,14 @@ extern void st_init_bitmap_functions(struct dd_function_table *functions); +extern void +st_init_bitmap(struct st_context *st); extern void st_destroy_bitmap(struct st_context *st); +extern void +st_flush_bitmap_cache(struct st_context *st); + #endif /* ST_CB_BITMAP_H */ diff --git a/src/mesa/state_tracker/st_cb_flush.c b/src/mesa/state_tracker/st_cb_flush.c index a536a059bd5..e321b401e2d 100644 --- a/src/mesa/state_tracker/st_cb_flush.c +++ b/src/mesa/state_tracker/st_cb_flush.c @@ -35,6 +35,7 @@ #include "main/macros.h" #include "main/context.h" #include "st_context.h" +#include "st_cb_bitmap.h" #include "st_cb_flush.h" #include "st_cb_fbo.h" #include "st_public.h" @@ -48,6 +49,8 @@ void st_flush( struct st_context *st, uint pipeFlushFlags, { FLUSH_VERTICES(st->ctx, 0); + st_flush_bitmap_cache(st); + st->pipe->flush( st->pipe, pipeFlushFlags, fence ); } diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 726e06d7c2b..a20195f2dea 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -109,6 +109,7 @@ st_create_context_priv( GLcontext *ctx, struct pipe_context *pipe ) st->cso_context = cso_create_context(pipe); st_init_atoms( st ); + st_init_bitmap(st); st_init_draw( st ); st_init_generate_mipmap(st); st_init_blit(st); diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index f235c194b74..85e3d47e1aa 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -42,6 +42,7 @@ struct cso_cache; struct cso_blend; struct gen_mipmap_state; struct blit_state; +struct bitmap_cache; #define ST_NEW_MESA 0x1 /* Mesa state has changed */ @@ -151,6 +152,7 @@ struct st_context void *vs; float vertices[4][3][4]; /**< vertex pos + color + texcoord */ struct pipe_buffer *vbuf; + struct bitmap_cache *cache; } bitmap; /** for glClear */