Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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