Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / mesa / state_tracker / st_cb_drawpixels.c
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 */
70 static GLboolean
71 is_passthrough_program(const struct gl_fragment_program *prog)
72 {
73 if (prog->Base.NumInstructions == 2) {
74 const struct prog_instruction *inst = prog->Base.Instructions;
75 if (inst[0].Opcode == OPCODE_MOV &&
76 inst[1].Opcode == OPCODE_END &&
77 inst[0].DstReg.File == PROGRAM_OUTPUT &&
78 inst[0].DstReg.Index == FRAG_RESULT_COLR &&
79 inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
80 inst[0].SrcReg[0].File == PROGRAM_INPUT &&
81 inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
82 inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
83 return GL_TRUE;
84 }
85 }
86 return GL_FALSE;
87 }
88
89
90
91 /**
92 * Make fragment shader for glDraw/CopyPixels. This shader is made
93 * by combining the pixel transfer shader with the user-defined shader.
94 */
95 static struct st_fragment_program *
96 combined_drawpix_fragment_program(GLcontext *ctx)
97 {
98 struct st_context *st = ctx->st;
99 struct st_fragment_program *stfp;
100
101 if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
102 && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
103 /* the pixel tranfer program has not changed and the user-defined
104 * program has not changed, so re-use the combined program.
105 */
106 stfp = st->pixel_xfer.combined_prog;
107 }
108 else {
109 /* Concatenate the pixel transfer program with the current user-
110 * defined program.
111 */
112 if (is_passthrough_program(&st->fp->Base)) {
113 stfp = (struct st_fragment_program *)
114 _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base);
115 }
116 else {
117 #if 0
118 printf("Base program:\n");
119 _mesa_print_program(&st->fp->Base.Base);
120 printf("DrawPix program:\n");
121 _mesa_print_program(&st->pixel_xfer.program->Base.Base);
122 #endif
123 stfp = (struct st_fragment_program *)
124 _mesa_combine_programs(ctx,
125 &st->pixel_xfer.program->Base.Base,
126 &st->fp->Base.Base);
127 }
128
129 #if 0
130 {
131 struct gl_program *p = &stfp->Base.Base;
132 printf("Combined DrawPixels program:\n");
133 _mesa_print_program(p);
134 printf("InputsRead: 0x%x\n", p->InputsRead);
135 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
136 _mesa_print_parameter_list(p->Parameters);
137 }
138 #endif
139
140 /* translate to TGSI tokens */
141 st_translate_fragment_program(st, stfp, NULL);
142
143 /* save new program, update serial numbers */
144 st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
145 st->pixel_xfer.user_prog_sn = st->fp->serialNo;
146 st->pixel_xfer.combined_prog_sn = stfp->serialNo;
147 st->pixel_xfer.combined_prog = stfp;
148 }
149
150 /* Ideally we'd have updated the pipe constants during the normal
151 * st/atom mechanism. But we can't since this is specific to glDrawPixels.
152 */
153 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
154
155 return stfp;
156 }
157
158
159 /**
160 * Create fragment shader that does a TEX() instruction to get a Z
161 * value, then writes to FRAG_RESULT_DEPR.
162 * Pass fragment color through as-is.
163 */
164 static struct st_fragment_program *
165 make_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_DEPR;
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_COLR;
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_COLR) | (1 << FRAG_RESULT_DEPR);
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 */
231 static struct st_vertex_program *
232 st_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
306 static 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 */
324 static struct pipe_texture *
325 make_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_surface *surface;
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 surface = screen->get_tex_surface(screen, pt, 0, 0, 0,
371 PIPE_BUFFER_USAGE_CPU_WRITE);
372
373 /* map texture surface */
374 dest = screen->surface_map(screen, surface,
375 PIPE_BUFFER_USAGE_CPU_WRITE);
376
377 /* Put image into texture surface.
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 surface->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->surface_unmap(screen, surface);
395 pipe_surface_reference(&surface, NULL);
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 */
415 static void
416 draw_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 ubyte *map;
489
490 /* allocate/load buffer object with vertex data */
491 buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX,
492 sizeof(verts));
493 map = pipe_buffer_map(pipe->screen, buf, PIPE_BUFFER_USAGE_CPU_WRITE);
494 memcpy(map, verts, sizeof(verts));
495 pipe_buffer_unmap(pipe->screen, buf);
496
497 util_draw_vertex_buffer(pipe, buf, 0,
498 PIPE_PRIM_QUADS,
499 4, /* verts */
500 3); /* attribs/vert */
501 pipe_buffer_reference(pipe->screen, &buf, NULL);
502 }
503 }
504
505
506
507 static void
508 draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
509 GLsizei width, GLsizei height,
510 GLfloat zoomX, GLfloat zoomY,
511 struct pipe_texture *pt,
512 struct st_vertex_program *stvp,
513 struct st_fragment_program *stfp,
514 const GLfloat *color,
515 GLboolean invertTex)
516 {
517 struct st_context *st = ctx->st;
518 struct pipe_context *pipe = ctx->st->pipe;
519 struct cso_context *cso = ctx->st->cso_context;
520 GLfloat x0, y0, x1, y1;
521 GLsizei maxSize;
522
523 /* limit checks */
524 /* XXX if DrawPixels image is larger than max texture size, break
525 * it up into chunks.
526 */
527 maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
528 assert(width <= maxSize);
529 assert(height <= maxSize);
530
531 cso_save_rasterizer(cso);
532 cso_save_viewport(cso);
533 cso_save_samplers(cso);
534 cso_save_sampler_textures(cso);
535 cso_save_fragment_shader(cso);
536 cso_save_vertex_shader(cso);
537
538 /* rasterizer state: just scissor */
539 {
540 struct pipe_rasterizer_state rasterizer;
541 memset(&rasterizer, 0, sizeof(rasterizer));
542 rasterizer.gl_rasterization_rules = 1;
543 rasterizer.scissor = ctx->Scissor.Enabled;
544 cso_set_rasterizer(cso, &rasterizer);
545 }
546
547 /* fragment shader state: TEX lookup program */
548 cso_set_fragment_shader_handle(cso, stfp->driver_shader);
549
550 /* vertex shader state: position + texcoord pass-through */
551 cso_set_vertex_shader_handle(cso, stvp->driver_shader);
552
553
554 /* texture sampling state: */
555 {
556 struct pipe_sampler_state sampler;
557 memset(&sampler, 0, sizeof(sampler));
558 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
559 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
560 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
561 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
562 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
563 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
564 sampler.normalized_coords = 1;
565
566 cso_single_sampler(cso, 0, &sampler);
567 if (st->pixel_xfer.pixelmap_enabled) {
568 cso_single_sampler(cso, 1, &sampler);
569 }
570 cso_single_sampler_done(cso);
571 }
572
573 /* viewport state: viewport matching window dims */
574 {
575 const float width = (float) ctx->DrawBuffer->Width;
576 const float height = (float) ctx->DrawBuffer->Height;
577 struct pipe_viewport_state vp;
578 vp.scale[0] = 0.5f * width;
579 vp.scale[1] = -0.5f * height;
580 vp.scale[2] = 1.0f;
581 vp.scale[3] = 1.0f;
582 vp.translate[0] = 0.5f * width;
583 vp.translate[1] = 0.5f * height;
584 vp.translate[2] = 0.0f;
585 vp.translate[3] = 0.0f;
586 cso_set_viewport(cso, &vp);
587 }
588
589 /* texture state: */
590 if (st->pixel_xfer.pixelmap_enabled) {
591 struct pipe_texture *textures[2];
592 textures[0] = pt;
593 textures[1] = st->pixel_xfer.pixelmap_texture;
594 pipe->set_sampler_textures(pipe, 2, textures);
595 }
596 else {
597 pipe->set_sampler_textures(pipe, 1, &pt);
598 }
599
600 /* Compute window coords (y=0=bottom) with pixel zoom.
601 * Recall that these coords are transformed by the current
602 * vertex shader and viewport transformation.
603 */
604 x0 = (GLfloat) x;
605 x1 = x + width * ctx->Pixel.ZoomX;
606 y0 = (GLfloat) y;
607 y1 = y + height * ctx->Pixel.ZoomY;
608 //if(!color)
609 draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex);
610 //else
611 //printf("skip draw quad\n");
612 /* restore state */
613 cso_restore_rasterizer(cso);
614 cso_restore_viewport(cso);
615 cso_restore_samplers(cso);
616 cso_restore_sampler_textures(cso);
617 cso_restore_fragment_shader(cso);
618 cso_restore_vertex_shader(cso);
619 }
620
621
622 /**
623 * Check if a GL format/type combination is a match to the given pipe format.
624 * XXX probably move this to a re-usable place.
625 */
626 static GLboolean
627 compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat)
628 {
629 static const GLuint one = 1;
630 GLubyte littleEndian = *((GLubyte *) &one);
631
632 if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
633 format == GL_RGBA &&
634 type == GL_UNSIGNED_BYTE &&
635 !littleEndian) {
636 return GL_TRUE;
637 }
638 else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
639 format == GL_ABGR_EXT &&
640 type == GL_UNSIGNED_BYTE &&
641 littleEndian) {
642 return GL_TRUE;
643 }
644 else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM &&
645 format == GL_BGRA &&
646 type == GL_UNSIGNED_BYTE &&
647 littleEndian) {
648 return GL_TRUE;
649 }
650 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
651 format == GL_RGB &&
652 type == GL_UNSIGNED_SHORT_5_6_5) {
653 /* endian don't care */
654 return GL_TRUE;
655 }
656 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
657 format == GL_BGR &&
658 type == GL_UNSIGNED_SHORT_5_6_5_REV) {
659 /* endian don't care */
660 return GL_TRUE;
661 }
662 else if (pipeFormat == PIPE_FORMAT_S8_UNORM &&
663 format == GL_STENCIL_INDEX &&
664 type == GL_UNSIGNED_BYTE) {
665 return GL_TRUE;
666 }
667 else if (pipeFormat == PIPE_FORMAT_Z32_UNORM &&
668 format == GL_DEPTH_COMPONENT &&
669 type == GL_UNSIGNED_INT) {
670 return GL_TRUE;
671 }
672 /* XXX add more cases */
673 else {
674 return GL_FALSE;
675 }
676 }
677
678
679 /**
680 * Check if any per-fragment ops are enabled.
681 * XXX probably move this to a re-usable place.
682 */
683 static GLboolean
684 any_fragment_ops(const struct st_context *st)
685 {
686 if (st->state.depth_stencil.alpha.enabled ||
687 st->state.depth_stencil.depth.enabled ||
688 st->state.blend.blend_enable ||
689 st->state.blend.logicop_enable)
690 /* XXX more checks */
691 return GL_TRUE;
692 else
693 return GL_FALSE;
694 }
695
696
697 /**
698 * Check if any pixel transfer ops are enabled.
699 * XXX probably move this to a re-usable place.
700 */
701 static GLboolean
702 any_pixel_transfer_ops(const struct st_context *st)
703 {
704 if (st->ctx->Pixel.RedScale != 1.0 ||
705 st->ctx->Pixel.RedBias != 0.0 ||
706 st->ctx->Pixel.GreenScale != 1.0 ||
707 st->ctx->Pixel.GreenBias != 0.0 ||
708 st->ctx->Pixel.BlueScale != 1.0 ||
709 st->ctx->Pixel.BlueBias != 0.0 ||
710 st->ctx->Pixel.AlphaScale != 1.0 ||
711 st->ctx->Pixel.AlphaBias != 0.0 ||
712 st->ctx->Pixel.MapColorFlag)
713 /* XXX more checks */
714 return GL_TRUE;
715 else
716 return GL_FALSE;
717 }
718
719
720 /**
721 * Draw image with a blit, or other non-textured quad method.
722 */
723 static void
724 draw_blit(struct st_context *st,
725 GLsizei width, GLsizei height,
726 GLenum format, GLenum type, const GLvoid *pixels)
727 {
728
729
730 }
731
732
733 static void
734 draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
735 GLsizei width, GLsizei height, GLenum type,
736 const struct gl_pixelstore_attrib *unpack,
737 const GLvoid *pixels)
738 {
739 struct st_context *st = ctx->st;
740 struct pipe_context *pipe = st->pipe;
741 struct pipe_screen *screen = pipe->screen;
742 struct st_renderbuffer *strb;
743 struct pipe_surface *ps;
744 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
745 GLint skipPixels;
746 ubyte *stmap;
747
748 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
749
750 strb = st_renderbuffer(ctx->DrawBuffer->
751 Attachment[BUFFER_STENCIL].Renderbuffer);
752 ps = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
753 PIPE_BUFFER_USAGE_CPU_WRITE);
754
755 /* map the stencil buffer */
756 stmap = screen->surface_map(screen, ps,
757 PIPE_BUFFER_USAGE_CPU_WRITE);
758
759 /* if width > MAX_WIDTH, have to process image in chunks */
760 skipPixels = 0;
761 while (skipPixels < width) {
762 const GLint spanX = x + skipPixels;
763 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
764 GLint row;
765 for (row = 0; row < height; row++) {
766 GLint spanY = y + row;
767 GLubyte values[MAX_WIDTH];
768 GLenum destType = GL_UNSIGNED_BYTE;
769 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
770 width, height,
771 GL_COLOR_INDEX, type,
772 row, skipPixels);
773 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
774 type, source, unpack,
775 ctx->_ImageTransferState);
776 if (zoom) {
777 /*
778 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
779 spanX, spanY, values);
780 */
781 }
782 else {
783 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
784 spanY = ctx->DrawBuffer->Height - spanY - 1;
785 }
786
787 switch (ps->format) {
788 case PIPE_FORMAT_S8_UNORM:
789 {
790 ubyte *dest = stmap + spanY * ps->stride + spanX;
791 memcpy(dest, values, spanWidth);
792 }
793 break;
794 case PIPE_FORMAT_S8Z24_UNORM:
795 {
796 uint *dest = (uint *) (stmap + spanY * ps->stride + spanX*4);
797 GLint k;
798 for (k = 0; k < spanWidth; k++) {
799 uint p = dest[k];
800 p = (p & 0xffffff) | (values[k] << 24);
801 dest[k] = p;
802 }
803 }
804 break;
805 default:
806 assert(0);
807 }
808 }
809 }
810 skipPixels += spanWidth;
811 }
812
813 /* unmap the stencil buffer */
814 screen->surface_unmap(screen, ps);
815 pipe_surface_reference(&ps, NULL);
816 }
817
818
819 /**
820 * Called via ctx->Driver.DrawPixels()
821 */
822 static void
823 st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
824 GLenum format, GLenum type,
825 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
826 {
827 struct st_fragment_program *stfp;
828 struct st_vertex_program *stvp;
829 struct st_context *st = ctx->st;
830 struct pipe_surface *ps;
831 GLuint bufferFormat;
832 const GLfloat *color;
833
834 if (format == GL_STENCIL_INDEX) {
835 draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
836 return;
837 }
838
839 _mesa_set_vp_override( ctx, TRUE );
840 _mesa_update_state( ctx );
841
842 st_validate_state(st);
843
844 if (format == GL_DEPTH_COMPONENT) {
845 ps = st->state.framebuffer.zsbuf;
846 stfp = make_fragment_shader_z(ctx->st);
847 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
848 color = ctx->Current.RasterColor;
849 }
850 else if (format == GL_STENCIL_INDEX) {
851 ps = st->state.framebuffer.zsbuf;
852 /* XXX special case - can't use texture map */
853 color = NULL;
854 }
855 else {
856 ps = st->state.framebuffer.cbufs[0];
857 stfp = combined_drawpix_fragment_program(ctx);
858 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
859 color = NULL;
860 }
861
862 bufferFormat = ps->format;
863
864 if (1/*any_fragment_ops(st) ||
865 any_pixel_transfer_ops(st) ||
866 !compatible_formats(format, type, ps->format)*/) {
867 /* textured quad */
868 struct pipe_texture *pt
869 = make_texture(ctx->st, width, height, format, type, unpack, pixels);
870 if (pt) {
871 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
872 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
873 pt, stvp, stfp, color, GL_FALSE);
874 pipe_texture_reference(&pt, NULL);
875 }
876 }
877 else {
878 /* blit */
879 draw_blit(st, width, height, format, type, pixels);
880 }
881
882 _mesa_set_vp_override( ctx, FALSE );
883 }
884
885
886
887 static void
888 copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
889 GLsizei width, GLsizei height,
890 GLint dstx, GLint dsty)
891 {
892 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
893 struct pipe_screen *screen = ctx->st->pipe->screen;
894 struct pipe_surface *psDraw;
895 ubyte *drawMap;
896 ubyte *buffer;
897 int i;
898
899 buffer = malloc(width * height * sizeof(ubyte));
900 if (!buffer) {
901 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
902 return;
903 }
904
905 /* this will do stencil pixel transfer ops */
906 st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
907 &ctx->DefaultPacking, buffer);
908
909 psDraw = screen->get_tex_surface(screen, rbDraw->texture, 0, 0, 0,
910 PIPE_BUFFER_USAGE_CPU_WRITE);
911
912 assert(psDraw->block.width == 1);
913 assert(psDraw->block.height == 1);
914
915 /* map the stencil buffer */
916 drawMap = screen->surface_map(screen, psDraw, PIPE_BUFFER_USAGE_CPU_WRITE);
917
918 /* draw */
919 /* XXX PixelZoom not handled yet */
920 for (i = 0; i < height; i++) {
921 ubyte *dst;
922 const ubyte *src;
923 int y;
924
925 y = dsty + i;
926
927 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
928 y = ctx->DrawBuffer->Height - y - 1;
929 }
930
931 dst = drawMap + y * psDraw->stride + dstx * psDraw->block.size;
932 src = buffer + i * width;
933
934 switch (psDraw->format) {
935 case PIPE_FORMAT_S8Z24_UNORM:
936 {
937 uint *dst4 = (uint *) dst;
938 int j;
939 for (j = 0; j < width; j++) {
940 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
941 dst4++;
942 }
943 }
944 break;
945 case PIPE_FORMAT_S8_UNORM:
946 memcpy(dst, src, width);
947 break;
948 default:
949 assert(0);
950 }
951 }
952
953 free(buffer);
954
955 /* unmap the stencil buffer */
956 screen->surface_unmap(screen, psDraw);
957 pipe_surface_reference(&psDraw, NULL);
958 }
959
960
961 static void
962 st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
963 GLsizei width, GLsizei height,
964 GLint dstx, GLint dsty, GLenum type)
965 {
966 struct st_context *st = ctx->st;
967 struct pipe_context *pipe = st->pipe;
968 struct pipe_screen *screen = pipe->screen;
969 struct st_renderbuffer *rbRead;
970 struct st_vertex_program *stvp;
971 struct st_fragment_program *stfp;
972 struct pipe_surface *psTex;
973 struct pipe_texture *pt;
974 GLfloat *color;
975 enum pipe_format srcFormat, texFormat;
976
977 /* make sure rendering has completed */
978 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
979
980 st_validate_state(st);
981
982 if (type == GL_STENCIL) {
983 /* can't use texturing to do stencil */
984 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
985 return;
986 }
987
988 if (type == GL_COLOR) {
989 rbRead = st_get_color_read_renderbuffer(ctx);
990 color = NULL;
991 stfp = combined_drawpix_fragment_program(ctx);
992 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
993 }
994 else {
995 assert(type == GL_DEPTH);
996 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
997 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
998 stfp = make_fragment_shader_z(ctx->st);
999 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
1000 }
1001
1002 srcFormat = rbRead->texture->format;
1003
1004 if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D,
1005 PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
1006 texFormat = srcFormat;
1007 }
1008 else {
1009 /* srcFormat can't be used as a texture format */
1010 if (type == GL_DEPTH) {
1011 texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D,
1012 PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
1013 assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */
1014 }
1015 else {
1016 /* default color format */
1017 texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D,
1018 PIPE_TEXTURE_USAGE_SAMPLER);
1019 assert(texFormat != PIPE_FORMAT_NONE);
1020 }
1021 }
1022
1023 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
1024 width, height, 1, 0,
1025 PIPE_TEXTURE_USAGE_SAMPLER);
1026 if (!pt)
1027 return;
1028
1029 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1030 srcy = ctx->DrawBuffer->Height - srcy - height;
1031 }
1032
1033 if (srcFormat == texFormat) {
1034 /* copy source framebuffer surface into mipmap/texture */
1035 struct pipe_surface *psRead = screen->get_tex_surface(screen,
1036 rbRead->texture, 0, 0, 0,
1037 PIPE_BUFFER_USAGE_GPU_READ);
1038 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
1039 PIPE_BUFFER_USAGE_GPU_WRITE );
1040 pipe->surface_copy(pipe,
1041 FALSE,
1042 psTex, /* dest */
1043 0, 0, /* destx/y */
1044 psRead,
1045 srcx, srcy, width, height);
1046 pipe_surface_reference(&psRead, NULL);
1047 }
1048 else {
1049 /* CPU-based fallback/conversion */
1050 struct pipe_surface *psRead = screen->get_tex_surface(screen,
1051 rbRead->texture, 0, 0, 0,
1052 PIPE_BUFFER_USAGE_CPU_READ);
1053
1054 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
1055 PIPE_BUFFER_USAGE_CPU_WRITE );
1056
1057 if (type == GL_COLOR) {
1058 /* alternate path using get/put_tile() */
1059 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1060
1061 pipe_get_tile_rgba(psRead, srcx, srcy, width, height, buf);
1062 pipe_put_tile_rgba(psTex, 0, 0, width, height, buf);
1063
1064 free(buf);
1065 }
1066 else {
1067 /* GL_DEPTH */
1068 GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
1069 pipe_get_tile_z(psRead, srcx, srcy, width, height, buf);
1070 pipe_put_tile_z(psTex, 0, 0, width, height, buf);
1071 free(buf);
1072 }
1073 pipe_surface_reference(&psRead, NULL);
1074 }
1075
1076 pipe_surface_reference(&psTex, NULL);
1077
1078 /* draw textured quad */
1079 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1080 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1081 pt, stvp, stfp, color, GL_TRUE);
1082
1083 pipe_texture_reference(&pt, NULL);
1084 }
1085
1086
1087
1088 void st_init_drawpixels_functions(struct dd_function_table *functions)
1089 {
1090 functions->DrawPixels = st_DrawPixels;
1091 functions->CopyPixels = st_CopyPixels;
1092 }
1093
1094
1095 void
1096 st_destroy_drawpix(struct st_context *st)
1097 {
1098 st_reference_fragprog(st, &st->drawpix.z_shader, NULL);
1099 st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
1100 st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL);
1101 st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL);
1102 }
1103
1104