st_cb_drawpixels.c revision e3f3e22cf7e9af4c5416d37329b7b8ee50f0cfcb
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 "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 "util/p_tile.h"
59#include "util/u_draw_quad.h"
60#include "shader/prog_instruction.h"
61#include "cso_cache/cso_context.h"
62
63
64/**
65 * Check if the given program is:
66 * 0: MOVE result.color, fragment.color;
67 * 1: END;
68 */
69static GLboolean
70is_passthrough_program(const struct gl_fragment_program *prog)
71{
72   if (prog->Base.NumInstructions == 2) {
73      const struct prog_instruction *inst = prog->Base.Instructions;
74      if (inst[0].Opcode == OPCODE_MOV &&
75          inst[1].Opcode == OPCODE_END &&
76          inst[0].DstReg.File == PROGRAM_OUTPUT &&
77          inst[0].DstReg.Index == FRAG_RESULT_COLR &&
78          inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
79          inst[0].SrcReg[0].File == PROGRAM_INPUT &&
80          inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
81          inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
82         return GL_TRUE;
83      }
84   }
85   return GL_FALSE;
86}
87
88
89
90/**
91 * Make fragment shader for glDraw/CopyPixels.  This shader is made
92 * by combining the pixel transfer shader with the user-defined shader.
93 */
94static struct st_fragment_program *
95combined_drawpix_fragment_program(GLcontext *ctx)
96{
97   struct st_context *st = ctx->st;
98   struct st_fragment_program *stfp;
99
100   if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
101       && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
102      /* the pixel tranfer program has not changed and the user-defined
103       * program has not changed, so re-use the combined program.
104       */
105      stfp = st->pixel_xfer.combined_prog;
106   }
107   else {
108      /* Concatenate the pixel transfer program with the current user-
109       * defined program.
110       */
111      if (is_passthrough_program(&st->fp->Base)) {
112         stfp = (struct st_fragment_program *)
113            _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base);
114      }
115      else {
116#if 0
117         printf("Base program:\n");
118         _mesa_print_program(&st->fp->Base.Base);
119         printf("DrawPix program:\n");
120         _mesa_print_program(&st->pixel_xfer.program->Base.Base);
121#endif
122         stfp = (struct st_fragment_program *)
123            _mesa_combine_programs(ctx,
124                                   &st->pixel_xfer.program->Base.Base,
125                                   &st->fp->Base.Base);
126      }
127
128#if 0
129      {
130         struct gl_program *p = &stfp->Base.Base;
131         printf("Combined DrawPixels program:\n");
132         _mesa_print_program(p);
133         printf("InputsRead: 0x%x\n", p->InputsRead);
134         printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
135         _mesa_print_parameter_list(p->Parameters);
136      }
137#endif
138
139      /* translate to TGSI tokens */
140      st_translate_fragment_program(st, stfp, NULL);
141
142      /* save new program, update serial numbers */
143      st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
144      st->pixel_xfer.user_prog_sn = st->fp->serialNo;
145      st->pixel_xfer.combined_prog_sn = stfp->serialNo;
146      st->pixel_xfer.combined_prog = stfp;
147   }
148
149   /* Ideally we'd have updated the pipe constants during the normal
150    * st/atom mechanism.  But we can't since this is specific to glDrawPixels.
151    */
152   st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
153
154   return stfp;
155}
156
157
158/**
159 * Create fragment shader that does a TEX() instruction to get a Z
160 * value, then writes to FRAG_RESULT_DEPR.
161 * Pass fragment color through as-is.
162 */
163static struct st_fragment_program *
164make_fragment_shader_z(struct st_context *st)
165{
166   GLcontext *ctx = st->ctx;
167   struct gl_program *p;
168   GLuint ic = 0;
169
170   if (st->drawpix.z_shader) {
171      return st->drawpix.z_shader;
172   }
173
174   /*
175    * Create shader now
176    */
177   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
178   if (!p)
179      return NULL;
180
181   p->NumInstructions = 3;
182
183   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
184   if (!p->Instructions) {
185      ctx->Driver.DeleteProgram(ctx, p);
186      return NULL;
187   }
188   _mesa_init_instructions(p->Instructions, p->NumInstructions);
189
190   /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
191   p->Instructions[ic].Opcode = OPCODE_TEX;
192   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
193   p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR;
194   p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
195   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
196   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
197   p->Instructions[ic].TexSrcUnit = 0;
198   p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
199   ic++;
200
201   /* MOV result.color, fragment.color */
202   p->Instructions[ic].Opcode = OPCODE_MOV;
203   p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
204   p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
205   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
206   p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
207   ic++;
208
209   /* END; */
210   p->Instructions[ic++].Opcode = OPCODE_END;
211
212   assert(ic == p->NumInstructions);
213
214   p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
215   p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR);
216   p->SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */
217
218   st->drawpix.z_shader = (struct st_fragment_program *) p;
219   st_translate_fragment_program(st, st->drawpix.z_shader, NULL);
220
221   return st->drawpix.z_shader;
222}
223
224
225
226/**
227 * Create a simple vertex shader that just passes through the
228 * vertex position and texcoord (and optionally, color).
229 */
230static struct st_vertex_program *
231st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor)
232{
233   GLcontext *ctx = st->ctx;
234   struct st_vertex_program *stvp;
235   struct gl_program *p;
236   GLuint ic = 0;
237
238   if (st->drawpix.vert_shaders[passColor])
239      return st->drawpix.vert_shaders[passColor];
240
241   /*
242    * Create shader now
243    */
244   p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
245   if (!p)
246      return NULL;
247
248   if (passColor)
249      p->NumInstructions = 4;
250   else
251      p->NumInstructions = 3;
252
253   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
254   if (!p->Instructions) {
255      ctx->Driver.DeleteProgram(ctx, p);
256      return NULL;
257   }
258   _mesa_init_instructions(p->Instructions, p->NumInstructions);
259   /* MOV result.pos, vertex.pos; */
260   p->Instructions[0].Opcode = OPCODE_MOV;
261   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
262   p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
263   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
264   p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
265   /* MOV result.texcoord0, vertex.texcoord0; */
266   p->Instructions[1].Opcode = OPCODE_MOV;
267   p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
268   p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
269   p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
270   p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
271   ic = 2;
272   if (passColor) {
273      /* MOV result.color0, vertex.color0; */
274      p->Instructions[ic].Opcode = OPCODE_MOV;
275      p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
276      p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
277      p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
278      p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
279      ic++;
280   }
281
282   /* END; */
283   p->Instructions[ic].Opcode = OPCODE_END;
284   ic++;
285
286   assert(ic == p->NumInstructions);
287
288   p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
289   p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
290                        (1 << VERT_RESULT_HPOS));
291   if (passColor) {
292      p->InputsRead |= VERT_BIT_COLOR0;
293      p->OutputsWritten |= (1 << VERT_RESULT_COL0);
294   }
295
296   stvp = (struct st_vertex_program *) p;
297   st_translate_vertex_program(st, stvp, NULL, NULL, NULL);
298
299   st->drawpix.vert_shaders[passColor] = stvp;
300
301   return stvp;
302}
303
304
305static GLenum
306_mesa_base_format(GLenum format)
307{
308   switch (format) {
309   case GL_DEPTH_COMPONENT:
310      return GL_DEPTH_COMPONENT;
311   case GL_STENCIL_INDEX:
312      return GL_STENCIL_INDEX;
313   default:
314      return GL_RGBA;
315   }
316}
317
318
319/**
320 * Make texture containing an image for glDrawPixels image.
321 * If 'pixels' is NULL, leave the texture image data undefined.
322 */
323static struct pipe_texture *
324make_texture(struct st_context *st,
325	     GLsizei width, GLsizei height, GLenum format, GLenum type,
326	     const struct gl_pixelstore_attrib *unpack,
327	     const GLvoid *pixels)
328{
329   GLcontext *ctx = st->ctx;
330   struct pipe_context *pipe = st->pipe;
331   struct pipe_screen *screen = pipe->screen;
332   const struct gl_texture_format *mformat;
333   struct pipe_texture *pt;
334   enum pipe_format pipeFormat;
335   GLuint cpp;
336   GLenum baseFormat;
337
338   baseFormat = _mesa_base_format(format);
339
340   mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
341   assert(mformat);
342
343   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
344   assert(pipeFormat);
345   cpp = st_sizeof_format(pipeFormat);
346
347   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
348   if (!pixels)
349      return NULL;
350
351   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
352			  1, 0,
353                          PIPE_TEXTURE_USAGE_SAMPLER);
354   if (!pt) {
355      _mesa_unmap_drawpix_pbo(ctx, unpack);
356      return NULL;
357   }
358
359   {
360      struct pipe_surface *surface;
361      static const GLuint dstImageOffsets = 0;
362      GLboolean success;
363      GLubyte *dest;
364      const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
365
366      /* we'll do pixel transfer in a fragment shader */
367      ctx->_ImageTransferState = 0x0;
368
369      surface = screen->get_tex_surface(screen, pt, 0, 0, 0,
370                                        PIPE_BUFFER_USAGE_CPU_WRITE);
371
372      /* map texture surface */
373      dest = screen->surface_map(screen, surface,
374                                 PIPE_BUFFER_USAGE_CPU_WRITE);
375
376      /* Put image into texture surface.
377       * Note that the image is actually going to be upside down in
378       * the texture.  We deal with that with texcoords.
379       */
380      success = mformat->StoreImage(ctx, 2,           /* dims */
381                                    baseFormat,       /* baseInternalFormat */
382                                    mformat,          /* gl_texture_format */
383                                    dest,             /* dest */
384                                    0, 0, 0,          /* dstX/Y/Zoffset */
385                                    surface->stride,  /* dstRowStride, bytes */
386                                    &dstImageOffsets, /* dstImageOffsets */
387                                    width, height, 1, /* size */
388                                    format, type,     /* src format/type */
389                                    pixels,           /* data source */
390                                    unpack);
391
392      /* unmap */
393      screen->surface_unmap(screen, surface);
394      pipe_surface_reference(&surface, NULL);
395
396      assert(success);
397
398      /* restore */
399      ctx->_ImageTransferState = imageTransferStateSave;
400   }
401
402   _mesa_unmap_drawpix_pbo(ctx, unpack);
403
404   return pt;
405}
406
407
408/**
409 * Draw quad with texcoords and optional color.
410 * Coords are window coords with y=0=bottom.
411 * \param color  may be null
412 * \param invertTex  if true, flip texcoords vertically
413 */
414static void
415draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
416          GLfloat x1, GLfloat y1, const GLfloat *color,
417          GLboolean invertTex)
418{
419   struct st_context *st = ctx->st;
420   struct pipe_context *pipe = ctx->st->pipe;
421   GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
422
423   /* setup vertex data */
424   {
425      const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
426      const GLfloat fb_width = (GLfloat) fb->Width;
427      const GLfloat fb_height = (GLfloat) fb->Height;
428      const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f;
429      const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
430      const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
431      const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
432      const GLfloat sLeft = 0.0f, sRight = 1.0f;
433      const GLfloat tTop = invertTex, tBot = 1.0f - tTop;
434      GLuint tex, i;
435
436      /* upper-left */
437      verts[0][0][0] = clip_x0;    /* v[0].attr[0].x */
438      verts[0][0][1] = clip_y0;    /* v[0].attr[0].y */
439
440      /* upper-right */
441      verts[1][0][0] = clip_x1;
442      verts[1][0][1] = clip_y0;
443
444      /* lower-right */
445      verts[2][0][0] = clip_x1;
446      verts[2][0][1] = clip_y1;
447
448      /* lower-left */
449      verts[3][0][0] = clip_x0;
450      verts[3][0][1] = clip_y1;
451
452      tex = color ? 2 : 1;
453      verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */
454      verts[0][tex][1] = tTop;  /* v[0].attr[tex].t */
455      verts[1][tex][0] = sRight;
456      verts[1][tex][1] = tTop;
457      verts[2][tex][0] = sRight;
458      verts[2][tex][1] = tBot;
459      verts[3][tex][0] = sLeft;
460      verts[3][tex][1] = tBot;
461
462      /* same for all verts: */
463      if (color) {
464         for (i = 0; i < 4; i++) {
465            verts[i][0][2] = z;   /*Z*/
466            verts[i][0][3] = 1.0f; /*W*/
467            verts[i][1][0] = color[0];
468            verts[i][1][1] = color[1];
469            verts[i][1][2] = color[2];
470            verts[i][1][3] = color[3];
471            verts[i][2][2] = 0.0f; /*R*/
472            verts[i][2][3] = 1.0f; /*Q*/
473         }
474      }
475      else {
476         for (i = 0; i < 4; i++) {
477            verts[i][0][2] = z;   /*Z*/
478            verts[i][0][3] = 1.0f; /*W*/
479            verts[i][1][2] = 0.0f; /*R*/
480            verts[i][1][3] = 1.0f; /*Q*/
481         }
482      }
483   }
484
485   {
486      struct pipe_buffer *buf;
487      ubyte *map;
488
489      /* allocate/load buffer object with vertex data */
490      buf = pipe_buffer_create(pipe, 32, PIPE_BUFFER_USAGE_VERTEX,
491                               sizeof(verts));
492      map = pipe_buffer_map(pipe, buf, PIPE_BUFFER_USAGE_CPU_WRITE);
493      memcpy(map, verts, sizeof(verts));
494      pipe_buffer_unmap(pipe, buf);
495
496      util_draw_vertex_buffer(pipe, buf,
497                              PIPE_PRIM_QUADS,
498                              4,  /* verts */
499                              3); /* attribs/vert */
500      pipe_buffer_reference(pipe->winsys, &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   //if(!color)
608   draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex);
609   //else
610   //printf("skip draw quad\n");
611   /* restore state */
612   cso_restore_rasterizer(cso);
613   cso_restore_viewport(cso);
614   cso_restore_samplers(cso);
615   cso_restore_sampler_textures(cso);
616   cso_restore_fragment_shader(cso);
617   cso_restore_vertex_shader(cso);
618}
619
620
621/**
622 * Check if a GL format/type combination is a match to the given pipe format.
623 * XXX probably move this to a re-usable place.
624 */
625static GLboolean
626compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat)
627{
628   static const GLuint one = 1;
629   GLubyte littleEndian = *((GLubyte *) &one);
630
631   if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
632       format == GL_RGBA &&
633       type == GL_UNSIGNED_BYTE &&
634       !littleEndian) {
635      return GL_TRUE;
636   }
637   else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
638            format == GL_ABGR_EXT &&
639            type == GL_UNSIGNED_BYTE &&
640            littleEndian) {
641      return GL_TRUE;
642   }
643   else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM &&
644            format == GL_BGRA &&
645            type == GL_UNSIGNED_BYTE &&
646            littleEndian) {
647      return GL_TRUE;
648   }
649   else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
650            format == GL_RGB &&
651            type == GL_UNSIGNED_SHORT_5_6_5) {
652      /* endian don't care */
653      return GL_TRUE;
654   }
655   else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
656            format == GL_BGR &&
657            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
658      /* endian don't care */
659      return GL_TRUE;
660   }
661   else if (pipeFormat == PIPE_FORMAT_S8_UNORM &&
662            format == GL_STENCIL_INDEX &&
663            type == GL_UNSIGNED_BYTE) {
664      return GL_TRUE;
665   }
666   else if (pipeFormat == PIPE_FORMAT_Z32_UNORM &&
667            format == GL_DEPTH_COMPONENT &&
668            type == GL_UNSIGNED_INT) {
669      return GL_TRUE;
670   }
671   /* XXX add more cases */
672   else {
673      return GL_FALSE;
674   }
675}
676
677
678/**
679 * Check if any per-fragment ops are enabled.
680 * XXX probably move this to a re-usable place.
681 */
682static GLboolean
683any_fragment_ops(const struct st_context *st)
684{
685   if (st->state.depth_stencil.alpha.enabled ||
686       st->state.depth_stencil.depth.enabled ||
687       st->state.blend.blend_enable ||
688       st->state.blend.logicop_enable)
689      /* XXX more checks */
690      return GL_TRUE;
691   else
692      return GL_FALSE;
693}
694
695
696/**
697 * Check if any pixel transfer ops are enabled.
698 * XXX probably move this to a re-usable place.
699 */
700static GLboolean
701any_pixel_transfer_ops(const struct st_context *st)
702{
703   if (st->ctx->Pixel.RedScale != 1.0 ||
704       st->ctx->Pixel.RedBias != 0.0 ||
705       st->ctx->Pixel.GreenScale != 1.0 ||
706       st->ctx->Pixel.GreenBias != 0.0 ||
707       st->ctx->Pixel.BlueScale != 1.0 ||
708       st->ctx->Pixel.BlueBias != 0.0 ||
709       st->ctx->Pixel.AlphaScale != 1.0 ||
710       st->ctx->Pixel.AlphaBias != 0.0 ||
711       st->ctx->Pixel.MapColorFlag)
712      /* XXX more checks */
713      return GL_TRUE;
714   else
715      return GL_FALSE;
716}
717
718
719/**
720 * Draw image with a blit, or other non-textured quad method.
721 */
722static void
723draw_blit(struct st_context *st,
724          GLsizei width, GLsizei height,
725          GLenum format, GLenum type, const GLvoid *pixels)
726{
727
728
729}
730
731
732static void
733draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
734                    GLsizei width, GLsizei height, GLenum type,
735                    const struct gl_pixelstore_attrib *unpack,
736                    const GLvoid *pixels)
737{
738   struct st_context *st = ctx->st;
739   struct pipe_context *pipe = st->pipe;
740   struct pipe_screen *screen = pipe->screen;
741   struct st_renderbuffer *strb;
742   struct pipe_surface *ps;
743   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
744   GLint skipPixels;
745   ubyte *stmap;
746
747   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
748
749   strb = st_renderbuffer(ctx->DrawBuffer->
750                          Attachment[BUFFER_STENCIL].Renderbuffer);
751   ps = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
752                                PIPE_BUFFER_USAGE_CPU_WRITE);
753
754   /* map the stencil buffer */
755   stmap = screen->surface_map(screen, ps,
756                               PIPE_BUFFER_USAGE_CPU_WRITE);
757
758   /* if width > MAX_WIDTH, have to process image in chunks */
759   skipPixels = 0;
760   while (skipPixels < width) {
761      const GLint spanX = x + skipPixels;
762      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
763      GLint row;
764      for (row = 0; row < height; row++) {
765         GLint spanY = y + row;
766         GLubyte values[MAX_WIDTH];
767         GLenum destType = GL_UNSIGNED_BYTE;
768         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
769                                                      width, height,
770                                                      GL_COLOR_INDEX, type,
771                                                      row, skipPixels);
772         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
773                                   type, source, unpack,
774                                   ctx->_ImageTransferState);
775         if (zoom) {
776            /*
777            _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
778                                              spanX, spanY, values);
779            */
780         }
781         else {
782            if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
783               spanY = ctx->DrawBuffer->Height - spanY - 1;
784            }
785
786            switch (ps->format) {
787            case PIPE_FORMAT_S8_UNORM:
788               {
789                  ubyte *dest = stmap + spanY * ps->stride + spanX;
790                  memcpy(dest, values, spanWidth);
791               }
792               break;
793            case PIPE_FORMAT_S8Z24_UNORM:
794               {
795                  uint *dest = (uint *) (stmap + spanY * ps->stride + spanX*4);
796                  GLint k;
797                  for (k = 0; k < spanWidth; k++) {
798                     uint p = dest[k];
799                     p = (p & 0xffffff) | (values[k] << 24);
800                     dest[k] = p;
801                  }
802               }
803               break;
804            default:
805               assert(0);
806            }
807         }
808      }
809      skipPixels += spanWidth;
810   }
811
812   /* unmap the stencil buffer */
813   screen->surface_unmap(screen, ps);
814   pipe_surface_reference(&ps, NULL);
815}
816
817
818/**
819 * Called via ctx->Driver.DrawPixels()
820 */
821static void
822st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
823              GLenum format, GLenum type,
824              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
825{
826   struct st_fragment_program *stfp;
827   struct st_vertex_program *stvp;
828   struct st_context *st = ctx->st;
829   struct pipe_surface *ps;
830   GLuint bufferFormat;
831   const GLfloat *color;
832
833   if (format == GL_STENCIL_INDEX) {
834      draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
835      return;
836   }
837
838   st_validate_state(st);
839
840   if (format == GL_DEPTH_COMPONENT) {
841      ps = st->state.framebuffer.zsbuf;
842      stfp = make_fragment_shader_z(ctx->st);
843      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
844      color = ctx->Current.RasterColor;
845   }
846   else if (format == GL_STENCIL_INDEX) {
847      ps = st->state.framebuffer.zsbuf;
848      /* XXX special case - can't use texture map */
849      color = NULL;
850   }
851   else {
852      ps = st->state.framebuffer.cbufs[0];
853      stfp = combined_drawpix_fragment_program(ctx);
854      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
855      color = NULL;
856   }
857
858   bufferFormat = ps->format;
859
860   if (1/*any_fragment_ops(st) ||
861       any_pixel_transfer_ops(st) ||
862       !compatible_formats(format, type, ps->format)*/) {
863      /* textured quad */
864      struct pipe_texture *pt
865         = make_texture(ctx->st, width, height, format, type, unpack, pixels);
866      if (pt) {
867         draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
868                            width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
869                            pt, stvp, stfp, color, GL_FALSE);
870         pipe_texture_reference(&pt, NULL);
871      }
872   }
873   else {
874      /* blit */
875      draw_blit(st, width, height, format, type, pixels);
876   }
877}
878
879
880
881static void
882copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
883                    GLsizei width, GLsizei height,
884                    GLint dstx, GLint dsty)
885{
886   struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
887   struct pipe_screen *screen = ctx->st->pipe->screen;
888   struct pipe_surface *psDraw;
889   ubyte *drawMap;
890   ubyte *buffer;
891   int i;
892
893   buffer = malloc(width * height * sizeof(ubyte));
894   if (!buffer) {
895      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
896      return;
897   }
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   psDraw = screen->get_tex_surface(screen, rbDraw->texture, 0, 0, 0,
904                                    PIPE_BUFFER_USAGE_CPU_WRITE);
905
906   assert(psDraw->block.width == 1);
907   assert(psDraw->block.height == 1);
908
909   /* map the stencil buffer */
910   drawMap = screen->surface_map(screen, psDraw, PIPE_BUFFER_USAGE_CPU_WRITE);
911
912   /* draw */
913   /* XXX PixelZoom not handled yet */
914   for (i = 0; i < height; i++) {
915      ubyte *dst;
916      const ubyte *src;
917      int y;
918
919      y = dsty + i;
920
921      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
922         y = ctx->DrawBuffer->Height - y - 1;
923      }
924
925      dst = drawMap + y * psDraw->stride + dstx * psDraw->block.size;
926      src = buffer + i * width;
927
928      switch (psDraw->format) {
929      case PIPE_FORMAT_S8Z24_UNORM:
930         {
931            uint *dst4 = (uint *) dst;
932            int j;
933            for (j = 0; j < width; j++) {
934               *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
935               dst4++;
936            }
937         }
938         break;
939      case PIPE_FORMAT_S8_UNORM:
940         memcpy(dst, src, width);
941         break;
942      default:
943         assert(0);
944      }
945   }
946
947   free(buffer);
948
949   /* unmap the stencil buffer */
950   screen->surface_unmap(screen, psDraw);
951   pipe_surface_reference(&psDraw, NULL);
952}
953
954
955static void
956st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
957              GLsizei width, GLsizei height,
958              GLint dstx, GLint dsty, GLenum type)
959{
960   struct st_context *st = ctx->st;
961   struct pipe_context *pipe = st->pipe;
962   struct pipe_screen *screen = pipe->screen;
963   struct st_renderbuffer *rbRead;
964   struct st_vertex_program *stvp;
965   struct st_fragment_program *stfp;
966   struct pipe_surface *psTex;
967   struct pipe_texture *pt;
968   GLfloat *color;
969   enum pipe_format srcFormat, texFormat;
970
971   /* make sure rendering has completed */
972   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
973
974   st_validate_state(st);
975
976   if (type == GL_STENCIL) {
977      /* can't use texturing to do stencil */
978      copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
979      return;
980   }
981
982   if (type == GL_COLOR) {
983      rbRead = st_get_color_read_renderbuffer(ctx);
984      color = NULL;
985      stfp = combined_drawpix_fragment_program(ctx);
986      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
987   }
988   else {
989      assert(type == GL_DEPTH);
990      rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
991      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
992      stfp = make_fragment_shader_z(ctx->st);
993      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
994   }
995
996   srcFormat = rbRead->texture->format;
997
998   if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D,
999                                   PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
1000      texFormat = srcFormat;
1001   }
1002   else {
1003      /* srcFormat can't be used as a texture format */
1004      if (type == GL_DEPTH) {
1005         texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D,
1006                                      PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
1007         assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */
1008      }
1009      else {
1010         /* default color format */
1011         texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D,
1012                                      PIPE_TEXTURE_USAGE_SAMPLER);
1013         assert(texFormat != PIPE_FORMAT_NONE);
1014      }
1015   }
1016
1017   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
1018                          width, height, 1, 0,
1019                          PIPE_TEXTURE_USAGE_SAMPLER);
1020   if (!pt)
1021      return;
1022
1023   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1024      srcy = ctx->DrawBuffer->Height - srcy - height;
1025   }
1026
1027   if (srcFormat == texFormat) {
1028      /* copy source framebuffer surface into mipmap/texture */
1029      struct pipe_surface *psRead = screen->get_tex_surface(screen,
1030                                       rbRead->texture, 0, 0, 0,
1031                                       PIPE_BUFFER_USAGE_GPU_READ);
1032      psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
1033                                      PIPE_BUFFER_USAGE_GPU_WRITE );
1034      pipe->surface_copy(pipe,
1035                         FALSE,
1036			 psTex, /* dest */
1037			 0, 0, /* destx/y */
1038			 psRead,
1039			 srcx, srcy, width, height);
1040      pipe_surface_reference(&psRead, NULL);
1041   }
1042   else {
1043      /* CPU-based fallback/conversion */
1044      struct pipe_surface *psRead = screen->get_tex_surface(screen,
1045                                       rbRead->texture, 0, 0, 0,
1046                                       PIPE_BUFFER_USAGE_CPU_READ);
1047
1048      psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
1049                                      PIPE_BUFFER_USAGE_CPU_WRITE );
1050
1051      if (type == GL_COLOR) {
1052         /* alternate path using get/put_tile() */
1053         GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1054
1055         pipe_get_tile_rgba(psRead, srcx, srcy, width, height, buf);
1056         pipe_put_tile_rgba(psTex, 0, 0, width, height, buf);
1057
1058         free(buf);
1059      }
1060      else {
1061         /* GL_DEPTH */
1062         GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
1063         pipe_get_tile_z(psRead, srcx, srcy, width, height, buf);
1064         pipe_put_tile_z(psTex, 0, 0, width, height, buf);
1065         free(buf);
1066      }
1067      pipe_surface_reference(&psRead, NULL);
1068   }
1069
1070   pipe_surface_reference(&psTex, NULL);
1071
1072   /* draw textured quad */
1073   draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1074                      width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1075                      pt, stvp, stfp, color, GL_TRUE);
1076
1077   pipe_texture_reference(&pt, NULL);
1078}
1079
1080
1081
1082void st_init_drawpixels_functions(struct dd_function_table *functions)
1083{
1084   functions->DrawPixels = st_DrawPixels;
1085   functions->CopyPixels = st_CopyPixels;
1086}
1087
1088
1089void
1090st_destroy_drawpix(struct st_context *st)
1091{
1092   st_reference_fragprog(st, &st->drawpix.z_shader, NULL);
1093   st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
1094   st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL);
1095   st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL);
1096}
1097
1098
1099