void _mesa_Disable( GLenum cap ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); _mesa_set_enable( ctx, cap, GL_FALSE ); }
/** * Enable GL capability. Called by glEnable() * \param cap state to enable. */ void GLAPIENTRY _mesa_Enable( GLenum cap ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); _mesa_set_enable( ctx, cap, GL_TRUE ); }
/* * Allocate a new stencil buffer. If there's an old one it will be * deallocated first. The new stencil buffer will be uninitialized. */ void gl_alloc_stencil_buffer( GLcontext *ctx ) { GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height; /* deallocate current stencil buffer if present */ if (ctx->Buffer->Stencil) { FREE(ctx->Buffer->Stencil); ctx->Buffer->Stencil = NULL; } /* allocate new stencil buffer */ ctx->Buffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil)); if (!ctx->Buffer->Stencil) { /* out of memory */ _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" ); } }
bool brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb, GLbitfield buffers, bool partial_clear) { struct gl_context *ctx = &brw->ctx; mesa_format format; enum { FAST_CLEAR, REP_CLEAR, PLAIN_CLEAR } clear_type; GLbitfield plain_clear_buffers, meta_save, rep_clear_buffers, fast_clear_buffers; struct rect fast_clear_rect, clear_rect; int layers; fast_clear_buffers = rep_clear_buffers = plain_clear_buffers = 0; /* First we loop through the color draw buffers and determine which ones * can be fast cleared, which ones can use the replicated write and which * ones have to fall back to regular color clear. */ for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); int index = fb->_ColorDrawBufferIndexes[buf]; /* Only clear the buffers present in the provided mask */ if (((1 << index) & buffers) == 0) continue; /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported, * the framebuffer can be complete with some attachments missing. In * this case the _ColorDrawBuffers pointer will be NULL. */ if (rb == NULL) continue; clear_type = FAST_CLEAR; /* We don't have fast clear until gen7. */ if (brw->gen < 7) clear_type = REP_CLEAR; if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_NO_MCS) clear_type = REP_CLEAR; /* We can't do scissored fast clears because of the restrictions on the * fast clear rectangle size. */ if (partial_clear) clear_type = REP_CLEAR; /* Fast clear is only supported for colors where all components are * either 0 or 1. */ format = _mesa_get_render_format(ctx, irb->mt->format); if (!is_color_fast_clear_compatible(brw, format, &ctx->Color.ClearColor)) clear_type = REP_CLEAR; /* From the SNB PRM (Vol4_Part1): * * "Replicated data (Message Type = 111) is only supported when * accessing tiled memory. Using this Message Type to access * linear (untiled) memory is UNDEFINED." */ if (irb->mt->tiling == I915_TILING_NONE) { perf_debug("falling back to plain clear because buffers are untiled\n"); clear_type = PLAIN_CLEAR; } /* Constant color writes ignore everything in blend and color calculator * state. This is not documented. */ GLubyte *color_mask = ctx->Color.ColorMask[buf]; for (int i = 0; i < 4; i++) { if (_mesa_format_has_color_component(irb->mt->format, i) && !color_mask[i]) { perf_debug("falling back to plain clear because of color mask\n"); clear_type = PLAIN_CLEAR; } } /* Allocate the MCS for non MSRT surfaces now if we're doing a fast * clear and we don't have the MCS yet. On failure, fall back to * replicated clear. */ if (clear_type == FAST_CLEAR && irb->mt->mcs_mt == NULL) if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) clear_type = REP_CLEAR; switch (clear_type) { case FAST_CLEAR: irb->mt->fast_clear_color_value = compute_fast_clear_color_bits(&ctx->Color.ClearColor); irb->need_downsample = true; /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the * clear is redundant and can be skipped. Only skip after we've * updated the fast clear color above though. */ if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR) continue; /* Set fast_clear_state to RESOLVED so we don't try resolve them when * we draw, in case the mt is also bound as a texture. */ irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED; irb->need_downsample = true; fast_clear_buffers |= 1 << index; get_fast_clear_rect(brw, fb, irb, &fast_clear_rect); break; case REP_CLEAR: rep_clear_buffers |= 1 << index; get_buffer_rect(brw, fb, irb, &clear_rect); break; case PLAIN_CLEAR: plain_clear_buffers |= 1 << index; get_buffer_rect(brw, fb, irb, &clear_rect); continue; } } if (!(fast_clear_buffers | rep_clear_buffers)) { if (plain_clear_buffers) /* If we only have plain clears, skip the meta save/restore. */ goto out; else /* Nothing left to do. This happens when we hit the redundant fast * clear case above and nothing else. */ return true; } meta_save = MESA_META_ALPHA_TEST | MESA_META_BLEND | MESA_META_DEPTH_TEST | MESA_META_RASTERIZATION | MESA_META_SHADER | MESA_META_STENCIL_TEST | MESA_META_VERTEX | MESA_META_VIEWPORT | MESA_META_CLIP | MESA_META_CLAMP_FRAGMENT_COLOR | MESA_META_MULTISAMPLE | MESA_META_OCCLUSION_QUERY | MESA_META_DRAW_BUFFERS; _mesa_meta_begin(ctx, meta_save); if (!brw_fast_clear_init(brw)) { /* This is going to be hard to recover from, most likely out of memory. * Bail and let meta try and (probably) fail for us. */ plain_clear_buffers = buffers; goto bail_to_meta; } /* Clears never have the color clamped. */ if (ctx->Extensions.ARB_color_buffer_float) _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); _mesa_DepthMask(GL_FALSE); _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); use_rectlist(brw, true); layers = MAX2(1, fb->MaxNumLayers); if (fast_clear_buffers) { _mesa_meta_drawbuffers_from_bitfield(fast_clear_buffers); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE); brw_draw_rectlist(ctx, &fast_clear_rect, layers); set_fast_clear_op(brw, 0); } if (rep_clear_buffers) { _mesa_meta_drawbuffers_from_bitfield(rep_clear_buffers); brw_bind_rep_write_shader(brw, ctx->Color.ClearColor.f); brw_draw_rectlist(ctx, &clear_rect, layers); } /* Now set the mts we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll * resolve them eventually. */ for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); int index = fb->_ColorDrawBufferIndexes[buf]; if ((1 << index) & fast_clear_buffers) irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; } bail_to_meta: /* Dirty _NEW_BUFFERS so we reemit SURFACE_STATE which sets the fast clear * color before resolve and sets irb->mt->fast_clear_state to UNRESOLVED if * we render to it. */ brw->NewGLState |= _NEW_BUFFERS; /* Set the custom state back to normal and dirty the same bits as above */ use_rectlist(brw, false); _mesa_meta_end(ctx); /* From BSpec: Render Target Fast Clear: * * After Render target fast clear, pipe-control with color cache * write-flush must be issued before sending any DRAW commands on that * render target. */ intel_batchbuffer_emit_mi_flush(brw); /* If we had to fall back to plain clear for any buffers, clear those now * by calling into meta. */ out: if (plain_clear_buffers) _mesa_meta_glsl_Clear(&brw->ctx, plain_clear_buffers); return true; }
/** * Leave meta state. This is like a light-weight version of glPopAttrib(). */ void _mesa_meta_end(struct gl_context *ctx) { struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth]; const GLbitfield state = save->SavedState; if (state & MESA_META_ALPHA_TEST) { if (ctx->Color.AlphaEnabled != save->AlphaEnabled) _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled); _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef); } if (state & MESA_META_BLEND) { if (ctx->Color.BlendEnabled != save->BlendEnabled) { _mesa_set_enable(ctx, GL_BLEND, (save->BlendEnabled & 1)); } if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled) _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled); } if (state & MESA_META_COLOR_MASK) { if (!TEST_EQ_4V(ctx->Color.ColorMask, save->ColorMask)) { _mesa_ColorMask(save->ColorMask[0], save->ColorMask[1], save->ColorMask[2], save->ColorMask[3]); } } if (state & MESA_META_DEPTH_TEST) { if (ctx->Depth.Test != save->Depth.Test) _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test); _mesa_DepthFunc(save->Depth.Func); _mesa_DepthMask(save->Depth.Mask); } if (state & MESA_META_FOG) { _mesa_set_enable(ctx, GL_FOG, save->Fog); } if (state & MESA_META_PIXEL_STORE) { ctx->Pack = save->Pack; ctx->Unpack = save->Unpack; } if (state & MESA_META_PIXEL_TRANSFER) { ctx->Pixel.RedScale = save->RedScale; ctx->Pixel.RedBias = save->RedBias; ctx->Pixel.GreenScale = save->GreenScale; ctx->Pixel.GreenBias = save->GreenBias; ctx->Pixel.BlueScale = save->BlueScale; ctx->Pixel.BlueBias = save->BlueBias; ctx->Pixel.AlphaScale = save->AlphaScale; ctx->Pixel.AlphaBias = save->AlphaBias; ctx->Pixel.MapColorFlag = save->MapColorFlag; /* XXX more state */ ctx->NewState |=_NEW_PIXEL; } if (state & MESA_META_RASTERIZATION) { _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset); _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); } if (state & MESA_META_SCISSOR) { _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled); _mesa_Scissor(save->Scissor.X, save->Scissor.Y, save->Scissor.Width, save->Scissor.Height); } if (state & MESA_META_STENCIL_TEST) { const struct gl_stencil_attrib *stencil = &save->Stencil; _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); _mesa_StencilFunc(stencil->Function, stencil->Ref, stencil->ValueMask); _mesa_StencilMask(stencil->WriteMask); _mesa_StencilOp(stencil->FailFunc, stencil->ZFailFunc, stencil->ZPassFunc); } if (state & MESA_META_TEXTURE) { GLuint tgt; /* restore texenv for unit[0] */ _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); /* restore texture objects for unit[0] only */ for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { if (ctx->Texture.Unit.CurrentTex[tgt] != save->CurrentTexture[tgt]) { FLUSH_VERTICES(ctx, _NEW_TEXTURE); _mesa_reference_texobj(&ctx->Texture.Unit.CurrentTex[tgt], save->CurrentTexture[tgt]); } _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL); } /* Restore fixed function texture enables, texgen */ if (ctx->Texture.Unit.Enabled != save->TexEnabled) { FLUSH_VERTICES(ctx, _NEW_TEXTURE); ctx->Texture.Unit.Enabled = save->TexEnabled; } if (ctx->Texture.Unit.TexGenEnabled != save->TexGenEnabled) { FLUSH_VERTICES(ctx, _NEW_TEXTURE); ctx->Texture.Unit.TexGenEnabled = save->TexGenEnabled; } } if (state & MESA_META_TRANSFORM) { _mesa_MatrixMode(GL_TEXTURE); _mesa_LoadMatrixf(save->TextureMatrix); _mesa_MatrixMode(GL_MODELVIEW); _mesa_LoadMatrixf(save->ModelviewMatrix); _mesa_MatrixMode(GL_PROJECTION); _mesa_LoadMatrixf(save->ProjectionMatrix); _mesa_MatrixMode(save->MatrixMode); } if (state & MESA_META_CLIP) { if (save->ClipPlanesEnabled) { GLuint i; for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { if (save->ClipPlanesEnabled & (1 << i)) { _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); } } } } if (state & MESA_META_VIEWPORT) { if (save->ViewportX != ctx->Viewport.X || save->ViewportY != ctx->Viewport.Y || save->ViewportW != ctx->Viewport.Width || save->ViewportH != ctx->Viewport.Height) { _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY, save->ViewportW, save->ViewportH); } _mesa_DepthRange(save->DepthNear, save->DepthFar); } /* misc */ if (save->Lighting) { _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE); } if (save->RasterDiscard) { _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_TRUE); } }
/** * Enter meta state. This is like a light-weight version of glPushAttrib * but it also resets most GL state back to default values. * * \param state bitmask of MESA_META_* flags indicating which attribute groups * to save and reset to their defaults */ void _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) { struct save_state *save; /* hope MAX_META_OPS_DEPTH is large enough */ assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH); save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++]; memset(save, 0, sizeof(*save)); save->SavedState = state; if (state & MESA_META_ALPHA_TEST) { save->AlphaEnabled = ctx->Color.AlphaEnabled; save->AlphaFunc = ctx->Color.AlphaFunc; save->AlphaRef = ctx->Color.AlphaRef; if (ctx->Color.AlphaEnabled) _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE); } if (state & MESA_META_BLEND) { save->BlendEnabled = ctx->Color.BlendEnabled; if (ctx->Color.BlendEnabled) { _mesa_set_enable(ctx, GL_BLEND, GL_FALSE); } save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled; if (ctx->Color.ColorLogicOpEnabled) _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE); } if (state & MESA_META_COLOR_MASK) { memcpy(save->ColorMask, ctx->Color.ColorMask, sizeof(ctx->Color.ColorMask)); if (!ctx->Color.ColorMask[0] || !ctx->Color.ColorMask[1] || !ctx->Color.ColorMask[2] || !ctx->Color.ColorMask[3]) _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } if (state & MESA_META_DEPTH_TEST) { save->Depth = ctx->Depth; /* struct copy */ if (ctx->Depth.Test) _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); } if (state & MESA_META_FOG) { save->Fog = ctx->Fog.Enabled; if (ctx->Fog.Enabled) _mesa_set_enable(ctx, GL_FOG, GL_FALSE); } if (state & MESA_META_PIXEL_STORE) { save->Pack = ctx->Pack; save->Unpack = ctx->Unpack; ctx->Pack = ctx->DefaultPacking; ctx->Unpack = ctx->DefaultPacking; } if (state & MESA_META_PIXEL_TRANSFER) { save->RedScale = ctx->Pixel.RedScale; save->RedBias = ctx->Pixel.RedBias; save->GreenScale = ctx->Pixel.GreenScale; save->GreenBias = ctx->Pixel.GreenBias; save->BlueScale = ctx->Pixel.BlueScale; save->BlueBias = ctx->Pixel.BlueBias; save->AlphaScale = ctx->Pixel.AlphaScale; save->AlphaBias = ctx->Pixel.AlphaBias; save->MapColorFlag = ctx->Pixel.MapColorFlag; ctx->Pixel.RedScale = 1.0F; ctx->Pixel.RedBias = 0.0F; ctx->Pixel.GreenScale = 1.0F; ctx->Pixel.GreenBias = 0.0F; ctx->Pixel.BlueScale = 1.0F; ctx->Pixel.BlueBias = 0.0F; ctx->Pixel.AlphaScale = 1.0F; ctx->Pixel.AlphaBias = 0.0F; ctx->Pixel.MapColorFlag = GL_FALSE; /* XXX more state */ ctx->NewState |=_NEW_PIXEL; } if (state & MESA_META_RASTERIZATION) { save->FrontPolygonMode = ctx->Polygon.FrontMode; save->BackPolygonMode = ctx->Polygon.BackMode; save->PolygonOffset = ctx->Polygon.OffsetFill; save->PolygonSmooth = ctx->Polygon.SmoothFlag; save->PolygonStipple = ctx->Polygon.StippleFlag; save->PolygonCull = ctx->Polygon.CullFlag; _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE); _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE); } if (state & MESA_META_SCISSOR) { save->Scissor = ctx->Scissor; /* struct copy */ _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); } if (state & MESA_META_STENCIL_TEST) { save->Stencil = ctx->Stencil; /* struct copy */ if (ctx->Stencil.Enabled) _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); /* NOTE: other stencil state not reset */ } if (state & MESA_META_TEXTURE) { GLuint tgt; save->EnvMode = ctx->Texture.Unit.EnvMode; /* Disable all texture units */ save->TexEnabled = ctx->Texture.Unit.Enabled; save->TexGenEnabled = ctx->Texture.Unit.TexGenEnabled; if (ctx->Texture.Unit.Enabled || ctx->Texture.Unit.TexGenEnabled) { _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); if (ctx->Extensions.ARB_texture_cube_map) _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); } /* save current texture objects for unit[0] only */ for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { _mesa_reference_texobj(&save->CurrentTexture[tgt], ctx->Texture.Unit.CurrentTex[tgt]); } _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } if (state & MESA_META_TRANSFORM) { memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m, 16 * sizeof(GLfloat)); memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m, 16 * sizeof(GLfloat)); memcpy(save->TextureMatrix, ctx->TextureMatrixStack.Top->m, 16 * sizeof(GLfloat)); save->MatrixMode = ctx->Transform.MatrixMode; /* set 1:1 vertex:pixel coordinate transform */ _mesa_MatrixMode(GL_TEXTURE); _mesa_LoadIdentity(); _mesa_MatrixMode(GL_MODELVIEW); _mesa_LoadIdentity(); _mesa_MatrixMode(GL_PROJECTION); _mesa_LoadIdentity(); _mesa_Ortho(0.0, ctx->DrawBuffer->Width, 0.0, ctx->DrawBuffer->Height, -1.0, 1.0); } if (state & MESA_META_CLIP) { save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled; if (ctx->Transform.ClipPlanesEnabled) { GLuint i; for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); } } } if (state & MESA_META_VIEWPORT) { /* save viewport state */ save->ViewportX = ctx->Viewport.X; save->ViewportY = ctx->Viewport.Y; save->ViewportW = ctx->Viewport.Width; save->ViewportH = ctx->Viewport.Height; /* set viewport to match window size */ if (ctx->Viewport.X != 0 || ctx->Viewport.Y != 0 || ctx->Viewport.Width != ctx->DrawBuffer->Width || ctx->Viewport.Height != ctx->DrawBuffer->Height) { _mesa_set_viewport(ctx, 0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); } /* save depth range state */ save->DepthNear = ctx->Viewport.Near; save->DepthFar = ctx->Viewport.Far; /* set depth range to default */ _mesa_DepthRange(0.0, 1.0); } if (state & MESA_META_SELECT_FEEDBACK) { save->RenderMode = ctx->RenderMode; if (ctx->RenderMode == GL_SELECT) { save->Select = ctx->Select; /* struct copy */ _mesa_RenderMode(GL_RENDER); } else if (ctx->RenderMode == GL_FEEDBACK) { save->Feedback = ctx->Feedback; /* struct copy */ _mesa_RenderMode(GL_RENDER); } } /* misc */ { save->Lighting = ctx->Light.Enabled; if (ctx->Light.Enabled) _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE); save->RasterDiscard = ctx->RasterDiscard; if (ctx->RasterDiscard) _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE); } }
/** * Meta implementation of ctx->Driver.BlitFramebuffer() in terms * of texture mapping and polygon rendering. */ GLbitfield _mesa_meta_BlitFramebuffer(struct gl_context *ctx, const struct gl_framebuffer *readFb, const struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLint dstW = abs(dstX1 - dstX0); const GLint dstH = abs(dstY1 - dstY0); const GLint dstFlipX = (dstX1 - dstX0) / dstW; const GLint dstFlipY = (dstY1 - dstY0) / dstH; struct { GLint srcX0, srcY0, srcX1, srcY1; GLint dstX0, dstY0, dstX1, dstY1; } clip = { srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1 }; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; /* Multisample texture blit support requires texture multisample. */ if (readFb->Visual.samples > 0 && !ctx->Extensions.ARB_texture_multisample) { return mask; } /* Clip a copy of the blit coordinates. If these differ from the input * coordinates, then we'll set the scissor. */ if (!_mesa_clip_blit(ctx, readFb, drawFb, &clip.srcX0, &clip.srcY0, &clip.srcX1, &clip.srcY1, &clip.dstX0, &clip.dstY0, &clip.dstX1, &clip.dstY1)) { /* clipped/scissored everything away */ return 0; } /* Only scissor affects blit, but we're doing to set a custom scissor if * necessary anyway, so save/clear state. */ _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS); /* Dithering shouldn't be performed for glBlitFramebuffer */ _mesa_set_enable(ctx, GL_DITHER, GL_FALSE); /* If the clipping earlier changed the destination rect at all, then * enable the scissor to clip to it. */ if (clip.dstX0 != dstX0 || clip.dstY0 != dstY0 || clip.dstX1 != dstX1 || clip.dstY1 != dstY1) { _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE); _mesa_Scissor(MIN2(clip.dstX0, clip.dstX1), MIN2(clip.dstY0, clip.dstY1), abs(clip.dstX0 - clip.dstX1), abs(clip.dstY0 - clip.dstY1)); } /* Try faster, direct texture approach first */ if (mask & GL_COLOR_BUFFER_BIT) { if (blitframebuffer_texture(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, filter, dstFlipX, dstFlipY, use_glsl_version, false)) { mask &= ~GL_COLOR_BUFFER_BIT; } } if (mask & GL_DEPTH_BUFFER_BIT && use_glsl_version) { if (blitframebuffer_texture(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, filter, dstFlipX, dstFlipY, use_glsl_version, true)) { mask &= ~GL_DEPTH_BUFFER_BIT; } } if (mask & GL_STENCIL_BUFFER_BIT) { /* XXX can't easily do stencil */ } _mesa_meta_end(ctx); return mask; }
/** * Try to do a color or depth glBlitFramebuffer using texturing. * * We can do this when the src renderbuffer is actually a texture, or when the * driver exposes BindRenderbufferTexImage(). */ static bool blitframebuffer_texture(struct gl_context *ctx, const struct gl_framebuffer *readFb, const struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLenum filter, GLint flipX, GLint flipY, GLboolean glsl_version, GLboolean do_depth) { int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex; const struct gl_renderbuffer_attachment *readAtt = &readFb->Attachment[att_index]; struct blit_state *blit = &ctx->Meta->Blit; struct fb_tex_blit_state fb_tex_blit; const GLint dstX = MIN2(dstX0, dstX1); const GLint dstY = MIN2(dstY0, dstY1); const GLint dstW = abs(dstX1 - dstX0); const GLint dstH = abs(dstY1 - dstY0); const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); bool scaled_blit = false; struct gl_texture_object *texObj; GLuint srcLevel; GLenum target; struct gl_renderbuffer *rb = readAtt->Renderbuffer; struct temp_texture *meta_temp_texture; if (rb->NumSamples && !ctx->Extensions.ARB_texture_multisample) return false; _mesa_meta_fb_tex_blit_begin(ctx, &fb_tex_blit); if (readAtt->Texture && (readAtt->Texture->Target == GL_TEXTURE_2D || readAtt->Texture->Target == GL_TEXTURE_RECTANGLE || readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE || readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { /* If there's a texture attached of a type we can handle, then just use * it directly. */ srcLevel = readAtt->TextureLevel; texObj = readAtt->Texture; target = texObj->Target; } else if (!readAtt->Texture && ctx->Driver.BindRenderbufferTexImage) { if (!_mesa_meta_bind_rb_as_tex_image(ctx, rb, &fb_tex_blit.tempTex, &texObj, &target)) return false; srcLevel = 0; if (_mesa_is_winsys_fbo(readFb)) { GLint temp = srcY0; srcY0 = rb->Height - srcY1; srcY1 = rb->Height - temp; flipY = -flipY; } } else { GLenum tex_base_format; /* Fall back to doing a CopyTexSubImage to get the destination * renderbuffer into a texture. */ if (ctx->Meta->Blit.no_ctsi_fallback) return false; if (rb->NumSamples > 1) return false; if (do_depth) { meta_temp_texture = _mesa_meta_get_temp_depth_texture(ctx); tex_base_format = GL_DEPTH_COMPONENT; } else { meta_temp_texture = _mesa_meta_get_temp_texture(ctx); tex_base_format = _mesa_base_tex_format(ctx, rb->InternalFormat); } srcLevel = 0; target = meta_temp_texture->Target; texObj = _mesa_lookup_texture(ctx, meta_temp_texture->TexObj); if (texObj == NULL) { return false; } _mesa_meta_setup_copypix_texture(ctx, meta_temp_texture, srcX0, srcY0, srcW, srcH, tex_base_format, filter); srcX0 = 0; srcY0 = 0; srcX1 = srcW; srcY1 = srcH; } fb_tex_blit.baseLevelSave = texObj->BaseLevel; fb_tex_blit.maxLevelSave = texObj->MaxLevel; fb_tex_blit.stencilSamplingSave = texObj->StencilSampling; scaled_blit = dstW != srcW || dstH != srcH; if (glsl_version) { setup_glsl_blit_framebuffer(ctx, blit, drawFb, rb, target, filter, scaled_blit, do_depth); } else { _mesa_meta_setup_ff_tnl_for_blit(ctx, &ctx->Meta->Blit.VAO, &ctx->Meta->Blit.buf_obj, 2); } /* printf("Blit from texture!\n"); printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); */ fb_tex_blit.sampler = _mesa_meta_setup_sampler(ctx, texObj, target, filter, srcLevel); /* Always do our blits with no net sRGB decode or encode. * * However, if both the src and dst can be srgb decode/encoded, enable them * so that we do any blending (from scaling or from MSAA resolves) in the * right colorspace. * * Our choice of not doing any net encode/decode is from the GL 3.0 * specification: * * "Blit operations bypass the fragment pipeline. The only fragment * operations which affect a blit are the pixel ownership test and the * scissor test." * * The GL 4.4 specification disagrees and says that the sRGB part of the * fragment pipeline applies, but this was found to break applications. */ if (ctx->Extensions.EXT_texture_sRGB_decode) { if (_mesa_get_format_color_encoding(rb->Format) == GL_SRGB && drawFb->Visual.sRGBCapable) { _mesa_SamplerParameteri(fb_tex_blit.sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); _mesa_set_framebuffer_srgb(ctx, GL_TRUE); } else { _mesa_SamplerParameteri(fb_tex_blit.sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); /* set_framebuffer_srgb was set by _mesa_meta_begin(). */ } } if (!glsl_version) { _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); _mesa_set_enable(ctx, target, GL_TRUE); } /* Prepare vertex data (the VBO was previously created and bound) */ { struct vertex verts[4]; GLfloat s0, t0, s1, t1; if (target == GL_TEXTURE_2D) { const struct gl_texture_image *texImage = _mesa_select_tex_image(texObj, target, srcLevel); s0 = srcX0 / (float) texImage->Width; s1 = srcX1 / (float) texImage->Width; t0 = srcY0 / (float) texImage->Height; t1 = srcY1 / (float) texImage->Height; } else { assert(target == GL_TEXTURE_RECTANGLE_ARB || target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); s0 = (float) srcX0; s1 = (float) srcX1; t0 = (float) srcY0; t1 = (float) srcY1; } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F * flipX; verts[0].y = -1.0F * flipY; verts[1].x = 1.0F * flipX; verts[1].y = -1.0F * flipY; verts[2].x = 1.0F * flipX; verts[2].y = 1.0F * flipY; verts[3].x = -1.0F * flipX; verts[3].y = 1.0F * flipY; verts[0].tex[0] = s0; verts[0].tex[1] = t0; verts[0].tex[2] = readAtt->Zoffset; verts[1].tex[0] = s1; verts[1].tex[1] = t0; verts[1].tex[2] = readAtt->Zoffset; verts[2].tex[0] = s1; verts[2].tex[1] = t1; verts[2].tex[2] = readAtt->Zoffset; verts[3].tex[0] = s0; verts[3].tex[1] = t1; verts[3].tex[2] = readAtt->Zoffset; _mesa_buffer_sub_data(ctx, blit->buf_obj, 0, sizeof(verts), verts, __func__); } /* setup viewport */ _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH); _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth); _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth); _mesa_DepthMask(do_depth); _mesa_DepthFunc(GL_ALWAYS); _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); _mesa_meta_fb_tex_blit_end(ctx, target, &fb_tex_blit); return true; }
static void setup_glsl_msaa_blit_shader(struct gl_context *ctx, struct blit_state *blit, const struct gl_framebuffer *drawFb, struct gl_renderbuffer *src_rb, GLenum target) { const char *vs_source; char *fs_source; void *mem_ctx; enum blit_msaa_shader shader_index; bool dst_is_msaa = false; GLenum src_datatype; const char *vec4_prefix; const char *sampler_array_suffix = ""; char *name; const char *texcoord_type = "vec2"; int samples; int shader_offset = 0; if (src_rb) { samples = MAX2(src_rb->NumSamples, 1); src_datatype = _mesa_get_format_datatype(src_rb->Format); } else { /* depth-or-color glCopyTexImage fallback path that passes a NULL rb and * doesn't handle integer. */ samples = 1; src_datatype = GL_UNSIGNED_NORMALIZED; } /* We expect only power of 2 samples in source multisample buffer. */ assert(samples > 0 && _mesa_is_pow_two(samples)); while (samples >> (shader_offset + 1)) { shader_offset++; } /* Update the assert if we plan to support more than 16X MSAA. */ assert(shader_offset >= 0 && shader_offset <= 4); if (drawFb->Visual.samples > 1) { /* If you're calling meta_BlitFramebuffer with the destination * multisampled, this is the only path that will work -- swrast and * CopyTexImage won't work on it either. */ assert(ctx->Extensions.ARB_sample_shading); dst_is_msaa = true; /* We need shader invocation per sample, not per pixel */ _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_TRUE); _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_TRUE); _mesa_MinSampleShading(1.0); } switch (target) { case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: if (src_rb && (src_rb->_BaseFormat == GL_DEPTH_COMPONENT || src_rb->_BaseFormat == GL_DEPTH_STENCIL)) { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY; else shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE; } else { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_COPY; else { shader_index = BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + shader_offset; } } if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { shader_index += (BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_RESOLVE - BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE); sampler_array_suffix = "Array"; texcoord_type = "vec3"; } break; default: _mesa_problem(ctx, "Unkown texture target %s\n", _mesa_enum_to_string(target)); shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE; } /* We rely on the enum being sorted this way. */ STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 5); STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 10); if (src_datatype == GL_INT) { shader_index += 5; vec4_prefix = "i"; } else if (src_datatype == GL_UNSIGNED_INT) { shader_index += 10; vec4_prefix = "u"; } else { vec4_prefix = ""; } if (blit->msaa_shaders[shader_index]) { _mesa_UseProgram(blit->msaa_shaders[shader_index]); return; } mem_ctx = ralloc_context(NULL); if (shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_COPY || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY) { char *sample_index; const char *arb_sample_shading_extension_string; if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_index = "gl_SampleID"; name = "depth MSAA copy"; } else { /* Don't need that extension, since we're drawing to a single-sampled * destination. */ arb_sample_shading_extension_string = ""; /* From the GL 4.3 spec: * * "If there is a multisample buffer (the value of SAMPLE_BUFFERS * is one), then values are obtained from the depth samples in * this buffer. It is recommended that the depth value of the * centermost sample be used, though implementations may choose * any function of the depth sample values at each pixel. * * We're slacking and instead of choosing centermost, we've got 0. */ sample_index = "0"; name = "depth MSAA resolve"; } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "uniform sampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out vec4 out_color;\n" "\n" "void main()\n" "{\n" " gl_FragDepth = texelFetch(texSampler, i%s(texCoords), %s).r;\n" "}\n", arb_sample_shading_extension_string, sampler_array_suffix, texcoord_type, texcoord_type, sample_index); } else { /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1 * sample). Yes, this is ridiculous. */ char *sample_resolve; const char *arb_sample_shading_extension_string; const char *merge_function; name = ralloc_asprintf(mem_ctx, "%svec4 MSAA %s", vec4_prefix, dst_is_msaa ? "copy" : "resolve"); if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_resolve = ralloc_asprintf(mem_ctx, " out_color = texelFetch(texSampler, i%s(texCoords), gl_SampleID);", texcoord_type); merge_function = ""; } else { int i; int step; if (src_datatype == GL_INT || src_datatype == GL_UNSIGNED_INT) { merge_function = "gvec4 merge(gvec4 a, gvec4 b) { return (a >> gvec4(1)) + (b >> gvec4(1)) + (a & b & gvec4(1)); }\n"; } else { /* The divide will happen at the end for floats. */ merge_function = "vec4 merge(vec4 a, vec4 b) { return (a + b); }\n"; } arb_sample_shading_extension_string = ""; /* We're assuming power of two samples for this resolution procedure. * * To avoid losing any floating point precision if the samples all * happen to have the same value, we merge pairs of values at a time * (so the floating point exponent just gets increased), rather than * doing a naive sum and dividing. */ assert(_mesa_is_pow_two(samples)); /* Fetch each individual sample. */ sample_resolve = rzalloc_size(mem_ctx, 1); for (i = 0; i < samples; i++) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_1_%d = texelFetch(texSampler, i%s(texCoords), %d);\n", i, texcoord_type, i); } /* Now, merge each pair of samples, then merge each pair of those, * etc. */ for (step = 2; step <= samples; step *= 2) { for (i = 0; i < samples; i += step) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_%d_%d = merge(sample_%d_%d, sample_%d_%d);\n", step, i, step / 2, i, step / 2, i + step / 2); } } /* Scale the final result. */ if (src_datatype == GL_UNSIGNED_INT || src_datatype == GL_INT) { ralloc_asprintf_append(&sample_resolve, " out_color = sample_%d_0;\n", samples); } else { ralloc_asprintf_append(&sample_resolve, " gl_FragColor = sample_%d_0 / %f;\n", samples, (float)samples); } } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "#define gvec4 %svec4\n" "uniform %ssampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out gvec4 out_color;\n" "\n" "%s" /* merge_function */ "void main()\n" "{\n" "%s\n" /* sample_resolve */ "}\n", arb_sample_shading_extension_string, vec4_prefix, vec4_prefix, sampler_array_suffix, texcoord_type, merge_function, sample_resolve); } _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name, &blit->msaa_shaders[shader_index]); ralloc_free(mem_ctx); }
/** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, 1D/2D array textures or texture * borders. */ void _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct vertex verts[4]; const GLuint baseLevel = texObj->BaseLevel; const GLuint maxLevel = texObj->MaxLevel; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; GLenum faceTarget; GLuint dstLevel; GLuint samplerSave; GLint swizzle[4]; GLboolean swizzleSaved = GL_FALSE; if (fallback_required(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); return; } if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { faceTarget = target; target = GL_TEXTURE_CUBE_MAP; } else { faceTarget = target; } _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS); /* Choose between glsl version and fixed function version of * GenerateMipmap function. */ if (use_glsl_version) { _mesa_meta_setup_vertex_objects(&mipmap->VAO, &mipmap->VBO, true, 2, 4, 0); _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders); } else { _mesa_meta_setup_ff_tnl_for_blit(&mipmap->VAO, &mipmap->VBO, 3); _mesa_set_enable(ctx, target, GL_TRUE); } samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; if (currentTexUnitSave != 0) glBindTexture(target, texObj->Name); if (!mipmap->Sampler) { glGenSamplers(1, &mipmap->Sampler); glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); /* We don't want to encode or decode sRGB values; treat them as linear. * This is not technically correct for GLES3 but we don't get any API * error at the moment. */ if (ctx->Extensions.EXT_texture_sRGB_decode) { glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); } } else { glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); } assert(mipmap->FBO != 0); glBindFramebuffer(GL_FRAMEBUFFER, mipmap->FBO); glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); // if (texObj->_Swizzle != SWIZZLE_NOOP) { // static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; // memcpy(swizzle, texObj->Swizzle, sizeof(swizzle)); // swizzleSaved = GL_TRUE; // glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop); // } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F; verts[0].y = -1.0F; verts[1].x = 1.0F; verts[1].y = -1.0F; verts[2].x = 1.0F; verts[2].y = 1.0F; verts[3].x = -1.0F; verts[3].y = 1.0F; /* texture is already locked, unlock now */ _mesa_unlock_texture(ctx, texObj); for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; const GLuint srcLevel = dstLevel - 1; GLuint layer; GLsizei srcWidth, srcHeight, srcDepth; GLsizei dstWidth, dstHeight, dstDepth; srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel); assert(srcImage->Border == 0); /* src size */ srcWidth = srcImage->Width; if (target == GL_TEXTURE_1D_ARRAY) { srcHeight = 1; srcDepth = srcImage->Height; } else { srcHeight = srcImage->Height; srcDepth = srcImage->Depth; } /* new dst size */ dstWidth = minify(srcWidth, 1); dstHeight = minify(srcHeight, 1); // dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth; dstDepth = srcDepth; if (dstWidth == srcWidth && dstHeight == srcHeight && dstDepth == srcDepth) { /* all done */ break; } /* Allocate storage for the destination mipmap image(s) */ /* Set MaxLevel large enough to hold the new level when we allocate it */ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); if (!prepare_mipmap_level(ctx, texObj, dstLevel, dstWidth, dstHeight, dstDepth, srcImage->InternalFormat, srcImage->TexFormat)) { /* All done. We either ran out of memory or we would go beyond the * last valid level of an immutable texture if we continued. */ break; } dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); /* limit minification to src level */ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); /* setup viewport */ _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight); glDrawBuffer(GL_COLOR_ATTACHMENT0); for (layer = 0; layer < dstDepth; ++layer) { /* Setup texture coordinates */ _mesa_meta_setup_texture_coords(faceTarget, layer, 0, 0, 1, /* width, height never used here */ verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW); _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { _mesa_problem(ctx, "Unexpected incomplete framebuffer in " "_mesa_meta_GenerateMipmap()"); break; } assert(dstWidth == ctx->DrawBuffer->Width); if (target == GL_TEXTURE_1D_ARRAY) { assert(dstHeight == 1); } else { assert(dstHeight == ctx->DrawBuffer->Height); } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } } _mesa_lock_texture(ctx, texObj); /* relock */ glBindSampler(ctx->Texture.CurrentUnit, samplerSave); _mesa_meta_end(ctx); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); if (genMipmapSave) glTexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); // if (swizzleSaved) // glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); }
/** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, or texture borders. */ void _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct vertex verts[4]; const GLuint baseLevel = texObj->BaseLevel; const GLuint maxLevel = texObj->MaxLevel; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; GLenum faceTarget; GLuint dstLevel; struct gl_sampler_object *samp_obj_save = NULL; GLint swizzle[4]; GLboolean swizzleSaved = GL_FALSE; /* GLint so the compiler won't complain about type signedness mismatch in * the calls to _mesa_texture_parameteriv below. */ static const GLint always_false = GL_FALSE; static const GLint always_true = GL_TRUE; if (fallback_required(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); return; } if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { faceTarget = target; target = GL_TEXTURE_CUBE_MAP; } else { faceTarget = target; } _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS); _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); /* Choose between glsl version and fixed function version of * GenerateMipmap function. */ if (use_glsl_version) { _mesa_meta_setup_vertex_objects(ctx, &mipmap->VAO, &mipmap->buf_obj, true, 2, 4, 0); _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders); } else { _mesa_meta_setup_ff_tnl_for_blit(ctx, &mipmap->VAO, &mipmap->buf_obj, 3); _mesa_set_enable(ctx, target, GL_TRUE); } _mesa_reference_sampler_object(ctx, &samp_obj_save, ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler); /* We may have been called from glGenerateTextureMipmap with CurrentUnit * still set to 0, so we don't know when we can skip binding the texture. * Assume that _mesa_BindTexture will be fast if we're rebinding the same * texture. */ _mesa_BindTexture(target, texObj->Name); if (mipmap->samp_obj == NULL) { mipmap->samp_obj = ctx->Driver.NewSamplerObject(ctx, 0xDEADBEEF); if (mipmap->samp_obj == NULL) { /* This is a bit lazy. Flag out of memory, and then don't bother to * clean up. Once out of memory is flagged, the only realistic next * move is to destroy the context. That will trigger all the right * clean up. */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenerateMipmap"); return; } _mesa_set_sampler_filters(ctx, mipmap->samp_obj, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); _mesa_set_sampler_wrap(ctx, mipmap->samp_obj, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); /* We don't want to encode or decode sRGB values; treat them as linear. */ _mesa_set_sampler_srgb_decode(ctx, mipmap->samp_obj, GL_SKIP_DECODE_EXT); } _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, mipmap->samp_obj); assert(mipmap->fb != NULL); _mesa_bind_framebuffers(ctx, mipmap->fb, mipmap->fb); _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_false, false); if (texObj->_Swizzle != SWIZZLE_NOOP) { static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; memcpy(swizzle, texObj->Swizzle, sizeof(swizzle)); swizzleSaved = GL_TRUE; _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop, false); } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F; verts[0].y = -1.0F; verts[1].x = 1.0F; verts[1].y = -1.0F; verts[2].x = 1.0F; verts[2].y = 1.0F; verts[3].x = -1.0F; verts[3].y = 1.0F; /* texture is already locked, unlock now */ _mesa_unlock_texture(ctx, texObj); _mesa_prepare_mipmap_levels(ctx, texObj, baseLevel, maxLevel); for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; const GLuint srcLevel = dstLevel - 1; GLuint layer; GLsizei srcWidth, srcHeight, srcDepth; GLsizei dstWidth, dstHeight, dstDepth; srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel); assert(srcImage->Border == 0); /* src size */ srcWidth = srcImage->Width; if (target == GL_TEXTURE_1D_ARRAY) { srcHeight = 1; srcDepth = srcImage->Height; } else { srcHeight = srcImage->Height; srcDepth = srcImage->Depth; } /* new dst size */ dstWidth = minify(srcWidth, 1); dstHeight = minify(srcHeight, 1); dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth; if (dstWidth == srcWidth && dstHeight == srcHeight && dstDepth == srcDepth) { /* all done */ break; } /* Allocate storage for the destination mipmap image(s) */ /* Set MaxLevel large enough to hold the new level when we allocate it */ _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, (GLint *) &dstLevel, false); dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); /* All done. We either ran out of memory or we would go beyond the last * valid level of an immutable texture if we continued. */ if (dstImage == NULL) break; /* limit minification to src level */ _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, (GLint *) &srcLevel, false); /* setup viewport */ _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); for (layer = 0; layer < dstDepth; ++layer) { /* Setup texture coordinates */ _mesa_meta_setup_texture_coords(faceTarget, layer, 0, 0, /* xoffset, yoffset */ srcWidth, srcHeight, /* img size */ srcWidth, srcHeight, srcDepth, verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ _mesa_buffer_data(ctx, mipmap->buf_obj, GL_NONE, sizeof(verts), verts, GL_DYNAMIC_DRAW, __func__); _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (_mesa_check_framebuffer_status(ctx, ctx->DrawBuffer) != GL_FRAMEBUFFER_COMPLETE) { _mesa_problem(ctx, "Unexpected incomplete framebuffer in " "_mesa_meta_GenerateMipmap()"); break; } assert(dstWidth == ctx->DrawBuffer->Width); if (target == GL_TEXTURE_1D_ARRAY) { assert(dstHeight == 1); } else { assert(dstHeight == ctx->DrawBuffer->Height); } _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } } _mesa_lock_texture(ctx, texObj); /* relock */ _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj_save); _mesa_reference_sampler_object(ctx, &samp_obj_save, NULL); _mesa_meta_end(ctx); _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, &maxLevelSave, false); if (genMipmapSave) _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_true, false); if (swizzleSaved) _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzle, false); }
/* * This function is kind of long just because we have to call a lot * of device driver functions to update device driver state. * * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions * in order to restore GL state. This isn't terribly efficient but it * ensures that dirty flags and any derived state gets updated correctly. * We could at least check if the value to restore equals the current value * and then skip the Mesa call. */ void _mesa_PopAttrib(void) { struct gl_attrib_node *attr, *next; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (ctx->AttribStackDepth == 0) { _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" ); return; } ctx->AttribStackDepth--; attr = ctx->AttribStack[ctx->AttribStackDepth]; while (attr) { if (MESA_VERBOSE&VERBOSE_API) { fprintf(stderr, "glPopAttrib %s\n", _mesa_lookup_enum_by_nr(attr->kind)); } switch (attr->kind) { case GL_ACCUM_BUFFER_BIT: { const struct gl_accum_attrib *accum; accum = (const struct gl_accum_attrib *) attr->data; _mesa_ClearAccum(accum->ClearColor[0], accum->ClearColor[1], accum->ClearColor[2], accum->ClearColor[3]); } break; case GL_COLOR_BUFFER_BIT: { const struct gl_colorbuffer_attrib *color; color = (const struct gl_colorbuffer_attrib *) attr->data; _mesa_ClearIndex((GLfloat) color->ClearIndex); _mesa_ClearColor(CHAN_TO_FLOAT(color->ClearColor[0]), CHAN_TO_FLOAT(color->ClearColor[1]), CHAN_TO_FLOAT(color->ClearColor[2]), CHAN_TO_FLOAT(color->ClearColor[3])); _mesa_IndexMask(color->IndexMask); _mesa_ColorMask((GLboolean) (color->ColorMask[0] != 0), (GLboolean) (color->ColorMask[1] != 0), (GLboolean) (color->ColorMask[2] != 0), (GLboolean) (color->ColorMask[3] != 0)); _mesa_DrawBuffer(color->DrawBuffer); _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); _mesa_AlphaFunc(color->AlphaFunc, CHAN_TO_FLOAT(color->AlphaRef)); _mesa_set_enable(ctx, GL_BLEND, color->BlendEnabled); _mesa_BlendFuncSeparateEXT(color->BlendSrcRGB, color->BlendDstRGB, color->BlendSrcA, color->BlendDstA); _mesa_BlendEquation(color->BlendEquation); _mesa_BlendColor(color->BlendColor[0], color->BlendColor[1], color->BlendColor[2], color->BlendColor[3]); _mesa_LogicOp(color->LogicOp); _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, color->ColorLogicOpEnabled); _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP, color->IndexLogicOpEnabled); _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag); } break; case GL_CURRENT_BIT: FLUSH_CURRENT( ctx, 0 ); MEMCPY( &ctx->Current, attr->data, sizeof(struct gl_current_attrib) ); break; case GL_DEPTH_BUFFER_BIT: { const struct gl_depthbuffer_attrib *depth; depth = (const struct gl_depthbuffer_attrib *) attr->data; _mesa_DepthFunc(depth->Func); _mesa_ClearDepth(depth->Clear); _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); _mesa_DepthMask(depth->Mask); if (ctx->Extensions.HP_occlusion_test) _mesa_set_enable(ctx, GL_OCCLUSION_TEST_HP, depth->OcclusionTest); } break; case GL_ENABLE_BIT: { const struct gl_enable_attrib *enable; enable = (const struct gl_enable_attrib *) attr->data; pop_enable_group(ctx, enable); ctx->NewState |= _NEW_ALL; } break; case GL_EVAL_BIT: MEMCPY( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) ); ctx->NewState |= _NEW_EVAL; break; case GL_FOG_BIT: { const struct gl_fog_attrib *fog; fog = (const struct gl_fog_attrib *) attr->data; _mesa_set_enable(ctx, GL_FOG, fog->Enabled); _mesa_Fogfv(GL_FOG_COLOR, fog->Color); _mesa_Fogf(GL_FOG_DENSITY, fog->Density); _mesa_Fogf(GL_FOG_START, fog->Start); _mesa_Fogf(GL_FOG_END, fog->End); _mesa_Fogf(GL_FOG_INDEX, fog->Index); _mesa_Fogi(GL_FOG_MODE, fog->Mode); } break; case GL_HINT_BIT: { const struct gl_hint_attrib *hint; hint = (const struct gl_hint_attrib *) attr->data; _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT, hint->PerspectiveCorrection ); _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth); _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth); _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth); _mesa_Hint(GL_FOG_HINT, hint->Fog); _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, hint->ClipVolumeClipping); if (ctx->Extensions.ARB_texture_compression) _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB, hint->TextureCompression); } break; case GL_LIGHTING_BIT: { GLuint i; const struct gl_light_attrib *light; light = (const struct gl_light_attrib *) attr->data; /* lighting enable */ _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); /* per-light state */ if (ctx->ModelView.flags & MAT_DIRTY_INVERSE) _math_matrix_analyse( &ctx->ModelView ); for (i = 0; i < MAX_LIGHTS; i++) { GLenum lgt = (GLenum) (GL_LIGHT0 + i); const struct gl_light *l = &light->Light[i]; GLfloat tmp[4]; _mesa_set_enable(ctx, lgt, l->Enabled); _mesa_Lightfv( lgt, GL_AMBIENT, l->Ambient ); _mesa_Lightfv( lgt, GL_DIFFUSE, l->Diffuse ); _mesa_Lightfv( lgt, GL_SPECULAR, l->Specular ); TRANSFORM_POINT( tmp, ctx->ModelView.inv, l->EyePosition ); _mesa_Lightfv( lgt, GL_POSITION, tmp ); TRANSFORM_POINT( tmp, ctx->ModelView.m, l->EyeDirection ); _mesa_Lightfv( lgt, GL_SPOT_DIRECTION, tmp ); _mesa_Lightfv( lgt, GL_SPOT_EXPONENT, &l->SpotExponent ); _mesa_Lightfv( lgt, GL_SPOT_CUTOFF, &l->SpotCutoff ); _mesa_Lightfv( lgt, GL_CONSTANT_ATTENUATION, &l->ConstantAttenuation ); _mesa_Lightfv( lgt, GL_LINEAR_ATTENUATION, &l->LinearAttenuation ); _mesa_Lightfv( lgt, GL_QUADRATIC_ATTENUATION, &l->QuadraticAttenuation ); } /* light model */ _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, light->Model.Ambient); _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, (GLfloat) light->Model.LocalViewer); _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE, (GLfloat) light->Model.TwoSide); _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, (GLfloat) light->Model.ColorControl); /* materials */ MEMCPY(ctx->Light.Material, light->Material, 2 * sizeof(struct gl_material)); /* shade model */ _mesa_ShadeModel(light->ShadeModel); /* color material */ _mesa_ColorMaterial(light->ColorMaterialFace, light->ColorMaterialMode); _mesa_set_enable(ctx, GL_COLOR_MATERIAL, light->ColorMaterialEnabled); } break; case GL_LINE_BIT: { const struct gl_line_attrib *line; line = (const struct gl_line_attrib *) attr->data; _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag); _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag); _mesa_LineStipple(line->StippleFactor, line->StipplePattern); _mesa_LineWidth(line->Width); } break; case GL_LIST_BIT: MEMCPY( &ctx->List, attr->data, sizeof(struct gl_list_attrib) ); break; case GL_PIXEL_MODE_BIT: MEMCPY( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); ctx->NewState |= _NEW_PIXEL; break; case GL_POINT_BIT: { const struct gl_point_attrib *point; point = (const struct gl_point_attrib *) attr->data; _mesa_PointSize(point->Size); _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); if (ctx->Extensions.EXT_point_parameters) { _mesa_PointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, point->Params); _mesa_PointParameterfEXT(GL_POINT_SIZE_MIN_EXT, point->MinSize); _mesa_PointParameterfEXT(GL_POINT_SIZE_MAX_EXT, point->MaxSize); _mesa_PointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, point->Threshold); } } break; case GL_POLYGON_BIT: { const struct gl_polygon_attrib *polygon; polygon = (const struct gl_polygon_attrib *) attr->data; _mesa_CullFace(polygon->CullFaceMode); _mesa_FrontFace(polygon->FrontFace); _mesa_PolygonMode(GL_FRONT, polygon->FrontMode); _mesa_PolygonMode(GL_BACK, polygon->BackMode); _mesa_PolygonOffset(polygon->OffsetFactor, polygon->OffsetUnits); _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag); _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag); _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT, polygon->OffsetPoint); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE, polygon->OffsetLine); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, polygon->OffsetFill); } break; case GL_POLYGON_STIPPLE_BIT: MEMCPY( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) ); ctx->NewState |= _NEW_POLYGONSTIPPLE; if (ctx->Driver.PolygonStipple) ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data ); break; case GL_SCISSOR_BIT: { const struct gl_scissor_attrib *scissor; scissor = (const struct gl_scissor_attrib *) attr->data; _mesa_Scissor(scissor->X, scissor->Y, scissor->Width, scissor->Height); _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled); } break; case GL_STENCIL_BUFFER_BIT: { const struct gl_stencil_attrib *stencil; stencil = (const struct gl_stencil_attrib *) attr->data; _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); _mesa_StencilFunc(stencil->Function, stencil->Ref, stencil->ValueMask); _mesa_StencilMask(stencil->WriteMask); _mesa_StencilOp(stencil->FailFunc, stencil->ZFailFunc, stencil->ZPassFunc); } break; case GL_TRANSFORM_BIT: { GLuint i; const struct gl_transform_attrib *xform; xform = (const struct gl_transform_attrib *) attr->data; _mesa_MatrixMode(xform->MatrixMode); if (ctx->ProjectionMatrix.flags & MAT_DIRTY) _math_matrix_analyse( &ctx->ProjectionMatrix ); /* restore clip planes */ for (i = 0; i < MAX_CLIP_PLANES; i++) { const GLfloat *eyePlane = xform->EyeUserPlane[i]; COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane); if (xform->ClipEnabled[i]) { _mesa_transform_vector( ctx->Transform._ClipUserPlane[i], eyePlane, ctx->ProjectionMatrix.inv ); _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE ); } else { _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE ); } if (ctx->Driver.ClipPlane) ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane ); } /* normalize/rescale */ _mesa_set_enable(ctx, GL_NORMALIZE, ctx->Transform.Normalize); _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT, ctx->Transform.RescaleNormals); } break; case GL_TEXTURE_BIT: /* Take care of texture object reference counters */ { const struct gl_texture_attrib *texture; texture = (const struct gl_texture_attrib *) attr->data; pop_texture_group(ctx, texture); ctx->NewState |= _NEW_TEXTURE; } break; case GL_VIEWPORT_BIT: { const struct gl_viewport_attrib *vp; vp = (const struct gl_viewport_attrib *) attr->data; _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height); _mesa_DepthRange(vp->Near, vp->Far); } break; case GL_MULTISAMPLE_BIT_ARB: { const struct gl_multisample_attrib *ms; ms = (const struct gl_multisample_attrib *) attr->data; _mesa_SampleCoverageARB(ms->SampleCoverageValue, ms->SampleCoverageInvert); } break; default: _mesa_problem( ctx, "Bad attrib flag in PopAttrib"); break; } next = attr->next; FREE( attr->data ); FREE( attr ); attr = next; } }
static void pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) { GLuint u; for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { const struct gl_texture_unit *unit = &texAttrib->Unit[u]; GLuint i; _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u); _mesa_set_enable(ctx, GL_TEXTURE_1D, (GLboolean) (unit->Enabled & TEXTURE0_1D ? GL_TRUE : GL_FALSE)); _mesa_set_enable(ctx, GL_TEXTURE_2D, (GLboolean) (unit->Enabled & TEXTURE0_2D ? GL_TRUE : GL_FALSE)); _mesa_set_enable(ctx, GL_TEXTURE_3D, (GLboolean) (unit->Enabled & TEXTURE0_3D ? GL_TRUE : GL_FALSE)); if (ctx->Extensions.ARB_texture_cube_map) { _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, (GLboolean) (unit->Enabled & TEXTURE0_CUBE ? GL_TRUE : GL_FALSE)); } if (ctx->Extensions.NV_texture_rectangle) { _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, (GLboolean) (unit->Enabled & TEXTURE0_RECT ? GL_TRUE : GL_FALSE)); } _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenModeS); _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenModeT); _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenModeR); _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenModeQ); _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->ObjectPlaneS); _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->ObjectPlaneT); _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->ObjectPlaneR); _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->ObjectPlaneQ); _mesa_TexGenfv(GL_S, GL_EYE_PLANE, unit->EyePlaneS); _mesa_TexGenfv(GL_T, GL_EYE_PLANE, unit->EyePlaneT); _mesa_TexGenfv(GL_R, GL_EYE_PLANE, unit->EyePlaneR); _mesa_TexGenfv(GL_Q, GL_EYE_PLANE, unit->EyePlaneQ); if (ctx->Extensions.EXT_texture_lod_bias) { _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); } if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, unit->CombineModeRGB); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, unit->CombineModeA); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, unit->CombineSourceRGB[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, unit->CombineSourceRGB[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, unit->CombineSourceRGB[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, unit->CombineSourceA[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, unit->CombineSourceA[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, unit->CombineSourceA[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, unit->CombineOperandRGB[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, unit->CombineOperandRGB[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, unit->CombineOperandRGB[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, unit->CombineOperandA[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, unit->CombineOperandA[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, unit->CombineOperandA[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1 << unit->CombineScaleShiftRGB); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 << unit->CombineScaleShiftA); } /* Restore texture object state */ for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { GLenum target = 0; const struct gl_texture_object *obj = NULL; GLfloat bordColor[4]; switch (i) { case 0: target = GL_TEXTURE_1D; obj = &unit->Saved1D; break; case 1: target = GL_TEXTURE_2D; obj = &unit->Saved2D; break; case 2: target = GL_TEXTURE_3D; obj = &unit->Saved3D; break; case 3: if (!ctx->Extensions.ARB_texture_cube_map) continue; target = GL_TEXTURE_CUBE_MAP_ARB; obj = &unit->SavedCubeMap; break; case 4: if (!ctx->Extensions.NV_texture_rectangle) continue; target = GL_TEXTURE_RECTANGLE_NV; obj = &unit->SavedRect; break; default: ; /* silence warnings */ } _mesa_BindTexture(target, obj->Name); bordColor[0] = CHAN_TO_FLOAT(obj->BorderColor[0]); bordColor[1] = CHAN_TO_FLOAT(obj->BorderColor[1]); bordColor[2] = CHAN_TO_FLOAT(obj->BorderColor[2]); bordColor[3] = CHAN_TO_FLOAT(obj->BorderColor[3]); _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority); _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, bordColor); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR); _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter); _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); if (ctx->Extensions.EXT_texture_filter_anisotropic) { _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, obj->MaxAnisotropy); } if (ctx->Extensions.SGIX_shadow) { _mesa_TexParameteri(target, GL_TEXTURE_COMPARE_SGIX, obj->CompareFlag); _mesa_TexParameteri(target, GL_TEXTURE_COMPARE_OPERATOR_SGIX, obj->CompareOperator); } if (ctx->Extensions.SGIX_shadow_ambient) { _mesa_TexParameterf(target, GL_SHADOW_AMBIENT_SGIX, CHAN_TO_FLOAT(obj->ShadowAmbient)); } } } _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texAttrib->CurrentUnit); /* "un-bump" the texture object reference counts. We did that so they * wouldn't inadvertantly get deleted while they were still referenced * inside the attribute state stack. */ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { ctx->Texture.Unit[u].Current1D->RefCount--; ctx->Texture.Unit[u].Current2D->RefCount--; ctx->Texture.Unit[u].Current3D->RefCount--; ctx->Texture.Unit[u].CurrentCubeMap->RefCount--; ctx->Texture.Unit[u].CurrentRect->RefCount--; } }
static void pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) { GLuint i; #define TEST_AND_UPDATE(VALUE, NEWVALUE, ENUM) \ if ((VALUE) != (NEWVALUE)) { \ _mesa_set_enable( ctx, ENUM, (NEWVALUE) ); \ } TEST_AND_UPDATE(ctx->Color.AlphaEnabled, enable->AlphaTest, GL_ALPHA_TEST); TEST_AND_UPDATE(ctx->Color.BlendEnabled, enable->Blend, GL_BLEND); for (i=0;i<MAX_CLIP_PLANES;i++) { if (ctx->Transform.ClipEnabled[i] != enable->ClipPlane[i]) _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), enable->ClipPlane[i]); } TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial, GL_COLOR_MATERIAL); TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE); TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST); TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER); TEST_AND_UPDATE(ctx->Pixel.Convolution1DEnabled, enable->Convolution1D, GL_CONVOLUTION_1D); TEST_AND_UPDATE(ctx->Pixel.Convolution2DEnabled, enable->Convolution2D, GL_CONVOLUTION_2D); TEST_AND_UPDATE(ctx->Pixel.Separable2DEnabled, enable->Separable2D, GL_SEPARABLE_2D); TEST_AND_UPDATE(ctx->Fog.Enabled, enable->Fog, GL_FOG); TEST_AND_UPDATE(ctx->Light.Enabled, enable->Lighting, GL_LIGHTING); TEST_AND_UPDATE(ctx->Line.SmoothFlag, enable->LineSmooth, GL_LINE_SMOOTH); TEST_AND_UPDATE(ctx->Line.StippleFlag, enable->LineStipple, GL_LINE_STIPPLE); TEST_AND_UPDATE(ctx->Color.IndexLogicOpEnabled, enable->IndexLogicOp, GL_INDEX_LOGIC_OP); TEST_AND_UPDATE(ctx->Color.ColorLogicOpEnabled, enable->ColorLogicOp, GL_COLOR_LOGIC_OP); TEST_AND_UPDATE(ctx->Eval.Map1Color4, enable->Map1Color4, GL_MAP1_COLOR_4); TEST_AND_UPDATE(ctx->Eval.Map1Index, enable->Map1Index, GL_MAP1_INDEX); TEST_AND_UPDATE(ctx->Eval.Map1Normal, enable->Map1Normal, GL_MAP1_NORMAL); TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord1, enable->Map1TextureCoord1, GL_MAP1_TEXTURE_COORD_1); TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord2, enable->Map1TextureCoord2, GL_MAP1_TEXTURE_COORD_2); TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord3, enable->Map1TextureCoord3, GL_MAP1_TEXTURE_COORD_3); TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord4, enable->Map1TextureCoord4, GL_MAP1_TEXTURE_COORD_4); TEST_AND_UPDATE(ctx->Eval.Map1Vertex3, enable->Map1Vertex3, GL_MAP1_VERTEX_3); TEST_AND_UPDATE(ctx->Eval.Map1Vertex4, enable->Map1Vertex4, GL_MAP1_VERTEX_4); TEST_AND_UPDATE(ctx->Eval.Map2Color4, enable->Map2Color4, GL_MAP2_COLOR_4); TEST_AND_UPDATE(ctx->Eval.Map2Index, enable->Map2Index, GL_MAP2_INDEX); TEST_AND_UPDATE(ctx->Eval.Map2Normal, enable->Map2Normal, GL_MAP2_NORMAL); TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord1, enable->Map2TextureCoord1, GL_MAP2_TEXTURE_COORD_1); TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord2, enable->Map2TextureCoord2, GL_MAP2_TEXTURE_COORD_2); TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord3, enable->Map2TextureCoord3, GL_MAP2_TEXTURE_COORD_3); TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord4, enable->Map2TextureCoord4, GL_MAP2_TEXTURE_COORD_4); TEST_AND_UPDATE(ctx->Eval.Map2Vertex3, enable->Map2Vertex3, GL_MAP2_VERTEX_3); TEST_AND_UPDATE(ctx->Eval.Map2Vertex4, enable->Map2Vertex4, GL_MAP2_VERTEX_4); TEST_AND_UPDATE(ctx->Eval.AutoNormal, enable->AutoNormal, GL_AUTO_NORMAL); TEST_AND_UPDATE(ctx->Transform.Normalize, enable->Normalize, GL_NORMALIZE); TEST_AND_UPDATE(ctx->Transform.RescaleNormals, enable->RescaleNormals, GL_RESCALE_NORMAL_EXT); TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped, enable->RasterPositionUnclipped, GL_RASTER_POSITION_UNCLIPPED_IBM); TEST_AND_UPDATE(ctx->Pixel.PixelTextureEnabled, enable->PixelTexture, GL_POINT_SMOOTH); TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth, GL_POINT_SMOOTH); TEST_AND_UPDATE(ctx->Polygon.OffsetPoint, enable->PolygonOffsetPoint, GL_POLYGON_OFFSET_POINT); TEST_AND_UPDATE(ctx->Polygon.OffsetLine, enable->PolygonOffsetLine, GL_POLYGON_OFFSET_LINE); TEST_AND_UPDATE(ctx->Polygon.OffsetFill, enable->PolygonOffsetFill, GL_POLYGON_OFFSET_FILL); TEST_AND_UPDATE(ctx->Polygon.SmoothFlag, enable->PolygonSmooth, GL_POLYGON_SMOOTH); TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple, GL_POLYGON_STIPPLE); TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST); TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST); TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled, GL_MULTISAMPLE_ARB); TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage, enable->SampleAlphaToCoverage, GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToOne, enable->SampleAlphaToOne, GL_SAMPLE_ALPHA_TO_ONE_ARB); TEST_AND_UPDATE(ctx->Multisample.SampleCoverage, enable->SampleCoverage, GL_SAMPLE_COVERAGE_ARB); TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert, enable->SampleCoverageInvert, GL_SAMPLE_COVERAGE_INVERT_ARB); #undef TEST_AND_UPDATE /* texture unit enables */ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { if (ctx->Texture.Unit[i].Enabled != enable->Texture[i]) { ctx->Texture.Unit[i].Enabled = enable->Texture[i]; if (ctx->Driver.Enable) { if (ctx->Driver.ActiveTexture) { (*ctx->Driver.ActiveTexture)(ctx, i); } (*ctx->Driver.Enable)( ctx, GL_TEXTURE_1D, (GLboolean) (enable->Texture[i] & TEXTURE0_1D) ); (*ctx->Driver.Enable)( ctx, GL_TEXTURE_2D, (GLboolean) (enable->Texture[i] & TEXTURE0_2D) ); (*ctx->Driver.Enable)( ctx, GL_TEXTURE_3D, (GLboolean) (enable->Texture[i] & TEXTURE0_3D) ); if (ctx->Extensions.ARB_texture_cube_map) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_CUBE_MAP_ARB, (GLboolean) (enable->Texture[i] & TEXTURE0_CUBE) ); if (ctx->Extensions.NV_texture_rectangle) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_RECTANGLE_NV, (GLboolean) (enable->Texture[i] & TEXTURE0_RECT) ); } } if (ctx->Texture.Unit[i].TexGenEnabled != enable->TexGen[i]) { ctx->Texture.Unit[i].TexGenEnabled = enable->TexGen[i]; if (ctx->Driver.Enable) { if (ctx->Driver.ActiveTexture) { (*ctx->Driver.ActiveTexture)(ctx, i); } if (enable->TexGen[i] & S_BIT) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_S, GL_TRUE); else (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_S, GL_FALSE); if (enable->TexGen[i] & T_BIT) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_T, GL_TRUE); else (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_T, GL_FALSE); if (enable->TexGen[i] & R_BIT) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_R, GL_TRUE); else (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_R, GL_FALSE); if (enable->TexGen[i] & Q_BIT) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_Q, GL_TRUE); else (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_Q, GL_FALSE); } } } if (ctx->Driver.ActiveTexture) { (*ctx->Driver.ActiveTexture)(ctx, ctx->Texture.CurrentUnit); } }