Home | History | Annotate | Download | only in state_tracker
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28  /*
     29   * Authors:
     30   *   Brian Paul
     31   */
     32 
     33 #include "main/imports.h"
     34 #include "main/image.h"
     35 #include "main/bufferobj.h"
     36 #include "main/macros.h"
     37 #include "main/mfeatures.h"
     38 #include "main/pbo.h"
     39 #include "program/program.h"
     40 #include "program/prog_print.h"
     41 
     42 #include "st_context.h"
     43 #include "st_atom.h"
     44 #include "st_atom_constbuf.h"
     45 #include "st_program.h"
     46 #include "st_cb_bitmap.h"
     47 #include "st_texture.h"
     48 
     49 #include "pipe/p_context.h"
     50 #include "pipe/p_defines.h"
     51 #include "pipe/p_shader_tokens.h"
     52 #include "util/u_inlines.h"
     53 #include "util/u_draw_quad.h"
     54 #include "util/u_simple_shaders.h"
     55 #include "util/u_upload_mgr.h"
     56 #include "program/prog_instruction.h"
     57 #include "cso_cache/cso_context.h"
     58 
     59 
     60 #if FEATURE_drawpix
     61 
     62 /**
     63  * glBitmaps are drawn as textured quads.  The user's bitmap pattern
     64  * is stored in a texture image.  An alpha8 texture format is used.
     65  * The fragment shader samples a bit (texel) from the texture, then
     66  * discards the fragment if the bit is off.
     67  *
     68  * Note that we actually store the inverse image of the bitmap to
     69  * simplify the fragment program.  An "on" bit gets stored as texel=0x0
     70  * and an "off" bit is stored as texel=0xff.  Then we kill the
     71  * fragment if the negated texel value is less than zero.
     72  */
     73 
     74 
     75 /**
     76  * The bitmap cache attempts to accumulate multiple glBitmap calls in a
     77  * buffer which is then rendered en mass upon a flush, state change, etc.
     78  * A wide, short buffer is used to target the common case of a series
     79  * of glBitmap calls being used to draw text.
     80  */
     81 static GLboolean UseBitmapCache = GL_TRUE;
     82 
     83 
     84 #define BITMAP_CACHE_WIDTH  512
     85 #define BITMAP_CACHE_HEIGHT 32
     86 
     87 struct bitmap_cache
     88 {
     89    /** Window pos to render the cached image */
     90    GLint xpos, ypos;
     91    /** Bounds of region used in window coords */
     92    GLint xmin, ymin, xmax, ymax;
     93 
     94    GLfloat color[4];
     95 
     96    /** Bitmap's Z position */
     97    GLfloat zpos;
     98 
     99    struct pipe_resource *texture;
    100    struct pipe_transfer *trans;
    101 
    102    GLboolean empty;
    103 
    104    /** An I8 texture image: */
    105    ubyte *buffer;
    106 };
    107 
    108 
    109 /** Epsilon for Z comparisons */
    110 #define Z_EPSILON 1e-06
    111 
    112 
    113 /**
    114  * Make fragment program for glBitmap:
    115  *   Sample the texture and kill the fragment if the bit is 0.
    116  * This program will be combined with the user's fragment program.
    117  */
    118 static struct st_fragment_program *
    119 make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex)
    120 {
    121    struct st_context *st = st_context(ctx);
    122    struct st_fragment_program *stfp;
    123    struct gl_program *p;
    124    GLuint ic = 0;
    125 
    126    p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
    127    if (!p)
    128       return NULL;
    129 
    130    p->NumInstructions = 3;
    131 
    132    p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
    133    if (!p->Instructions) {
    134       ctx->Driver.DeleteProgram(ctx, p);
    135       return NULL;
    136    }
    137    _mesa_init_instructions(p->Instructions, p->NumInstructions);
    138 
    139    /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
    140    p->Instructions[ic].Opcode = OPCODE_TEX;
    141    p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
    142    p->Instructions[ic].DstReg.Index = 0;
    143    p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
    144    p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
    145    p->Instructions[ic].TexSrcUnit = samplerIndex;
    146    p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
    147    ic++;
    148 
    149    /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
    150    p->Instructions[ic].Opcode = OPCODE_KIL;
    151    p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
    152 
    153    if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
    154       p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX;
    155 
    156    p->Instructions[ic].SrcReg[0].Index = 0;
    157    p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW;
    158    ic++;
    159 
    160    /* END; */
    161    p->Instructions[ic++].Opcode = OPCODE_END;
    162 
    163    assert(ic == p->NumInstructions);
    164 
    165    p->InputsRead = FRAG_BIT_TEX0;
    166    p->OutputsWritten = 0x0;
    167    p->SamplersUsed = (1 << samplerIndex);
    168 
    169    stfp = (struct st_fragment_program *) p;
    170    stfp->Base.UsesKill = GL_TRUE;
    171 
    172    return stfp;
    173 }
    174 
    175 
    176 static struct gl_program *
    177 make_bitmap_fragment_program_glsl(struct st_context *st,
    178                                   struct st_fragment_program *orig,
    179                                   GLuint samplerIndex)
    180 {
    181    struct gl_context *ctx = st->ctx;
    182    struct st_fragment_program *fp = (struct st_fragment_program *)
    183       ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
    184 
    185    if (!fp)
    186       return NULL;
    187 
    188    get_bitmap_visitor(fp, orig->glsl_to_tgsi, samplerIndex);
    189    return &fp->Base.Base;
    190 }
    191 
    192 
    193 static int
    194 find_free_bit(uint bitfield)
    195 {
    196    int i;
    197    for (i = 0; i < 32; i++) {
    198       if ((bitfield & (1 << i)) == 0) {
    199          return i;
    200       }
    201    }
    202    return -1;
    203 }
    204 
    205 
    206 /**
    207  * Combine basic bitmap fragment program with the user-defined program.
    208  * \param st  current context
    209  * \param fpIn  the incoming fragment program
    210  * \param fpOut  the new fragment program which does fragment culling
    211  * \param bitmap_sampler  sampler number for the bitmap texture
    212  */
    213 void
    214 st_make_bitmap_fragment_program(struct st_context *st,
    215                                 struct gl_fragment_program *fpIn,
    216                                 struct gl_fragment_program **fpOut,
    217                                 GLuint *bitmap_sampler)
    218 {
    219    struct st_fragment_program *bitmap_prog;
    220    struct st_fragment_program *stfpIn = (struct st_fragment_program *) fpIn;
    221    struct gl_program *newProg;
    222    uint sampler;
    223 
    224    /*
    225     * Generate new program which is the user-defined program prefixed
    226     * with the bitmap sampler/kill instructions.
    227     */
    228    sampler = find_free_bit(fpIn->Base.SamplersUsed);
    229 
    230    if (stfpIn->glsl_to_tgsi)
    231       newProg = make_bitmap_fragment_program_glsl(st, stfpIn, sampler);
    232    else {
    233       bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler);
    234 
    235       newProg = _mesa_combine_programs(st->ctx,
    236                                        &bitmap_prog->Base.Base,
    237                                        &fpIn->Base);
    238       /* done with this after combining */
    239       st_reference_fragprog(st, &bitmap_prog, NULL);
    240    }
    241 
    242 #if 0
    243    {
    244       printf("Combined bitmap program:\n");
    245       _mesa_print_program(newProg);
    246       printf("InputsRead: 0x%x\n", newProg->InputsRead);
    247       printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
    248       _mesa_print_parameter_list(newProg->Parameters);
    249    }
    250 #endif
    251 
    252    /* return results */
    253    *fpOut = (struct gl_fragment_program *) newProg;
    254    *bitmap_sampler = sampler;
    255 }
    256 
    257 
    258 /**
    259  * Copy user-provide bitmap bits into texture buffer, expanding
    260  * bits into texels.
    261  * "On" bits will set texels to 0x0.
    262  * "Off" bits will not modify texels.
    263  * Note that the image is actually going to be upside down in
    264  * the texture.  We deal with that with texcoords.
    265  */
    266 static void
    267 unpack_bitmap(struct st_context *st,
    268               GLint px, GLint py, GLsizei width, GLsizei height,
    269               const struct gl_pixelstore_attrib *unpack,
    270               const GLubyte *bitmap,
    271               ubyte *destBuffer, uint destStride)
    272 {
    273    destBuffer += py * destStride + px;
    274 
    275    _mesa_expand_bitmap(width, height, unpack, bitmap,
    276                        destBuffer, destStride, 0x0);
    277 }
    278 
    279 
    280 /**
    281  * Create a texture which represents a bitmap image.
    282  */
    283 static struct pipe_resource *
    284 make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height,
    285                     const struct gl_pixelstore_attrib *unpack,
    286                     const GLubyte *bitmap)
    287 {
    288    struct st_context *st = st_context(ctx);
    289    struct pipe_context *pipe = st->pipe;
    290    struct pipe_transfer *transfer;
    291    ubyte *dest;
    292    struct pipe_resource *pt;
    293 
    294    /* PBO source... */
    295    bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap);
    296    if (!bitmap) {
    297       return NULL;
    298    }
    299 
    300    /**
    301     * Create texture to hold bitmap pattern.
    302     */
    303    pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format,
    304                           0, width, height, 1, 1,
    305                           PIPE_BIND_SAMPLER_VIEW);
    306    if (!pt) {
    307       _mesa_unmap_pbo_source(ctx, unpack);
    308       return NULL;
    309    }
    310 
    311    transfer = pipe_get_transfer(st->pipe, pt, 0, 0,
    312                                 PIPE_TRANSFER_WRITE,
    313                                 0, 0, width, height);
    314 
    315    dest = pipe_transfer_map(pipe, transfer);
    316 
    317    /* Put image into texture transfer */
    318    memset(dest, 0xff, height * transfer->stride);
    319    unpack_bitmap(st, 0, 0, width, height, unpack, bitmap,
    320                  dest, transfer->stride);
    321 
    322    _mesa_unmap_pbo_source(ctx, unpack);
    323 
    324    /* Release transfer */
    325    pipe_transfer_unmap(pipe, transfer);
    326    pipe->transfer_destroy(pipe, transfer);
    327 
    328    return pt;
    329 }
    330 
    331 static void
    332 setup_bitmap_vertex_data(struct st_context *st, bool normalized,
    333                          int x, int y, int width, int height,
    334                          float z, const float color[4],
    335 			 struct pipe_resource **vbuf,
    336 			 unsigned *vbuf_offset)
    337 {
    338    const GLfloat fb_width = (GLfloat)st->state.framebuffer.width;
    339    const GLfloat fb_height = (GLfloat)st->state.framebuffer.height;
    340    const GLfloat x0 = (GLfloat)x;
    341    const GLfloat x1 = (GLfloat)(x + width);
    342    const GLfloat y0 = (GLfloat)y;
    343    const GLfloat y1 = (GLfloat)(y + height);
    344    GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0;
    345    GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop;
    346    const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
    347    const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
    348    const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
    349    const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
    350    GLuint i;
    351    float (*vertices)[3][4];  /**< vertex pos + color + texcoord */
    352 
    353    if(!normalized)
    354    {
    355       sRight = (GLfloat) width;
    356       tBot = (GLfloat) height;
    357    }
    358 
    359    if (u_upload_alloc(st->uploader, 0, 4 * sizeof(vertices[0]),
    360                       vbuf_offset, vbuf, (void **) &vertices) != PIPE_OK) {
    361       return;
    362    }
    363 
    364    /* Positions are in clip coords since we need to do clipping in case
    365     * the bitmap quad goes beyond the window bounds.
    366     */
    367    vertices[0][0][0] = clip_x0;
    368    vertices[0][0][1] = clip_y0;
    369    vertices[0][2][0] = sLeft;
    370    vertices[0][2][1] = tTop;
    371 
    372    vertices[1][0][0] = clip_x1;
    373    vertices[1][0][1] = clip_y0;
    374    vertices[1][2][0] = sRight;
    375    vertices[1][2][1] = tTop;
    376 
    377    vertices[2][0][0] = clip_x1;
    378    vertices[2][0][1] = clip_y1;
    379    vertices[2][2][0] = sRight;
    380    vertices[2][2][1] = tBot;
    381 
    382    vertices[3][0][0] = clip_x0;
    383    vertices[3][0][1] = clip_y1;
    384    vertices[3][2][0] = sLeft;
    385    vertices[3][2][1] = tBot;
    386 
    387    /* same for all verts: */
    388    for (i = 0; i < 4; i++) {
    389       vertices[i][0][2] = z;
    390       vertices[i][0][3] = 1.0f;
    391       vertices[i][1][0] = color[0];
    392       vertices[i][1][1] = color[1];
    393       vertices[i][1][2] = color[2];
    394       vertices[i][1][3] = color[3];
    395       vertices[i][2][2] = 0.0; /*R*/
    396       vertices[i][2][3] = 1.0; /*Q*/
    397    }
    398 
    399    u_upload_unmap(st->uploader);
    400 }
    401 
    402 
    403 
    404 /**
    405  * Render a glBitmap by drawing a textured quad
    406  */
    407 static void
    408 draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    409                  GLsizei width, GLsizei height,
    410                  struct pipe_sampler_view *sv,
    411                  const GLfloat *color)
    412 {
    413    struct st_context *st = st_context(ctx);
    414    struct pipe_context *pipe = st->pipe;
    415    struct cso_context *cso = st->cso_context;
    416    struct st_fp_variant *fpv;
    417    struct st_fp_variant_key key;
    418    GLuint maxSize;
    419    GLuint offset;
    420    struct pipe_resource *vbuf = NULL;
    421 
    422    memset(&key, 0, sizeof(key));
    423    key.st = st;
    424    key.bitmap = GL_TRUE;
    425    key.clamp_color = st->clamp_frag_color_in_shader &&
    426                      st->ctx->Color._ClampFragmentColor &&
    427                      !st->ctx->DrawBuffer->_IntegerColor;
    428 
    429    fpv = st_get_fp_variant(st, st->fp, &key);
    430 
    431    /* As an optimization, Mesa's fragment programs will sometimes get the
    432     * primary color from a statevar/constant rather than a varying variable.
    433     * when that's the case, we need to ensure that we use the 'color'
    434     * parameter and not the current attribute color (which may have changed
    435     * through glRasterPos and state validation.
    436     * So, we force the proper color here.  Not elegant, but it works.
    437     */
    438    {
    439       GLfloat colorSave[4];
    440       COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
    441       COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color);
    442       st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT);
    443       COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave);
    444    }
    445 
    446 
    447    /* limit checks */
    448    /* XXX if the bitmap is larger than the max texture size, break
    449     * it up into chunks.
    450     */
    451    maxSize = 1 << (pipe->screen->get_param(pipe->screen,
    452                                     PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
    453    assert(width <= (GLsizei)maxSize);
    454    assert(height <= (GLsizei)maxSize);
    455 
    456    cso_save_rasterizer(cso);
    457    cso_save_samplers(cso, PIPE_SHADER_FRAGMENT);
    458    cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT);
    459    cso_save_viewport(cso);
    460    cso_save_fragment_shader(cso);
    461    cso_save_stream_outputs(cso);
    462    cso_save_vertex_shader(cso);
    463    cso_save_geometry_shader(cso);
    464    cso_save_vertex_elements(cso);
    465    cso_save_vertex_buffers(cso);
    466 
    467    /* rasterizer state: just scissor */
    468    st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled;
    469    cso_set_rasterizer(cso, &st->bitmap.rasterizer);
    470 
    471    /* fragment shader state: TEX lookup program */
    472    cso_set_fragment_shader_handle(cso, fpv->driver_shader);
    473 
    474    /* vertex shader state: position + texcoord pass-through */
    475    cso_set_vertex_shader_handle(cso, st->bitmap.vs);
    476 
    477    /* geometry shader state: disabled */
    478    cso_set_geometry_shader_handle(cso, NULL);
    479 
    480    /* user samplers, plus our bitmap sampler */
    481    {
    482       struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
    483       uint num = MAX2(fpv->bitmap_sampler + 1,
    484                       st->state.num_samplers[PIPE_SHADER_FRAGMENT]);
    485       uint i;
    486       for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++) {
    487          samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i];
    488       }
    489       samplers[fpv->bitmap_sampler] =
    490          &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT];
    491       cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, num,
    492                        (const struct pipe_sampler_state **) samplers);
    493    }
    494 
    495    /* user textures, plus the bitmap texture */
    496    {
    497       struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
    498       uint num = MAX2(fpv->bitmap_sampler + 1,
    499                       st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]);
    500       memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT],
    501              sizeof(sampler_views));
    502       sampler_views[fpv->bitmap_sampler] = sv;
    503       cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, num, sampler_views);
    504    }
    505 
    506    /* viewport state: viewport matching window dims */
    507    {
    508       const GLboolean invert = st->state.fb_orientation == Y_0_TOP;
    509       const GLfloat width = (GLfloat)st->state.framebuffer.width;
    510       const GLfloat height = (GLfloat)st->state.framebuffer.height;
    511       struct pipe_viewport_state vp;
    512       vp.scale[0] =  0.5f * width;
    513       vp.scale[1] = height * (invert ? -0.5f : 0.5f);
    514       vp.scale[2] = 0.5f;
    515       vp.scale[3] = 1.0f;
    516       vp.translate[0] = 0.5f * width;
    517       vp.translate[1] = 0.5f * height;
    518       vp.translate[2] = 0.5f;
    519       vp.translate[3] = 0.0f;
    520       cso_set_viewport(cso, &vp);
    521    }
    522 
    523    cso_set_vertex_elements(cso, 3, st->velems_util_draw);
    524    cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
    525 
    526    /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
    527    z = z * 2.0f - 1.0f;
    528 
    529    /* draw textured quad */
    530    setup_bitmap_vertex_data(st, sv->texture->target != PIPE_TEXTURE_RECT,
    531 			    x, y, width, height, z, color, &vbuf, &offset);
    532 
    533    if (vbuf) {
    534       util_draw_vertex_buffer(pipe, st->cso_context, vbuf, offset,
    535                               PIPE_PRIM_TRIANGLE_FAN,
    536                               4,  /* verts */
    537                               3); /* attribs/vert */
    538    }
    539 
    540    /* restore state */
    541    cso_restore_rasterizer(cso);
    542    cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT);
    543    cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT);
    544    cso_restore_viewport(cso);
    545    cso_restore_fragment_shader(cso);
    546    cso_restore_vertex_shader(cso);
    547    cso_restore_geometry_shader(cso);
    548    cso_restore_vertex_elements(cso);
    549    cso_restore_vertex_buffers(cso);
    550    cso_restore_stream_outputs(cso);
    551 
    552    pipe_resource_reference(&vbuf, NULL);
    553 }
    554 
    555 
    556 static void
    557 reset_cache(struct st_context *st)
    558 {
    559    struct pipe_context *pipe = st->pipe;
    560    struct bitmap_cache *cache = st->bitmap.cache;
    561 
    562    /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/
    563    cache->empty = GL_TRUE;
    564 
    565    cache->xmin = 1000000;
    566    cache->xmax = -1000000;
    567    cache->ymin = 1000000;
    568    cache->ymax = -1000000;
    569 
    570    if (cache->trans) {
    571       pipe->transfer_destroy(pipe, cache->trans);
    572       cache->trans = NULL;
    573    }
    574 
    575    assert(!cache->texture);
    576 
    577    /* allocate a new texture */
    578    cache->texture = st_texture_create(st, PIPE_TEXTURE_2D,
    579                                       st->bitmap.tex_format, 0,
    580                                       BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
    581                                       1, 1,
    582 				      PIPE_BIND_SAMPLER_VIEW);
    583 }
    584 
    585 
    586 /** Print bitmap image to stdout (debug) */
    587 static void
    588 print_cache(const struct bitmap_cache *cache)
    589 {
    590    int i, j, k;
    591 
    592    for (i = 0; i < BITMAP_CACHE_HEIGHT; i++) {
    593       k = BITMAP_CACHE_WIDTH * (BITMAP_CACHE_HEIGHT - i - 1);
    594       for (j = 0; j < BITMAP_CACHE_WIDTH; j++) {
    595          if (cache->buffer[k])
    596             printf("X");
    597          else
    598             printf(" ");
    599          k++;
    600       }
    601       printf("\n");
    602    }
    603 }
    604 
    605 
    606 /**
    607  * Create gallium pipe_transfer object for the bitmap cache.
    608  */
    609 static void
    610 create_cache_trans(struct st_context *st)
    611 {
    612    struct pipe_context *pipe = st->pipe;
    613    struct bitmap_cache *cache = st->bitmap.cache;
    614 
    615    if (cache->trans)
    616       return;
    617 
    618    /* Map the texture transfer.
    619     * Subsequent glBitmap calls will write into the texture image.
    620     */
    621    cache->trans = pipe_get_transfer(st->pipe, cache->texture, 0, 0,
    622                                     PIPE_TRANSFER_WRITE, 0, 0,
    623                                     BITMAP_CACHE_WIDTH,
    624                                     BITMAP_CACHE_HEIGHT);
    625    cache->buffer = pipe_transfer_map(pipe, cache->trans);
    626 
    627    /* init image to all 0xff */
    628    memset(cache->buffer, 0xff, cache->trans->stride * BITMAP_CACHE_HEIGHT);
    629 }
    630 
    631 
    632 /**
    633  * If there's anything in the bitmap cache, draw/flush it now.
    634  */
    635 void
    636 st_flush_bitmap_cache(struct st_context *st)
    637 {
    638    if (!st->bitmap.cache->empty) {
    639       struct bitmap_cache *cache = st->bitmap.cache;
    640 
    641       struct pipe_context *pipe = st->pipe;
    642       struct pipe_sampler_view *sv;
    643 
    644       assert(cache->xmin <= cache->xmax);
    645 
    646 /*    printf("flush size %d x %d  at %d, %d\n",
    647              cache->xmax - cache->xmin,
    648              cache->ymax - cache->ymin,
    649              cache->xpos, cache->ypos);
    650 */
    651 
    652       /* The texture transfer has been mapped until now.
    653           * So unmap and release the texture transfer before drawing.
    654           */
    655       if (cache->trans) {
    656          if (0)
    657             print_cache(cache);
    658          pipe_transfer_unmap(pipe, cache->trans);
    659          cache->buffer = NULL;
    660 
    661          pipe->transfer_destroy(pipe, cache->trans);
    662          cache->trans = NULL;
    663       }
    664 
    665       sv = st_create_texture_sampler_view(st->pipe, cache->texture);
    666       if (sv) {
    667          draw_bitmap_quad(st->ctx,
    668                           cache->xpos,
    669                           cache->ypos,
    670                           cache->zpos,
    671                           BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
    672                           sv,
    673                           cache->color);
    674 
    675          pipe_sampler_view_reference(&sv, NULL);
    676       }
    677 
    678       /* release/free the texture */
    679       pipe_resource_reference(&cache->texture, NULL);
    680 
    681       reset_cache(st);
    682    }
    683 }
    684 
    685 
    686 /**
    687  * Try to accumulate this glBitmap call in the bitmap cache.
    688  * \return  GL_TRUE for success, GL_FALSE if bitmap is too large, etc.
    689  */
    690 static GLboolean
    691 accum_bitmap(struct st_context *st,
    692              GLint x, GLint y, GLsizei width, GLsizei height,
    693              const struct gl_pixelstore_attrib *unpack,
    694              const GLubyte *bitmap )
    695 {
    696    struct bitmap_cache *cache = st->bitmap.cache;
    697    int px = -999, py = -999;
    698    const GLfloat z = st->ctx->Current.RasterPos[2];
    699 
    700    if (width > BITMAP_CACHE_WIDTH ||
    701        height > BITMAP_CACHE_HEIGHT)
    702       return GL_FALSE; /* too big to cache */
    703 
    704    if (!cache->empty) {
    705       px = x - cache->xpos;  /* pos in buffer */
    706       py = y - cache->ypos;
    707       if (px < 0 || px + width > BITMAP_CACHE_WIDTH ||
    708           py < 0 || py + height > BITMAP_CACHE_HEIGHT ||
    709           !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color) ||
    710           ((fabs(z - cache->zpos) > Z_EPSILON))) {
    711          /* This bitmap would extend beyond cache bounds, or the bitmap
    712           * color is changing
    713           * so flush and continue.
    714           */
    715          st_flush_bitmap_cache(st);
    716       }
    717    }
    718 
    719    if (cache->empty) {
    720       /* Initialize.  Center bitmap vertically in the buffer. */
    721       px = 0;
    722       py = (BITMAP_CACHE_HEIGHT - height) / 2;
    723       cache->xpos = x;
    724       cache->ypos = y - py;
    725       cache->zpos = z;
    726       cache->empty = GL_FALSE;
    727       COPY_4FV(cache->color, st->ctx->Current.RasterColor);
    728    }
    729 
    730    assert(px != -999);
    731    assert(py != -999);
    732 
    733    if (x < cache->xmin)
    734       cache->xmin = x;
    735    if (y < cache->ymin)
    736       cache->ymin = y;
    737    if (x + width > cache->xmax)
    738       cache->xmax = x + width;
    739    if (y + height > cache->ymax)
    740       cache->ymax = y + height;
    741 
    742    /* create the transfer if needed */
    743    create_cache_trans(st);
    744 
    745    unpack_bitmap(st, px, py, width, height, unpack, bitmap,
    746                  cache->buffer, BITMAP_CACHE_WIDTH);
    747 
    748    return GL_TRUE; /* accumulated */
    749 }
    750 
    751 
    752 
    753 /**
    754  * Called via ctx->Driver.Bitmap()
    755  */
    756 static void
    757 st_Bitmap(struct gl_context *ctx, GLint x, GLint y,
    758           GLsizei width, GLsizei height,
    759           const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
    760 {
    761    struct st_context *st = st_context(ctx);
    762    struct pipe_resource *pt;
    763 
    764    if (width == 0 || height == 0)
    765       return;
    766 
    767    st_validate_state(st);
    768 
    769    if (!st->bitmap.vs) {
    770       /* create pass-through vertex shader now */
    771       const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
    772                                       TGSI_SEMANTIC_COLOR,
    773                                       TGSI_SEMANTIC_GENERIC };
    774       const uint semantic_indexes[] = { 0, 0, 0 };
    775       st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3,
    776                                                           semantic_names,
    777                                                           semantic_indexes);
    778    }
    779 
    780    if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap))
    781       return;
    782 
    783    pt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
    784    if (pt) {
    785       struct pipe_sampler_view *sv =
    786          st_create_texture_sampler_view(st->pipe, pt);
    787 
    788       assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT);
    789 
    790       if (sv) {
    791          draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2],
    792                           width, height, sv,
    793                           st->ctx->Current.RasterColor);
    794 
    795          pipe_sampler_view_reference(&sv, NULL);
    796       }
    797 
    798       /* release/free the texture */
    799       pipe_resource_reference(&pt, NULL);
    800    }
    801 }
    802 
    803 
    804 /** Per-context init */
    805 void
    806 st_init_bitmap_functions(struct dd_function_table *functions)
    807 {
    808    functions->Bitmap = st_Bitmap;
    809 }
    810 
    811 
    812 /** Per-context init */
    813 void
    814 st_init_bitmap(struct st_context *st)
    815 {
    816    struct pipe_sampler_state *sampler = &st->bitmap.samplers[0];
    817    struct pipe_context *pipe = st->pipe;
    818    struct pipe_screen *screen = pipe->screen;
    819 
    820    /* init sampler state once */
    821    memset(sampler, 0, sizeof(*sampler));
    822    sampler->wrap_s = PIPE_TEX_WRAP_CLAMP;
    823    sampler->wrap_t = PIPE_TEX_WRAP_CLAMP;
    824    sampler->wrap_r = PIPE_TEX_WRAP_CLAMP;
    825    sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST;
    826    sampler->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    827    sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    828    st->bitmap.samplers[1] = *sampler;
    829    st->bitmap.samplers[1].normalized_coords = 1;
    830 
    831    /* init baseline rasterizer state once */
    832    memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer));
    833    st->bitmap.rasterizer.gl_rasterization_rules = 1;
    834    st->bitmap.rasterizer.depth_clip = 1;
    835 
    836    /* find a usable texture format */
    837    if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM,
    838                                    PIPE_TEXTURE_2D, 0,
    839                                    PIPE_BIND_SAMPLER_VIEW)) {
    840       st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM;
    841    }
    842    else if (screen->is_format_supported(screen, PIPE_FORMAT_A8_UNORM,
    843                                         PIPE_TEXTURE_2D, 0,
    844                                         PIPE_BIND_SAMPLER_VIEW)) {
    845       st->bitmap.tex_format = PIPE_FORMAT_A8_UNORM;
    846    }
    847    else if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM,
    848                                         PIPE_TEXTURE_2D, 0,
    849                                         PIPE_BIND_SAMPLER_VIEW)) {
    850       st->bitmap.tex_format = PIPE_FORMAT_L8_UNORM;
    851    }
    852    else {
    853       /* XXX support more formats */
    854       assert(0);
    855    }
    856 
    857    /* alloc bitmap cache object */
    858    st->bitmap.cache = ST_CALLOC_STRUCT(bitmap_cache);
    859 
    860    reset_cache(st);
    861 }
    862 
    863 
    864 /** Per-context tear-down */
    865 void
    866 st_destroy_bitmap(struct st_context *st)
    867 {
    868    struct pipe_context *pipe = st->pipe;
    869    struct bitmap_cache *cache = st->bitmap.cache;
    870 
    871    if (st->bitmap.vs) {
    872       cso_delete_vertex_shader(st->cso_context, st->bitmap.vs);
    873       st->bitmap.vs = NULL;
    874    }
    875 
    876    if (cache) {
    877       if (cache->trans) {
    878          pipe_transfer_unmap(pipe, cache->trans);
    879          pipe->transfer_destroy(pipe, cache->trans);
    880       }
    881       pipe_resource_reference(&st->bitmap.cache->texture, NULL);
    882       free(st->bitmap.cache);
    883       st->bitmap.cache = NULL;
    884    }
    885 }
    886 
    887 #endif /* FEATURE_drawpix */
    888