st_cb_drawpixels.c revision b7615e5240707b022b81478dde545cec7fb9397f
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_DEPTH_STENCIL:
313      return GL_DEPTH_STENCIL;
314   case GL_STENCIL_INDEX:
315      return GL_STENCIL_INDEX;
316   default:
317      return GL_RGBA;
318   }
319}
320
321
322/**
323 * Make texture containing an image for glDrawPixels image.
324 * If 'pixels' is NULL, leave the texture image data undefined.
325 */
326static struct pipe_texture *
327make_texture(struct st_context *st,
328	     GLsizei width, GLsizei height, GLenum format, GLenum type,
329	     const struct gl_pixelstore_attrib *unpack,
330	     const GLvoid *pixels)
331{
332   GLcontext *ctx = st->ctx;
333   struct pipe_context *pipe = st->pipe;
334   struct pipe_screen *screen = pipe->screen;
335   const struct gl_texture_format *mformat;
336   struct pipe_texture *pt;
337   enum pipe_format pipeFormat;
338   GLuint cpp;
339   GLenum baseFormat;
340
341   baseFormat = _mesa_base_format(format);
342
343   mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
344   assert(mformat);
345
346   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
347   assert(pipeFormat);
348   cpp = st_sizeof_format(pipeFormat);
349
350   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
351   if (!pixels)
352      return NULL;
353
354   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
355			  1, 0,
356                          PIPE_TEXTURE_USAGE_SAMPLER);
357   if (!pt) {
358      _mesa_unmap_drawpix_pbo(ctx, unpack);
359      return NULL;
360   }
361
362   {
363      struct pipe_transfer *transfer;
364      static const GLuint dstImageOffsets = 0;
365      GLboolean success;
366      GLubyte *dest;
367      const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
368
369      /* we'll do pixel transfer in a fragment shader */
370      ctx->_ImageTransferState = 0x0;
371
372      transfer = screen->get_tex_transfer(screen, pt, 0, 0, 0,
373                                          PIPE_TRANSFER_WRITE, 0, 0,
374                                          width, height);
375
376      /* map texture transfer */
377      dest = screen->transfer_map(screen, transfer);
378
379      /* Put image into texture transfer.
380       * Note that the image is actually going to be upside down in
381       * the texture.  We deal with that with texcoords.
382       */
383      success = mformat->StoreImage(ctx, 2,           /* dims */
384                                    baseFormat,       /* baseInternalFormat */
385                                    mformat,          /* gl_texture_format */
386                                    dest,             /* dest */
387                                    0, 0, 0,          /* dstX/Y/Zoffset */
388                                    transfer->stride, /* dstRowStride, bytes */
389                                    &dstImageOffsets, /* dstImageOffsets */
390                                    width, height, 1, /* size */
391                                    format, type,     /* src format/type */
392                                    pixels,           /* data source */
393                                    unpack);
394
395      /* unmap */
396      screen->transfer_unmap(screen, transfer);
397      screen->tex_transfer_destroy(transfer);
398
399      assert(success);
400
401      /* restore */
402      ctx->_ImageTransferState = imageTransferStateSave;
403   }
404
405   _mesa_unmap_drawpix_pbo(ctx, unpack);
406
407   return pt;
408}
409
410
411/**
412 * Draw quad with texcoords and optional color.
413 * Coords are window coords with y=0=bottom.
414 * \param color  may be null
415 * \param invertTex  if true, flip texcoords vertically
416 */
417static void
418draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
419          GLfloat x1, GLfloat y1, const GLfloat *color,
420          GLboolean invertTex)
421{
422   struct st_context *st = ctx->st;
423   struct pipe_context *pipe = ctx->st->pipe;
424   GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
425
426   /* setup vertex data */
427   {
428      const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
429      const GLfloat fb_width = (GLfloat) fb->Width;
430      const GLfloat fb_height = (GLfloat) fb->Height;
431      const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f;
432      const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
433      const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
434      const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
435      const GLfloat sLeft = 0.0f, sRight = 1.0f;
436      const GLfloat tTop = invertTex, tBot = 1.0f - tTop;
437      GLuint tex, i;
438
439      /* upper-left */
440      verts[0][0][0] = clip_x0;    /* v[0].attr[0].x */
441      verts[0][0][1] = clip_y0;    /* v[0].attr[0].y */
442
443      /* upper-right */
444      verts[1][0][0] = clip_x1;
445      verts[1][0][1] = clip_y0;
446
447      /* lower-right */
448      verts[2][0][0] = clip_x1;
449      verts[2][0][1] = clip_y1;
450
451      /* lower-left */
452      verts[3][0][0] = clip_x0;
453      verts[3][0][1] = clip_y1;
454
455      tex = color ? 2 : 1;
456      verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */
457      verts[0][tex][1] = tTop;  /* v[0].attr[tex].t */
458      verts[1][tex][0] = sRight;
459      verts[1][tex][1] = tTop;
460      verts[2][tex][0] = sRight;
461      verts[2][tex][1] = tBot;
462      verts[3][tex][0] = sLeft;
463      verts[3][tex][1] = tBot;
464
465      /* same for all verts: */
466      if (color) {
467         for (i = 0; i < 4; i++) {
468            verts[i][0][2] = z;   /*Z*/
469            verts[i][0][3] = 1.0f; /*W*/
470            verts[i][1][0] = color[0];
471            verts[i][1][1] = color[1];
472            verts[i][1][2] = color[2];
473            verts[i][1][3] = color[3];
474            verts[i][2][2] = 0.0f; /*R*/
475            verts[i][2][3] = 1.0f; /*Q*/
476         }
477      }
478      else {
479         for (i = 0; i < 4; i++) {
480            verts[i][0][2] = z;   /*Z*/
481            verts[i][0][3] = 1.0f; /*W*/
482            verts[i][1][2] = 0.0f; /*R*/
483            verts[i][1][3] = 1.0f; /*Q*/
484         }
485      }
486   }
487
488   {
489      struct pipe_buffer *buf;
490
491      /* allocate/load buffer object with vertex data */
492      buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX,
493                               sizeof(verts));
494      pipe_buffer_write(pipe->screen, buf, 0, sizeof(verts), verts);
495
496      util_draw_vertex_buffer(pipe, buf, 0,
497                              PIPE_PRIM_QUADS,
498                              4,  /* verts */
499                              3); /* attribs/vert */
500      pipe_buffer_reference(&buf, NULL);
501   }
502}
503
504
505
506static void
507draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
508                   GLsizei width, GLsizei height,
509                   GLfloat zoomX, GLfloat zoomY,
510                   struct pipe_texture *pt,
511                   struct st_vertex_program *stvp,
512                   struct st_fragment_program *stfp,
513                   const GLfloat *color,
514                   GLboolean invertTex)
515{
516   struct st_context *st = ctx->st;
517   struct pipe_context *pipe = ctx->st->pipe;
518   struct cso_context *cso = ctx->st->cso_context;
519   GLfloat x0, y0, x1, y1;
520   GLsizei maxSize;
521
522   /* limit checks */
523   /* XXX if DrawPixels image is larger than max texture size, break
524    * it up into chunks.
525    */
526   maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
527   assert(width <= maxSize);
528   assert(height <= maxSize);
529
530   cso_save_rasterizer(cso);
531   cso_save_viewport(cso);
532   cso_save_samplers(cso);
533   cso_save_sampler_textures(cso);
534   cso_save_fragment_shader(cso);
535   cso_save_vertex_shader(cso);
536
537   /* rasterizer state: just scissor */
538   {
539      struct pipe_rasterizer_state rasterizer;
540      memset(&rasterizer, 0, sizeof(rasterizer));
541      rasterizer.gl_rasterization_rules = 1;
542      rasterizer.scissor = ctx->Scissor.Enabled;
543      cso_set_rasterizer(cso, &rasterizer);
544   }
545
546   /* fragment shader state: TEX lookup program */
547   cso_set_fragment_shader_handle(cso, stfp->driver_shader);
548
549   /* vertex shader state: position + texcoord pass-through */
550   cso_set_vertex_shader_handle(cso, stvp->driver_shader);
551
552
553   /* texture sampling state: */
554   {
555      struct pipe_sampler_state sampler;
556      memset(&sampler, 0, sizeof(sampler));
557      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
558      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
559      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
560      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
561      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
562      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
563      sampler.normalized_coords = 1;
564
565      cso_single_sampler(cso, 0, &sampler);
566      if (st->pixel_xfer.pixelmap_enabled) {
567         cso_single_sampler(cso, 1, &sampler);
568      }
569      cso_single_sampler_done(cso);
570   }
571
572   /* viewport state: viewport matching window dims */
573   {
574      const float width = (float) ctx->DrawBuffer->Width;
575      const float height = (float) ctx->DrawBuffer->Height;
576      struct pipe_viewport_state vp;
577      vp.scale[0] =  0.5f * width;
578      vp.scale[1] = -0.5f * height;
579      vp.scale[2] = 1.0f;
580      vp.scale[3] = 1.0f;
581      vp.translate[0] = 0.5f * width;
582      vp.translate[1] = 0.5f * height;
583      vp.translate[2] = 0.0f;
584      vp.translate[3] = 0.0f;
585      cso_set_viewport(cso, &vp);
586   }
587
588   /* texture state: */
589   if (st->pixel_xfer.pixelmap_enabled) {
590      struct pipe_texture *textures[2];
591      textures[0] = pt;
592      textures[1] = st->pixel_xfer.pixelmap_texture;
593      pipe->set_sampler_textures(pipe, 2, textures);
594   }
595   else {
596      pipe->set_sampler_textures(pipe, 1, &pt);
597   }
598
599   /* Compute window coords (y=0=bottom) with pixel zoom.
600    * Recall that these coords are transformed by the current
601    * vertex shader and viewport transformation.
602    */
603   x0 = (GLfloat) x;
604   x1 = x + width * ctx->Pixel.ZoomX;
605   y0 = (GLfloat) y;
606   y1 = y + height * ctx->Pixel.ZoomY;
607
608   draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex);
609
610   /* restore state */
611   cso_restore_rasterizer(cso);
612   cso_restore_viewport(cso);
613   cso_restore_samplers(cso);
614   cso_restore_sampler_textures(cso);
615   cso_restore_fragment_shader(cso);
616   cso_restore_vertex_shader(cso);
617}
618
619
620static void
621draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
622                    GLsizei width, GLsizei height, GLenum format, GLenum type,
623                    const struct gl_pixelstore_attrib *unpack,
624                    const GLvoid *pixels)
625{
626   struct st_context *st = ctx->st;
627   struct pipe_context *pipe = st->pipe;
628   struct pipe_screen *screen = pipe->screen;
629   struct st_renderbuffer *strb;
630   struct pipe_transfer *pt;
631   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
632   GLint skipPixels;
633   ubyte *stmap;
634
635   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
636
637   strb = st_renderbuffer(ctx->DrawBuffer->
638                          Attachment[BUFFER_STENCIL].Renderbuffer);
639
640   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
641      y = ctx->DrawBuffer->Height - y - height;
642   }
643
644   pt = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0,
645                                 PIPE_TRANSFER_WRITE, x, y,
646                                 width, height);
647
648   stmap = screen->transfer_map(screen, pt);
649
650   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
651   assert(pixels);
652
653   /* if width > MAX_WIDTH, have to process image in chunks */
654   skipPixels = 0;
655   while (skipPixels < width) {
656      const GLint spanX = skipPixels;
657      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
658      GLint row;
659      for (row = 0; row < height; row++) {
660         GLubyte sValues[MAX_WIDTH];
661         GLuint zValues[MAX_WIDTH];
662         GLenum destType = GL_UNSIGNED_BYTE;
663         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
664                                                      width, height,
665                                                      format, type,
666                                                      row, skipPixels);
667         _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues,
668                                   type, source, unpack,
669                                   ctx->_ImageTransferState);
670
671         if (format == GL_DEPTH_STENCIL) {
672            _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues,
673                                    (1 << 24) - 1, type, source, unpack);
674         }
675
676         if (zoom) {
677            _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with "
678                          "zoom not complete");
679         }
680
681         {
682            GLint spanY;
683
684            if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
685               spanY = height - row - 1;
686            }
687            else {
688               spanY = row;
689            }
690
691            /* now pack the stencil (and Z) values in the dest format */
692            switch (pt->format) {
693            case PIPE_FORMAT_S8_UNORM:
694               {
695                  ubyte *dest = stmap + spanY * pt->stride + spanX;
696                  memcpy(dest, sValues, spanWidth);
697               }
698               break;
699            case PIPE_FORMAT_S8Z24_UNORM:
700               if (format == GL_DEPTH_STENCIL) {
701                  uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
702                  GLint k;
703                  for (k = 0; k < spanWidth; k++) {
704                     dest[k] = zValues[k] | (sValues[k] << 24);
705                  }
706               }
707               else {
708                  uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
709                  GLint k;
710                  for (k = 0; k < spanWidth; k++) {
711                     dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24);
712                  }
713               }
714               break;
715            case PIPE_FORMAT_Z24S8_UNORM:
716               if (format == GL_DEPTH_STENCIL) {
717                  uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
718                  GLint k;
719                  for (k = 0; k < spanWidth; k++) {
720                     dest[k] = zValues[k] | (sValues[k] << 24);
721                  }
722               }
723               else {
724                  uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
725                  GLint k;
726                  for (k = 0; k < spanWidth; k++) {
727                     dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff);
728                  }
729               }
730               break;
731            default:
732               assert(0);
733            }
734         }
735      }
736      skipPixels += spanWidth;
737   }
738
739   _mesa_unmap_drawpix_pbo(ctx, unpack);
740
741   /* unmap the stencil buffer */
742   screen->transfer_unmap(screen, pt);
743   screen->tex_transfer_destroy(pt);
744}
745
746
747/**
748 * Called via ctx->Driver.DrawPixels()
749 */
750static void
751st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
752              GLenum format, GLenum type,
753              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
754{
755   struct st_fragment_program *stfp;
756   struct st_vertex_program *stvp;
757   struct st_context *st = ctx->st;
758   struct pipe_surface *ps;
759   GLuint bufferFormat;
760   const GLfloat *color;
761
762   if (format == GL_STENCIL_INDEX ||
763       format == GL_DEPTH_STENCIL) {
764      draw_stencil_pixels(ctx, x, y, width, height, format, type,
765                          unpack, pixels);
766      return;
767   }
768
769   _mesa_set_vp_override( ctx, TRUE );
770   _mesa_update_state( ctx );
771
772   st_validate_state(st);
773
774   if (format == GL_DEPTH_COMPONENT) {
775      ps = st->state.framebuffer.zsbuf;
776      stfp = make_fragment_shader_z(ctx->st);
777      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
778      color = ctx->Current.RasterColor;
779   }
780   else {
781      ps = st->state.framebuffer.cbufs[0];
782      stfp = combined_drawpix_fragment_program(ctx);
783      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
784      color = NULL;
785   }
786
787   bufferFormat = ps->format;
788
789   /* draw with textured quad */
790   {
791      struct pipe_texture *pt
792         = make_texture(ctx->st, width, height, format, type, unpack, pixels);
793      if (pt) {
794         draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
795                            width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
796                            pt, stvp, stfp, color, GL_FALSE);
797         pipe_texture_reference(&pt, NULL);
798      }
799   }
800
801   _mesa_set_vp_override( ctx, FALSE );
802}
803
804
805
806static void
807copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
808                    GLsizei width, GLsizei height,
809                    GLint dstx, GLint dsty)
810{
811   struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
812   struct pipe_screen *screen = ctx->st->pipe->screen;
813   struct pipe_transfer *ptDraw;
814   ubyte *drawMap;
815   ubyte *buffer;
816   int i;
817
818   buffer = _mesa_malloc(width * height * sizeof(ubyte));
819   if (!buffer) {
820      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
821      return;
822   }
823
824   /* this will do stencil pixel transfer ops */
825   st_read_stencil_pixels(ctx, srcx, srcy, width, height,
826                          GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
827                          &ctx->DefaultPacking, buffer);
828
829   ptDraw = screen->get_tex_transfer(screen, rbDraw->texture, 0, 0, 0,
830                                     PIPE_TRANSFER_WRITE, dstx, dsty,
831                                     width, height);
832
833   assert(ptDraw->block.width == 1);
834   assert(ptDraw->block.height == 1);
835
836   /* map the stencil buffer */
837   drawMap = screen->transfer_map(screen, ptDraw);
838
839   /* draw */
840   /* XXX PixelZoom not handled yet */
841   for (i = 0; i < height; i++) {
842      ubyte *dst;
843      const ubyte *src;
844      int y;
845
846      y = i;
847
848      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
849         y = height - y - 1;
850      }
851
852      dst = drawMap + y * ptDraw->stride;
853      src = buffer + i * width;
854
855      switch (ptDraw->format) {
856      case PIPE_FORMAT_S8Z24_UNORM:
857         {
858            uint *dst4 = (uint *) dst;
859            int j;
860            for (j = 0; j < width; j++) {
861               *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
862               dst4++;
863            }
864         }
865         break;
866      case PIPE_FORMAT_Z24S8_UNORM:
867         {
868            uint *dst4 = (uint *) dst;
869            int j;
870            for (j = 0; j < width; j++) {
871               *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff);
872               dst4++;
873            }
874         }
875         break;
876      case PIPE_FORMAT_S8_UNORM:
877         memcpy(dst, src, width);
878         break;
879      default:
880         assert(0);
881      }
882   }
883
884   _mesa_free(buffer);
885
886   /* unmap the stencil buffer */
887   screen->transfer_unmap(screen, ptDraw);
888   screen->tex_transfer_destroy(ptDraw);
889}
890
891
892static void
893st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
894              GLsizei width, GLsizei height,
895              GLint dstx, GLint dsty, GLenum type)
896{
897   struct st_context *st = ctx->st;
898   struct pipe_context *pipe = st->pipe;
899   struct pipe_screen *screen = pipe->screen;
900   struct st_renderbuffer *rbRead;
901   struct st_vertex_program *stvp;
902   struct st_fragment_program *stfp;
903   struct pipe_texture *pt;
904   GLfloat *color;
905   enum pipe_format srcFormat, texFormat;
906
907   /* make sure rendering has completed */
908   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
909
910   st_validate_state(st);
911
912   if (type == GL_STENCIL) {
913      /* can't use texturing to do stencil */
914      copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
915      return;
916   }
917
918   if (type == GL_COLOR) {
919      rbRead = st_get_color_read_renderbuffer(ctx);
920      color = NULL;
921      stfp = combined_drawpix_fragment_program(ctx);
922      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
923   }
924   else {
925      assert(type == GL_DEPTH);
926      rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
927      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
928      stfp = make_fragment_shader_z(ctx->st);
929      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
930   }
931
932   srcFormat = rbRead->texture->format;
933
934   if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D,
935                                   PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
936      texFormat = srcFormat;
937   }
938   else {
939      /* srcFormat can't be used as a texture format */
940      if (type == GL_DEPTH) {
941         texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D,
942                                      PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
943         assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */
944      }
945      else {
946         /* default color format */
947         texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D,
948                                      PIPE_TEXTURE_USAGE_SAMPLER);
949         assert(texFormat != PIPE_FORMAT_NONE);
950      }
951   }
952
953   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
954                          width, height, 1, 0,
955                          PIPE_TEXTURE_USAGE_SAMPLER);
956   if (!pt)
957      return;
958
959   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
960      srcy = ctx->DrawBuffer->Height - srcy - height;
961   }
962
963   if (srcFormat == texFormat) {
964      /* copy source framebuffer surface into mipmap/texture */
965      struct pipe_surface *psRead = screen->get_tex_surface(screen,
966                                       rbRead->texture, 0, 0, 0,
967                                       PIPE_BUFFER_USAGE_GPU_READ);
968      struct pipe_surface *psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
969                                      PIPE_BUFFER_USAGE_GPU_WRITE );
970      pipe->surface_copy(pipe,
971			 psTex, /* dest */
972			 0, 0, /* destx/y */
973			 psRead,
974			 srcx, srcy, width, height);
975      pipe_surface_reference(&psRead, NULL);
976      pipe_surface_reference(&psTex, NULL);
977   }
978   else {
979      /* CPU-based fallback/conversion */
980      struct pipe_transfer *ptRead =
981         screen->get_tex_transfer(screen, rbRead->texture, 0, 0, 0,
982                                  PIPE_TRANSFER_READ, srcx, srcy, width,
983                                  height);
984
985      struct pipe_transfer *ptTex =
986         screen->get_tex_transfer(screen, pt, 0, 0, 0, PIPE_TRANSFER_WRITE,
987                                  0, 0, width, height);
988
989      if (type == GL_COLOR) {
990         /* alternate path using get/put_tile() */
991         GLfloat *buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
992
993         pipe_get_tile_rgba(ptRead, 0, 0, width, height, buf);
994         pipe_put_tile_rgba(ptTex, 0, 0, width, height, buf);
995
996         _mesa_free(buf);
997      }
998      else {
999         /* GL_DEPTH */
1000         GLuint *buf = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
1001         pipe_get_tile_z(ptRead, 0, 0, width, height, buf);
1002         pipe_put_tile_z(ptTex, 0, 0, width, height, buf);
1003         _mesa_free(buf);
1004      }
1005
1006      screen->tex_transfer_destroy(ptRead);
1007      screen->tex_transfer_destroy(ptTex);
1008   }
1009
1010   /* draw textured quad */
1011   draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1012                      width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1013                      pt, stvp, stfp, color, GL_TRUE);
1014
1015   pipe_texture_reference(&pt, NULL);
1016}
1017
1018
1019
1020void st_init_drawpixels_functions(struct dd_function_table *functions)
1021{
1022   functions->DrawPixels = st_DrawPixels;
1023   functions->CopyPixels = st_CopyPixels;
1024}
1025
1026
1027void
1028st_destroy_drawpix(struct st_context *st)
1029{
1030   st_reference_fragprog(st, &st->drawpix.z_shader, NULL);
1031   st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
1032   st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL);
1033   st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL);
1034}
1035