st_cb_drawpixels.c revision 62ef614eb3a9e28c39606657f576e320f158623e
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Brian Paul
31  */
32
33#include "main/imports.h"
34#include "main/image.h"
35#include "main/bufferobj.h"
36#include "main/macros.h"
37#include "main/texformat.h"
38#include "main/state.h"
39#include "shader/program.h"
40#include "shader/prog_parameter.h"
41#include "shader/prog_print.h"
42
43#include "st_context.h"
44#include "st_atom.h"
45#include "st_atom_constbuf.h"
46#include "st_draw.h"
47#include "st_program.h"
48#include "st_cb_drawpixels.h"
49#include "st_cb_readpixels.h"
50#include "st_cb_fbo.h"
51#include "st_cb_texture.h"
52#include "st_draw.h"
53#include "st_format.h"
54#include "st_mesa_to_tgsi.h"
55#include "st_texture.h"
56#include "pipe/p_context.h"
57#include "pipe/p_defines.h"
58#include "pipe/p_inlines.h"
59#include "util/u_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_COLOR &&
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_DEPTH.
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   struct gl_program *p;
169   GLuint ic = 0;
170
171   if (st->drawpix.z_shader) {
172      return st->drawpix.z_shader;
173   }
174
175   /*
176    * Create shader now
177    */
178   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
179   if (!p)
180      return NULL;
181
182   p->NumInstructions = 3;
183
184   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
185   if (!p->Instructions) {
186      ctx->Driver.DeleteProgram(ctx, p);
187      return NULL;
188   }
189   _mesa_init_instructions(p->Instructions, p->NumInstructions);
190
191   /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
192   p->Instructions[ic].Opcode = OPCODE_TEX;
193   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
194   p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH;
195   p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
196   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
197   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
198   p->Instructions[ic].TexSrcUnit = 0;
199   p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
200   ic++;
201
202   /* MOV result.color, fragment.color */
203   p->Instructions[ic].Opcode = OPCODE_MOV;
204   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
205   p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLOR;
206   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
207   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
208   ic++;
209
210   /* END; */
211   p->Instructions[ic++].Opcode = OPCODE_END;
212
213   assert(ic == p->NumInstructions);
214
215   p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
216   p->OutputsWritten = (1 << FRAG_RESULT_COLOR) | (1 << FRAG_RESULT_DEPTH);
217   p->SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */
218
219   st->drawpix.z_shader = (struct st_fragment_program *) p;
220   st_translate_fragment_program(st, st->drawpix.z_shader, NULL);
221
222   return st->drawpix.z_shader;
223}
224
225
226
227/**
228 * Create a simple vertex shader that just passes through the
229 * vertex position and texcoord (and optionally, color).
230 */
231static struct st_vertex_program *
232st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor)
233{
234   GLcontext *ctx = st->ctx;
235   struct st_vertex_program *stvp;
236   struct gl_program *p;
237   GLuint ic = 0;
238
239   if (st->drawpix.vert_shaders[passColor])
240      return st->drawpix.vert_shaders[passColor];
241
242   /*
243    * Create shader now
244    */
245   p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
246   if (!p)
247      return NULL;
248
249   if (passColor)
250      p->NumInstructions = 4;
251   else
252      p->NumInstructions = 3;
253
254   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
255   if (!p->Instructions) {
256      ctx->Driver.DeleteProgram(ctx, p);
257      return NULL;
258   }
259   _mesa_init_instructions(p->Instructions, p->NumInstructions);
260   /* MOV result.pos, vertex.pos; */
261   p->Instructions[0].Opcode = OPCODE_MOV;
262   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
263   p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
264   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
265   p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
266   /* MOV result.texcoord0, vertex.texcoord0; */
267   p->Instructions[1].Opcode = OPCODE_MOV;
268   p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
269   p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
270   p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
271   p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
272   ic = 2;
273   if (passColor) {
274      /* MOV result.color0, vertex.color0; */
275      p->Instructions[ic].Opcode = OPCODE_MOV;
276      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
277      p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
278      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
279      p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
280      ic++;
281   }
282
283   /* END; */
284   p->Instructions[ic].Opcode = OPCODE_END;
285   ic++;
286
287   assert(ic == p->NumInstructions);
288
289   p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
290   p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
291                        (1 << VERT_RESULT_HPOS));
292   if (passColor) {
293      p->InputsRead |= VERT_BIT_COLOR0;
294      p->OutputsWritten |= (1 << VERT_RESULT_COL0);
295   }
296
297   stvp = (struct st_vertex_program *) p;
298   st_translate_vertex_program(st, stvp, NULL, NULL, NULL);
299
300   st->drawpix.vert_shaders[passColor] = stvp;
301
302   return stvp;
303}
304
305
306static GLenum
307_mesa_base_format(GLenum format)
308{
309   switch (format) {
310   case GL_DEPTH_COMPONENT:
311      return GL_DEPTH_COMPONENT;
312   case GL_STENCIL_INDEX:
313      return GL_STENCIL_INDEX;
314   default:
315      return GL_RGBA;
316   }
317}
318
319
320/**
321 * Make texture containing an image for glDrawPixels image.
322 * If 'pixels' is NULL, leave the texture image data undefined.
323 */
324static struct pipe_texture *
325make_texture(struct st_context *st,
326	     GLsizei width, GLsizei height, GLenum format, GLenum type,
327	     const struct gl_pixelstore_attrib *unpack,
328	     const GLvoid *pixels)
329{
330   GLcontext *ctx = st->ctx;
331   struct pipe_context *pipe = st->pipe;
332   struct pipe_screen *screen = pipe->screen;
333   const struct gl_texture_format *mformat;
334   struct pipe_texture *pt;
335   enum pipe_format pipeFormat;
336   GLuint cpp;
337   GLenum baseFormat;
338
339   baseFormat = _mesa_base_format(format);
340
341   mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
342   assert(mformat);
343
344   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
345   assert(pipeFormat);
346   cpp = st_sizeof_format(pipeFormat);
347
348   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
349   if (!pixels)
350      return NULL;
351
352   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
353			  1, 0,
354                          PIPE_TEXTURE_USAGE_SAMPLER);
355   if (!pt) {
356      _mesa_unmap_drawpix_pbo(ctx, unpack);
357      return NULL;
358   }
359
360   {
361      struct pipe_transfer *transfer;
362      static const GLuint dstImageOffsets = 0;
363      GLboolean success;
364      GLubyte *dest;
365      const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
366
367      /* we'll do pixel transfer in a fragment shader */
368      ctx->_ImageTransferState = 0x0;
369
370      transfer = screen->get_tex_transfer(screen, pt, 0, 0, 0,
371                                          PIPE_TRANSFER_WRITE, 0, 0,
372                                          width, height);
373
374      /* map texture transfer */
375      dest = screen->transfer_map(screen, transfer);
376
377      /* Put image into texture transfer.
378       * Note that the image is actually going to be upside down in
379       * the texture.  We deal with that with texcoords.
380       */
381      success = mformat->StoreImage(ctx, 2,           /* dims */
382                                    baseFormat,       /* baseInternalFormat */
383                                    mformat,          /* gl_texture_format */
384                                    dest,             /* dest */
385                                    0, 0, 0,          /* dstX/Y/Zoffset */
386                                    transfer->stride, /* dstRowStride, bytes */
387                                    &dstImageOffsets, /* dstImageOffsets */
388                                    width, height, 1, /* size */
389                                    format, type,     /* src format/type */
390                                    pixels,           /* data source */
391                                    unpack);
392
393      /* unmap */
394      screen->transfer_unmap(screen, transfer);
395      screen->tex_transfer_destroy(transfer);
396
397      assert(success);
398
399      /* restore */
400      ctx->_ImageTransferState = imageTransferStateSave;
401   }
402
403   _mesa_unmap_drawpix_pbo(ctx, unpack);
404
405   return pt;
406}
407
408
409/**
410 * Draw quad with texcoords and optional color.
411 * Coords are window coords with y=0=bottom.
412 * \param color  may be null
413 * \param invertTex  if true, flip texcoords vertically
414 */
415static void
416draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
417          GLfloat x1, GLfloat y1, const GLfloat *color,
418          GLboolean invertTex)
419{
420   struct st_context *st = ctx->st;
421   struct pipe_context *pipe = ctx->st->pipe;
422   GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
423
424   /* setup vertex data */
425   {
426      const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
427      const GLfloat fb_width = (GLfloat) fb->Width;
428      const GLfloat fb_height = (GLfloat) fb->Height;
429      const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f;
430      const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
431      const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
432      const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
433      const GLfloat sLeft = 0.0f, sRight = 1.0f;
434      const GLfloat tTop = invertTex, tBot = 1.0f - tTop;
435      GLuint tex, i;
436
437      /* upper-left */
438      verts[0][0][0] = clip_x0;    /* v[0].attr[0].x */
439      verts[0][0][1] = clip_y0;    /* v[0].attr[0].y */
440
441      /* upper-right */
442      verts[1][0][0] = clip_x1;
443      verts[1][0][1] = clip_y0;
444
445      /* lower-right */
446      verts[2][0][0] = clip_x1;
447      verts[2][0][1] = clip_y1;
448
449      /* lower-left */
450      verts[3][0][0] = clip_x0;
451      verts[3][0][1] = clip_y1;
452
453      tex = color ? 2 : 1;
454      verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */
455      verts[0][tex][1] = tTop;  /* v[0].attr[tex].t */
456      verts[1][tex][0] = sRight;
457      verts[1][tex][1] = tTop;
458      verts[2][tex][0] = sRight;
459      verts[2][tex][1] = tBot;
460      verts[3][tex][0] = sLeft;
461      verts[3][tex][1] = tBot;
462
463      /* same for all verts: */
464      if (color) {
465         for (i = 0; i < 4; i++) {
466            verts[i][0][2] = z;   /*Z*/
467            verts[i][0][3] = 1.0f; /*W*/
468            verts[i][1][0] = color[0];
469            verts[i][1][1] = color[1];
470            verts[i][1][2] = color[2];
471            verts[i][1][3] = color[3];
472            verts[i][2][2] = 0.0f; /*R*/
473            verts[i][2][3] = 1.0f; /*Q*/
474         }
475      }
476      else {
477         for (i = 0; i < 4; i++) {
478            verts[i][0][2] = z;   /*Z*/
479            verts[i][0][3] = 1.0f; /*W*/
480            verts[i][1][2] = 0.0f; /*R*/
481            verts[i][1][3] = 1.0f; /*Q*/
482         }
483      }
484   }
485
486   {
487      struct pipe_buffer *buf;
488
489      /* allocate/load buffer object with vertex data */
490      buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX,
491                               sizeof(verts));
492      pipe_buffer_write(pipe->screen, buf, 0, sizeof(verts), verts);
493
494      util_draw_vertex_buffer(pipe, buf, 0,
495                              PIPE_PRIM_QUADS,
496                              4,  /* verts */
497                              3); /* attribs/vert */
498      pipe_buffer_reference(&buf, NULL);
499   }
500}
501
502
503
504static void
505draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
506                   GLsizei width, GLsizei height,
507                   GLfloat zoomX, GLfloat zoomY,
508                   struct pipe_texture *pt,
509                   struct st_vertex_program *stvp,
510                   struct st_fragment_program *stfp,
511                   const GLfloat *color,
512                   GLboolean invertTex)
513{
514   struct st_context *st = ctx->st;
515   struct pipe_context *pipe = ctx->st->pipe;
516   struct cso_context *cso = ctx->st->cso_context;
517   GLfloat x0, y0, x1, y1;
518   GLsizei maxSize;
519
520   /* limit checks */
521   /* XXX if DrawPixels image is larger than max texture size, break
522    * it up into chunks.
523    */
524   maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
525   assert(width <= maxSize);
526   assert(height <= maxSize);
527
528   cso_save_rasterizer(cso);
529   cso_save_viewport(cso);
530   cso_save_samplers(cso);
531   cso_save_sampler_textures(cso);
532   cso_save_fragment_shader(cso);
533   cso_save_vertex_shader(cso);
534
535   /* rasterizer state: just scissor */
536   {
537      struct pipe_rasterizer_state rasterizer;
538      memset(&rasterizer, 0, sizeof(rasterizer));
539      rasterizer.gl_rasterization_rules = 1;
540      rasterizer.scissor = ctx->Scissor.Enabled;
541      cso_set_rasterizer(cso, &rasterizer);
542   }
543
544   /* fragment shader state: TEX lookup program */
545   cso_set_fragment_shader_handle(cso, stfp->driver_shader);
546
547   /* vertex shader state: position + texcoord pass-through */
548   cso_set_vertex_shader_handle(cso, stvp->driver_shader);
549
550
551   /* texture sampling state: */
552   {
553      struct pipe_sampler_state sampler;
554      memset(&sampler, 0, sizeof(sampler));
555      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
556      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
557      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
558      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
559      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
560      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
561      sampler.normalized_coords = 1;
562
563      cso_single_sampler(cso, 0, &sampler);
564      if (st->pixel_xfer.pixelmap_enabled) {
565         cso_single_sampler(cso, 1, &sampler);
566      }
567      cso_single_sampler_done(cso);
568   }
569
570   /* viewport state: viewport matching window dims */
571   {
572      const float width = (float) ctx->DrawBuffer->Width;
573      const float height = (float) ctx->DrawBuffer->Height;
574      struct pipe_viewport_state vp;
575      vp.scale[0] =  0.5f * width;
576      vp.scale[1] = -0.5f * height;
577      vp.scale[2] = 1.0f;
578      vp.scale[3] = 1.0f;
579      vp.translate[0] = 0.5f * width;
580      vp.translate[1] = 0.5f * height;
581      vp.translate[2] = 0.0f;
582      vp.translate[3] = 0.0f;
583      cso_set_viewport(cso, &vp);
584   }
585
586   /* texture state: */
587   if (st->pixel_xfer.pixelmap_enabled) {
588      struct pipe_texture *textures[2];
589      textures[0] = pt;
590      textures[1] = st->pixel_xfer.pixelmap_texture;
591      pipe->set_sampler_textures(pipe, 2, textures);
592   }
593   else {
594      pipe->set_sampler_textures(pipe, 1, &pt);
595   }
596
597   /* Compute window coords (y=0=bottom) with pixel zoom.
598    * Recall that these coords are transformed by the current
599    * vertex shader and viewport transformation.
600    */
601   x0 = (GLfloat) x;
602   x1 = x + width * ctx->Pixel.ZoomX;
603   y0 = (GLfloat) y;
604   y1 = y + height * ctx->Pixel.ZoomY;
605
606   draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex);
607
608   /* restore state */
609   cso_restore_rasterizer(cso);
610   cso_restore_viewport(cso);
611   cso_restore_samplers(cso);
612   cso_restore_sampler_textures(cso);
613   cso_restore_fragment_shader(cso);
614   cso_restore_vertex_shader(cso);
615}
616
617
618static void
619draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
620                    GLsizei width, GLsizei height, GLenum type,
621                    const struct gl_pixelstore_attrib *unpack,
622                    const GLvoid *pixels)
623{
624   struct st_context *st = ctx->st;
625   struct pipe_context *pipe = st->pipe;
626   struct pipe_screen *screen = pipe->screen;
627   struct st_renderbuffer *strb;
628   struct pipe_transfer *pt;
629   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
630   GLint skipPixels;
631   ubyte *stmap;
632
633   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
634
635   strb = st_renderbuffer(ctx->DrawBuffer->
636                          Attachment[BUFFER_STENCIL].Renderbuffer);
637   pt = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0,
638                                 PIPE_TRANSFER_WRITE, x, y,
639                                 width, height);
640
641   stmap = screen->transfer_map(screen, pt);
642
643   /* if width > MAX_WIDTH, have to process image in chunks */
644   skipPixels = 0;
645   while (skipPixels < width) {
646      const GLint spanX = skipPixels;
647      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
648      GLint row;
649      for (row = 0; row < height; row++) {
650         GLint spanY = row;
651         GLubyte values[MAX_WIDTH];
652         GLenum destType = GL_UNSIGNED_BYTE;
653         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
654                                                      width, height,
655                                                      GL_COLOR_INDEX, type,
656                                                      row, skipPixels);
657         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
658                                   type, source, unpack,
659                                   ctx->_ImageTransferState);
660         if (zoom) {
661            /*
662            _swrast_write_zoomed_stencil_span(ctx, 0, 0, spanWidth,
663                                              spanX, spanY, values);
664            */
665         }
666         else {
667            if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
668               spanY = height - spanY - 1;
669            }
670
671            switch (pt->format) {
672            case PIPE_FORMAT_S8_UNORM:
673               {
674                  ubyte *dest = stmap + spanY * pt->stride + spanX;
675                  memcpy(dest, values, spanWidth);
676               }
677               break;
678            case PIPE_FORMAT_S8Z24_UNORM:
679               {
680                  uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
681                  GLint k;
682                  for (k = 0; k < spanWidth; k++) {
683                     uint p = dest[k];
684                     p = (p & 0xffffff) | (values[k] << 24);
685                     dest[k] = p;
686                  }
687               }
688               break;
689            default:
690               assert(0);
691            }
692         }
693      }
694      skipPixels += spanWidth;
695   }
696
697   /* unmap the stencil buffer */
698   screen->transfer_unmap(screen, pt);
699   screen->tex_transfer_destroy(pt);
700}
701
702
703/**
704 * Called via ctx->Driver.DrawPixels()
705 */
706static void
707st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
708              GLenum format, GLenum type,
709              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
710{
711   struct st_fragment_program *stfp;
712   struct st_vertex_program *stvp;
713   struct st_context *st = ctx->st;
714   struct pipe_surface *ps;
715   GLuint bufferFormat;
716   const GLfloat *color;
717
718   if (format == GL_STENCIL_INDEX) {
719      draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
720      return;
721   }
722
723   _mesa_set_vp_override( ctx, TRUE );
724   _mesa_update_state( ctx );
725
726   st_validate_state(st);
727
728   if (format == GL_DEPTH_COMPONENT) {
729      ps = st->state.framebuffer.zsbuf;
730      stfp = make_fragment_shader_z(ctx->st);
731      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
732      color = ctx->Current.RasterColor;
733   }
734   else if (format == GL_STENCIL_INDEX) {
735      ps = st->state.framebuffer.zsbuf;
736      /* XXX special case - can't use texture map */
737      color = NULL;
738   }
739   else {
740      ps = st->state.framebuffer.cbufs[0];
741      stfp = combined_drawpix_fragment_program(ctx);
742      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
743      color = NULL;
744   }
745
746   bufferFormat = ps->format;
747
748   /* draw with textured quad */
749   {
750      struct pipe_texture *pt
751         = make_texture(ctx->st, width, height, format, type, unpack, pixels);
752      if (pt) {
753         draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
754                            width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
755                            pt, stvp, stfp, color, GL_FALSE);
756         pipe_texture_reference(&pt, NULL);
757      }
758   }
759
760   _mesa_set_vp_override( ctx, FALSE );
761}
762
763
764
765static void
766copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
767                    GLsizei width, GLsizei height,
768                    GLint dstx, GLint dsty)
769{
770   struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
771   struct pipe_screen *screen = ctx->st->pipe->screen;
772   struct pipe_transfer *ptDraw;
773   ubyte *drawMap;
774   ubyte *buffer;
775   int i;
776
777   buffer = _mesa_malloc(width * height * sizeof(ubyte));
778   if (!buffer) {
779      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
780      return;
781   }
782
783   /* this will do stencil pixel transfer ops */
784   st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
785                          &ctx->DefaultPacking, buffer);
786
787   ptDraw = screen->get_tex_transfer(screen, rbDraw->texture, 0, 0, 0,
788                                     PIPE_TRANSFER_WRITE, dstx, dsty,
789                                     width, height);
790
791   assert(ptDraw->block.width == 1);
792   assert(ptDraw->block.height == 1);
793
794   /* map the stencil buffer */
795   drawMap = screen->transfer_map(screen, ptDraw);
796
797   /* draw */
798   /* XXX PixelZoom not handled yet */
799   for (i = 0; i < height; i++) {
800      ubyte *dst;
801      const ubyte *src;
802      int y;
803
804      y = i;
805
806      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
807         y = height - y - 1;
808      }
809
810      dst = drawMap + y * ptDraw->stride;
811      src = buffer + i * width;
812
813      switch (ptDraw->format) {
814      case PIPE_FORMAT_S8Z24_UNORM:
815         {
816            uint *dst4 = (uint *) dst;
817            int j;
818            for (j = 0; j < width; j++) {
819               *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
820               dst4++;
821            }
822         }
823         break;
824      case PIPE_FORMAT_S8_UNORM:
825         memcpy(dst, src, width);
826         break;
827      default:
828         assert(0);
829      }
830   }
831
832   _mesa_free(buffer);
833
834   /* unmap the stencil buffer */
835   screen->transfer_unmap(screen, ptDraw);
836   screen->tex_transfer_destroy(ptDraw);
837}
838
839
840static void
841st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
842              GLsizei width, GLsizei height,
843              GLint dstx, GLint dsty, GLenum type)
844{
845   struct st_context *st = ctx->st;
846   struct pipe_context *pipe = st->pipe;
847   struct pipe_screen *screen = pipe->screen;
848   struct st_renderbuffer *rbRead;
849   struct st_vertex_program *stvp;
850   struct st_fragment_program *stfp;
851   struct pipe_texture *pt;
852   GLfloat *color;
853   enum pipe_format srcFormat, texFormat;
854
855   /* make sure rendering has completed */
856   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
857
858   st_validate_state(st);
859
860   if (type == GL_STENCIL) {
861      /* can't use texturing to do stencil */
862      copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
863      return;
864   }
865
866   if (type == GL_COLOR) {
867      rbRead = st_get_color_read_renderbuffer(ctx);
868      color = NULL;
869      stfp = combined_drawpix_fragment_program(ctx);
870      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
871   }
872   else {
873      assert(type == GL_DEPTH);
874      rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
875      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
876      stfp = make_fragment_shader_z(ctx->st);
877      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
878   }
879
880   srcFormat = rbRead->texture->format;
881
882   if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D,
883                                   PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
884      texFormat = srcFormat;
885   }
886   else {
887      /* srcFormat can't be used as a texture format */
888      if (type == GL_DEPTH) {
889         texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D,
890                                      PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
891         assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */
892      }
893      else {
894         /* default color format */
895         texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D,
896                                      PIPE_TEXTURE_USAGE_SAMPLER);
897         assert(texFormat != PIPE_FORMAT_NONE);
898      }
899   }
900
901   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
902                          width, height, 1, 0,
903                          PIPE_TEXTURE_USAGE_SAMPLER);
904   if (!pt)
905      return;
906
907   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
908      srcy = ctx->DrawBuffer->Height - srcy - height;
909   }
910
911   if (srcFormat == texFormat) {
912      /* copy source framebuffer surface into mipmap/texture */
913      struct pipe_surface *psRead = screen->get_tex_surface(screen,
914                                       rbRead->texture, 0, 0, 0,
915                                       PIPE_BUFFER_USAGE_GPU_READ);
916      struct pipe_surface *psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
917                                      PIPE_BUFFER_USAGE_GPU_WRITE );
918      pipe->surface_copy(pipe,
919                         FALSE,
920			 psTex, /* dest */
921			 0, 0, /* destx/y */
922			 psRead,
923			 srcx, srcy, width, height);
924      pipe_surface_reference(&psRead, NULL);
925      pipe_surface_reference(&psTex, NULL);
926   }
927   else {
928      /* CPU-based fallback/conversion */
929      struct pipe_transfer *ptRead =
930         screen->get_tex_transfer(screen, rbRead->texture, 0, 0, 0,
931                                  PIPE_TRANSFER_READ, srcx, srcy, width,
932                                  height);
933
934      struct pipe_transfer *ptTex =
935         screen->get_tex_transfer(screen, pt, 0, 0, 0, PIPE_TRANSFER_WRITE,
936                                  0, 0, width, height);
937
938      if (type == GL_COLOR) {
939         /* alternate path using get/put_tile() */
940         GLfloat *buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
941
942         pipe_get_tile_rgba(ptRead, 0, 0, width, height, buf);
943         pipe_put_tile_rgba(ptTex, 0, 0, width, height, buf);
944
945         _mesa_free(buf);
946      }
947      else {
948         /* GL_DEPTH */
949         GLuint *buf = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
950         pipe_get_tile_z(ptRead, 0, 0, width, height, buf);
951         pipe_put_tile_z(ptTex, 0, 0, width, height, buf);
952         _mesa_free(buf);
953      }
954
955      screen->tex_transfer_destroy(ptRead);
956      screen->tex_transfer_destroy(ptTex);
957   }
958
959   /* draw textured quad */
960   draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
961                      width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
962                      pt, stvp, stfp, color, GL_TRUE);
963
964   pipe_texture_reference(&pt, NULL);
965}
966
967
968
969void st_init_drawpixels_functions(struct dd_function_table *functions)
970{
971   functions->DrawPixels = st_DrawPixels;
972   functions->CopyPixels = st_CopyPixels;
973}
974
975
976void
977st_destroy_drawpix(struct st_context *st)
978{
979   st_reference_fragprog(st, &st->drawpix.z_shader, NULL);
980   st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
981   st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL);
982   st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL);
983}
984