gallium: pipe->surface_copy can flip the contents vertically when necessary.
[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/macros.h"
36 #include "main/texformat.h"
37 #include "shader/program.h"
38 #include "shader/prog_parameter.h"
39 #include "shader/prog_print.h"
40
41 #include "st_context.h"
42 #include "st_atom.h"
43 #include "st_atom_constbuf.h"
44 #include "st_cache.h"
45 #include "st_draw.h"
46 #include "st_program.h"
47 #include "st_cb_drawpixels.h"
48 #include "st_cb_readpixels.h"
49 #include "st_cb_fbo.h"
50 #include "st_cb_texture.h"
51 #include "st_draw.h"
52 #include "st_format.h"
53 #include "st_mesa_to_tgsi.h"
54 #include "st_texture.h"
55 #include "pipe/p_context.h"
56 #include "pipe/p_defines.h"
57 #include "pipe/p_inlines.h"
58 #include "pipe/p_winsys.h"
59 #include "pipe/util/p_tile.h"
60 #include "shader/prog_instruction.h"
61
62
63 /**
64 * Check if the given program is:
65 * 0: MOVE result.color, fragment.color;
66 * 1: END;
67 */
68 static GLboolean
69 is_passthrough_program(const struct gl_fragment_program *prog)
70 {
71 if (prog->Base.NumInstructions == 2) {
72 const struct prog_instruction *inst = prog->Base.Instructions;
73 if (inst[0].Opcode == OPCODE_MOV &&
74 inst[1].Opcode == OPCODE_END &&
75 inst[0].DstReg.File == PROGRAM_OUTPUT &&
76 inst[0].DstReg.Index == FRAG_RESULT_COLR &&
77 inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
78 inst[0].SrcReg[0].File == PROGRAM_INPUT &&
79 inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
80 inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
81 return GL_TRUE;
82 }
83 }
84 return GL_FALSE;
85 }
86
87
88 /**
89 * Make fragment program for glBitmap:
90 * Sample the texture and kill the fragment if the bit is 0.
91 * This program will be combined with the user's fragment program.
92 */
93 static struct st_fragment_program *
94 make_bitmap_fragment_program(GLcontext *ctx)
95 {
96 struct st_fragment_program *stfp;
97 struct gl_program *p;
98 GLuint ic = 0;
99
100 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
101 if (!p)
102 return NULL;
103
104 p->NumInstructions = 5;
105
106 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
107 if (!p->Instructions) {
108 ctx->Driver.DeleteProgram(ctx, p);
109 return NULL;
110 }
111 _mesa_init_instructions(p->Instructions, p->NumInstructions);
112
113 /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
114 p->Instructions[ic].Opcode = OPCODE_TEX;
115 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
116 p->Instructions[ic].DstReg.Index = 0;
117 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
118 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
119 p->Instructions[ic].TexSrcUnit = 0;
120 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
121 ic++;
122
123 /* SWZ tmp0.x, tmp0.x, 1111; # tmp0.x = 1.0 */
124 p->Instructions[ic].Opcode = OPCODE_SWZ;
125 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
126 p->Instructions[ic].DstReg.Index = 0;
127 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_X;
128 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
129 p->Instructions[ic].SrcReg[0].Index = 0;
130 p->Instructions[ic].SrcReg[0].Swizzle
131 = MAKE_SWIZZLE4(SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE );
132 ic++;
133
134 /* SUB tmp0, tmp0.wwww, tmp0.xxxx; # tmp0.w -= 1 */
135 p->Instructions[ic].Opcode = OPCODE_SUB;
136 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
137 p->Instructions[ic].DstReg.Index = 0;
138 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
139 p->Instructions[ic].SrcReg[0].Index = 0;
140 p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_WWWW;
141 p->Instructions[ic].SrcReg[1].File = PROGRAM_TEMPORARY;
142 p->Instructions[ic].SrcReg[1].Index = 0;
143 p->Instructions[ic].SrcReg[1].Swizzle = SWIZZLE_XXXX; /* 1.0 */
144 ic++;
145
146 /* KIL if tmp0 < 0 */
147 p->Instructions[ic].Opcode = OPCODE_KIL;
148 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
149 p->Instructions[ic].SrcReg[0].Index = 0;
150 ic++;
151
152 /* END; */
153 p->Instructions[ic++].Opcode = OPCODE_END;
154
155 assert(ic == p->NumInstructions);
156
157 p->InputsRead = FRAG_BIT_TEX0;
158 p->OutputsWritten = 0x0;
159
160 stfp = (struct st_fragment_program *) p;
161 stfp->Base.UsesKill = GL_TRUE;
162 st_translate_fragment_program(ctx->st, stfp, NULL,
163 stfp->tokens, ST_MAX_SHADER_TOKENS);
164
165 return stfp;
166 }
167
168
169 /**
170 * Combine basic bitmap fragment program with the user-defined program.
171 */
172 static struct st_fragment_program *
173 combined_bitmap_fragment_program(GLcontext *ctx)
174 {
175 struct st_context *st = ctx->st;
176 struct st_fragment_program *stfp;
177
178 if (!st->bitmap.program) {
179 /* create the basic bitmap fragment program */
180 st->bitmap.program = make_bitmap_fragment_program(ctx);
181 }
182
183 if (st->bitmap.user_prog_sn == st->fp->serialNo) {
184 /* re-use */
185 stfp = st->bitmap.combined_prog;
186 }
187 else {
188 /* Concatenate the bitmap program with the current user-defined program.
189 */
190 stfp = (struct st_fragment_program *)
191 _mesa_combine_programs(ctx,
192 &st->bitmap.program->Base.Base,
193 &st->fp->Base.Base);
194
195 #if 0
196 {
197 struct gl_program *p = &stfp->Base.Base;
198 printf("Combined bitmap program:\n");
199 _mesa_print_program(p);
200 printf("InputsRead: 0x%x\n", p->InputsRead);
201 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
202 _mesa_print_parameter_list(p->Parameters);
203 }
204 #endif
205
206 /* translate to TGSI tokens */
207 st_translate_fragment_program(st, stfp, NULL,
208 stfp->tokens, ST_MAX_SHADER_TOKENS);
209
210 /* save new program, update serial numbers */
211 st->bitmap.user_prog_sn = st->fp->serialNo;
212 st->bitmap.combined_prog = stfp;
213 }
214
215 /* Ideally we'd have updated the pipe constants during the normal
216 * st/atom mechanism. But we can't since this is specific to glBitmap.
217 */
218 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
219
220 return stfp;
221 }
222
223
224
225 /**
226 * Make fragment shader for glDraw/CopyPixels. This shader is made
227 * by combining the pixel transfer shader with the user-defined shader.
228 */
229 static struct st_fragment_program *
230 combined_drawpix_fragment_program(GLcontext *ctx)
231 {
232 struct st_context *st = ctx->st;
233 struct st_fragment_program *stfp;
234
235 if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
236 && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
237 /* the pixel tranfer program has not changed and the user-defined
238 * program has not changed, so re-use the combined program.
239 */
240 stfp = st->pixel_xfer.combined_prog;
241 }
242 else {
243 /* Concatenate the pixel transfer program with the current user-
244 * defined program.
245 */
246 if (is_passthrough_program(&st->fp->Base)) {
247 stfp = (struct st_fragment_program *)
248 _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base);
249 }
250 else {
251 stfp = (struct st_fragment_program *)
252 _mesa_combine_programs(ctx,
253 &st->pixel_xfer.program->Base.Base,
254 &st->fp->Base.Base);
255 }
256
257 #if 0
258 {
259 struct gl_program *p = &stfp->Base.Base;
260 printf("Combined DrawPixels program:\n");
261 _mesa_print_program(p);
262 printf("InputsRead: 0x%x\n", p->InputsRead);
263 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
264 _mesa_print_parameter_list(p->Parameters);
265 }
266 #endif
267
268 /* translate to TGSI tokens */
269 st_translate_fragment_program(st, stfp, NULL,
270 stfp->tokens, ST_MAX_SHADER_TOKENS);
271
272 /* save new program, update serial numbers */
273 st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
274 st->pixel_xfer.user_prog_sn = st->fp->serialNo;
275 st->pixel_xfer.combined_prog_sn = stfp->serialNo;
276 st->pixel_xfer.combined_prog = stfp;
277 }
278
279 /* Ideally we'd have updated the pipe constants during the normal
280 * st/atom mechanism. But we can't since this is specific to glDrawPixels.
281 */
282 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
283
284 return stfp;
285 }
286
287
288 /**
289 * Create fragment shader that does a TEX() instruction to get a Z
290 * value, then writes to FRAG_RESULT_DEPR.
291 * Pass fragment color through as-is.
292 */
293 static struct st_fragment_program *
294 make_fragment_shader_z(struct st_context *st)
295 {
296 GLcontext *ctx = st->ctx;
297 /* only make programs once and re-use */
298 static struct st_fragment_program *stfp = NULL;
299 struct gl_program *p;
300 GLuint ic = 0;
301
302 if (stfp)
303 return stfp;
304
305 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
306 if (!p)
307 return NULL;
308
309 p->NumInstructions = 3;
310
311 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
312 if (!p->Instructions) {
313 ctx->Driver.DeleteProgram(ctx, p);
314 return NULL;
315 }
316 _mesa_init_instructions(p->Instructions, p->NumInstructions);
317
318 /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
319 p->Instructions[ic].Opcode = OPCODE_TEX;
320 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
321 p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR;
322 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
323 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
324 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
325 p->Instructions[ic].TexSrcUnit = 0;
326 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
327 ic++;
328
329 /* MOV result.color, fragment.color */
330 p->Instructions[ic].Opcode = OPCODE_MOV;
331 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
332 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
333 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
334 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
335 ic++;
336
337 /* END; */
338 p->Instructions[ic++].Opcode = OPCODE_END;
339
340 assert(ic == p->NumInstructions);
341
342 p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
343 p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR);
344
345 stfp = (struct st_fragment_program *) p;
346 st_translate_fragment_program(st, stfp, NULL,
347 stfp->tokens, ST_MAX_SHADER_TOKENS);
348
349 return stfp;
350 }
351
352
353
354 /**
355 * Create a simple vertex shader that just passes through the
356 * vertex position and texcoord (and optionally, color).
357 */
358 struct st_vertex_program *
359 st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor)
360 {
361 /* only make programs once and re-use */
362 static struct st_vertex_program *progs[2] = { NULL, NULL };
363 GLcontext *ctx = st->ctx;
364 struct st_vertex_program *stvp;
365 struct gl_program *p;
366 GLuint ic = 0;
367
368 if (progs[passColor])
369 return progs[passColor];
370
371 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
372 if (!p)
373 return NULL;
374
375 if (passColor)
376 p->NumInstructions = 4;
377 else
378 p->NumInstructions = 3;
379
380 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
381 if (!p->Instructions) {
382 ctx->Driver.DeleteProgram(ctx, p);
383 return NULL;
384 }
385 _mesa_init_instructions(p->Instructions, p->NumInstructions);
386 /* MOV result.pos, vertex.pos; */
387 p->Instructions[0].Opcode = OPCODE_MOV;
388 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
389 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
390 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
391 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
392 /* MOV result.texcoord0, vertex.texcoord0; */
393 p->Instructions[1].Opcode = OPCODE_MOV;
394 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
395 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
396 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
397 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
398 ic = 2;
399 if (passColor) {
400 /* MOV result.color0, vertex.color0; */
401 p->Instructions[ic].Opcode = OPCODE_MOV;
402 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
403 p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
404 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
405 p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
406 ic++;
407 }
408
409 /* END; */
410 p->Instructions[ic].Opcode = OPCODE_END;
411 ic++;
412
413 assert(ic == p->NumInstructions);
414
415 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
416 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
417 (1 << VERT_RESULT_HPOS));
418 if (passColor) {
419 p->InputsRead |= VERT_BIT_COLOR0;
420 p->OutputsWritten |= (1 << VERT_RESULT_COL0);
421 }
422
423 stvp = (struct st_vertex_program *) p;
424 st_translate_vertex_program(st, stvp, NULL,
425 stvp->tokens, ST_MAX_SHADER_TOKENS);
426
427 progs[passColor] = stvp;
428
429 return stvp;
430 }
431
432
433 static GLenum
434 _mesa_base_format(GLenum format)
435 {
436 switch (format) {
437 case GL_DEPTH_COMPONENT:
438 return GL_DEPTH_COMPONENT;
439 case GL_STENCIL_INDEX:
440 return GL_STENCIL_INDEX;
441 default:
442 return GL_RGBA;
443 }
444 }
445
446
447 /**
448 * Make texture containing an image for glDrawPixels image.
449 * If 'pixels' is NULL, leave the texture image data undefined.
450 */
451 static struct pipe_texture *
452 make_texture(struct st_context *st,
453 GLsizei width, GLsizei height, GLenum format, GLenum type,
454 const struct gl_pixelstore_attrib *unpack,
455 const GLvoid *pixels)
456 {
457 GLcontext *ctx = st->ctx;
458 struct pipe_context *pipe = st->pipe;
459 const struct gl_texture_format *mformat;
460 struct pipe_texture *pt;
461 enum pipe_format pipeFormat;
462 GLuint cpp;
463 GLenum baseFormat;
464
465 baseFormat = _mesa_base_format(format);
466
467 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
468 assert(mformat);
469
470 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
471 assert(pipeFormat);
472 cpp = st_sizeof_format(pipeFormat);
473
474 pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
475 1, 0);
476 if (!pt)
477 return NULL;
478
479 if (unpack->BufferObj && unpack->BufferObj->Name) {
480 /*
481 pt->region = buffer_object_region(unpack->BufferObj);
482 */
483 printf("st_DrawPixels (sourcing from PBO not implemented yet)\n");
484 }
485
486 {
487 struct pipe_surface *surface;
488 static const GLuint dstImageOffsets = 0;
489 GLboolean success;
490 GLubyte *dest;
491 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
492
493 /* we'll do pixel transfer in a fragment shader */
494 ctx->_ImageTransferState = 0x0;
495
496 surface = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
497
498 /* map texture surface */
499 dest = pipe_surface_map(surface);
500
501 /* Put image into texture surface.
502 * Note that the image is actually going to be upside down in
503 * the texture. We deal with that with texcoords.
504 */
505 success = mformat->StoreImage(ctx, 2, /* dims */
506 baseFormat, /* baseInternalFormat */
507 mformat, /* gl_texture_format */
508 dest, /* dest */
509 0, 0, 0, /* dstX/Y/Zoffset */
510 surface->pitch * cpp, /* dstRowStride, bytes */
511 &dstImageOffsets, /* dstImageOffsets */
512 width, height, 1, /* size */
513 format, type, /* src format/type */
514 pixels, /* data source */
515 unpack);
516
517 /* unmap */
518 pipe_surface_unmap(surface);
519 pipe_surface_reference(&surface, NULL);
520 assert(success);
521
522 /* restore */
523 ctx->_ImageTransferState = imageTransferStateSave;
524 }
525
526 return pt;
527 }
528
529
530 /**
531 * Draw textured quad.
532 * Coords are window coords with y=0=bottom.
533 */
534 static void
535 draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
536 GLfloat x1, GLfloat y1, GLboolean invertTex)
537 {
538 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
539 GLuint i;
540 GLfloat sLeft = 0.0, sRight = 1.0;
541 GLfloat tTop = invertTex, tBot = 1.0 - tTop;
542
543 /* upper-left */
544 verts[0][0][0] = x0; /* attr[0].x */
545 verts[0][0][1] = y0; /* attr[0].y */
546 verts[0][1][0] = sLeft; /* attr[1].s */
547 verts[0][1][1] = tTop; /* attr[1].t */
548
549 /* upper-right */
550 verts[1][0][0] = x1;
551 verts[1][0][1] = y0;
552 verts[1][1][0] = sRight;
553 verts[1][1][1] = tTop;
554
555 /* lower-right */
556 verts[2][0][0] = x1;
557 verts[2][0][1] = y1;
558 verts[2][1][0] = sRight;
559 verts[2][1][1] = tBot;
560
561 /* lower-left */
562 verts[3][0][0] = x0;
563 verts[3][0][1] = y1;
564 verts[3][1][0] = sLeft;
565 verts[3][1][1] = tBot;
566
567 /* same for all verts: */
568 for (i = 0; i < 4; i++) {
569 verts[i][0][2] = z; /*Z*/
570 verts[i][0][3] = 1.0; /*W*/
571 verts[i][1][2] = 0.0; /*R*/
572 verts[i][1][3] = 1.0; /*Q*/
573 }
574
575 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, GL_FALSE);
576 }
577
578
579 static void
580 draw_quad_colored(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
581 GLfloat x1, GLfloat y1, const GLfloat *color,
582 GLboolean invertTex)
583 {
584 GLfloat bias = ctx->st->bitmap_texcoord_bias;
585 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
586 GLuint i;
587 GLfloat xBias = bias / (x1-x0);
588 GLfloat yBias = bias / (y1-y0);
589 GLfloat sLeft = 0.0 + xBias, sRight = 1.0 + xBias;
590 GLfloat tTop = invertTex - yBias, tBot = 1.0 - tTop - yBias;
591
592 /* upper-left */
593 verts[0][0][0] = x0; /* attr[0].x */
594 verts[0][0][1] = y0; /* attr[0].y */
595 verts[0][2][0] = sLeft; /* attr[2].s */
596 verts[0][2][1] = tTop; /* attr[2].t */
597
598 /* upper-right */
599 verts[1][0][0] = x1;
600 verts[1][0][1] = y0;
601 verts[1][2][0] = sRight;
602 verts[1][2][1] = tTop;
603
604 /* lower-right */
605 verts[2][0][0] = x1;
606 verts[2][0][1] = y1;
607 verts[2][2][0] = sRight;
608 verts[2][2][1] = tBot;
609
610 /* lower-left */
611 verts[3][0][0] = x0;
612 verts[3][0][1] = y1;
613 verts[3][2][0] = sLeft;
614 verts[3][2][1] = tBot;
615
616 /* same for all verts: */
617 for (i = 0; i < 4; i++) {
618 verts[i][0][2] = z; /*Z*/
619 verts[i][0][3] = 1.0; /*W*/
620 verts[i][1][0] = color[0];
621 verts[i][1][1] = color[1];
622 verts[i][1][2] = color[2];
623 verts[i][1][3] = color[3];
624 verts[i][2][2] = 0.0; /*R*/
625 verts[i][2][3] = 1.0; /*Q*/
626 }
627
628 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 3, GL_FALSE);
629 }
630
631
632
633 static void
634 draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
635 GLsizei width, GLsizei height,
636 GLfloat zoomX, GLfloat zoomY,
637 struct pipe_texture *pt,
638 struct st_vertex_program *stvp,
639 struct st_fragment_program *stfp,
640 const GLfloat *color,
641 GLboolean invertTex)
642 {
643 const GLuint unit = 0;
644 struct pipe_context *pipe = ctx->st->pipe;
645 GLfloat x0, y0, x1, y1;
646 GLuint maxSize;
647
648 /* limit checks */
649 /* XXX if DrawPixels image is larger than max texture size, break
650 * it up into chunks.
651 */
652 maxSize = 1 << (pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
653 assert(width <= maxSize);
654 assert(height <= maxSize);
655
656 /* setup state: just scissor */
657 {
658 struct pipe_rasterizer_state setup;
659 const struct cso_rasterizer *cso;
660 memset(&setup, 0, sizeof(setup));
661 if (ctx->Scissor.Enabled)
662 setup.scissor = 1;
663 cso = st_cached_rasterizer_state(ctx->st, &setup);
664 pipe->bind_rasterizer_state(pipe, cso->data);
665 }
666
667 /* fragment shader state: TEX lookup program */
668 pipe->bind_fs_state(pipe, stfp->cso->data);
669
670 /* vertex shader state: position + texcoord pass-through */
671 pipe->bind_vs_state(pipe, stvp->cso->data);
672
673 /* texture sampling state: */
674 {
675 struct pipe_sampler_state sampler;
676 const struct cso_sampler *cso;
677 memset(&sampler, 0, sizeof(sampler));
678 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
679 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
680 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
681 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
682 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
683 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
684 sampler.normalized_coords = 1;
685 cso = st_cached_sampler_state(ctx->st, &sampler);
686 pipe->bind_sampler_state(pipe, unit, cso->data);
687 }
688
689 /* viewport state: viewport matching window dims */
690 {
691 const float width = ctx->DrawBuffer->Width;
692 const float height = ctx->DrawBuffer->Height;
693 struct pipe_viewport_state vp;
694 vp.scale[0] = 0.5 * width;
695 vp.scale[1] = -0.5 * height;
696 vp.scale[2] = 1.0;
697 vp.scale[3] = 1.0;
698 vp.translate[0] = 0.5 * width;
699 vp.translate[1] = 0.5 * height;
700 vp.translate[2] = 0.0;
701 vp.translate[3] = 0.0;
702 pipe->set_viewport_state(pipe, &vp);
703 }
704
705 /* texture state: */
706 {
707 pipe->set_sampler_texture(pipe, unit, pt);
708 }
709
710 /* Compute window coords (y=0=bottom) with pixel zoom.
711 * Recall that these coords are transformed by the current
712 * vertex shader and viewport transformation.
713 */
714 x0 = x;
715 x1 = x + width * ctx->Pixel.ZoomX;
716 y0 = y;
717 y1 = y + height * ctx->Pixel.ZoomY;
718
719 /* draw textured quad */
720 if (color)
721 draw_quad_colored(ctx, x0, y0, z, x1, y1, color, invertTex);
722 else
723 draw_quad(ctx, x0, y0, z, x1, y1, invertTex);
724
725 /* restore GL state */
726 pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer->data);
727 pipe->bind_fs_state(pipe, ctx->st->state.fs->data);
728 pipe->bind_vs_state(pipe, ctx->st->state.vs->cso->data);
729 pipe->set_sampler_texture(pipe, unit, ctx->st->state.sampler_texture[unit]);
730 pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]->data);
731 pipe->set_viewport_state(pipe, &ctx->st->state.viewport);
732 }
733
734
735 /**
736 * Check if a GL format/type combination is a match to the given pipe format.
737 * XXX probably move this to a re-usable place.
738 */
739 static GLboolean
740 compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat)
741 {
742 static const GLuint one = 1;
743 GLubyte littleEndian = *((GLubyte *) &one);
744
745 if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
746 format == GL_RGBA &&
747 type == GL_UNSIGNED_BYTE &&
748 !littleEndian) {
749 return GL_TRUE;
750 }
751 else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM &&
752 format == GL_ABGR_EXT &&
753 type == GL_UNSIGNED_BYTE &&
754 littleEndian) {
755 return GL_TRUE;
756 }
757 else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM &&
758 format == GL_BGRA &&
759 type == GL_UNSIGNED_BYTE &&
760 littleEndian) {
761 return GL_TRUE;
762 }
763 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
764 format == GL_RGB &&
765 type == GL_UNSIGNED_SHORT_5_6_5) {
766 /* endian don't care */
767 return GL_TRUE;
768 }
769 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM &&
770 format == GL_BGR &&
771 type == GL_UNSIGNED_SHORT_5_6_5_REV) {
772 /* endian don't care */
773 return GL_TRUE;
774 }
775 else if (pipeFormat == PIPE_FORMAT_S8_UNORM &&
776 format == GL_STENCIL_INDEX &&
777 type == GL_UNSIGNED_BYTE) {
778 return GL_TRUE;
779 }
780 else if (pipeFormat == PIPE_FORMAT_Z32_UNORM &&
781 format == GL_DEPTH_COMPONENT &&
782 type == GL_UNSIGNED_INT) {
783 return GL_TRUE;
784 }
785 /* XXX add more cases */
786 else {
787 return GL_FALSE;
788 }
789 }
790
791
792 /**
793 * Check if any per-fragment ops are enabled.
794 * XXX probably move this to a re-usable place.
795 */
796 static GLboolean
797 any_fragment_ops(const struct st_context *st)
798 {
799 if (st->state.depth_stencil->state.alpha.enabled ||
800 st->state.blend->state.blend_enable ||
801 st->state.blend->state.logicop_enable ||
802 st->state.depth_stencil->state.depth.enabled)
803 /* XXX more checks */
804 return GL_TRUE;
805 else
806 return GL_FALSE;
807 }
808
809
810 /**
811 * Check if any pixel transfer ops are enabled.
812 * XXX probably move this to a re-usable place.
813 */
814 static GLboolean
815 any_pixel_transfer_ops(const struct st_context *st)
816 {
817 if (st->ctx->Pixel.RedScale != 1.0 ||
818 st->ctx->Pixel.RedBias != 0.0 ||
819 st->ctx->Pixel.GreenScale != 1.0 ||
820 st->ctx->Pixel.GreenBias != 0.0 ||
821 st->ctx->Pixel.BlueScale != 1.0 ||
822 st->ctx->Pixel.BlueBias != 0.0 ||
823 st->ctx->Pixel.AlphaScale != 1.0 ||
824 st->ctx->Pixel.AlphaBias != 0.0 ||
825 st->ctx->Pixel.MapColorFlag)
826 /* XXX more checks */
827 return GL_TRUE;
828 else
829 return GL_FALSE;
830 }
831
832
833 /**
834 * Draw image with a blit, or other non-textured quad method.
835 */
836 static void
837 draw_blit(struct st_context *st,
838 GLsizei width, GLsizei height,
839 GLenum format, GLenum type, const GLvoid *pixels)
840 {
841
842
843 }
844
845
846 static void
847 draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
848 GLsizei width, GLsizei height, GLenum type,
849 const struct gl_pixelstore_attrib *unpack,
850 const GLvoid *pixels)
851 {
852 struct st_context *st = ctx->st;
853 struct pipe_context *pipe = st->pipe;
854 struct pipe_surface *ps = st->state.framebuffer.zsbuf;
855 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
856 GLint skipPixels;
857 ubyte *stmap;
858
859 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE);
860
861 /* map the stencil buffer */
862 stmap = pipe_surface_map(ps);
863
864 /* if width > MAX_WIDTH, have to process image in chunks */
865 skipPixels = 0;
866 while (skipPixels < width) {
867 const GLint spanX = x + skipPixels;
868 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
869 GLint row;
870 for (row = 0; row < height; row++) {
871 GLint spanY = y + row;
872 GLubyte values[MAX_WIDTH];
873 GLenum destType = GL_UNSIGNED_BYTE;
874 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
875 width, height,
876 GL_COLOR_INDEX, type,
877 row, skipPixels);
878 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
879 type, source, unpack,
880 ctx->_ImageTransferState);
881 if (zoom) {
882 /*
883 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
884 spanX, spanY, values);
885 */
886 }
887 else {
888 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
889 spanY = ctx->DrawBuffer->Height - spanY - 1;
890 }
891
892 switch (ps->format) {
893 case PIPE_FORMAT_U_S8:
894 {
895 ubyte *dest = stmap + spanY * ps->pitch + spanX;
896 memcpy(dest, values, spanWidth);
897 }
898 break;
899 case PIPE_FORMAT_S8Z24_UNORM:
900 {
901 uint *dest = (uint *) stmap + spanY * ps->pitch + spanX;
902 GLint k;
903 for (k = 0; k < spanWidth; k++) {
904 uint p = dest[k];
905 p = (p & 0xffffff) | (values[k] << 24);
906 dest[k] = p;
907 }
908 }
909 break;
910 default:
911 assert(0);
912 }
913 }
914 }
915 skipPixels += spanWidth;
916 }
917
918 /* unmap the stencil buffer */
919 pipe_surface_unmap(ps);
920 }
921
922
923 /**
924 * Called via ctx->Driver.DrawPixels()
925 */
926 static void
927 st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
928 GLenum format, GLenum type,
929 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
930 {
931 struct st_fragment_program *stfp;
932 struct st_vertex_program *stvp;
933 struct st_context *st = ctx->st;
934 struct pipe_surface *ps;
935 GLuint bufferFormat;
936 const GLfloat *color;
937
938 if (format == GL_STENCIL_INDEX) {
939 draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
940 return;
941 }
942
943 st_validate_state(st);
944
945 if (format == GL_DEPTH_COMPONENT) {
946 ps = st->state.framebuffer.zsbuf;
947 stfp = make_fragment_shader_z(ctx->st);
948 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
949 color = ctx->Current.RasterColor;
950 }
951 else if (format == GL_STENCIL_INDEX) {
952 ps = st->state.framebuffer.zsbuf;
953 /* XXX special case - can't use texture map */
954 color = NULL;
955 }
956 else {
957 ps = st->state.framebuffer.cbufs[0];
958 stfp = combined_drawpix_fragment_program(ctx);
959 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
960 color = NULL;
961 }
962
963 bufferFormat = ps->format;
964
965 if (any_fragment_ops(st) ||
966 any_pixel_transfer_ops(st) ||
967 !compatible_formats(format, type, ps->format)) {
968 /* textured quad */
969 struct pipe_texture *pt
970 = make_texture(ctx->st, width, height, format, type, unpack, pixels);
971 if (pt) {
972 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
973 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
974 pt, stvp, stfp, color, GL_FALSE);
975 st->pipe->texture_release(st->pipe, &pt);
976 }
977 }
978 else {
979 /* blit */
980 draw_blit(st, width, height, format, type, pixels);
981 }
982 }
983
984
985
986 /**
987 * Create a texture which represents a bitmap image.
988 */
989 static struct pipe_texture *
990 make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height,
991 const struct gl_pixelstore_attrib *unpack,
992 const GLubyte *bitmap)
993 {
994 struct pipe_context *pipe = ctx->st->pipe;
995 struct pipe_surface *surface;
996 uint format = 0, cpp, comp;
997 ubyte *dest;
998 struct pipe_texture *pt;
999 int row, col;
1000
1001 /* find a texture format we know */
1002 if (pipe->is_format_supported( pipe, PIPE_FORMAT_U_I8, PIPE_TEXTURE )) {
1003 format = PIPE_FORMAT_U_I8;
1004 cpp = 1;
1005 comp = 0;
1006 }
1007 else if (pipe->is_format_supported( pipe, PIPE_FORMAT_A8R8G8B8_UNORM, PIPE_TEXTURE )) {
1008 format = PIPE_FORMAT_A8R8G8B8_UNORM;
1009 cpp = 4;
1010 comp = 3; /* alpha channel */ /*XXX little-endian dependency */
1011 }
1012 else {
1013 /* XXX support more formats */
1014 assert( 0 );
1015 }
1016
1017 /**
1018 * Create a texture.
1019 */
1020 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0, width, height,
1021 1, 0);
1022 if (!pt)
1023 return NULL;
1024
1025 if (unpack->BufferObj && unpack->BufferObj->Name) {
1026 /*
1027 pt->region = buffer_object_region(unpack->BufferObj);
1028 */
1029 printf("st_Bitmap (sourcing from PBO not implemented yet)\n");
1030 }
1031
1032 surface = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
1033
1034 /* map texture surface */
1035 dest = pipe_surface_map(surface);
1036
1037 /* Put image into texture surface.
1038 * Note that the image is actually going to be upside down in
1039 * the texture. We deal with that with texcoords.
1040 */
1041
1042 for (row = 0; row < height; row++) {
1043 const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
1044 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
1045 ubyte *destRow = dest + row * surface->pitch * cpp;
1046
1047 if (unpack->LsbFirst) {
1048 /* Lsb first */
1049 GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
1050 for (col = 0; col < width; col++) {
1051
1052 /* set texel to 255 if bit is set */
1053 destRow[comp] = (*src & mask) ? 255 : 0;
1054 destRow += cpp;
1055
1056 if (mask == 128U) {
1057 src++;
1058 mask = 1U;
1059 }
1060 else {
1061 mask = mask << 1;
1062 }
1063 }
1064
1065 /* get ready for next row */
1066 if (mask != 1)
1067 src++;
1068 }
1069 else {
1070 /* Msb first */
1071 GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
1072 for (col = 0; col < width; col++) {
1073
1074 /* set texel to 255 if bit is set */
1075 destRow[comp] =(*src & mask) ? 255 : 0;
1076 destRow += cpp;
1077
1078 if (mask == 1U) {
1079 src++;
1080 mask = 128U;
1081 }
1082 else {
1083 mask = mask >> 1;
1084 }
1085 }
1086
1087 /* get ready for next row */
1088 if (mask != 128)
1089 src++;
1090 }
1091
1092 } /* row */
1093
1094 /* Release surface */
1095 pipe_surface_unmap(surface);
1096 pipe_surface_reference(&surface, NULL);
1097
1098 pt->format = format;
1099
1100 return pt;
1101 }
1102
1103
1104
1105 static void
1106 st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
1107 const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
1108 {
1109 struct st_fragment_program *stfp;
1110 struct st_vertex_program *stvp;
1111 struct st_context *st = ctx->st;
1112 struct pipe_texture *pt;
1113
1114 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
1115 stfp = combined_bitmap_fragment_program(ctx);
1116
1117 st_validate_state(st);
1118
1119 pt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
1120 if (pt) {
1121 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
1122 width, height, 1.0, 1.0,
1123 pt, stvp, stfp,
1124 ctx->Current.RasterColor, GL_FALSE);
1125
1126 st->pipe->texture_release(st->pipe, &pt);
1127 }
1128 }
1129
1130
1131 static void
1132 copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
1133 GLsizei width, GLsizei height,
1134 GLint dstx, GLint dsty)
1135 {
1136 struct st_renderbuffer *rbRead = st_renderbuffer(ctx->ReadBuffer->_StencilBuffer);
1137 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
1138 struct pipe_surface *psRead = rbRead->surface;
1139 struct pipe_surface *psDraw = rbDraw->surface;
1140 ubyte *readMap, *drawMap;
1141 ubyte *buffer;
1142 int i;
1143
1144 buffer = malloc(width * height * sizeof(ubyte));
1145 if (!buffer) {
1146 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
1147 return;
1148 }
1149
1150 /* map the stencil buffers */
1151 readMap = pipe_surface_map(psRead);
1152 drawMap = pipe_surface_map(psDraw);
1153
1154 /* this will do stencil pixel transfer ops */
1155 st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
1156 &ctx->DefaultPacking, buffer);
1157
1158 /* draw */
1159 /* XXX PixelZoom not handled yet */
1160 for (i = 0; i < height; i++) {
1161 ubyte *dst;
1162 const ubyte *src;
1163 int y;
1164
1165 y = dsty + i;
1166
1167 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1168 y = ctx->DrawBuffer->Height - y - 1;
1169 }
1170
1171 dst = drawMap + (y * psDraw->pitch + dstx) * psDraw->cpp;
1172 src = buffer + i * width;
1173
1174 switch (psDraw->format) {
1175 case PIPE_FORMAT_S8Z24_UNORM:
1176 {
1177 uint *dst4 = (uint *) dst;
1178 int j;
1179 for (j = 0; j < width; j++) {
1180 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
1181 dst4++;
1182 }
1183 }
1184 break;
1185 case PIPE_FORMAT_U_S8:
1186 memcpy(dst, src, width);
1187 break;
1188 default:
1189 assert(0);
1190 }
1191 }
1192
1193 free(buffer);
1194
1195 /* unmap the stencil buffers */
1196 pipe_surface_unmap(psRead);
1197 pipe_surface_unmap(psDraw);
1198 }
1199
1200
1201 static void
1202 st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
1203 GLsizei width, GLsizei height,
1204 GLint dstx, GLint dsty, GLenum type)
1205 {
1206 struct st_context *st = ctx->st;
1207 struct pipe_context *pipe = st->pipe;
1208 struct st_renderbuffer *rbRead;
1209 struct st_vertex_program *stvp;
1210 struct st_fragment_program *stfp;
1211 struct pipe_surface *psRead;
1212 struct pipe_surface *psTex;
1213 struct pipe_texture *pt;
1214 GLfloat *color;
1215 uint format;
1216
1217 /* make sure rendering has completed */
1218 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE);
1219
1220 st_validate_state(st);
1221
1222 if (type == GL_STENCIL) {
1223 /* can't use texturing to do stencil */
1224 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
1225 return;
1226 }
1227
1228 if (type == GL_COLOR) {
1229 rbRead = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
1230 color = NULL;
1231 stfp = combined_drawpix_fragment_program(ctx);
1232 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
1233 }
1234 else {
1235 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
1236 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
1237 stfp = make_fragment_shader_z(ctx->st);
1238 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
1239 }
1240
1241 psRead = rbRead->surface;
1242 format = psRead->format;
1243
1244 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0, width, height,
1245 1, 0);
1246 if (!pt)
1247 return;
1248
1249 psTex = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
1250
1251 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1252 srcy = ctx->DrawBuffer->Height - srcy - height;
1253 }
1254
1255 /* For some drivers (like Xlib) it's not possible to treat the
1256 * front/back color buffers as surfaces (they're XImages and Pixmaps).
1257 * So, this var tells us if we can use surface_copy here...
1258 */
1259 if (st->haveFramebufferSurfaces) {
1260 /* copy source framebuffer surface into mipmap/texture */
1261 pipe->surface_copy(pipe,
1262 FALSE,
1263 psTex, /* dest */
1264 0, 0, /* destx/y */
1265 psRead,
1266 srcx, srcy, width, height);
1267 }
1268 else {
1269 /* alternate path using get/put_tile() */
1270 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1271
1272 pipe_get_tile_rgba(pipe, psRead, srcx, srcy, width, height, buf);
1273 pipe_put_tile_rgba(pipe, psTex, 0, 0, width, height, buf);
1274
1275 free(buf);
1276 }
1277
1278 /* draw textured quad */
1279 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1280 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1281 pt, stvp, stfp, color, GL_TRUE);
1282
1283 pipe_surface_reference(&psTex, NULL);
1284 st->pipe->texture_release(st->pipe, &pt);
1285 }
1286
1287
1288
1289 void st_init_drawpixels_functions(struct dd_function_table *functions)
1290 {
1291 functions->DrawPixels = st_DrawPixels;
1292 functions->CopyPixels = st_CopyPixels;
1293 functions->Bitmap = st_Bitmap;
1294 }