Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | 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/format_pack.h" |
||
37 | #include "main/macros.h" |
||
38 | #include "main/mtypes.h" |
||
39 | #include "main/pack.h" |
||
40 | #include "main/pbo.h" |
||
41 | #include "main/readpix.h" |
||
42 | #include "main/texformat.h" |
||
43 | #include "main/teximage.h" |
||
44 | #include "main/texstore.h" |
||
45 | #include "main/glformats.h" |
||
46 | #include "program/program.h" |
||
47 | #include "program/prog_print.h" |
||
48 | #include "program/prog_instruction.h" |
||
49 | |||
50 | #include "st_atom.h" |
||
51 | #include "st_atom_constbuf.h" |
||
52 | #include "st_cb_drawpixels.h" |
||
53 | #include "st_cb_readpixels.h" |
||
54 | #include "st_cb_fbo.h" |
||
55 | #include "st_context.h" |
||
56 | #include "st_debug.h" |
||
57 | #include "st_format.h" |
||
58 | #include "st_program.h" |
||
59 | #include "st_texture.h" |
||
60 | |||
61 | #include "pipe/p_context.h" |
||
62 | #include "pipe/p_defines.h" |
||
63 | #include "tgsi/tgsi_ureg.h" |
||
64 | #include "util/u_draw_quad.h" |
||
65 | #include "util/u_format.h" |
||
66 | #include "util/u_inlines.h" |
||
67 | #include "util/u_math.h" |
||
68 | #include "util/u_tile.h" |
||
69 | #include "util/u_upload_mgr.h" |
||
70 | #include "cso_cache/cso_context.h" |
||
71 | |||
72 | |||
73 | /** |
||
74 | * Check if the given program is: |
||
75 | * 0: MOVE result.color, fragment.color; |
||
76 | * 1: END; |
||
77 | */ |
||
78 | static GLboolean |
||
79 | is_passthrough_program(const struct gl_fragment_program *prog) |
||
80 | { |
||
81 | if (prog->Base.NumInstructions == 2) { |
||
82 | const struct prog_instruction *inst = prog->Base.Instructions; |
||
83 | if (inst[0].Opcode == OPCODE_MOV && |
||
84 | inst[1].Opcode == OPCODE_END && |
||
85 | inst[0].DstReg.File == PROGRAM_OUTPUT && |
||
86 | inst[0].DstReg.Index == FRAG_RESULT_COLOR && |
||
87 | inst[0].DstReg.WriteMask == WRITEMASK_XYZW && |
||
88 | inst[0].SrcReg[0].File == PROGRAM_INPUT && |
||
89 | inst[0].SrcReg[0].Index == VARYING_SLOT_COL0 && |
||
90 | inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { |
||
91 | return GL_TRUE; |
||
92 | } |
||
93 | } |
||
94 | return GL_FALSE; |
||
95 | } |
||
96 | |||
97 | |||
98 | /** |
||
99 | * Returns a fragment program which implements the current pixel transfer ops. |
||
100 | */ |
||
101 | static struct gl_fragment_program * |
||
102 | get_glsl_pixel_transfer_program(struct st_context *st, |
||
103 | struct st_fragment_program *orig) |
||
104 | { |
||
105 | int pixelMaps = 0, scaleAndBias = 0; |
||
106 | struct gl_context *ctx = st->ctx; |
||
107 | struct st_fragment_program *fp = (struct st_fragment_program *) |
||
108 | ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); |
||
109 | |||
110 | if (!fp) |
||
111 | return NULL; |
||
112 | |||
113 | if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 || |
||
114 | ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 || |
||
115 | ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 || |
||
116 | ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) { |
||
117 | scaleAndBias = 1; |
||
118 | } |
||
119 | |||
120 | pixelMaps = ctx->Pixel.MapColorFlag; |
||
121 | |||
122 | if (pixelMaps) { |
||
123 | /* create the colormap/texture now if not already done */ |
||
124 | if (!st->pixel_xfer.pixelmap_texture) { |
||
125 | st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx); |
||
126 | st->pixel_xfer.pixelmap_sampler_view = |
||
127 | st_create_texture_sampler_view(st->pipe, |
||
128 | st->pixel_xfer.pixelmap_texture); |
||
129 | } |
||
130 | } |
||
131 | |||
132 | get_pixel_transfer_visitor(fp, orig->glsl_to_tgsi, |
||
133 | scaleAndBias, pixelMaps); |
||
134 | |||
135 | return &fp->Base; |
||
136 | } |
||
137 | |||
138 | |||
139 | /** |
||
140 | * Make fragment shader for glDraw/CopyPixels. This shader is made |
||
141 | * by combining the pixel transfer shader with the user-defined shader. |
||
142 | * \param fpIn the current/incoming fragment program |
||
143 | * \param fpOut returns the combined fragment program |
||
144 | */ |
||
145 | void |
||
146 | st_make_drawpix_fragment_program(struct st_context *st, |
||
147 | struct gl_fragment_program *fpIn, |
||
148 | struct gl_fragment_program **fpOut) |
||
149 | { |
||
150 | struct gl_program *newProg; |
||
151 | struct st_fragment_program *stfp = (struct st_fragment_program *) fpIn; |
||
152 | |||
153 | if (is_passthrough_program(fpIn)) { |
||
154 | newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, |
||
155 | &st->pixel_xfer.program->Base); |
||
156 | } |
||
157 | else if (stfp->glsl_to_tgsi != NULL) { |
||
158 | newProg = (struct gl_program *) get_glsl_pixel_transfer_program(st, stfp); |
||
159 | } |
||
160 | else { |
||
161 | #if 0 |
||
162 | /* debug */ |
||
163 | printf("Base program:\n"); |
||
164 | _mesa_print_program(&fpIn->Base); |
||
165 | printf("DrawPix program:\n"); |
||
166 | _mesa_print_program(&st->pixel_xfer.program->Base.Base); |
||
167 | #endif |
||
168 | newProg = _mesa_combine_programs(st->ctx, |
||
169 | &st->pixel_xfer.program->Base.Base, |
||
170 | &fpIn->Base); |
||
171 | } |
||
172 | |||
173 | #if 0 |
||
174 | /* debug */ |
||
175 | printf("Combined DrawPixels program:\n"); |
||
176 | _mesa_print_program(newProg); |
||
177 | printf("InputsRead: 0x%x\n", newProg->InputsRead); |
||
178 | printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); |
||
179 | _mesa_print_parameter_list(newProg->Parameters); |
||
180 | #endif |
||
181 | |||
182 | *fpOut = (struct gl_fragment_program *) newProg; |
||
183 | } |
||
184 | |||
185 | |||
186 | /** |
||
187 | * Create fragment program that does a TEX() instruction to get a Z and/or |
||
188 | * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. |
||
189 | * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). |
||
190 | * Pass fragment color through as-is. |
||
191 | * \return pointer to the gl_fragment program |
||
192 | */ |
||
193 | struct gl_fragment_program * |
||
194 | st_make_drawpix_z_stencil_program(struct st_context *st, |
||
195 | GLboolean write_depth, |
||
196 | GLboolean write_stencil) |
||
197 | { |
||
198 | struct gl_context *ctx = st->ctx; |
||
199 | struct gl_program *p; |
||
200 | struct gl_fragment_program *fp; |
||
201 | GLuint ic = 0; |
||
202 | const GLuint shaderIndex = write_depth * 2 + write_stencil; |
||
203 | |||
204 | assert(shaderIndex < Elements(st->drawpix.shaders)); |
||
205 | |||
206 | if (st->drawpix.shaders[shaderIndex]) { |
||
207 | /* already have the proper shader */ |
||
208 | return st->drawpix.shaders[shaderIndex]; |
||
209 | } |
||
210 | |||
211 | /* |
||
212 | * Create shader now |
||
213 | */ |
||
214 | p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); |
||
215 | if (!p) |
||
216 | return NULL; |
||
217 | |||
218 | p->NumInstructions = write_depth ? 3 : 1; |
||
219 | p->NumInstructions += write_stencil ? 1 : 0; |
||
220 | |||
221 | p->Instructions = _mesa_alloc_instructions(p->NumInstructions); |
||
222 | if (!p->Instructions) { |
||
223 | ctx->Driver.DeleteProgram(ctx, p); |
||
224 | return NULL; |
||
225 | } |
||
226 | _mesa_init_instructions(p->Instructions, p->NumInstructions); |
||
227 | |||
228 | if (write_depth) { |
||
229 | /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ |
||
230 | p->Instructions[ic].Opcode = OPCODE_TEX; |
||
231 | p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; |
||
232 | p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; |
||
233 | p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; |
||
234 | p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; |
||
235 | p->Instructions[ic].SrcReg[0].Index = VARYING_SLOT_TEX0; |
||
236 | p->Instructions[ic].TexSrcUnit = 0; |
||
237 | p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; |
||
238 | ic++; |
||
239 | /* MOV result.color, fragment.color; */ |
||
240 | p->Instructions[ic].Opcode = OPCODE_MOV; |
||
241 | p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; |
||
242 | p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLOR; |
||
243 | p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; |
||
244 | p->Instructions[ic].SrcReg[0].Index = VARYING_SLOT_COL0; |
||
245 | ic++; |
||
246 | } |
||
247 | |||
248 | if (write_stencil) { |
||
249 | /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ |
||
250 | p->Instructions[ic].Opcode = OPCODE_TEX; |
||
251 | p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; |
||
252 | p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; |
||
253 | p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; |
||
254 | p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; |
||
255 | p->Instructions[ic].SrcReg[0].Index = VARYING_SLOT_TEX0; |
||
256 | p->Instructions[ic].TexSrcUnit = 1; |
||
257 | p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; |
||
258 | ic++; |
||
259 | } |
||
260 | |||
261 | /* END; */ |
||
262 | p->Instructions[ic++].Opcode = OPCODE_END; |
||
263 | |||
264 | assert(ic == p->NumInstructions); |
||
265 | |||
266 | p->InputsRead = VARYING_BIT_TEX0 | VARYING_BIT_COL0; |
||
267 | p->OutputsWritten = 0; |
||
268 | if (write_depth) { |
||
269 | p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH); |
||
270 | p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_COLOR); |
||
271 | } |
||
272 | if (write_stencil) |
||
273 | p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL); |
||
274 | |||
275 | p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ |
||
276 | if (write_stencil) |
||
277 | p->SamplersUsed |= 1 << 1; |
||
278 | |||
279 | fp = (struct gl_fragment_program *) p; |
||
280 | |||
281 | /* save the new shader */ |
||
282 | st->drawpix.shaders[shaderIndex] = fp; |
||
283 | |||
284 | return fp; |
||
285 | } |
||
286 | |||
287 | |||
288 | /** |
||
289 | * Create a simple vertex shader that just passes through the |
||
290 | * vertex position and texcoord (and optionally, color). |
||
291 | */ |
||
292 | static void * |
||
293 | make_passthrough_vertex_shader(struct st_context *st, |
||
294 | GLboolean passColor) |
||
295 | { |
||
296 | const unsigned texcoord_semantic = st->needs_texcoord_semantic ? |
||
297 | TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; |
||
298 | |||
299 | if (!st->drawpix.vert_shaders[passColor]) { |
||
300 | struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); |
||
301 | |||
302 | if (ureg == NULL) |
||
303 | return NULL; |
||
304 | |||
305 | /* MOV result.pos, vertex.pos; */ |
||
306 | ureg_MOV(ureg, |
||
307 | ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), |
||
308 | ureg_DECL_vs_input( ureg, 0 )); |
||
309 | |||
310 | /* MOV result.texcoord0, vertex.attr[1]; */ |
||
311 | ureg_MOV(ureg, |
||
312 | ureg_DECL_output( ureg, texcoord_semantic, 0 ), |
||
313 | ureg_DECL_vs_input( ureg, 1 )); |
||
314 | |||
315 | if (passColor) { |
||
316 | /* MOV result.color0, vertex.attr[2]; */ |
||
317 | ureg_MOV(ureg, |
||
318 | ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), |
||
319 | ureg_DECL_vs_input( ureg, 2 )); |
||
320 | } |
||
321 | |||
322 | ureg_END( ureg ); |
||
323 | |||
324 | st->drawpix.vert_shaders[passColor] = |
||
325 | ureg_create_shader_and_destroy( ureg, st->pipe ); |
||
326 | } |
||
327 | |||
328 | return st->drawpix.vert_shaders[passColor]; |
||
329 | } |
||
330 | |||
331 | |||
332 | /** |
||
333 | * Return a texture internalFormat for drawing/copying an image |
||
334 | * of the given format and type. |
||
335 | */ |
||
336 | static GLenum |
||
337 | internal_format(struct gl_context *ctx, GLenum format, GLenum type) |
||
338 | { |
||
339 | switch (format) { |
||
340 | case GL_DEPTH_COMPONENT: |
||
341 | switch (type) { |
||
342 | case GL_UNSIGNED_SHORT: |
||
343 | return GL_DEPTH_COMPONENT16; |
||
344 | |||
345 | case GL_UNSIGNED_INT: |
||
346 | return GL_DEPTH_COMPONENT32; |
||
347 | |||
348 | case GL_FLOAT: |
||
349 | if (ctx->Extensions.ARB_depth_buffer_float) |
||
350 | return GL_DEPTH_COMPONENT32F; |
||
351 | else |
||
352 | return GL_DEPTH_COMPONENT; |
||
353 | |||
354 | default: |
||
355 | return GL_DEPTH_COMPONENT; |
||
356 | } |
||
357 | |||
358 | case GL_DEPTH_STENCIL: |
||
359 | switch (type) { |
||
360 | case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: |
||
361 | return GL_DEPTH32F_STENCIL8; |
||
362 | |||
363 | case GL_UNSIGNED_INT_24_8: |
||
364 | default: |
||
365 | return GL_DEPTH24_STENCIL8; |
||
366 | } |
||
367 | |||
368 | case GL_STENCIL_INDEX: |
||
369 | return GL_STENCIL_INDEX; |
||
370 | |||
371 | default: |
||
372 | if (_mesa_is_enum_format_integer(format)) { |
||
373 | switch (type) { |
||
374 | case GL_BYTE: |
||
375 | return GL_RGBA8I; |
||
376 | case GL_UNSIGNED_BYTE: |
||
377 | return GL_RGBA8UI; |
||
378 | case GL_SHORT: |
||
379 | return GL_RGBA16I; |
||
380 | case GL_UNSIGNED_SHORT: |
||
381 | return GL_RGBA16UI; |
||
382 | case GL_INT: |
||
383 | return GL_RGBA32I; |
||
384 | case GL_UNSIGNED_INT: |
||
385 | return GL_RGBA32UI; |
||
386 | default: |
||
387 | assert(0 && "Unexpected type in internal_format()"); |
||
388 | return GL_RGBA_INTEGER; |
||
389 | } |
||
390 | } |
||
391 | else { |
||
392 | switch (type) { |
||
393 | case GL_UNSIGNED_BYTE: |
||
394 | case GL_UNSIGNED_INT_8_8_8_8: |
||
395 | case GL_UNSIGNED_INT_8_8_8_8_REV: |
||
396 | default: |
||
397 | return GL_RGBA8; |
||
398 | |||
399 | case GL_UNSIGNED_BYTE_3_3_2: |
||
400 | case GL_UNSIGNED_BYTE_2_3_3_REV: |
||
401 | return GL_R3_G3_B2; |
||
402 | |||
403 | case GL_UNSIGNED_SHORT_4_4_4_4: |
||
404 | case GL_UNSIGNED_SHORT_4_4_4_4_REV: |
||
405 | return GL_RGBA4; |
||
406 | |||
407 | case GL_UNSIGNED_SHORT_5_6_5: |
||
408 | case GL_UNSIGNED_SHORT_5_6_5_REV: |
||
409 | return GL_RGB565; |
||
410 | |||
411 | case GL_UNSIGNED_SHORT_5_5_5_1: |
||
412 | case GL_UNSIGNED_SHORT_1_5_5_5_REV: |
||
413 | return GL_RGB5_A1; |
||
414 | |||
415 | case GL_UNSIGNED_INT_10_10_10_2: |
||
416 | case GL_UNSIGNED_INT_2_10_10_10_REV: |
||
417 | return GL_RGB10_A2; |
||
418 | |||
419 | case GL_UNSIGNED_SHORT: |
||
420 | case GL_UNSIGNED_INT: |
||
421 | return GL_RGBA16; |
||
422 | |||
423 | case GL_BYTE: |
||
424 | return |
||
425 | ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8; |
||
426 | |||
427 | case GL_SHORT: |
||
428 | case GL_INT: |
||
429 | return |
||
430 | ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; |
||
431 | |||
432 | case GL_HALF_FLOAT_ARB: |
||
433 | return |
||
434 | ctx->Extensions.ARB_texture_float ? GL_RGBA16F : |
||
435 | ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; |
||
436 | |||
437 | case GL_FLOAT: |
||
438 | case GL_DOUBLE: |
||
439 | return |
||
440 | ctx->Extensions.ARB_texture_float ? GL_RGBA32F : |
||
441 | ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; |
||
442 | |||
443 | case GL_UNSIGNED_INT_5_9_9_9_REV: |
||
444 | assert(ctx->Extensions.EXT_texture_shared_exponent); |
||
445 | return GL_RGB9_E5; |
||
446 | |||
447 | case GL_UNSIGNED_INT_10F_11F_11F_REV: |
||
448 | assert(ctx->Extensions.EXT_packed_float); |
||
449 | return GL_R11F_G11F_B10F; |
||
450 | } |
||
451 | } |
||
452 | } |
||
453 | } |
||
454 | |||
455 | |||
456 | /** |
||
457 | * Create a temporary texture to hold an image of the given size. |
||
458 | * If width, height are not POT and the driver only handles POT textures, |
||
459 | * allocate the next larger size of texture that is POT. |
||
460 | */ |
||
461 | static struct pipe_resource * |
||
462 | alloc_texture(struct st_context *st, GLsizei width, GLsizei height, |
||
463 | enum pipe_format texFormat, unsigned bind) |
||
464 | { |
||
465 | struct pipe_resource *pt; |
||
466 | |||
467 | pt = st_texture_create(st, st->internal_target, texFormat, 0, |
||
468 | width, height, 1, 1, 0, bind); |
||
469 | |||
470 | return pt; |
||
471 | } |
||
472 | |||
473 | |||
474 | /** |
||
475 | * Make texture containing an image for glDrawPixels image. |
||
476 | * If 'pixels' is NULL, leave the texture image data undefined. |
||
477 | */ |
||
478 | static struct pipe_resource * |
||
479 | make_texture(struct st_context *st, |
||
480 | GLsizei width, GLsizei height, GLenum format, GLenum type, |
||
481 | const struct gl_pixelstore_attrib *unpack, |
||
482 | const GLvoid *pixels) |
||
483 | { |
||
484 | struct gl_context *ctx = st->ctx; |
||
485 | struct pipe_context *pipe = st->pipe; |
||
486 | gl_format mformat; |
||
487 | struct pipe_resource *pt; |
||
488 | enum pipe_format pipeFormat; |
||
489 | GLenum baseInternalFormat; |
||
490 | |||
491 | /* Choose a pixel format for the temp texture which will hold the |
||
492 | * image to draw. |
||
493 | */ |
||
494 | pipeFormat = st_choose_matching_format(pipe->screen, PIPE_BIND_SAMPLER_VIEW, |
||
495 | format, type, unpack->SwapBytes); |
||
496 | |||
497 | if (pipeFormat != PIPE_FORMAT_NONE) { |
||
498 | mformat = st_pipe_format_to_mesa_format(pipeFormat); |
||
499 | baseInternalFormat = _mesa_get_format_base_format(mformat); |
||
500 | } |
||
501 | else { |
||
502 | /* Use the generic approach. */ |
||
503 | GLenum intFormat = internal_format(ctx, format, type); |
||
504 | |||
505 | baseInternalFormat = _mesa_base_tex_format(ctx, intFormat); |
||
506 | pipeFormat = st_choose_format(st, intFormat, format, type, |
||
507 | PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW, |
||
508 | FALSE); |
||
509 | assert(pipeFormat != PIPE_FORMAT_NONE); |
||
510 | mformat = st_pipe_format_to_mesa_format(pipeFormat); |
||
511 | } |
||
512 | |||
513 | pixels = _mesa_map_pbo_source(ctx, unpack, pixels); |
||
514 | if (!pixels) |
||
515 | return NULL; |
||
516 | |||
517 | /* alloc temporary texture */ |
||
518 | pt = alloc_texture(st, width, height, pipeFormat, PIPE_BIND_SAMPLER_VIEW); |
||
519 | if (!pt) { |
||
520 | _mesa_unmap_pbo_source(ctx, unpack); |
||
521 | return NULL; |
||
522 | } |
||
523 | |||
524 | { |
||
525 | struct pipe_transfer *transfer; |
||
526 | GLboolean success; |
||
527 | GLubyte *dest; |
||
528 | const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; |
||
529 | |||
530 | /* we'll do pixel transfer in a fragment shader */ |
||
531 | ctx->_ImageTransferState = 0x0; |
||
532 | |||
533 | /* map texture transfer */ |
||
534 | dest = pipe_transfer_map(pipe, pt, 0, 0, |
||
535 | PIPE_TRANSFER_WRITE, 0, 0, |
||
536 | width, height, &transfer); |
||
537 | |||
538 | |||
539 | /* Put image into texture transfer. |
||
540 | * Note that the image is actually going to be upside down in |
||
541 | * the texture. We deal with that with texcoords. |
||
542 | */ |
||
543 | success = _mesa_texstore(ctx, 2, /* dims */ |
||
544 | baseInternalFormat, /* baseInternalFormat */ |
||
545 | mformat, /* gl_format */ |
||
546 | transfer->stride, /* dstRowStride, bytes */ |
||
547 | &dest, /* destSlices */ |
||
548 | width, height, 1, /* size */ |
||
549 | format, type, /* src format/type */ |
||
550 | pixels, /* data source */ |
||
551 | unpack); |
||
552 | |||
553 | /* unmap */ |
||
554 | pipe_transfer_unmap(pipe, transfer); |
||
555 | |||
556 | assert(success); |
||
557 | |||
558 | /* restore */ |
||
559 | ctx->_ImageTransferState = imageTransferStateSave; |
||
560 | } |
||
561 | |||
562 | _mesa_unmap_pbo_source(ctx, unpack); |
||
563 | |||
564 | return pt; |
||
565 | } |
||
566 | |||
567 | |||
568 | /** |
||
569 | * Draw quad with texcoords and optional color. |
||
570 | * Coords are gallium window coords with y=0=top. |
||
571 | * \param color may be null |
||
572 | * \param invertTex if true, flip texcoords vertically |
||
573 | */ |
||
574 | static void |
||
575 | draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, |
||
576 | GLfloat x1, GLfloat y1, const GLfloat *color, |
||
577 | GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) |
||
578 | { |
||
579 | struct st_context *st = st_context(ctx); |
||
580 | struct pipe_context *pipe = st->pipe; |
||
581 | GLfloat (*verts)[3][4]; /* four verts, three attribs, XYZW */ |
||
582 | struct pipe_resource *buf = NULL; |
||
583 | unsigned offset; |
||
584 | |||
585 | if (u_upload_alloc(st->uploader, 0, 4 * sizeof(verts[0]), &offset, |
||
586 | &buf, (void **) &verts) != PIPE_OK) { |
||
587 | return; |
||
588 | } |
||
589 | |||
590 | /* setup vertex data */ |
||
591 | { |
||
592 | const struct gl_framebuffer *fb = st->ctx->DrawBuffer; |
||
593 | const GLfloat fb_width = (GLfloat) fb->Width; |
||
594 | const GLfloat fb_height = (GLfloat) fb->Height; |
||
595 | const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; |
||
596 | const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; |
||
597 | const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; |
||
598 | const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; |
||
599 | const GLfloat sLeft = 0.0f, sRight = maxXcoord; |
||
600 | const GLfloat tTop = invertTex ? maxYcoord : 0.0f; |
||
601 | const GLfloat tBot = invertTex ? 0.0f : maxYcoord; |
||
602 | GLuint i; |
||
603 | |||
604 | /* upper-left */ |
||
605 | verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ |
||
606 | verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ |
||
607 | |||
608 | /* upper-right */ |
||
609 | verts[1][0][0] = clip_x1; |
||
610 | verts[1][0][1] = clip_y0; |
||
611 | |||
612 | /* lower-right */ |
||
613 | verts[2][0][0] = clip_x1; |
||
614 | verts[2][0][1] = clip_y1; |
||
615 | |||
616 | /* lower-left */ |
||
617 | verts[3][0][0] = clip_x0; |
||
618 | verts[3][0][1] = clip_y1; |
||
619 | |||
620 | verts[0][1][0] = sLeft; /* v[0].attr[1].S */ |
||
621 | verts[0][1][1] = tTop; /* v[0].attr[1].T */ |
||
622 | verts[1][1][0] = sRight; |
||
623 | verts[1][1][1] = tTop; |
||
624 | verts[2][1][0] = sRight; |
||
625 | verts[2][1][1] = tBot; |
||
626 | verts[3][1][0] = sLeft; |
||
627 | verts[3][1][1] = tBot; |
||
628 | |||
629 | /* same for all verts: */ |
||
630 | if (color) { |
||
631 | for (i = 0; i < 4; i++) { |
||
632 | verts[i][0][2] = z; /* v[i].attr[0].z */ |
||
633 | verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ |
||
634 | verts[i][2][0] = color[0]; /* v[i].attr[2].r */ |
||
635 | verts[i][2][1] = color[1]; /* v[i].attr[2].g */ |
||
636 | verts[i][2][2] = color[2]; /* v[i].attr[2].b */ |
||
637 | verts[i][2][3] = color[3]; /* v[i].attr[2].a */ |
||
638 | verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ |
||
639 | verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ |
||
640 | } |
||
641 | } |
||
642 | else { |
||
643 | for (i = 0; i < 4; i++) { |
||
644 | verts[i][0][2] = z; /*Z*/ |
||
645 | verts[i][0][3] = 1.0f; /*W*/ |
||
646 | verts[i][1][2] = 0.0f; /*R*/ |
||
647 | verts[i][1][3] = 1.0f; /*Q*/ |
||
648 | } |
||
649 | } |
||
650 | } |
||
651 | |||
652 | u_upload_unmap(st->uploader); |
||
653 | util_draw_vertex_buffer(pipe, st->cso_context, buf, |
||
654 | cso_get_aux_vertex_buffer_slot(st->cso_context), |
||
655 | offset, |
||
656 | PIPE_PRIM_QUADS, |
||
657 | 4, /* verts */ |
||
658 | 3); /* attribs/vert */ |
||
659 | pipe_resource_reference(&buf, NULL); |
||
660 | } |
||
661 | |||
662 | |||
663 | |||
664 | static void |
||
665 | draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, |
||
666 | GLsizei width, GLsizei height, |
||
667 | GLfloat zoomX, GLfloat zoomY, |
||
668 | struct pipe_sampler_view **sv, |
||
669 | int num_sampler_view, |
||
670 | void *driver_vp, |
||
671 | void *driver_fp, |
||
672 | const GLfloat *color, |
||
673 | GLboolean invertTex, |
||
674 | GLboolean write_depth, GLboolean write_stencil) |
||
675 | { |
||
676 | struct st_context *st = st_context(ctx); |
||
677 | struct pipe_context *pipe = st->pipe; |
||
678 | struct cso_context *cso = st->cso_context; |
||
679 | GLfloat x0, y0, x1, y1; |
||
680 | GLsizei maxSize; |
||
681 | boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; |
||
682 | |||
683 | /* limit checks */ |
||
684 | /* XXX if DrawPixels image is larger than max texture size, break |
||
685 | * it up into chunks. |
||
686 | */ |
||
687 | maxSize = 1 << (pipe->screen->get_param(pipe->screen, |
||
688 | PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); |
||
689 | assert(width <= maxSize); |
||
690 | assert(height <= maxSize); |
||
691 | |||
692 | cso_save_rasterizer(cso); |
||
693 | cso_save_viewport(cso); |
||
694 | cso_save_samplers(cso, PIPE_SHADER_FRAGMENT); |
||
695 | cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT); |
||
696 | cso_save_fragment_shader(cso); |
||
697 | cso_save_stream_outputs(cso); |
||
698 | cso_save_vertex_shader(cso); |
||
699 | cso_save_geometry_shader(cso); |
||
700 | cso_save_vertex_elements(cso); |
||
701 | cso_save_aux_vertex_buffer_slot(cso); |
||
702 | if (write_stencil) { |
||
703 | cso_save_depth_stencil_alpha(cso); |
||
704 | cso_save_blend(cso); |
||
705 | } |
||
706 | |||
707 | /* rasterizer state: just scissor */ |
||
708 | { |
||
709 | struct pipe_rasterizer_state rasterizer; |
||
710 | memset(&rasterizer, 0, sizeof(rasterizer)); |
||
711 | rasterizer.clamp_fragment_color = !st->clamp_frag_color_in_shader && |
||
712 | ctx->Color._ClampFragmentColor; |
||
713 | rasterizer.half_pixel_center = 1; |
||
714 | rasterizer.bottom_edge_rule = 1; |
||
715 | rasterizer.depth_clip = !ctx->Transform.DepthClamp; |
||
716 | rasterizer.scissor = ctx->Scissor.Enabled; |
||
717 | cso_set_rasterizer(cso, &rasterizer); |
||
718 | } |
||
719 | |||
720 | if (write_stencil) { |
||
721 | /* Stencil writing bypasses the normal fragment pipeline to |
||
722 | * disable color writing and set stencil test to always pass. |
||
723 | */ |
||
724 | struct pipe_depth_stencil_alpha_state dsa; |
||
725 | struct pipe_blend_state blend; |
||
726 | |||
727 | /* depth/stencil */ |
||
728 | memset(&dsa, 0, sizeof(dsa)); |
||
729 | dsa.stencil[0].enabled = 1; |
||
730 | dsa.stencil[0].func = PIPE_FUNC_ALWAYS; |
||
731 | dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; |
||
732 | dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; |
||
733 | if (write_depth) { |
||
734 | /* writing depth+stencil: depth test always passes */ |
||
735 | dsa.depth.enabled = 1; |
||
736 | dsa.depth.writemask = ctx->Depth.Mask; |
||
737 | dsa.depth.func = PIPE_FUNC_ALWAYS; |
||
738 | } |
||
739 | cso_set_depth_stencil_alpha(cso, &dsa); |
||
740 | |||
741 | /* blend (colormask) */ |
||
742 | memset(&blend, 0, sizeof(blend)); |
||
743 | cso_set_blend(cso, &blend); |
||
744 | } |
||
745 | |||
746 | /* fragment shader state: TEX lookup program */ |
||
747 | cso_set_fragment_shader_handle(cso, driver_fp); |
||
748 | |||
749 | /* vertex shader state: position + texcoord pass-through */ |
||
750 | cso_set_vertex_shader_handle(cso, driver_vp); |
||
751 | |||
752 | /* geometry shader state: disabled */ |
||
753 | cso_set_geometry_shader_handle(cso, NULL); |
||
754 | |||
755 | /* texture sampling state: */ |
||
756 | { |
||
757 | struct pipe_sampler_state sampler; |
||
758 | memset(&sampler, 0, sizeof(sampler)); |
||
759 | sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; |
||
760 | sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; |
||
761 | sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; |
||
762 | sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
763 | sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; |
||
764 | sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
765 | sampler.normalized_coords = normalized; |
||
766 | |||
767 | cso_single_sampler(cso, PIPE_SHADER_FRAGMENT, 0, &sampler); |
||
768 | if (num_sampler_view > 1) { |
||
769 | cso_single_sampler(cso, PIPE_SHADER_FRAGMENT, 1, &sampler); |
||
770 | } |
||
771 | cso_single_sampler_done(cso, PIPE_SHADER_FRAGMENT); |
||
772 | } |
||
773 | |||
774 | /* viewport state: viewport matching window dims */ |
||
775 | { |
||
776 | const float w = (float) ctx->DrawBuffer->Width; |
||
777 | const float h = (float) ctx->DrawBuffer->Height; |
||
778 | struct pipe_viewport_state vp; |
||
779 | vp.scale[0] = 0.5f * w; |
||
780 | vp.scale[1] = -0.5f * h; |
||
781 | vp.scale[2] = 0.5f; |
||
782 | vp.scale[3] = 1.0f; |
||
783 | vp.translate[0] = 0.5f * w; |
||
784 | vp.translate[1] = 0.5f * h; |
||
785 | vp.translate[2] = 0.5f; |
||
786 | vp.translate[3] = 0.0f; |
||
787 | cso_set_viewport(cso, &vp); |
||
788 | } |
||
789 | |||
790 | cso_set_vertex_elements(cso, 3, st->velems_util_draw); |
||
791 | cso_set_stream_outputs(st->cso_context, 0, NULL, 0); |
||
792 | |||
793 | /* texture state: */ |
||
794 | cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, num_sampler_view, sv); |
||
795 | |||
796 | /* Compute Gallium window coords (y=0=top) with pixel zoom. |
||
797 | * Recall that these coords are transformed by the current |
||
798 | * vertex shader and viewport transformation. |
||
799 | */ |
||
800 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { |
||
801 | y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); |
||
802 | invertTex = !invertTex; |
||
803 | } |
||
804 | |||
805 | x0 = (GLfloat) x; |
||
806 | x1 = x + width * ctx->Pixel.ZoomX; |
||
807 | y0 = (GLfloat) y; |
||
808 | y1 = y + height * ctx->Pixel.ZoomY; |
||
809 | |||
810 | /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ |
||
811 | z = z * 2.0f - 1.0f; |
||
812 | |||
813 | draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, |
||
814 | normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, |
||
815 | normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); |
||
816 | |||
817 | /* restore state */ |
||
818 | cso_restore_rasterizer(cso); |
||
819 | cso_restore_viewport(cso); |
||
820 | cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT); |
||
821 | cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT); |
||
822 | cso_restore_fragment_shader(cso); |
||
823 | cso_restore_vertex_shader(cso); |
||
824 | cso_restore_geometry_shader(cso); |
||
825 | cso_restore_vertex_elements(cso); |
||
826 | cso_restore_aux_vertex_buffer_slot(cso); |
||
827 | cso_restore_stream_outputs(cso); |
||
828 | if (write_stencil) { |
||
829 | cso_restore_depth_stencil_alpha(cso); |
||
830 | cso_restore_blend(cso); |
||
831 | } |
||
832 | } |
||
833 | |||
834 | |||
835 | /** |
||
836 | * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we |
||
837 | * can't use a fragment shader to write stencil values. |
||
838 | */ |
||
839 | static void |
||
840 | draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, |
||
841 | GLsizei width, GLsizei height, GLenum format, GLenum type, |
||
842 | const struct gl_pixelstore_attrib *unpack, |
||
843 | const GLvoid *pixels) |
||
844 | { |
||
845 | struct st_context *st = st_context(ctx); |
||
846 | struct pipe_context *pipe = st->pipe; |
||
847 | struct st_renderbuffer *strb; |
||
848 | enum pipe_transfer_usage usage; |
||
849 | struct pipe_transfer *pt; |
||
850 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; |
||
851 | ubyte *stmap; |
||
852 | struct gl_pixelstore_attrib clippedUnpack = *unpack; |
||
853 | GLubyte *sValues; |
||
854 | GLuint *zValues; |
||
855 | |||
856 | if (!zoom) { |
||
857 | if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, |
||
858 | &clippedUnpack)) { |
||
859 | /* totally clipped */ |
||
860 | return; |
||
861 | } |
||
862 | } |
||
863 | |||
864 | strb = st_renderbuffer(ctx->DrawBuffer-> |
||
865 | Attachment[BUFFER_STENCIL].Renderbuffer); |
||
866 | |||
867 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
868 | y = ctx->DrawBuffer->Height - y - height; |
||
869 | } |
||
870 | |||
871 | if (format == GL_STENCIL_INDEX && |
||
872 | _mesa_is_format_packed_depth_stencil(strb->Base.Format)) { |
||
873 | /* writing stencil to a combined depth+stencil buffer */ |
||
874 | usage = PIPE_TRANSFER_READ_WRITE; |
||
875 | } |
||
876 | else { |
||
877 | usage = PIPE_TRANSFER_WRITE; |
||
878 | } |
||
879 | |||
880 | stmap = pipe_transfer_map(pipe, strb->texture, |
||
881 | strb->rtt_level, strb->rtt_face + strb->rtt_slice, |
||
882 | usage, x, y, |
||
883 | width, height, &pt); |
||
884 | |||
885 | pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); |
||
886 | assert(pixels); |
||
887 | |||
888 | sValues = malloc(width * sizeof(GLubyte)); |
||
889 | zValues = malloc(width * sizeof(GLuint)); |
||
890 | |||
891 | if (sValues && zValues) { |
||
892 | GLint row; |
||
893 | for (row = 0; row < height; row++) { |
||
894 | GLfloat *zValuesFloat = (GLfloat*)zValues; |
||
895 | GLenum destType = GL_UNSIGNED_BYTE; |
||
896 | const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, |
||
897 | width, height, |
||
898 | format, type, |
||
899 | row, 0); |
||
900 | _mesa_unpack_stencil_span(ctx, width, destType, sValues, |
||
901 | type, source, &clippedUnpack, |
||
902 | ctx->_ImageTransferState); |
||
903 | |||
904 | if (format == GL_DEPTH_STENCIL) { |
||
905 | GLenum ztype = |
||
906 | pt->resource->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT ? |
||
907 | GL_FLOAT : GL_UNSIGNED_INT; |
||
908 | |||
909 | _mesa_unpack_depth_span(ctx, width, ztype, zValues, |
||
910 | (1 << 24) - 1, type, source, |
||
911 | &clippedUnpack); |
||
912 | } |
||
913 | |||
914 | if (zoom) { |
||
915 | _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " |
||
916 | "zoom not complete"); |
||
917 | } |
||
918 | |||
919 | { |
||
920 | GLint spanY; |
||
921 | |||
922 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
923 | spanY = height - row - 1; |
||
924 | } |
||
925 | else { |
||
926 | spanY = row; |
||
927 | } |
||
928 | |||
929 | /* now pack the stencil (and Z) values in the dest format */ |
||
930 | switch (pt->resource->format) { |
||
931 | case PIPE_FORMAT_S8_UINT: |
||
932 | { |
||
933 | ubyte *dest = stmap + spanY * pt->stride; |
||
934 | assert(usage == PIPE_TRANSFER_WRITE); |
||
935 | memcpy(dest, sValues, width); |
||
936 | } |
||
937 | break; |
||
938 | case PIPE_FORMAT_Z24_UNORM_S8_UINT: |
||
939 | if (format == GL_DEPTH_STENCIL) { |
||
940 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
941 | GLint k; |
||
942 | assert(usage == PIPE_TRANSFER_WRITE); |
||
943 | for (k = 0; k < width; k++) { |
||
944 | dest[k] = zValues[k] | (sValues[k] << 24); |
||
945 | } |
||
946 | } |
||
947 | else { |
||
948 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
949 | GLint k; |
||
950 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
951 | for (k = 0; k < width; k++) { |
||
952 | dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); |
||
953 | } |
||
954 | } |
||
955 | break; |
||
956 | case PIPE_FORMAT_S8_UINT_Z24_UNORM: |
||
957 | if (format == GL_DEPTH_STENCIL) { |
||
958 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
959 | GLint k; |
||
960 | assert(usage == PIPE_TRANSFER_WRITE); |
||
961 | for (k = 0; k < width; k++) { |
||
962 | dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); |
||
963 | } |
||
964 | } |
||
965 | else { |
||
966 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
967 | GLint k; |
||
968 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
969 | for (k = 0; k < width; k++) { |
||
970 | dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); |
||
971 | } |
||
972 | } |
||
973 | break; |
||
974 | case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: |
||
975 | if (format == GL_DEPTH_STENCIL) { |
||
976 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
977 | GLfloat *destf = (GLfloat*)dest; |
||
978 | GLint k; |
||
979 | assert(usage == PIPE_TRANSFER_WRITE); |
||
980 | for (k = 0; k < width; k++) { |
||
981 | destf[k*2] = zValuesFloat[k]; |
||
982 | dest[k*2+1] = sValues[k] & 0xff; |
||
983 | } |
||
984 | } |
||
985 | else { |
||
986 | uint *dest = (uint *) (stmap + spanY * pt->stride); |
||
987 | GLint k; |
||
988 | assert(usage == PIPE_TRANSFER_READ_WRITE); |
||
989 | for (k = 0; k < width; k++) { |
||
990 | dest[k*2+1] = sValues[k] & 0xff; |
||
991 | } |
||
992 | } |
||
993 | break; |
||
994 | default: |
||
995 | assert(0); |
||
996 | } |
||
997 | } |
||
998 | } |
||
999 | } |
||
1000 | else { |
||
1001 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels()"); |
||
1002 | } |
||
1003 | |||
1004 | free(sValues); |
||
1005 | free(zValues); |
||
1006 | |||
1007 | _mesa_unmap_pbo_source(ctx, &clippedUnpack); |
||
1008 | |||
1009 | /* unmap the stencil buffer */ |
||
1010 | pipe_transfer_unmap(pipe, pt); |
||
1011 | } |
||
1012 | |||
1013 | |||
1014 | /** |
||
1015 | * Get fragment program variant for a glDrawPixels or glCopyPixels |
||
1016 | * command for RGBA data. |
||
1017 | */ |
||
1018 | static struct st_fp_variant * |
||
1019 | get_color_fp_variant(struct st_context *st) |
||
1020 | { |
||
1021 | struct gl_context *ctx = st->ctx; |
||
1022 | struct st_fp_variant_key key; |
||
1023 | struct st_fp_variant *fpv; |
||
1024 | |||
1025 | memset(&key, 0, sizeof(key)); |
||
1026 | |||
1027 | key.st = st; |
||
1028 | key.drawpixels = 1; |
||
1029 | key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || |
||
1030 | ctx->Pixel.RedScale != 1.0 || |
||
1031 | ctx->Pixel.GreenBias != 0.0 || |
||
1032 | ctx->Pixel.GreenScale != 1.0 || |
||
1033 | ctx->Pixel.BlueBias != 0.0 || |
||
1034 | ctx->Pixel.BlueScale != 1.0 || |
||
1035 | ctx->Pixel.AlphaBias != 0.0 || |
||
1036 | ctx->Pixel.AlphaScale != 1.0); |
||
1037 | key.pixelMaps = ctx->Pixel.MapColorFlag; |
||
1038 | key.clamp_color = st->clamp_frag_color_in_shader && |
||
1039 | st->ctx->Color._ClampFragmentColor; |
||
1040 | |||
1041 | fpv = st_get_fp_variant(st, st->fp, &key); |
||
1042 | |||
1043 | return fpv; |
||
1044 | } |
||
1045 | |||
1046 | |||
1047 | /** |
||
1048 | * Get fragment program variant for a glDrawPixels or glCopyPixels |
||
1049 | * command for depth/stencil data. |
||
1050 | */ |
||
1051 | static struct st_fp_variant * |
||
1052 | get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, |
||
1053 | GLboolean write_stencil) |
||
1054 | { |
||
1055 | struct st_fp_variant_key key; |
||
1056 | struct st_fp_variant *fpv; |
||
1057 | |||
1058 | memset(&key, 0, sizeof(key)); |
||
1059 | |||
1060 | key.st = st; |
||
1061 | key.drawpixels = 1; |
||
1062 | key.drawpixels_z = write_depth; |
||
1063 | key.drawpixels_stencil = write_stencil; |
||
1064 | |||
1065 | fpv = st_get_fp_variant(st, st->fp, &key); |
||
1066 | |||
1067 | return fpv; |
||
1068 | } |
||
1069 | |||
1070 | |||
1071 | /** |
||
1072 | * Clamp glDrawPixels width and height to the maximum texture size. |
||
1073 | */ |
||
1074 | static void |
||
1075 | clamp_size(struct pipe_context *pipe, GLsizei *width, GLsizei *height, |
||
1076 | struct gl_pixelstore_attrib *unpack) |
||
1077 | { |
||
1078 | const int maxSize = |
||
1079 | 1 << (pipe->screen->get_param(pipe->screen, |
||
1080 | PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); |
||
1081 | |||
1082 | if (*width > maxSize) { |
||
1083 | if (unpack->RowLength == 0) |
||
1084 | unpack->RowLength = *width; |
||
1085 | *width = maxSize; |
||
1086 | } |
||
1087 | if (*height > maxSize) { |
||
1088 | *height = maxSize; |
||
1089 | } |
||
1090 | } |
||
1091 | |||
1092 | |||
1093 | /** |
||
1094 | * Called via ctx->Driver.DrawPixels() |
||
1095 | */ |
||
1096 | static void |
||
1097 | st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, |
||
1098 | GLsizei width, GLsizei height, |
||
1099 | GLenum format, GLenum type, |
||
1100 | const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) |
||
1101 | { |
||
1102 | void *driver_vp, *driver_fp; |
||
1103 | struct st_context *st = st_context(ctx); |
||
1104 | const GLfloat *color; |
||
1105 | struct pipe_context *pipe = st->pipe; |
||
1106 | GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; |
||
1107 | struct pipe_sampler_view *sv[2]; |
||
1108 | int num_sampler_view = 1; |
||
1109 | struct st_fp_variant *fpv; |
||
1110 | struct gl_pixelstore_attrib clippedUnpack; |
||
1111 | |||
1112 | /* Mesa state should be up to date by now */ |
||
1113 | assert(ctx->NewState == 0x0); |
||
1114 | |||
1115 | st_validate_state(st); |
||
1116 | |||
1117 | /* Limit the size of the glDrawPixels to the max texture size. |
||
1118 | * Strictly speaking, that's not correct but since we don't handle |
||
1119 | * larger images yet, this is better than crashing. |
||
1120 | */ |
||
1121 | clippedUnpack = *unpack; |
||
1122 | unpack = &clippedUnpack; |
||
1123 | clamp_size(st->pipe, &width, &height, &clippedUnpack); |
||
1124 | |||
1125 | if (format == GL_DEPTH_STENCIL) |
||
1126 | write_stencil = write_depth = GL_TRUE; |
||
1127 | else if (format == GL_STENCIL_INDEX) |
||
1128 | write_stencil = GL_TRUE; |
||
1129 | else if (format == GL_DEPTH_COMPONENT) |
||
1130 | write_depth = GL_TRUE; |
||
1131 | |||
1132 | if (write_stencil && |
||
1133 | !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { |
||
1134 | /* software fallback */ |
||
1135 | draw_stencil_pixels(ctx, x, y, width, height, format, type, |
||
1136 | unpack, pixels); |
||
1137 | return; |
||
1138 | } |
||
1139 | |||
1140 | /* |
||
1141 | * Get vertex/fragment shaders |
||
1142 | */ |
||
1143 | if (write_depth || write_stencil) { |
||
1144 | fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); |
||
1145 | |||
1146 | driver_fp = fpv->driver_shader; |
||
1147 | |||
1148 | driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); |
||
1149 | |||
1150 | color = ctx->Current.RasterColor; |
||
1151 | } |
||
1152 | else { |
||
1153 | fpv = get_color_fp_variant(st); |
||
1154 | |||
1155 | driver_fp = fpv->driver_shader; |
||
1156 | |||
1157 | driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); |
||
1158 | |||
1159 | color = NULL; |
||
1160 | if (st->pixel_xfer.pixelmap_enabled) { |
||
1161 | sv[1] = st->pixel_xfer.pixelmap_sampler_view; |
||
1162 | num_sampler_view++; |
||
1163 | } |
||
1164 | } |
||
1165 | |||
1166 | /* update fragment program constants */ |
||
1167 | st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); |
||
1168 | |||
1169 | /* draw with textured quad */ |
||
1170 | { |
||
1171 | struct pipe_resource *pt |
||
1172 | = make_texture(st, width, height, format, type, unpack, pixels); |
||
1173 | if (pt) { |
||
1174 | sv[0] = st_create_texture_sampler_view(st->pipe, pt); |
||
1175 | |||
1176 | if (sv[0]) { |
||
1177 | /* Create a second sampler view to read stencil. |
||
1178 | * The stencil is written using the shader stencil export |
||
1179 | * functionality. */ |
||
1180 | if (write_stencil) { |
||
1181 | enum pipe_format stencil_format = |
||
1182 | util_format_stencil_only(pt->format); |
||
1183 | |||
1184 | sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, |
||
1185 | stencil_format); |
||
1186 | num_sampler_view++; |
||
1187 | } |
||
1188 | |||
1189 | draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], |
||
1190 | width, height, |
||
1191 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, |
||
1192 | sv, |
||
1193 | num_sampler_view, |
||
1194 | driver_vp, |
||
1195 | driver_fp, |
||
1196 | color, GL_FALSE, write_depth, write_stencil); |
||
1197 | pipe_sampler_view_reference(&sv[0], NULL); |
||
1198 | if (num_sampler_view > 1) |
||
1199 | pipe_sampler_view_reference(&sv[1], NULL); |
||
1200 | } |
||
1201 | pipe_resource_reference(&pt, NULL); |
||
1202 | } |
||
1203 | } |
||
1204 | } |
||
1205 | |||
1206 | |||
1207 | |||
1208 | /** |
||
1209 | * Software fallback for glCopyPixels(GL_STENCIL). |
||
1210 | */ |
||
1211 | static void |
||
1212 | copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, |
||
1213 | GLsizei width, GLsizei height, |
||
1214 | GLint dstx, GLint dsty) |
||
1215 | { |
||
1216 | struct st_renderbuffer *rbDraw; |
||
1217 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
1218 | enum pipe_transfer_usage usage; |
||
1219 | struct pipe_transfer *ptDraw; |
||
1220 | ubyte *drawMap; |
||
1221 | ubyte *buffer; |
||
1222 | int i; |
||
1223 | |||
1224 | buffer = malloc(width * height * sizeof(ubyte)); |
||
1225 | if (!buffer) { |
||
1226 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); |
||
1227 | return; |
||
1228 | } |
||
1229 | |||
1230 | /* Get the dest renderbuffer */ |
||
1231 | rbDraw = st_renderbuffer(ctx->DrawBuffer-> |
||
1232 | Attachment[BUFFER_STENCIL].Renderbuffer); |
||
1233 | |||
1234 | /* this will do stencil pixel transfer ops */ |
||
1235 | _mesa_readpixels(ctx, srcx, srcy, width, height, |
||
1236 | GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, |
||
1237 | &ctx->DefaultPacking, buffer); |
||
1238 | |||
1239 | if (0) { |
||
1240 | /* debug code: dump stencil values */ |
||
1241 | GLint row, col; |
||
1242 | for (row = 0; row < height; row++) { |
||
1243 | printf("%3d: ", row); |
||
1244 | for (col = 0; col < width; col++) { |
||
1245 | printf("%02x ", buffer[col + row * width]); |
||
1246 | } |
||
1247 | printf("\n"); |
||
1248 | } |
||
1249 | } |
||
1250 | |||
1251 | if (_mesa_is_format_packed_depth_stencil(rbDraw->Base.Format)) |
||
1252 | usage = PIPE_TRANSFER_READ_WRITE; |
||
1253 | else |
||
1254 | usage = PIPE_TRANSFER_WRITE; |
||
1255 | |||
1256 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
1257 | dsty = rbDraw->Base.Height - dsty - height; |
||
1258 | } |
||
1259 | |||
1260 | assert(util_format_get_blockwidth(rbDraw->texture->format) == 1); |
||
1261 | assert(util_format_get_blockheight(rbDraw->texture->format) == 1); |
||
1262 | |||
1263 | /* map the stencil buffer */ |
||
1264 | drawMap = pipe_transfer_map(pipe, |
||
1265 | rbDraw->texture, |
||
1266 | rbDraw->rtt_level, |
||
1267 | rbDraw->rtt_face + rbDraw->rtt_slice, |
||
1268 | usage, dstx, dsty, |
||
1269 | width, height, &ptDraw); |
||
1270 | |||
1271 | /* draw */ |
||
1272 | /* XXX PixelZoom not handled yet */ |
||
1273 | for (i = 0; i < height; i++) { |
||
1274 | ubyte *dst; |
||
1275 | const ubyte *src; |
||
1276 | int y; |
||
1277 | |||
1278 | y = i; |
||
1279 | |||
1280 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
1281 | y = height - y - 1; |
||
1282 | } |
||
1283 | |||
1284 | dst = drawMap + y * ptDraw->stride; |
||
1285 | src = buffer + i * width; |
||
1286 | |||
1287 | _mesa_pack_ubyte_stencil_row(rbDraw->Base.Format, width, src, dst); |
||
1288 | } |
||
1289 | |||
1290 | free(buffer); |
||
1291 | |||
1292 | /* unmap the stencil buffer */ |
||
1293 | pipe_transfer_unmap(pipe, ptDraw); |
||
1294 | } |
||
1295 | |||
1296 | |||
1297 | /** |
||
1298 | * Return renderbuffer to use for reading color pixels for glCopyPixels |
||
1299 | */ |
||
1300 | static struct st_renderbuffer * |
||
1301 | st_get_color_read_renderbuffer(struct gl_context *ctx) |
||
1302 | { |
||
1303 | struct gl_framebuffer *fb = ctx->ReadBuffer; |
||
1304 | struct st_renderbuffer *strb = |
||
1305 | st_renderbuffer(fb->_ColorReadBuffer); |
||
1306 | |||
1307 | return strb; |
||
1308 | } |
||
1309 | |||
1310 | |||
1311 | /** |
||
1312 | * \return TRUE if two regions overlap, FALSE otherwise |
||
1313 | */ |
||
1314 | static boolean |
||
1315 | regions_overlap(int srcX0, int srcY0, |
||
1316 | int srcX1, int srcY1, |
||
1317 | int dstX0, int dstY0, |
||
1318 | int dstX1, int dstY1) |
||
1319 | { |
||
1320 | if (MAX2(srcX0, srcX1) < MIN2(dstX0, dstX1)) |
||
1321 | return FALSE; /* src completely left of dst */ |
||
1322 | |||
1323 | if (MAX2(dstX0, dstX1) < MIN2(srcX0, srcX1)) |
||
1324 | return FALSE; /* dst completely left of src */ |
||
1325 | |||
1326 | if (MAX2(srcY0, srcY1) < MIN2(dstY0, dstY1)) |
||
1327 | return FALSE; /* src completely above dst */ |
||
1328 | |||
1329 | if (MAX2(dstY0, dstY1) < MIN2(srcY0, srcY1)) |
||
1330 | return FALSE; /* dst completely above src */ |
||
1331 | |||
1332 | return TRUE; /* some overlap */ |
||
1333 | } |
||
1334 | |||
1335 | |||
1336 | /** |
||
1337 | * Try to do a glCopyPixels for simple cases with a blit by calling |
||
1338 | * pipe->blit(). |
||
1339 | * |
||
1340 | * We can do this when we're copying color pixels (depth/stencil |
||
1341 | * eventually) with no pixel zoom, no pixel transfer ops, no |
||
1342 | * per-fragment ops, and the src/dest regions don't overlap. |
||
1343 | */ |
||
1344 | static GLboolean |
||
1345 | blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, |
||
1346 | GLsizei width, GLsizei height, |
||
1347 | GLint dstx, GLint dsty, GLenum type) |
||
1348 | { |
||
1349 | struct st_context *st = st_context(ctx); |
||
1350 | struct pipe_context *pipe = st->pipe; |
||
1351 | struct pipe_screen *screen = pipe->screen; |
||
1352 | struct gl_pixelstore_attrib pack, unpack; |
||
1353 | GLint readX, readY, readW, readH, drawX, drawY, drawW, drawH; |
||
1354 | |||
1355 | if (type == GL_COLOR && |
||
1356 | ctx->Pixel.ZoomX == 1.0 && |
||
1357 | ctx->Pixel.ZoomY == 1.0 && |
||
1358 | ctx->_ImageTransferState == 0x0 && |
||
1359 | !ctx->Color.BlendEnabled && |
||
1360 | !ctx->Color.AlphaEnabled && |
||
1361 | !ctx->Depth.Test && |
||
1362 | !ctx->Fog.Enabled && |
||
1363 | !ctx->Stencil.Enabled && |
||
1364 | !ctx->FragmentProgram.Enabled && |
||
1365 | !ctx->VertexProgram.Enabled && |
||
1366 | !ctx->Shader.CurrentFragmentProgram && |
||
1367 | ctx->DrawBuffer->_NumColorDrawBuffers == 1 && |
||
1368 | !ctx->Query.CondRenderQuery && |
||
1369 | !ctx->Query.CurrentOcclusionObject) { |
||
1370 | struct st_renderbuffer *rbRead, *rbDraw; |
||
1371 | |||
1372 | /* |
||
1373 | * Clip the read region against the src buffer bounds. |
||
1374 | * We'll still allocate a temporary buffer/texture for the original |
||
1375 | * src region size but we'll only read the region which is on-screen. |
||
1376 | * This may mean that we draw garbage pixels into the dest region, but |
||
1377 | * that's expected. |
||
1378 | */ |
||
1379 | readX = srcx; |
||
1380 | readY = srcy; |
||
1381 | readW = width; |
||
1382 | readH = height; |
||
1383 | pack = ctx->DefaultPacking; |
||
1384 | if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) |
||
1385 | return GL_TRUE; /* all done */ |
||
1386 | |||
1387 | /* clip against dest buffer bounds and scissor box */ |
||
1388 | drawX = dstx + pack.SkipPixels; |
||
1389 | drawY = dsty + pack.SkipRows; |
||
1390 | unpack = pack; |
||
1391 | if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) |
||
1392 | return GL_TRUE; /* all done */ |
||
1393 | |||
1394 | readX = readX - pack.SkipPixels + unpack.SkipPixels; |
||
1395 | readY = readY - pack.SkipRows + unpack.SkipRows; |
||
1396 | |||
1397 | drawW = readW; |
||
1398 | drawH = readH; |
||
1399 | |||
1400 | rbRead = st_get_color_read_renderbuffer(ctx); |
||
1401 | rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); |
||
1402 | |||
1403 | /* Flip src/dst position depending on the orientation of buffers. */ |
||
1404 | if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { |
||
1405 | readY = rbRead->Base.Height - readY; |
||
1406 | readH = -readH; |
||
1407 | } |
||
1408 | |||
1409 | if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { |
||
1410 | /* We can't flip the destination for pipe->blit, so we only adjust |
||
1411 | * its position and flip the source. |
||
1412 | */ |
||
1413 | drawY = rbDraw->Base.Height - drawY - drawH; |
||
1414 | readY += readH; |
||
1415 | readH = -readH; |
||
1416 | } |
||
1417 | |||
1418 | if (rbRead != rbDraw || |
||
1419 | !regions_overlap(readX, readY, readX + readW, readY + readH, |
||
1420 | drawX, drawY, drawX + drawW, drawY + drawH)) { |
||
1421 | struct pipe_blit_info blit; |
||
1422 | |||
1423 | memset(&blit, 0, sizeof(blit)); |
||
1424 | blit.src.resource = rbRead->texture; |
||
1425 | blit.src.level = rbRead->rtt_level; |
||
1426 | blit.src.format = rbRead->texture->format; |
||
1427 | blit.src.box.x = readX; |
||
1428 | blit.src.box.y = readY; |
||
1429 | blit.src.box.z = rbRead->rtt_face + rbRead->rtt_slice; |
||
1430 | blit.src.box.width = readW; |
||
1431 | blit.src.box.height = readH; |
||
1432 | blit.src.box.depth = 1; |
||
1433 | blit.dst.resource = rbDraw->texture; |
||
1434 | blit.dst.level = rbDraw->rtt_level; |
||
1435 | blit.dst.format = rbDraw->texture->format; |
||
1436 | blit.dst.box.x = drawX; |
||
1437 | blit.dst.box.y = drawY; |
||
1438 | blit.dst.box.z = rbDraw->rtt_face + rbDraw->rtt_slice; |
||
1439 | blit.dst.box.width = drawW; |
||
1440 | blit.dst.box.height = drawH; |
||
1441 | blit.dst.box.depth = 1; |
||
1442 | blit.mask = PIPE_MASK_RGBA; |
||
1443 | blit.filter = PIPE_TEX_FILTER_NEAREST; |
||
1444 | |||
1445 | if (screen->is_format_supported(screen, blit.src.format, |
||
1446 | blit.src.resource->target, |
||
1447 | blit.src.resource->nr_samples, |
||
1448 | PIPE_BIND_SAMPLER_VIEW) && |
||
1449 | screen->is_format_supported(screen, blit.dst.format, |
||
1450 | blit.dst.resource->target, |
||
1451 | blit.dst.resource->nr_samples, |
||
1452 | PIPE_BIND_RENDER_TARGET)) { |
||
1453 | pipe->blit(pipe, &blit); |
||
1454 | return GL_TRUE; |
||
1455 | } |
||
1456 | } |
||
1457 | } |
||
1458 | |||
1459 | return GL_FALSE; |
||
1460 | } |
||
1461 | |||
1462 | |||
1463 | static void |
||
1464 | st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, |
||
1465 | GLsizei width, GLsizei height, |
||
1466 | GLint dstx, GLint dsty, GLenum type) |
||
1467 | { |
||
1468 | struct st_context *st = st_context(ctx); |
||
1469 | struct pipe_context *pipe = st->pipe; |
||
1470 | struct pipe_screen *screen = pipe->screen; |
||
1471 | struct st_renderbuffer *rbRead; |
||
1472 | void *driver_vp, *driver_fp; |
||
1473 | struct pipe_resource *pt; |
||
1474 | struct pipe_sampler_view *sv[2]; |
||
1475 | int num_sampler_view = 1; |
||
1476 | GLfloat *color; |
||
1477 | enum pipe_format srcFormat; |
||
1478 | unsigned srcBind; |
||
1479 | GLboolean invertTex = GL_FALSE; |
||
1480 | GLint readX, readY, readW, readH; |
||
1481 | struct gl_pixelstore_attrib pack = ctx->DefaultPacking; |
||
1482 | struct st_fp_variant *fpv; |
||
1483 | |||
1484 | st_validate_state(st); |
||
1485 | |||
1486 | if (type == GL_DEPTH_STENCIL) { |
||
1487 | /* XXX make this more efficient */ |
||
1488 | st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_STENCIL); |
||
1489 | st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_DEPTH); |
||
1490 | return; |
||
1491 | } |
||
1492 | |||
1493 | if (type == GL_STENCIL) { |
||
1494 | /* can't use texturing to do stencil */ |
||
1495 | copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); |
||
1496 | return; |
||
1497 | } |
||
1498 | |||
1499 | if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) |
||
1500 | return; |
||
1501 | |||
1502 | /* |
||
1503 | * The subsequent code implements glCopyPixels by copying the source |
||
1504 | * pixels into a temporary texture that's then applied to a textured quad. |
||
1505 | * When we draw the textured quad, all the usual per-fragment operations |
||
1506 | * are handled. |
||
1507 | */ |
||
1508 | |||
1509 | |||
1510 | /* |
||
1511 | * Get vertex/fragment shaders |
||
1512 | */ |
||
1513 | if (type == GL_COLOR) { |
||
1514 | rbRead = st_get_color_read_renderbuffer(ctx); |
||
1515 | color = NULL; |
||
1516 | |||
1517 | fpv = get_color_fp_variant(st); |
||
1518 | driver_fp = fpv->driver_shader; |
||
1519 | |||
1520 | driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); |
||
1521 | |||
1522 | if (st->pixel_xfer.pixelmap_enabled) { |
||
1523 | sv[1] = st->pixel_xfer.pixelmap_sampler_view; |
||
1524 | num_sampler_view++; |
||
1525 | } |
||
1526 | } |
||
1527 | else { |
||
1528 | assert(type == GL_DEPTH); |
||
1529 | rbRead = st_renderbuffer(ctx->ReadBuffer-> |
||
1530 | Attachment[BUFFER_DEPTH].Renderbuffer); |
||
1531 | color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; |
||
1532 | |||
1533 | fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); |
||
1534 | driver_fp = fpv->driver_shader; |
||
1535 | |||
1536 | driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); |
||
1537 | } |
||
1538 | |||
1539 | /* update fragment program constants */ |
||
1540 | st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); |
||
1541 | |||
1542 | /* Choose the format for the temporary texture. */ |
||
1543 | srcFormat = rbRead->texture->format; |
||
1544 | srcBind = PIPE_BIND_SAMPLER_VIEW | |
||
1545 | (type == GL_COLOR ? PIPE_BIND_RENDER_TARGET : PIPE_BIND_DEPTH_STENCIL); |
||
1546 | |||
1547 | if (!screen->is_format_supported(screen, srcFormat, st->internal_target, 0, |
||
1548 | srcBind)) { |
||
1549 | /* srcFormat is non-renderable. Find a compatible renderable format. */ |
||
1550 | if (type == GL_DEPTH) { |
||
1551 | srcFormat = st_choose_format(st, GL_DEPTH_COMPONENT, GL_NONE, |
||
1552 | GL_NONE, st->internal_target, 0, |
||
1553 | srcBind, FALSE); |
||
1554 | } |
||
1555 | else { |
||
1556 | assert(type == GL_COLOR); |
||
1557 | |||
1558 | if (util_format_is_float(srcFormat)) { |
||
1559 | srcFormat = st_choose_format(st, GL_RGBA32F, GL_NONE, |
||
1560 | GL_NONE, st->internal_target, 0, |
||
1561 | srcBind, FALSE); |
||
1562 | } |
||
1563 | else if (util_format_is_pure_sint(srcFormat)) { |
||
1564 | srcFormat = st_choose_format(st, GL_RGBA32I, GL_NONE, |
||
1565 | GL_NONE, st->internal_target, 0, |
||
1566 | srcBind, FALSE); |
||
1567 | } |
||
1568 | else if (util_format_is_pure_uint(srcFormat)) { |
||
1569 | srcFormat = st_choose_format(st, GL_RGBA32UI, GL_NONE, |
||
1570 | GL_NONE, st->internal_target, 0, |
||
1571 | srcBind, FALSE); |
||
1572 | } |
||
1573 | else if (util_format_is_snorm(srcFormat)) { |
||
1574 | srcFormat = st_choose_format(st, GL_RGBA16_SNORM, GL_NONE, |
||
1575 | GL_NONE, st->internal_target, 0, |
||
1576 | srcBind, FALSE); |
||
1577 | } |
||
1578 | else { |
||
1579 | srcFormat = st_choose_format(st, GL_RGBA, GL_NONE, |
||
1580 | GL_NONE, st->internal_target, 0, |
||
1581 | srcBind, FALSE); |
||
1582 | } |
||
1583 | } |
||
1584 | |||
1585 | if (srcFormat == PIPE_FORMAT_NONE) { |
||
1586 | assert(0 && "cannot choose a format for src of CopyPixels"); |
||
1587 | return; |
||
1588 | } |
||
1589 | } |
||
1590 | |||
1591 | /* Invert src region if needed */ |
||
1592 | if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { |
||
1593 | srcy = ctx->ReadBuffer->Height - srcy - height; |
||
1594 | invertTex = !invertTex; |
||
1595 | } |
||
1596 | |||
1597 | /* Clip the read region against the src buffer bounds. |
||
1598 | * We'll still allocate a temporary buffer/texture for the original |
||
1599 | * src region size but we'll only read the region which is on-screen. |
||
1600 | * This may mean that we draw garbage pixels into the dest region, but |
||
1601 | * that's expected. |
||
1602 | */ |
||
1603 | readX = srcx; |
||
1604 | readY = srcy; |
||
1605 | readW = width; |
||
1606 | readH = height; |
||
1607 | if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) { |
||
1608 | /* The source region is completely out of bounds. Do nothing. |
||
1609 | * The GL spec says "Results of copies from outside the window, |
||
1610 | * or from regions of the window that are not exposed, are |
||
1611 | * hardware dependent and undefined." |
||
1612 | */ |
||
1613 | return; |
||
1614 | } |
||
1615 | |||
1616 | readW = MAX2(0, readW); |
||
1617 | readH = MAX2(0, readH); |
||
1618 | |||
1619 | /* Allocate the temporary texture. */ |
||
1620 | pt = alloc_texture(st, width, height, srcFormat, srcBind); |
||
1621 | if (!pt) |
||
1622 | return; |
||
1623 | |||
1624 | sv[0] = st_create_texture_sampler_view(st->pipe, pt); |
||
1625 | if (!sv[0]) { |
||
1626 | pipe_resource_reference(&pt, NULL); |
||
1627 | return; |
||
1628 | } |
||
1629 | |||
1630 | /* Copy the src region to the temporary texture. */ |
||
1631 | { |
||
1632 | struct pipe_blit_info blit; |
||
1633 | |||
1634 | memset(&blit, 0, sizeof(blit)); |
||
1635 | blit.src.resource = rbRead->texture; |
||
1636 | blit.src.level = rbRead->rtt_level; |
||
1637 | blit.src.format = rbRead->texture->format; |
||
1638 | blit.src.box.x = readX; |
||
1639 | blit.src.box.y = readY; |
||
1640 | blit.src.box.z = rbRead->rtt_face + rbRead->rtt_slice; |
||
1641 | blit.src.box.width = readW; |
||
1642 | blit.src.box.height = readH; |
||
1643 | blit.src.box.depth = 1; |
||
1644 | blit.dst.resource = pt; |
||
1645 | blit.dst.level = 0; |
||
1646 | blit.dst.format = pt->format; |
||
1647 | blit.dst.box.x = pack.SkipPixels; |
||
1648 | blit.dst.box.y = pack.SkipRows; |
||
1649 | blit.dst.box.z = 0; |
||
1650 | blit.dst.box.width = readW; |
||
1651 | blit.dst.box.height = readH; |
||
1652 | blit.dst.box.depth = 1; |
||
1653 | blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S; |
||
1654 | blit.filter = PIPE_TEX_FILTER_NEAREST; |
||
1655 | |||
1656 | pipe->blit(pipe, &blit); |
||
1657 | } |
||
1658 | |||
1659 | /* OK, the texture 'pt' contains the src image/pixels. Now draw a |
||
1660 | * textured quad with that texture. |
||
1661 | */ |
||
1662 | draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], |
||
1663 | width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, |
||
1664 | sv, |
||
1665 | num_sampler_view, |
||
1666 | driver_vp, |
||
1667 | driver_fp, |
||
1668 | color, invertTex, GL_FALSE, GL_FALSE); |
||
1669 | |||
1670 | pipe_resource_reference(&pt, NULL); |
||
1671 | pipe_sampler_view_reference(&sv[0], NULL); |
||
1672 | } |
||
1673 | |||
1674 | |||
1675 | |||
1676 | void st_init_drawpixels_functions(struct dd_function_table *functions) |
||
1677 | { |
||
1678 | functions->DrawPixels = st_DrawPixels; |
||
1679 | functions->CopyPixels = st_CopyPixels; |
||
1680 | } |
||
1681 | |||
1682 | |||
1683 | void |
||
1684 | st_destroy_drawpix(struct st_context *st) |
||
1685 | { |
||
1686 | GLuint i; |
||
1687 | |||
1688 | for (i = 0; i < Elements(st->drawpix.shaders); i++) { |
||
1689 | if (st->drawpix.shaders[i]) |
||
1690 | _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); |
||
1691 | } |
||
1692 | |||
1693 | st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); |
||
1694 | if (st->drawpix.vert_shaders[0]) |
||
1695 | cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[0]); |
||
1696 | if (st->drawpix.vert_shaders[1]) |
||
1697 | cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[1]); |
||
1698 | }>>>>>>>>><>>>>><>>><>>><>>><>>=>=>><>>>><>> |