st_cb_drawpixels.c revision 4b822a101680532ce6df52904af91194b78a16ba
1238b6a9d33bf87e23f86866885394cd453a06495Rafael Espindola/**************************************************************************
2238b6a9d33bf87e23f86866885394cd453a06495Rafael Espindola *
391338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
491338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * All Rights Reserved.
591338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka *
691338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * Permission is hereby granted, free of charge, to any person obtaining a
791338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * copy of this software and associated documentation files (the
891338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * "Software"), to deal in the Software without restriction, including
991338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * without limitation the rights to use, copy, modify, merge, publish,
1091338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * distribute, sub license, and/or sell copies of the Software, and to
1191338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * permit persons to whom the Software is furnished to do so, subject to
1291338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * the following conditions:
1391338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka *
1491338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * The above copyright notice and this permission notice (including the
1591338cf4129cfdb85af7e9ef396ab09621da10ecAkira Hatanaka * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Brian Paul
31  */
32
33#include "main/imports.h"
34#include "main/image.h"
35#include "main/bufferobj.h"
36#include "main/macros.h"
37#include "main/texformat.h"
38#include "shader/program.h"
39#include "shader/prog_parameter.h"
40#include "shader/prog_print.h"
41
42#include "st_context.h"
43#include "st_atom.h"
44#include "st_atom_constbuf.h"
45#include "st_draw.h"
46#include "st_program.h"
47#include "st_cb_drawpixels.h"
48#include "st_cb_readpixels.h"
49#include "st_cb_fbo.h"
50#include "st_cb_texture.h"
51#include "st_draw.h"
52#include "st_format.h"
53#include "st_mesa_to_tgsi.h"
54#include "st_texture.h"
55#include "pipe/p_context.h"
56#include "pipe/p_defines.h"
57#include "pipe/p_inlines.h"
58#include "pipe/p_winsys.h"
59#include "util/p_tile.h"
60#include "util/u_draw_quad.h"
61#include "shader/prog_instruction.h"
62#include "cso_cache/cso_context.h"
63
64
65/**
66 * Check if the given program is:
67 * 0: MOVE result.color, fragment.color;
68 * 1: END;
69 */
70static GLboolean
71is_passthrough_program(const struct gl_fragment_program *prog)
72{
73   if (prog->Base.NumInstructions == 2) {
74      const struct prog_instruction *inst = prog->Base.Instructions;
75      if (inst[0].Opcode == OPCODE_MOV &&
76          inst[1].Opcode == OPCODE_END &&
77          inst[0].DstReg.File == PROGRAM_OUTPUT &&
78          inst[0].DstReg.Index == FRAG_RESULT_COLR &&
79          inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
80          inst[0].SrcReg[0].File == PROGRAM_INPUT &&
81          inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
82          inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
83         return GL_TRUE;
84      }
85   }
86   return GL_FALSE;
87}
88
89
90
91/**
92 * Make fragment shader for glDraw/CopyPixels.  This shader is made
93 * by combining the pixel transfer shader with the user-defined shader.
94 */
95static struct st_fragment_program *
96combined_drawpix_fragment_program(GLcontext *ctx)
97{
98   struct st_context *st = ctx->st;
99   struct st_fragment_program *stfp;
100
101   if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
102       && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
103      /* the pixel tranfer program has not changed and the user-defined
104       * program has not changed, so re-use the combined program.
105       */
106      stfp = st->pixel_xfer.combined_prog;
107   }
108   else {
109      /* Concatenate the pixel transfer program with the current user-
110       * defined program.
111       */
112      if (is_passthrough_program(&st->fp->Base)) {
113         stfp = (struct st_fragment_program *)
114            _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base);
115      }
116      else {
117#if 0
118         printf("Base program:\n");
119         _mesa_print_program(&st->fp->Base.Base);
120         printf("DrawPix program:\n");
121         _mesa_print_program(&st->pixel_xfer.program->Base.Base);
122#endif
123         stfp = (struct st_fragment_program *)
124            _mesa_combine_programs(ctx,
125                                   &st->pixel_xfer.program->Base.Base,
126                                   &st->fp->Base.Base);
127      }
128
129#if 0
130      {
131         struct gl_program *p = &stfp->Base.Base;
132         printf("Combined DrawPixels program:\n");
133         _mesa_print_program(p);
134         printf("InputsRead: 0x%x\n", p->InputsRead);
135         printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
136         _mesa_print_parameter_list(p->Parameters);
137      }
138#endif
139
140      /* translate to TGSI tokens */
141      st_translate_fragment_program(st, stfp, NULL);
142
143      /* save new program, update serial numbers */
144      st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
145      st->pixel_xfer.user_prog_sn = st->fp->serialNo;
146      st->pixel_xfer.combined_prog_sn = stfp->serialNo;
147      st->pixel_xfer.combined_prog = stfp;
148   }
149
150   /* Ideally we'd have updated the pipe constants during the normal
151    * st/atom mechanism.  But we can't since this is specific to glDrawPixels.
152    */
153   st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
154
155   return stfp;
156}
157
158
159/**
160 * Create fragment shader that does a TEX() instruction to get a Z
161 * value, then writes to FRAG_RESULT_DEPR.
162 * Pass fragment color through as-is.
163 */
164static struct st_fragment_program *
165make_fragment_shader_z(struct st_context *st)
166{
167   GLcontext *ctx = st->ctx;
168   /* only make programs once and re-use */
169   static struct st_fragment_program *stfp = NULL;
170   struct gl_program *p;
171   GLuint ic = 0;
172
173   if (stfp)
174      return stfp;
175
176   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
177   if (!p)
178      return NULL;
179
180   p->NumInstructions = 3;
181
182   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
183   if (!p->Instructions) {
184      ctx->Driver.DeleteProgram(ctx, p);
185      return NULL;
186   }
187   _mesa_init_instructions(p->Instructions, p->NumInstructions);
188
189   /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
190   p->Instructions[ic].Opcode = OPCODE_TEX;
191   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
192   p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR;
193   p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
194   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
195   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
196   p->Instructions[ic].TexSrcUnit = 0;
197   p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
198   ic++;
199
200   /* MOV result.color, fragment.color */
201   p->Instructions[ic].Opcode = OPCODE_MOV;
202   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
203   p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
204   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
205   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
206   ic++;
207
208   /* END; */
209   p->Instructions[ic++].Opcode = OPCODE_END;
210
211   assert(ic == p->NumInstructions);
212
213   p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
214   p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR);
215   p->SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */
216
217   stfp = (struct st_fragment_program *) p;
218   st_translate_fragment_program(st, stfp, NULL);
219
220   return stfp;
221}
222
223
224
225/**
226 * Create a simple vertex shader that just passes through the
227 * vertex position and texcoord (and optionally, color).
228 */
229static struct st_vertex_program *
230st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor)
231{
232   /* only make programs once and re-use */
233   static struct st_vertex_program *progs[2] = { NULL, NULL };
234   GLcontext *ctx = st->ctx;
235   struct st_vertex_program *stvp;
236   struct gl_program *p;
237   GLuint ic = 0;
238
239   if (progs[passColor])
240      return progs[passColor];
241
242   p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
243   if (!p)
244      return NULL;
245
246   if (passColor)
247      p->NumInstructions = 4;
248   else
249      p->NumInstructions = 3;
250
251   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
252   if (!p->Instructions) {
253      ctx->Driver.DeleteProgram(ctx, p);
254      return NULL;
255   }
256   _mesa_init_instructions(p->Instructions, p->NumInstructions);
257   /* MOV result.pos, vertex.pos; */
258   p->Instructions[0].Opcode = OPCODE_MOV;
259   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
260   p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
261   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
262   p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
263   /* MOV result.texcoord0, vertex.texcoord0; */
264   p->Instructions[1].Opcode = OPCODE_MOV;
265   p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
266   p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
267   p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
268   p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
269   ic = 2;
270   if (passColor) {
271      /* MOV result.color0, vertex.color0; */
272      p->Instructions[ic].Opcode = OPCODE_MOV;
273      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
274      p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
275      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
276      p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
277      ic++;
278   }
279
280   /* END; */
281   p->Instructions[ic].Opcode = OPCODE_END;
282   ic++;
283
284   assert(ic == p->NumInstructions);
285
286   p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
287   p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
288                        (1 << VERT_RESULT_HPOS));
289   if (passColor) {
290      p->InputsRead |= VERT_BIT_COLOR0;
291      p->OutputsWritten |= (1 << VERT_RESULT_COL0);
292   }
293
294   stvp = (struct st_vertex_program *) p;
295   st_translate_vertex_program(st, stvp, NULL);
296
297   progs[passColor] = stvp;
298
299   return stvp;
300}
301
302
303static GLenum
304_mesa_base_format(GLenum format)
305{
306   switch (format) {
307   case GL_DEPTH_COMPONENT:
308      return GL_DEPTH_COMPONENT;
309   case GL_STENCIL_INDEX:
310      return GL_STENCIL_INDEX;
311   default:
312      return GL_RGBA;
313   }
314}
315
316
317/**
318 * Make texture containing an image for glDrawPixels image.
319 * If 'pixels' is NULL, leave the texture image data undefined.
320 */
321static struct pipe_texture *
322make_texture(struct st_context *st,
323	     GLsizei width, GLsizei height, GLenum format, GLenum type,
324	     const struct gl_pixelstore_attrib *unpack,
325	     const GLvoid *pixels)
326{
327   GLcontext *ctx = st->ctx;
328   struct pipe_context *pipe = st->pipe;
329   struct pipe_screen *screen = pipe->screen;
330   const struct gl_texture_format *mformat;
331   struct pipe_texture *pt;
332   enum pipe_format pipeFormat;
333   GLuint cpp;
334   GLenum baseFormat;
335
336   baseFormat = _mesa_base_format(format);
337
338   mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
339   assert(mformat);
340
341   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
342   assert(pipeFormat);
343   cpp = st_sizeof_format(pipeFormat);
344
345   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
346   if (!pixels)
347      return NULL;
348
349   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
350			  1, 0);
351   if (!pt) {
352      _mesa_unmap_drapix_pbo(ctx, unpack);
353      return NULL;
354   }
355
356   {
357      struct pipe_surface *surface;
358      static const GLuint dstImageOffsets = 0;
359      GLboolean success;
360      GLubyte *dest;
361      const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
362
363      /* we'll do pixel transfer in a fragment shader */
364      ctx->_ImageTransferState = 0x0;
365
366      surface = screen->get_tex_surface(screen, pt, 0, 0, 0);
367
368      /* map texture surface */
369      dest = pipe_surface_map(surface);
370
371      /* Put image into texture surface.
372       * Note that the image is actually going to be upside down in
373       * the texture.  We deal with that with texcoords.
374       */
375      success = mformat->StoreImage(ctx, 2,           /* dims */
376                                    baseFormat,       /* baseInternalFormat */
377                                    mformat,          /* gl_texture_format */
378                                    dest,             /* dest */
379                                    0, 0, 0,          /* dstX/Y/Zoffset */
380                                    surface->pitch * cpp, /* dstRowStride, bytes */
381                                    &dstImageOffsets, /* dstImageOffsets */
382                                    width, height, 1, /* size */
383                                    format, type,     /* src format/type */
384                                    pixels,           /* data source */
385                                    unpack);
386
387      /* unmap */
388      pipe_surface_unmap(surface);
389      pipe_surface_reference(&surface, NULL);
390      pipe->texture_update(pipe, pt, 0, 0x1);
391
392      assert(success);
393
394      /* restore */
395      ctx->_ImageTransferState = imageTransferStateSave;
396   }
397
398   _mesa_unmap_drapix_pbo(ctx, unpack);
399
400   return pt;
401}
402
403
404/**
405 * Draw textured quad.
406 * Coords are window coords with y=0=bottom.
407 */
408static void
409draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
410          GLfloat x1, GLfloat y1, GLboolean invertTex)
411{
412   GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
413   GLuint i;
414   GLfloat sLeft = 0.0, sRight = 1.0;
415   GLfloat tTop = invertTex, tBot = 1.0 - tTop;
416
417   /* upper-left */
418   verts[0][0][0] = x0;    /* attr[0].x */
419   verts[0][0][1] = y0;    /* attr[0].y */
420   verts[0][1][0] = sLeft; /* attr[1].s */
421   verts[0][1][1] = tTop;  /* attr[1].t */
422
423   /* upper-right */
424   verts[1][0][0] = x1;
425   verts[1][0][1] = y0;
426   verts[1][1][0] = sRight;
427   verts[1][1][1] = tTop;
428
429   /* lower-right */
430   verts[2][0][0] = x1;
431   verts[2][0][1] = y1;
432   verts[2][1][0] = sRight;
433   verts[2][1][1] = tBot;
434
435   /* lower-left */
436   verts[3][0][0] = x0;
437   verts[3][0][1] = y1;
438   verts[3][1][0] = sLeft;
439   verts[3][1][1] = tBot;
440
441   /* same for all verts: */
442   for (i = 0; i < 4; i++) {
443      verts[i][0][2] = z;   /*Z*/
444      verts[i][0][3] = 1.0; /*W*/
445      verts[i][1][2] = 0.0; /*R*/
446      verts[i][1][3] = 1.0; /*Q*/
447   }
448
449   st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, GL_FALSE);
450}
451
452
453static void
454draw_quad_colored(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
455                  GLfloat x1, GLfloat y1, const GLfloat *color,
456                  GLboolean invertTex)
457{
458   GLfloat bias = ctx->st->bitmap_texcoord_bias;
459   GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
460   GLuint i;
461   GLfloat xBias = bias / (x1-x0);
462   GLfloat yBias = bias / (y1-y0);
463   GLfloat sLeft = 0.0 + xBias, sRight = 1.0 + xBias;
464   GLfloat tTop = invertTex - yBias, tBot = 1.0 - tTop - yBias;
465
466   /* upper-left */
467   verts[0][0][0] = x0;    /* attr[0].x */
468   verts[0][0][1] = y0;    /* attr[0].y */
469   verts[0][2][0] = sLeft; /* attr[2].s */
470   verts[0][2][1] = tTop;  /* attr[2].t */
471
472   /* upper-right */
473   verts[1][0][0] = x1;
474   verts[1][0][1] = y0;
475   verts[1][2][0] = sRight;
476   verts[1][2][1] = tTop;
477
478   /* lower-right */
479   verts[2][0][0] = x1;
480   verts[2][0][1] = y1;
481   verts[2][2][0] = sRight;
482   verts[2][2][1] = tBot;
483
484   /* lower-left */
485   verts[3][0][0] = x0;
486   verts[3][0][1] = y1;
487   verts[3][2][0] = sLeft;
488   verts[3][2][1] = tBot;
489
490   /* same for all verts: */
491   for (i = 0; i < 4; i++) {
492      verts[i][0][2] = z;   /*Z*/
493      verts[i][0][3] = 1.0; /*W*/
494      verts[i][1][0] = color[0];
495      verts[i][1][1] = color[1];
496      verts[i][1][2] = color[2];
497      verts[i][1][3] = color[3];
498      verts[i][2][2] = 0.0; /*R*/
499      verts[i][2][3] = 1.0; /*Q*/
500   }
501
502   st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 3, GL_FALSE);
503}
504
505
506
507static void
508draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
509                   GLsizei width, GLsizei height,
510                   GLfloat zoomX, GLfloat zoomY,
511                   struct pipe_texture *pt,
512                   struct st_vertex_program *stvp,
513                   struct st_fragment_program *stfp,
514                   const GLfloat *color,
515                   GLboolean invertTex)
516{
517   struct st_context *st = ctx->st;
518   struct pipe_context *pipe = ctx->st->pipe;
519   struct cso_context *cso = ctx->st->cso_context;
520   GLfloat x0, y0, x1, y1;
521   GLuint maxSize;
522
523   /* limit checks */
524   /* XXX if DrawPixels image is larger than max texture size, break
525    * it up into chunks.
526    */
527   maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
528   assert(width <= maxSize);
529   assert(height <= maxSize);
530
531   cso_save_rasterizer(cso);
532   cso_save_viewport(cso);
533   cso_save_samplers(cso);
534   cso_save_sampler_textures(cso);
535
536   /* rasterizer state: just scissor */
537   {
538      struct pipe_rasterizer_state rasterizer;
539      memset(&rasterizer, 0, sizeof(rasterizer));
540      rasterizer.gl_rasterization_rules = 1;
541      rasterizer.scissor = ctx->Scissor.Enabled;
542      cso_set_rasterizer(cso, &rasterizer);
543   }
544
545   /* fragment shader state: TEX lookup program */
546   pipe->bind_fs_state(pipe, stfp->driver_shader);
547
548   /* vertex shader state: position + texcoord pass-through */
549   pipe->bind_vs_state(pipe, stvp->driver_shader);
550
551
552   /* texture sampling state: */
553   {
554      struct pipe_sampler_state sampler;
555      memset(&sampler, 0, sizeof(sampler));
556      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
557      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
558      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
559      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
560      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
561      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
562      sampler.normalized_coords = 1;
563
564      cso_single_sampler(cso, 0, &sampler);
565      if (st->pixel_xfer.pixelmap_enabled) {
566         cso_single_sampler(cso, 1, &sampler);
567      }
568      cso_single_sampler_done(cso);
569   }
570
571   /* viewport state: viewport matching window dims */
572   {
573      const float width = ctx->DrawBuffer->Width;
574      const float height = ctx->DrawBuffer->Height;
575      struct pipe_viewport_state vp;
576      vp.scale[0] =  0.5 * width;
577      vp.scale[1] = -0.5 * height;
578      vp.scale[2] = 1.0;
579      vp.scale[3] = 1.0;
580      vp.translate[0] = 0.5 * width;
581      vp.translate[1] = 0.5 * height;
582      vp.translate[2] = 0.0;
583      vp.translate[3] = 0.0;
584      cso_set_viewport(cso, &vp);
585   }
586
587   /* texture state: */
588   if (st->pixel_xfer.pixelmap_enabled) {
589      struct pipe_texture *textures[2];
590      textures[0] = pt;
591      textures[1] = st->pixel_xfer.pixelmap_texture;
592      pipe->set_sampler_textures(pipe, 2, textures);
593   }
594   else {
595      pipe->set_sampler_textures(pipe, 1, &pt);
596   }
597
598   /* Compute window coords (y=0=bottom) with pixel zoom.
599    * Recall that these coords are transformed by the current
600    * vertex shader and viewport transformation.
601    */
602   x0 = x;
603   x1 = x + width * ctx->Pixel.ZoomX;
604   y0 = y;
605   y1 = y + height * ctx->Pixel.ZoomY;
606
607   /* draw textured quad */
608   if (color)
609      draw_quad_colored(ctx, x0, y0, z, x1, y1, color, invertTex);
610   else
611      draw_quad(ctx, x0, y0, z, x1, y1, invertTex);
612
613   /* restore state */
614   cso_restore_rasterizer(cso);
615   cso_restore_viewport(cso);
616   cso_restore_samplers(cso);
617   cso_restore_sampler_textures(cso);
618
619   /* shaders don't go through cso yet */
620   pipe->bind_fs_state(pipe, st->fp->driver_shader);
621   pipe->bind_vs_state(pipe, st->vp->driver_shader);
622}
623
624
625/**
626 * Check if a GL format/type combination is a match to the given pipe format.
627 * XXX probably move this to a re-usable place.
628 */
629static GLboolean
630compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat)
631{
632   static const GLuint one = 1;
633   GLubyte littleEndian = *((GLubyte *) &one);
634
635   if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
636       format == GL_RGBA &&
637       type == GL_UNSIGNED_BYTE &&
638       !littleEndian) {
639      return GL_TRUE;
640   }
641   else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
642            format == GL_ABGR_EXT &&
643            type == GL_UNSIGNED_BYTE &&
644            littleEndian) {
645      return GL_TRUE;
646   }
647   else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM &&
648            format == GL_BGRA &&
649            type == GL_UNSIGNED_BYTE &&
650            littleEndian) {
651      return GL_TRUE;
652   }
653   else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
654            format == GL_RGB &&
655            type == GL_UNSIGNED_SHORT_5_6_5) {
656      /* endian don't care */
657      return GL_TRUE;
658   }
659   else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
660            format == GL_BGR &&
661            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
662      /* endian don't care */
663      return GL_TRUE;
664   }
665   else if (pipeFormat == PIPE_FORMAT_S8_UNORM &&
666            format == GL_STENCIL_INDEX &&
667            type == GL_UNSIGNED_BYTE) {
668      return GL_TRUE;
669   }
670   else if (pipeFormat == PIPE_FORMAT_Z32_UNORM &&
671            format == GL_DEPTH_COMPONENT &&
672            type == GL_UNSIGNED_INT) {
673      return GL_TRUE;
674   }
675   /* XXX add more cases */
676   else {
677      return GL_FALSE;
678   }
679}
680
681
682/**
683 * Check if any per-fragment ops are enabled.
684 * XXX probably move this to a re-usable place.
685 */
686static GLboolean
687any_fragment_ops(const struct st_context *st)
688{
689   if (st->state.depth_stencil.alpha.enabled ||
690       st->state.depth_stencil.depth.enabled ||
691       st->state.blend.blend_enable ||
692       st->state.blend.logicop_enable)
693      /* XXX more checks */
694      return GL_TRUE;
695   else
696      return GL_FALSE;
697}
698
699
700/**
701 * Check if any pixel transfer ops are enabled.
702 * XXX probably move this to a re-usable place.
703 */
704static GLboolean
705any_pixel_transfer_ops(const struct st_context *st)
706{
707   if (st->ctx->Pixel.RedScale != 1.0 ||
708       st->ctx->Pixel.RedBias != 0.0 ||
709       st->ctx->Pixel.GreenScale != 1.0 ||
710       st->ctx->Pixel.GreenBias != 0.0 ||
711       st->ctx->Pixel.BlueScale != 1.0 ||
712       st->ctx->Pixel.BlueBias != 0.0 ||
713       st->ctx->Pixel.AlphaScale != 1.0 ||
714       st->ctx->Pixel.AlphaBias != 0.0 ||
715       st->ctx->Pixel.MapColorFlag)
716      /* XXX more checks */
717      return GL_TRUE;
718   else
719      return GL_FALSE;
720}
721
722
723/**
724 * Draw image with a blit, or other non-textured quad method.
725 */
726static void
727draw_blit(struct st_context *st,
728          GLsizei width, GLsizei height,
729          GLenum format, GLenum type, const GLvoid *pixels)
730{
731
732
733}
734
735
736static void
737draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
738                    GLsizei width, GLsizei height, GLenum type,
739                    const struct gl_pixelstore_attrib *unpack,
740                    const GLvoid *pixels)
741{
742   struct st_context *st = ctx->st;
743   struct pipe_context *pipe = st->pipe;
744   struct pipe_surface *ps = st->state.framebuffer.zsbuf;
745   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
746   GLint skipPixels;
747   ubyte *stmap;
748
749   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
750
751   /* map the stencil buffer */
752   stmap = pipe_surface_map(ps);
753
754   /* if width > MAX_WIDTH, have to process image in chunks */
755   skipPixels = 0;
756   while (skipPixels < width) {
757      const GLint spanX = x + skipPixels;
758      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
759      GLint row;
760      for (row = 0; row < height; row++) {
761         GLint spanY = y + row;
762         GLubyte values[MAX_WIDTH];
763         GLenum destType = GL_UNSIGNED_BYTE;
764         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
765                                                      width, height,
766                                                      GL_COLOR_INDEX, type,
767                                                      row, skipPixels);
768         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
769                                   type, source, unpack,
770                                   ctx->_ImageTransferState);
771         if (zoom) {
772            /*
773            _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
774                                              spanX, spanY, values);
775            */
776         }
777         else {
778            if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
779               spanY = ctx->DrawBuffer->Height - spanY - 1;
780            }
781
782            switch (ps->format) {
783            case PIPE_FORMAT_U_S8:
784               {
785                  ubyte *dest = stmap + spanY * ps->pitch + spanX;
786                  memcpy(dest, values, spanWidth);
787               }
788               break;
789            case PIPE_FORMAT_S8Z24_UNORM:
790               {
791                  uint *dest = (uint *) stmap + spanY * ps->pitch + spanX;
792                  GLint k;
793                  for (k = 0; k < spanWidth; k++) {
794                     uint p = dest[k];
795                     p = (p & 0xffffff) | (values[k] << 24);
796                     dest[k] = p;
797                  }
798               }
799               break;
800            default:
801               assert(0);
802            }
803         }
804      }
805      skipPixels += spanWidth;
806   }
807
808   /* unmap the stencil buffer */
809   pipe_surface_unmap(ps);
810}
811
812
813/**
814 * Called via ctx->Driver.DrawPixels()
815 */
816static void
817st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
818              GLenum format, GLenum type,
819              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
820{
821   struct st_fragment_program *stfp;
822   struct st_vertex_program *stvp;
823   struct st_context *st = ctx->st;
824   struct pipe_surface *ps;
825   GLuint bufferFormat;
826   const GLfloat *color;
827
828   if (format == GL_STENCIL_INDEX) {
829      draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
830      return;
831   }
832
833   st_validate_state(st);
834
835   if (format == GL_DEPTH_COMPONENT) {
836      ps = st->state.framebuffer.zsbuf;
837      stfp = make_fragment_shader_z(ctx->st);
838      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
839      color = ctx->Current.RasterColor;
840   }
841   else if (format == GL_STENCIL_INDEX) {
842      ps = st->state.framebuffer.zsbuf;
843      /* XXX special case - can't use texture map */
844      color = NULL;
845   }
846   else {
847      ps = st->state.framebuffer.cbufs[0];
848      stfp = combined_drawpix_fragment_program(ctx);
849      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
850      color = NULL;
851   }
852
853   bufferFormat = ps->format;
854
855   if (1/*any_fragment_ops(st) ||
856       any_pixel_transfer_ops(st) ||
857       !compatible_formats(format, type, ps->format)*/) {
858      /* textured quad */
859      struct pipe_texture *pt
860         = make_texture(ctx->st, width, height, format, type, unpack, pixels);
861      if (pt) {
862         draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
863                            width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
864                            pt, stvp, stfp, color, GL_FALSE);
865         pipe_texture_reference(&pt, NULL);
866      }
867   }
868   else {
869      /* blit */
870      draw_blit(st, width, height, format, type, pixels);
871   }
872}
873
874
875
876static void
877copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
878                    GLsizei width, GLsizei height,
879                    GLint dstx, GLint dsty)
880{
881   struct st_renderbuffer *rbRead = st_renderbuffer(ctx->ReadBuffer->_StencilBuffer);
882   struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
883   struct pipe_surface *psRead = rbRead->surface;
884   struct pipe_surface *psDraw = rbDraw->surface;
885   ubyte *readMap, *drawMap;
886   ubyte *buffer;
887   int i;
888
889   buffer = malloc(width * height * sizeof(ubyte));
890   if (!buffer) {
891      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
892      return;
893   }
894
895   /* map the stencil buffers */
896   readMap = pipe_surface_map(psRead);
897   drawMap = pipe_surface_map(psDraw);
898
899   /* this will do stencil pixel transfer ops */
900   st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
901                          &ctx->DefaultPacking, buffer);
902
903   /* draw */
904   /* XXX PixelZoom not handled yet */
905   for (i = 0; i < height; i++) {
906      ubyte *dst;
907      const ubyte *src;
908      int y;
909
910      y = dsty + i;
911
912      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
913         y = ctx->DrawBuffer->Height - y - 1;
914      }
915
916      dst = drawMap + (y * psDraw->pitch + dstx) * psDraw->cpp;
917      src = buffer + i * width;
918
919      switch (psDraw->format) {
920      case PIPE_FORMAT_S8Z24_UNORM:
921         {
922            uint *dst4 = (uint *) dst;
923            int j;
924            for (j = 0; j < width; j++) {
925               *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
926               dst4++;
927            }
928         }
929         break;
930      case PIPE_FORMAT_U_S8:
931         memcpy(dst, src, width);
932         break;
933      default:
934         assert(0);
935      }
936   }
937
938   free(buffer);
939
940   /* unmap the stencil buffers */
941   pipe_surface_unmap(psRead);
942   pipe_surface_unmap(psDraw);
943}
944
945
946static void
947st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
948              GLsizei width, GLsizei height,
949              GLint dstx, GLint dsty, GLenum type)
950{
951   struct st_context *st = ctx->st;
952   struct pipe_context *pipe = st->pipe;
953   struct pipe_screen *screen = pipe->screen;
954   struct st_renderbuffer *rbRead;
955   struct st_vertex_program *stvp;
956   struct st_fragment_program *stfp;
957   struct pipe_surface *psRead;
958   struct pipe_surface *psTex;
959   struct pipe_texture *pt;
960   GLfloat *color;
961   enum pipe_format srcFormat, texFormat;
962
963   /* make sure rendering has completed */
964   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
965
966   st_validate_state(st);
967
968   if (type == GL_STENCIL) {
969      /* can't use texturing to do stencil */
970      copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
971      return;
972   }
973
974   if (type == GL_COLOR) {
975      rbRead = st_get_color_read_renderbuffer(ctx);
976      color = NULL;
977      stfp = combined_drawpix_fragment_program(ctx);
978      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
979   }
980   else {
981      assert(type == GL_DEPTH);
982      rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
983      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
984      stfp = make_fragment_shader_z(ctx->st);
985      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
986   }
987
988   psRead = rbRead->surface;
989   srcFormat = psRead->format;
990
991   if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE)) {
992      texFormat = srcFormat;
993   }
994   else {
995      /* srcFormat can't be used as a texture format */
996      if (type == GL_DEPTH) {
997         static const enum pipe_format zFormats[] = {
998            PIPE_FORMAT_Z16_UNORM,
999            PIPE_FORMAT_Z32_UNORM,
1000            PIPE_FORMAT_S8Z24_UNORM,
1001            PIPE_FORMAT_Z24S8_UNORM
1002         };
1003         uint i;
1004         texFormat = 0;
1005         for (i = 0; i < Elements(zFormats); i++) {
1006            if (screen->is_format_supported(screen, zFormats[i],
1007                                            PIPE_TEXTURE)) {
1008               texFormat = zFormats[i];
1009               break;
1010            }
1011         }
1012         assert(texFormat); /* XXX no depth texture formats??? */
1013      }
1014      else {
1015         /* todo */
1016         assert(0);
1017      }
1018   }
1019
1020   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
1021                          width, height, 1, 0);
1022   if (!pt)
1023      return;
1024
1025   psTex = screen->get_tex_surface(screen, pt, 0, 0, 0);
1026
1027   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1028      srcy = ctx->DrawBuffer->Height - srcy - height;
1029   }
1030
1031   if (srcFormat == texFormat) {
1032      /* copy source framebuffer surface into mipmap/texture */
1033      pipe->surface_copy(pipe,
1034                         FALSE,
1035			 psTex, /* dest */
1036			 0, 0, /* destx/y */
1037			 psRead,
1038			 srcx, srcy, width, height);
1039   }
1040   else if (type == GL_COLOR) {
1041      /* alternate path using get/put_tile() */
1042      GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1043
1044      pipe_get_tile_rgba(pipe, psRead, srcx, srcy, width, height, buf);
1045      pipe_put_tile_rgba(pipe, psTex, 0, 0, width, height, buf);
1046
1047      free(buf);
1048   }
1049   else {
1050      /* GL_DEPTH */
1051      GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
1052      pipe_get_tile_z(pipe, psRead, srcx, srcy, width, height, buf);
1053      pipe_put_tile_z(pipe, psTex, 0, 0, width, height, buf);
1054      free(buf);
1055   }
1056
1057   /* draw textured quad */
1058   draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1059                      width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1060                      pt, stvp, stfp, color, GL_TRUE);
1061
1062   pipe_surface_reference(&psTex, NULL);
1063   pipe_texture_reference(&pt, NULL);
1064}
1065
1066
1067
1068void st_init_drawpixels_functions(struct dd_function_table *functions)
1069{
1070   functions->DrawPixels = st_DrawPixels;
1071   functions->CopyPixels = st_CopyPixels;
1072}
1073