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