initial use of KIL for glBitmap rendering
[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
36 #include "st_context.h"
37 #include "st_atom.h"
38 #include "st_cache.h"
39 #include "st_draw.h"
40 #include "st_program.h"
41 #include "st_cb_drawpixels.h"
42 #include "st_cb_texture.h"
43 #include "st_draw.h"
44 #include "st_format.h"
45 #include "pipe/p_context.h"
46 #include "pipe/p_defines.h"
47 #include "pipe/tgsi/mesa/mesa_to_tgsi.h"
48 #include "shader/prog_instruction.h"
49 #include "vf/vf.h"
50
51
52
53 /**
54 * Create a simple fragment shader that does a TEX() instruction to get
55 * the fragment color.
56 */
57 static struct st_fragment_program *
58 make_fragment_shader(struct st_context *st, GLboolean bitmapMode)
59 {
60 GLcontext *ctx = st->ctx;
61 struct st_fragment_program *stfp;
62 struct gl_program *p;
63 GLuint ic = 0;
64
65 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
66 if (!p)
67 return NULL;
68
69 #define CULL 1 /* Use KIL to cull 0 bits/pixels in bitmap? */
70
71 if (bitmapMode)
72 #if CULL
73 p->NumInstructions = 7;
74 #else
75 p->NumInstructions = 3;
76 #endif
77 else
78 p->NumInstructions = 2;
79
80 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
81 if (!p->Instructions) {
82 ctx->Driver.DeleteProgram(ctx, p);
83 return NULL;
84 }
85 _mesa_init_instructions(p->Instructions, p->NumInstructions);
86 if (bitmapMode) {
87 /*
88 * XXX This is temporary
89 * We actually need to cull the fragment if the texture value is zero.
90 * But TGSI doesn't support conditionals yet.
91 * Also, we need to compose this fragment shader with the current
92 * user-provided fragment shader so the fragment program is applied
93 * to the fragments which aren't culled.
94 */
95 /* TEX temp0, fragment.texcoord[0], texture[0], 2D; */
96 p->Instructions[ic].Opcode = OPCODE_TEX;
97 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
98 p->Instructions[ic].DstReg.Index = 0;
99 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
100 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
101 p->Instructions[ic].TexSrcUnit = 0;
102 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
103 ic++;
104 #if CULL
105 /* IF temp0 */
106 p->Instructions[ic].Opcode = OPCODE_IF;
107 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
108 p->Instructions[ic].SrcReg[0].Index = 0;
109 p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_WWWW;
110 p->Instructions[ic].BranchTarget = ic + 2;
111 ic++;
112
113 /* MOV result.color, fragment.color */
114 p->Instructions[ic].Opcode = OPCODE_MOV;
115 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
116 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
117 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
118 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
119 ic++;
120
121 /* ELSE */
122 p->Instructions[ic].Opcode = OPCODE_ELSE;
123 p->Instructions[ic].BranchTarget = ic + 2;
124 ic++;
125
126 /* KILL */
127 p->Instructions[ic].Opcode = OPCODE_KIL_NV;
128 ic++;
129
130 /* ENDIF */
131 p->Instructions[ic].Opcode = OPCODE_ENDIF;
132 ic++;
133 #else
134 /* MUL result.color, temp0.xxxx, fragment.color */
135 p->Instructions[ic].Opcode = OPCODE_MUL;
136 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
137 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
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_INPUT;
142 p->Instructions[ic].SrcReg[1].Index = FRAG_ATTRIB_COL0;
143 ic++;
144 #endif
145 }
146 else {
147 /* DrawPixels mode */
148 /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
149 p->Instructions[ic].Opcode = OPCODE_TEX;
150 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
151 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
152 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
153 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
154 p->Instructions[ic].TexSrcUnit = 0;
155 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
156 ic++;
157 }
158 /* END; */
159 p->Instructions[ic++].Opcode = OPCODE_END;
160
161 assert(ic == p->NumInstructions);
162
163 p->InputsRead = FRAG_BIT_TEX0;
164 p->OutputsWritten = (1 << FRAG_RESULT_COLR);
165 if (bitmapMode) {
166 p->InputsRead |= FRAG_BIT_COL0;
167 }
168
169 stfp = (struct st_fragment_program *) p;
170 st_translate_fragment_program(st, stfp, NULL,
171 stfp->tokens, ST_MAX_SHADER_TOKENS);
172
173 return stfp;
174 }
175
176
177 /**
178 * Create a simple vertex shader that just passes through the
179 * vertex position and texcoord (and color).
180 */
181 static struct st_vertex_program *
182 make_vertex_shader(struct st_context *st, GLboolean passColor)
183 {
184 GLcontext *ctx = st->ctx;
185 struct st_vertex_program *stvp;
186 struct gl_program *p;
187 GLuint ic = 0;
188
189 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
190 if (!p)
191 return NULL;
192
193 if (passColor)
194 p->NumInstructions = 4;
195 else
196 p->NumInstructions = 3;
197
198 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
199 if (!p->Instructions) {
200 ctx->Driver.DeleteProgram(ctx, p);
201 return NULL;
202 }
203 _mesa_init_instructions(p->Instructions, p->NumInstructions);
204 /* MOV result.pos, vertex.pos; */
205 p->Instructions[0].Opcode = OPCODE_MOV;
206 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
207 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
208 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
209 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
210 /* MOV result.texcoord0, vertex.texcoord0; */
211 p->Instructions[1].Opcode = OPCODE_MOV;
212 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
213 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
214 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
215 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
216 ic = 2;
217 if (passColor) {
218 /* MOV result.color0, vertex.color0; */
219 p->Instructions[ic].Opcode = OPCODE_MOV;
220 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
221 p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
222 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
223 p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
224 ic++;
225 }
226
227 /* END; */
228 p->Instructions[ic].Opcode = OPCODE_END;
229 ic++;
230
231 assert(ic == p->NumInstructions);
232
233 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
234 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
235 (1 << VERT_RESULT_HPOS));
236 if (passColor) {
237 p->InputsRead |= VERT_BIT_COLOR0;
238 p->OutputsWritten |= (1 << VERT_RESULT_COL0);
239 }
240
241 stvp = (struct st_vertex_program *) p;
242 st_translate_vertex_program(st, stvp, NULL,
243 stvp->tokens, ST_MAX_SHADER_TOKENS);
244
245 return stvp;
246 }
247
248
249 /**
250 * Make mipmap tree containing the glDrawPixels image.
251 */
252 static struct pipe_mipmap_tree *
253 make_mipmap_tree(struct st_context *st,
254 GLsizei width, GLsizei height, GLenum format, GLenum type,
255 const struct gl_pixelstore_attrib *unpack,
256 const GLvoid *pixels)
257 {
258 struct pipe_context *pipe = st->pipe;
259 const struct gl_texture_format *mformat;
260 const GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE;
261 struct pipe_mipmap_tree *mt;
262 GLuint pipeFormat, cpp;
263
264 mformat = st_ChooseTextureFormat(st->ctx, GL_RGBA, format, type);
265 assert(mformat);
266
267 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
268 assert(pipeFormat);
269 cpp = st_sizeof_format(pipeFormat);
270
271 mt = CALLOC_STRUCT(pipe_mipmap_tree);
272 if (!mt)
273 return NULL;
274
275 if (unpack->BufferObj && unpack->BufferObj->Name) {
276 /*
277 mt->region = buffer_object_region(unpack->BufferObj);
278 */
279 printf("st_DrawPixels (sourcing from PBO not implemented yet)\n");
280 }
281 else {
282 static const GLuint dstImageOffsets = 0;
283 GLboolean success;
284 GLubyte *dest;
285 GLuint pitch;
286
287 /* allocate texture region/storage */
288 mt->region = st->pipe->region_alloc(st->pipe, cpp, width, height, flags);
289 pitch = mt->region->pitch;
290
291 /* map texture region */
292 dest = pipe->region_map(pipe, mt->region);
293
294 /* Put image into texture region.
295 * Note that the image is actually going to be upside down in
296 * the texture. We deal with that with texcoords.
297 */
298 success = mformat->StoreImage(st->ctx, 2, /* dims */
299 GL_RGBA, /* baseInternalFormat */
300 mformat, /* gl_texture_format */
301 dest, /* dest */
302 0, 0, 0, /* dstX/Y/Zoffset */
303 pitch * cpp, /* dstRowStride, bytes */
304 &dstImageOffsets, /* dstImageOffsets */
305 width, height, 1, /* size */
306 format, type, /* src format/type */
307 pixels, /* data source */
308 unpack);
309
310 /* unmap */
311 pipe->region_unmap(pipe, mt->region);
312
313 assert(success);
314 }
315
316 mt->target = PIPE_TEXTURE_2D;
317 mt->internal_format = GL_RGBA;
318 mt->format = pipeFormat;
319 mt->first_level = 0;
320 mt->last_level = 0;
321 mt->width0 = width;
322 mt->height0 = height;
323 mt->depth0 = 1;
324 mt->cpp = cpp;
325 mt->compressed = 0;
326 mt->pitch = mt->region->pitch;
327 mt->depth_pitch = 0;
328 mt->total_height = height;
329 mt->level[0].level_offset = 0;
330 mt->level[0].width = width;
331 mt->level[0].height = height;
332 mt->level[0].depth = 1;
333 mt->level[0].nr_images = 1;
334 mt->level[0].image_offset = NULL;
335 mt->refcount = 1;
336
337 return mt;
338 }
339
340
341 static void
342 free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
343 {
344 pipe->region_release(pipe, &mt->region);
345 free(mt);
346 }
347
348
349 /**
350 * Draw textured quad.
351 * Coords are window coords with y=0=bottom.
352 */
353 static void
354 draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
355 GLfloat x1, GLfloat y1)
356 {
357 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
358 GLuint i;
359
360 /* upper-left */
361 verts[0][0][0] = x0; /* attr[0].x */
362 verts[0][0][1] = y0; /* attr[0].x */
363 verts[0][1][0] = 0.0; /* attr[1].s */
364 verts[0][1][1] = 0.0; /* attr[1].t */
365
366 /* upper-right */
367 verts[1][0][0] = x1;
368 verts[1][0][1] = y0;
369 verts[1][1][0] = 1.0;
370 verts[1][1][1] = 0.0;
371
372 /* lower-right */
373 verts[2][0][0] = x1;
374 verts[2][0][1] = y1;
375 verts[2][1][0] = 1.0;
376 verts[2][1][1] = 1.0;
377
378 /* lower-left */
379 verts[3][0][0] = x0;
380 verts[3][0][1] = y1;
381 verts[3][1][0] = 0.0;
382 verts[3][1][1] = 1.0;
383
384 /* same for all verts: */
385 for (i = 0; i < 4; i++) {
386 verts[i][0][2] = z; /*Z*/
387 verts[i][0][3] = 1.0; /*W*/
388 verts[i][1][2] = 0.0; /*R*/
389 verts[i][1][3] = 1.0; /*Q*/
390 }
391
392 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2);
393 }
394
395
396 static void
397 draw_quad_colored(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
398 GLfloat x1, GLfloat y1, const GLfloat *color)
399 {
400 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
401 GLuint i;
402
403 /* upper-left */
404 verts[0][0][0] = x0; /* attr[0].x */
405 verts[0][0][1] = y0; /* attr[0].x */
406 verts[0][2][0] = 0.0; /* attr[2].s */
407 verts[0][2][1] = 0.0; /* attr[2].t */
408
409 /* upper-right */
410 verts[1][0][0] = x1;
411 verts[1][0][1] = y0;
412 verts[1][2][0] = 1.0;
413 verts[1][2][1] = 0.0;
414
415 /* lower-right */
416 verts[2][0][0] = x1;
417 verts[2][0][1] = y1;
418 verts[2][2][0] = 1.0;
419 verts[2][2][1] = 1.0;
420
421 /* lower-left */
422 verts[3][0][0] = x0;
423 verts[3][0][1] = y1;
424 verts[3][2][0] = 0.0;
425 verts[3][2][1] = 1.0;
426
427 /* same for all verts: */
428 for (i = 0; i < 4; i++) {
429 verts[i][0][2] = z; /*Z*/
430 verts[i][0][3] = 1.0; /*W*/
431 verts[i][1][0] = color[0];
432 verts[i][1][1] = color[1];
433 verts[i][1][2] = color[2];
434 verts[i][1][3] = color[3];
435 verts[i][2][2] = 0.0; /*R*/
436 verts[i][2][3] = 1.0; /*Q*/
437 }
438
439 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 3);
440 }
441
442
443
444 static void
445 draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
446 GLsizei width, GLsizei height,
447 GLfloat zoomX, GLfloat zoomY,
448 struct pipe_mipmap_tree *mt,
449 struct st_vertex_program *stvp,
450 struct st_fragment_program *stfp,
451 const GLfloat *color)
452 {
453 const GLuint unit = 0;
454 struct pipe_context *pipe = ctx->st->pipe;
455 GLfloat x0, y0, x1, y1;
456 GLuint maxWidth, maxHeight;
457
458 /* limit checks */
459 /* XXX if DrawPixels image is larger than max texture size, break
460 * it up into chunks.
461 */
462 pipe->max_texture_size(pipe, PIPE_TEXTURE_2D, &maxWidth, &maxHeight, NULL);
463 assert(width <= maxWidth);
464 assert(height <= maxHeight);
465
466 /* setup state: just scissor */
467 {
468 struct pipe_rasterizer_state setup;
469 const struct cso_rasterizer *cso;
470 memset(&setup, 0, sizeof(setup));
471 if (ctx->Scissor.Enabled)
472 setup.scissor = 1;
473 cso = st_cached_rasterizer_state(ctx->st, &setup);
474 pipe->bind_rasterizer_state(pipe, cso->data);
475 }
476
477 /* fragment shader state: TEX lookup program */
478 pipe->bind_fs_state(pipe, stfp->fs->data);
479
480 /* vertex shader state: position + texcoord pass-through */
481 pipe->bind_vs_state(pipe, stvp->vs->data);
482
483 /* texture sampling state: */
484 {
485 struct pipe_sampler_state sampler;
486 const struct cso_sampler *cso;
487 memset(&sampler, 0, sizeof(sampler));
488 sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
489 sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
490 sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
491 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
492 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
493 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
494 cso = st_cached_sampler_state(ctx->st, &sampler);
495 pipe->bind_sampler_state(pipe, unit, cso->data);
496 }
497
498 /* viewport state: viewport matching window dims */
499 {
500 const float width = ctx->DrawBuffer->Width;
501 const float height = ctx->DrawBuffer->Height;
502 struct pipe_viewport_state vp;
503 vp.scale[0] = 0.5 * width;
504 vp.scale[1] = -0.5 * height;
505 vp.scale[2] = 0.5;
506 vp.scale[3] = 1.0;
507 vp.translate[0] = 0.5 * width;
508 vp.translate[1] = 0.5 * height;
509 vp.translate[2] = 0.5;
510 vp.translate[3] = 0.0;
511 pipe->set_viewport_state(pipe, &vp);
512 }
513
514 /* mipmap tree state: */
515 {
516 pipe->set_texture_state(pipe, unit, mt);
517 }
518
519 /* Compute window coords (y=0=bottom) with pixel zoom.
520 * Recall that these coords are transformed by the current
521 * vertex shader and viewport transformation.
522 */
523 x0 = x;
524 x1 = x + width * ctx->Pixel.ZoomX;
525 y0 = y;
526 y1 = y + height * ctx->Pixel.ZoomY;
527
528 /* draw textured quad */
529 if (color)
530 draw_quad_colored(ctx, x0, y0, z, x1, y1, color);
531 else
532 draw_quad(ctx, x0, y0, z, x1, y1);
533
534 /* restore GL state */
535 pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer->data);
536 pipe->bind_fs_state(pipe, ctx->st->state.fs->data);
537 pipe->bind_vs_state(pipe, ctx->st->state.vs->data);
538 pipe->set_texture_state(pipe, unit, ctx->st->state.texture[unit]);
539 pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]->data);
540 pipe->set_viewport_state(pipe, &ctx->st->state.viewport);
541 }
542
543
544 /**
545 * Check if a GL format/type combination is a match to the given pipe format.
546 * XXX probably move this to a re-usable place.
547 */
548 static GLboolean
549 compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
550 {
551 static const GLuint one = 1;
552 GLubyte littleEndian = *((GLubyte *) &one);
553
554 if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
555 format == GL_RGBA &&
556 type == GL_UNSIGNED_BYTE &&
557 !littleEndian) {
558 return GL_TRUE;
559 }
560 else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
561 format == GL_ABGR_EXT &&
562 type == GL_UNSIGNED_BYTE &&
563 littleEndian) {
564 return GL_TRUE;
565 }
566 else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
567 format == GL_BGRA &&
568 type == GL_UNSIGNED_BYTE &&
569 littleEndian) {
570 return GL_TRUE;
571 }
572 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
573 format == GL_RGB &&
574 type == GL_UNSIGNED_SHORT_5_6_5) {
575 /* endian don't care */
576 return GL_TRUE;
577 }
578 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
579 format == GL_BGR &&
580 type == GL_UNSIGNED_SHORT_5_6_5_REV) {
581 /* endian don't care */
582 return GL_TRUE;
583 }
584 else if (pipeFormat == PIPE_FORMAT_U_S8 &&
585 format == GL_STENCIL_INDEX &&
586 type == GL_UNSIGNED_BYTE) {
587 return GL_TRUE;
588 }
589 else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
590 format == GL_DEPTH_COMPONENT &&
591 type == GL_UNSIGNED_INT) {
592 return GL_TRUE;
593 }
594 /* XXX add more cases */
595 else {
596 return GL_FALSE;
597 }
598 }
599
600
601 /**
602 * Check if any per-fragment ops are enabled.
603 * XXX probably move this to a re-usable place.
604 */
605 static GLboolean
606 any_fragment_ops(const struct st_context *st)
607 {
608 if (st->state.alpha_test->state.enabled ||
609 st->state.blend->state.blend_enable ||
610 st->state.blend->state.logicop_enable ||
611 st->state.depth_stencil->state.depth.enabled)
612 /* XXX more checks */
613 return GL_TRUE;
614 else
615 return GL_FALSE;
616 }
617
618
619 /**
620 * Check if any pixel transfer ops are enabled.
621 * XXX probably move this to a re-usable place.
622 */
623 static GLboolean
624 any_pixel_transfer_ops(const struct st_context *st)
625 {
626 if (st->ctx->Pixel.RedScale != 1.0 ||
627 st->ctx->Pixel.RedBias != 0.0 ||
628 st->ctx->Pixel.GreenScale != 1.0 ||
629 st->ctx->Pixel.GreenBias != 0.0 ||
630 st->ctx->Pixel.BlueScale != 1.0 ||
631 st->ctx->Pixel.BlueBias != 0.0 ||
632 st->ctx->Pixel.AlphaScale != 1.0 ||
633 st->ctx->Pixel.AlphaBias != 0.0 ||
634 st->ctx->Pixel.MapColorFlag)
635 /* XXX more checks */
636 return GL_TRUE;
637 else
638 return GL_FALSE;
639 }
640
641
642 /**
643 * Draw image with a blit, or other non-textured quad method.
644 */
645 static void
646 draw_blit(struct st_context *st,
647 GLsizei width, GLsizei height,
648 GLenum format, GLenum type, const GLvoid *pixels)
649 {
650
651
652 }
653
654
655 /**
656 * Called via ctx->Driver.DrawPixels()
657 */
658 static void
659 st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
660 GLenum format, GLenum type,
661 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
662 {
663 static struct st_fragment_program *stfp = NULL;
664 static struct st_vertex_program *stvp = NULL;
665 struct st_context *st = ctx->st;
666 struct pipe_surface *ps;
667 GLuint bufferFormat;
668
669 /* create the fragment program if needed */
670 if (!stfp) {
671 stfp = make_fragment_shader(ctx->st, GL_FALSE);
672 }
673 /* and vertex program */
674 if (!stvp) {
675 stvp = make_vertex_shader(ctx->st, GL_FALSE);
676 }
677
678 st_validate_state(st);
679
680 if (format == GL_DEPTH_COMPONENT) {
681 ps = st->state.framebuffer.zbuf;
682 }
683 else if (format == GL_STENCIL_INDEX) {
684 ps = st->state.framebuffer.sbuf;
685 }
686 else {
687 ps = st->state.framebuffer.cbufs[0];
688 }
689
690 bufferFormat = ps->format;
691
692 if (any_fragment_ops(st) ||
693 any_pixel_transfer_ops(st) ||
694 !compatible_formats(format, type, ps->format)) {
695 /* textured quad */
696 struct pipe_mipmap_tree *mt
697 = make_mipmap_tree(ctx->st, width, height, format, type,
698 unpack, pixels);
699 if (mt) {
700 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
701 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
702 mt, stvp, stfp, NULL);
703 free_mipmap_tree(st->pipe, mt);
704 }
705 }
706 else {
707 /* blit */
708 draw_blit(st, width, height, format, type, pixels);
709 }
710 }
711
712
713
714 /**
715 * Create a texture which represents a bitmap image.
716 */
717 static struct pipe_mipmap_tree *
718 make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height,
719 const struct gl_pixelstore_attrib *unpack,
720 const GLubyte *bitmap)
721 {
722 struct pipe_context *pipe = ctx->st->pipe;
723 const uint flags = PIPE_SURFACE_FLAG_TEXTURE;
724 uint numFormats, i, format = 0, cpp, comp, pitch;
725 const uint *formats = ctx->st->pipe->supported_formats(pipe, &numFormats);
726 ubyte *dest;
727 struct pipe_mipmap_tree *mt;
728 int row, col;
729
730 /* find a texture format we know */
731 for (i = 0; i < numFormats; i++) {
732 switch (formats[i]) {
733 case PIPE_FORMAT_U_I8:
734 format = formats[i];
735 cpp = 1;
736 comp = 0;
737 break;
738 case PIPE_FORMAT_U_A8_R8_G8_B8:
739 format = formats[i];
740 cpp = 4;
741 comp = 3; /* alpha channel */ /*XXX little-endian dependency */
742 break;
743 default:
744 /* XXX support more formats */
745 ;
746 }
747 }
748 assert(format);
749
750 /**
751 * Create a mipmap tree.
752 */
753 mt = CALLOC_STRUCT(pipe_mipmap_tree);
754 if (!mt)
755 return NULL;
756
757 if (unpack->BufferObj && unpack->BufferObj->Name) {
758 /*
759 mt->region = buffer_object_region(unpack->BufferObj);
760 */
761 printf("st_Bitmap (sourcing from PBO not implemented yet)\n");
762 }
763
764
765 /* allocate texture region/storage */
766 mt->region = pipe->region_alloc(pipe, cpp, width, height, flags);
767 pitch = mt->region->pitch;
768
769 /* map texture region */
770 dest = pipe->region_map(pipe, mt->region);
771 if (!dest) {
772 printf("st_Bitmap region_map() failed!?!");
773 return NULL;
774 }
775
776 /* Put image into texture region.
777 * Note that the image is actually going to be upside down in
778 * the texture. We deal with that with texcoords.
779 */
780
781 for (row = 0; row < height; row++) {
782 const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
783 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
784 ubyte *destRow = dest + row * pitch * cpp;
785
786 if (unpack->LsbFirst) {
787 /* Lsb first */
788 GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
789 assert(0);
790 for (col = 0; col < width; col++) {
791
792 /* set texel to 255 if bit is set */
793 destRow[comp] = (*src & mask) ? 255 : 0;
794 destRow += cpp;
795
796 if (mask == 128U) {
797 src++;
798 mask = 1U;
799 }
800 else {
801 mask = mask << 1;
802 }
803 }
804
805 /* get ready for next row */
806 if (mask != 1)
807 src++;
808 }
809 else {
810 /* Msb first */
811 GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
812 for (col = 0; col < width; col++) {
813
814 /* set texel to 255 if bit is set */
815 destRow[comp] =(*src & mask) ? 255 : 0;
816 destRow += cpp;
817
818 if (mask == 1U) {
819 src++;
820 mask = 128U;
821 }
822 else {
823 mask = mask >> 1;
824 }
825 }
826
827 /* get ready for next row */
828 if (mask != 128)
829 src++;
830 }
831
832 } /* row */
833
834 /* unmap */
835 pipe->region_unmap(pipe, mt->region);
836
837 mt->target = PIPE_TEXTURE_2D;
838 mt->internal_format = GL_RGBA;
839 mt->format = format;
840 mt->first_level = 0;
841 mt->last_level = 0;
842 mt->width0 = width;
843 mt->height0 = height;
844 mt->depth0 = 1;
845 mt->cpp = cpp;
846 mt->compressed = 0;
847 mt->pitch = mt->region->pitch;
848 mt->depth_pitch = 0;
849 mt->total_height = height;
850 mt->level[0].level_offset = 0;
851 mt->level[0].width = width;
852 mt->level[0].height = height;
853 mt->level[0].depth = 1;
854 mt->level[0].nr_images = 1;
855 mt->level[0].image_offset = NULL;
856 mt->refcount = 1;
857
858 return mt;
859 }
860
861
862
863 static void
864 st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
865 const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
866 {
867 static struct st_vertex_program *stvp = NULL;
868 static struct st_fragment_program *stfp = NULL;
869 struct st_context *st = ctx->st;
870 struct pipe_mipmap_tree *mt;
871
872 /* create the fragment program if needed */
873 if (!stfp) {
874 stfp = make_fragment_shader(ctx->st, GL_TRUE);
875 }
876 /* and vertex program */
877 if (!stvp) {
878 stvp = make_vertex_shader(ctx->st, GL_TRUE);
879 }
880
881 st_validate_state(st);
882
883 mt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
884 if (mt) {
885 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
886 width, height, 1.0, 1.0,
887 mt, stvp, stfp,
888 ctx->Current.RasterColor);
889
890 free_mipmap_tree(st->pipe, mt);
891 }
892 }
893
894
895 static void
896 st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
897 GLsizei width, GLsizei height,
898 GLint dstx, GLint dsty, GLenum type)
899 {
900 struct st_context *st = ctx->st;
901
902 st_validate_state(st);
903
904 fprintf(stderr, "st_CopyPixels not implemented yet\n");
905 /* XXX to do */
906 }
907
908
909
910 void st_init_drawpixels_functions(struct dd_function_table *functions)
911 {
912 functions->DrawPixels = st_DrawPixels;
913 functions->CopyPixels = st_CopyPixels;
914 functions->Bitmap = st_Bitmap;
915 }