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