st_cb_drawpixels.c revision e51aa572934c39fe3c99470343f776be4e783f42
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 "imports.h" 34 35#include "st_context.h" 36#include "st_atom.h" 37#include "st_draw.h" 38#include "st_program.h" 39#include "st_cb_drawpixels.h" 40#include "st_cb_texture.h" 41#include "st_format.h" 42#include "pipe/p_context.h" 43#include "pipe/p_defines.h" 44#include "pipe/tgsi/mesa/mesa_to_tgsi.h" 45#include "shader/prog_instruction.h" 46#include "vf/vf.h" 47 48 49 50/** 51 * Create a simple fragment shader that passes the texture color through 52 * to the fragment color. 53 */ 54static struct st_fragment_program * 55make_drawpixels_shader(struct st_context *st) 56{ 57 GLcontext *ctx = st->ctx; 58 struct st_fragment_program *stfp; 59 struct gl_program *p; 60 GLboolean b; 61 62 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); 63 if (!p) 64 return NULL; 65 66 p->NumInstructions = 2; 67 p->Instructions = _mesa_alloc_instructions(2); 68 if (!p->Instructions) { 69 ctx->Driver.DeleteProgram(ctx, p); 70 return NULL; 71 } 72 _mesa_init_instructions(p->Instructions, 2); 73 /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */ 74 p->Instructions[0].Opcode = OPCODE_TEX; 75 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; 76 p->Instructions[0].DstReg.Index = FRAG_RESULT_COLR; 77 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; 78 p->Instructions[0].SrcReg[0].Index = FRAG_ATTRIB_TEX0; 79 p->Instructions[0].TexSrcUnit = 0; 80 p->Instructions[0].TexSrcTarget = TEXTURE_2D_INDEX; 81 /* END; */ 82 p->Instructions[1].Opcode = OPCODE_END; 83 84 p->InputsRead = FRAG_BIT_TEX0; 85 p->OutputsWritten = (1 << FRAG_RESULT_COLR); 86 87 stfp = (struct st_fragment_program *) p; 88 /* compile into tgsi format */ 89 b = tgsi_mesa_compile_fp_program(&stfp->Base, 90 stfp->tokens, ST_FP_MAX_TOKENS); 91 assert(b); 92 93 return stfp; 94} 95 96 97static struct pipe_mipmap_tree * 98make_mipmap_tree(struct st_context *st, 99 GLsizei width, GLsizei height, GLenum format, GLenum type, 100 const struct gl_pixelstore_attrib *unpack, 101 const GLvoid *pixels) 102{ 103 struct pipe_context *pipe = st->pipe; 104 const struct gl_texture_format *mformat; 105 GLuint pipeFormat = st_choose_pipe_format(st->pipe, GL_RGBA, format, type); 106 int cpp = 4; 107 struct pipe_mipmap_tree *mt = CALLOC_STRUCT(pipe_mipmap_tree); 108 GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE; 109 110 mformat = st_ChooseTextureFormat(st->ctx, GL_RGBA, format, type); 111 assert(format); 112 113 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); 114 assert(pipeFormat); 115 116 if (unpack->BufferObj && unpack->BufferObj->Name) { 117 /* 118 mt->region = buffer_object_region(unpack->BufferObj); 119 */ 120 } 121 else { 122 static const GLuint dstImageOffsets = 0; 123 GLboolean success; 124 GLubyte *dest; 125 GLuint pitch; 126 127 /* allocate texture region/storage */ 128 mt->region = st->pipe->region_alloc(st->pipe, cpp, width, height, flags); 129 pitch = mt->region->pitch; 130 131 /* map texture region */ 132 dest = pipe->region_map(pipe, mt->region); 133 134 /* put image into texture region */ 135 success = mformat->StoreImage(st->ctx, 2, /* dims */ 136 GL_RGBA, /* baseInternalFormat */ 137 mformat, /* gl_texture_format */ 138 dest, /* dest */ 139 0, 0, 0, /* dstX/Y/Zoffset */ 140 pitch * cpp, /* dstRowStride */ 141 &dstImageOffsets, /* dstImageOffsets */ 142 width, height, 1, /* size */ 143 format, type, /* src format/type */ 144 pixels, /* data source */ 145 unpack); 146 147 /* unmap */ 148 pipe->region_unmap(pipe, mt->region); 149 150 assert(success); 151 } 152 153 mt->target = GL_TEXTURE_2D; 154 mt->internal_format = GL_RGBA; 155 mt->format = pipeFormat; 156 mt->first_level = 0; 157 mt->last_level = 0; 158 mt->width0 = width; 159 mt->height0 = height; 160 mt->depth0 = 1; 161 mt->cpp = cpp; 162 mt->compressed = 0; 163 mt->pitch = mt->region->pitch; 164 mt->depth_pitch = 0; 165 mt->total_height = height; 166 mt->level[0].level_offset = 0; 167 mt->level[0].width = width; 168 mt->level[0].height = height; 169 mt->level[0].depth = 1; 170 mt->level[0].nr_images = 1; 171 mt->level[0].image_offset = NULL; 172 mt->refcount = 1; 173 174 return mt; 175} 176 177 178static void 179free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt) 180{ 181 pipe->region_release(pipe, &mt->region); 182 free(mt); 183} 184 185 186static void 187draw_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z, 188 GLsizei width, GLsizei height) 189{ 190 static const GLuint attribs[2] = { 191 VF_ATTRIB_POS, 192 VF_ATTRIB_TEX0 193 }; 194 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */ 195 GLuint i; 196 197 /* lower-left */ 198 verts[0][0][0] = x; 199 verts[0][0][1] = y; 200 verts[0][1][0] = 0.0; 201 verts[0][1][1] = 0.0; 202 203 /* lower-right */ 204 verts[1][0][0] = x + width; 205 verts[1][0][1] = y; 206 verts[1][1][0] = 1.0; 207 verts[1][1][1] = 0.0; 208 209 /* upper-right */ 210 verts[2][0][0] = x + width; 211 verts[2][0][1] = y + height; 212 verts[2][1][0] = 1.0; 213 verts[2][1][1] = 1.0; 214 215 /* upper-left */ 216 verts[3][0][0] = x; 217 verts[3][0][1] = y + height; 218 verts[3][1][0] = 0.0; 219 verts[3][1][1] = 1.0; 220 221 /* same for all verts: */ 222 for (i = 0; i < 4; i++) { 223 verts[i][0][2] = z; /*Z*/ 224 verts[i][0][3] = 1.0; /*W*/ 225 verts[i][1][2] = 0.0; /*R*/ 226 verts[i][1][3] = 1.0; /*Q*/ 227 } 228 229 st->pipe->draw_vertices(st->pipe, GL_QUADS, 230 4, (GLfloat *) verts, 2, attribs); 231} 232 233 234static void 235draw_textured_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z, 236 GLsizei width, GLsizei height, GLenum format, GLenum type, 237 const struct gl_pixelstore_attrib *unpack, 238 const GLvoid *pixels) 239{ 240 struct pipe_mipmap_tree *mt; 241 242 /* setup state: just scissor */ 243 { 244 struct pipe_setup_state setup; 245 memset(&setup, 0, sizeof(setup)); 246 if (st->ctx->Scissor.Enabled) 247 setup.scissor = 1; 248 st->pipe->set_setup_state(st->pipe, &setup); 249 } 250 251 /* fragment shader state: color pass-through program */ 252 { 253 static struct st_fragment_program *stfp = NULL; 254 struct pipe_fs_state fs; 255 if (!stfp) { 256 stfp = make_drawpixels_shader(st); 257 } 258 memset(&fs, 0, sizeof(fs)); 259 fs.inputs_read = stfp->Base.Base.InputsRead; 260 fs.tokens = &stfp->tokens[0]; 261 fs.constants = NULL; 262 st->pipe->set_fs_state(st->pipe, &fs); 263 } 264 265 /* mipmap tree state: */ 266 { 267 mt = make_mipmap_tree(st, width, height, format, type, unpack, pixels); 268 st->pipe->set_texture_state(st->pipe, 0, mt); 269 } 270 271 /* draw textured quad */ 272 draw_quad(st, x, y, z, width, height); 273 274 /* restore GL state */ 275 st->pipe->set_setup_state(st->pipe, &st->state.setup); 276 st->pipe->set_fs_state(st->pipe, &st->state.fs); 277 278 free_mipmap_tree(st->pipe, mt); 279} 280 281 282/** 283 * Check if a GL format/type combination is a match to the given pipe format. 284 * XXX probably move this to a re-usable place. 285 */ 286static GLboolean 287compatible_formats(GLenum format, GLenum type, GLuint pipeFormat) 288{ 289 static const GLuint one = 1; 290 GLubyte littleEndian = *((GLubyte *) &one); 291 292 if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 && 293 format == GL_RGBA && 294 type == GL_UNSIGNED_BYTE && 295 !littleEndian) { 296 return GL_TRUE; 297 } 298 else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 && 299 format == GL_ABGR_EXT && 300 type == GL_UNSIGNED_BYTE && 301 littleEndian) { 302 return GL_TRUE; 303 } 304 else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 && 305 format == GL_BGRA && 306 type == GL_UNSIGNED_BYTE && 307 littleEndian) { 308 return GL_TRUE; 309 } 310 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 && 311 format == GL_RGB && 312 type == GL_UNSIGNED_SHORT_5_6_5) { 313 /* endian don't care */ 314 return GL_TRUE; 315 } 316 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 && 317 format == GL_BGR && 318 type == GL_UNSIGNED_SHORT_5_6_5_REV) { 319 /* endian don't care */ 320 return GL_TRUE; 321 } 322 else if (pipeFormat == PIPE_FORMAT_U_S8 && 323 format == GL_STENCIL_INDEX && 324 type == GL_UNSIGNED_BYTE) { 325 return GL_TRUE; 326 } 327 else if (pipeFormat == PIPE_FORMAT_U_Z32 && 328 format == GL_DEPTH_COMPONENT && 329 type == GL_UNSIGNED_INT) { 330 return GL_TRUE; 331 } 332 /* XXX add more cases */ 333 else { 334 return GL_FALSE; 335 } 336} 337 338 339/** 340 * Check if any per-fragment ops are enabled. 341 * XXX probably move this to a re-usable place. 342 */ 343static GLboolean 344any_fragment_ops(const struct st_context *st) 345{ 346 if (st->state.alpha_test.enabled || 347 st->state.blend.blend_enable || 348 st->state.blend.logicop_enable || 349 st->state.depth.enabled) 350 /* XXX more checks */ 351 return GL_TRUE; 352 else 353 return GL_FALSE; 354} 355 356 357/** 358 * Check if any pixel transfer ops are enabled. 359 * XXX probably move this to a re-usable place. 360 */ 361static GLboolean 362any_pixel_transfer_ops(const struct st_context *st) 363{ 364 if (st->ctx->Pixel.RedScale != 1.0 || 365 st->ctx->Pixel.RedBias != 0.0 || 366 st->ctx->Pixel.GreenScale != 1.0 || 367 st->ctx->Pixel.GreenBias != 0.0 || 368 st->ctx->Pixel.BlueScale != 1.0 || 369 st->ctx->Pixel.BlueBias != 0.0 || 370 st->ctx->Pixel.AlphaScale != 1.0 || 371 st->ctx->Pixel.AlphaBias != 0.0 || 372 st->ctx->Pixel.MapColorFlag) 373 /* XXX more checks */ 374 return GL_TRUE; 375 else 376 return GL_FALSE; 377} 378 379 380/** 381 * Draw image with a blit, or other non-textured quad method. 382 */ 383static void 384draw_blit(struct st_context *st, 385 GLsizei width, GLsizei height, 386 GLenum format, GLenum type, const GLvoid *pixels) 387{ 388 389 390} 391 392 393/** 394 * Called via ctx->Driver.DrawPixels() 395 */ 396static void 397st_drawpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 398 GLenum format, GLenum type, 399 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) 400{ 401 struct st_context *st = ctx->st; 402 struct pipe_surface *ps; 403 GLuint bufferFormat; 404 405 if (format == GL_DEPTH_COMPONENT) { 406 ps = st->state.framebuffer.zbuf; 407 } 408 else if (format == GL_STENCIL_INDEX) { 409 ps = st->state.framebuffer.sbuf; 410 } 411 else { 412 ps = st->state.framebuffer.cbufs[0]; 413 } 414 415 bufferFormat = ps->format; 416 417 if (any_fragment_ops(st) || 418 any_pixel_transfer_ops(st) || 419 !compatible_formats(format, type, ps->format)) { 420 /* textured quad */ 421 draw_textured_quad(st, x, y, ctx->Current.RasterPos[2], width, height, 422 format, type, unpack, pixels); 423 } 424 else { 425 /* blit */ 426 draw_blit(st, width, height, format, type, pixels); 427 } 428} 429 430 431void st_init_drawpixels_functions(struct dd_function_table *functions) 432{ 433 functions->DrawPixels = st_drawpixels; 434} 435 436