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