7ddc03cd021aecdd76ba4674720baa93e216dd53
[reactos.git] / reactos / dll / opengl / mesa / src / mesa / drivers / common / meta.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.6
4 *
5 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR 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/arrayobj.h"
38 #include "main/blend.h"
39 #include "main/bufferobj.h"
40 #include "main/buffers.h"
41 #include "main/colortab.h"
42 #include "main/context.h"
43 #include "main/depth.h"
44 #include "main/enable.h"
45 #include "main/feedback.h"
46 #include "main/formats.h"
47 #include "main/image.h"
48 #include "main/macros.h"
49 #include "main/matrix.h"
50 #include "main/pixel.h"
51 #include "main/pbo.h"
52 #include "main/polygon.h"
53 #include "main/readpix.h"
54 #include "main/scissor.h"
55 #include "main/state.h"
56 #include "main/stencil.h"
57 #include "main/texobj.h"
58 #include "main/texenv.h"
59 #include "main/texgetimage.h"
60 #include "main/teximage.h"
61 #include "main/texparam.h"
62 #include "main/texstate.h"
63 #include "main/varray.h"
64 #include "main/viewport.h"
65 #include "swrast/swrast.h"
66 #include "drivers/common/meta.h"
67
68
69 /** Return offset in bytes of the field within a vertex struct */
70 #define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
71
72 /**
73 * State which we may save/restore across meta ops.
74 * XXX this may be incomplete...
75 */
76 struct save_state
77 {
78 GLbitfield SavedState; /**< bitmask of MESA_META_* flags */
79
80 /** MESA_META_ALPHA_TEST */
81 GLboolean AlphaEnabled;
82 GLenum AlphaFunc;
83 GLclampf AlphaRef;
84
85 /** MESA_META_BLEND */
86 GLbitfield BlendEnabled;
87 GLboolean ColorLogicOpEnabled;
88
89 /** MESA_META_COLOR_MASK */
90 GLubyte ColorMask[4];
91
92 /** MESA_META_DEPTH_TEST */
93 struct gl_depthbuffer_attrib Depth;
94
95 /** MESA_META_FOG */
96 GLboolean Fog;
97
98 /** MESA_META_PIXEL_STORE */
99 struct gl_pixelstore_attrib Pack, Unpack;
100
101 /** MESA_META_PIXEL_TRANSFER */
102 GLfloat RedBias, RedScale;
103 GLfloat GreenBias, GreenScale;
104 GLfloat BlueBias, BlueScale;
105 GLfloat AlphaBias, AlphaScale;
106 GLfloat DepthBias, DepthScale;
107 GLboolean MapColorFlag;
108
109 /** MESA_META_RASTERIZATION */
110 GLenum FrontPolygonMode, BackPolygonMode;
111 GLboolean PolygonOffset;
112 GLboolean PolygonSmooth;
113 GLboolean PolygonStipple;
114 GLboolean PolygonCull;
115
116 /** MESA_META_SCISSOR */
117 struct gl_scissor_attrib Scissor;
118
119 /** MESA_META_STENCIL_TEST */
120 struct gl_stencil_attrib Stencil;
121
122 /** MESA_META_TRANSFORM */
123 GLenum MatrixMode;
124 GLfloat ModelviewMatrix[16];
125 GLfloat ProjectionMatrix[16];
126 GLfloat TextureMatrix[16];
127
128 /** MESA_META_CLIP */
129 GLbitfield ClipPlanesEnabled;
130
131 /** MESA_META_TEXTURE */
132 struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS];
133 /** mask of TEXTURE_2D_BIT, etc */
134 GLbitfield TexEnabled;
135 GLbitfield TexGenEnabled;
136 GLuint EnvMode; /* unit[0] only */
137
138 /** MESA_META_VERTEX */
139 struct gl_array_object *ArrayObj;
140 struct gl_buffer_object *ArrayBufferObj;
141
142 /** MESA_META_VIEWPORT */
143 GLint ViewportX, ViewportY, ViewportW, ViewportH;
144 GLclampd DepthNear, DepthFar;
145
146 /** MESA_META_SELECT_FEEDBACK */
147 GLenum RenderMode;
148 struct gl_selection Select;
149 struct gl_feedback Feedback;
150
151 /** Miscellaneous (always disabled) */
152 GLboolean Lighting;
153 GLboolean RasterDiscard;
154 };
155
156 /**
157 * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc.
158 * This is currently shared by all the meta ops. But we could create a
159 * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc.
160 */
161 struct temp_texture
162 {
163 GLuint TexObj;
164 GLenum Target; /**< GL_TEXTURE_2D */
165 GLsizei MinSize; /**< Min texture size to allocate */
166 GLsizei MaxSize; /**< Max possible texture size */
167 GLboolean NPOT; /**< Non-power of two size OK? */
168 GLsizei Width, Height; /**< Current texture size */
169 GLenum IntFormat;
170 GLfloat Sright, Ttop; /**< right, top texcoords */
171 };
172
173
174 /**
175 * State for glBlitFramebufer()
176 */
177 struct blit_state
178 {
179 GLuint ArrayObj;
180 GLuint VBO;
181 GLuint DepthFP;
182 };
183
184
185 /**
186 * State for glClear()
187 */
188 struct clear_state
189 {
190 GLuint ArrayObj;
191 GLuint VBO;
192 GLuint ShaderProg;
193 GLint ColorLocation;
194
195 GLuint IntegerShaderProg;
196 GLint IntegerColorLocation;
197 };
198
199
200 /**
201 * State for glCopyPixels()
202 */
203 struct copypix_state
204 {
205 GLuint ArrayObj;
206 GLuint VBO;
207 };
208
209 #define MAX_META_OPS_DEPTH 8
210 /**
211 * All per-context meta state.
212 */
213 struct gl_meta_state
214 {
215 /** Stack of state saved during meta-ops */
216 struct save_state Save[MAX_META_OPS_DEPTH];
217 /** Save stack depth */
218 GLuint SaveStackDepth;
219
220 struct temp_texture TempTex;
221
222 struct copypix_state CopyPix; /**< For _mesa_meta_CopyPixels() */
223 };
224
225 static void cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex);
226
227 /**
228 * Initialize meta-ops for a context.
229 * To be called once during context creation.
230 */
231 void
232 _mesa_meta_init(struct gl_context *ctx)
233 {
234 ASSERT(!ctx->Meta);
235
236 ctx->Meta = CALLOC_STRUCT(gl_meta_state);
237 }
238
239
240 /**
241 * Free context meta-op state.
242 * To be called once during context destruction.
243 */
244 void
245 _mesa_meta_free(struct gl_context *ctx)
246 {
247 GET_CURRENT_CONTEXT(old_context);
248 _mesa_make_current(ctx, NULL, NULL);
249 cleanup_temp_texture(ctx, &ctx->Meta->TempTex);
250 if (old_context)
251 _mesa_make_current(old_context, old_context->WinSysDrawBuffer, old_context->WinSysReadBuffer);
252 else
253 _mesa_make_current(NULL, NULL, NULL);
254 free(ctx->Meta);
255 ctx->Meta = NULL;
256 }
257
258
259 /**
260 * Enter meta state. This is like a light-weight version of glPushAttrib
261 * but it also resets most GL state back to default values.
262 *
263 * \param state bitmask of MESA_META_* flags indicating which attribute groups
264 * to save and reset to their defaults
265 */
266 void
267 _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
268 {
269 struct save_state *save;
270
271 /* hope MAX_META_OPS_DEPTH is large enough */
272 assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH);
273
274 save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++];
275 memset(save, 0, sizeof(*save));
276 save->SavedState = state;
277
278 if (state & MESA_META_ALPHA_TEST) {
279 save->AlphaEnabled = ctx->Color.AlphaEnabled;
280 save->AlphaFunc = ctx->Color.AlphaFunc;
281 save->AlphaRef = ctx->Color.AlphaRef;
282 if (ctx->Color.AlphaEnabled)
283 _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE);
284 }
285
286 if (state & MESA_META_BLEND) {
287 save->BlendEnabled = ctx->Color.BlendEnabled;
288 if (ctx->Color.BlendEnabled) {
289 _mesa_set_enable(ctx, GL_BLEND, GL_FALSE);
290 }
291 save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled;
292 if (ctx->Color.ColorLogicOpEnabled)
293 _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE);
294 }
295
296 if (state & MESA_META_COLOR_MASK) {
297 memcpy(save->ColorMask, ctx->Color.ColorMask,
298 sizeof(ctx->Color.ColorMask));
299 if (!ctx->Color.ColorMask[0] ||
300 !ctx->Color.ColorMask[1] ||
301 !ctx->Color.ColorMask[2] ||
302 !ctx->Color.ColorMask[3])
303 _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
304 }
305
306 if (state & MESA_META_DEPTH_TEST) {
307 save->Depth = ctx->Depth; /* struct copy */
308 if (ctx->Depth.Test)
309 _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE);
310 }
311
312 if (state & MESA_META_FOG) {
313 save->Fog = ctx->Fog.Enabled;
314 if (ctx->Fog.Enabled)
315 _mesa_set_enable(ctx, GL_FOG, GL_FALSE);
316 }
317
318 if (state & MESA_META_PIXEL_STORE) {
319 save->Pack = ctx->Pack;
320 save->Unpack = ctx->Unpack;
321 ctx->Pack = ctx->DefaultPacking;
322 ctx->Unpack = ctx->DefaultPacking;
323 }
324
325 if (state & MESA_META_PIXEL_TRANSFER) {
326 save->RedScale = ctx->Pixel.RedScale;
327 save->RedBias = ctx->Pixel.RedBias;
328 save->GreenScale = ctx->Pixel.GreenScale;
329 save->GreenBias = ctx->Pixel.GreenBias;
330 save->BlueScale = ctx->Pixel.BlueScale;
331 save->BlueBias = ctx->Pixel.BlueBias;
332 save->AlphaScale = ctx->Pixel.AlphaScale;
333 save->AlphaBias = ctx->Pixel.AlphaBias;
334 save->MapColorFlag = ctx->Pixel.MapColorFlag;
335 ctx->Pixel.RedScale = 1.0F;
336 ctx->Pixel.RedBias = 0.0F;
337 ctx->Pixel.GreenScale = 1.0F;
338 ctx->Pixel.GreenBias = 0.0F;
339 ctx->Pixel.BlueScale = 1.0F;
340 ctx->Pixel.BlueBias = 0.0F;
341 ctx->Pixel.AlphaScale = 1.0F;
342 ctx->Pixel.AlphaBias = 0.0F;
343 ctx->Pixel.MapColorFlag = GL_FALSE;
344 /* XXX more state */
345 ctx->NewState |=_NEW_PIXEL;
346 }
347
348 if (state & MESA_META_RASTERIZATION) {
349 save->FrontPolygonMode = ctx->Polygon.FrontMode;
350 save->BackPolygonMode = ctx->Polygon.BackMode;
351 save->PolygonOffset = ctx->Polygon.OffsetFill;
352 save->PolygonSmooth = ctx->Polygon.SmoothFlag;
353 save->PolygonStipple = ctx->Polygon.StippleFlag;
354 save->PolygonCull = ctx->Polygon.CullFlag;
355 _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL);
356 _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE);
357 _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE);
358 _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE);
359 _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE);
360 }
361
362 if (state & MESA_META_SCISSOR) {
363 save->Scissor = ctx->Scissor; /* struct copy */
364 _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE);
365 }
366
367 if (state & MESA_META_STENCIL_TEST) {
368 save->Stencil = ctx->Stencil; /* struct copy */
369 if (ctx->Stencil.Enabled)
370 _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE);
371 /* NOTE: other stencil state not reset */
372 }
373
374 if (state & MESA_META_TEXTURE) {
375 GLuint tgt;
376
377 save->EnvMode = ctx->Texture.Unit.EnvMode;
378
379 /* Disable all texture units */
380 save->TexEnabled = ctx->Texture.Unit.Enabled;
381 save->TexGenEnabled = ctx->Texture.Unit.TexGenEnabled;
382 if (ctx->Texture.Unit.Enabled ||
383 ctx->Texture.Unit.TexGenEnabled) {
384 _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE);
385 _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE);
386 _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE);
387 if (ctx->Extensions.ARB_texture_cube_map)
388 _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE);
389 _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE);
390 _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE);
391 _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE);
392 _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE);
393 }
394
395 /* save current texture objects for unit[0] only */
396 for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
397 _mesa_reference_texobj(&save->CurrentTexture[tgt],
398 ctx->Texture.Unit.CurrentTex[tgt]);
399 }
400 _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
401 }
402
403 if (state & MESA_META_TRANSFORM) {
404 memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m,
405 16 * sizeof(GLfloat));
406 memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m,
407 16 * sizeof(GLfloat));
408 memcpy(save->TextureMatrix, ctx->TextureMatrixStack.Top->m,
409 16 * sizeof(GLfloat));
410 save->MatrixMode = ctx->Transform.MatrixMode;
411 /* set 1:1 vertex:pixel coordinate transform */
412 _mesa_MatrixMode(GL_TEXTURE);
413 _mesa_LoadIdentity();
414 _mesa_MatrixMode(GL_MODELVIEW);
415 _mesa_LoadIdentity();
416 _mesa_MatrixMode(GL_PROJECTION);
417 _mesa_LoadIdentity();
418 _mesa_Ortho(0.0, ctx->DrawBuffer->Width,
419 0.0, ctx->DrawBuffer->Height,
420 -1.0, 1.0);
421 }
422
423 if (state & MESA_META_CLIP) {
424 save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled;
425 if (ctx->Transform.ClipPlanesEnabled) {
426 GLuint i;
427 for (i = 0; i < ctx->Const.MaxClipPlanes; i++) {
428 _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE);
429 }
430 }
431 }
432
433 if (state & MESA_META_VERTEX) {
434 /* save vertex array object state */
435 _mesa_reference_array_object(ctx, &save->ArrayObj,
436 ctx->Array.ArrayObj);
437 _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj,
438 ctx->Array.ArrayBufferObj);
439 /* set some default state? */
440 }
441
442 if (state & MESA_META_VIEWPORT) {
443 /* save viewport state */
444 save->ViewportX = ctx->Viewport.X;
445 save->ViewportY = ctx->Viewport.Y;
446 save->ViewportW = ctx->Viewport.Width;
447 save->ViewportH = ctx->Viewport.Height;
448 /* set viewport to match window size */
449 if (ctx->Viewport.X != 0 ||
450 ctx->Viewport.Y != 0 ||
451 ctx->Viewport.Width != ctx->DrawBuffer->Width ||
452 ctx->Viewport.Height != ctx->DrawBuffer->Height) {
453 _mesa_set_viewport(ctx, 0, 0,
454 ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
455 }
456 /* save depth range state */
457 save->DepthNear = ctx->Viewport.Near;
458 save->DepthFar = ctx->Viewport.Far;
459 /* set depth range to default */
460 _mesa_DepthRange(0.0, 1.0);
461 }
462
463 if (state & MESA_META_SELECT_FEEDBACK) {
464 save->RenderMode = ctx->RenderMode;
465 if (ctx->RenderMode == GL_SELECT) {
466 save->Select = ctx->Select; /* struct copy */
467 _mesa_RenderMode(GL_RENDER);
468 } else if (ctx->RenderMode == GL_FEEDBACK) {
469 save->Feedback = ctx->Feedback; /* struct copy */
470 _mesa_RenderMode(GL_RENDER);
471 }
472 }
473
474 /* misc */
475 {
476 save->Lighting = ctx->Light.Enabled;
477 if (ctx->Light.Enabled)
478 _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE);
479 save->RasterDiscard = ctx->RasterDiscard;
480 if (ctx->RasterDiscard)
481 _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE);
482 }
483 }
484
485
486 /**
487 * Leave meta state. This is like a light-weight version of glPopAttrib().
488 */
489 void
490 _mesa_meta_end(struct gl_context *ctx)
491 {
492 struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth];
493 const GLbitfield state = save->SavedState;
494
495 if (state & MESA_META_ALPHA_TEST) {
496 if (ctx->Color.AlphaEnabled != save->AlphaEnabled)
497 _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled);
498 _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef);
499 }
500
501 if (state & MESA_META_BLEND) {
502 if (ctx->Color.BlendEnabled != save->BlendEnabled) {
503 _mesa_set_enable(ctx, GL_BLEND, (save->BlendEnabled & 1));
504 }
505 if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled)
506 _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled);
507 }
508
509 if (state & MESA_META_COLOR_MASK) {
510 if (!TEST_EQ_4V(ctx->Color.ColorMask, save->ColorMask)) {
511 _mesa_ColorMask(save->ColorMask[0], save->ColorMask[1],
512 save->ColorMask[2], save->ColorMask[3]);
513 }
514 }
515
516 if (state & MESA_META_DEPTH_TEST) {
517 if (ctx->Depth.Test != save->Depth.Test)
518 _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test);
519 _mesa_DepthFunc(save->Depth.Func);
520 _mesa_DepthMask(save->Depth.Mask);
521 }
522
523 if (state & MESA_META_FOG) {
524 _mesa_set_enable(ctx, GL_FOG, save->Fog);
525 }
526
527 if (state & MESA_META_PIXEL_STORE) {
528 ctx->Pack = save->Pack;
529 ctx->Unpack = save->Unpack;
530 }
531
532 if (state & MESA_META_PIXEL_TRANSFER) {
533 ctx->Pixel.RedScale = save->RedScale;
534 ctx->Pixel.RedBias = save->RedBias;
535 ctx->Pixel.GreenScale = save->GreenScale;
536 ctx->Pixel.GreenBias = save->GreenBias;
537 ctx->Pixel.BlueScale = save->BlueScale;
538 ctx->Pixel.BlueBias = save->BlueBias;
539 ctx->Pixel.AlphaScale = save->AlphaScale;
540 ctx->Pixel.AlphaBias = save->AlphaBias;
541 ctx->Pixel.MapColorFlag = save->MapColorFlag;
542 /* XXX more state */
543 ctx->NewState |=_NEW_PIXEL;
544 }
545
546 if (state & MESA_META_RASTERIZATION) {
547 _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode);
548 _mesa_PolygonMode(GL_BACK, save->BackPolygonMode);
549 _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple);
550 _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset);
551 _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth);
552 _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull);
553 }
554
555 if (state & MESA_META_SCISSOR) {
556 _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled);
557 _mesa_Scissor(save->Scissor.X, save->Scissor.Y,
558 save->Scissor.Width, save->Scissor.Height);
559 }
560
561 if (state & MESA_META_STENCIL_TEST) {
562 const struct gl_stencil_attrib *stencil = &save->Stencil;
563
564 _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled);
565 _mesa_ClearStencil(stencil->Clear);
566 if (ctx->Extensions.EXT_stencil_two_side) {
567 _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT,
568 stencil->TestTwoSide);
569 _mesa_ActiveStencilFaceEXT(stencil->ActiveFace
570 ? GL_BACK : GL_FRONT);
571 }
572 /* front state */
573 _mesa_StencilFuncSeparate(GL_FRONT,
574 stencil->Function[0],
575 stencil->Ref[0],
576 stencil->ValueMask[0]);
577 _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]);
578 _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0],
579 stencil->ZFailFunc[0],
580 stencil->ZPassFunc[0]);
581 /* back state */
582 _mesa_StencilFuncSeparate(GL_BACK,
583 stencil->Function[1],
584 stencil->Ref[1],
585 stencil->ValueMask[1]);
586 _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]);
587 _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1],
588 stencil->ZFailFunc[1],
589 stencil->ZPassFunc[1]);
590 }
591
592 if (state & MESA_META_TEXTURE) {
593 GLuint tgt;
594
595 /* restore texenv for unit[0] */
596 _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode);
597
598 /* restore texture objects for unit[0] only */
599 for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
600 if (ctx->Texture.Unit.CurrentTex[tgt] != save->CurrentTexture[tgt]) {
601 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
602 _mesa_reference_texobj(&ctx->Texture.Unit.CurrentTex[tgt],
603 save->CurrentTexture[tgt]);
604 }
605 _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL);
606 }
607
608 /* Restore fixed function texture enables, texgen */
609 if (ctx->Texture.Unit.Enabled != save->TexEnabled) {
610 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
611 ctx->Texture.Unit.Enabled = save->TexEnabled;
612 }
613
614 if (ctx->Texture.Unit.TexGenEnabled != save->TexGenEnabled) {
615 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
616 ctx->Texture.Unit.TexGenEnabled = save->TexGenEnabled;
617 }
618 }
619
620 if (state & MESA_META_TRANSFORM) {
621 _mesa_MatrixMode(GL_TEXTURE);
622 _mesa_LoadMatrixf(save->TextureMatrix);
623
624 _mesa_MatrixMode(GL_MODELVIEW);
625 _mesa_LoadMatrixf(save->ModelviewMatrix);
626
627 _mesa_MatrixMode(GL_PROJECTION);
628 _mesa_LoadMatrixf(save->ProjectionMatrix);
629
630 _mesa_MatrixMode(save->MatrixMode);
631 }
632
633 if (state & MESA_META_CLIP) {
634 if (save->ClipPlanesEnabled) {
635 GLuint i;
636 for (i = 0; i < ctx->Const.MaxClipPlanes; i++) {
637 if (save->ClipPlanesEnabled & (1 << i)) {
638 _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE);
639 }
640 }
641 }
642 }
643
644 if (state & MESA_META_VERTEX) {
645 /* restore vertex buffer object */
646 _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name);
647 _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL);
648
649 /* restore vertex array object */
650 _mesa_BindVertexArray(save->ArrayObj->Name);
651 _mesa_reference_array_object(ctx, &save->ArrayObj, NULL);
652 }
653
654 if (state & MESA_META_VIEWPORT) {
655 if (save->ViewportX != ctx->Viewport.X ||
656 save->ViewportY != ctx->Viewport.Y ||
657 save->ViewportW != ctx->Viewport.Width ||
658 save->ViewportH != ctx->Viewport.Height) {
659 _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY,
660 save->ViewportW, save->ViewportH);
661 }
662 _mesa_DepthRange(save->DepthNear, save->DepthFar);
663 }
664
665 /* misc */
666 if (save->Lighting) {
667 _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE);
668 }
669 if (save->RasterDiscard) {
670 _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_TRUE);
671 }
672 }
673
674
675 /**
676 * Determine whether Mesa is currently in a meta state.
677 */
678 GLboolean
679 _mesa_meta_in_progress(struct gl_context *ctx)
680 {
681 return ctx->Meta->SaveStackDepth != 0;
682 }
683
684
685 /**
686 * Convert Z from a normalized value in the range [0, 1] to an object-space
687 * Z coordinate in [-1, +1] so that drawing at the new Z position with the
688 * default/identity ortho projection results in the original Z value.
689 * Used by the meta-Clear, Draw/CopyPixels and Bitmap functions where the Z
690 * value comes from the clear value or raster position.
691 */
692 static INLINE GLfloat
693 invert_z(GLfloat normZ)
694 {
695 GLfloat objZ = 1.0f - 2.0f * normZ;
696 return objZ;
697 }
698
699
700 /**
701 * One-time init for a temp_texture object.
702 * Choose tex target, compute max tex size, etc.
703 */
704 static void
705 init_temp_texture(struct gl_context *ctx, struct temp_texture *tex)
706 {
707 /* use 2D texture, NPOT if possible */
708 tex->Target = GL_TEXTURE_2D;
709 tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
710 tex->NPOT = ctx->Extensions.ARB_texture_non_power_of_two;
711 tex->MinSize = 16; /* 16 x 16 at least */
712 assert(tex->MaxSize > 0);
713
714 _mesa_GenTextures(1, &tex->TexObj);
715 }
716
717 static void
718 cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex)
719 {
720 if (!tex->TexObj)
721 return;
722 _mesa_DeleteTextures(1, &tex->TexObj);
723 tex->TexObj = 0;
724 }
725
726
727 /**
728 * Return pointer to temp_texture info for non-bitmap ops.
729 * This does some one-time init if needed.
730 */
731 static struct temp_texture *
732 get_temp_texture(struct gl_context *ctx)
733 {
734 struct temp_texture *tex = &ctx->Meta->TempTex;
735
736 if (!tex->TexObj) {
737 init_temp_texture(ctx, tex);
738 }
739
740 return tex;
741 }
742
743
744 /**
745 * Compute the width/height of texture needed to draw an image of the
746 * given size. Return a flag indicating whether the current texture
747 * can be re-used (glTexSubImage2D) or if a new texture needs to be
748 * allocated (glTexImage2D).
749 * Also, compute s/t texcoords for drawing.
750 *
751 * \return GL_TRUE if new texture is needed, GL_FALSE otherwise
752 */
753 static GLboolean
754 alloc_texture(struct temp_texture *tex,
755 GLsizei width, GLsizei height, GLenum intFormat)
756 {
757 GLboolean newTex = GL_FALSE;
758
759 ASSERT(width <= tex->MaxSize);
760 ASSERT(height <= tex->MaxSize);
761
762 if (width > tex->Width ||
763 height > tex->Height ||
764 intFormat != tex->IntFormat) {
765 /* alloc new texture (larger or different format) */
766
767 if (tex->NPOT) {
768 /* use non-power of two size */
769 tex->Width = MAX2(tex->MinSize, width);
770 tex->Height = MAX2(tex->MinSize, height);
771 }
772 else {
773 /* find power of two size */
774 GLsizei w, h;
775 w = h = tex->MinSize;
776 while (w < width)
777 w *= 2;
778 while (h < height)
779 h *= 2;
780 tex->Width = w;
781 tex->Height = h;
782 }
783
784 tex->IntFormat = intFormat;
785
786 newTex = GL_TRUE;
787 }
788
789 /* compute texcoords */
790 tex->Sright = (GLfloat) width / tex->Width;
791 tex->Ttop = (GLfloat) height / tex->Height;
792
793 return newTex;
794 }
795
796
797 /**
798 * Setup/load texture for glCopyPixels or glBlitFramebuffer.
799 */
800 static void
801 setup_copypix_texture(struct temp_texture *tex,
802 GLboolean newTex,
803 GLint srcX, GLint srcY,
804 GLsizei width, GLsizei height, GLenum intFormat,
805 GLenum filter)
806 {
807 _mesa_BindTexture(tex->Target, tex->TexObj);
808 _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter);
809 _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter);
810 _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
811
812 /* copy framebuffer image to texture */
813 if (newTex) {
814 /* create new tex image */
815 if (tex->Width == width && tex->Height == height) {
816 /* create new tex with framebuffer data */
817 _mesa_CopyTexImage2D(tex->Target, 0, tex->IntFormat,
818 srcX, srcY, width, height, 0);
819 }
820 else {
821 /* create empty texture */
822 _mesa_TexImage2D(tex->Target, 0, tex->IntFormat,
823 tex->Width, tex->Height, 0,
824 intFormat, GL_UNSIGNED_BYTE, NULL);
825 /* load image */
826 _mesa_CopyTexSubImage2D(tex->Target, 0,
827 0, 0, srcX, srcY, width, height);
828 }
829 }
830 else {
831 /* replace existing tex image */
832 _mesa_CopyTexSubImage2D(tex->Target, 0,
833 0, 0, srcX, srcY, width, height);
834 }
835 }
836
837 /**
838 * Meta implementation of ctx->Driver.CopyPixels() in terms
839 * of texture mapping and polygon rendering and GLSL shaders.
840 */
841 void
842 _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
843 GLsizei width, GLsizei height,
844 GLint dstX, GLint dstY, GLenum type)
845 {
846 struct copypix_state *copypix = &ctx->Meta->CopyPix;
847 struct temp_texture *tex = get_temp_texture(ctx);
848 struct vertex {
849 GLfloat x, y, z, s, t;
850 };
851 struct vertex verts[4];
852 GLboolean newTex;
853 GLenum intFormat = GL_RGBA;
854
855 if (type != GL_COLOR ||
856 ctx->_ImageTransferState ||
857 ctx->Fog.Enabled ||
858 width > tex->MaxSize ||
859 height > tex->MaxSize) {
860 /* XXX avoid this fallback */
861 _swrast_CopyPixels(ctx, srcX, srcY, width, height, dstX, dstY, type);
862 return;
863 }
864
865 /* Most GL state applies to glCopyPixels, but a there's a few things
866 * we need to override:
867 */
868 _mesa_meta_begin(ctx, (MESA_META_RASTERIZATION |
869 MESA_META_TEXTURE |
870 MESA_META_TRANSFORM |
871 MESA_META_CLIP |
872 MESA_META_VERTEX |
873 MESA_META_VIEWPORT));
874
875 if (copypix->ArrayObj == 0) {
876 /* one-time setup */
877
878 /* create vertex array object */
879 _mesa_GenVertexArrays(1, &copypix->ArrayObj);
880 _mesa_BindVertexArray(copypix->ArrayObj);
881
882 /* create vertex array buffer */
883 _mesa_GenBuffersARB(1, &copypix->VBO);
884 _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO);
885 _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts),
886 NULL, GL_DYNAMIC_DRAW_ARB);
887
888 /* setup vertex arrays */
889 _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
890 _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s));
891 _mesa_EnableClientState(GL_VERTEX_ARRAY);
892 _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
893 }
894 else {
895 _mesa_BindVertexArray(copypix->ArrayObj);
896 _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO);
897 }
898
899 newTex = alloc_texture(tex, width, height, intFormat);
900
901 /* vertex positions, texcoords (after texture allocation!) */
902 {
903 const GLfloat dstX0 = (GLfloat) dstX;
904 const GLfloat dstY0 = (GLfloat) dstY;
905 const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX;
906 const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY;
907 const GLfloat z = invert_z(ctx->Current.RasterPos[2]);
908
909 verts[0].x = dstX0;
910 verts[0].y = dstY0;
911 verts[0].z = z;
912 verts[0].s = 0.0F;
913 verts[0].t = 0.0F;
914 verts[1].x = dstX1;
915 verts[1].y = dstY0;
916 verts[1].z = z;
917 verts[1].s = tex->Sright;
918 verts[1].t = 0.0F;
919 verts[2].x = dstX1;
920 verts[2].y = dstY1;
921 verts[2].z = z;
922 verts[2].s = tex->Sright;
923 verts[2].t = tex->Ttop;
924 verts[3].x = dstX0;
925 verts[3].y = dstY1;
926 verts[3].z = z;
927 verts[3].s = 0.0F;
928 verts[3].t = tex->Ttop;
929
930 /* upload new vertex data */
931 _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
932 }
933
934 /* Alloc/setup texture */
935 setup_copypix_texture(tex, newTex, srcX, srcY, width, height,
936 GL_RGBA, GL_NEAREST);
937
938 _mesa_set_enable(ctx, tex->Target, GL_TRUE);
939
940 /* draw textured quad */
941 _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
942
943 _mesa_set_enable(ctx, tex->Target, GL_FALSE);
944
945 _mesa_meta_end(ctx);
946 }
947
948
949 /**
950 * Determine the GL data type to use for the temporary image read with
951 * ReadPixels() and passed to Tex[Sub]Image().
952 */
953 static GLenum
954 get_temp_image_type(struct gl_context *ctx, GLenum baseFormat)
955 {
956 switch (baseFormat) {
957 case GL_RGBA:
958 case GL_RGB:
959 case GL_RG:
960 case GL_RED:
961 case GL_ALPHA:
962 case GL_LUMINANCE:
963 case GL_LUMINANCE_ALPHA:
964 case GL_INTENSITY:
965 if (ctx->DrawBuffer->Visual.redBits <= 8)
966 return GL_UNSIGNED_BYTE;
967 else if (ctx->DrawBuffer->Visual.redBits <= 16)
968 return GL_UNSIGNED_SHORT;
969 else
970 return GL_FLOAT;
971 case GL_DEPTH_COMPONENT:
972 return GL_UNSIGNED_INT;
973 default:
974 _mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()",
975 baseFormat);
976 return 0;
977 }
978 }
979
980
981 /**
982 * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions.
983 * Have to be careful with locking and meta state for pixel transfer.
984 */
985 static void
986 copy_tex_sub_image(struct gl_context *ctx,
987 GLuint dims,
988 struct gl_texture_image *texImage,
989 GLint xoffset, GLint yoffset, GLint zoffset,
990 struct gl_renderbuffer *rb,
991 GLint x, GLint y,
992 GLsizei width, GLsizei height)
993 {
994 struct gl_texture_object *texObj = texImage->TexObject;
995 const GLenum target = texObj->Target;
996 GLenum format, type;
997 GLint bpp;
998 void *buf;
999
1000 /* Choose format/type for temporary image buffer */
1001 format = _mesa_get_format_base_format(texImage->TexFormat);
1002 if (format == GL_LUMINANCE ||
1003 format == GL_LUMINANCE_ALPHA ||
1004 format == GL_INTENSITY) {
1005 /* We don't want to use GL_LUMINANCE, GL_INTENSITY, etc. for the
1006 * temp image buffer because glReadPixels will do L=R+G+B which is
1007 * not what we want (should be L=R).
1008 */
1009 format = GL_RGBA;
1010 }
1011
1012 if (_mesa_is_format_integer_color(texImage->TexFormat)) {
1013 _mesa_problem(ctx, "unsupported integer color copyteximage");
1014 return;
1015 }
1016
1017 type = get_temp_image_type(ctx, format);
1018 bpp = _mesa_bytes_per_pixel(format, type);
1019 if (bpp <= 0) {
1020 _mesa_problem(ctx, "Bad bpp in meta copy_tex_sub_image()");
1021 return;
1022 }
1023
1024 /*
1025 * Alloc image buffer (XXX could use a PBO)
1026 */
1027 buf = malloc(width * height * bpp);
1028 if (!buf) {
1029 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%uD", dims);
1030 return;
1031 }
1032
1033 _mesa_unlock_texture(ctx, texObj); /* need to unlock first */
1034
1035 /*
1036 * Read image from framebuffer (disable pixel transfer ops)
1037 */
1038 _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER);
1039 ctx->Driver.ReadPixels(ctx, x, y, width, height,
1040 format, type, &ctx->Pack, buf);
1041 _mesa_meta_end(ctx);
1042
1043 _mesa_update_state(ctx); /* to update pixel transfer state */
1044
1045 /*
1046 * Store texture data (with pixel transfer ops)
1047 */
1048 _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE);
1049 if (target == GL_TEXTURE_1D) {
1050 ctx->Driver.TexSubImage1D(ctx, texImage,
1051 xoffset, width,
1052 format, type, buf, &ctx->Unpack);
1053 }
1054 else if (target == GL_TEXTURE_3D) {
1055 ctx->Driver.TexSubImage3D(ctx, texImage,
1056 xoffset, yoffset, zoffset, width, height, 1,
1057 format, type, buf, &ctx->Unpack);
1058 }
1059 else {
1060 ctx->Driver.TexSubImage2D(ctx, texImage,
1061 xoffset, yoffset, width, height,
1062 format, type, buf, &ctx->Unpack);
1063 }
1064 _mesa_meta_end(ctx);
1065
1066 _mesa_lock_texture(ctx, texObj); /* re-lock */
1067
1068 free(buf);
1069 }
1070
1071
1072 void
1073 _mesa_meta_CopyTexSubImage1D(struct gl_context *ctx,
1074 struct gl_texture_image *texImage,
1075 GLint xoffset,
1076 struct gl_renderbuffer *rb,
1077 GLint x, GLint y, GLsizei width)
1078 {
1079 copy_tex_sub_image(ctx, 1, texImage, xoffset, 0, 0,
1080 rb, x, y, width, 1);
1081 }
1082
1083
1084 void
1085 _mesa_meta_CopyTexSubImage2D(struct gl_context *ctx,
1086 struct gl_texture_image *texImage,
1087 GLint xoffset, GLint yoffset,
1088 struct gl_renderbuffer *rb,
1089 GLint x, GLint y,
1090 GLsizei width, GLsizei height)
1091 {
1092 copy_tex_sub_image(ctx, 2, texImage, xoffset, yoffset, 0,
1093 rb, x, y, width, height);
1094 }
1095
1096
1097 void
1098 _mesa_meta_CopyTexSubImage3D(struct gl_context *ctx,
1099 struct gl_texture_image *texImage,
1100 GLint xoffset, GLint yoffset, GLint zoffset,
1101 struct gl_renderbuffer *rb,
1102 GLint x, GLint y,
1103 GLsizei width, GLsizei height)
1104 {
1105 copy_tex_sub_image(ctx, 3, texImage, xoffset, yoffset, zoffset,
1106 rb, x, y, width, height);
1107 }