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