Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1901 | serge | 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/bufferobj.h" |
||
36 | #include "main/macros.h" |
||
37 | #include "main/pack.h" |
||
38 | #include "main/texformat.h" |
||
39 | #include "main/texstore.h" |
||
40 | #include "program/program.h" |
||
41 | #include "program/prog_print.h" |
||
42 | #include "program/prog_instruction.h" |
||
43 | |||
44 | #include "st_atom.h" |
||
45 | #include "st_atom_constbuf.h" |
||
46 | #include "st_cb_drawpixels.h" |
||
47 | #include "st_cb_readpixels.h" |
||
48 | #include "st_cb_fbo.h" |
||
49 | #include "st_context.h" |
||
50 | #include "st_debug.h" |
||
51 | #include "st_format.h" |
||
52 | #include "st_program.h" |
||
53 | #include "st_texture.h" |
||
54 | |||
55 | #include "pipe/p_context.h" |
||
56 | #include "pipe/p_defines.h" |
||
57 | #include "tgsi/tgsi_ureg.h" |
||
58 | #include "util/u_draw_quad.h" |
||
59 | #include "util/u_format.h" |
||
60 | #include "util/u_inlines.h" |
||
61 | #include "util/u_math.h" |
||
62 | #include "util/u_tile.h" |
||
63 | #include "cso_cache/cso_context.h" |
||
64 | |||
65 | |||
66 | #if FEATURE_drawpix |
||
67 | |||
68 | /** |
||
69 | * Check if the given program is: |
||
70 | * 0: MOVE result.color, fragment.color; |
||
71 | * 1: END; |
||
72 | */ |
||
73 | static GLboolean |
||
74 | is_passthrough_program(const struct gl_fragment_program *prog) |
||
75 | { |
||
76 | if (prog->Base.NumInstructions == 2) { |
||
77 | const struct prog_instruction *inst = prog->Base.Instructions; |
||
78 | if (inst[0].Opcode == OPCODE_MOV && |
||
79 | inst[1].Opcode == OPCODE_END && |
||
80 | inst[0].DstReg.File == PROGRAM_OUTPUT && |
||
81 | inst[0].DstReg.Index == FRAG_RESULT_COLOR && |
||
82 | inst[0].DstReg.WriteMask == WRITEMASK_XYZW && |
||
83 | inst[0].SrcReg[0].File == PROGRAM_INPUT && |
||
84 | inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && |
||
85 | inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { |
||
86 | return GL_TRUE; |
||
87 | } |
||
88 | } |
||
89 | return GL_FALSE; |
||
90 | } |
||
91 | |||
92 | |||
93 | |||
94 | /** |
||
95 | * Make fragment shader for glDraw/CopyPixels. This shader is made |
||
96 | * by combining the pixel transfer shader with the user-defined shader. |
||
97 | * \return pointer to Gallium driver fragment shader |
||
98 | */ |
||
99 | static void * |
||
100 | combined_drawpix_fragment_program(struct gl_context *ctx) |
||
101 | { |
||
102 | struct st_context *st = st_context(ctx); |
||
103 | struct st_fragment_program *stfp; |
||
104 | |||
105 | if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn |
||
106 | && st->fp->serialNo == st->pixel_xfer.user_prog_sn) { |
||
107 | /* the pixel tranfer program has not changed and the user-defined |
||
108 | * program has not changed, so re-use the combined program. |
||
109 | */ |
||
110 | stfp = st->pixel_xfer.combined_prog; |
||
111 | } |
||
112 | else { |
||
113 | /* Concatenate the pixel transfer program with the current user- |
||
114 | * defined program. |
||
115 | */ |
||
116 | if (is_passthrough_program(&st->fp->Base)) { |
||
117 | stfp = (struct st_fragment_program *) |
||
118 | _mesa_clone_fragment_program(ctx, &st->pixel_xfer.program->Base); |
||
119 | } |
||
120 | else { |
||
121 | #if 0 |
||
122 | printf("Base program:\n"); |
||
123 | _mesa_print_program(&st->fp->Base.Base); |
||
124 | printf("DrawPix program:\n"); |
||
125 | _mesa_print_program(&st->pixel_xfer.program->Base.Base); |
||
126 | #endif |
||
127 | stfp = (struct st_fragment_program *) |
||
128 | _mesa_combine_programs(ctx, |
||
129 | &st->pixel_xfer.program->Base.Base, |
||
130 | &st->fp->Base.Base); |
||
131 | } |
||
132 | |||
133 | #if 0 |
||
134 | { |
||
135 | struct gl_program *p = &stfp->Base.Base; |
||
136 | printf("Combined DrawPixels program:\n"); |
||
137 | _mesa_print_program(p); |
||
138 | printf("InputsRead: 0x%x\n", p->InputsRead); |
||
139 | printf("OutputsWritten: 0x%x\n", p->OutputsWritten); |
||
140 | _mesa_print_parameter_list(p->Parameters); |
||
141 | } |
||
142 | #endif |
||
143 | |||
144 | /* translate to TGSI tokens */ |
||
145 | st_translate_fragment_program(st, stfp); |
||
146 | |||
147 | /* save new program, update serial numbers */ |
||
148 | st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo; |
||
149 | st->pixel_xfer.user_prog_sn = st->fp->serialNo; |
||
150 | st->pixel_xfer.combined_prog_sn = stfp->serialNo; |
||
151 | /* can't reference new program directly, already have a reference on it */ |
||
152 | st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); |
||
153 | st->pixel_xfer.combined_prog = stfp; |
||
154 | } |
||
155 | |||
156 | /* Ideally we'd have updated the pipe constants during the normal |
||
157 | * st/atom mechanism. But we can't since this is specific to glDrawPixels. |
||
158 | */ |
||
159 | st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); |
||
160 | |||
161 | return stfp->driver_shader; |
||
162 | } |
||
163 | |||
164 | |||
165 | /** |
||
166 | * Create fragment shader that does a TEX() instruction to get a Z and/or |
||
167 | * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. |
||
168 | * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). |
||
169 | * Pass fragment color through as-is. |
||
170 | * \return pointer to the Gallium driver fragment shader |
||
171 | */ |
||
172 | static void * |
||
173 | make_fragment_shader_z_stencil(struct st_context *st, GLboolean write_depth, |
||
174 | GLboolean write_stencil) |
||
175 | { |
||
176 | struct gl_context *ctx = st->ctx; |
||
177 | struct gl_program *p; |
||
178 | struct st_fragment_program *stp; |
||
179 | GLuint ic = 0; |
||
180 | const GLuint shaderIndex = write_depth * 2 + write_stencil; |
||
181 | |||
182 | assert(shaderIndex < Elements(st->drawpix.shaders)); |
||
183 | |||
184 | if (st->drawpix.shaders[shaderIndex]) { |
||
185 | /* already have the proper shader */ |
||
186 | return st->drawpix.shaders[shaderIndex]->driver_shader; |
||
187 | } |
||
188 | |||
189 | /* |
||
190 | * Create shader now |
||
191 | */ |
||
192 | p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); |
||
193 | if (!p) |
||
194 | return NULL; |
||
195 | |||
196 | p->NumInstructions = write_depth ? 2 : 1; |
||
197 | p->NumInstructions += write_stencil ? 1 : 0; |
||
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 | if (write_depth) { |
||
207 | /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ |
||
208 | p->Instructions[ic].Opcode = OPCODE_TEX; |
||
209 | p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; |
||
210 | p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; |
||
211 | p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; |
||
212 | p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; |
||
213 | p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; |
||
214 | p->Instructions[ic].TexSrcUnit = 0; |
||
215 | p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; |
||
216 | ic++; |
||
217 | } |
||
218 | |||
219 | if (write_stencil) { |
||
220 | /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ |
||
221 | p->Instructions[ic].Opcode = OPCODE_TEX; |
||
222 | p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; |
||
223 | p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; |
||
224 | p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; |
||
225 | p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; |
||
226 | p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; |
||
227 | p->Instructions[ic].TexSrcUnit = 1; |
||
228 | p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; |
||
229 | ic++; |
||
230 | } |
||
231 | |||
232 | /* END; */ |
||
233 | p->Instructions[ic++].Opcode = OPCODE_END; |
||
234 | |||
235 | assert(ic == p->NumInstructions); |
||
236 | |||
237 | p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; |
||
238 | p->OutputsWritten = 0; |
||
239 | if (write_depth) |
||
240 | p->OutputsWritten |= (1 << FRAG_RESULT_DEPTH); |
||
241 | if (write_stencil) |
||
242 | p->OutputsWritten |= (1 << FRAG_RESULT_STENCIL); |
||
243 | |||
244 | p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ |
||
245 | if (write_stencil) |
||
246 | p->SamplersUsed |= 1 << 1; |
||
247 | |||
248 | stp = st_fragment_program((struct gl_fragment_program *) p); |
||
249 | |||
250 | /* save the new shader */ |
||
251 | st->drawpix.shaders[shaderIndex] = stp; |
||
252 | |||
253 | st_translate_fragment_program(st, stp); |
||
254 | |||
255 | return stp->driver_shader; |
||
256 | } |
||
257 | |||
258 | |||
259 | |||
260 | /** |
||
261 | * Create a simple vertex shader that just passes through the |
||
262 | * vertex position and texcoord (and optionally, color). |
||
263 | */ |
||
264 | static void * |
||
265 | make_passthrough_vertex_shader(struct st_context *st, |
||
266 | GLboolean passColor) |
||
267 | { |
||
268 | if (!st->drawpix.vert_shaders[passColor]) { |
||
269 | struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); |
||
270 | |||
271 | if (ureg == NULL) |
||
272 | return NULL; |
||
273 | |||
274 | /* MOV result.pos, vertex.pos; */ |
||
275 | ureg_MOV(ureg, |
||
276 | ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), |
||
277 | ureg_DECL_vs_input( ureg, 0 )); |
||
278 | |||
279 | /* MOV result.texcoord0, vertex.attr[1]; */ |
||
280 | ureg_MOV(ureg, |
||
281 | ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), |
||
282 | ureg_DECL_vs_input( ureg, 1 )); |
||
283 | |||
284 | if (passColor) { |
||
285 | /* MOV result.color0, vertex.attr[2]; */ |
||
286 | ureg_MOV(ureg, |
||
287 | ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), |
||
288 | ureg_DECL_vs_input( ureg, 2 )); |
||
289 | } |
||
290 | |||
291 | ureg_END( ureg ); |
||
292 | |||
293 | st->drawpix.vert_shaders[passColor] = |
||
294 | ureg_create_shader_and_destroy( ureg, st->pipe ); |
||
295 | } |
||
296 | |||
297 | return st->drawpix.vert_shaders[passColor]; |
||
298 | } |
||
299 | |||
300 | |||
301 | /** |
||
302 | * Return a texture base format for drawing/copying an image |
||
303 | * of the given format. |
||
304 | */ |
||
305 | static GLenum |
||
306 | base_format(GLenum format) |
||
307 | { |
||
308 | switch (format) { |
||
309 | case GL_DEPTH_COMPONENT: |
||
310 | return GL_DEPTH_COMPONENT; |
||
311 | case GL_DEPTH_STENCIL: |
||
312 | return GL_DEPTH_STENCIL; |
||
313 | case GL_STENCIL_INDEX: |
||
314 | return GL_STENCIL_INDEX; |
||
315 | default: |
||
316 | return GL_RGBA; |
||
317 | } |
||
318 | } |
||
319 | |||
320 | |||
321 | /** |
||
322 | * Return a texture internalFormat for drawing/copying an image |
||
323 | * of the given format and type. |
||
324 | */ |
||
325 | static GLenum |
||
326 | internal_format(GLenum format, GLenum type) |
||
327 | { |
||
328 | switch (format) { |
||
329 | case GL_DEPTH_COMPONENT: |
||
330 | return GL_DEPTH_COMPONENT; |
||
331 | case GL_DEPTH_STENCIL: |
||
332 | return GL_DEPTH_STENCIL; |
||
333 | case GL_STENCIL_INDEX: |
||
334 | return GL_STENCIL_INDEX; |
||
335 | default: |
||
336 | if (_mesa_is_integer_format(format)) { |
||
337 | switch (type) { |
||
338 | case GL_BYTE: |
||
339 | return GL_RGBA8I; |
||
340 | case GL_UNSIGNED_BYTE: |
||
341 | return GL_RGBA8UI; |
||
342 | case GL_SHORT: |
||
343 | return GL_RGBA16I; |
||
344 | case GL_UNSIGNED_SHORT: |
||
345 | return GL_RGBA16UI; |
||
346 | case GL_INT: |
||
347 | return GL_RGBA32I; |
||
348 | case GL_UNSIGNED_INT: |
||
349 | return GL_RGBA32UI; |
||
350 | default: |
||
351 | assert(0 && "Unexpected type in internal_format()"); |
||
352 | return GL_RGBA_INTEGER; |
||
353 | } |
||
354 | } |
||
355 | else { |
||
356 | return GL_RGBA; |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | |||
361 | |||
362 | /** |
||
363 | * Create a temporary texture to hold an image of the given size. |
||
364 | * If width, height are not POT and the driver only handles POT textures, |
||
365 | * allocate the next larger size of texture that is POT. |
||
366 | */ |
||
367 | static struct pipe_resource * |
||
368 | alloc_texture(struct st_context *st, GLsizei width, GLsizei height, |
||
369 | enum pipe_format texFormat) |
||
370 | { |
||
371 | struct pipe_resource *pt; |
||
372 | |||
373 | pt = st_texture_create(st, st->internal_target, texFormat, 0, |
||
374 | width, height, 1, PIPE_BIND_SAMPLER_VIEW); |
||
375 | |||
376 | return pt; |
||
377 | } |
||
378 | |||
379 | |||
380 | /** |
||
381 | * Make texture containing an image for glDrawPixels image. |
||
382 | * If 'pixels' is NULL, leave the texture image data undefined. |
||
383 | */ |
||
384 | static struct pipe_resource * |
||
385 | make_texture(struct st_context *st, |
||
386 | GLsizei width, GLsizei height, GLenum format, GLenum type, |
||
387 | const struct gl_pixelstore_attrib *unpack, |
||
388 | const GLvoid *pixels) |
||
389 | { |
||
390 | struct gl_context *ctx = st->ctx; |
||
391 | struct pipe_context *pipe = st->pipe; |
||
392 | gl_format mformat; |
||
393 | struct pipe_resource *pt; |
||
394 | enum pipe_format pipeFormat; |
||
395 | GLuint cpp; |
||
396 | GLenum baseFormat, intFormat; |
||
397 | |||
398 | baseFormat = base_format(format); |
||
399 | intFormat = internal_format(format, type); |
||
400 | |||
401 | mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, |
||
402 | format, type, GL_FALSE); |
||
403 | assert(mformat); |
||
404 | |||
405 | pipeFormat = st_mesa_format_to_pipe_format(mformat); |
||
406 | assert(pipeFormat); |
||
407 | cpp = util_format_get_blocksize(pipeFormat); |
||
408 | |||
409 | pixels = _mesa_map_pbo_source(ctx, unpack, pixels); |
||
410 | if (!pixels) |
||
411 | return NULL; |
||
412 | |||
413 | /* alloc temporary texture */ |
||
414 | pt = alloc_texture(st, width, height, pipeFormat); |
||
415 | if (!pt) { |
||
416 | _mesa_unmap_pbo_source(ctx, unpack); |
||
417 | return NULL; |
||
418 | } |
||
419 | |||
420 | { |
||
421 | struct pipe_transfer *transfer; |
||
422 | static const GLuint dstImageOffsets = 0; |
||
423 | GLboolean success; |
||
424 | GLubyte *dest; |
||
425 | const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; |
||
426 | |||
427 | /* we'll do pixel transfer in a fragment shader */ |
||
428 | ctx->_ImageTransferState = 0x0; |
||
429 | |||
430 | transfer = pipe_get_transfer(st->pipe, pt, 0, 0, |
||
431 | PIPE_TRANSFER_WRITE, 0, 0, |
||
432 | width, height); |
||
433 | |||
434 | /* map texture transfer */ |
||
435 | dest = pipe_transfer_map(pipe, transfer); |
||
436 | |||
437 | |||
438 | /* Put image into texture transfer. |
||
439 | * Note that the image is actually going to be upside down in |
||
440 | * the texture. We deal with that with texcoords. |
||
441 | */ |
||
442 | success = _mesa_texstore(ctx, 2, /* dims */ |
||
443 | baseFormat, /* baseInternalFormat */ |
||
444 | mformat, /* gl_format */ |
||
445 | dest, /* dest */ |
||
446 | 0, 0, 0, /* dstX/Y/Zoffset */ |
||
447 | transfer->stride, /* dstRowStride, bytes */ |
||
448 | &dstImageOffsets, /* dstImageOffsets */ |
||
449 | width, height, 1, /* size */ |
||
450 | format, type, /* src format/type */ |
||
451 | pixels, /* data source */ |
||
452 | unpack); |
||
453 | |||
454 | /* unmap */ |
||
455 | pipe_transfer_unmap(pipe, transfer); |
||
456 | pipe->transfer_destroy(pipe, transfer); |
||
457 | |||
458 | assert(success); |
||
459 | |||
460 | /* restore */ |
||
461 | ctx->_ImageTransferState = imageTransferStateSave; |
||
462 | } |
||
463 | |||
464 | _mesa_unmap_pbo_source(ctx, unpack); |
||
465 | |||
466 | return pt; |
||
467 | } |
||
468 | |||
469 | |||
470 | /** |
||
471 | * Draw quad with texcoords and optional color. |
||
472 | * Coords are gallium window coords with y=0=top. |
||
473 | * \param color may be null |
||
474 | * \param invertTex if true, flip texcoords vertically |
||
475 | */ |
||
476 | static void |
||
477 | draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, |
||
478 | GLfloat x1, GLfloat y1, const GLfloat *color, |
||
479 | GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) |
||
480 | { |
||
481 | struct st_context *st = st_context(ctx); |
||
482 | struct pipe_context *pipe = st->pipe; |
||
483 | GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ |
||
484 | |||
485 | /* setup vertex data */ |
||
486 | { |
||
487 | const struct gl_framebuffer *fb = st->ctx->DrawBuffer; |
||
488 | const GLfloat fb_width = (GLfloat) fb->Width; |
||
489 | const GLfloat fb_height = (GLfloat) fb->Height; |
||
490 | const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; |
||
491 | const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; |
||
492 | const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; |
||
493 | const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; |
||
494 | const GLfloat sLeft = 0.0f, sRight = maxXcoord; |
||
495 | const GLfloat tTop = invertTex ? maxYcoord : 0.0f; |
||
496 | const GLfloat tBot = invertTex ? 0.0f : maxYcoord; |
||
497 | GLuint i; |
||
498 | |||
499 | /* upper-left */ |
||
500 | verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ |
||
501 | verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ |
||
502 | |||
503 | /* upper-right */ |
||
504 | verts[1][0][0] = clip_x1; |
||
505 | verts[1][0][1] = clip_y0; |
||
506 | |||
507 | /* lower-right */ |
||
508 | verts[2][0][0] = clip_x1; |
||
509 | verts[2][0][1] = clip_y1; |
||
510 | |||
511 | /* lower-left */ |
||
512 | verts[3][0][0] = clip_x0; |
||
513 | verts[3][0][1] = clip_y1; |
||
514 | |||
515 | verts[0][1][0] = sLeft; /* v[0].attr[1].S */ |
||
516 | verts[0][1][1] = tTop; /* v[0].attr[1].T */ |
||
517 | verts[1][1][0] = sRight; |
||
518 | verts[1][1][1] = tTop; |
||
519 | verts[2][1][0] = sRight; |
||
520 | verts[2][1][1] = tBot; |
||
521 | verts[3][1][0] = sLeft; |
||
522 | verts[3][1][1] = tBot; |
||
523 | |||
524 | /* same for all verts: */ |
||
525 | if (color) { |
||
526 | for (i = 0; i < 4; i++) { |
||
527 | verts[i][0][2] = z; /* v[i].attr[0].z */ |
||
528 | verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ |
||
529 | verts[i][2][0] = color[0]; /* v[i].attr[2].r */ |
||
530 | verts[i][2][1] = color[1]; /* v[i].attr[2].g */ |
||
531 | verts[i][2][2] = color[2]; /* v[i].attr[2].b */ |
||
532 | verts[i][2][3] = color[3]; /* v[i].attr[2].a */ |
||
533 | verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ |
||
534 | verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ |
||
535 | } |
||
536 | } |
||
537 | else { |
||
538 | for (i = 0; i < 4; i++) { |
||
539 | verts[i][0][2] = z; /*Z*/ |
||
540 | verts[i][0][3] = 1.0f; /*W*/ |
||
541 | verts[i][1][2] = 0.0f; /*R*/ |
||
542 | verts[i][1][3] = 1.0f; /*Q*/ |
||
543 | } |
||
544 | } |
||
545 | } |
||
546 | |||
547 | { |
||
548 | struct pipe_resource *buf; |
||
549 | |||
550 | /* allocate/load buffer object with vertex data */ |
||
551 | buf = pipe_buffer_create(pipe->screen, |
||
552 | PIPE_BIND_VERTEX_BUFFER, |
||
553 | sizeof(verts)); |
||
554 | pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); |
||
555 | |||
556 | util_draw_vertex_buffer(pipe, buf, 0, |
||
557 | PIPE_PRIM_QUADS, |
||
558 | 4, /* verts */ |
||
559 | 3); /* attribs/vert */ |
||
560 | pipe_resource_reference(&buf, NULL); |
||
561 | } |
||
562 | } |
||
563 | |||
564 | |||
565 | |||
566 | static void |
||
567 | draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, |
||
568 | GLsizei width, GLsizei height, |
||
569 | GLfloat zoomX, GLfloat zoomY, |
||
570 | struct pipe_sampler_view **sv, |
||
571 | int num_sampler_view, |
||
572 | void *driver_vp, |
||
573 | void *driver_fp, |
||
574 | const GLfloat *color, |
||
575 | GLboolean invertTex, |
||
576 | GLboolean write_depth, GLboolean write_stencil) |
||
577 | { |
||
578 | struct st_context *st = st_context(ctx); |
||
579 | struct pipe_context *pipe = st->pipe; |
||
580 | struct cso_context *cso = st->cso_context; |
||
581 | GLfloat x0, y0, x1, y1; |
||
582 | GLsizei maxSize; |
||
583 | boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; |
||
584 | |||
585 | /* limit checks */ |
||
586 | /* XXX if DrawPixels image is larger than max texture size, break |
||
587 | * it up into chunks. |
||
588 | */ |
||
589 | maxSize = 1 << (pipe->screen->get_param(pipe->screen, |
||
590 | PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); |
||
591 | assert(width <= maxSize); |
||
592 | assert(height <= maxSize); |
||
593 | |||
594 | cso_save_rasterizer(cso); |
||
595 | cso_save_viewport(cso); |
||
596 | cso_save_samplers(cso); |
||
597 | cso_save_fragment_sampler_views(cso); |
||
598 | cso_save_fragment_shader(cso); |
||
599 | cso_save_vertex_shader(cso); |
||
600 | cso_save_vertex_elements(cso); |
||
601 | if (write_stencil) { |
||
602 | cso_save_depth_stencil_alpha(cso); |
||
603 | cso_save_blend(cso); |
||
604 | } |
||
605 | |||
606 | /* rasterizer state: just scissor */ |
||
607 | { |
||
608 | struct pipe_rasterizer_state rasterizer; |
||
609 | memset(&rasterizer, 0, sizeof(rasterizer)); |
||
610 | rasterizer.gl_rasterization_rules = 1; |
||
611 | rasterizer.scissor = ctx->Scissor.Enabled; |
||
612 | cso_set_rasterizer(cso, &rasterizer); |
||
613 | } |
||
614 | |||
615 | if (write_stencil) { |
||
616 | /* Stencil writing bypasses the normal fragment pipeline to |
||
617 | * disable color writing and set stencil test to always pass. |
||
618 | */ |
||
619 | struct pipe_depth_stencil_alpha_state dsa; |
||
620 | struct pipe_blend_state blend; |
||
621 | |||
622 | /* depth/stencil */ |
||
623 | memset(&dsa, 0, sizeof(dsa)); |
||
624 | dsa.stencil[0].enabled = 1; |
||
625 | dsa.stencil[0].func = PIPE_FUNC_ALWAYS; |
||
626 | dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; |
||
627 | dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; |
||
628 | if (write_depth) { |
||
629 | /* writing depth+stencil: depth test always passes */ |
||
630 | dsa.depth.enabled = 1; |
||
631 | dsa.depth.writemask = ctx->Depth.Mask; |
||
632 | dsa.depth.func = PIPE_FUNC_ALWAYS; |
||
633 | } |
||
634 | cso_set_depth_stencil_alpha(cso, &dsa); |
||
635 | |||
636 | /* blend (colormask) */ |
||
637 | memset(&blend, 0, sizeof(blend)); |
||
638 | cso_set_blend(cso, &blend); |
||
639 | } |
||
640 | |||
641 | /* fragment shader state: TEX lookup program */ |
||
642 | cso_set_fragment_shader_handle(cso, driver_fp); |
||
643 | |||
644 | /* vertex shader state: position + texcoord pass-through */ |
||
645 | cso_set_vertex_shader_handle(cso, driver_vp); |
||
646 | |||
647 | |||
648 | /* texture sampling state: */ |
||
649 | { |
||
650 | struct pipe_sampler_state sampler; |
||
651 | memset(&sampler, 0, sizeof(sampler)); |
||
652 | sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; |
||
653 | sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; |
||
654 | sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; |
||
655 | sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
656 | sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; |
||
657 | sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
658 | sampler.normalized_coords = normalized; |
||
659 | |||
660 | cso_single_sampler(cso, 0, &sampler); |
||
661 | if (num_sampler_view > 1) { |
||
662 | cso_single_sampler(cso, 1, &sampler); |
||
663 | } |
||
664 | cso_single_sampler_done(cso); |
||
665 | } |
||
666 | |||
667 | /* viewport state: viewport matching window dims */ |
||
668 | { |
||
669 | const float w = (float) ctx->DrawBuffer->Width; |
||
670 | const float h = (float) ctx->DrawBuffer->Height; |
||
671 | struct pipe_viewport_state vp; |
||
672 | vp.scale[0] = 0.5f * w; |
||
673 | vp.scale[1] = -0.5f * h; |
||
674 | vp.scale[2] = 0.5f; |
||
675 | vp.scale[3] = 1.0f; |
||
676 | vp.translate[0] = 0.5f * w; |
||
677 | vp.translate[1] = 0.5f * h; |
||
678 | vp.translate[2] = 0.5f; |
||
679 | vp.translate[3] = 0.0f; |
||
680 | cso_set_viewport(cso, &vp); |
||
681 | } |
||
682 | |||
683 | cso_set_vertex_elements(cso, 3, st->velems_util_draw); |
||
684 | |||
685 | /* texture state: */ |
||
686 | cso_set_fragment_sampler_views(cso, num_sampler_view, sv); |
||
687 | |||
688 | /* Compute Gallium window coords (y=0=top) with pixel zoom. |
||
689 | * Recall that these coords are transformed by the current |
||
690 | * vertex shader and viewport transformation. |
||
691 | */ |
||
692 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { |
||
693 | y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); |
||
694 | invertTex = !invertTex; |
||
695 | } |
||
696 | |||
697 | x0 = (GLfloat) x; |
||
698 | x1 = x + width * ctx->Pixel.ZoomX; |
||
699 | y0 = (GLfloat) y; |
||
700 | y1 = y + height * ctx->Pixel.ZoomY; |
||
701 | |||
702 | /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ |
||
703 | z = z * 2.0 - 1.0; |
||
704 | |||
705 | draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, |
||
706 | normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, |
||
707 | normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); |
||
708 | |||
709 | /* restore state */ |
||
710 | cso_restore_rasterizer(cso); |
||
711 | cso_restore_viewport(cso); |
||
712 | cso_restore_samplers(cso); |
||
713 | cso_restore_fragment_sampler_views(cso); |
||
714 | cso_restore_fragment_shader(cso); |
||
715 | cso_restore_vertex_shader(cso); |
||
716 | cso_restore_vertex_elements(cso); |
||
717 | if (write_stencil) { |
||
718 | cso_restore_depth_stencil_alpha(cso); |
||
719 | cso_restore_blend(cso); |
||
720 | } |
||
721 | } |
||
722 | |||
723 | |||
724 | /** |
||
725 | * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we |
||
726 | * can't use a fragment shader to write stencil values. |
||
727 | */ |
||
728 | static void |
||
729 | draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, |
||
730 | GLsizei width, GLsizei height, GLenum format, GLenum type, |
||
731 | const struct gl_pixelstore_attrib *unpack, |
||
732 | const GLvoid *pixels) |
||
733 | { |
||
734 | struct st_context *st = st_context(ctx); |
||
735 | struct pipe_context *pipe = st->pipe; |
||
736 | struct st_renderbuffer *strb; |
||
737 | enum pipe_transfer_usage usage; |
||
738 | struct pipe_transfer *pt; |
||
739 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; |
||
740 | GLint skipPixels; |
||
741 | ubyte *stmap; |
||
742 | struct gl_pixelstore_attrib clippedUnpack = *unpack; |
||
743 | |||
744 | if (!zoom) { |
||
745 | if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, |
||
746 | &clippedUnpack)) { |
||
747 | /* totally clipped */ |
||
748 | return; |
||
749 | } |
||
750 | } |
||
751 | |||
752 | strb = st_renderbuffer(ctx->DrawBuffer-> |
||
753 | Attachment[BUFFER_STENCIL].Renderbuffer); |
||
754 | |||
755 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
756 | y = ctx->DrawBuffer->Height - y - height; |
||
757 | } |
||
758 | |||
759 | if(format != GL_DEPTH_STENCIL && |
||
760 | util_format_get_component_bits(strb->format, |
||
761 | UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) |
||
762 | usage = PIPE_TRANSFER_READ_WRITE; |
||
763 | else |
||
764 | usage = PIPE_TRANSFER_WRITE; |
||
765 | |||
766 | pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, |
||
767 | usage, x, y, |
||
768 | width, height); |
||
769 | |||
770 | stmap = pipe_transfer_map(pipe, pt); |
||
771 | |||
772 | pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); |
||
773 | assert(pixels); |
||
774 | |||
775 | /* if width > MAX_WIDTH, have to process image in chunks */ |
||
776 | skipPixels = 0; |
||
777 | while (skipPixels < width) { |
||
778 | const GLint spanX = skipPixels; |
||
779 | const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); |
||
780 | GLint row; |
||
781 | for (row = 0; row < height; row++) { |
||
782 | GLubyte sValues[MAX_WIDTH]; |
||
783 | GLuint zValues[MAX_WIDTH]; |
||
784 | GLenum destType = GL_UNSIGNED_BYTE; |
||
785 | const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, |
||
786 | width, height, |
||
787 | format, type, |
||
788 | row, skipPixels); |
||
789 | _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, |
||
790 | type, source, &clippedUnpack, |
||
791 | ctx->_ImageTransferState); |
||
792 | |||
793 | if (format == GL_DEPTH_STENCIL) { |
||
794 | _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, |
||
795 | (1 << 24) - 1, type, source, |
||
796 | &clippedUnpack); |
||
797 | } |
||
798 | |||
799 | if (zoom) { |
||
800 | _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " |
||
801 | "zoom not complete"); |
||
802 | } |
||
803 | |||
804 | { |
||
805 | GLint spanY; |
||
806 | |||
807 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
808 | spanY = height - row - 1; |
||
809 | } |
||
810 | else { |
||
811 | spanY = row; |
||
812 | } |
||
813 | |||
814 | /* now pack the stencil (and Z) values in the dest format */ |
||
815 | switch (pt->resource->format) { |
||
816 | case PIPE_FORMAT_S8_USCALED: |
||
817 | { |
||
818 | ubyte *dest = stmap + spanY * pt->stride + spanX; |
||
819 | assert(usage == PIPE_TRANSFER_WRITE); |
||
820 | memcpy(dest, sValues, spanWidth); |
||
821 | } |
||
822 | break; |
||
823 | case PIPE_FORMAT_Z24_UNORM_S8_USCALED: |
||
824 | if (format == GL_DEPTH_STENCIL) { |
||
825 | uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); |
||
826 | GLint k; |
||
827 | assert(usage == PIPE_TRANSFER_WRITE); |
||
828 | for (k = 0; k < spanWidth; k++) { |
||
829 | dest[k] = zValues[k] | (sValues[k] << 24); |
||
830 | } |
||
831 | } |
||
832 | else { |
||
833 | uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); |
||
834 | GLint k; |
||
835 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
836 | for (k = 0; k < spanWidth; k++) { |
||
837 | dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); |
||
838 | } |
||
839 | } |
||
840 | break; |
||
841 | case PIPE_FORMAT_S8_USCALED_Z24_UNORM: |
||
842 | if (format == GL_DEPTH_STENCIL) { |
||
843 | uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); |
||
844 | GLint k; |
||
845 | assert(usage == PIPE_TRANSFER_WRITE); |
||
846 | for (k = 0; k < spanWidth; k++) { |
||
847 | dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); |
||
848 | } |
||
849 | } |
||
850 | else { |
||
851 | uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); |
||
852 | GLint k; |
||
853 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
854 | for (k = 0; k < spanWidth; k++) { |
||
855 | dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); |
||
856 | } |
||
857 | } |
||
858 | break; |
||
859 | default: |
||
860 | assert(0); |
||
861 | } |
||
862 | } |
||
863 | } |
||
864 | skipPixels += spanWidth; |
||
865 | } |
||
866 | |||
867 | _mesa_unmap_pbo_source(ctx, &clippedUnpack); |
||
868 | |||
869 | /* unmap the stencil buffer */ |
||
870 | pipe_transfer_unmap(pipe, pt); |
||
871 | pipe->transfer_destroy(pipe, pt); |
||
872 | } |
||
873 | |||
874 | |||
875 | /** |
||
876 | * Called via ctx->Driver.DrawPixels() |
||
877 | */ |
||
878 | static void |
||
879 | st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, |
||
880 | GLsizei width, GLsizei height, |
||
881 | GLenum format, GLenum type, |
||
882 | const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) |
||
883 | { |
||
884 | void *driver_vp, *driver_fp; |
||
885 | struct st_context *st = st_context(ctx); |
||
886 | const GLfloat *color; |
||
887 | struct pipe_context *pipe = st->pipe; |
||
888 | GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; |
||
889 | struct pipe_sampler_view *sv[2]; |
||
890 | int num_sampler_view = 1; |
||
891 | enum pipe_format stencil_format = PIPE_FORMAT_NONE; |
||
892 | |||
893 | if (format == GL_DEPTH_STENCIL) |
||
894 | write_stencil = write_depth = GL_TRUE; |
||
895 | else if (format == GL_STENCIL_INDEX) |
||
896 | write_stencil = GL_TRUE; |
||
897 | else if (format == GL_DEPTH_COMPONENT) |
||
898 | write_depth = GL_TRUE; |
||
899 | |||
900 | if (write_stencil) { |
||
901 | enum pipe_format tex_format; |
||
902 | /* can we write to stencil if not fallback */ |
||
903 | if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) |
||
904 | goto stencil_fallback; |
||
905 | |||
906 | tex_format = st_choose_format(st->pipe->screen, base_format(format), |
||
907 | PIPE_TEXTURE_2D, |
||
908 | 0, PIPE_BIND_SAMPLER_VIEW); |
||
909 | if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) |
||
910 | stencil_format = PIPE_FORMAT_X24S8_USCALED; |
||
911 | else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) |
||
912 | stencil_format = PIPE_FORMAT_S8X24_USCALED; |
||
913 | else |
||
914 | stencil_format = PIPE_FORMAT_S8_USCALED; |
||
915 | if (stencil_format == PIPE_FORMAT_NONE) |
||
916 | goto stencil_fallback; |
||
917 | } |
||
918 | |||
919 | /* Mesa state should be up to date by now */ |
||
920 | assert(ctx->NewState == 0x0); |
||
921 | |||
922 | st_validate_state(st); |
||
923 | |||
924 | if (write_depth || write_stencil) { |
||
925 | driver_fp = make_fragment_shader_z_stencil(st, write_depth, write_stencil); |
||
926 | driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); |
||
927 | color = ctx->Current.RasterColor; |
||
928 | } |
||
929 | else { |
||
930 | driver_fp = combined_drawpix_fragment_program(ctx); |
||
931 | driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); |
||
932 | color = NULL; |
||
933 | if (st->pixel_xfer.pixelmap_enabled) { |
||
934 | sv[1] = st->pixel_xfer.pixelmap_sampler_view; |
||
935 | num_sampler_view++; |
||
936 | } |
||
937 | } |
||
938 | |||
939 | /* draw with textured quad */ |
||
940 | { |
||
941 | struct pipe_resource *pt |
||
942 | = make_texture(st, width, height, format, type, unpack, pixels); |
||
943 | if (pt) { |
||
944 | sv[0] = st_create_texture_sampler_view(st->pipe, pt); |
||
945 | |||
946 | if (sv[0]) { |
||
947 | if (write_stencil) { |
||
948 | sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, |
||
949 | stencil_format); |
||
950 | num_sampler_view++; |
||
951 | } |
||
952 | |||
953 | draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], |
||
954 | width, height, |
||
955 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, |
||
956 | sv, |
||
957 | num_sampler_view, |
||
958 | driver_vp, |
||
959 | driver_fp, |
||
960 | color, GL_FALSE, write_depth, write_stencil); |
||
961 | pipe_sampler_view_reference(&sv[0], NULL); |
||
962 | if (num_sampler_view > 1) |
||
963 | pipe_sampler_view_reference(&sv[1], NULL); |
||
964 | } |
||
965 | pipe_resource_reference(&pt, NULL); |
||
966 | } |
||
967 | } |
||
968 | return; |
||
969 | |||
970 | stencil_fallback: |
||
971 | draw_stencil_pixels(ctx, x, y, width, height, format, type, |
||
972 | unpack, pixels); |
||
973 | } |
||
974 | |||
975 | |||
976 | |||
977 | /** |
||
978 | * Software fallback for glCopyPixels(GL_STENCIL). |
||
979 | */ |
||
980 | static void |
||
981 | copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, |
||
982 | GLsizei width, GLsizei height, |
||
983 | GLint dstx, GLint dsty) |
||
984 | { |
||
985 | struct st_renderbuffer *rbDraw; |
||
986 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
987 | enum pipe_transfer_usage usage; |
||
988 | struct pipe_transfer *ptDraw; |
||
989 | ubyte *drawMap; |
||
990 | ubyte *buffer; |
||
991 | int i; |
||
992 | |||
993 | buffer = malloc(width * height * sizeof(ubyte)); |
||
994 | if (!buffer) { |
||
995 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); |
||
996 | return; |
||
997 | } |
||
998 | |||
999 | /* Get the dest renderbuffer. If there's a wrapper, use the |
||
1000 | * underlying renderbuffer. |
||
1001 | */ |
||
1002 | rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); |
||
1003 | if (rbDraw->Base.Wrapped) |
||
1004 | rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); |
||
1005 | |||
1006 | /* this will do stencil pixel transfer ops */ |
||
1007 | st_read_stencil_pixels(ctx, srcx, srcy, width, height, |
||
1008 | GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, |
||
1009 | &ctx->DefaultPacking, buffer); |
||
1010 | |||
1011 | if (0) { |
||
1012 | /* debug code: dump stencil values */ |
||
1013 | GLint row, col; |
||
1014 | for (row = 0; row < height; row++) { |
||
1015 | printf("%3d: ", row); |
||
1016 | for (col = 0; col < width; col++) { |
||
1017 | printf("%02x ", buffer[col + row * width]); |
||
1018 | } |
||
1019 | printf("\n"); |
||
1020 | } |
||
1021 | } |
||
1022 | |||
1023 | if (util_format_get_component_bits(rbDraw->format, |
||
1024 | UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) |
||
1025 | usage = PIPE_TRANSFER_READ_WRITE; |
||
1026 | else |
||
1027 | usage = PIPE_TRANSFER_WRITE; |
||
1028 | |||
1029 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
1030 | dsty = rbDraw->Base.Height - dsty - height; |
||
1031 | } |
||
1032 | |||
1033 | ptDraw = pipe_get_transfer(st_context(ctx)->pipe, |
||
1034 | rbDraw->texture, 0, 0, |
||
1035 | usage, dstx, dsty, |
||
1036 | width, height); |
||
1037 | |||
1038 | assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); |
||
1039 | assert(util_format_get_blockheight(ptDraw->resource->format) == 1); |
||
1040 | |||
1041 | /* map the stencil buffer */ |
||
1042 | drawMap = pipe_transfer_map(pipe, ptDraw); |
||
1043 | |||
1044 | /* draw */ |
||
1045 | /* XXX PixelZoom not handled yet */ |
||
1046 | for (i = 0; i < height; i++) { |
||
1047 | ubyte *dst; |
||
1048 | const ubyte *src; |
||
1049 | int y; |
||
1050 | |||
1051 | y = i; |
||
1052 | |||
1053 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
1054 | y = height - y - 1; |
||
1055 | } |
||
1056 | |||
1057 | dst = drawMap + y * ptDraw->stride; |
||
1058 | src = buffer + i * width; |
||
1059 | |||
1060 | switch (ptDraw->resource->format) { |
||
1061 | case PIPE_FORMAT_Z24_UNORM_S8_USCALED: |
||
1062 | { |
||
1063 | uint *dst4 = (uint *) dst; |
||
1064 | int j; |
||
1065 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
1066 | for (j = 0; j < width; j++) { |
||
1067 | *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); |
||
1068 | dst4++; |
||
1069 | } |
||
1070 | } |
||
1071 | break; |
||
1072 | case PIPE_FORMAT_S8_USCALED_Z24_UNORM: |
||
1073 | { |
||
1074 | uint *dst4 = (uint *) dst; |
||
1075 | int j; |
||
1076 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
1077 | for (j = 0; j < width; j++) { |
||
1078 | *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); |
||
1079 | dst4++; |
||
1080 | } |
||
1081 | } |
||
1082 | break; |
||
1083 | case PIPE_FORMAT_S8_USCALED: |
||
1084 | assert(usage == PIPE_TRANSFER_WRITE); |
||
1085 | memcpy(dst, src, width); |
||
1086 | break; |
||
1087 | default: |
||
1088 | assert(0); |
||
1089 | } |
||
1090 | } |
||
1091 | |||
1092 | free(buffer); |
||
1093 | |||
1094 | /* unmap the stencil buffer */ |
||
1095 | pipe_transfer_unmap(pipe, ptDraw); |
||
1096 | pipe->transfer_destroy(pipe, ptDraw); |
||
1097 | } |
||
1098 | |||
1099 | |||
1100 | static void |
||
1101 | st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, |
||
1102 | GLsizei width, GLsizei height, |
||
1103 | GLint dstx, GLint dsty, GLenum type) |
||
1104 | { |
||
1105 | struct st_context *st = st_context(ctx); |
||
1106 | struct pipe_context *pipe = st->pipe; |
||
1107 | struct pipe_screen *screen = pipe->screen; |
||
1108 | struct st_renderbuffer *rbRead; |
||
1109 | void *driver_vp, *driver_fp; |
||
1110 | struct pipe_resource *pt; |
||
1111 | struct pipe_sampler_view *sv[2]; |
||
1112 | int num_sampler_view = 1; |
||
1113 | GLfloat *color; |
||
1114 | enum pipe_format srcFormat, texFormat; |
||
1115 | GLboolean invertTex = GL_FALSE; |
||
1116 | GLint readX, readY, readW, readH; |
||
1117 | GLuint sample_count; |
||
1118 | struct gl_pixelstore_attrib pack = ctx->DefaultPacking; |
||
1119 | |||
1120 | st_validate_state(st); |
||
1121 | |||
1122 | if (type == GL_STENCIL) { |
||
1123 | /* can't use texturing to do stencil */ |
||
1124 | copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); |
||
1125 | return; |
||
1126 | } |
||
1127 | |||
1128 | if (type == GL_COLOR) { |
||
1129 | rbRead = st_get_color_read_renderbuffer(ctx); |
||
1130 | color = NULL; |
||
1131 | driver_fp = combined_drawpix_fragment_program(ctx); |
||
1132 | driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); |
||
1133 | if (st->pixel_xfer.pixelmap_enabled) { |
||
1134 | sv[1] = st->pixel_xfer.pixelmap_sampler_view; |
||
1135 | num_sampler_view++; |
||
1136 | } |
||
1137 | } |
||
1138 | else { |
||
1139 | assert(type == GL_DEPTH); |
||
1140 | rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); |
||
1141 | color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; |
||
1142 | driver_fp = make_fragment_shader_z_stencil(st, GL_TRUE, GL_FALSE); |
||
1143 | driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); |
||
1144 | } |
||
1145 | |||
1146 | if (rbRead->Base.Wrapped) |
||
1147 | rbRead = st_renderbuffer(rbRead->Base.Wrapped); |
||
1148 | |||
1149 | sample_count = rbRead->texture->nr_samples; |
||
1150 | /* I believe this would be legal, presumably would need to do a resolve |
||
1151 | for color, and for depth/stencil spec says to just use one of the |
||
1152 | depth/stencil samples per pixel? Need some transfer clarifications. */ |
||
1153 | assert(sample_count < 2); |
||
1154 | |||
1155 | srcFormat = rbRead->texture->format; |
||
1156 | |||
1157 | if (screen->is_format_supported(screen, srcFormat, st->internal_target, |
||
1158 | sample_count, |
||
1159 | PIPE_BIND_SAMPLER_VIEW, 0)) { |
||
1160 | texFormat = srcFormat; |
||
1161 | } |
||
1162 | else { |
||
1163 | /* srcFormat can't be used as a texture format */ |
||
1164 | if (type == GL_DEPTH) { |
||
1165 | texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, |
||
1166 | st->internal_target, sample_count, |
||
1167 | PIPE_BIND_DEPTH_STENCIL); |
||
1168 | assert(texFormat != PIPE_FORMAT_NONE); |
||
1169 | } |
||
1170 | else { |
||
1171 | /* default color format */ |
||
1172 | texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, |
||
1173 | sample_count, PIPE_BIND_SAMPLER_VIEW); |
||
1174 | assert(texFormat != PIPE_FORMAT_NONE); |
||
1175 | } |
||
1176 | } |
||
1177 | |||
1178 | /* Invert src region if needed */ |
||
1179 | if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { |
||
1180 | srcy = ctx->ReadBuffer->Height - srcy - height; |
||
1181 | invertTex = !invertTex; |
||
1182 | } |
||
1183 | |||
1184 | /* Clip the read region against the src buffer bounds. |
||
1185 | * We'll still allocate a temporary buffer/texture for the original |
||
1186 | * src region size but we'll only read the region which is on-screen. |
||
1187 | * This may mean that we draw garbage pixels into the dest region, but |
||
1188 | * that's expected. |
||
1189 | */ |
||
1190 | readX = srcx; |
||
1191 | readY = srcy; |
||
1192 | readW = width; |
||
1193 | readH = height; |
||
1194 | _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); |
||
1195 | readW = MAX2(0, readW); |
||
1196 | readH = MAX2(0, readH); |
||
1197 | |||
1198 | /* alloc temporary texture */ |
||
1199 | pt = alloc_texture(st, width, height, texFormat); |
||
1200 | if (!pt) |
||
1201 | return; |
||
1202 | |||
1203 | sv[0] = st_create_texture_sampler_view(st->pipe, pt); |
||
1204 | if (!sv[0]) { |
||
1205 | pipe_resource_reference(&pt, NULL); |
||
1206 | return; |
||
1207 | } |
||
1208 | |||
1209 | /* Make temporary texture which is a copy of the src region. |
||
1210 | */ |
||
1211 | if (srcFormat == texFormat) { |
||
1212 | struct pipe_box src_box; |
||
1213 | u_box_2d(readX, readY, readW, readH, &src_box); |
||
1214 | /* copy source framebuffer surface into mipmap/texture */ |
||
1215 | pipe->resource_copy_region(pipe, |
||
1216 | pt, /* dest tex */ |
||
1217 | 0, |
||
1218 | pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ |
||
1219 | rbRead->texture, /* src tex */ |
||
1220 | 0, |
||
1221 | &src_box); |
||
1222 | |||
1223 | } |
||
1224 | else { |
||
1225 | /* CPU-based fallback/conversion */ |
||
1226 | struct pipe_transfer *ptRead = |
||
1227 | pipe_get_transfer(st->pipe, rbRead->texture, |
||
1228 | 0, 0, /* level, layer */ |
||
1229 | PIPE_TRANSFER_READ, |
||
1230 | readX, readY, readW, readH); |
||
1231 | struct pipe_transfer *ptTex; |
||
1232 | enum pipe_transfer_usage transfer_usage; |
||
1233 | |||
1234 | if (ST_DEBUG & DEBUG_FALLBACK) |
||
1235 | debug_printf("%s: fallback processing\n", __FUNCTION__); |
||
1236 | |||
1237 | if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) |
||
1238 | transfer_usage = PIPE_TRANSFER_READ_WRITE; |
||
1239 | else |
||
1240 | transfer_usage = PIPE_TRANSFER_WRITE; |
||
1241 | |||
1242 | ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, |
||
1243 | 0, 0, width, height); |
||
1244 | |||
1245 | /* copy image from ptRead surface to ptTex surface */ |
||
1246 | if (type == GL_COLOR) { |
||
1247 | /* alternate path using get/put_tile() */ |
||
1248 | GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); |
||
1249 | pipe_get_tile_rgba(pipe, ptRead, 0, 0, readW, readH, buf); |
||
1250 | pipe_put_tile_rgba(pipe, ptTex, pack.SkipPixels, pack.SkipRows, |
||
1251 | readW, readH, buf); |
||
1252 | free(buf); |
||
1253 | } |
||
1254 | else { |
||
1255 | /* GL_DEPTH */ |
||
1256 | GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); |
||
1257 | pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); |
||
1258 | pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, |
||
1259 | readW, readH, buf); |
||
1260 | free(buf); |
||
1261 | } |
||
1262 | |||
1263 | pipe->transfer_destroy(pipe, ptRead); |
||
1264 | pipe->transfer_destroy(pipe, ptTex); |
||
1265 | } |
||
1266 | |||
1267 | /* OK, the texture 'pt' contains the src image/pixels. Now draw a |
||
1268 | * textured quad with that texture. |
||
1269 | */ |
||
1270 | draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], |
||
1271 | width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, |
||
1272 | sv, |
||
1273 | num_sampler_view, |
||
1274 | driver_vp, |
||
1275 | driver_fp, |
||
1276 | color, invertTex, GL_FALSE, GL_FALSE); |
||
1277 | |||
1278 | pipe_resource_reference(&pt, NULL); |
||
1279 | pipe_sampler_view_reference(&sv[0], NULL); |
||
1280 | } |
||
1281 | |||
1282 | |||
1283 | |||
1284 | void st_init_drawpixels_functions(struct dd_function_table *functions) |
||
1285 | { |
||
1286 | functions->DrawPixels = st_DrawPixels; |
||
1287 | functions->CopyPixels = st_CopyPixels; |
||
1288 | } |
||
1289 | |||
1290 | |||
1291 | void |
||
1292 | st_destroy_drawpix(struct st_context *st) |
||
1293 | { |
||
1294 | GLuint i; |
||
1295 | |||
1296 | for (i = 0; i < Elements(st->drawpix.shaders); i++) { |
||
1297 | if (st->drawpix.shaders[i]) |
||
1298 | st_reference_fragprog(st, &st->drawpix.shaders[i], NULL); |
||
1299 | } |
||
1300 | |||
1301 | st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); |
||
1302 | if (st->drawpix.vert_shaders[0]) |
||
1303 | ureg_free_tokens(st->drawpix.vert_shaders[0]); |
||
1304 | if (st->drawpix.vert_shaders[1]) |
||
1305 | ureg_free_tokens(st->drawpix.vert_shaders[1]); |
||
1306 | } |
||
1307 | |||
1308 | #endif /* FEATURE_drawpix */>>>><>>>>>>><>>><>>><>>><>>>=>=>><>>>><>><>><>> |