st_cb_drawpixels.c revision 7de874ec2c7b9e3aff7f81b7e30045b45381fbad
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/macros.h"
36
37#include "st_context.h"
38#include "st_atom.h"
39#include "st_cache.h"
40#include "st_draw.h"
41#include "st_program.h"
42#include "st_cb_drawpixels.h"
43#include "st_cb_readpixels.h"
44#include "st_cb_fbo.h"
45#include "st_cb_texture.h"
46#include "st_draw.h"
47#include "st_format.h"
48#include "st_mesa_to_tgsi.h"
49#include "pipe/p_context.h"
50#include "pipe/p_defines.h"
51#include "pipe/p_inlines.h"
52#include "pipe/p_winsys.h"
53#include "shader/prog_instruction.h"
54
55
56
57/**
58 * Create a simple fragment shader that does a TEX() instruction to get
59 * the fragment color.
60 * If bitmapMode, use KIL instruction to kill the "0-pixels".
61 */
62static struct st_fragment_program *
63make_fragment_shader(struct st_context *st, GLboolean bitmapMode)
64{
65   /* only make programs once and re-use */
66   static struct st_fragment_program *progs[2] = { NULL, NULL };
67   GLcontext *ctx = st->ctx;
68   struct st_fragment_program *stfp;
69   struct gl_program *p;
70   GLuint ic = 0;
71
72   if (progs[bitmapMode])
73      return progs[bitmapMode];
74
75   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
76   if (!p)
77      return NULL;
78
79   if (bitmapMode)
80      p->NumInstructions = 6;
81   else
82      p->NumInstructions = 2;
83
84   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
85   if (!p->Instructions) {
86      ctx->Driver.DeleteProgram(ctx, p);
87      return NULL;
88   }
89   _mesa_init_instructions(p->Instructions, p->NumInstructions);
90   if (bitmapMode) {
91      /*
92       * XXX, we need to compose this fragment shader with the current
93       * user-provided fragment shader so the fragment program is applied
94       * to the fragments which aren't culled.
95       */
96      /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
97      p->Instructions[ic].Opcode = OPCODE_TEX;
98      p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
99      p->Instructions[ic].DstReg.Index = 0;
100      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
101      p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
102      p->Instructions[ic].TexSrcUnit = 0;
103      p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
104      ic++;
105
106      /* SWZ tmp0.x, tmp0.x, 1111; # tmp0.x = 1.0 */
107      p->Instructions[ic].Opcode = OPCODE_SWZ;
108      p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
109      p->Instructions[ic].DstReg.Index = 0;
110      p->Instructions[ic].DstReg.WriteMask = WRITEMASK_X;
111      p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
112      p->Instructions[ic].SrcReg[0].Index = 0;
113      p->Instructions[ic].SrcReg[0].Swizzle
114         = MAKE_SWIZZLE4(SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE );
115      ic++;
116
117      /* SUB tmp0, tmp0.wwww, tmp0.xxxx;  #  tmp0.w -= 1 */
118      p->Instructions[ic].Opcode = OPCODE_SUB;
119      p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
120      p->Instructions[ic].DstReg.Index = 0;
121      p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
122      p->Instructions[ic].SrcReg[0].Index = 0;
123      p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_WWWW;
124      p->Instructions[ic].SrcReg[1].File = PROGRAM_TEMPORARY;
125      p->Instructions[ic].SrcReg[1].Index = 0;
126      p->Instructions[ic].SrcReg[1].Swizzle = SWIZZLE_XXXX; /* 1.0 */
127      ic++;
128
129      /* KIL if tmp0 < 0 */
130      p->Instructions[ic].Opcode = OPCODE_KIL;
131      p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
132      p->Instructions[ic].SrcReg[0].Index = 0;
133      ic++;
134
135      /* MOV result.color, fragment.color */
136      p->Instructions[ic].Opcode = OPCODE_MOV;
137      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
138      p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
139      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
140      p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
141      ic++;
142   }
143   else {
144      /* DrawPixels mode */
145      /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
146      p->Instructions[ic].Opcode = OPCODE_TEX;
147      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
148      p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
149      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
150      p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
151      p->Instructions[ic].TexSrcUnit = 0;
152      p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
153      ic++;
154   }
155   /* END; */
156   p->Instructions[ic++].Opcode = OPCODE_END;
157
158   assert(ic == p->NumInstructions);
159
160   p->InputsRead = FRAG_BIT_TEX0;
161   p->OutputsWritten = (1 << FRAG_RESULT_COLR);
162   if (bitmapMode) {
163      p->InputsRead |= FRAG_BIT_COL0;
164   }
165
166   stfp = (struct st_fragment_program *) p;
167   st_translate_fragment_program(st, stfp, NULL,
168                                 stfp->tokens, ST_MAX_SHADER_TOKENS);
169
170   progs[bitmapMode] = stfp;
171
172   return stfp;
173}
174
175
176/**
177 * Create fragment shader that does a TEX() instruction to get a Z
178 * value, then writes to FRAG_RESULT_DEPR.
179 * Pass fragment color through as-is.
180 */
181static struct st_fragment_program *
182make_fragment_shader_z(struct st_context *st)
183{
184   GLcontext *ctx = st->ctx;
185   /* only make programs once and re-use */
186   static struct st_fragment_program *stfp = NULL;
187   struct gl_program *p;
188   GLuint ic = 0;
189
190   if (stfp)
191      return stfp;
192
193   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
194   if (!p)
195      return NULL;
196
197   p->NumInstructions = 3;
198
199   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
200   if (!p->Instructions) {
201      ctx->Driver.DeleteProgram(ctx, p);
202      return NULL;
203   }
204   _mesa_init_instructions(p->Instructions, p->NumInstructions);
205
206   /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
207   p->Instructions[ic].Opcode = OPCODE_TEX;
208   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
209   p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR;
210   p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
211   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
212   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
213   p->Instructions[ic].TexSrcUnit = 0;
214   p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
215   ic++;
216
217   /* MOV result.color, fragment.color */
218   p->Instructions[ic].Opcode = OPCODE_MOV;
219   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
220   p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
221   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
222   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
223   ic++;
224
225   /* END; */
226   p->Instructions[ic++].Opcode = OPCODE_END;
227
228   assert(ic == p->NumInstructions);
229
230   p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
231   p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR);
232
233   stfp = (struct st_fragment_program *) p;
234   st_translate_fragment_program(st, stfp, NULL,
235                                 stfp->tokens, ST_MAX_SHADER_TOKENS);
236
237   return stfp;
238}
239
240
241
242/**
243 * Create a simple vertex shader that just passes through the
244 * vertex position and texcoord (and optionally, color).
245 */
246static struct st_vertex_program *
247make_vertex_shader(struct st_context *st, GLboolean passColor)
248{
249   /* only make programs once and re-use */
250   static struct st_vertex_program *progs[2] = { NULL, NULL };
251   GLcontext *ctx = st->ctx;
252   struct st_vertex_program *stvp;
253   struct gl_program *p;
254   GLuint ic = 0;
255
256   if (progs[passColor])
257      return progs[passColor];
258
259   p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
260   if (!p)
261      return NULL;
262
263   if (passColor)
264      p->NumInstructions = 4;
265   else
266      p->NumInstructions = 3;
267
268   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
269   if (!p->Instructions) {
270      ctx->Driver.DeleteProgram(ctx, p);
271      return NULL;
272   }
273   _mesa_init_instructions(p->Instructions, p->NumInstructions);
274   /* MOV result.pos, vertex.pos; */
275   p->Instructions[0].Opcode = OPCODE_MOV;
276   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
277   p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
278   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
279   p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
280   /* MOV result.texcoord0, vertex.texcoord0; */
281   p->Instructions[1].Opcode = OPCODE_MOV;
282   p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
283   p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
284   p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
285   p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
286   ic = 2;
287   if (passColor) {
288      /* MOV result.color0, vertex.color0; */
289      p->Instructions[ic].Opcode = OPCODE_MOV;
290      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
291      p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
292      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
293      p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
294      ic++;
295   }
296
297   /* END; */
298   p->Instructions[ic].Opcode = OPCODE_END;
299   ic++;
300
301   assert(ic == p->NumInstructions);
302
303   p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
304   p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
305                        (1 << VERT_RESULT_HPOS));
306   if (passColor) {
307      p->InputsRead |= VERT_BIT_COLOR0;
308      p->OutputsWritten |= (1 << VERT_RESULT_COL0);
309   }
310
311   stvp = (struct st_vertex_program *) p;
312   st_translate_vertex_program(st, stvp, NULL,
313                               stvp->tokens, ST_MAX_SHADER_TOKENS);
314
315   progs[passColor] = stvp;
316
317   return stvp;
318}
319
320
321static GLenum
322_mesa_base_format(GLenum format)
323{
324   switch (format) {
325   case GL_DEPTH_COMPONENT:
326      return GL_DEPTH_COMPONENT;
327   case GL_STENCIL_INDEX:
328      return GL_STENCIL_INDEX;
329   default:
330      return GL_RGBA;
331   }
332}
333
334
335
336static struct pipe_mipmap_tree *
337alloc_mipmap_tree(struct st_context *st,
338                  GLsizei width, GLsizei height, uint pipeFormat)
339{
340   const GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE;
341   struct pipe_mipmap_tree *mt;
342   GLuint cpp;
343
344   mt = CALLOC_STRUCT(pipe_mipmap_tree);
345   if (!mt)
346      return NULL;
347
348   cpp = st_sizeof_format(pipeFormat);
349
350   /* allocate texture region/storage */
351   mt->region = st->pipe->winsys->region_alloc(st->pipe->winsys,
352                                               cpp, width, height, flags);
353
354   mt->target = PIPE_TEXTURE_2D;
355   mt->internal_format = GL_RGBA;
356   mt->format = pipeFormat;
357   mt->first_level = 0;
358   mt->last_level = 0;
359   mt->width0 = width;
360   mt->height0 = height;
361   mt->depth0 = 1;
362   mt->cpp = cpp;
363   mt->compressed = 0;
364   mt->pitch = mt->region->pitch;
365   mt->depth_pitch = 0;
366   mt->total_height = height;
367   mt->level[0].level_offset = 0;
368   mt->level[0].width = width;
369   mt->level[0].height = height;
370   mt->level[0].depth = 1;
371   mt->level[0].nr_images = 1;
372   mt->level[0].image_offset = NULL;
373   mt->refcount = 1;
374
375   return mt;
376}
377
378
379/**
380 * Make mipmap tree containing an image for glDrawPixels image.
381 * If 'pixels' is NULL, leave the texture image data undefined.
382 */
383static struct pipe_mipmap_tree *
384make_mipmap_tree(struct st_context *st,
385                 GLsizei width, GLsizei height, GLenum format, GLenum type,
386                 const struct gl_pixelstore_attrib *unpack,
387                 const GLvoid *pixels)
388{
389   struct pipe_context *pipe = st->pipe;
390   const struct gl_texture_format *mformat;
391   struct pipe_mipmap_tree *mt;
392   GLuint pipeFormat, cpp;
393   GLenum baseFormat;
394
395   baseFormat = _mesa_base_format(format);
396
397   mformat = st_ChooseTextureFormat(st->ctx, baseFormat, format, type);
398   assert(mformat);
399
400   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
401   assert(pipeFormat);
402   cpp = st_sizeof_format(pipeFormat);
403
404   mt = alloc_mipmap_tree(st, width, height, pipeFormat);
405   if (!mt)
406      return NULL;
407
408   if (unpack->BufferObj && unpack->BufferObj->Name) {
409      /*
410      mt->region = buffer_object_region(unpack->BufferObj);
411      */
412      printf("st_DrawPixels (sourcing from PBO not implemented yet)\n");
413   }
414
415   {
416      static const GLuint dstImageOffsets = 0;
417      GLboolean success;
418      GLuint pitch = mt->region->pitch;
419      GLubyte *dest;
420
421      /* map texture region */
422      dest = pipe->region_map(pipe, mt->region);
423
424      /* Put image into texture region.
425       * Note that the image is actually going to be upside down in
426       * the texture.  We deal with that with texcoords.
427       */
428      success = mformat->StoreImage(st->ctx, 2,       /* dims */
429                                    baseFormat,       /* baseInternalFormat */
430                                    mformat,          /* gl_texture_format */
431                                    dest,             /* dest */
432                                    0, 0, 0,          /* dstX/Y/Zoffset */
433                                    pitch * cpp,      /* dstRowStride, bytes */
434                                    &dstImageOffsets, /* dstImageOffsets */
435                                    width, height, 1, /* size */
436                                    format, type,     /* src format/type */
437                                    pixels,           /* data source */
438                                    unpack);
439
440      /* unmap */
441      pipe->region_unmap(pipe, mt->region);
442      assert(success);
443   }
444
445#if 0
446   mt->target = PIPE_TEXTURE_2D;
447   mt->internal_format = GL_RGBA;
448   mt->format = pipeFormat;
449   mt->first_level = 0;
450   mt->last_level = 0;
451   mt->width0 = width;
452   mt->height0 = height;
453   mt->depth0 = 1;
454   mt->cpp = cpp;
455   mt->compressed = 0;
456   mt->pitch = mt->region->pitch;
457   mt->depth_pitch = 0;
458   mt->total_height = height;
459   mt->level[0].level_offset = 0;
460   mt->level[0].width = width;
461   mt->level[0].height = height;
462   mt->level[0].depth = 1;
463   mt->level[0].nr_images = 1;
464   mt->level[0].image_offset = NULL;
465   mt->refcount = 1;
466#endif
467   return mt;
468}
469
470
471static void
472free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
473{
474   pipe->winsys->region_release(pipe->winsys, &mt->region);
475   free(mt);
476}
477
478
479/**
480 * Draw textured quad.
481 * Coords are window coords with y=0=bottom.
482 */
483static void
484draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
485          GLfloat x1, GLfloat y1, GLboolean invertTex)
486{
487   GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
488   GLuint i;
489   GLfloat tTop = invertTex, tBot = 1.0 - tTop;
490
491   /* upper-left */
492   verts[0][0][0] = x0;    /* attr[0].x */
493   verts[0][0][1] = y0;    /* attr[0].x */
494   verts[0][1][0] = 0.0;   /* attr[1].s */
495   verts[0][1][1] = tTop;  /* attr[1].t */
496
497   /* upper-right */
498   verts[1][0][0] = x1;
499   verts[1][0][1] = y0;
500   verts[1][1][0] = 1.0;
501   verts[1][1][1] = tTop;
502
503   /* lower-right */
504   verts[2][0][0] = x1;
505   verts[2][0][1] = y1;
506   verts[2][1][0] = 1.0;
507   verts[2][1][1] = tBot;
508
509   /* lower-left */
510   verts[3][0][0] = x0;
511   verts[3][0][1] = y1;
512   verts[3][1][0] = 0.0;
513   verts[3][1][1] = tBot;
514
515   /* same for all verts: */
516   for (i = 0; i < 4; i++) {
517      verts[i][0][2] = z;   /*Z*/
518      verts[i][0][3] = 1.0; /*W*/
519      verts[i][1][2] = 0.0; /*R*/
520      verts[i][1][3] = 1.0; /*Q*/
521   }
522
523   st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2);
524}
525
526
527static void
528draw_quad_colored(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
529                  GLfloat x1, GLfloat y1, const GLfloat *color,
530                  GLboolean invertTex)
531{
532   GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
533   GLuint i;
534   GLfloat tTop = invertTex, tBot = 1.0 - tTop;
535
536   /* upper-left */
537   verts[0][0][0] = x0;    /* attr[0].x */
538   verts[0][0][1] = y0;    /* attr[0].y */
539   verts[0][2][0] = 0.0;   /* attr[2].s */
540   verts[0][2][1] = tTop;  /* attr[2].t */
541
542   /* upper-right */
543   verts[1][0][0] = x1;
544   verts[1][0][1] = y0;
545   verts[1][2][0] = 1.0;
546   verts[1][2][1] = tTop;
547
548   /* lower-right */
549   verts[2][0][0] = x1;
550   verts[2][0][1] = y1;
551   verts[2][2][0] = 1.0;
552   verts[2][2][1] = tBot;
553
554   /* lower-left */
555   verts[3][0][0] = x0;
556   verts[3][0][1] = y1;
557   verts[3][2][0] = 0.0;
558   verts[3][2][1] = tBot;
559
560   /* same for all verts: */
561   for (i = 0; i < 4; i++) {
562      verts[i][0][2] = z;   /*Z*/
563      verts[i][0][3] = 1.0; /*W*/
564      verts[i][1][0] = color[0];
565      verts[i][1][1] = color[1];
566      verts[i][1][2] = color[2];
567      verts[i][1][3] = color[3];
568      verts[i][2][2] = 0.0; /*R*/
569      verts[i][2][3] = 1.0; /*Q*/
570   }
571
572   st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 3);
573}
574
575
576
577static void
578draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
579                   GLsizei width, GLsizei height,
580                   GLfloat zoomX, GLfloat zoomY,
581                   struct pipe_mipmap_tree *mt,
582                   struct st_vertex_program *stvp,
583                   struct st_fragment_program *stfp,
584                   const GLfloat *color,
585                   GLboolean invertTex)
586{
587   const GLuint unit = 0;
588   struct pipe_context *pipe = ctx->st->pipe;
589   GLfloat x0, y0, x1, y1;
590   GLuint maxWidth, maxHeight;
591
592   /* limit checks */
593   /* XXX if DrawPixels image is larger than max texture size, break
594    * it up into chunks.
595    */
596   pipe->max_texture_size(pipe, PIPE_TEXTURE_2D, &maxWidth, &maxHeight, NULL);
597   assert(width <= maxWidth);
598   assert(height <= maxHeight);
599
600   /* setup state: just scissor */
601   {
602      struct pipe_rasterizer_state  setup;
603      const struct cso_rasterizer  *cso;
604      memset(&setup, 0, sizeof(setup));
605      if (ctx->Scissor.Enabled)
606         setup.scissor = 1;
607      cso = st_cached_rasterizer_state(ctx->st, &setup);
608      pipe->bind_rasterizer_state(pipe, cso->data);
609   }
610
611   /* fragment shader state: TEX lookup program */
612   pipe->bind_fs_state(pipe, stfp->fs->data);
613
614   /* vertex shader state: position + texcoord pass-through */
615   pipe->bind_vs_state(pipe, stvp->vs->data);
616
617   /* texture sampling state: */
618   {
619      struct pipe_sampler_state sampler;
620      const struct cso_sampler *cso;
621      memset(&sampler, 0, sizeof(sampler));
622      sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
623      sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
624      sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
625      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
626      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
627      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
628      sampler.normalized_coords = 1;
629      cso = st_cached_sampler_state(ctx->st, &sampler);
630      pipe->bind_sampler_state(pipe, unit, cso->data);
631   }
632
633   /* viewport state: viewport matching window dims */
634   {
635      const float width = ctx->DrawBuffer->Width;
636      const float height = ctx->DrawBuffer->Height;
637      struct pipe_viewport_state vp;
638      vp.scale[0] =  0.5 * width;
639      vp.scale[1] = -0.5 * height;
640      vp.scale[2] = 1.0;
641      vp.scale[3] = 1.0;
642      vp.translate[0] = 0.5 * width;
643      vp.translate[1] = 0.5 * height;
644      vp.translate[2] = 0.0;
645      vp.translate[3] = 0.0;
646      pipe->set_viewport_state(pipe, &vp);
647   }
648
649   /* mipmap tree state: */
650   {
651      pipe->set_texture_state(pipe, unit, mt);
652   }
653
654   /* Compute window coords (y=0=bottom) with pixel zoom.
655    * Recall that these coords are transformed by the current
656    * vertex shader and viewport transformation.
657    */
658   x0 = x;
659   x1 = x + width * ctx->Pixel.ZoomX;
660   y0 = y;
661   y1 = y + height * ctx->Pixel.ZoomY;
662
663   /* draw textured quad */
664   if (color)
665      draw_quad_colored(ctx, x0, y0, z, x1, y1, color, invertTex);
666   else
667      draw_quad(ctx, x0, y0, z, x1, y1, invertTex);
668
669   /* restore GL state */
670   pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer->data);
671   pipe->bind_fs_state(pipe, ctx->st->state.fs->data);
672   pipe->bind_vs_state(pipe, ctx->st->state.vs->data);
673   pipe->set_texture_state(pipe, unit, ctx->st->state.texture[unit]);
674   pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]->data);
675   pipe->set_viewport_state(pipe, &ctx->st->state.viewport);
676}
677
678
679/**
680 * Check if a GL format/type combination is a match to the given pipe format.
681 * XXX probably move this to a re-usable place.
682 */
683static GLboolean
684compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
685{
686   static const GLuint one = 1;
687   GLubyte littleEndian = *((GLubyte *) &one);
688
689   if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
690       format == GL_RGBA &&
691       type == GL_UNSIGNED_BYTE &&
692       !littleEndian) {
693      return GL_TRUE;
694   }
695   else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
696            format == GL_ABGR_EXT &&
697            type == GL_UNSIGNED_BYTE &&
698            littleEndian) {
699      return GL_TRUE;
700   }
701   else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
702            format == GL_BGRA &&
703            type == GL_UNSIGNED_BYTE &&
704            littleEndian) {
705      return GL_TRUE;
706   }
707   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
708            format == GL_RGB &&
709            type == GL_UNSIGNED_SHORT_5_6_5) {
710      /* endian don't care */
711      return GL_TRUE;
712   }
713   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
714            format == GL_BGR &&
715            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
716      /* endian don't care */
717      return GL_TRUE;
718   }
719   else if (pipeFormat == PIPE_FORMAT_U_S8 &&
720            format == GL_STENCIL_INDEX &&
721            type == GL_UNSIGNED_BYTE) {
722      return GL_TRUE;
723   }
724   else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
725            format == GL_DEPTH_COMPONENT &&
726            type == GL_UNSIGNED_INT) {
727      return GL_TRUE;
728   }
729   /* XXX add more cases */
730   else {
731      return GL_FALSE;
732   }
733}
734
735
736/**
737 * Check if any per-fragment ops are enabled.
738 * XXX probably move this to a re-usable place.
739 */
740static GLboolean
741any_fragment_ops(const struct st_context *st)
742{
743   if (st->state.alpha_test->state.enabled ||
744       st->state.blend->state.blend_enable ||
745       st->state.blend->state.logicop_enable ||
746       st->state.depth_stencil->state.depth.enabled)
747      /* XXX more checks */
748      return GL_TRUE;
749   else
750      return GL_FALSE;
751}
752
753
754/**
755 * Check if any pixel transfer ops are enabled.
756 * XXX probably move this to a re-usable place.
757 */
758static GLboolean
759any_pixel_transfer_ops(const struct st_context *st)
760{
761   if (st->ctx->Pixel.RedScale != 1.0 ||
762       st->ctx->Pixel.RedBias != 0.0 ||
763       st->ctx->Pixel.GreenScale != 1.0 ||
764       st->ctx->Pixel.GreenBias != 0.0 ||
765       st->ctx->Pixel.BlueScale != 1.0 ||
766       st->ctx->Pixel.BlueBias != 0.0 ||
767       st->ctx->Pixel.AlphaScale != 1.0 ||
768       st->ctx->Pixel.AlphaBias != 0.0 ||
769       st->ctx->Pixel.MapColorFlag)
770      /* XXX more checks */
771      return GL_TRUE;
772   else
773      return GL_FALSE;
774}
775
776
777/**
778 * Draw image with a blit, or other non-textured quad method.
779 */
780static void
781draw_blit(struct st_context *st,
782          GLsizei width, GLsizei height,
783          GLenum format, GLenum type, const GLvoid *pixels)
784{
785
786
787}
788
789
790static void
791draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
792                    GLsizei width, GLsizei height, GLenum type,
793                    const struct gl_pixelstore_attrib *unpack,
794                    const GLvoid *pixels)
795{
796   struct st_context *st = ctx->st;
797   struct pipe_context *pipe = st->pipe;
798   struct pipe_surface *ps = st->state.framebuffer.sbuf;
799   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
800   GLint skipPixels;
801   ubyte *stmap;
802
803   pipe->flush(pipe, 0);
804
805   /* map the stencil buffer */
806   stmap = pipe->region_map(pipe, ps->region);
807
808   /* if width > MAX_WIDTH, have to process image in chunks */
809   skipPixels = 0;
810   while (skipPixels < width) {
811      const GLint spanX = x + skipPixels;
812      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
813      GLint row;
814      for (row = 0; row < height; row++) {
815         GLint spanY = y + row;
816         GLubyte values[MAX_WIDTH];
817         GLenum destType = GL_UNSIGNED_BYTE;
818         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
819                                                      width, height,
820                                                      GL_COLOR_INDEX, type,
821                                                      row, skipPixels);
822         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
823                                   type, source, unpack,
824                                   ctx->_ImageTransferState);
825         if (zoom) {
826            /*
827            _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
828                                              spanX, spanY, values);
829            */
830         }
831         else {
832            if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
833               spanY = ctx->DrawBuffer->Height - spanY - 1;
834            }
835
836            switch (ps->format) {
837            case PIPE_FORMAT_U_S8:
838               {
839                  ubyte *dest = stmap + spanY * ps->region->pitch + spanX;
840                  memcpy(dest, values, spanWidth);
841               }
842               break;
843            case PIPE_FORMAT_S8_Z24:
844               {
845                  uint *dest = (uint *) stmap + spanY * ps->region->pitch + spanX;
846                  GLint k;
847                  for (k = 0; k < spanWidth; k++) {
848                     uint p = dest[k];
849                     p = (p & 0xffffff) | (values[k] << 24);
850                     dest[k] = p;
851                  }
852               }
853               break;
854            default:
855               assert(0);
856            }
857         }
858      }
859      skipPixels += spanWidth;
860   }
861
862   /* unmap the stencil buffer */
863   pipe->region_unmap(pipe, ps->region);
864}
865
866
867/**
868 * Called via ctx->Driver.DrawPixels()
869 */
870static void
871st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
872              GLenum format, GLenum type,
873              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
874{
875   struct st_fragment_program *stfp;
876   struct st_vertex_program *stvp;
877   struct st_context *st = ctx->st;
878   struct pipe_surface *ps;
879   GLuint bufferFormat;
880   const GLfloat *color;
881
882   if (format == GL_STENCIL_INDEX) {
883      draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
884      return;
885   }
886
887   st_validate_state(st);
888
889   if (format == GL_DEPTH_COMPONENT) {
890      ps = st->state.framebuffer.zbuf;
891      stfp = make_fragment_shader_z(ctx->st);
892      stvp = make_vertex_shader(ctx->st, GL_TRUE);
893      color = ctx->Current.RasterColor;
894   }
895   else if (format == GL_STENCIL_INDEX) {
896      ps = st->state.framebuffer.sbuf;
897      /* XXX special case - can't use texture map */
898      color = NULL;
899   }
900   else {
901      ps = st->state.framebuffer.cbufs[0];
902      stfp = make_fragment_shader(ctx->st, GL_FALSE);
903      stvp = make_vertex_shader(ctx->st, GL_FALSE);
904      color = NULL;
905   }
906
907   bufferFormat = ps->format;
908
909   if (any_fragment_ops(st) ||
910       any_pixel_transfer_ops(st) ||
911       !compatible_formats(format, type, ps->format)) {
912      /* textured quad */
913      struct pipe_mipmap_tree *mt
914         = make_mipmap_tree(ctx->st, width, height, format, type,
915                            unpack, pixels);
916      if (mt) {
917         draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
918                            width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
919                            mt, stvp, stfp, color, GL_FALSE);
920         free_mipmap_tree(st->pipe, mt);
921      }
922   }
923   else {
924      /* blit */
925      draw_blit(st, width, height, format, type, pixels);
926   }
927}
928
929
930
931/**
932 * Create a texture which represents a bitmap image.
933 */
934static struct pipe_mipmap_tree *
935make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height,
936                    const struct gl_pixelstore_attrib *unpack,
937                    const GLubyte *bitmap)
938{
939   struct pipe_context *pipe = ctx->st->pipe;
940   const uint flags = PIPE_SURFACE_FLAG_TEXTURE;
941   uint format = 0, cpp, comp, pitch;
942   ubyte *dest;
943   struct pipe_mipmap_tree *mt;
944   int row, col;
945
946   /* find a texture format we know */
947   if (pipe->is_format_supported( pipe, PIPE_FORMAT_U_I8 )) {
948      format = PIPE_FORMAT_U_I8;
949      cpp = 1;
950      comp = 0;
951   }
952   else if (pipe->is_format_supported( pipe, PIPE_FORMAT_U_A8_R8_G8_B8 )) {
953      format = PIPE_FORMAT_U_A8_R8_G8_B8;
954      cpp = 4;
955      comp = 3; /* alpha channel */ /*XXX little-endian dependency */
956   }
957   else {
958      /* XXX support more formats */
959      assert( 0 );
960   }
961
962   /**
963    * Create a mipmap tree.
964    */
965   mt = CALLOC_STRUCT(pipe_mipmap_tree);
966   if (!mt)
967      return NULL;
968
969   if (unpack->BufferObj && unpack->BufferObj->Name) {
970      /*
971      mt->region = buffer_object_region(unpack->BufferObj);
972      */
973      printf("st_Bitmap (sourcing from PBO not implemented yet)\n");
974   }
975
976
977   /* allocate texture region/storage */
978   mt->region = pipe->winsys->region_alloc(pipe->winsys,
979                                           cpp, width, height, flags);
980   pitch = mt->region->pitch;
981
982   /* map texture region */
983   dest = pipe->region_map(pipe, mt->region);
984   if (!dest) {
985      printf("st_Bitmap region_map() failed!?!");
986      return NULL;
987   }
988
989   /* Put image into texture region.
990    * Note that the image is actually going to be upside down in
991    * the texture.  We deal with that with texcoords.
992    */
993
994   for (row = 0; row < height; row++) {
995      const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
996                 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
997      ubyte *destRow = dest + row * pitch * cpp;
998
999      if (unpack->LsbFirst) {
1000         /* Lsb first */
1001         GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
1002         for (col = 0; col < width; col++) {
1003
1004            /* set texel to 255 if bit is set */
1005            destRow[comp] = (*src & mask) ? 255 : 0;
1006            destRow += cpp;
1007
1008            if (mask == 128U) {
1009               src++;
1010               mask = 1U;
1011            }
1012            else {
1013               mask = mask << 1;
1014            }
1015         }
1016
1017         /* get ready for next row */
1018         if (mask != 1)
1019            src++;
1020      }
1021      else {
1022         /* Msb first */
1023         GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
1024         for (col = 0; col < width; col++) {
1025
1026            /* set texel to 255 if bit is set */
1027            destRow[comp] =(*src & mask) ? 255 : 0;
1028            destRow += cpp;
1029
1030            if (mask == 1U) {
1031               src++;
1032               mask = 128U;
1033            }
1034            else {
1035               mask = mask >> 1;
1036            }
1037         }
1038
1039         /* get ready for next row */
1040         if (mask != 128)
1041            src++;
1042      }
1043
1044   } /* row */
1045
1046   /* unmap */
1047   pipe->region_unmap(pipe, mt->region);
1048
1049   mt->target = PIPE_TEXTURE_2D;
1050   mt->internal_format = GL_RGBA;
1051   mt->format = format;
1052   mt->first_level = 0;
1053   mt->last_level = 0;
1054   mt->width0 = width;
1055   mt->height0 = height;
1056   mt->depth0 = 1;
1057   mt->cpp = cpp;
1058   mt->compressed = 0;
1059   mt->pitch = mt->region->pitch;
1060   mt->depth_pitch = 0;
1061   mt->total_height = height;
1062   mt->level[0].level_offset = 0;
1063   mt->level[0].width = width;
1064   mt->level[0].height = height;
1065   mt->level[0].depth = 1;
1066   mt->level[0].nr_images = 1;
1067   mt->level[0].image_offset = NULL;
1068   mt->refcount = 1;
1069
1070   return mt;
1071}
1072
1073
1074
1075static void
1076st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
1077          const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
1078{
1079   struct st_vertex_program *stvp;
1080   struct st_fragment_program *stfp;
1081   struct st_context *st = ctx->st;
1082   struct pipe_mipmap_tree *mt;
1083
1084   /* create the fragment program */
1085   stfp = make_fragment_shader(ctx->st, GL_TRUE);
1086
1087   /* and vertex program */
1088   stvp = make_vertex_shader(ctx->st, GL_TRUE);
1089
1090   st_validate_state(st);
1091
1092   mt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
1093   if (mt) {
1094      draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
1095                         width, height, 1.0, 1.0,
1096                         mt, stvp, stfp,
1097                         ctx->Current.RasterColor, GL_FALSE);
1098
1099      free_mipmap_tree(st->pipe, mt);
1100   }
1101}
1102
1103
1104static void
1105copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
1106                    GLsizei width, GLsizei height,
1107                    GLint dstx, GLint dsty)
1108{
1109   struct st_context *st = ctx->st;
1110   struct pipe_context *pipe = st->pipe;
1111   struct st_renderbuffer *rbRead = st_renderbuffer(ctx->ReadBuffer->_StencilBuffer);
1112   struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
1113   struct pipe_surface *psRead = rbRead->surface;
1114   struct pipe_surface *psDraw = rbDraw->surface;
1115   ubyte *readMap, *drawMap;
1116   ubyte *buffer;
1117   int i;
1118
1119   buffer = malloc(width * height * sizeof(ubyte));
1120   if (!buffer) {
1121      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
1122      return;
1123   }
1124
1125   /* map the stencil buffers */
1126   readMap = pipe->region_map(pipe, psRead->region);
1127   drawMap = pipe->region_map(pipe, psDraw->region);
1128
1129   /* this will do stencil pixel transfer ops */
1130   st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
1131                          &ctx->DefaultPacking, buffer);
1132
1133   /* draw */
1134   /* XXX PixelZoom not handled yet */
1135   for (i = 0; i < height; i++) {
1136      ubyte *dst;
1137      const ubyte *src;
1138      int y;
1139
1140      y = dsty + i;
1141
1142      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1143         y = ctx->DrawBuffer->Height - y - 1;
1144      }
1145
1146      dst = drawMap + (y * psDraw->region->pitch + dstx) * psDraw->region->cpp;
1147      src = buffer + i * width;
1148
1149      switch (psDraw->format) {
1150      case PIPE_FORMAT_S8_Z24:
1151         {
1152            uint *dst4 = (uint *) dst;
1153            int j;
1154            for (j = 0; j < width; j++) {
1155               *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
1156               dst4++;
1157            }
1158         }
1159         break;
1160      case PIPE_FORMAT_U_S8:
1161         memcpy(dst, src, width);
1162         break;
1163      default:
1164         assert(0);
1165      }
1166   }
1167
1168   free(buffer);
1169
1170   /* unmap the stencil buffers */
1171   pipe->region_unmap(pipe, psRead->region);
1172   pipe->region_unmap(pipe, psDraw->region);
1173}
1174
1175
1176static void
1177st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
1178              GLsizei width, GLsizei height,
1179              GLint dstx, GLint dsty, GLenum type)
1180{
1181   struct st_context *st = ctx->st;
1182   struct pipe_context *pipe = st->pipe;
1183   struct st_renderbuffer *rbRead;
1184   struct st_vertex_program *stvp;
1185   struct st_fragment_program *stfp;
1186   struct pipe_surface *psRead;
1187   struct pipe_mipmap_tree *mt;
1188   GLfloat *color;
1189   uint format;
1190
1191   st_validate_state(st);
1192
1193   if (type == GL_STENCIL) {
1194      /* can't use texturing to do stencil */
1195      copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
1196      return;
1197   }
1198
1199   if (type == GL_COLOR) {
1200      rbRead = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
1201      color = NULL;
1202      stfp = make_fragment_shader(ctx->st, GL_FALSE);
1203      stvp = make_vertex_shader(ctx->st, GL_FALSE);
1204   }
1205   else {
1206      rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
1207      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
1208      stfp = make_fragment_shader_z(ctx->st);
1209      stvp = make_vertex_shader(ctx->st, GL_TRUE);
1210   }
1211
1212   psRead = rbRead->surface;
1213   format = psRead->format;
1214
1215   mt = alloc_mipmap_tree(ctx->st, width, height, format);
1216   if (!mt)
1217      return;
1218
1219   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1220      srcy = ctx->DrawBuffer->Height - srcy - height;
1221   }
1222
1223   /* For some drivers (like Xlib) it's not possible to treat the
1224    * front/back color buffers as regions (they're XImages and Pixmaps).
1225    * So, this var tells us if we can use region_copy here...
1226    */
1227   if (st->haveFramebufferRegions) {
1228      /* copy source framebuffer region into mipmap/texture */
1229      pipe->region_copy(pipe,
1230                        mt->region, /* dest */
1231                        0, /* dest_offset */
1232                        0, 0, /* destx/y */
1233                        psRead->region,
1234                        0, /* src_offset */
1235                        srcx, srcy, width, height);
1236   }
1237   else {
1238      /* alternate path using get/put_tile() */
1239      struct pipe_surface *psTex;
1240      GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1241
1242      psTex = pipe->get_tex_surface(pipe, mt, 0, 0, 0);
1243
1244      (void) pipe->region_map(pipe, psRead->region);
1245      (void) pipe->region_map(pipe, psTex->region);
1246
1247      pipe->get_tile_rgba(pipe, psRead, srcx, srcy, width, height, buf);
1248      pipe->put_tile_rgba(pipe, psTex, 0, 0, width, height, buf);
1249
1250      pipe->region_unmap(pipe, psRead->region);
1251      pipe->region_unmap(pipe, psTex->region);
1252
1253      pipe_surface_reference(&psTex, NULL);
1254
1255      free(buf);
1256   }
1257
1258
1259   /* draw textured quad */
1260   draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1261                      width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1262                      mt, stvp, stfp, color, GL_TRUE);
1263
1264   free_mipmap_tree(st->pipe, mt);
1265}
1266
1267
1268
1269void st_init_drawpixels_functions(struct dd_function_table *functions)
1270{
1271   functions->DrawPixels = st_DrawPixels;
1272   functions->CopyPixels = st_CopyPixels;
1273   functions->Bitmap = st_Bitmap;
1274}
1275