Rev 4358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 2009 VMware, Inc. 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 "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | */ |
||
24 | |||
25 | /** |
||
26 | * Meta operations. Some GL operations can be expressed in terms of |
||
27 | * other GL operations. For example, glBlitFramebuffer() can be done |
||
28 | * with texture mapping and glClear() can be done with polygon rendering. |
||
29 | * |
||
30 | * \author Brian Paul |
||
31 | */ |
||
32 | |||
33 | |||
34 | #include "main/glheader.h" |
||
35 | #include "main/mtypes.h" |
||
36 | #include "main/imports.h" |
||
37 | #include "main/arbprogram.h" |
||
38 | #include "main/arrayobj.h" |
||
39 | #include "main/blend.h" |
||
40 | #include "main/bufferobj.h" |
||
41 | #include "main/buffers.h" |
||
42 | #include "main/colortab.h" |
||
43 | #include "main/condrender.h" |
||
44 | #include "main/depth.h" |
||
45 | #include "main/enable.h" |
||
46 | #include "main/fbobject.h" |
||
47 | #include "main/feedback.h" |
||
48 | #include "main/formats.h" |
||
49 | #include "main/glformats.h" |
||
50 | #include "main/image.h" |
||
51 | #include "main/macros.h" |
||
52 | #include "main/matrix.h" |
||
53 | #include "main/mipmap.h" |
||
54 | #include "main/pixel.h" |
||
55 | #include "main/pbo.h" |
||
56 | #include "main/polygon.h" |
||
57 | #include "main/queryobj.h" |
||
58 | #include "main/readpix.h" |
||
59 | #include "main/scissor.h" |
||
60 | #include "main/shaderapi.h" |
||
61 | #include "main/shaderobj.h" |
||
62 | #include "main/state.h" |
||
63 | #include "main/stencil.h" |
||
64 | #include "main/texobj.h" |
||
65 | #include "main/texenv.h" |
||
66 | #include "main/texgetimage.h" |
||
67 | #include "main/teximage.h" |
||
68 | #include "main/texparam.h" |
||
69 | #include "main/texstate.h" |
||
70 | #include "main/transformfeedback.h" |
||
71 | #include "main/uniforms.h" |
||
72 | #include "main/varray.h" |
||
73 | #include "main/viewport.h" |
||
74 | #include "main/samplerobj.h" |
||
75 | #include "program/program.h" |
||
76 | #include "swrast/swrast.h" |
||
77 | #include "drivers/common/meta.h" |
||
78 | #include "main/enums.h" |
||
79 | #include "main/glformats.h" |
||
80 | #include "../glsl/ralloc.h" |
||
81 | |||
82 | /** Return offset in bytes of the field within a vertex struct */ |
||
83 | #define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD)) |
||
84 | |||
85 | /** |
||
86 | * State which we may save/restore across meta ops. |
||
87 | * XXX this may be incomplete... |
||
88 | */ |
||
89 | struct save_state |
||
90 | { |
||
91 | GLbitfield SavedState; /**< bitmask of MESA_META_* flags */ |
||
92 | |||
93 | /** MESA_META_CLEAR (and others?) */ |
||
94 | struct gl_query_object *CurrentOcclusionObject; |
||
95 | |||
96 | /** MESA_META_ALPHA_TEST */ |
||
97 | GLboolean AlphaEnabled; |
||
98 | GLenum AlphaFunc; |
||
99 | GLclampf AlphaRef; |
||
100 | |||
101 | /** MESA_META_BLEND */ |
||
102 | GLbitfield BlendEnabled; |
||
103 | GLboolean ColorLogicOpEnabled; |
||
104 | |||
105 | /** MESA_META_COLOR_MASK */ |
||
106 | GLubyte ColorMask[MAX_DRAW_BUFFERS][4]; |
||
107 | |||
108 | /** MESA_META_DEPTH_TEST */ |
||
109 | struct gl_depthbuffer_attrib Depth; |
||
110 | |||
111 | /** MESA_META_FOG */ |
||
112 | GLboolean Fog; |
||
113 | |||
114 | /** MESA_META_PIXEL_STORE */ |
||
115 | struct gl_pixelstore_attrib Pack, Unpack; |
||
116 | |||
117 | /** MESA_META_PIXEL_TRANSFER */ |
||
118 | GLfloat RedBias, RedScale; |
||
119 | GLfloat GreenBias, GreenScale; |
||
120 | GLfloat BlueBias, BlueScale; |
||
121 | GLfloat AlphaBias, AlphaScale; |
||
122 | GLfloat DepthBias, DepthScale; |
||
123 | GLboolean MapColorFlag; |
||
124 | |||
125 | /** MESA_META_RASTERIZATION */ |
||
126 | GLenum FrontPolygonMode, BackPolygonMode; |
||
127 | GLboolean PolygonOffset; |
||
128 | GLboolean PolygonSmooth; |
||
129 | GLboolean PolygonStipple; |
||
130 | GLboolean PolygonCull; |
||
131 | |||
132 | /** MESA_META_SCISSOR */ |
||
133 | struct gl_scissor_attrib Scissor; |
||
134 | |||
135 | /** MESA_META_SHADER */ |
||
136 | GLboolean VertexProgramEnabled; |
||
137 | struct gl_vertex_program *VertexProgram; |
||
138 | GLboolean FragmentProgramEnabled; |
||
139 | struct gl_fragment_program *FragmentProgram; |
||
140 | GLboolean ATIFragmentShaderEnabled; |
||
141 | struct gl_shader_program *VertexShader; |
||
142 | struct gl_shader_program *GeometryShader; |
||
143 | struct gl_shader_program *FragmentShader; |
||
144 | struct gl_shader_program *ActiveShader; |
||
145 | |||
146 | /** MESA_META_STENCIL_TEST */ |
||
147 | struct gl_stencil_attrib Stencil; |
||
148 | |||
149 | /** MESA_META_TRANSFORM */ |
||
150 | GLenum MatrixMode; |
||
151 | GLfloat ModelviewMatrix[16]; |
||
152 | GLfloat ProjectionMatrix[16]; |
||
153 | GLfloat TextureMatrix[16]; |
||
154 | |||
155 | /** MESA_META_CLIP */ |
||
156 | GLbitfield ClipPlanesEnabled; |
||
157 | |||
158 | /** MESA_META_TEXTURE */ |
||
159 | GLuint ActiveUnit; |
||
160 | GLuint ClientActiveUnit; |
||
161 | /** for unit[0] only */ |
||
162 | struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS]; |
||
163 | /** mask of TEXTURE_2D_BIT, etc */ |
||
164 | GLbitfield TexEnabled[MAX_TEXTURE_UNITS]; |
||
165 | GLbitfield TexGenEnabled[MAX_TEXTURE_UNITS]; |
||
166 | GLuint EnvMode; /* unit[0] only */ |
||
167 | |||
168 | /** MESA_META_VERTEX */ |
||
169 | struct gl_array_object *ArrayObj; |
||
170 | struct gl_buffer_object *ArrayBufferObj; |
||
171 | |||
172 | /** MESA_META_VIEWPORT */ |
||
173 | GLint ViewportX, ViewportY, ViewportW, ViewportH; |
||
174 | GLclampd DepthNear, DepthFar; |
||
175 | |||
176 | /** MESA_META_CLAMP_FRAGMENT_COLOR */ |
||
177 | GLenum ClampFragmentColor; |
||
178 | |||
179 | /** MESA_META_CLAMP_VERTEX_COLOR */ |
||
180 | GLenum ClampVertexColor; |
||
181 | |||
182 | /** MESA_META_CONDITIONAL_RENDER */ |
||
183 | struct gl_query_object *CondRenderQuery; |
||
184 | GLenum CondRenderMode; |
||
185 | |||
186 | /** MESA_META_SELECT_FEEDBACK */ |
||
187 | GLenum RenderMode; |
||
188 | struct gl_selection Select; |
||
189 | struct gl_feedback Feedback; |
||
190 | |||
191 | /** MESA_META_MULTISAMPLE */ |
||
192 | GLboolean MultisampleEnabled; |
||
193 | |||
194 | /** MESA_META_FRAMEBUFFER_SRGB */ |
||
195 | GLboolean sRGBEnabled; |
||
196 | |||
197 | /** Miscellaneous (always disabled) */ |
||
198 | GLboolean Lighting; |
||
199 | GLboolean RasterDiscard; |
||
200 | GLboolean TransformFeedbackNeedsResume; |
||
201 | }; |
||
202 | |||
203 | /** |
||
204 | * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. |
||
205 | * This is currently shared by all the meta ops. But we could create a |
||
206 | * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. |
||
207 | */ |
||
208 | struct temp_texture |
||
209 | { |
||
210 | GLuint TexObj; |
||
211 | GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ |
||
212 | GLsizei MinSize; /**< Min texture size to allocate */ |
||
213 | GLsizei MaxSize; /**< Max possible texture size */ |
||
214 | GLboolean NPOT; /**< Non-power of two size OK? */ |
||
215 | GLsizei Width, Height; /**< Current texture size */ |
||
216 | GLenum IntFormat; |
||
217 | GLfloat Sright, Ttop; /**< right, top texcoords */ |
||
218 | }; |
||
219 | |||
220 | |||
221 | /** |
||
222 | * State for glBlitFramebufer() |
||
223 | */ |
||
224 | struct blit_state |
||
225 | { |
||
226 | GLuint ArrayObj; |
||
227 | GLuint VBO; |
||
228 | GLuint DepthFP; |
||
229 | GLuint ShaderProg; |
||
230 | GLuint RectShaderProg; |
||
231 | struct temp_texture depthTex; |
||
232 | }; |
||
233 | |||
234 | |||
235 | /** |
||
236 | * State for glClear() |
||
237 | */ |
||
238 | struct clear_state |
||
239 | { |
||
240 | GLuint ArrayObj; |
||
241 | GLuint VBO; |
||
242 | GLuint ShaderProg; |
||
243 | GLint ColorLocation; |
||
244 | |||
245 | GLuint IntegerShaderProg; |
||
246 | GLint IntegerColorLocation; |
||
247 | }; |
||
248 | |||
249 | |||
250 | /** |
||
251 | * State for glCopyPixels() |
||
252 | */ |
||
253 | struct copypix_state |
||
254 | { |
||
255 | GLuint ArrayObj; |
||
256 | GLuint VBO; |
||
257 | }; |
||
258 | |||
259 | |||
260 | /** |
||
261 | * State for glDrawPixels() |
||
262 | */ |
||
263 | struct drawpix_state |
||
264 | { |
||
265 | GLuint ArrayObj; |
||
266 | |||
267 | GLuint StencilFP; /**< Fragment program for drawing stencil images */ |
||
268 | GLuint DepthFP; /**< Fragment program for drawing depth images */ |
||
269 | }; |
||
270 | |||
271 | |||
272 | /** |
||
273 | * State for glBitmap() |
||
274 | */ |
||
275 | struct bitmap_state |
||
276 | { |
||
277 | GLuint ArrayObj; |
||
278 | GLuint VBO; |
||
279 | struct temp_texture Tex; /**< separate texture from other meta ops */ |
||
280 | }; |
||
281 | |||
282 | /** |
||
283 | * State for GLSL texture sampler which is used to generate fragment |
||
284 | * shader in _mesa_meta_generate_mipmap(). |
||
285 | */ |
||
286 | struct glsl_sampler { |
||
287 | const char *type; |
||
288 | const char *func; |
||
289 | const char *texcoords; |
||
290 | GLuint shader_prog; |
||
291 | }; |
||
292 | |||
293 | /** |
||
294 | * State for _mesa_meta_generate_mipmap() |
||
295 | */ |
||
296 | struct gen_mipmap_state |
||
297 | { |
||
298 | GLuint ArrayObj; |
||
299 | GLuint VBO; |
||
300 | GLuint FBO; |
||
301 | GLuint Sampler; |
||
302 | GLuint ShaderProg; |
||
303 | struct glsl_sampler sampler_1d; |
||
304 | struct glsl_sampler sampler_2d; |
||
305 | struct glsl_sampler sampler_3d; |
||
306 | struct glsl_sampler sampler_cubemap; |
||
307 | struct glsl_sampler sampler_1d_array; |
||
308 | struct glsl_sampler sampler_2d_array; |
||
309 | }; |
||
310 | |||
311 | /** |
||
312 | * State for texture decompression |
||
313 | */ |
||
314 | struct decompress_state |
||
315 | { |
||
316 | GLuint ArrayObj; |
||
317 | GLuint VBO, FBO, RBO, Sampler; |
||
318 | GLint Width, Height; |
||
319 | }; |
||
320 | |||
321 | /** |
||
322 | * State for glDrawTex() |
||
323 | */ |
||
324 | struct drawtex_state |
||
325 | { |
||
326 | GLuint ArrayObj; |
||
327 | GLuint VBO; |
||
328 | }; |
||
329 | |||
330 | #define MAX_META_OPS_DEPTH 8 |
||
331 | /** |
||
332 | * All per-context meta state. |
||
333 | */ |
||
334 | struct gl_meta_state |
||
335 | { |
||
336 | /** Stack of state saved during meta-ops */ |
||
337 | struct save_state Save[MAX_META_OPS_DEPTH]; |
||
338 | /** Save stack depth */ |
||
339 | GLuint SaveStackDepth; |
||
340 | |||
341 | struct temp_texture TempTex; |
||
342 | |||
343 | struct blit_state Blit; /**< For _mesa_meta_BlitFramebuffer() */ |
||
344 | struct clear_state Clear; /**< For _mesa_meta_Clear() */ |
||
345 | struct copypix_state CopyPix; /**< For _mesa_meta_CopyPixels() */ |
||
346 | struct drawpix_state DrawPix; /**< For _mesa_meta_DrawPixels() */ |
||
347 | struct bitmap_state Bitmap; /**< For _mesa_meta_Bitmap() */ |
||
348 | struct gen_mipmap_state Mipmap; /**< For _mesa_meta_GenerateMipmap() */ |
||
349 | struct decompress_state Decompress; /**< For texture decompression */ |
||
350 | struct drawtex_state DrawTex; /**< For _mesa_meta_DrawTex() */ |
||
351 | }; |
||
352 | |||
353 | static void meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit); |
||
354 | static void cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex); |
||
355 | static void meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear); |
||
356 | static void meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, |
||
357 | struct gen_mipmap_state *mipmap); |
||
358 | |||
359 | static GLuint |
||
360 | compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB *source) |
||
361 | { |
||
362 | GLuint shader; |
||
363 | GLint ok, size; |
||
364 | GLchar *info; |
||
365 | |||
366 | shader = _mesa_CreateShaderObjectARB(target); |
||
367 | _mesa_ShaderSource(shader, 1, &source, NULL); |
||
368 | _mesa_CompileShader(shader); |
||
369 | |||
370 | _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &ok); |
||
371 | if (ok) |
||
372 | return shader; |
||
373 | |||
374 | _mesa_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); |
||
375 | if (size == 0) { |
||
376 | _mesa_DeleteObjectARB(shader); |
||
377 | return 0; |
||
378 | } |
||
379 | |||
380 | info = malloc(size); |
||
381 | if (!info) { |
||
382 | _mesa_DeleteObjectARB(shader); |
||
383 | return 0; |
||
384 | } |
||
385 | |||
386 | _mesa_GetProgramInfoLog(shader, size, NULL, info); |
||
387 | _mesa_problem(ctx, |
||
388 | "meta program compile failed:\n%s\n" |
||
389 | "source:\n%s\n", |
||
390 | info, source); |
||
391 | |||
392 | free(info); |
||
393 | _mesa_DeleteObjectARB(shader); |
||
394 | |||
395 | return 0; |
||
396 | } |
||
397 | |||
398 | static GLuint |
||
399 | link_program_with_debug(struct gl_context *ctx, GLuint program) |
||
400 | { |
||
401 | GLint ok, size; |
||
402 | GLchar *info; |
||
403 | |||
404 | _mesa_LinkProgram(program); |
||
405 | |||
406 | _mesa_GetProgramiv(program, GL_LINK_STATUS, &ok); |
||
407 | if (ok) |
||
408 | return program; |
||
409 | |||
410 | _mesa_GetProgramiv(program, GL_INFO_LOG_LENGTH, &size); |
||
411 | if (size == 0) |
||
412 | return 0; |
||
413 | |||
414 | info = malloc(size); |
||
415 | if (!info) |
||
416 | return 0; |
||
417 | |||
418 | _mesa_GetProgramInfoLog(program, size, NULL, info); |
||
419 | _mesa_problem(ctx, "meta program link failed:\n%s", info); |
||
420 | |||
421 | free(info); |
||
422 | |||
423 | return 0; |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * Initialize meta-ops for a context. |
||
428 | * To be called once during context creation. |
||
429 | */ |
||
430 | void |
||
431 | _mesa_meta_init(struct gl_context *ctx) |
||
432 | { |
||
433 | ASSERT(!ctx->Meta); |
||
434 | |||
435 | ctx->Meta = CALLOC_STRUCT(gl_meta_state); |
||
436 | } |
||
437 | |||
438 | |||
439 | /** |
||
440 | * Free context meta-op state. |
||
441 | * To be called once during context destruction. |
||
442 | */ |
||
443 | void |
||
444 | _mesa_meta_free(struct gl_context *ctx) |
||
445 | { |
||
446 | GET_CURRENT_CONTEXT(old_context); |
||
447 | _mesa_make_current(ctx, NULL, NULL); |
||
448 | meta_glsl_blit_cleanup(ctx, &ctx->Meta->Blit); |
||
449 | meta_glsl_clear_cleanup(ctx, &ctx->Meta->Clear); |
||
450 | meta_glsl_generate_mipmap_cleanup(ctx, &ctx->Meta->Mipmap); |
||
451 | cleanup_temp_texture(ctx, &ctx->Meta->TempTex); |
||
452 | if (old_context) |
||
453 | _mesa_make_current(old_context, old_context->WinSysDrawBuffer, old_context->WinSysReadBuffer); |
||
454 | else |
||
455 | _mesa_make_current(NULL, NULL, NULL); |
||
456 | free(ctx->Meta); |
||
457 | ctx->Meta = NULL; |
||
458 | } |
||
459 | |||
460 | |||
461 | /** |
||
462 | * Enter meta state. This is like a light-weight version of glPushAttrib |
||
463 | * but it also resets most GL state back to default values. |
||
464 | * |
||
465 | * \param state bitmask of MESA_META_* flags indicating which attribute groups |
||
466 | * to save and reset to their defaults |
||
467 | */ |
||
468 | void |
||
469 | _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) |
||
470 | { |
||
471 | struct save_state *save; |
||
472 | |||
473 | /* hope MAX_META_OPS_DEPTH is large enough */ |
||
474 | assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH); |
||
475 | |||
476 | save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++]; |
||
477 | memset(save, 0, sizeof(*save)); |
||
478 | save->SavedState = state; |
||
479 | |||
480 | /* Pausing transform feedback needs to be done early, or else we won't be |
||
481 | * able to change other state. |
||
482 | */ |
||
483 | save->TransformFeedbackNeedsResume = |
||
484 | _mesa_is_xfb_active_and_unpaused(ctx); |
||
485 | if (save->TransformFeedbackNeedsResume) |
||
486 | _mesa_PauseTransformFeedback(); |
||
487 | |||
488 | /* After saving the current occlusion object, call EndQuery so that no |
||
489 | * occlusion querying will be active during the meta-operation. |
||
490 | */ |
||
491 | if (state & MESA_META_OCCLUSION_QUERY) { |
||
492 | save->CurrentOcclusionObject = ctx->Query.CurrentOcclusionObject; |
||
493 | if (save->CurrentOcclusionObject) |
||
494 | _mesa_EndQuery(save->CurrentOcclusionObject->Target); |
||
495 | } |
||
496 | |||
497 | if (state & MESA_META_ALPHA_TEST) { |
||
498 | save->AlphaEnabled = ctx->Color.AlphaEnabled; |
||
499 | save->AlphaFunc = ctx->Color.AlphaFunc; |
||
500 | save->AlphaRef = ctx->Color.AlphaRef; |
||
501 | if (ctx->Color.AlphaEnabled) |
||
502 | _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE); |
||
503 | } |
||
504 | |||
505 | if (state & MESA_META_BLEND) { |
||
506 | save->BlendEnabled = ctx->Color.BlendEnabled; |
||
507 | if (ctx->Color.BlendEnabled) { |
||
508 | if (ctx->Extensions.EXT_draw_buffers2) { |
||
509 | GLuint i; |
||
510 | for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { |
||
511 | _mesa_set_enablei(ctx, GL_BLEND, i, GL_FALSE); |
||
512 | } |
||
513 | } |
||
514 | else { |
||
515 | _mesa_set_enable(ctx, GL_BLEND, GL_FALSE); |
||
516 | } |
||
517 | } |
||
518 | save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled; |
||
519 | if (ctx->Color.ColorLogicOpEnabled) |
||
520 | _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE); |
||
521 | } |
||
522 | |||
523 | if (state & MESA_META_COLOR_MASK) { |
||
524 | memcpy(save->ColorMask, ctx->Color.ColorMask, |
||
525 | sizeof(ctx->Color.ColorMask)); |
||
526 | if (!ctx->Color.ColorMask[0][0] || |
||
527 | !ctx->Color.ColorMask[0][1] || |
||
528 | !ctx->Color.ColorMask[0][2] || |
||
529 | !ctx->Color.ColorMask[0][3]) |
||
530 | _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
||
531 | } |
||
532 | |||
533 | if (state & MESA_META_DEPTH_TEST) { |
||
534 | save->Depth = ctx->Depth; /* struct copy */ |
||
535 | if (ctx->Depth.Test) |
||
536 | _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); |
||
537 | } |
||
538 | |||
539 | if ((state & MESA_META_FOG) |
||
540 | && ctx->API != API_OPENGL_CORE |
||
541 | && ctx->API != API_OPENGLES2) { |
||
542 | save->Fog = ctx->Fog.Enabled; |
||
543 | if (ctx->Fog.Enabled) |
||
544 | _mesa_set_enable(ctx, GL_FOG, GL_FALSE); |
||
545 | } |
||
546 | |||
547 | if (state & MESA_META_PIXEL_STORE) { |
||
548 | save->Pack = ctx->Pack; |
||
549 | save->Unpack = ctx->Unpack; |
||
550 | ctx->Pack = ctx->DefaultPacking; |
||
551 | ctx->Unpack = ctx->DefaultPacking; |
||
552 | } |
||
553 | |||
554 | if (state & MESA_META_PIXEL_TRANSFER) { |
||
555 | save->RedScale = ctx->Pixel.RedScale; |
||
556 | save->RedBias = ctx->Pixel.RedBias; |
||
557 | save->GreenScale = ctx->Pixel.GreenScale; |
||
558 | save->GreenBias = ctx->Pixel.GreenBias; |
||
559 | save->BlueScale = ctx->Pixel.BlueScale; |
||
560 | save->BlueBias = ctx->Pixel.BlueBias; |
||
561 | save->AlphaScale = ctx->Pixel.AlphaScale; |
||
562 | save->AlphaBias = ctx->Pixel.AlphaBias; |
||
563 | save->MapColorFlag = ctx->Pixel.MapColorFlag; |
||
564 | ctx->Pixel.RedScale = 1.0F; |
||
565 | ctx->Pixel.RedBias = 0.0F; |
||
566 | ctx->Pixel.GreenScale = 1.0F; |
||
567 | ctx->Pixel.GreenBias = 0.0F; |
||
568 | ctx->Pixel.BlueScale = 1.0F; |
||
569 | ctx->Pixel.BlueBias = 0.0F; |
||
570 | ctx->Pixel.AlphaScale = 1.0F; |
||
571 | ctx->Pixel.AlphaBias = 0.0F; |
||
572 | ctx->Pixel.MapColorFlag = GL_FALSE; |
||
573 | /* XXX more state */ |
||
574 | ctx->NewState |=_NEW_PIXEL; |
||
575 | } |
||
576 | |||
577 | if (state & MESA_META_RASTERIZATION) { |
||
578 | save->FrontPolygonMode = ctx->Polygon.FrontMode; |
||
579 | save->BackPolygonMode = ctx->Polygon.BackMode; |
||
580 | save->PolygonOffset = ctx->Polygon.OffsetFill; |
||
581 | save->PolygonSmooth = ctx->Polygon.SmoothFlag; |
||
582 | save->PolygonStipple = ctx->Polygon.StippleFlag; |
||
583 | save->PolygonCull = ctx->Polygon.CullFlag; |
||
584 | _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
||
585 | _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE); |
||
586 | if (ctx->API == API_OPENGL_COMPAT) { |
||
587 | _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); |
||
588 | _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); |
||
589 | } |
||
590 | _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE); |
||
591 | } |
||
592 | |||
593 | if (state & MESA_META_SCISSOR) { |
||
594 | save->Scissor = ctx->Scissor; /* struct copy */ |
||
595 | _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); |
||
596 | } |
||
597 | |||
598 | if (state & MESA_META_SHADER) { |
||
599 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) { |
||
600 | save->VertexProgramEnabled = ctx->VertexProgram.Enabled; |
||
601 | _mesa_reference_vertprog(ctx, &save->VertexProgram, |
||
602 | ctx->VertexProgram.Current); |
||
603 | _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE); |
||
604 | } |
||
605 | |||
606 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) { |
||
607 | save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled; |
||
608 | _mesa_reference_fragprog(ctx, &save->FragmentProgram, |
||
609 | ctx->FragmentProgram.Current); |
||
610 | _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE); |
||
611 | } |
||
612 | |||
613 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) { |
||
614 | save->ATIFragmentShaderEnabled = ctx->ATIFragmentShader.Enabled; |
||
615 | _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, GL_FALSE); |
||
616 | } |
||
617 | |||
618 | _mesa_reference_shader_program(ctx, &save->VertexShader, |
||
619 | ctx->Shader.CurrentVertexProgram); |
||
620 | _mesa_reference_shader_program(ctx, &save->GeometryShader, |
||
621 | ctx->Shader.CurrentGeometryProgram); |
||
622 | _mesa_reference_shader_program(ctx, &save->FragmentShader, |
||
623 | ctx->Shader.CurrentFragmentProgram); |
||
624 | _mesa_reference_shader_program(ctx, &save->ActiveShader, |
||
625 | ctx->Shader.ActiveProgram); |
||
626 | |||
627 | _mesa_UseProgram(0); |
||
628 | } |
||
629 | |||
630 | if (state & MESA_META_STENCIL_TEST) { |
||
631 | save->Stencil = ctx->Stencil; /* struct copy */ |
||
632 | if (ctx->Stencil.Enabled) |
||
633 | _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); |
||
634 | /* NOTE: other stencil state not reset */ |
||
635 | } |
||
636 | |||
637 | if (state & MESA_META_TEXTURE) { |
||
638 | GLuint u, tgt; |
||
639 | |||
640 | save->ActiveUnit = ctx->Texture.CurrentUnit; |
||
641 | save->ClientActiveUnit = ctx->Array.ActiveTexture; |
||
642 | save->EnvMode = ctx->Texture.Unit[0].EnvMode; |
||
643 | |||
644 | /* Disable all texture units */ |
||
645 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { |
||
646 | for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { |
||
647 | save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; |
||
648 | save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled; |
||
649 | if (ctx->Texture.Unit[u].Enabled || |
||
650 | ctx->Texture.Unit[u].TexGenEnabled) { |
||
651 | _mesa_ActiveTexture(GL_TEXTURE0 + u); |
||
652 | _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); |
||
653 | if (ctx->Extensions.ARB_texture_cube_map) |
||
654 | _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); |
||
655 | if (_mesa_is_gles(ctx) && |
||
656 | ctx->Extensions.OES_EGL_image_external) |
||
657 | _mesa_set_enable(ctx, GL_TEXTURE_EXTERNAL_OES, GL_FALSE); |
||
658 | |||
659 | if (ctx->API == API_OPENGL_COMPAT) { |
||
660 | _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); |
||
661 | _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); |
||
662 | if (ctx->Extensions.NV_texture_rectangle) |
||
663 | _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); |
||
664 | _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); |
||
665 | _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); |
||
666 | _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); |
||
667 | _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); |
||
668 | } else { |
||
669 | _mesa_set_enable(ctx, GL_TEXTURE_GEN_STR_OES, GL_FALSE); |
||
670 | } |
||
671 | } |
||
672 | } |
||
673 | } |
||
674 | |||
675 | /* save current texture objects for unit[0] only */ |
||
676 | for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { |
||
677 | _mesa_reference_texobj(&save->CurrentTexture[tgt], |
||
678 | ctx->Texture.Unit[0].CurrentTex[tgt]); |
||
679 | } |
||
680 | |||
681 | /* set defaults for unit[0] */ |
||
682 | _mesa_ActiveTexture(GL_TEXTURE0); |
||
683 | _mesa_ClientActiveTexture(GL_TEXTURE0); |
||
684 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { |
||
685 | _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
||
686 | } |
||
687 | } |
||
688 | |||
689 | if (state & MESA_META_TRANSFORM) { |
||
690 | GLuint activeTexture = ctx->Texture.CurrentUnit; |
||
691 | memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m, |
||
692 | 16 * sizeof(GLfloat)); |
||
693 | memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m, |
||
694 | 16 * sizeof(GLfloat)); |
||
695 | memcpy(save->TextureMatrix, ctx->TextureMatrixStack[0].Top->m, |
||
696 | 16 * sizeof(GLfloat)); |
||
697 | save->MatrixMode = ctx->Transform.MatrixMode; |
||
698 | /* set 1:1 vertex:pixel coordinate transform */ |
||
699 | _mesa_ActiveTexture(GL_TEXTURE0); |
||
700 | _mesa_MatrixMode(GL_TEXTURE); |
||
701 | _mesa_LoadIdentity(); |
||
702 | _mesa_ActiveTexture(GL_TEXTURE0 + activeTexture); |
||
703 | _mesa_MatrixMode(GL_MODELVIEW); |
||
704 | _mesa_LoadIdentity(); |
||
705 | _mesa_MatrixMode(GL_PROJECTION); |
||
706 | _mesa_LoadIdentity(); |
||
707 | |||
708 | /* glOrtho with width = 0 or height = 0 generates GL_INVALID_VALUE. |
||
709 | * This can occur when there is no draw buffer. |
||
710 | */ |
||
711 | if (ctx->DrawBuffer->Width != 0 && ctx->DrawBuffer->Height != 0) |
||
712 | _mesa_Ortho(0.0, ctx->DrawBuffer->Width, |
||
713 | 0.0, ctx->DrawBuffer->Height, |
||
714 | -1.0, 1.0); |
||
715 | } |
||
716 | |||
717 | if (state & MESA_META_CLIP) { |
||
718 | save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled; |
||
719 | if (ctx->Transform.ClipPlanesEnabled) { |
||
720 | GLuint i; |
||
721 | for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { |
||
722 | _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); |
||
723 | } |
||
724 | } |
||
725 | } |
||
726 | |||
727 | if (state & MESA_META_VERTEX) { |
||
728 | /* save vertex array object state */ |
||
729 | _mesa_reference_array_object(ctx, &save->ArrayObj, |
||
730 | ctx->Array.ArrayObj); |
||
731 | _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, |
||
732 | ctx->Array.ArrayBufferObj); |
||
733 | /* set some default state? */ |
||
734 | } |
||
735 | |||
736 | if (state & MESA_META_VIEWPORT) { |
||
737 | /* save viewport state */ |
||
738 | save->ViewportX = ctx->Viewport.X; |
||
739 | save->ViewportY = ctx->Viewport.Y; |
||
740 | save->ViewportW = ctx->Viewport.Width; |
||
741 | save->ViewportH = ctx->Viewport.Height; |
||
742 | /* set viewport to match window size */ |
||
743 | if (ctx->Viewport.X != 0 || |
||
744 | ctx->Viewport.Y != 0 || |
||
745 | ctx->Viewport.Width != ctx->DrawBuffer->Width || |
||
746 | ctx->Viewport.Height != ctx->DrawBuffer->Height) { |
||
747 | _mesa_set_viewport(ctx, 0, 0, |
||
748 | ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); |
||
749 | } |
||
750 | /* save depth range state */ |
||
751 | save->DepthNear = ctx->Viewport.Near; |
||
752 | save->DepthFar = ctx->Viewport.Far; |
||
753 | /* set depth range to default */ |
||
754 | _mesa_DepthRange(0.0, 1.0); |
||
755 | } |
||
756 | |||
757 | if (state & MESA_META_CLAMP_FRAGMENT_COLOR) { |
||
758 | save->ClampFragmentColor = ctx->Color.ClampFragmentColor; |
||
759 | |||
760 | /* Generally in here we want to do clamping according to whether |
||
761 | * it's for the pixel path (ClampFragmentColor is GL_TRUE), |
||
762 | * regardless of the internal implementation of the metaops. |
||
763 | */ |
||
764 | if (ctx->Color.ClampFragmentColor != GL_TRUE && |
||
765 | ctx->Extensions.ARB_color_buffer_float) |
||
766 | _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); |
||
767 | } |
||
768 | |||
769 | if (state & MESA_META_CLAMP_VERTEX_COLOR) { |
||
770 | save->ClampVertexColor = ctx->Light.ClampVertexColor; |
||
771 | |||
772 | /* Generally in here we never want vertex color clamping -- |
||
773 | * result clamping is only dependent on fragment clamping. |
||
774 | */ |
||
775 | if (ctx->Extensions.ARB_color_buffer_float) |
||
776 | _mesa_ClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE); |
||
777 | } |
||
778 | |||
779 | if (state & MESA_META_CONDITIONAL_RENDER) { |
||
780 | save->CondRenderQuery = ctx->Query.CondRenderQuery; |
||
781 | save->CondRenderMode = ctx->Query.CondRenderMode; |
||
782 | |||
783 | if (ctx->Query.CondRenderQuery) |
||
784 | _mesa_EndConditionalRender(); |
||
785 | } |
||
786 | |||
787 | if (state & MESA_META_SELECT_FEEDBACK) { |
||
788 | save->RenderMode = ctx->RenderMode; |
||
789 | if (ctx->RenderMode == GL_SELECT) { |
||
790 | save->Select = ctx->Select; /* struct copy */ |
||
791 | _mesa_RenderMode(GL_RENDER); |
||
792 | } else if (ctx->RenderMode == GL_FEEDBACK) { |
||
793 | save->Feedback = ctx->Feedback; /* struct copy */ |
||
794 | _mesa_RenderMode(GL_RENDER); |
||
795 | } |
||
796 | } |
||
797 | |||
798 | if (state & MESA_META_MULTISAMPLE) { |
||
799 | save->MultisampleEnabled = ctx->Multisample.Enabled; |
||
800 | if (ctx->Multisample.Enabled) |
||
801 | _mesa_set_multisample(ctx, GL_FALSE); |
||
802 | } |
||
803 | |||
804 | if (state & MESA_META_FRAMEBUFFER_SRGB) { |
||
805 | save->sRGBEnabled = ctx->Color.sRGBEnabled; |
||
806 | if (ctx->Color.sRGBEnabled) |
||
807 | _mesa_set_framebuffer_srgb(ctx, GL_FALSE); |
||
808 | } |
||
809 | |||
810 | /* misc */ |
||
811 | { |
||
812 | save->Lighting = ctx->Light.Enabled; |
||
813 | if (ctx->Light.Enabled) |
||
814 | _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE); |
||
815 | save->RasterDiscard = ctx->RasterDiscard; |
||
816 | if (ctx->RasterDiscard) |
||
817 | _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE); |
||
818 | } |
||
819 | } |
||
820 | |||
821 | |||
822 | /** |
||
823 | * Leave meta state. This is like a light-weight version of glPopAttrib(). |
||
824 | */ |
||
825 | void |
||
826 | _mesa_meta_end(struct gl_context *ctx) |
||
827 | { |
||
828 | struct save_state *save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth - 1]; |
||
829 | const GLbitfield state = save->SavedState; |
||
830 | |||
831 | /* After starting a new occlusion query, initialize the results to the |
||
832 | * values saved previously. The driver will then continue to increment |
||
833 | * these values. |
||
834 | */ |
||
835 | if (state & MESA_META_OCCLUSION_QUERY) { |
||
836 | if (save->CurrentOcclusionObject) { |
||
837 | _mesa_BeginQuery(save->CurrentOcclusionObject->Target, |
||
838 | save->CurrentOcclusionObject->Id); |
||
839 | ctx->Query.CurrentOcclusionObject->Result = save->CurrentOcclusionObject->Result; |
||
840 | } |
||
841 | } |
||
842 | |||
843 | if (state & MESA_META_ALPHA_TEST) { |
||
844 | if (ctx->Color.AlphaEnabled != save->AlphaEnabled) |
||
845 | _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled); |
||
846 | _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef); |
||
847 | } |
||
848 | |||
849 | if (state & MESA_META_BLEND) { |
||
850 | if (ctx->Color.BlendEnabled != save->BlendEnabled) { |
||
851 | if (ctx->Extensions.EXT_draw_buffers2) { |
||
852 | GLuint i; |
||
853 | for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { |
||
854 | _mesa_set_enablei(ctx, GL_BLEND, i, (save->BlendEnabled >> i) & 1); |
||
855 | } |
||
856 | } |
||
857 | else { |
||
858 | _mesa_set_enable(ctx, GL_BLEND, (save->BlendEnabled & 1)); |
||
859 | } |
||
860 | } |
||
861 | if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled) |
||
862 | _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled); |
||
863 | } |
||
864 | |||
865 | if (state & MESA_META_COLOR_MASK) { |
||
866 | GLuint i; |
||
867 | for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { |
||
868 | if (!TEST_EQ_4V(ctx->Color.ColorMask[i], save->ColorMask[i])) { |
||
869 | if (i == 0) { |
||
870 | _mesa_ColorMask(save->ColorMask[i][0], save->ColorMask[i][1], |
||
871 | save->ColorMask[i][2], save->ColorMask[i][3]); |
||
872 | } |
||
873 | else { |
||
874 | _mesa_ColorMaski(i, |
||
875 | save->ColorMask[i][0], |
||
876 | save->ColorMask[i][1], |
||
877 | save->ColorMask[i][2], |
||
878 | save->ColorMask[i][3]); |
||
879 | } |
||
880 | } |
||
881 | } |
||
882 | } |
||
883 | |||
884 | if (state & MESA_META_DEPTH_TEST) { |
||
885 | if (ctx->Depth.Test != save->Depth.Test) |
||
886 | _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test); |
||
887 | _mesa_DepthFunc(save->Depth.Func); |
||
888 | _mesa_DepthMask(save->Depth.Mask); |
||
889 | } |
||
890 | |||
891 | if ((state & MESA_META_FOG) |
||
892 | && ctx->API != API_OPENGL_CORE |
||
893 | && ctx->API != API_OPENGLES2) { |
||
894 | _mesa_set_enable(ctx, GL_FOG, save->Fog); |
||
895 | } |
||
896 | |||
897 | if (state & MESA_META_PIXEL_STORE) { |
||
898 | ctx->Pack = save->Pack; |
||
899 | ctx->Unpack = save->Unpack; |
||
900 | } |
||
901 | |||
902 | if (state & MESA_META_PIXEL_TRANSFER) { |
||
903 | ctx->Pixel.RedScale = save->RedScale; |
||
904 | ctx->Pixel.RedBias = save->RedBias; |
||
905 | ctx->Pixel.GreenScale = save->GreenScale; |
||
906 | ctx->Pixel.GreenBias = save->GreenBias; |
||
907 | ctx->Pixel.BlueScale = save->BlueScale; |
||
908 | ctx->Pixel.BlueBias = save->BlueBias; |
||
909 | ctx->Pixel.AlphaScale = save->AlphaScale; |
||
910 | ctx->Pixel.AlphaBias = save->AlphaBias; |
||
911 | ctx->Pixel.MapColorFlag = save->MapColorFlag; |
||
912 | /* XXX more state */ |
||
913 | ctx->NewState |=_NEW_PIXEL; |
||
914 | } |
||
915 | |||
916 | if (state & MESA_META_RASTERIZATION) { |
||
917 | /* Core context requires that front and back mode be the same. |
||
918 | */ |
||
919 | if (ctx->API == API_OPENGL_CORE) { |
||
920 | _mesa_PolygonMode(GL_FRONT_AND_BACK, save->FrontPolygonMode); |
||
921 | } else { |
||
922 | _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); |
||
923 | _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); |
||
924 | } |
||
925 | if (ctx->API == API_OPENGL_COMPAT) { |
||
926 | _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); |
||
927 | _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); |
||
928 | } |
||
929 | _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset); |
||
930 | _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); |
||
931 | } |
||
932 | |||
933 | if (state & MESA_META_SCISSOR) { |
||
934 | _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled); |
||
935 | _mesa_Scissor(save->Scissor.X, save->Scissor.Y, |
||
936 | save->Scissor.Width, save->Scissor.Height); |
||
937 | } |
||
938 | |||
939 | if (state & MESA_META_SHADER) { |
||
940 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) { |
||
941 | _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, |
||
942 | save->VertexProgramEnabled); |
||
943 | _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, |
||
944 | save->VertexProgram); |
||
945 | _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL); |
||
946 | } |
||
947 | |||
948 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) { |
||
949 | _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, |
||
950 | save->FragmentProgramEnabled); |
||
951 | _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, |
||
952 | save->FragmentProgram); |
||
953 | _mesa_reference_fragprog(ctx, &save->FragmentProgram, NULL); |
||
954 | } |
||
955 | |||
956 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) { |
||
957 | _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, |
||
958 | save->ATIFragmentShaderEnabled); |
||
959 | } |
||
960 | |||
961 | if (ctx->Extensions.ARB_vertex_shader) |
||
962 | _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader); |
||
963 | |||
964 | if (ctx->Extensions.ARB_geometry_shader4) |
||
965 | _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, |
||
966 | save->GeometryShader); |
||
967 | |||
968 | if (ctx->Extensions.ARB_fragment_shader) |
||
969 | _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, |
||
970 | save->FragmentShader); |
||
971 | |||
972 | _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, |
||
973 | save->ActiveShader); |
||
974 | |||
975 | _mesa_reference_shader_program(ctx, &save->VertexShader, NULL); |
||
976 | _mesa_reference_shader_program(ctx, &save->GeometryShader, NULL); |
||
977 | _mesa_reference_shader_program(ctx, &save->FragmentShader, NULL); |
||
978 | _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL); |
||
979 | } |
||
980 | |||
981 | if (state & MESA_META_STENCIL_TEST) { |
||
982 | const struct gl_stencil_attrib *stencil = &save->Stencil; |
||
983 | |||
984 | _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); |
||
985 | _mesa_ClearStencil(stencil->Clear); |
||
986 | if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_stencil_two_side) { |
||
987 | _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, |
||
988 | stencil->TestTwoSide); |
||
989 | _mesa_ActiveStencilFaceEXT(stencil->ActiveFace |
||
990 | ? GL_BACK : GL_FRONT); |
||
991 | } |
||
992 | /* front state */ |
||
993 | _mesa_StencilFuncSeparate(GL_FRONT, |
||
994 | stencil->Function[0], |
||
995 | stencil->Ref[0], |
||
996 | stencil->ValueMask[0]); |
||
997 | _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); |
||
998 | _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], |
||
999 | stencil->ZFailFunc[0], |
||
1000 | stencil->ZPassFunc[0]); |
||
1001 | /* back state */ |
||
1002 | _mesa_StencilFuncSeparate(GL_BACK, |
||
1003 | stencil->Function[1], |
||
1004 | stencil->Ref[1], |
||
1005 | stencil->ValueMask[1]); |
||
1006 | _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); |
||
1007 | _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], |
||
1008 | stencil->ZFailFunc[1], |
||
1009 | stencil->ZPassFunc[1]); |
||
1010 | } |
||
1011 | |||
1012 | if (state & MESA_META_TEXTURE) { |
||
1013 | GLuint u, tgt; |
||
1014 | |||
1015 | ASSERT(ctx->Texture.CurrentUnit == 0); |
||
1016 | |||
1017 | /* restore texenv for unit[0] */ |
||
1018 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { |
||
1019 | _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); |
||
1020 | } |
||
1021 | |||
1022 | /* restore texture objects for unit[0] only */ |
||
1023 | for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { |
||
1024 | if (ctx->Texture.Unit[0].CurrentTex[tgt] != save->CurrentTexture[tgt]) { |
||
1025 | FLUSH_VERTICES(ctx, _NEW_TEXTURE); |
||
1026 | _mesa_reference_texobj(&ctx->Texture.Unit[0].CurrentTex[tgt], |
||
1027 | save->CurrentTexture[tgt]); |
||
1028 | } |
||
1029 | _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL); |
||
1030 | } |
||
1031 | |||
1032 | /* Restore fixed function texture enables, texgen */ |
||
1033 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { |
||
1034 | for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { |
||
1035 | if (ctx->Texture.Unit[u].Enabled != save->TexEnabled[u]) { |
||
1036 | FLUSH_VERTICES(ctx, _NEW_TEXTURE); |
||
1037 | ctx->Texture.Unit[u].Enabled = save->TexEnabled[u]; |
||
1038 | } |
||
1039 | |||
1040 | if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) { |
||
1041 | FLUSH_VERTICES(ctx, _NEW_TEXTURE); |
||
1042 | ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u]; |
||
1043 | } |
||
1044 | } |
||
1045 | } |
||
1046 | |||
1047 | /* restore current unit state */ |
||
1048 | _mesa_ActiveTexture(GL_TEXTURE0 + save->ActiveUnit); |
||
1049 | _mesa_ClientActiveTexture(GL_TEXTURE0 + save->ClientActiveUnit); |
||
1050 | } |
||
1051 | |||
1052 | if (state & MESA_META_TRANSFORM) { |
||
1053 | GLuint activeTexture = ctx->Texture.CurrentUnit; |
||
1054 | _mesa_ActiveTexture(GL_TEXTURE0); |
||
1055 | _mesa_MatrixMode(GL_TEXTURE); |
||
1056 | _mesa_LoadMatrixf(save->TextureMatrix); |
||
1057 | _mesa_ActiveTexture(GL_TEXTURE0 + activeTexture); |
||
1058 | |||
1059 | _mesa_MatrixMode(GL_MODELVIEW); |
||
1060 | _mesa_LoadMatrixf(save->ModelviewMatrix); |
||
1061 | |||
1062 | _mesa_MatrixMode(GL_PROJECTION); |
||
1063 | _mesa_LoadMatrixf(save->ProjectionMatrix); |
||
1064 | |||
1065 | _mesa_MatrixMode(save->MatrixMode); |
||
1066 | } |
||
1067 | |||
1068 | if (state & MESA_META_CLIP) { |
||
1069 | if (save->ClipPlanesEnabled) { |
||
1070 | GLuint i; |
||
1071 | for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { |
||
1072 | if (save->ClipPlanesEnabled & (1 << i)) { |
||
1073 | _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); |
||
1074 | } |
||
1075 | } |
||
1076 | } |
||
1077 | } |
||
1078 | |||
1079 | if (state & MESA_META_VERTEX) { |
||
1080 | /* restore vertex buffer object */ |
||
1081 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name); |
||
1082 | _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL); |
||
1083 | |||
1084 | /* restore vertex array object */ |
||
1085 | _mesa_BindVertexArray(save->ArrayObj->Name); |
||
1086 | _mesa_reference_array_object(ctx, &save->ArrayObj, NULL); |
||
1087 | } |
||
1088 | |||
1089 | if (state & MESA_META_VIEWPORT) { |
||
1090 | if (save->ViewportX != ctx->Viewport.X || |
||
1091 | save->ViewportY != ctx->Viewport.Y || |
||
1092 | save->ViewportW != ctx->Viewport.Width || |
||
1093 | save->ViewportH != ctx->Viewport.Height) { |
||
1094 | _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY, |
||
1095 | save->ViewportW, save->ViewportH); |
||
1096 | } |
||
1097 | _mesa_DepthRange(save->DepthNear, save->DepthFar); |
||
1098 | } |
||
1099 | |||
1100 | if (state & MESA_META_CLAMP_FRAGMENT_COLOR && |
||
1101 | ctx->Extensions.ARB_color_buffer_float) { |
||
1102 | _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, save->ClampFragmentColor); |
||
1103 | } |
||
1104 | |||
1105 | if (state & MESA_META_CLAMP_VERTEX_COLOR && |
||
1106 | ctx->Extensions.ARB_color_buffer_float) { |
||
1107 | _mesa_ClampColor(GL_CLAMP_VERTEX_COLOR, save->ClampVertexColor); |
||
1108 | } |
||
1109 | |||
1110 | if (state & MESA_META_CONDITIONAL_RENDER) { |
||
1111 | if (save->CondRenderQuery) |
||
1112 | _mesa_BeginConditionalRender(save->CondRenderQuery->Id, |
||
1113 | save->CondRenderMode); |
||
1114 | } |
||
1115 | |||
1116 | if (state & MESA_META_SELECT_FEEDBACK) { |
||
1117 | if (save->RenderMode == GL_SELECT) { |
||
1118 | _mesa_RenderMode(GL_SELECT); |
||
1119 | ctx->Select = save->Select; |
||
1120 | } else if (save->RenderMode == GL_FEEDBACK) { |
||
1121 | _mesa_RenderMode(GL_FEEDBACK); |
||
1122 | ctx->Feedback = save->Feedback; |
||
1123 | } |
||
1124 | } |
||
1125 | |||
1126 | if (state & MESA_META_MULTISAMPLE) { |
||
1127 | if (ctx->Multisample.Enabled != save->MultisampleEnabled) |
||
1128 | _mesa_set_multisample(ctx, save->MultisampleEnabled); |
||
1129 | } |
||
1130 | |||
1131 | if (state & MESA_META_FRAMEBUFFER_SRGB) { |
||
1132 | if (ctx->Color.sRGBEnabled != save->sRGBEnabled) |
||
1133 | _mesa_set_framebuffer_srgb(ctx, save->sRGBEnabled); |
||
1134 | } |
||
1135 | |||
1136 | /* misc */ |
||
1137 | if (save->Lighting) { |
||
1138 | _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE); |
||
1139 | } |
||
1140 | if (save->RasterDiscard) { |
||
1141 | _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_TRUE); |
||
1142 | } |
||
1143 | if (save->TransformFeedbackNeedsResume) |
||
1144 | _mesa_ResumeTransformFeedback(); |
||
1145 | |||
1146 | ctx->Meta->SaveStackDepth--; |
||
1147 | } |
||
1148 | |||
1149 | |||
1150 | /** |
||
1151 | * Determine whether Mesa is currently in a meta state. |
||
1152 | */ |
||
1153 | GLboolean |
||
1154 | _mesa_meta_in_progress(struct gl_context *ctx) |
||
1155 | { |
||
1156 | return ctx->Meta->SaveStackDepth != 0; |
||
1157 | } |
||
1158 | |||
1159 | |||
1160 | /** |
||
1161 | * Convert Z from a normalized value in the range [0, 1] to an object-space |
||
1162 | * Z coordinate in [-1, +1] so that drawing at the new Z position with the |
||
1163 | * default/identity ortho projection results in the original Z value. |
||
1164 | * Used by the meta-Clear, Draw/CopyPixels and Bitmap functions where the Z |
||
1165 | * value comes from the clear value or raster position. |
||
1166 | */ |
||
1167 | static INLINE GLfloat |
||
1168 | invert_z(GLfloat normZ) |
||
1169 | { |
||
1170 | GLfloat objZ = 1.0f - 2.0f * normZ; |
||
1171 | return objZ; |
||
1172 | } |
||
1173 | |||
1174 | |||
1175 | /** |
||
1176 | * One-time init for a temp_texture object. |
||
1177 | * Choose tex target, compute max tex size, etc. |
||
1178 | */ |
||
1179 | static void |
||
1180 | init_temp_texture(struct gl_context *ctx, struct temp_texture *tex) |
||
1181 | { |
||
1182 | /* prefer texture rectangle */ |
||
1183 | if (_mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle) { |
||
1184 | tex->Target = GL_TEXTURE_RECTANGLE; |
||
1185 | tex->MaxSize = ctx->Const.MaxTextureRectSize; |
||
1186 | tex->NPOT = GL_TRUE; |
||
1187 | } |
||
1188 | else { |
||
1189 | /* use 2D texture, NPOT if possible */ |
||
1190 | tex->Target = GL_TEXTURE_2D; |
||
1191 | tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1); |
||
1192 | tex->NPOT = ctx->Extensions.ARB_texture_non_power_of_two; |
||
1193 | } |
||
1194 | tex->MinSize = 16; /* 16 x 16 at least */ |
||
1195 | assert(tex->MaxSize > 0); |
||
1196 | |||
1197 | _mesa_GenTextures(1, &tex->TexObj); |
||
1198 | } |
||
1199 | |||
1200 | static void |
||
1201 | cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex) |
||
1202 | { |
||
1203 | if (!tex->TexObj) |
||
1204 | return; |
||
1205 | _mesa_DeleteTextures(1, &tex->TexObj); |
||
1206 | tex->TexObj = 0; |
||
1207 | } |
||
1208 | |||
1209 | |||
1210 | /** |
||
1211 | * Return pointer to temp_texture info for non-bitmap ops. |
||
1212 | * This does some one-time init if needed. |
||
1213 | */ |
||
1214 | static struct temp_texture * |
||
1215 | get_temp_texture(struct gl_context *ctx) |
||
1216 | { |
||
1217 | struct temp_texture *tex = &ctx->Meta->TempTex; |
||
1218 | |||
1219 | if (!tex->TexObj) { |
||
1220 | init_temp_texture(ctx, tex); |
||
1221 | } |
||
1222 | |||
1223 | return tex; |
||
1224 | } |
||
1225 | |||
1226 | |||
1227 | /** |
||
1228 | * Return pointer to temp_texture info for _mesa_meta_bitmap(). |
||
1229 | * We use a separate texture for bitmaps to reduce texture |
||
1230 | * allocation/deallocation. |
||
1231 | */ |
||
1232 | static struct temp_texture * |
||
1233 | get_bitmap_temp_texture(struct gl_context *ctx) |
||
1234 | { |
||
1235 | struct temp_texture *tex = &ctx->Meta->Bitmap.Tex; |
||
1236 | |||
1237 | if (!tex->TexObj) { |
||
1238 | init_temp_texture(ctx, tex); |
||
1239 | } |
||
1240 | |||
1241 | return tex; |
||
1242 | } |
||
1243 | |||
1244 | /** |
||
1245 | * Return pointer to depth temp_texture. |
||
1246 | * This does some one-time init if needed. |
||
1247 | */ |
||
1248 | static struct temp_texture * |
||
1249 | get_temp_depth_texture(struct gl_context *ctx) |
||
1250 | { |
||
1251 | struct temp_texture *tex = &ctx->Meta->Blit.depthTex; |
||
1252 | |||
1253 | if (!tex->TexObj) { |
||
1254 | init_temp_texture(ctx, tex); |
||
1255 | } |
||
1256 | |||
1257 | return tex; |
||
1258 | } |
||
1259 | |||
1260 | /** |
||
1261 | * Compute the width/height of texture needed to draw an image of the |
||
1262 | * given size. Return a flag indicating whether the current texture |
||
1263 | * can be re-used (glTexSubImage2D) or if a new texture needs to be |
||
1264 | * allocated (glTexImage2D). |
||
1265 | * Also, compute s/t texcoords for drawing. |
||
1266 | * |
||
1267 | * \return GL_TRUE if new texture is needed, GL_FALSE otherwise |
||
1268 | */ |
||
1269 | static GLboolean |
||
1270 | alloc_texture(struct temp_texture *tex, |
||
1271 | GLsizei width, GLsizei height, GLenum intFormat) |
||
1272 | { |
||
1273 | GLboolean newTex = GL_FALSE; |
||
1274 | |||
1275 | ASSERT(width <= tex->MaxSize); |
||
1276 | ASSERT(height <= tex->MaxSize); |
||
1277 | |||
1278 | if (width > tex->Width || |
||
1279 | height > tex->Height || |
||
1280 | intFormat != tex->IntFormat) { |
||
1281 | /* alloc new texture (larger or different format) */ |
||
1282 | |||
1283 | if (tex->NPOT) { |
||
1284 | /* use non-power of two size */ |
||
1285 | tex->Width = MAX2(tex->MinSize, width); |
||
1286 | tex->Height = MAX2(tex->MinSize, height); |
||
1287 | } |
||
1288 | else { |
||
1289 | /* find power of two size */ |
||
1290 | GLsizei w, h; |
||
1291 | w = h = tex->MinSize; |
||
1292 | while (w < width) |
||
1293 | w *= 2; |
||
1294 | while (h < height) |
||
1295 | h *= 2; |
||
1296 | tex->Width = w; |
||
1297 | tex->Height = h; |
||
1298 | } |
||
1299 | |||
1300 | tex->IntFormat = intFormat; |
||
1301 | |||
1302 | newTex = GL_TRUE; |
||
1303 | } |
||
1304 | |||
1305 | /* compute texcoords */ |
||
1306 | if (tex->Target == GL_TEXTURE_RECTANGLE) { |
||
1307 | tex->Sright = (GLfloat) width; |
||
1308 | tex->Ttop = (GLfloat) height; |
||
1309 | } |
||
1310 | else { |
||
1311 | tex->Sright = (GLfloat) width / tex->Width; |
||
1312 | tex->Ttop = (GLfloat) height / tex->Height; |
||
1313 | } |
||
1314 | |||
1315 | return newTex; |
||
1316 | } |
||
1317 | |||
1318 | |||
1319 | /** |
||
1320 | * Setup/load texture for glCopyPixels or glBlitFramebuffer. |
||
1321 | */ |
||
1322 | static void |
||
1323 | setup_copypix_texture(struct gl_context *ctx, |
||
1324 | struct temp_texture *tex, |
||
1325 | GLboolean newTex, |
||
1326 | GLint srcX, GLint srcY, |
||
1327 | GLsizei width, GLsizei height, GLenum intFormat, |
||
1328 | GLenum filter) |
||
1329 | { |
||
1330 | _mesa_BindTexture(tex->Target, tex->TexObj); |
||
1331 | _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter); |
||
1332 | _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter); |
||
1333 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) |
||
1334 | _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
||
1335 | |||
1336 | /* copy framebuffer image to texture */ |
||
1337 | if (newTex) { |
||
1338 | /* create new tex image */ |
||
1339 | if (tex->Width == width && tex->Height == height) { |
||
1340 | /* create new tex with framebuffer data */ |
||
1341 | _mesa_CopyTexImage2D(tex->Target, 0, tex->IntFormat, |
||
1342 | srcX, srcY, width, height, 0); |
||
1343 | } |
||
1344 | else { |
||
1345 | /* create empty texture */ |
||
1346 | _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, |
||
1347 | tex->Width, tex->Height, 0, |
||
1348 | intFormat, GL_UNSIGNED_BYTE, NULL); |
||
1349 | /* load image */ |
||
1350 | _mesa_CopyTexSubImage2D(tex->Target, 0, |
||
1351 | 0, 0, srcX, srcY, width, height); |
||
1352 | } |
||
1353 | } |
||
1354 | else { |
||
1355 | /* replace existing tex image */ |
||
1356 | _mesa_CopyTexSubImage2D(tex->Target, 0, |
||
1357 | 0, 0, srcX, srcY, width, height); |
||
1358 | } |
||
1359 | } |
||
1360 | |||
1361 | |||
1362 | /** |
||
1363 | * Setup/load texture for glDrawPixels. |
||
1364 | */ |
||
1365 | static void |
||
1366 | setup_drawpix_texture(struct gl_context *ctx, |
||
1367 | struct temp_texture *tex, |
||
1368 | GLboolean newTex, |
||
1369 | GLenum texIntFormat, |
||
1370 | GLsizei width, GLsizei height, |
||
1371 | GLenum format, GLenum type, |
||
1372 | const GLvoid *pixels) |
||
1373 | { |
||
1374 | _mesa_BindTexture(tex->Target, tex->TexObj); |
||
1375 | _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
||
1376 | _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
||
1377 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) |
||
1378 | _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
||
1379 | |||
1380 | /* copy pixel data to texture */ |
||
1381 | if (newTex) { |
||
1382 | /* create new tex image */ |
||
1383 | if (tex->Width == width && tex->Height == height) { |
||
1384 | /* create new tex and load image data */ |
||
1385 | _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, |
||
1386 | tex->Width, tex->Height, 0, format, type, pixels); |
||
1387 | } |
||
1388 | else { |
||
1389 | struct gl_buffer_object *save_unpack_obj = NULL; |
||
1390 | |||
1391 | _mesa_reference_buffer_object(ctx, &save_unpack_obj, |
||
1392 | ctx->Unpack.BufferObj); |
||
1393 | _mesa_BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); |
||
1394 | /* create empty texture */ |
||
1395 | _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, |
||
1396 | tex->Width, tex->Height, 0, format, type, NULL); |
||
1397 | if (save_unpack_obj != NULL) |
||
1398 | _mesa_BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, |
||
1399 | save_unpack_obj->Name); |
||
1400 | /* load image */ |
||
1401 | _mesa_TexSubImage2D(tex->Target, 0, |
||
1402 | 0, 0, width, height, format, type, pixels); |
||
1403 | } |
||
1404 | } |
||
1405 | else { |
||
1406 | /* replace existing tex image */ |
||
1407 | _mesa_TexSubImage2D(tex->Target, 0, |
||
1408 | 0, 0, width, height, format, type, pixels); |
||
1409 | } |
||
1410 | } |
||
1411 | |||
1412 | |||
1413 | |||
1414 | /** |
||
1415 | * One-time init for drawing depth pixels. |
||
1416 | */ |
||
1417 | static void |
||
1418 | init_blit_depth_pixels(struct gl_context *ctx) |
||
1419 | { |
||
1420 | static const char *program = |
||
1421 | "!!ARBfp1.0\n" |
||
1422 | "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" |
||
1423 | "END \n"; |
||
1424 | char program2[200]; |
||
1425 | struct blit_state *blit = &ctx->Meta->Blit; |
||
1426 | struct temp_texture *tex = get_temp_texture(ctx); |
||
1427 | const char *texTarget; |
||
1428 | |||
1429 | assert(blit->DepthFP == 0); |
||
1430 | |||
1431 | /* replace %s with "RECT" or "2D" */ |
||
1432 | assert(strlen(program) + 4 < sizeof(program2)); |
||
1433 | if (tex->Target == GL_TEXTURE_RECTANGLE) |
||
1434 | texTarget = "RECT"; |
||
1435 | else |
||
1436 | texTarget = "2D"; |
||
1437 | _mesa_snprintf(program2, sizeof(program2), program, texTarget); |
||
1438 | |||
1439 | _mesa_GenProgramsARB(1, &blit->DepthFP); |
||
1440 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); |
||
1441 | _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, |
||
1442 | strlen(program2), (const GLubyte *) program2); |
||
1443 | } |
||
1444 | |||
1445 | static void |
||
1446 | setup_ff_blit_framebuffer(struct gl_context *ctx, |
||
1447 | struct blit_state *blit) |
||
1448 | { |
||
1449 | struct vertex { |
||
1450 | GLfloat x, y, s, t; |
||
1451 | }; |
||
1452 | struct vertex verts[4]; |
||
1453 | |||
1454 | if (blit->ArrayObj == 0) { |
||
1455 | /* one-time setup */ |
||
1456 | |||
1457 | /* create vertex array object */ |
||
1458 | _mesa_GenVertexArrays(1, &blit->ArrayObj); |
||
1459 | _mesa_BindVertexArray(blit->ArrayObj); |
||
1460 | |||
1461 | /* create vertex array buffer */ |
||
1462 | _mesa_GenBuffers(1, &blit->VBO); |
||
1463 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); |
||
1464 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
1465 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
1466 | |||
1467 | /* setup vertex arrays */ |
||
1468 | _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
1469 | _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); |
||
1470 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
1471 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
1472 | } |
||
1473 | |||
1474 | /* setup projection matrix */ |
||
1475 | _mesa_MatrixMode(GL_PROJECTION); |
||
1476 | _mesa_LoadIdentity(); |
||
1477 | _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); |
||
1478 | |||
1479 | } |
||
1480 | |||
1481 | static void |
||
1482 | setup_glsl_blit_framebuffer(struct gl_context *ctx, |
||
1483 | struct blit_state *blit, |
||
1484 | GLenum target) |
||
1485 | { |
||
1486 | struct vertex { |
||
1487 | GLfloat x, y, s, t; |
||
1488 | }; |
||
1489 | struct vertex verts[4]; |
||
1490 | const char *vs_source; |
||
1491 | char *fs_source; |
||
1492 | GLuint vs, fs; |
||
1493 | void *mem_ctx; |
||
1494 | GLuint ShaderProg; |
||
1495 | GLboolean texture_2d = (target == GL_TEXTURE_2D); |
||
1496 | |||
1497 | /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */ |
||
1498 | assert(_mesa_is_desktop_gl(ctx) || texture_2d); |
||
1499 | |||
1500 | /* Check if already initialized */ |
||
1501 | if (blit->ArrayObj == 0) { |
||
1502 | |||
1503 | /* create vertex array object */ |
||
1504 | _mesa_GenVertexArrays(1, &blit->ArrayObj); |
||
1505 | _mesa_BindVertexArray(blit->ArrayObj); |
||
1506 | |||
1507 | /* create vertex array buffer */ |
||
1508 | _mesa_GenBuffers(1, &blit->VBO); |
||
1509 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); |
||
1510 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
1511 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
1512 | |||
1513 | /* setup vertex arrays */ |
||
1514 | _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, |
||
1515 | sizeof(struct vertex), OFFSET(x)); |
||
1516 | _mesa_VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, |
||
1517 | sizeof(struct vertex), OFFSET(s)); |
||
4401 | Serge | 1518 | |
1519 | _mesa_EnableVertexAttribArray(0); |
||
1520 | _mesa_EnableVertexAttribArray(1); |
||
4358 | Serge | 1521 | } |
1522 | |||
1523 | /* Generate a relevant fragment shader program for the texture target */ |
||
1524 | if ((target == GL_TEXTURE_2D && blit->ShaderProg != 0) || |
||
1525 | (target == GL_TEXTURE_RECTANGLE && blit->RectShaderProg != 0)) { |
||
1526 | return; |
||
1527 | } |
||
1528 | |||
1529 | mem_ctx = ralloc_context(NULL); |
||
1530 | |||
1531 | if (ctx->Const.GLSLVersion < 130) { |
||
1532 | vs_source = |
||
1533 | "attribute vec2 position;\n" |
||
1534 | "attribute vec2 textureCoords;\n" |
||
1535 | "varying vec2 texCoords;\n" |
||
1536 | "void main()\n" |
||
1537 | "{\n" |
||
1538 | " texCoords = textureCoords;\n" |
||
1539 | " gl_Position = vec4(position, 0.0, 1.0);\n" |
||
1540 | "}\n"; |
||
1541 | |||
1542 | fs_source = ralloc_asprintf(mem_ctx, |
||
1543 | "#ifdef GL_ES\n" |
||
1544 | "precision highp float;\n" |
||
1545 | "#endif\n" |
||
1546 | "uniform %s texSampler;\n" |
||
1547 | "varying vec2 texCoords;\n" |
||
1548 | "void main()\n" |
||
1549 | "{\n" |
||
1550 | " gl_FragColor = %s(texSampler, texCoords);\n" |
||
1551 | " gl_FragDepth = gl_FragColor.r;\n" |
||
1552 | "}\n", |
||
1553 | texture_2d ? "sampler2D" : "sampler2DRect", |
||
1554 | texture_2d ? "texture2D" : "texture2DRect"); |
||
1555 | } |
||
1556 | else { |
||
1557 | vs_source = ralloc_asprintf(mem_ctx, |
||
1558 | "#version %s\n" |
||
1559 | "in vec2 position;\n" |
||
1560 | "in vec2 textureCoords;\n" |
||
1561 | "out vec2 texCoords;\n" |
||
1562 | "void main()\n" |
||
1563 | "{\n" |
||
1564 | " texCoords = textureCoords;\n" |
||
1565 | " gl_Position = vec4(position, 0.0, 1.0);\n" |
||
1566 | "}\n", |
||
1567 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); |
||
1568 | fs_source = ralloc_asprintf(mem_ctx, |
||
1569 | "#version %s\n" |
||
1570 | "#ifdef GL_ES\n" |
||
1571 | "precision highp float;\n" |
||
1572 | "#endif\n" |
||
1573 | "uniform %s texSampler;\n" |
||
1574 | "in vec2 texCoords;\n" |
||
1575 | "out vec4 out_color;\n" |
||
1576 | "\n" |
||
1577 | "void main()\n" |
||
1578 | "{\n" |
||
1579 | " out_color = %s(texSampler, texCoords);\n" |
||
1580 | " gl_FragDepth = out_color.r;\n" |
||
1581 | "}\n", |
||
1582 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es", |
||
1583 | texture_2d ? "sampler2D" : "sampler2DRect", |
||
1584 | texture_2d ? "texture" : "texture2DRect"); |
||
1585 | } |
||
1586 | |||
1587 | vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source); |
||
1588 | fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source); |
||
1589 | |||
1590 | ShaderProg = _mesa_CreateProgramObjectARB(); |
||
1591 | _mesa_AttachShader(ShaderProg, fs); |
||
1592 | _mesa_DeleteObjectARB(fs); |
||
1593 | _mesa_AttachShader(ShaderProg, vs); |
||
1594 | _mesa_DeleteObjectARB(vs); |
||
1595 | _mesa_BindAttribLocation(ShaderProg, 0, "position"); |
||
1596 | _mesa_BindAttribLocation(ShaderProg, 1, "texcoords"); |
||
1597 | link_program_with_debug(ctx, ShaderProg); |
||
1598 | ralloc_free(mem_ctx); |
||
1599 | if (texture_2d) |
||
1600 | blit->ShaderProg = ShaderProg; |
||
1601 | else |
||
1602 | blit->RectShaderProg = ShaderProg; |
||
1603 | } |
||
1604 | |||
1605 | /** |
||
1606 | * Try to do a glBlitFramebuffer using no-copy texturing. |
||
1607 | * We can do this when the src renderbuffer is actually a texture. |
||
1608 | * But if the src buffer == dst buffer we cannot do this. |
||
1609 | * |
||
1610 | * \return new buffer mask indicating the buffers left to blit using the |
||
1611 | * normal path. |
||
1612 | */ |
||
1613 | static GLbitfield |
||
1614 | blitframebuffer_texture(struct gl_context *ctx, |
||
1615 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
1616 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
1617 | GLbitfield mask, GLenum filter, GLint flipX, |
||
1618 | GLint flipY, GLboolean glsl_version) |
||
1619 | { |
||
1620 | if (mask & GL_COLOR_BUFFER_BIT) { |
||
1621 | const struct gl_framebuffer *drawFb = ctx->DrawBuffer; |
||
1622 | const struct gl_framebuffer *readFb = ctx->ReadBuffer; |
||
1623 | const struct gl_renderbuffer_attachment *drawAtt; |
||
1624 | const struct gl_renderbuffer_attachment *readAtt = |
||
1625 | &readFb->Attachment[readFb->_ColorReadBufferIndex]; |
||
1626 | |||
1627 | if (readAtt && readAtt->Texture) { |
||
1628 | struct blit_state *blit = &ctx->Meta->Blit; |
||
1629 | const GLint dstX = MIN2(dstX0, dstX1); |
||
1630 | const GLint dstY = MIN2(dstY0, dstY1); |
||
1631 | const GLint dstW = abs(dstX1 - dstX0); |
||
1632 | const GLint dstH = abs(dstY1 - dstY0); |
||
1633 | const struct gl_texture_object *texObj = readAtt->Texture; |
||
1634 | const GLuint srcLevel = readAtt->TextureLevel; |
||
1635 | const GLint baseLevelSave = texObj->BaseLevel; |
||
1636 | const GLint maxLevelSave = texObj->MaxLevel; |
||
1637 | const GLenum target = texObj->Target; |
||
1638 | GLuint sampler, samplerSave = |
||
1639 | ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? |
||
1640 | ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; |
||
1641 | int i; |
||
1642 | |||
1643 | /* Iterate through all draw buffers */ |
||
1644 | for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { |
||
1645 | int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; |
||
1646 | if (idx == -1) |
||
1647 | continue; |
||
1648 | drawAtt = &drawFb->Attachment[idx]; |
||
1649 | |||
1650 | if (drawAtt->Texture == readAtt->Texture) { |
||
1651 | /* Can't use same texture as both the source and dest. We need |
||
1652 | * to handle overlapping blits and besides, some hw may not |
||
1653 | * support this. |
||
1654 | */ |
||
1655 | return mask; |
||
1656 | } |
||
1657 | } |
||
1658 | |||
1659 | if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) { |
||
1660 | /* Can't handle other texture types at this time */ |
||
1661 | return mask; |
||
1662 | } |
||
1663 | |||
1664 | /* Choose between glsl version and fixed function version of |
||
1665 | * BlitFramebuffer function. |
||
1666 | */ |
||
1667 | if (glsl_version) { |
||
1668 | setup_glsl_blit_framebuffer(ctx, blit, target); |
||
1669 | if (target == GL_TEXTURE_2D) |
||
1670 | _mesa_UseProgram(blit->ShaderProg); |
||
1671 | else |
||
1672 | _mesa_UseProgram(blit->RectShaderProg); |
||
1673 | } |
||
1674 | else { |
||
1675 | setup_ff_blit_framebuffer(ctx, &ctx->Meta->Blit); |
||
1676 | } |
||
1677 | |||
1678 | _mesa_BindVertexArray(blit->ArrayObj); |
||
1679 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); |
||
1680 | |||
1681 | _mesa_GenSamplers(1, &sampler); |
||
1682 | _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler); |
||
1683 | |||
1684 | /* |
||
1685 | printf("Blit from texture!\n"); |
||
1686 | printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); |
||
1687 | printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); |
||
1688 | */ |
||
1689 | |||
1690 | /* Prepare src texture state */ |
||
1691 | _mesa_BindTexture(target, texObj->Name); |
||
1692 | _mesa_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, filter); |
||
1693 | _mesa_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, filter); |
||
1694 | if (target != GL_TEXTURE_RECTANGLE_ARB) { |
||
1695 | _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel); |
||
1696 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); |
||
1697 | } |
||
1698 | _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
||
1699 | _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
||
1700 | |||
1701 | /* Always do our blits with no sRGB decode or encode. Note that |
||
1702 | * GL_FRAMEBUFFER_SRGB has already been disabled by |
||
1703 | * _mesa_meta_begin(). |
||
1704 | */ |
||
1705 | if (ctx->Extensions.EXT_texture_sRGB_decode) { |
||
1706 | _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, |
||
1707 | GL_SKIP_DECODE_EXT); |
||
1708 | } |
||
1709 | |||
1710 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { |
||
1711 | _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
||
1712 | _mesa_set_enable(ctx, target, GL_TRUE); |
||
1713 | } |
||
1714 | |||
1715 | /* Prepare vertex data (the VBO was previously created and bound) */ |
||
1716 | { |
||
1717 | struct vertex { |
||
1718 | GLfloat x, y, s, t; |
||
1719 | }; |
||
1720 | struct vertex verts[4]; |
||
1721 | GLfloat s0, t0, s1, t1; |
||
1722 | |||
1723 | if (target == GL_TEXTURE_2D) { |
||
1724 | const struct gl_texture_image *texImage |
||
1725 | = _mesa_select_tex_image(ctx, texObj, target, srcLevel); |
||
1726 | s0 = srcX0 / (float) texImage->Width; |
||
1727 | s1 = srcX1 / (float) texImage->Width; |
||
1728 | t0 = srcY0 / (float) texImage->Height; |
||
1729 | t1 = srcY1 / (float) texImage->Height; |
||
1730 | } |
||
1731 | else { |
||
1732 | assert(target == GL_TEXTURE_RECTANGLE_ARB); |
||
1733 | s0 = srcX0; |
||
1734 | s1 = srcX1; |
||
1735 | t0 = srcY0; |
||
1736 | t1 = srcY1; |
||
1737 | } |
||
1738 | |||
1739 | /* setup vertex positions */ |
||
1740 | verts[0].x = -1.0F * flipX; |
||
1741 | verts[0].y = -1.0F * flipY; |
||
1742 | verts[1].x = 1.0F * flipX; |
||
1743 | verts[1].y = -1.0F * flipY; |
||
1744 | verts[2].x = 1.0F * flipX; |
||
1745 | verts[2].y = 1.0F * flipY; |
||
1746 | verts[3].x = -1.0F * flipX; |
||
1747 | verts[3].y = 1.0F * flipY; |
||
1748 | |||
1749 | verts[0].s = s0; |
||
1750 | verts[0].t = t0; |
||
1751 | verts[1].s = s1; |
||
1752 | verts[1].t = t0; |
||
1753 | verts[2].s = s1; |
||
1754 | verts[2].t = t1; |
||
1755 | verts[3].s = s0; |
||
1756 | verts[3].t = t1; |
||
1757 | |||
1758 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
1759 | } |
||
1760 | |||
1761 | /* setup viewport */ |
||
1762 | _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH); |
||
1763 | _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
||
1764 | _mesa_DepthMask(GL_FALSE); |
||
1765 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
1766 | |||
1767 | /* Restore texture object state, the texture binding will |
||
1768 | * be restored by _mesa_meta_end(). |
||
1769 | */ |
||
1770 | if (target != GL_TEXTURE_RECTANGLE_ARB) { |
||
1771 | _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); |
||
1772 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); |
||
1773 | } |
||
1774 | |||
1775 | _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); |
||
1776 | _mesa_DeleteSamplers(1, &sampler); |
||
1777 | |||
1778 | /* Done with color buffer */ |
||
1779 | mask &= ~GL_COLOR_BUFFER_BIT; |
||
1780 | } |
||
1781 | } |
||
1782 | |||
1783 | return mask; |
||
1784 | } |
||
1785 | |||
1786 | |||
1787 | /** |
||
1788 | * Meta implementation of ctx->Driver.BlitFramebuffer() in terms |
||
1789 | * of texture mapping and polygon rendering. |
||
1790 | */ |
||
1791 | void |
||
1792 | _mesa_meta_BlitFramebuffer(struct gl_context *ctx, |
||
1793 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
1794 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
1795 | GLbitfield mask, GLenum filter) |
||
1796 | { |
||
1797 | struct blit_state *blit = &ctx->Meta->Blit; |
||
1798 | struct temp_texture *tex = get_temp_texture(ctx); |
||
1799 | struct temp_texture *depthTex = get_temp_depth_texture(ctx); |
||
1800 | const GLsizei maxTexSize = tex->MaxSize; |
||
1801 | const GLint srcX = MIN2(srcX0, srcX1); |
||
1802 | const GLint srcY = MIN2(srcY0, srcY1); |
||
1803 | const GLint srcW = abs(srcX1 - srcX0); |
||
1804 | const GLint srcH = abs(srcY1 - srcY0); |
||
1805 | const GLint dstX = MIN2(dstX0, dstX1); |
||
1806 | const GLint dstY = MIN2(dstY0, dstY1); |
||
1807 | const GLint dstW = abs(dstX1 - dstX0); |
||
1808 | const GLint dstH = abs(dstY1 - dstY0); |
||
1809 | const GLint srcFlipX = (srcX1 - srcX0) / srcW; |
||
1810 | const GLint srcFlipY = (srcY1 - srcY0) / srcH; |
||
1811 | const GLint dstFlipX = (dstX1 - dstX0) / dstW; |
||
1812 | const GLint dstFlipY = (dstY1 - dstY0) / dstH; |
||
1813 | const GLint flipX = srcFlipX * dstFlipX; |
||
1814 | const GLint flipY = srcFlipY * dstFlipY; |
||
1815 | |||
1816 | struct vertex { |
||
1817 | GLfloat x, y, s, t; |
||
1818 | }; |
||
1819 | struct vertex verts[4]; |
||
1820 | GLboolean newTex; |
||
1821 | const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && |
||
1822 | ctx->Extensions.ARB_fragment_shader && |
||
1823 | (ctx->API != API_OPENGLES); |
||
1824 | |||
1825 | /* In addition to falling back if the blit size is larger than the maximum |
||
1826 | * texture size, fallback if the source is multisampled. This fallback can |
||
1827 | * be removed once Mesa gets support ARB_texture_multisample. |
||
1828 | */ |
||
1829 | if (srcW > maxTexSize || srcH > maxTexSize |
||
1830 | || ctx->ReadBuffer->Visual.samples > 0) { |
||
1831 | /* XXX avoid this fallback */ |
||
1832 | _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, |
||
1833 | dstX0, dstY0, dstX1, dstY1, mask, filter); |
||
1834 | return; |
||
1835 | } |
||
1836 | |||
1837 | /* only scissor effects blit so save/clear all other relevant state */ |
||
1838 | _mesa_meta_begin(ctx, ~MESA_META_SCISSOR); |
||
1839 | |||
1840 | /* Try faster, direct texture approach first */ |
||
1841 | mask = blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1, |
||
1842 | dstX0, dstY0, dstX1, dstY1, mask, filter, |
||
1843 | dstFlipX, dstFlipY, use_glsl_version); |
||
1844 | if (mask == 0x0) { |
||
1845 | _mesa_meta_end(ctx); |
||
1846 | return; |
||
1847 | } |
||
1848 | |||
1849 | /* Choose between glsl version and fixed function version of |
||
1850 | * BlitFramebuffer function. |
||
1851 | */ |
||
1852 | if (use_glsl_version) { |
||
1853 | setup_glsl_blit_framebuffer(ctx, blit, tex->Target); |
||
1854 | if (tex->Target == GL_TEXTURE_2D) |
||
1855 | _mesa_UseProgram(blit->ShaderProg); |
||
1856 | else |
||
1857 | _mesa_UseProgram(blit->RectShaderProg); |
||
1858 | } |
||
1859 | else { |
||
1860 | setup_ff_blit_framebuffer(ctx, blit); |
||
1861 | } |
||
1862 | |||
1863 | _mesa_BindVertexArray(blit->ArrayObj); |
||
1864 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); |
||
1865 | |||
1866 | /* Continue with "normal" approach which involves copying the src rect |
||
1867 | * into a temporary texture and is "blitted" by drawing a textured quad. |
||
1868 | */ |
||
1869 | { |
||
1870 | /* setup vertex positions */ |
||
1871 | verts[0].x = -1.0F * flipX; |
||
1872 | verts[0].y = -1.0F * flipY; |
||
1873 | verts[1].x = 1.0F * flipX; |
||
1874 | verts[1].y = -1.0F * flipY; |
||
1875 | verts[2].x = 1.0F * flipX; |
||
1876 | verts[2].y = 1.0F * flipY; |
||
1877 | verts[3].x = -1.0F * flipX; |
||
1878 | verts[3].y = 1.0F * flipY; |
||
1879 | |||
1880 | } |
||
1881 | |||
1882 | /* glEnable() in gles2 and gles3 doesn't allow GL_TEXTURE_{1D, 2D, etc.} |
||
1883 | * tokens. |
||
1884 | */ |
||
1885 | if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES) |
||
1886 | _mesa_set_enable(ctx, tex->Target, GL_TRUE); |
||
1887 | |||
1888 | if (mask & GL_COLOR_BUFFER_BIT) { |
||
1889 | const struct gl_framebuffer *readFb = ctx->ReadBuffer; |
||
1890 | const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; |
||
1891 | const GLenum rb_base_format = |
||
1892 | _mesa_base_tex_format(ctx, colorReadRb->InternalFormat); |
||
1893 | |||
1894 | /* Using the exact source rectangle to create the texture does incorrect |
||
1895 | * linear filtering along the edges. So, allocate the texture extended along |
||
1896 | * edges by one pixel in x, y directions. |
||
1897 | */ |
||
1898 | newTex = alloc_texture(tex, srcW + 2, srcH + 2, rb_base_format); |
||
1899 | setup_copypix_texture(ctx, tex, newTex, |
||
1900 | srcX - 1, srcY - 1, srcW + 2, srcH + 2, |
||
1901 | rb_base_format, filter); |
||
1902 | /* texcoords (after texture allocation!) */ |
||
1903 | { |
||
1904 | verts[0].s = 1.0F; |
||
1905 | verts[0].t = 1.0F; |
||
1906 | verts[1].s = tex->Sright - 1.0F; |
||
1907 | verts[1].t = 1.0F; |
||
1908 | verts[2].s = tex->Sright - 1.0F; |
||
1909 | verts[2].t = tex->Ttop - 1.0F; |
||
1910 | verts[3].s = 1.0F; |
||
1911 | verts[3].t = tex->Ttop - 1.0F; |
||
1912 | |||
1913 | /* upload new vertex data */ |
||
1914 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
1915 | } |
||
1916 | |||
1917 | _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH); |
||
1918 | _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
||
1919 | _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); |
||
1920 | _mesa_DepthMask(GL_FALSE); |
||
1921 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
1922 | mask &= ~GL_COLOR_BUFFER_BIT; |
||
1923 | } |
||
1924 | |||
1925 | if ((mask & GL_DEPTH_BUFFER_BIT) && |
||
1926 | _mesa_is_desktop_gl(ctx) && |
||
1927 | ctx->Extensions.ARB_depth_texture && |
||
1928 | ctx->Extensions.ARB_fragment_program) { |
||
1929 | |||
1930 | GLuint *tmp = malloc(srcW * srcH * sizeof(GLuint)); |
||
1931 | |||
1932 | if (tmp) { |
||
1933 | |||
1934 | newTex = alloc_texture(depthTex, srcW, srcH, GL_DEPTH_COMPONENT); |
||
1935 | _mesa_ReadPixels(srcX, srcY, srcW, srcH, GL_DEPTH_COMPONENT, |
||
1936 | GL_UNSIGNED_INT, tmp); |
||
1937 | setup_drawpix_texture(ctx, depthTex, newTex, GL_DEPTH_COMPONENT, |
||
1938 | srcW, srcH, GL_DEPTH_COMPONENT, |
||
1939 | GL_UNSIGNED_INT, tmp); |
||
1940 | |||
1941 | /* texcoords (after texture allocation!) */ |
||
1942 | { |
||
1943 | verts[0].s = 0.0F; |
||
1944 | verts[0].t = 0.0F; |
||
1945 | verts[1].s = depthTex->Sright; |
||
1946 | verts[1].t = 0.0F; |
||
1947 | verts[2].s = depthTex->Sright; |
||
1948 | verts[2].t = depthTex->Ttop; |
||
1949 | verts[3].s = 0.0F; |
||
1950 | verts[3].t = depthTex->Ttop; |
||
1951 | |||
1952 | /* upload new vertex data */ |
||
1953 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
1954 | } |
||
1955 | |||
1956 | if (!blit->DepthFP) |
||
1957 | init_blit_depth_pixels(ctx); |
||
1958 | |||
1959 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); |
||
1960 | _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); |
||
1961 | _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
||
1962 | _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); |
||
1963 | _mesa_DepthFunc(GL_ALWAYS); |
||
1964 | _mesa_DepthMask(GL_TRUE); |
||
1965 | |||
1966 | _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH); |
||
1967 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
1968 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
1969 | mask &= ~GL_DEPTH_BUFFER_BIT; |
||
1970 | |||
1971 | free(tmp); |
||
1972 | } |
||
1973 | } |
||
1974 | |||
1975 | if (mask & GL_STENCIL_BUFFER_BIT) { |
||
1976 | /* XXX can't easily do stencil */ |
||
1977 | } |
||
1978 | |||
1979 | if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES) |
||
1980 | _mesa_set_enable(ctx, tex->Target, GL_FALSE); |
||
1981 | |||
1982 | _mesa_meta_end(ctx); |
||
1983 | |||
1984 | if (mask) { |
||
1985 | _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, |
||
1986 | dstX0, dstY0, dstX1, dstY1, mask, filter); |
||
1987 | } |
||
1988 | } |
||
1989 | |||
1990 | static void |
||
1991 | meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit) |
||
1992 | { |
||
1993 | if (blit->ArrayObj) { |
||
1994 | _mesa_DeleteVertexArrays(1, &blit->ArrayObj); |
||
1995 | blit->ArrayObj = 0; |
||
1996 | _mesa_DeleteBuffers(1, &blit->VBO); |
||
1997 | blit->VBO = 0; |
||
1998 | } |
||
1999 | if (blit->DepthFP) { |
||
2000 | _mesa_DeleteProgramsARB(1, &blit->DepthFP); |
||
2001 | blit->DepthFP = 0; |
||
2002 | } |
||
2003 | |||
2004 | _mesa_DeleteObjectARB(blit->ShaderProg); |
||
2005 | blit->ShaderProg = 0; |
||
2006 | _mesa_DeleteObjectARB(blit->RectShaderProg); |
||
2007 | blit->RectShaderProg = 0; |
||
2008 | |||
2009 | _mesa_DeleteTextures(1, &blit->depthTex.TexObj); |
||
2010 | blit->depthTex.TexObj = 0; |
||
2011 | } |
||
2012 | |||
2013 | |||
2014 | /** |
||
2015 | * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. |
||
2016 | */ |
||
2017 | void |
||
2018 | _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) |
||
2019 | { |
||
2020 | struct clear_state *clear = &ctx->Meta->Clear; |
||
2021 | struct vertex { |
||
2022 | GLfloat x, y, z, r, g, b, a; |
||
2023 | }; |
||
2024 | struct vertex verts[4]; |
||
2025 | /* save all state but scissor, pixel pack/unpack */ |
||
2026 | GLbitfield metaSave = (MESA_META_ALL - |
||
2027 | MESA_META_SCISSOR - |
||
2028 | MESA_META_PIXEL_STORE - |
||
2029 | MESA_META_CONDITIONAL_RENDER - |
||
2030 | MESA_META_FRAMEBUFFER_SRGB); |
||
2031 | const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; |
||
2032 | |||
2033 | if (buffers & BUFFER_BITS_COLOR) { |
||
2034 | /* if clearing color buffers, don't save/restore colormask */ |
||
2035 | metaSave -= MESA_META_COLOR_MASK; |
||
2036 | } |
||
2037 | |||
2038 | _mesa_meta_begin(ctx, metaSave); |
||
2039 | |||
2040 | if (clear->ArrayObj == 0) { |
||
2041 | /* one-time setup */ |
||
2042 | |||
2043 | /* create vertex array object */ |
||
2044 | _mesa_GenVertexArrays(1, &clear->ArrayObj); |
||
2045 | _mesa_BindVertexArray(clear->ArrayObj); |
||
2046 | |||
2047 | /* create vertex array buffer */ |
||
2048 | _mesa_GenBuffers(1, &clear->VBO); |
||
2049 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); |
||
2050 | |||
2051 | /* setup vertex arrays */ |
||
2052 | _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
2053 | _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); |
||
2054 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
2055 | _mesa_EnableClientState(GL_COLOR_ARRAY); |
||
2056 | } |
||
2057 | else { |
||
2058 | _mesa_BindVertexArray(clear->ArrayObj); |
||
2059 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); |
||
2060 | } |
||
2061 | |||
2062 | /* GL_COLOR_BUFFER_BIT */ |
||
2063 | if (buffers & BUFFER_BITS_COLOR) { |
||
2064 | /* leave colormask, glDrawBuffer state as-is */ |
||
2065 | |||
2066 | /* Clears never have the color clamped. */ |
||
2067 | if (ctx->Extensions.ARB_color_buffer_float) |
||
2068 | _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); |
||
2069 | } |
||
2070 | else { |
||
2071 | ASSERT(metaSave & MESA_META_COLOR_MASK); |
||
2072 | _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
||
2073 | } |
||
2074 | |||
2075 | /* GL_DEPTH_BUFFER_BIT */ |
||
2076 | if (buffers & BUFFER_BIT_DEPTH) { |
||
2077 | _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); |
||
2078 | _mesa_DepthFunc(GL_ALWAYS); |
||
2079 | _mesa_DepthMask(GL_TRUE); |
||
2080 | } |
||
2081 | else { |
||
2082 | assert(!ctx->Depth.Test); |
||
2083 | } |
||
2084 | |||
2085 | /* GL_STENCIL_BUFFER_BIT */ |
||
2086 | if (buffers & BUFFER_BIT_STENCIL) { |
||
2087 | _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); |
||
2088 | _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, |
||
2089 | GL_REPLACE, GL_REPLACE, GL_REPLACE); |
||
2090 | _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, |
||
2091 | ctx->Stencil.Clear & stencilMax, |
||
2092 | ctx->Stencil.WriteMask[0]); |
||
2093 | } |
||
2094 | else { |
||
2095 | assert(!ctx->Stencil.Enabled); |
||
2096 | } |
||
2097 | |||
2098 | /* vertex positions/colors */ |
||
2099 | { |
||
2100 | const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin; |
||
2101 | const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin; |
||
2102 | const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax; |
||
2103 | const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax; |
||
2104 | const GLfloat z = invert_z(ctx->Depth.Clear); |
||
2105 | GLuint i; |
||
2106 | |||
2107 | verts[0].x = x0; |
||
2108 | verts[0].y = y0; |
||
2109 | verts[0].z = z; |
||
2110 | verts[1].x = x1; |
||
2111 | verts[1].y = y0; |
||
2112 | verts[1].z = z; |
||
2113 | verts[2].x = x1; |
||
2114 | verts[2].y = y1; |
||
2115 | verts[2].z = z; |
||
2116 | verts[3].x = x0; |
||
2117 | verts[3].y = y1; |
||
2118 | verts[3].z = z; |
||
2119 | |||
2120 | /* vertex colors */ |
||
2121 | for (i = 0; i < 4; i++) { |
||
2122 | verts[i].r = ctx->Color.ClearColor.f[0]; |
||
2123 | verts[i].g = ctx->Color.ClearColor.f[1]; |
||
2124 | verts[i].b = ctx->Color.ClearColor.f[2]; |
||
2125 | verts[i].a = ctx->Color.ClearColor.f[3]; |
||
2126 | } |
||
2127 | |||
2128 | /* upload new vertex data */ |
||
2129 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, |
||
2130 | GL_DYNAMIC_DRAW_ARB); |
||
2131 | } |
||
2132 | |||
2133 | /* draw quad */ |
||
2134 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2135 | |||
2136 | _mesa_meta_end(ctx); |
||
2137 | } |
||
2138 | |||
2139 | static void |
||
2140 | meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) |
||
2141 | { |
||
2142 | const char *vs_source = |
||
2143 | "attribute vec4 position;\n" |
||
2144 | "void main()\n" |
||
2145 | "{\n" |
||
2146 | " gl_Position = position;\n" |
||
2147 | "}\n"; |
||
2148 | const char *fs_source = |
||
2149 | "#ifdef GL_ES\n" |
||
2150 | "precision highp float;\n" |
||
2151 | "#endif\n" |
||
2152 | "uniform vec4 color;\n" |
||
2153 | "void main()\n" |
||
2154 | "{\n" |
||
2155 | " gl_FragColor = color;\n" |
||
2156 | "}\n"; |
||
2157 | GLuint vs, fs; |
||
2158 | bool has_integer_textures; |
||
2159 | |||
2160 | if (clear->ArrayObj != 0) |
||
2161 | return; |
||
2162 | |||
2163 | /* create vertex array object */ |
||
2164 | _mesa_GenVertexArrays(1, &clear->ArrayObj); |
||
2165 | _mesa_BindVertexArray(clear->ArrayObj); |
||
2166 | |||
2167 | /* create vertex array buffer */ |
||
2168 | _mesa_GenBuffers(1, &clear->VBO); |
||
2169 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); |
||
2170 | |||
2171 | /* setup vertex arrays */ |
||
2172 | _mesa_VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); |
||
2173 | _mesa_EnableVertexAttribArray(0); |
||
2174 | |||
2175 | vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER); |
||
2176 | _mesa_ShaderSource(vs, 1, &vs_source, NULL); |
||
2177 | _mesa_CompileShader(vs); |
||
2178 | |||
2179 | fs = _mesa_CreateShaderObjectARB(GL_FRAGMENT_SHADER); |
||
2180 | _mesa_ShaderSource(fs, 1, &fs_source, NULL); |
||
2181 | _mesa_CompileShader(fs); |
||
2182 | |||
2183 | clear->ShaderProg = _mesa_CreateProgramObjectARB(); |
||
2184 | _mesa_AttachShader(clear->ShaderProg, fs); |
||
2185 | _mesa_DeleteObjectARB(fs); |
||
2186 | _mesa_AttachShader(clear->ShaderProg, vs); |
||
2187 | _mesa_DeleteObjectARB(vs); |
||
2188 | _mesa_BindAttribLocation(clear->ShaderProg, 0, "position"); |
||
2189 | _mesa_LinkProgram(clear->ShaderProg); |
||
2190 | |||
2191 | clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg, |
||
2192 | "color"); |
||
2193 | |||
2194 | has_integer_textures = _mesa_is_gles3(ctx) || |
||
2195 | (_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130); |
||
2196 | |||
2197 | if (has_integer_textures) { |
||
2198 | void *shader_source_mem_ctx = ralloc_context(NULL); |
||
2199 | const char *vs_int_source = |
||
2200 | ralloc_asprintf(shader_source_mem_ctx, |
||
2201 | "#version %s\n" |
||
2202 | "in vec4 position;\n" |
||
2203 | "void main()\n" |
||
2204 | "{\n" |
||
2205 | " gl_Position = position;\n" |
||
2206 | "}\n", |
||
2207 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); |
||
2208 | const char *fs_int_source = |
||
2209 | ralloc_asprintf(shader_source_mem_ctx, |
||
2210 | "#version %s\n" |
||
2211 | "#ifdef GL_ES\n" |
||
2212 | "precision highp float;\n" |
||
2213 | "#endif\n" |
||
2214 | "uniform ivec4 color;\n" |
||
2215 | "out ivec4 out_color;\n" |
||
2216 | "\n" |
||
2217 | "void main()\n" |
||
2218 | "{\n" |
||
2219 | " out_color = color;\n" |
||
2220 | "}\n", |
||
2221 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); |
||
2222 | |||
2223 | vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source); |
||
2224 | fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source); |
||
2225 | ralloc_free(shader_source_mem_ctx); |
||
2226 | |||
2227 | clear->IntegerShaderProg = _mesa_CreateProgramObjectARB(); |
||
2228 | _mesa_AttachShader(clear->IntegerShaderProg, fs); |
||
2229 | _mesa_DeleteObjectARB(fs); |
||
2230 | _mesa_AttachShader(clear->IntegerShaderProg, vs); |
||
2231 | _mesa_DeleteObjectARB(vs); |
||
2232 | _mesa_BindAttribLocation(clear->IntegerShaderProg, 0, "position"); |
||
2233 | |||
2234 | /* Note that user-defined out attributes get automatically assigned |
||
2235 | * locations starting from 0, so we don't need to explicitly |
||
2236 | * BindFragDataLocation to 0. |
||
2237 | */ |
||
2238 | |||
2239 | link_program_with_debug(ctx, clear->IntegerShaderProg); |
||
2240 | |||
2241 | clear->IntegerColorLocation = |
||
2242 | _mesa_GetUniformLocation(clear->IntegerShaderProg, "color"); |
||
2243 | } |
||
2244 | } |
||
2245 | |||
2246 | static void |
||
2247 | meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear) |
||
2248 | { |
||
2249 | if (clear->ArrayObj == 0) |
||
2250 | return; |
||
2251 | _mesa_DeleteVertexArrays(1, &clear->ArrayObj); |
||
2252 | clear->ArrayObj = 0; |
||
2253 | _mesa_DeleteBuffers(1, &clear->VBO); |
||
2254 | clear->VBO = 0; |
||
2255 | _mesa_DeleteObjectARB(clear->ShaderProg); |
||
2256 | clear->ShaderProg = 0; |
||
2257 | |||
2258 | if (clear->IntegerShaderProg) { |
||
2259 | _mesa_DeleteObjectARB(clear->IntegerShaderProg); |
||
2260 | clear->IntegerShaderProg = 0; |
||
2261 | } |
||
2262 | } |
||
2263 | |||
2264 | /** |
||
2265 | * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. |
||
2266 | */ |
||
2267 | void |
||
2268 | _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) |
||
2269 | { |
||
2270 | struct clear_state *clear = &ctx->Meta->Clear; |
||
2271 | GLbitfield metaSave; |
||
2272 | const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; |
||
2273 | struct gl_framebuffer *fb = ctx->DrawBuffer; |
||
2274 | const float x0 = ((float)fb->_Xmin / fb->Width) * 2.0f - 1.0f; |
||
2275 | const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f; |
||
2276 | const float x1 = ((float)fb->_Xmax / fb->Width) * 2.0f - 1.0f; |
||
2277 | const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f; |
||
2278 | const float z = -invert_z(ctx->Depth.Clear); |
||
2279 | struct vertex { |
||
2280 | GLfloat x, y, z; |
||
2281 | } verts[4]; |
||
2282 | |||
2283 | metaSave = (MESA_META_ALPHA_TEST | |
||
2284 | MESA_META_BLEND | |
||
2285 | MESA_META_DEPTH_TEST | |
||
2286 | MESA_META_RASTERIZATION | |
||
2287 | MESA_META_SHADER | |
||
2288 | MESA_META_STENCIL_TEST | |
||
2289 | MESA_META_VERTEX | |
||
2290 | MESA_META_VIEWPORT | |
||
2291 | MESA_META_CLIP | |
||
2292 | MESA_META_CLAMP_FRAGMENT_COLOR | |
||
2293 | MESA_META_MULTISAMPLE | |
||
2294 | MESA_META_OCCLUSION_QUERY); |
||
2295 | |||
2296 | if (!(buffers & BUFFER_BITS_COLOR)) { |
||
2297 | /* We'll use colormask to disable color writes. Otherwise, |
||
2298 | * respect color mask |
||
2299 | */ |
||
2300 | metaSave |= MESA_META_COLOR_MASK; |
||
2301 | } |
||
2302 | |||
2303 | _mesa_meta_begin(ctx, metaSave); |
||
2304 | |||
2305 | meta_glsl_clear_init(ctx, clear); |
||
2306 | |||
2307 | if (fb->_IntegerColor) { |
||
2308 | _mesa_UseProgram(clear->IntegerShaderProg); |
||
2309 | _mesa_Uniform4iv(clear->IntegerColorLocation, 1, |
||
2310 | ctx->Color.ClearColor.i); |
||
2311 | } else { |
||
2312 | _mesa_UseProgram(clear->ShaderProg); |
||
2313 | _mesa_Uniform4fv(clear->ColorLocation, 1, |
||
2314 | ctx->Color.ClearColor.f); |
||
2315 | } |
||
2316 | |||
2317 | _mesa_BindVertexArray(clear->ArrayObj); |
||
2318 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); |
||
2319 | |||
2320 | /* GL_COLOR_BUFFER_BIT */ |
||
2321 | if (buffers & BUFFER_BITS_COLOR) { |
||
2322 | /* leave colormask, glDrawBuffer state as-is */ |
||
2323 | |||
2324 | /* Clears never have the color clamped. */ |
||
2325 | if (ctx->Extensions.ARB_color_buffer_float) |
||
2326 | _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); |
||
2327 | } |
||
2328 | else { |
||
2329 | ASSERT(metaSave & MESA_META_COLOR_MASK); |
||
2330 | _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
||
2331 | } |
||
2332 | |||
2333 | /* GL_DEPTH_BUFFER_BIT */ |
||
2334 | if (buffers & BUFFER_BIT_DEPTH) { |
||
2335 | _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); |
||
2336 | _mesa_DepthFunc(GL_ALWAYS); |
||
2337 | _mesa_DepthMask(GL_TRUE); |
||
2338 | } |
||
2339 | else { |
||
2340 | assert(!ctx->Depth.Test); |
||
2341 | } |
||
2342 | |||
2343 | /* GL_STENCIL_BUFFER_BIT */ |
||
2344 | if (buffers & BUFFER_BIT_STENCIL) { |
||
2345 | _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); |
||
2346 | _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, |
||
2347 | GL_REPLACE, GL_REPLACE, GL_REPLACE); |
||
2348 | _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, |
||
2349 | ctx->Stencil.Clear & stencilMax, |
||
2350 | ctx->Stencil.WriteMask[0]); |
||
2351 | } |
||
2352 | else { |
||
2353 | assert(!ctx->Stencil.Enabled); |
||
2354 | } |
||
2355 | |||
2356 | /* vertex positions */ |
||
2357 | verts[0].x = x0; |
||
2358 | verts[0].y = y0; |
||
2359 | verts[0].z = z; |
||
2360 | verts[1].x = x1; |
||
2361 | verts[1].y = y0; |
||
2362 | verts[1].z = z; |
||
2363 | verts[2].x = x1; |
||
2364 | verts[2].y = y1; |
||
2365 | verts[2].z = z; |
||
2366 | verts[3].x = x0; |
||
2367 | verts[3].y = y1; |
||
2368 | verts[3].z = z; |
||
2369 | |||
2370 | /* upload new vertex data */ |
||
2371 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, |
||
2372 | GL_DYNAMIC_DRAW_ARB); |
||
2373 | |||
2374 | /* draw quad */ |
||
2375 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2376 | |||
2377 | _mesa_meta_end(ctx); |
||
2378 | } |
||
2379 | |||
2380 | /** |
||
2381 | * Meta implementation of ctx->Driver.CopyPixels() in terms |
||
2382 | * of texture mapping and polygon rendering and GLSL shaders. |
||
2383 | */ |
||
2384 | void |
||
2385 | _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, |
||
2386 | GLsizei width, GLsizei height, |
||
2387 | GLint dstX, GLint dstY, GLenum type) |
||
2388 | { |
||
2389 | struct copypix_state *copypix = &ctx->Meta->CopyPix; |
||
2390 | struct temp_texture *tex = get_temp_texture(ctx); |
||
2391 | struct vertex { |
||
2392 | GLfloat x, y, z, s, t; |
||
2393 | }; |
||
2394 | struct vertex verts[4]; |
||
2395 | GLboolean newTex; |
||
2396 | GLenum intFormat = GL_RGBA; |
||
2397 | |||
2398 | if (type != GL_COLOR || |
||
2399 | ctx->_ImageTransferState || |
||
2400 | ctx->Fog.Enabled || |
||
2401 | width > tex->MaxSize || |
||
2402 | height > tex->MaxSize) { |
||
2403 | /* XXX avoid this fallback */ |
||
2404 | _swrast_CopyPixels(ctx, srcX, srcY, width, height, dstX, dstY, type); |
||
2405 | return; |
||
2406 | } |
||
2407 | |||
2408 | /* Most GL state applies to glCopyPixels, but a there's a few things |
||
2409 | * we need to override: |
||
2410 | */ |
||
2411 | _mesa_meta_begin(ctx, (MESA_META_RASTERIZATION | |
||
2412 | MESA_META_SHADER | |
||
2413 | MESA_META_TEXTURE | |
||
2414 | MESA_META_TRANSFORM | |
||
2415 | MESA_META_CLIP | |
||
2416 | MESA_META_VERTEX | |
||
2417 | MESA_META_VIEWPORT)); |
||
2418 | |||
2419 | if (copypix->ArrayObj == 0) { |
||
2420 | /* one-time setup */ |
||
2421 | |||
2422 | /* create vertex array object */ |
||
2423 | _mesa_GenVertexArrays(1, ©pix->ArrayObj); |
||
2424 | _mesa_BindVertexArray(copypix->ArrayObj); |
||
2425 | |||
2426 | /* create vertex array buffer */ |
||
2427 | _mesa_GenBuffers(1, ©pix->VBO); |
||
2428 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO); |
||
2429 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
2430 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
2431 | |||
2432 | /* setup vertex arrays */ |
||
2433 | _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
2434 | _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); |
||
2435 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
2436 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
2437 | } |
||
2438 | else { |
||
2439 | _mesa_BindVertexArray(copypix->ArrayObj); |
||
2440 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO); |
||
2441 | } |
||
2442 | |||
2443 | newTex = alloc_texture(tex, width, height, intFormat); |
||
2444 | |||
2445 | /* vertex positions, texcoords (after texture allocation!) */ |
||
2446 | { |
||
2447 | const GLfloat dstX0 = (GLfloat) dstX; |
||
2448 | const GLfloat dstY0 = (GLfloat) dstY; |
||
2449 | const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX; |
||
2450 | const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY; |
||
2451 | const GLfloat z = invert_z(ctx->Current.RasterPos[2]); |
||
2452 | |||
2453 | verts[0].x = dstX0; |
||
2454 | verts[0].y = dstY0; |
||
2455 | verts[0].z = z; |
||
2456 | verts[0].s = 0.0F; |
||
2457 | verts[0].t = 0.0F; |
||
2458 | verts[1].x = dstX1; |
||
2459 | verts[1].y = dstY0; |
||
2460 | verts[1].z = z; |
||
2461 | verts[1].s = tex->Sright; |
||
2462 | verts[1].t = 0.0F; |
||
2463 | verts[2].x = dstX1; |
||
2464 | verts[2].y = dstY1; |
||
2465 | verts[2].z = z; |
||
2466 | verts[2].s = tex->Sright; |
||
2467 | verts[2].t = tex->Ttop; |
||
2468 | verts[3].x = dstX0; |
||
2469 | verts[3].y = dstY1; |
||
2470 | verts[3].z = z; |
||
2471 | verts[3].s = 0.0F; |
||
2472 | verts[3].t = tex->Ttop; |
||
2473 | |||
2474 | /* upload new vertex data */ |
||
2475 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
2476 | } |
||
2477 | |||
2478 | /* Alloc/setup texture */ |
||
2479 | setup_copypix_texture(ctx, tex, newTex, srcX, srcY, width, height, |
||
2480 | GL_RGBA, GL_NEAREST); |
||
2481 | |||
2482 | _mesa_set_enable(ctx, tex->Target, GL_TRUE); |
||
2483 | |||
2484 | /* draw textured quad */ |
||
2485 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2486 | |||
2487 | _mesa_set_enable(ctx, tex->Target, GL_FALSE); |
||
2488 | |||
2489 | _mesa_meta_end(ctx); |
||
2490 | } |
||
2491 | |||
2492 | |||
2493 | |||
2494 | /** |
||
2495 | * When the glDrawPixels() image size is greater than the max rectangle |
||
2496 | * texture size we use this function to break the glDrawPixels() image |
||
2497 | * into tiles which fit into the max texture size. |
||
2498 | */ |
||
2499 | static void |
||
2500 | tiled_draw_pixels(struct gl_context *ctx, |
||
2501 | GLint tileSize, |
||
2502 | GLint x, GLint y, GLsizei width, GLsizei height, |
||
2503 | GLenum format, GLenum type, |
||
2504 | const struct gl_pixelstore_attrib *unpack, |
||
2505 | const GLvoid *pixels) |
||
2506 | { |
||
2507 | struct gl_pixelstore_attrib tileUnpack = *unpack; |
||
2508 | GLint i, j; |
||
2509 | |||
2510 | if (tileUnpack.RowLength == 0) |
||
2511 | tileUnpack.RowLength = width; |
||
2512 | |||
2513 | for (i = 0; i < width; i += tileSize) { |
||
2514 | const GLint tileWidth = MIN2(tileSize, width - i); |
||
2515 | const GLint tileX = (GLint) (x + i * ctx->Pixel.ZoomX); |
||
2516 | |||
2517 | tileUnpack.SkipPixels = unpack->SkipPixels + i; |
||
2518 | |||
2519 | for (j = 0; j < height; j += tileSize) { |
||
2520 | const GLint tileHeight = MIN2(tileSize, height - j); |
||
2521 | const GLint tileY = (GLint) (y + j * ctx->Pixel.ZoomY); |
||
2522 | |||
2523 | tileUnpack.SkipRows = unpack->SkipRows + j; |
||
2524 | |||
2525 | _mesa_meta_DrawPixels(ctx, tileX, tileY, tileWidth, tileHeight, |
||
2526 | format, type, &tileUnpack, pixels); |
||
2527 | } |
||
2528 | } |
||
2529 | } |
||
2530 | |||
2531 | |||
2532 | /** |
||
2533 | * One-time init for drawing stencil pixels. |
||
2534 | */ |
||
2535 | static void |
||
2536 | init_draw_stencil_pixels(struct gl_context *ctx) |
||
2537 | { |
||
2538 | /* This program is run eight times, once for each stencil bit. |
||
2539 | * The stencil values to draw are found in an 8-bit alpha texture. |
||
2540 | * We read the texture/stencil value and test if bit 'b' is set. |
||
2541 | * If the bit is not set, use KIL to kill the fragment. |
||
2542 | * Finally, we use the stencil test to update the stencil buffer. |
||
2543 | * |
||
2544 | * The basic algorithm for checking if a bit is set is: |
||
2545 | * if (is_odd(value / (1 << bit))) |
||
2546 | * result is one (or non-zero). |
||
2547 | * else |
||
2548 | * result is zero. |
||
2549 | * The program parameter contains three values: |
||
2550 | * parm.x = 255 / (1 << bit) |
||
2551 | * parm.y = 0.5 |
||
2552 | * parm.z = 0.0 |
||
2553 | */ |
||
2554 | static const char *program = |
||
2555 | "!!ARBfp1.0\n" |
||
2556 | "PARAM parm = program.local[0]; \n" |
||
2557 | "TEMP t; \n" |
||
2558 | "TEX t, fragment.texcoord[0], texture[0], %s; \n" /* NOTE %s here! */ |
||
2559 | "# t = t * 255 / bit \n" |
||
2560 | "MUL t.x, t.a, parm.x; \n" |
||
2561 | "# t = (int) t \n" |
||
2562 | "FRC t.y, t.x; \n" |
||
2563 | "SUB t.x, t.x, t.y; \n" |
||
2564 | "# t = t * 0.5 \n" |
||
2565 | "MUL t.x, t.x, parm.y; \n" |
||
2566 | "# t = fract(t.x) \n" |
||
2567 | "FRC t.x, t.x; # if t.x != 0, then the bit is set \n" |
||
2568 | "# t.x = (t.x == 0 ? 1 : 0) \n" |
||
2569 | "SGE t.x, -t.x, parm.z; \n" |
||
2570 | "KIL -t.x; \n" |
||
2571 | "# for debug only \n" |
||
2572 | "#MOV result.color, t.x; \n" |
||
2573 | "END \n"; |
||
2574 | char program2[1000]; |
||
2575 | struct drawpix_state *drawpix = &ctx->Meta->DrawPix; |
||
2576 | struct temp_texture *tex = get_temp_texture(ctx); |
||
2577 | const char *texTarget; |
||
2578 | |||
2579 | assert(drawpix->StencilFP == 0); |
||
2580 | |||
2581 | /* replace %s with "RECT" or "2D" */ |
||
2582 | assert(strlen(program) + 4 < sizeof(program2)); |
||
2583 | if (tex->Target == GL_TEXTURE_RECTANGLE) |
||
2584 | texTarget = "RECT"; |
||
2585 | else |
||
2586 | texTarget = "2D"; |
||
2587 | _mesa_snprintf(program2, sizeof(program2), program, texTarget); |
||
2588 | |||
2589 | _mesa_GenProgramsARB(1, &drawpix->StencilFP); |
||
2590 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); |
||
2591 | _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, |
||
2592 | strlen(program2), (const GLubyte *) program2); |
||
2593 | } |
||
2594 | |||
2595 | |||
2596 | /** |
||
2597 | * One-time init for drawing depth pixels. |
||
2598 | */ |
||
2599 | static void |
||
2600 | init_draw_depth_pixels(struct gl_context *ctx) |
||
2601 | { |
||
2602 | static const char *program = |
||
2603 | "!!ARBfp1.0\n" |
||
2604 | "PARAM color = program.local[0]; \n" |
||
2605 | "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" |
||
2606 | "MOV result.color, color; \n" |
||
2607 | "END \n"; |
||
2608 | char program2[200]; |
||
2609 | struct drawpix_state *drawpix = &ctx->Meta->DrawPix; |
||
2610 | struct temp_texture *tex = get_temp_texture(ctx); |
||
2611 | const char *texTarget; |
||
2612 | |||
2613 | assert(drawpix->DepthFP == 0); |
||
2614 | |||
2615 | /* replace %s with "RECT" or "2D" */ |
||
2616 | assert(strlen(program) + 4 < sizeof(program2)); |
||
2617 | if (tex->Target == GL_TEXTURE_RECTANGLE) |
||
2618 | texTarget = "RECT"; |
||
2619 | else |
||
2620 | texTarget = "2D"; |
||
2621 | _mesa_snprintf(program2, sizeof(program2), program, texTarget); |
||
2622 | |||
2623 | _mesa_GenProgramsARB(1, &drawpix->DepthFP); |
||
2624 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); |
||
2625 | _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, |
||
2626 | strlen(program2), (const GLubyte *) program2); |
||
2627 | } |
||
2628 | |||
2629 | |||
2630 | /** |
||
2631 | * Meta implementation of ctx->Driver.DrawPixels() in terms |
||
2632 | * of texture mapping and polygon rendering. |
||
2633 | */ |
||
2634 | void |
||
2635 | _mesa_meta_DrawPixels(struct gl_context *ctx, |
||
2636 | GLint x, GLint y, GLsizei width, GLsizei height, |
||
2637 | GLenum format, GLenum type, |
||
2638 | const struct gl_pixelstore_attrib *unpack, |
||
2639 | const GLvoid *pixels) |
||
2640 | { |
||
2641 | struct drawpix_state *drawpix = &ctx->Meta->DrawPix; |
||
2642 | struct temp_texture *tex = get_temp_texture(ctx); |
||
2643 | const struct gl_pixelstore_attrib unpackSave = ctx->Unpack; |
||
2644 | const GLuint origStencilMask = ctx->Stencil.WriteMask[0]; |
||
2645 | struct vertex { |
||
2646 | GLfloat x, y, z, s, t; |
||
2647 | }; |
||
2648 | struct vertex verts[4]; |
||
2649 | GLenum texIntFormat; |
||
2650 | GLboolean fallback, newTex; |
||
2651 | GLbitfield metaExtraSave = 0x0; |
||
2652 | GLuint vbo; |
||
2653 | |||
2654 | /* |
||
2655 | * Determine if we can do the glDrawPixels with texture mapping. |
||
2656 | */ |
||
2657 | fallback = GL_FALSE; |
||
2658 | if (ctx->Fog.Enabled) { |
||
2659 | fallback = GL_TRUE; |
||
2660 | } |
||
2661 | |||
2662 | if (_mesa_is_color_format(format)) { |
||
2663 | /* use more compact format when possible */ |
||
2664 | /* XXX disable special case for GL_LUMINANCE for now to work around |
||
2665 | * apparent i965 driver bug (see bug #23670). |
||
2666 | */ |
||
2667 | if (/*format == GL_LUMINANCE ||*/ format == GL_LUMINANCE_ALPHA) |
||
2668 | texIntFormat = format; |
||
2669 | else |
||
2670 | texIntFormat = GL_RGBA; |
||
2671 | |||
2672 | /* If we're not supposed to clamp the resulting color, then just |
||
2673 | * promote our texture to fully float. We could do better by |
||
2674 | * just going for the matching set of channels, in floating |
||
2675 | * point. |
||
2676 | */ |
||
2677 | if (ctx->Color.ClampFragmentColor != GL_TRUE && |
||
2678 | ctx->Extensions.ARB_texture_float) |
||
2679 | texIntFormat = GL_RGBA32F; |
||
2680 | } |
||
2681 | else if (_mesa_is_stencil_format(format)) { |
||
2682 | if (ctx->Extensions.ARB_fragment_program && |
||
2683 | ctx->Pixel.IndexShift == 0 && |
||
2684 | ctx->Pixel.IndexOffset == 0 && |
||
2685 | type == GL_UNSIGNED_BYTE) { |
||
2686 | /* We'll store stencil as alpha. This only works for GLubyte |
||
2687 | * image data because of how incoming values are mapped to alpha |
||
2688 | * in [0,1]. |
||
2689 | */ |
||
2690 | texIntFormat = GL_ALPHA; |
||
2691 | metaExtraSave = (MESA_META_COLOR_MASK | |
||
2692 | MESA_META_DEPTH_TEST | |
||
2693 | MESA_META_PIXEL_TRANSFER | |
||
2694 | MESA_META_SHADER | |
||
2695 | MESA_META_STENCIL_TEST); |
||
2696 | } |
||
2697 | else { |
||
2698 | fallback = GL_TRUE; |
||
2699 | } |
||
2700 | } |
||
2701 | else if (_mesa_is_depth_format(format)) { |
||
2702 | if (ctx->Extensions.ARB_depth_texture && |
||
2703 | ctx->Extensions.ARB_fragment_program) { |
||
2704 | texIntFormat = GL_DEPTH_COMPONENT; |
||
2705 | metaExtraSave = (MESA_META_SHADER); |
||
2706 | } |
||
2707 | else { |
||
2708 | fallback = GL_TRUE; |
||
2709 | } |
||
2710 | } |
||
2711 | else { |
||
2712 | fallback = GL_TRUE; |
||
2713 | } |
||
2714 | |||
2715 | if (fallback) { |
||
2716 | _swrast_DrawPixels(ctx, x, y, width, height, |
||
2717 | format, type, unpack, pixels); |
||
2718 | return; |
||
2719 | } |
||
2720 | |||
2721 | /* |
||
2722 | * Check image size against max texture size, draw as tiles if needed. |
||
2723 | */ |
||
2724 | if (width > tex->MaxSize || height > tex->MaxSize) { |
||
2725 | tiled_draw_pixels(ctx, tex->MaxSize, x, y, width, height, |
||
2726 | format, type, unpack, pixels); |
||
2727 | return; |
||
2728 | } |
||
2729 | |||
2730 | /* Most GL state applies to glDrawPixels (like blending, stencil, etc), |
||
2731 | * but a there's a few things we need to override: |
||
2732 | */ |
||
2733 | _mesa_meta_begin(ctx, (MESA_META_RASTERIZATION | |
||
2734 | MESA_META_SHADER | |
||
2735 | MESA_META_TEXTURE | |
||
2736 | MESA_META_TRANSFORM | |
||
2737 | MESA_META_CLIP | |
||
2738 | MESA_META_VERTEX | |
||
2739 | MESA_META_VIEWPORT | |
||
2740 | metaExtraSave)); |
||
2741 | |||
2742 | newTex = alloc_texture(tex, width, height, texIntFormat); |
||
2743 | |||
2744 | /* vertex positions, texcoords (after texture allocation!) */ |
||
2745 | { |
||
2746 | const GLfloat x0 = (GLfloat) x; |
||
2747 | const GLfloat y0 = (GLfloat) y; |
||
2748 | const GLfloat x1 = x + width * ctx->Pixel.ZoomX; |
||
2749 | const GLfloat y1 = y + height * ctx->Pixel.ZoomY; |
||
2750 | const GLfloat z = invert_z(ctx->Current.RasterPos[2]); |
||
2751 | |||
2752 | verts[0].x = x0; |
||
2753 | verts[0].y = y0; |
||
2754 | verts[0].z = z; |
||
2755 | verts[0].s = 0.0F; |
||
2756 | verts[0].t = 0.0F; |
||
2757 | verts[1].x = x1; |
||
2758 | verts[1].y = y0; |
||
2759 | verts[1].z = z; |
||
2760 | verts[1].s = tex->Sright; |
||
2761 | verts[1].t = 0.0F; |
||
2762 | verts[2].x = x1; |
||
2763 | verts[2].y = y1; |
||
2764 | verts[2].z = z; |
||
2765 | verts[2].s = tex->Sright; |
||
2766 | verts[2].t = tex->Ttop; |
||
2767 | verts[3].x = x0; |
||
2768 | verts[3].y = y1; |
||
2769 | verts[3].z = z; |
||
2770 | verts[3].s = 0.0F; |
||
2771 | verts[3].t = tex->Ttop; |
||
2772 | } |
||
2773 | |||
2774 | if (drawpix->ArrayObj == 0) { |
||
2775 | /* one-time setup: create vertex array object */ |
||
2776 | _mesa_GenVertexArrays(1, &drawpix->ArrayObj); |
||
2777 | } |
||
2778 | _mesa_BindVertexArray(drawpix->ArrayObj); |
||
2779 | |||
2780 | /* create vertex array buffer */ |
||
2781 | _mesa_GenBuffers(1, &vbo); |
||
2782 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, vbo); |
||
2783 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
2784 | verts, GL_DYNAMIC_DRAW_ARB); |
||
2785 | |||
2786 | /* setup vertex arrays */ |
||
2787 | _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
2788 | _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); |
||
2789 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
2790 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
2791 | |||
2792 | /* set given unpack params */ |
||
2793 | ctx->Unpack = *unpack; |
||
2794 | |||
2795 | _mesa_set_enable(ctx, tex->Target, GL_TRUE); |
||
2796 | |||
2797 | if (_mesa_is_stencil_format(format)) { |
||
2798 | /* Drawing stencil */ |
||
2799 | GLint bit; |
||
2800 | |||
2801 | if (!drawpix->StencilFP) |
||
2802 | init_draw_stencil_pixels(ctx); |
||
2803 | |||
2804 | setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, |
||
2805 | GL_ALPHA, type, pixels); |
||
2806 | |||
2807 | _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
||
2808 | |||
2809 | _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); |
||
2810 | |||
2811 | /* set all stencil bits to 0 */ |
||
2812 | _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
||
2813 | _mesa_StencilFunc(GL_ALWAYS, 0, 255); |
||
2814 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2815 | |||
2816 | /* set stencil bits to 1 where needed */ |
||
2817 | _mesa_StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); |
||
2818 | |||
2819 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); |
||
2820 | _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); |
||
2821 | |||
2822 | for (bit = 0; bit < ctx->DrawBuffer->Visual.stencilBits; bit++) { |
||
2823 | const GLuint mask = 1 << bit; |
||
2824 | if (mask & origStencilMask) { |
||
2825 | _mesa_StencilFunc(GL_ALWAYS, mask, mask); |
||
2826 | _mesa_StencilMask(mask); |
||
2827 | |||
2828 | _mesa_ProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, |
||
2829 | 255.0 / mask, 0.5, 0.0, 0.0); |
||
2830 | |||
2831 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2832 | } |
||
2833 | } |
||
2834 | } |
||
2835 | else if (_mesa_is_depth_format(format)) { |
||
2836 | /* Drawing depth */ |
||
2837 | if (!drawpix->DepthFP) |
||
2838 | init_draw_depth_pixels(ctx); |
||
2839 | |||
2840 | _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); |
||
2841 | _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); |
||
2842 | |||
2843 | /* polygon color = current raster color */ |
||
2844 | _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, |
||
2845 | ctx->Current.RasterColor); |
||
2846 | |||
2847 | setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, |
||
2848 | format, type, pixels); |
||
2849 | |||
2850 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2851 | } |
||
2852 | else { |
||
2853 | /* Drawing RGBA */ |
||
2854 | setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, |
||
2855 | format, type, pixels); |
||
2856 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
2857 | } |
||
2858 | |||
2859 | _mesa_set_enable(ctx, tex->Target, GL_FALSE); |
||
2860 | |||
2861 | _mesa_DeleteBuffers(1, &vbo); |
||
2862 | |||
2863 | /* restore unpack params */ |
||
2864 | ctx->Unpack = unpackSave; |
||
2865 | |||
2866 | _mesa_meta_end(ctx); |
||
2867 | } |
||
2868 | |||
2869 | static GLboolean |
||
2870 | alpha_test_raster_color(struct gl_context *ctx) |
||
2871 | { |
||
2872 | GLfloat alpha = ctx->Current.RasterColor[ACOMP]; |
||
2873 | GLfloat ref = ctx->Color.AlphaRef; |
||
2874 | |||
2875 | switch (ctx->Color.AlphaFunc) { |
||
2876 | case GL_NEVER: |
||
2877 | return GL_FALSE; |
||
2878 | case GL_LESS: |
||
2879 | return alpha < ref; |
||
2880 | case GL_EQUAL: |
||
2881 | return alpha == ref; |
||
2882 | case GL_LEQUAL: |
||
2883 | return alpha <= ref; |
||
2884 | case GL_GREATER: |
||
2885 | return alpha > ref; |
||
2886 | case GL_NOTEQUAL: |
||
2887 | return alpha != ref; |
||
2888 | case GL_GEQUAL: |
||
2889 | return alpha >= ref; |
||
2890 | case GL_ALWAYS: |
||
2891 | return GL_TRUE; |
||
2892 | default: |
||
2893 | assert(0); |
||
2894 | return GL_FALSE; |
||
2895 | } |
||
2896 | } |
||
2897 | |||
2898 | /** |
||
2899 | * Do glBitmap with a alpha texture quad. Use the alpha test to cull |
||
2900 | * the 'off' bits. A bitmap cache as in the gallium/mesa state |
||
2901 | * tracker would improve performance a lot. |
||
2902 | */ |
||
2903 | void |
||
2904 | _mesa_meta_Bitmap(struct gl_context *ctx, |
||
2905 | GLint x, GLint y, GLsizei width, GLsizei height, |
||
2906 | const struct gl_pixelstore_attrib *unpack, |
||
2907 | const GLubyte *bitmap1) |
||
2908 | { |
||
2909 | struct bitmap_state *bitmap = &ctx->Meta->Bitmap; |
||
2910 | struct temp_texture *tex = get_bitmap_temp_texture(ctx); |
||
2911 | const GLenum texIntFormat = GL_ALPHA; |
||
2912 | const struct gl_pixelstore_attrib unpackSave = *unpack; |
||
2913 | GLubyte fg, bg; |
||
2914 | struct vertex { |
||
2915 | GLfloat x, y, z, s, t, r, g, b, a; |
||
2916 | }; |
||
2917 | struct vertex verts[4]; |
||
2918 | GLboolean newTex; |
||
2919 | GLubyte *bitmap8; |
||
2920 | |||
2921 | /* |
||
2922 | * Check if swrast fallback is needed. |
||
2923 | */ |
||
2924 | if (ctx->_ImageTransferState || |
||
2925 | ctx->FragmentProgram._Enabled || |
||
2926 | ctx->Fog.Enabled || |
||
2927 | ctx->Texture._EnabledUnits || |
||
2928 | width > tex->MaxSize || |
||
2929 | height > tex->MaxSize) { |
||
2930 | _swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1); |
||
2931 | return; |
||
2932 | } |
||
2933 | |||
2934 | if (ctx->Color.AlphaEnabled && !alpha_test_raster_color(ctx)) |
||
2935 | return; |
||
2936 | |||
2937 | /* Most GL state applies to glBitmap (like blending, stencil, etc), |
||
2938 | * but a there's a few things we need to override: |
||
2939 | */ |
||
2940 | _mesa_meta_begin(ctx, (MESA_META_ALPHA_TEST | |
||
2941 | MESA_META_PIXEL_STORE | |
||
2942 | MESA_META_RASTERIZATION | |
||
2943 | MESA_META_SHADER | |
||
2944 | MESA_META_TEXTURE | |
||
2945 | MESA_META_TRANSFORM | |
||
2946 | MESA_META_CLIP | |
||
2947 | MESA_META_VERTEX | |
||
2948 | MESA_META_VIEWPORT)); |
||
2949 | |||
2950 | if (bitmap->ArrayObj == 0) { |
||
2951 | /* one-time setup */ |
||
2952 | |||
2953 | /* create vertex array object */ |
||
2954 | _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj); |
||
2955 | _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj); |
||
2956 | |||
2957 | /* create vertex array buffer */ |
||
2958 | _mesa_GenBuffers(1, &bitmap->VBO); |
||
2959 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO); |
||
2960 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
2961 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
2962 | |||
2963 | /* setup vertex arrays */ |
||
2964 | _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
2965 | _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); |
||
2966 | _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); |
||
2967 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
2968 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
2969 | _mesa_EnableClientState(GL_COLOR_ARRAY); |
||
2970 | } |
||
2971 | else { |
||
2972 | _mesa_BindVertexArray(bitmap->ArrayObj); |
||
2973 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO); |
||
2974 | } |
||
2975 | |||
2976 | newTex = alloc_texture(tex, width, height, texIntFormat); |
||
2977 | |||
2978 | /* vertex positions, texcoords, colors (after texture allocation!) */ |
||
2979 | { |
||
2980 | const GLfloat x0 = (GLfloat) x; |
||
2981 | const GLfloat y0 = (GLfloat) y; |
||
2982 | const GLfloat x1 = (GLfloat) (x + width); |
||
2983 | const GLfloat y1 = (GLfloat) (y + height); |
||
2984 | const GLfloat z = invert_z(ctx->Current.RasterPos[2]); |
||
2985 | GLuint i; |
||
2986 | |||
2987 | verts[0].x = x0; |
||
2988 | verts[0].y = y0; |
||
2989 | verts[0].z = z; |
||
2990 | verts[0].s = 0.0F; |
||
2991 | verts[0].t = 0.0F; |
||
2992 | verts[1].x = x1; |
||
2993 | verts[1].y = y0; |
||
2994 | verts[1].z = z; |
||
2995 | verts[1].s = tex->Sright; |
||
2996 | verts[1].t = 0.0F; |
||
2997 | verts[2].x = x1; |
||
2998 | verts[2].y = y1; |
||
2999 | verts[2].z = z; |
||
3000 | verts[2].s = tex->Sright; |
||
3001 | verts[2].t = tex->Ttop; |
||
3002 | verts[3].x = x0; |
||
3003 | verts[3].y = y1; |
||
3004 | verts[3].z = z; |
||
3005 | verts[3].s = 0.0F; |
||
3006 | verts[3].t = tex->Ttop; |
||
3007 | |||
3008 | for (i = 0; i < 4; i++) { |
||
3009 | verts[i].r = ctx->Current.RasterColor[0]; |
||
3010 | verts[i].g = ctx->Current.RasterColor[1]; |
||
3011 | verts[i].b = ctx->Current.RasterColor[2]; |
||
3012 | verts[i].a = ctx->Current.RasterColor[3]; |
||
3013 | } |
||
3014 | |||
3015 | /* upload new vertex data */ |
||
3016 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
3017 | } |
||
3018 | |||
3019 | /* choose different foreground/background alpha values */ |
||
3020 | CLAMPED_FLOAT_TO_UBYTE(fg, ctx->Current.RasterColor[ACOMP]); |
||
3021 | bg = (fg > 127 ? 0 : 255); |
||
3022 | |||
3023 | bitmap1 = _mesa_map_pbo_source(ctx, &unpackSave, bitmap1); |
||
3024 | if (!bitmap1) { |
||
3025 | _mesa_meta_end(ctx); |
||
3026 | return; |
||
3027 | } |
||
3028 | |||
3029 | bitmap8 = malloc(width * height); |
||
3030 | if (bitmap8) { |
||
3031 | memset(bitmap8, bg, width * height); |
||
3032 | _mesa_expand_bitmap(width, height, &unpackSave, bitmap1, |
||
3033 | bitmap8, width, fg); |
||
3034 | |||
3035 | _mesa_set_enable(ctx, tex->Target, GL_TRUE); |
||
3036 | |||
3037 | _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE); |
||
3038 | _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg)); |
||
3039 | |||
3040 | setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, |
||
3041 | GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); |
||
3042 | |||
3043 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
3044 | |||
3045 | _mesa_set_enable(ctx, tex->Target, GL_FALSE); |
||
3046 | |||
3047 | free(bitmap8); |
||
3048 | } |
||
3049 | |||
3050 | _mesa_unmap_pbo_source(ctx, &unpackSave); |
||
3051 | |||
3052 | _mesa_meta_end(ctx); |
||
3053 | } |
||
3054 | |||
3055 | |||
3056 | /** |
||
3057 | * Check if the call to _mesa_meta_GenerateMipmap() will require a |
||
3058 | * software fallback. The fallback path will require that the texture |
||
3059 | * images are mapped. |
||
3060 | * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise |
||
3061 | */ |
||
3062 | GLboolean |
||
3063 | _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, |
||
3064 | struct gl_texture_object *texObj) |
||
3065 | { |
||
3066 | const GLuint fboSave = ctx->DrawBuffer->Name; |
||
3067 | struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; |
||
3068 | struct gl_texture_image *baseImage; |
||
3069 | GLuint srcLevel; |
||
3070 | GLenum status; |
||
3071 | |||
3072 | /* check for fallbacks */ |
||
3073 | if (target == GL_TEXTURE_3D || |
||
3074 | target == GL_TEXTURE_1D_ARRAY || |
||
3075 | target == GL_TEXTURE_2D_ARRAY) { |
||
3076 | _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, |
||
3077 | "glGenerateMipmap() to %s target\n", |
||
3078 | _mesa_lookup_enum_by_nr(target)); |
||
3079 | return GL_TRUE; |
||
3080 | } |
||
3081 | |||
3082 | srcLevel = texObj->BaseLevel; |
||
3083 | baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel); |
||
3084 | if (!baseImage) { |
||
3085 | _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, |
||
3086 | "glGenerateMipmap() couldn't find base teximage\n"); |
||
3087 | return GL_TRUE; |
||
3088 | } |
||
3089 | |||
3090 | if (_mesa_is_format_compressed(baseImage->TexFormat)) { |
||
3091 | _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, |
||
3092 | "glGenerateMipmap() with %s format\n", |
||
3093 | _mesa_get_format_name(baseImage->TexFormat)); |
||
3094 | return GL_TRUE; |
||
3095 | } |
||
3096 | |||
3097 | if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB && |
||
3098 | !ctx->Extensions.EXT_texture_sRGB_decode) { |
||
3099 | /* The texture format is sRGB but we can't turn off sRGB->linear |
||
3100 | * texture sample conversion. So we won't be able to generate the |
||
3101 | * right colors when rendering. Need to use a fallback. |
||
3102 | */ |
||
3103 | _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, |
||
3104 | "glGenerateMipmap() of sRGB texture without " |
||
3105 | "sRGB decode\n"); |
||
3106 | return GL_TRUE; |
||
3107 | } |
||
3108 | |||
3109 | /* |
||
3110 | * Test that we can actually render in the texture's format. |
||
3111 | */ |
||
3112 | if (!mipmap->FBO) |
||
3113 | _mesa_GenFramebuffers(1, &mipmap->FBO); |
||
3114 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); |
||
3115 | |||
3116 | if (target == GL_TEXTURE_1D) { |
||
3117 | _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT, |
||
3118 | GL_COLOR_ATTACHMENT0_EXT, |
||
3119 | target, texObj->Name, srcLevel); |
||
3120 | } |
||
3121 | #if 0 |
||
3122 | /* other work is needed to enable 3D mipmap generation */ |
||
3123 | else if (target == GL_TEXTURE_3D) { |
||
3124 | GLint zoffset = 0; |
||
3125 | _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT, |
||
3126 | GL_COLOR_ATTACHMENT0_EXT, |
||
3127 | target, texObj->Name, srcLevel, zoffset); |
||
3128 | } |
||
3129 | #endif |
||
3130 | else { |
||
3131 | /* 2D / cube */ |
||
3132 | _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT, |
||
3133 | GL_COLOR_ATTACHMENT0_EXT, |
||
3134 | target, texObj->Name, srcLevel); |
||
3135 | } |
||
3136 | |||
3137 | status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); |
||
3138 | |||
3139 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave); |
||
3140 | |||
3141 | if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
||
3142 | _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, |
||
3143 | "glGenerateMipmap() got incomplete FBO\n"); |
||
3144 | return GL_TRUE; |
||
3145 | } |
||
3146 | |||
3147 | return GL_FALSE; |
||
3148 | } |
||
3149 | |||
3150 | |||
3151 | /** |
||
3152 | * Compute the texture coordinates for the four vertices of a quad for |
||
3153 | * drawing a 2D texture image or slice of a cube/3D texture. |
||
3154 | * \param faceTarget GL_TEXTURE_1D/2D/3D or cube face name |
||
3155 | * \param slice slice of a 1D/2D array texture or 3D texture |
||
3156 | * \param width width of the texture image |
||
3157 | * \param height height of the texture image |
||
3158 | * \param coords0/1/2/3 returns the computed texcoords |
||
3159 | */ |
||
3160 | static void |
||
3161 | setup_texture_coords(GLenum faceTarget, |
||
3162 | GLint slice, |
||
3163 | GLint width, |
||
3164 | GLint height, |
||
3165 | GLint depth, |
||
3166 | GLfloat coords0[3], |
||
3167 | GLfloat coords1[3], |
||
3168 | GLfloat coords2[3], |
||
3169 | GLfloat coords3[3]) |
||
3170 | { |
||
3171 | static const GLfloat st[4][2] = { |
||
3172 | {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} |
||
3173 | }; |
||
3174 | GLuint i; |
||
3175 | GLfloat r; |
||
3176 | |||
3177 | switch (faceTarget) { |
||
3178 | case GL_TEXTURE_1D: |
||
3179 | case GL_TEXTURE_2D: |
||
3180 | case GL_TEXTURE_3D: |
||
3181 | case GL_TEXTURE_2D_ARRAY: |
||
3182 | if (faceTarget == GL_TEXTURE_3D) { |
||
3183 | assert(slice < depth); |
||
3184 | assert(depth >= 1); |
||
3185 | r = (slice + 0.5f) / depth; |
||
3186 | } |
||
3187 | else if (faceTarget == GL_TEXTURE_2D_ARRAY) |
||
3188 | r = slice; |
||
3189 | else |
||
3190 | r = 0.0F; |
||
3191 | coords0[0] = 0.0F; /* s */ |
||
3192 | coords0[1] = 0.0F; /* t */ |
||
3193 | coords0[2] = r; /* r */ |
||
3194 | coords1[0] = 1.0F; |
||
3195 | coords1[1] = 0.0F; |
||
3196 | coords1[2] = r; |
||
3197 | coords2[0] = 1.0F; |
||
3198 | coords2[1] = 1.0F; |
||
3199 | coords2[2] = r; |
||
3200 | coords3[0] = 0.0F; |
||
3201 | coords3[1] = 1.0F; |
||
3202 | coords3[2] = r; |
||
3203 | break; |
||
3204 | case GL_TEXTURE_RECTANGLE_ARB: |
||
3205 | coords0[0] = 0.0F; /* s */ |
||
3206 | coords0[1] = 0.0F; /* t */ |
||
3207 | coords0[2] = 0.0F; /* r */ |
||
3208 | coords1[0] = width; |
||
3209 | coords1[1] = 0.0F; |
||
3210 | coords1[2] = 0.0F; |
||
3211 | coords2[0] = width; |
||
3212 | coords2[1] = height; |
||
3213 | coords2[2] = 0.0F; |
||
3214 | coords3[0] = 0.0F; |
||
3215 | coords3[1] = height; |
||
3216 | coords3[2] = 0.0F; |
||
3217 | break; |
||
3218 | case GL_TEXTURE_1D_ARRAY: |
||
3219 | coords0[0] = 0.0F; /* s */ |
||
3220 | coords0[1] = slice; /* t */ |
||
3221 | coords0[2] = 0.0F; /* r */ |
||
3222 | coords1[0] = 1.0f; |
||
3223 | coords1[1] = slice; |
||
3224 | coords1[2] = 0.0F; |
||
3225 | coords2[0] = 1.0F; |
||
3226 | coords2[1] = slice; |
||
3227 | coords2[2] = 0.0F; |
||
3228 | coords3[0] = 0.0F; |
||
3229 | coords3[1] = slice; |
||
3230 | coords3[2] = 0.0F; |
||
3231 | break; |
||
3232 | |||
3233 | case GL_TEXTURE_CUBE_MAP_POSITIVE_X: |
||
3234 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: |
||
3235 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: |
||
3236 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: |
||
3237 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: |
||
3238 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: |
||
3239 | /* loop over quad verts */ |
||
3240 | for (i = 0; i < 4; i++) { |
||
3241 | /* Compute sc = +/-scale and tc = +/-scale. |
||
3242 | * Not +/-1 to avoid cube face selection ambiguity near the edges, |
||
3243 | * though that can still sometimes happen with this scale factor... |
||
3244 | */ |
||
3245 | const GLfloat scale = 0.9999f; |
||
3246 | const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale; |
||
3247 | const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale; |
||
3248 | GLfloat *coord; |
||
3249 | |||
3250 | switch (i) { |
||
3251 | case 0: |
||
3252 | coord = coords0; |
||
3253 | break; |
||
3254 | case 1: |
||
3255 | coord = coords1; |
||
3256 | break; |
||
3257 | case 2: |
||
3258 | coord = coords2; |
||
3259 | break; |
||
3260 | case 3: |
||
3261 | coord = coords3; |
||
3262 | break; |
||
3263 | default: |
||
3264 | assert(0); |
||
3265 | } |
||
3266 | |||
3267 | switch (faceTarget) { |
||
3268 | case GL_TEXTURE_CUBE_MAP_POSITIVE_X: |
||
3269 | coord[0] = 1.0f; |
||
3270 | coord[1] = -tc; |
||
3271 | coord[2] = -sc; |
||
3272 | break; |
||
3273 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: |
||
3274 | coord[0] = -1.0f; |
||
3275 | coord[1] = -tc; |
||
3276 | coord[2] = sc; |
||
3277 | break; |
||
3278 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: |
||
3279 | coord[0] = sc; |
||
3280 | coord[1] = 1.0f; |
||
3281 | coord[2] = tc; |
||
3282 | break; |
||
3283 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: |
||
3284 | coord[0] = sc; |
||
3285 | coord[1] = -1.0f; |
||
3286 | coord[2] = -tc; |
||
3287 | break; |
||
3288 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: |
||
3289 | coord[0] = sc; |
||
3290 | coord[1] = -tc; |
||
3291 | coord[2] = 1.0f; |
||
3292 | break; |
||
3293 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: |
||
3294 | coord[0] = -sc; |
||
3295 | coord[1] = -tc; |
||
3296 | coord[2] = -1.0f; |
||
3297 | break; |
||
3298 | default: |
||
3299 | assert(0); |
||
3300 | } |
||
3301 | } |
||
3302 | break; |
||
3303 | default: |
||
3304 | assert(0 && "unexpected target in meta setup_texture_coords()"); |
||
3305 | } |
||
3306 | } |
||
3307 | |||
3308 | |||
3309 | static void |
||
3310 | setup_ff_generate_mipmap(struct gl_context *ctx, |
||
3311 | struct gen_mipmap_state *mipmap) |
||
3312 | { |
||
3313 | struct vertex { |
||
3314 | GLfloat x, y, tex[3]; |
||
3315 | }; |
||
3316 | |||
3317 | if (mipmap->ArrayObj == 0) { |
||
3318 | /* one-time setup */ |
||
3319 | /* create vertex array object */ |
||
3320 | _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj); |
||
3321 | _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj); |
||
3322 | |||
3323 | /* create vertex array buffer */ |
||
3324 | _mesa_GenBuffers(1, &mipmap->VBO); |
||
3325 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); |
||
3326 | /* setup vertex arrays */ |
||
3327 | _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
3328 | _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex)); |
||
3329 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
3330 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
3331 | } |
||
3332 | |||
3333 | /* setup projection matrix */ |
||
3334 | _mesa_MatrixMode(GL_PROJECTION); |
||
3335 | _mesa_LoadIdentity(); |
||
3336 | _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); |
||
3337 | } |
||
3338 | |||
3339 | |||
3340 | static struct glsl_sampler * |
||
3341 | setup_texture_sampler(GLenum target, struct gen_mipmap_state *mipmap) |
||
3342 | { |
||
3343 | switch(target) { |
||
3344 | case GL_TEXTURE_1D: |
||
3345 | mipmap->sampler_1d.type = "sampler1D"; |
||
3346 | mipmap->sampler_1d.func = "texture1D"; |
||
3347 | mipmap->sampler_1d.texcoords = "texCoords.x"; |
||
3348 | return &mipmap->sampler_1d; |
||
3349 | case GL_TEXTURE_2D: |
||
3350 | mipmap->sampler_2d.type = "sampler2D"; |
||
3351 | mipmap->sampler_2d.func = "texture2D"; |
||
3352 | mipmap->sampler_2d.texcoords = "texCoords.xy"; |
||
3353 | return &mipmap->sampler_2d; |
||
3354 | case GL_TEXTURE_3D: |
||
3355 | /* Code for mipmap generation with 3D textures is not used yet. |
||
3356 | * It's a sw fallback. |
||
3357 | */ |
||
3358 | mipmap->sampler_3d.type = "sampler3D"; |
||
3359 | mipmap->sampler_3d.func = "texture3D"; |
||
3360 | mipmap->sampler_3d.texcoords = "texCoords"; |
||
3361 | return &mipmap->sampler_3d; |
||
3362 | case GL_TEXTURE_CUBE_MAP: |
||
3363 | mipmap->sampler_cubemap.type = "samplerCube"; |
||
3364 | mipmap->sampler_cubemap.func = "textureCube"; |
||
3365 | mipmap->sampler_cubemap.texcoords = "texCoords"; |
||
3366 | return &mipmap->sampler_cubemap; |
||
3367 | case GL_TEXTURE_1D_ARRAY: |
||
3368 | mipmap->sampler_1d_array.type = "sampler1DArray"; |
||
3369 | mipmap->sampler_1d_array.func = "texture1DArray"; |
||
3370 | mipmap->sampler_1d_array.texcoords = "texCoords.xy"; |
||
3371 | return &mipmap->sampler_1d_array; |
||
3372 | case GL_TEXTURE_2D_ARRAY: |
||
3373 | mipmap->sampler_2d_array.type = "sampler2DArray"; |
||
3374 | mipmap->sampler_2d_array.func = "texture2DArray"; |
||
3375 | mipmap->sampler_2d_array.texcoords = "texCoords"; |
||
3376 | return &mipmap->sampler_2d_array; |
||
3377 | default: |
||
3378 | _mesa_problem(NULL, "Unexpected texture target 0x%x in" |
||
3379 | " setup_texture_sampler()\n", target); |
||
3380 | return NULL; |
||
3381 | } |
||
3382 | } |
||
3383 | |||
3384 | |||
3385 | static void |
||
3386 | setup_glsl_generate_mipmap(struct gl_context *ctx, |
||
3387 | struct gen_mipmap_state *mipmap, |
||
3388 | GLenum target) |
||
3389 | { |
||
3390 | struct vertex { |
||
3391 | GLfloat x, y, tex[3]; |
||
3392 | }; |
||
3393 | struct glsl_sampler *sampler; |
||
3394 | const char *vs_source; |
||
3395 | char *fs_source; |
||
3396 | GLuint vs, fs; |
||
3397 | void *mem_ctx; |
||
3398 | |||
3399 | /* Check if already initialized */ |
||
3400 | if (mipmap->ArrayObj == 0) { |
||
3401 | |||
3402 | /* create vertex array object */ |
||
3403 | _mesa_GenVertexArrays(1, &mipmap->ArrayObj); |
||
3404 | _mesa_BindVertexArray(mipmap->ArrayObj); |
||
3405 | |||
3406 | /* create vertex array buffer */ |
||
3407 | _mesa_GenBuffers(1, &mipmap->VBO); |
||
3408 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); |
||
3409 | |||
3410 | /* setup vertex arrays */ |
||
3411 | _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, |
||
3412 | sizeof(struct vertex), OFFSET(x)); |
||
3413 | _mesa_VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, |
||
3414 | sizeof(struct vertex), OFFSET(tex)); |
||
3415 | _mesa_EnableVertexAttribArray(0); |
||
3416 | _mesa_EnableVertexAttribArray(1); |
||
3417 | } |
||
3418 | |||
3419 | /* Generate a fragment shader program appropriate for the texture target */ |
||
3420 | sampler = setup_texture_sampler(target, mipmap); |
||
3421 | assert(sampler != NULL); |
||
3422 | if (sampler->shader_prog != 0) { |
||
3423 | mipmap->ShaderProg = sampler->shader_prog; |
||
3424 | return; |
||
3425 | } |
||
3426 | |||
3427 | mem_ctx = ralloc_context(NULL); |
||
3428 | |||
3429 | if (ctx->API == API_OPENGLES2 || ctx->Const.GLSLVersion < 130) { |
||
3430 | vs_source = |
||
3431 | "attribute vec2 position;\n" |
||
3432 | "attribute vec3 textureCoords;\n" |
||
3433 | "varying vec3 texCoords;\n" |
||
3434 | "void main()\n" |
||
3435 | "{\n" |
||
3436 | " texCoords = textureCoords;\n" |
||
3437 | " gl_Position = vec4(position, 0.0, 1.0);\n" |
||
3438 | "}\n"; |
||
3439 | |||
3440 | fs_source = ralloc_asprintf(mem_ctx, |
||
3441 | "#extension GL_EXT_texture_array : enable\n" |
||
3442 | "#ifdef GL_ES\n" |
||
3443 | "precision highp float;\n" |
||
3444 | "#endif\n" |
||
3445 | "uniform %s texSampler;\n" |
||
3446 | "varying vec3 texCoords;\n" |
||
3447 | "void main()\n" |
||
3448 | "{\n" |
||
3449 | " gl_FragColor = %s(texSampler, %s);\n" |
||
3450 | "}\n", |
||
3451 | sampler->type, |
||
3452 | sampler->func, sampler->texcoords); |
||
3453 | } |
||
3454 | else { |
||
3455 | vs_source = ralloc_asprintf(mem_ctx, |
||
3456 | "#version %s\n" |
||
3457 | "in vec2 position;\n" |
||
3458 | "in vec3 textureCoords;\n" |
||
3459 | "out vec3 texCoords;\n" |
||
3460 | "void main()\n" |
||
3461 | "{\n" |
||
3462 | " texCoords = textureCoords;\n" |
||
3463 | " gl_Position = vec4(position, 0.0, 1.0);\n" |
||
3464 | "}\n", |
||
3465 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); |
||
3466 | fs_source = ralloc_asprintf(mem_ctx, |
||
3467 | "#version %s\n" |
||
3468 | "#ifdef GL_ES\n" |
||
3469 | "precision highp float;\n" |
||
3470 | "#endif\n" |
||
3471 | "uniform %s texSampler;\n" |
||
3472 | "in vec3 texCoords;\n" |
||
3473 | "out vec4 out_color;\n" |
||
3474 | "\n" |
||
3475 | "void main()\n" |
||
3476 | "{\n" |
||
3477 | " out_color = texture(texSampler, %s);\n" |
||
3478 | "}\n", |
||
3479 | _mesa_is_desktop_gl(ctx) ? "130" : "300 es", |
||
3480 | sampler->type, |
||
3481 | sampler->texcoords); |
||
3482 | } |
||
3483 | |||
3484 | vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source); |
||
3485 | fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source); |
||
3486 | |||
3487 | mipmap->ShaderProg = _mesa_CreateProgramObjectARB(); |
||
3488 | _mesa_AttachShader(mipmap->ShaderProg, fs); |
||
3489 | _mesa_DeleteObjectARB(fs); |
||
3490 | _mesa_AttachShader(mipmap->ShaderProg, vs); |
||
3491 | _mesa_DeleteObjectARB(vs); |
||
3492 | _mesa_BindAttribLocation(mipmap->ShaderProg, 0, "position"); |
||
3493 | _mesa_BindAttribLocation(mipmap->ShaderProg, 1, "texcoords"); |
||
3494 | link_program_with_debug(ctx, mipmap->ShaderProg); |
||
3495 | sampler->shader_prog = mipmap->ShaderProg; |
||
3496 | ralloc_free(mem_ctx); |
||
3497 | } |
||
3498 | |||
3499 | |||
3500 | static void |
||
3501 | meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, |
||
3502 | struct gen_mipmap_state *mipmap) |
||
3503 | { |
||
3504 | if (mipmap->ArrayObj == 0) |
||
3505 | return; |
||
3506 | _mesa_DeleteVertexArrays(1, &mipmap->ArrayObj); |
||
3507 | mipmap->ArrayObj = 0; |
||
3508 | _mesa_DeleteBuffers(1, &mipmap->VBO); |
||
3509 | mipmap->VBO = 0; |
||
3510 | |||
3511 | _mesa_DeleteObjectARB(mipmap->sampler_1d.shader_prog); |
||
3512 | _mesa_DeleteObjectARB(mipmap->sampler_2d.shader_prog); |
||
3513 | _mesa_DeleteObjectARB(mipmap->sampler_3d.shader_prog); |
||
3514 | _mesa_DeleteObjectARB(mipmap->sampler_cubemap.shader_prog); |
||
3515 | _mesa_DeleteObjectARB(mipmap->sampler_1d_array.shader_prog); |
||
3516 | _mesa_DeleteObjectARB(mipmap->sampler_2d_array.shader_prog); |
||
3517 | |||
3518 | mipmap->sampler_1d.shader_prog = 0; |
||
3519 | mipmap->sampler_2d.shader_prog = 0; |
||
3520 | mipmap->sampler_3d.shader_prog = 0; |
||
3521 | mipmap->sampler_cubemap.shader_prog = 0; |
||
3522 | mipmap->sampler_1d_array.shader_prog = 0; |
||
3523 | mipmap->sampler_2d_array.shader_prog = 0; |
||
3524 | } |
||
3525 | |||
3526 | |||
3527 | /** |
||
3528 | * Called via ctx->Driver.GenerateMipmap() |
||
3529 | * Note: We don't yet support 3D textures, 1D/2D array textures or texture |
||
3530 | * borders. |
||
3531 | */ |
||
3532 | void |
||
3533 | _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, |
||
3534 | struct gl_texture_object *texObj) |
||
3535 | { |
||
3536 | struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; |
||
3537 | struct vertex { |
||
3538 | GLfloat x, y, tex[3]; |
||
3539 | }; |
||
3540 | struct vertex verts[4]; |
||
3541 | const GLuint baseLevel = texObj->BaseLevel; |
||
3542 | const GLuint maxLevel = texObj->MaxLevel; |
||
3543 | const GLint maxLevelSave = texObj->MaxLevel; |
||
3544 | const GLboolean genMipmapSave = texObj->GenerateMipmap; |
||
3545 | const GLuint fboSave = ctx->DrawBuffer->Name; |
||
3546 | const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit; |
||
3547 | const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && |
||
3548 | ctx->Extensions.ARB_fragment_shader && |
||
3549 | (ctx->API != API_OPENGLES); |
||
3550 | GLenum faceTarget; |
||
3551 | GLuint dstLevel; |
||
3552 | const GLint slice = 0; |
||
3553 | GLuint samplerSave; |
||
3554 | |||
3555 | if (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) { |
||
3556 | _mesa_generate_mipmap(ctx, target, texObj); |
||
3557 | return; |
||
3558 | } |
||
3559 | |||
3560 | if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && |
||
3561 | target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { |
||
3562 | faceTarget = target; |
||
3563 | target = GL_TEXTURE_CUBE_MAP; |
||
3564 | } |
||
3565 | else { |
||
3566 | faceTarget = target; |
||
3567 | } |
||
3568 | |||
3569 | _mesa_meta_begin(ctx, MESA_META_ALL); |
||
3570 | |||
3571 | /* Choose between glsl version and fixed function version of |
||
3572 | * GenerateMipmap function. |
||
3573 | */ |
||
3574 | if (use_glsl_version) { |
||
3575 | setup_glsl_generate_mipmap(ctx, mipmap, target); |
||
3576 | _mesa_UseProgram(mipmap->ShaderProg); |
||
3577 | } |
||
3578 | else { |
||
3579 | setup_ff_generate_mipmap(ctx, mipmap); |
||
3580 | _mesa_set_enable(ctx, target, GL_TRUE); |
||
3581 | } |
||
3582 | |||
3583 | _mesa_BindVertexArray(mipmap->ArrayObj); |
||
3584 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); |
||
3585 | |||
3586 | samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? |
||
3587 | ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; |
||
3588 | |||
3589 | if (currentTexUnitSave != 0) |
||
3590 | _mesa_BindTexture(target, texObj->Name); |
||
3591 | |||
3592 | if (!mipmap->FBO) { |
||
3593 | _mesa_GenFramebuffers(1, &mipmap->FBO); |
||
3594 | } |
||
3595 | |||
3596 | if (!mipmap->Sampler) { |
||
3597 | _mesa_GenSamplers(1, &mipmap->Sampler); |
||
3598 | _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); |
||
3599 | |||
3600 | _mesa_SamplerParameteri(mipmap->Sampler, |
||
3601 | GL_TEXTURE_MIN_FILTER, |
||
3602 | GL_LINEAR_MIPMAP_LINEAR); |
||
3603 | _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
||
3604 | _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
||
3605 | _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
||
3606 | _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); |
||
3607 | |||
3608 | /* We don't want to encode or decode sRGB values; treat them as linear. |
||
3609 | * This is not technically correct for GLES3 but we don't get any API |
||
3610 | * error at the moment. |
||
3611 | */ |
||
3612 | if (ctx->Extensions.EXT_texture_sRGB_decode) { |
||
3613 | _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, |
||
3614 | GL_SKIP_DECODE_EXT); |
||
3615 | } |
||
3616 | |||
3617 | } else { |
||
3618 | _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); |
||
3619 | } |
||
3620 | |||
3621 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); |
||
3622 | |||
3623 | if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) |
||
3624 | _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); |
||
3625 | else |
||
3626 | assert(!genMipmapSave); |
||
3627 | |||
3628 | /* Setup texture coordinates */ |
||
3629 | setup_texture_coords(faceTarget, |
||
3630 | slice, |
||
3631 | 0, 0, 1, /* width, height never used here */ |
||
3632 | verts[0].tex, |
||
3633 | verts[1].tex, |
||
3634 | verts[2].tex, |
||
3635 | verts[3].tex); |
||
3636 | |||
3637 | /* setup vertex positions */ |
||
3638 | verts[0].x = -1.0F; |
||
3639 | verts[0].y = -1.0F; |
||
3640 | verts[1].x = 1.0F; |
||
3641 | verts[1].y = -1.0F; |
||
3642 | verts[2].x = 1.0F; |
||
3643 | verts[2].y = 1.0F; |
||
3644 | verts[3].x = -1.0F; |
||
3645 | verts[3].y = 1.0F; |
||
3646 | |||
3647 | /* upload vertex data */ |
||
3648 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
3649 | verts, GL_DYNAMIC_DRAW_ARB); |
||
3650 | |||
3651 | /* texture is already locked, unlock now */ |
||
3652 | _mesa_unlock_texture(ctx, texObj); |
||
3653 | |||
3654 | for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { |
||
3655 | const struct gl_texture_image *srcImage; |
||
3656 | const GLuint srcLevel = dstLevel - 1; |
||
3657 | GLsizei srcWidth, srcHeight, srcDepth; |
||
3658 | GLsizei dstWidth, dstHeight, dstDepth; |
||
3659 | GLenum status; |
||
3660 | |||
3661 | srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel); |
||
3662 | assert(srcImage->Border == 0); |
||
3663 | |||
3664 | /* src size */ |
||
3665 | srcWidth = srcImage->Width; |
||
3666 | srcHeight = srcImage->Height; |
||
3667 | srcDepth = srcImage->Depth; |
||
3668 | |||
3669 | /* new dst size */ |
||
3670 | dstWidth = MAX2(1, srcWidth / 2); |
||
3671 | dstHeight = MAX2(1, srcHeight / 2); |
||
3672 | dstDepth = MAX2(1, srcDepth / 2); |
||
3673 | |||
3674 | if (dstWidth == srcImage->Width && |
||
3675 | dstHeight == srcImage->Height && |
||
3676 | dstDepth == srcImage->Depth) { |
||
3677 | /* all done */ |
||
3678 | break; |
||
3679 | } |
||
3680 | |||
3681 | /* Allocate storage for the destination mipmap image(s) */ |
||
3682 | |||
3683 | /* Set MaxLevel large enough to hold the new level when we allocate it */ |
||
3684 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); |
||
3685 | |||
3686 | if (!_mesa_prepare_mipmap_level(ctx, texObj, dstLevel, |
||
3687 | dstWidth, dstHeight, dstDepth, |
||
3688 | srcImage->Border, |
||
3689 | srcImage->InternalFormat, |
||
3690 | srcImage->TexFormat)) { |
||
3691 | /* All done. We either ran out of memory or we would go beyond the |
||
3692 | * last valid level of an immutable texture if we continued. |
||
3693 | */ |
||
3694 | break; |
||
3695 | } |
||
3696 | |||
3697 | /* limit minification to src level */ |
||
3698 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); |
||
3699 | |||
3700 | /* Set to draw into the current dstLevel */ |
||
3701 | if (target == GL_TEXTURE_1D) { |
||
3702 | _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT, |
||
3703 | GL_COLOR_ATTACHMENT0_EXT, |
||
3704 | target, |
||
3705 | texObj->Name, |
||
3706 | dstLevel); |
||
3707 | } |
||
3708 | else if (target == GL_TEXTURE_3D) { |
||
3709 | GLint zoffset = 0; /* XXX unfinished */ |
||
3710 | _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT, |
||
3711 | GL_COLOR_ATTACHMENT0_EXT, |
||
3712 | target, |
||
3713 | texObj->Name, |
||
3714 | dstLevel, zoffset); |
||
3715 | } |
||
3716 | else { |
||
3717 | /* 2D / cube */ |
||
3718 | _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT, |
||
3719 | GL_COLOR_ATTACHMENT0_EXT, |
||
3720 | faceTarget, |
||
3721 | texObj->Name, |
||
3722 | dstLevel); |
||
3723 | } |
||
3724 | |||
3725 | _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); |
||
3726 | |||
3727 | /* sanity check */ |
||
3728 | status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); |
||
3729 | if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
||
3730 | _mesa_problem(ctx, "Unexpected incomplete framebuffer in " |
||
3731 | "_mesa_meta_GenerateMipmap()"); |
||
3732 | break; |
||
3733 | } |
||
3734 | |||
3735 | assert(dstWidth == ctx->DrawBuffer->Width); |
||
3736 | assert(dstHeight == ctx->DrawBuffer->Height); |
||
3737 | |||
3738 | /* setup viewport */ |
||
3739 | _mesa_set_viewport(ctx, 0, 0, dstWidth, dstHeight); |
||
3740 | |||
3741 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
3742 | } |
||
3743 | |||
3744 | _mesa_lock_texture(ctx, texObj); /* relock */ |
||
3745 | |||
3746 | _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); |
||
3747 | |||
3748 | _mesa_meta_end(ctx); |
||
3749 | |||
3750 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); |
||
3751 | if (genMipmapSave) |
||
3752 | _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); |
||
3753 | |||
3754 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave); |
||
3755 | } |
||
3756 | |||
3757 | |||
3758 | /** |
||
3759 | * Determine the GL data type to use for the temporary image read with |
||
3760 | * ReadPixels() and passed to Tex[Sub]Image(). |
||
3761 | */ |
||
3762 | static GLenum |
||
3763 | get_temp_image_type(struct gl_context *ctx, gl_format format) |
||
3764 | { |
||
3765 | GLenum baseFormat; |
||
3766 | |||
3767 | baseFormat = _mesa_get_format_base_format(format); |
||
3768 | |||
3769 | switch (baseFormat) { |
||
3770 | case GL_RGBA: |
||
3771 | case GL_RGB: |
||
3772 | case GL_RG: |
||
3773 | case GL_RED: |
||
3774 | case GL_ALPHA: |
||
3775 | case GL_LUMINANCE: |
||
3776 | case GL_LUMINANCE_ALPHA: |
||
3777 | case GL_INTENSITY: |
||
3778 | if (ctx->DrawBuffer->Visual.redBits <= 8) { |
||
3779 | return GL_UNSIGNED_BYTE; |
||
3780 | } else if (ctx->DrawBuffer->Visual.redBits <= 16) { |
||
3781 | return GL_UNSIGNED_SHORT; |
||
3782 | } else { |
||
3783 | GLenum datatype = _mesa_get_format_datatype(format); |
||
3784 | if (datatype == GL_INT || datatype == GL_UNSIGNED_INT) |
||
3785 | return datatype; |
||
3786 | return GL_FLOAT; |
||
3787 | } |
||
3788 | case GL_DEPTH_COMPONENT: { |
||
3789 | GLenum datatype = _mesa_get_format_datatype(format); |
||
3790 | if (datatype == GL_FLOAT) |
||
3791 | return GL_FLOAT; |
||
3792 | else |
||
3793 | return GL_UNSIGNED_INT; |
||
3794 | } |
||
3795 | case GL_DEPTH_STENCIL: { |
||
3796 | GLenum datatype = _mesa_get_format_datatype(format); |
||
3797 | if (datatype == GL_FLOAT) |
||
3798 | return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; |
||
3799 | else |
||
3800 | return GL_UNSIGNED_INT_24_8; |
||
3801 | } |
||
3802 | default: |
||
3803 | _mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()", |
||
3804 | baseFormat); |
||
3805 | return 0; |
||
3806 | } |
||
3807 | } |
||
3808 | |||
3809 | |||
3810 | /** |
||
3811 | * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. |
||
3812 | * Have to be careful with locking and meta state for pixel transfer. |
||
3813 | */ |
||
3814 | void |
||
3815 | _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims, |
||
3816 | struct gl_texture_image *texImage, |
||
3817 | GLint xoffset, GLint yoffset, GLint zoffset, |
||
3818 | struct gl_renderbuffer *rb, |
||
3819 | GLint x, GLint y, |
||
3820 | GLsizei width, GLsizei height) |
||
3821 | { |
||
3822 | struct gl_texture_object *texObj = texImage->TexObject; |
||
3823 | GLenum format, type; |
||
3824 | GLint bpp; |
||
3825 | void *buf; |
||
3826 | |||
3827 | /* Choose format/type for temporary image buffer */ |
||
3828 | format = _mesa_get_format_base_format(texImage->TexFormat); |
||
3829 | if (format == GL_LUMINANCE || |
||
3830 | format == GL_LUMINANCE_ALPHA || |
||
3831 | format == GL_INTENSITY) { |
||
3832 | /* We don't want to use GL_LUMINANCE, GL_INTENSITY, etc. for the |
||
3833 | * temp image buffer because glReadPixels will do L=R+G+B which is |
||
3834 | * not what we want (should be L=R). |
||
3835 | */ |
||
3836 | format = GL_RGBA; |
||
3837 | } |
||
3838 | |||
3839 | type = get_temp_image_type(ctx, texImage->TexFormat); |
||
3840 | if (_mesa_is_format_integer_color(texImage->TexFormat)) { |
||
3841 | format = _mesa_base_format_to_integer_format(format); |
||
3842 | } |
||
3843 | bpp = _mesa_bytes_per_pixel(format, type); |
||
3844 | if (bpp <= 0) { |
||
3845 | _mesa_problem(ctx, "Bad bpp in _mesa_meta_CopyTexSubImage()"); |
||
3846 | return; |
||
3847 | } |
||
3848 | |||
3849 | /* |
||
3850 | * Alloc image buffer (XXX could use a PBO) |
||
3851 | */ |
||
3852 | buf = malloc(width * height * bpp); |
||
3853 | if (!buf) { |
||
3854 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%uD", dims); |
||
3855 | return; |
||
3856 | } |
||
3857 | |||
3858 | _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ |
||
3859 | |||
3860 | /* |
||
3861 | * Read image from framebuffer (disable pixel transfer ops) |
||
3862 | */ |
||
3863 | _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); |
||
3864 | ctx->Driver.ReadPixels(ctx, x, y, width, height, |
||
3865 | format, type, &ctx->Pack, buf); |
||
3866 | _mesa_meta_end(ctx); |
||
3867 | |||
3868 | _mesa_update_state(ctx); /* to update pixel transfer state */ |
||
3869 | |||
3870 | /* |
||
3871 | * Store texture data (with pixel transfer ops) |
||
3872 | */ |
||
3873 | _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE); |
||
3874 | |||
3875 | if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { |
||
3876 | assert(yoffset == 0); |
||
3877 | ctx->Driver.TexSubImage(ctx, dims, texImage, |
||
3878 | xoffset, zoffset, 0, width, 1, 1, |
||
3879 | format, type, buf, &ctx->Unpack); |
||
3880 | } else { |
||
3881 | ctx->Driver.TexSubImage(ctx, dims, texImage, |
||
3882 | xoffset, yoffset, zoffset, width, height, 1, |
||
3883 | format, type, buf, &ctx->Unpack); |
||
3884 | } |
||
3885 | |||
3886 | _mesa_meta_end(ctx); |
||
3887 | |||
3888 | _mesa_lock_texture(ctx, texObj); /* re-lock */ |
||
3889 | |||
3890 | free(buf); |
||
3891 | } |
||
3892 | |||
3893 | |||
3894 | /** |
||
3895 | * Decompress a texture image by drawing a quad with the compressed |
||
3896 | * texture and reading the pixels out of the color buffer. |
||
3897 | * \param slice which slice of a 3D texture or layer of a 1D/2D texture |
||
3898 | * \param destFormat format, ala glReadPixels |
||
3899 | * \param destType type, ala glReadPixels |
||
3900 | * \param dest destination buffer |
||
3901 | * \param destRowLength dest image rowLength (ala GL_PACK_ROW_LENGTH) |
||
3902 | */ |
||
3903 | static void |
||
3904 | decompress_texture_image(struct gl_context *ctx, |
||
3905 | struct gl_texture_image *texImage, |
||
3906 | GLuint slice, |
||
3907 | GLenum destFormat, GLenum destType, |
||
3908 | GLvoid *dest) |
||
3909 | { |
||
3910 | struct decompress_state *decompress = &ctx->Meta->Decompress; |
||
3911 | struct gl_texture_object *texObj = texImage->TexObject; |
||
3912 | const GLint width = texImage->Width; |
||
3913 | const GLint height = texImage->Height; |
||
3914 | const GLint depth = texImage->Height; |
||
3915 | const GLenum target = texObj->Target; |
||
3916 | GLenum faceTarget; |
||
3917 | struct vertex { |
||
3918 | GLfloat x, y, tex[3]; |
||
3919 | }; |
||
3920 | struct vertex verts[4]; |
||
3921 | GLuint fboDrawSave, fboReadSave; |
||
3922 | GLuint rbSave; |
||
3923 | GLuint samplerSave; |
||
3924 | |||
3925 | if (slice > 0) { |
||
3926 | assert(target == GL_TEXTURE_3D || |
||
3927 | target == GL_TEXTURE_2D_ARRAY); |
||
3928 | } |
||
3929 | |||
3930 | if (target == GL_TEXTURE_CUBE_MAP) { |
||
3931 | faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; |
||
3932 | } |
||
3933 | else { |
||
3934 | faceTarget = target; |
||
3935 | } |
||
3936 | |||
3937 | /* save fbo bindings (not saved by _mesa_meta_begin()) */ |
||
3938 | fboDrawSave = ctx->DrawBuffer->Name; |
||
3939 | fboReadSave = ctx->ReadBuffer->Name; |
||
3940 | rbSave = ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0; |
||
3941 | |||
3942 | _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_PIXEL_STORE); |
||
3943 | |||
3944 | samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? |
||
3945 | ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; |
||
3946 | |||
3947 | /* Create/bind FBO/renderbuffer */ |
||
3948 | if (decompress->FBO == 0) { |
||
3949 | _mesa_GenFramebuffers(1, &decompress->FBO); |
||
3950 | _mesa_GenRenderbuffers(1, &decompress->RBO); |
||
3951 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO); |
||
3952 | _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO); |
||
3953 | _mesa_FramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, |
||
3954 | GL_COLOR_ATTACHMENT0_EXT, |
||
3955 | GL_RENDERBUFFER_EXT, |
||
3956 | decompress->RBO); |
||
3957 | } |
||
3958 | else { |
||
3959 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO); |
||
3960 | } |
||
3961 | |||
3962 | /* alloc dest surface */ |
||
3963 | if (width > decompress->Width || height > decompress->Height) { |
||
3964 | _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO); |
||
3965 | _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA, |
||
3966 | width, height); |
||
3967 | decompress->Width = width; |
||
3968 | decompress->Height = height; |
||
3969 | } |
||
3970 | |||
3971 | /* setup VBO data */ |
||
3972 | if (decompress->ArrayObj == 0) { |
||
3973 | /* create vertex array object */ |
||
3974 | _mesa_GenVertexArrays(1, &decompress->ArrayObj); |
||
3975 | _mesa_BindVertexArray(decompress->ArrayObj); |
||
3976 | |||
3977 | /* create vertex array buffer */ |
||
3978 | _mesa_GenBuffers(1, &decompress->VBO); |
||
3979 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO); |
||
3980 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
3981 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
3982 | |||
3983 | /* setup vertex arrays */ |
||
3984 | _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
3985 | _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex)); |
||
3986 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
3987 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
3988 | } |
||
3989 | else { |
||
3990 | _mesa_BindVertexArray(decompress->ArrayObj); |
||
3991 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO); |
||
3992 | } |
||
3993 | |||
3994 | if (!decompress->Sampler) { |
||
3995 | _mesa_GenSamplers(1, &decompress->Sampler); |
||
3996 | _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler); |
||
3997 | /* nearest filtering */ |
||
3998 | _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
||
3999 | _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
||
4000 | /* No sRGB decode or encode.*/ |
||
4001 | if (ctx->Extensions.EXT_texture_sRGB_decode) { |
||
4002 | _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, |
||
4003 | GL_SKIP_DECODE_EXT); |
||
4004 | } |
||
4005 | |||
4006 | } else { |
||
4007 | _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler); |
||
4008 | } |
||
4009 | |||
4010 | setup_texture_coords(faceTarget, slice, width, height, depth, |
||
4011 | verts[0].tex, |
||
4012 | verts[1].tex, |
||
4013 | verts[2].tex, |
||
4014 | verts[3].tex); |
||
4015 | |||
4016 | /* setup vertex positions */ |
||
4017 | verts[0].x = 0.0F; |
||
4018 | verts[0].y = 0.0F; |
||
4019 | verts[1].x = width; |
||
4020 | verts[1].y = 0.0F; |
||
4021 | verts[2].x = width; |
||
4022 | verts[2].y = height; |
||
4023 | verts[3].x = 0.0F; |
||
4024 | verts[3].y = height; |
||
4025 | |||
4026 | _mesa_MatrixMode(GL_PROJECTION); |
||
4027 | _mesa_LoadIdentity(); |
||
4028 | _mesa_Ortho(0.0, width, 0.0, height, -1.0, 1.0); |
||
4029 | _mesa_set_viewport(ctx, 0, 0, width, height); |
||
4030 | |||
4031 | /* upload new vertex data */ |
||
4032 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
4033 | |||
4034 | /* setup texture state */ |
||
4035 | _mesa_BindTexture(target, texObj->Name); |
||
4036 | _mesa_set_enable(ctx, target, GL_TRUE); |
||
4037 | |||
4038 | { |
||
4039 | /* save texture object state */ |
||
4040 | const GLint baseLevelSave = texObj->BaseLevel; |
||
4041 | const GLint maxLevelSave = texObj->MaxLevel; |
||
4042 | |||
4043 | /* restrict sampling to the texture level of interest */ |
||
4044 | if (target != GL_TEXTURE_RECTANGLE_ARB) { |
||
4045 | _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, texImage->Level); |
||
4046 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, texImage->Level); |
||
4047 | } |
||
4048 | |||
4049 | /* render quad w/ texture into renderbuffer */ |
||
4050 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
4051 | |||
4052 | /* Restore texture object state, the texture binding will |
||
4053 | * be restored by _mesa_meta_end(). |
||
4054 | */ |
||
4055 | if (target != GL_TEXTURE_RECTANGLE_ARB) { |
||
4056 | _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); |
||
4057 | _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); |
||
4058 | } |
||
4059 | |||
4060 | } |
||
4061 | |||
4062 | /* read pixels from renderbuffer */ |
||
4063 | { |
||
4064 | GLenum baseTexFormat = texImage->_BaseFormat; |
||
4065 | GLenum destBaseFormat = _mesa_base_tex_format(ctx, destFormat); |
||
4066 | |||
4067 | /* The pixel transfer state will be set to default values at this point |
||
4068 | * (see MESA_META_PIXEL_TRANSFER) so pixel transfer ops are effectively |
||
4069 | * turned off (as required by glGetTexImage) but we need to handle some |
||
4070 | * special cases. In particular, single-channel texture values are |
||
4071 | * returned as red and two-channel texture values are returned as |
||
4072 | * red/alpha. |
||
4073 | */ |
||
4074 | if ((baseTexFormat == GL_LUMINANCE || |
||
4075 | baseTexFormat == GL_LUMINANCE_ALPHA || |
||
4076 | baseTexFormat == GL_INTENSITY) || |
||
4077 | /* If we're reading back an RGB(A) texture (using glGetTexImage) as |
||
4078 | * luminance then we need to return L=tex(R). |
||
4079 | */ |
||
4080 | ((baseTexFormat == GL_RGBA || |
||
4081 | baseTexFormat == GL_RGB || |
||
4082 | baseTexFormat == GL_RG) && |
||
4083 | (destBaseFormat == GL_LUMINANCE || |
||
4084 | destBaseFormat == GL_LUMINANCE_ALPHA || |
||
4085 | destBaseFormat == GL_LUMINANCE_INTEGER_EXT || |
||
4086 | destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT))) { |
||
4087 | /* Green and blue must be zero */ |
||
4088 | _mesa_PixelTransferf(GL_GREEN_SCALE, 0.0f); |
||
4089 | _mesa_PixelTransferf(GL_BLUE_SCALE, 0.0f); |
||
4090 | } |
||
4091 | |||
4092 | _mesa_ReadPixels(0, 0, width, height, destFormat, destType, dest); |
||
4093 | } |
||
4094 | |||
4095 | /* disable texture unit */ |
||
4096 | _mesa_set_enable(ctx, target, GL_FALSE); |
||
4097 | |||
4098 | _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); |
||
4099 | |||
4100 | _mesa_meta_end(ctx); |
||
4101 | |||
4102 | /* restore fbo bindings */ |
||
4103 | if (fboDrawSave == fboReadSave) { |
||
4104 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboDrawSave); |
||
4105 | } |
||
4106 | else { |
||
4107 | _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave); |
||
4108 | _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, fboReadSave); |
||
4109 | } |
||
4110 | _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, rbSave); |
||
4111 | } |
||
4112 | |||
4113 | |||
4114 | /** |
||
4115 | * This is just a wrapper around _mesa_get_tex_image() and |
||
4116 | * decompress_texture_image(). Meta functions should not be directly called |
||
4117 | * from core Mesa. |
||
4118 | */ |
||
4119 | void |
||
4120 | _mesa_meta_GetTexImage(struct gl_context *ctx, |
||
4121 | GLenum format, GLenum type, GLvoid *pixels, |
||
4122 | struct gl_texture_image *texImage) |
||
4123 | { |
||
4124 | /* We can only use the decompress-with-blit method here if the texels are |
||
4125 | * unsigned, normalized values. We could handle signed and unnormalized |
||
4126 | * with floating point renderbuffers... |
||
4127 | */ |
||
4128 | if (_mesa_is_format_compressed(texImage->TexFormat) && |
||
4129 | _mesa_get_format_datatype(texImage->TexFormat) |
||
4130 | == GL_UNSIGNED_NORMALIZED) { |
||
4131 | struct gl_texture_object *texObj = texImage->TexObject; |
||
4132 | GLuint slice; |
||
4133 | /* Need to unlock the texture here to prevent deadlock... */ |
||
4134 | _mesa_unlock_texture(ctx, texObj); |
||
4135 | for (slice = 0; slice < texImage->Depth; slice++) { |
||
4136 | void *dst; |
||
4137 | if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) { |
||
4138 | /* Setup pixel packing. SkipPixels and SkipRows will be applied |
||
4139 | * in the decompress_texture_image() function's call to |
||
4140 | * glReadPixels but we need to compute the dest slice's address |
||
4141 | * here (according to SkipImages and ImageHeight). |
||
4142 | */ |
||
4143 | struct gl_pixelstore_attrib packing = ctx->Pack; |
||
4144 | packing.SkipPixels = 0; |
||
4145 | packing.SkipRows = 0; |
||
4146 | dst = _mesa_image_address3d(&packing, pixels, texImage->Width, |
||
4147 | texImage->Height, format, type, |
||
4148 | slice, 0, 0); |
||
4149 | } |
||
4150 | else { |
||
4151 | dst = pixels; |
||
4152 | } |
||
4153 | decompress_texture_image(ctx, texImage, slice, format, type, dst); |
||
4154 | } |
||
4155 | /* ... and relock it */ |
||
4156 | _mesa_lock_texture(ctx, texObj); |
||
4157 | } |
||
4158 | else { |
||
4159 | _mesa_get_teximage(ctx, format, type, pixels, texImage); |
||
4160 | } |
||
4161 | } |
||
4162 | |||
4163 | |||
4164 | /** |
||
4165 | * Meta implementation of ctx->Driver.DrawTex() in terms |
||
4166 | * of polygon rendering. |
||
4167 | */ |
||
4168 | void |
||
4169 | _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, |
||
4170 | GLfloat width, GLfloat height) |
||
4171 | { |
||
4172 | struct drawtex_state *drawtex = &ctx->Meta->DrawTex; |
||
4173 | struct vertex { |
||
4174 | GLfloat x, y, z, st[MAX_TEXTURE_UNITS][2]; |
||
4175 | }; |
||
4176 | struct vertex verts[4]; |
||
4177 | GLuint i; |
||
4178 | |||
4179 | _mesa_meta_begin(ctx, (MESA_META_RASTERIZATION | |
||
4180 | MESA_META_SHADER | |
||
4181 | MESA_META_TRANSFORM | |
||
4182 | MESA_META_VERTEX | |
||
4183 | MESA_META_VIEWPORT)); |
||
4184 | |||
4185 | if (drawtex->ArrayObj == 0) { |
||
4186 | /* one-time setup */ |
||
4187 | GLint active_texture; |
||
4188 | |||
4189 | /* create vertex array object */ |
||
4190 | _mesa_GenVertexArrays(1, &drawtex->ArrayObj); |
||
4191 | _mesa_BindVertexArray(drawtex->ArrayObj); |
||
4192 | |||
4193 | /* create vertex array buffer */ |
||
4194 | _mesa_GenBuffers(1, &drawtex->VBO); |
||
4195 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO); |
||
4196 | _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), |
||
4197 | NULL, GL_DYNAMIC_DRAW_ARB); |
||
4198 | |||
4199 | /* client active texture is not part of the array object */ |
||
4200 | active_texture = ctx->Array.ActiveTexture; |
||
4201 | |||
4202 | /* setup vertex arrays */ |
||
4203 | _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); |
||
4204 | _mesa_EnableClientState(GL_VERTEX_ARRAY); |
||
4205 | for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { |
||
4206 | _mesa_ClientActiveTexture(GL_TEXTURE0 + i); |
||
4207 | _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(st[i])); |
||
4208 | _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); |
||
4209 | } |
||
4210 | |||
4211 | /* restore client active texture */ |
||
4212 | _mesa_ClientActiveTexture(GL_TEXTURE0 + active_texture); |
||
4213 | } |
||
4214 | else { |
||
4215 | _mesa_BindVertexArray(drawtex->ArrayObj); |
||
4216 | _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO); |
||
4217 | } |
||
4218 | |||
4219 | /* vertex positions, texcoords */ |
||
4220 | { |
||
4221 | const GLfloat x1 = x + width; |
||
4222 | const GLfloat y1 = y + height; |
||
4223 | |||
4224 | z = CLAMP(z, 0.0f, 1.0f); |
||
4225 | z = invert_z(z); |
||
4226 | |||
4227 | verts[0].x = x; |
||
4228 | verts[0].y = y; |
||
4229 | verts[0].z = z; |
||
4230 | |||
4231 | verts[1].x = x1; |
||
4232 | verts[1].y = y; |
||
4233 | verts[1].z = z; |
||
4234 | |||
4235 | verts[2].x = x1; |
||
4236 | verts[2].y = y1; |
||
4237 | verts[2].z = z; |
||
4238 | |||
4239 | verts[3].x = x; |
||
4240 | verts[3].y = y1; |
||
4241 | verts[3].z = z; |
||
4242 | |||
4243 | for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { |
||
4244 | const struct gl_texture_object *texObj; |
||
4245 | const struct gl_texture_image *texImage; |
||
4246 | GLfloat s, t, s1, t1; |
||
4247 | GLuint tw, th; |
||
4248 | |||
4249 | if (!ctx->Texture.Unit[i]._ReallyEnabled) { |
||
4250 | GLuint j; |
||
4251 | for (j = 0; j < 4; j++) { |
||
4252 | verts[j].st[i][0] = 0.0f; |
||
4253 | verts[j].st[i][1] = 0.0f; |
||
4254 | } |
||
4255 | continue; |
||
4256 | } |
||
4257 | |||
4258 | texObj = ctx->Texture.Unit[i]._Current; |
||
4259 | texImage = texObj->Image[0][texObj->BaseLevel]; |
||
4260 | tw = texImage->Width2; |
||
4261 | th = texImage->Height2; |
||
4262 | |||
4263 | s = (GLfloat) texObj->CropRect[0] / tw; |
||
4264 | t = (GLfloat) texObj->CropRect[1] / th; |
||
4265 | s1 = (GLfloat) (texObj->CropRect[0] + texObj->CropRect[2]) / tw; |
||
4266 | t1 = (GLfloat) (texObj->CropRect[1] + texObj->CropRect[3]) / th; |
||
4267 | |||
4268 | verts[0].st[i][0] = s; |
||
4269 | verts[0].st[i][1] = t; |
||
4270 | |||
4271 | verts[1].st[i][0] = s1; |
||
4272 | verts[1].st[i][1] = t; |
||
4273 | |||
4274 | verts[2].st[i][0] = s1; |
||
4275 | verts[2].st[i][1] = t1; |
||
4276 | |||
4277 | verts[3].st[i][0] = s; |
||
4278 | verts[3].st[i][1] = t1; |
||
4279 | } |
||
4280 | |||
4281 | _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); |
||
4282 | } |
||
4283 | |||
4284 | _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); |
||
4285 | |||
4286 | _mesa_meta_end(ctx); |
||
4287 | }>>>>=>=>=>=>=>>>>>=>>><>>>>><>><>>>><>>><>>>>>>=>=>><>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |