void brw_meta_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt) { struct gl_context *ctx = &brw->ctx; GLuint fbo; struct gl_renderbuffer *rb; struct rect rect; brw_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(1, &fbo); rb = brw_get_rb_for_slice(brw, mt, 0, 0, false); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, rb); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); brw_fast_clear_init(brw); use_rectlist(brw, true); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); /* SKL+ also has a resolve mode for compressed render targets and thus more * bits to let us select the type of resolve. For fast clear resolves, it * turns out we can use the same value as pre-SKL though. */ if (intel_miptree_is_lossless_compressed(brw, mt)) set_fast_clear_op(brw, GEN9_PS_RENDER_TARGET_RESOLVE_FULL); else set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE); mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED; get_resolve_rect(brw, mt, &rect); brw_draw_rectlist(brw, &rect, 1); set_fast_clear_op(brw, 0); use_rectlist(brw, false); _mesa_reference_renderbuffer(&rb, NULL); _mesa_DeleteFramebuffers(1, &fbo); _mesa_meta_end(ctx); /* We're typically called from intel_update_state() and we're supposed to * return with the state all updated to what it was before * brw_meta_resolve_color() was called. The meta rendering will have * messed up the state and we need to call _mesa_update_state() again to * get back to where we were supposed to be when resolve was called. */ if (ctx->NewState) _mesa_update_state(ctx); }
/** * Implementation of up or downsampling for window-system MSAA miptrees. */ void brw_meta_updownsample(struct brw_context *brw, struct intel_mipmap_tree *src_mt, struct intel_mipmap_tree *dst_mt) { struct gl_context *ctx = &brw->ctx; GLuint fbos[2], src_rbo, dst_rbo, src_fbo, dst_fbo; GLenum drawbuffer; GLbitfield attachment, blit_bit; if (_mesa_get_format_base_format(src_mt->format) == GL_DEPTH_COMPONENT || _mesa_get_format_base_format(src_mt->format) == GL_DEPTH_STENCIL) { attachment = GL_DEPTH_ATTACHMENT; drawbuffer = GL_NONE; blit_bit = GL_DEPTH_BUFFER_BIT; } else { attachment = GL_COLOR_ATTACHMENT0; drawbuffer = GL_COLOR_ATTACHMENT0; blit_bit = GL_COLOR_BUFFER_BIT; } brw_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(2, fbos); src_rbo = brw_get_rb_for_slice(brw, src_mt, 0, 0, false); dst_rbo = brw_get_rb_for_slice(brw, dst_mt, 0, 0, false); src_fbo = fbos[0]; dst_fbo = fbos[1]; _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, src_fbo); _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, src_rbo); _mesa_ReadBuffer(drawbuffer); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fbo); _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, dst_rbo); _mesa_DrawBuffer(drawbuffer); _mesa_BlitFramebuffer(0, 0, src_mt->logical_width0, src_mt->logical_height0, 0, 0, dst_mt->logical_width0, dst_mt->logical_height0, blit_bit, GL_NEAREST); _mesa_DeleteRenderbuffers(1, &src_rbo); _mesa_DeleteRenderbuffers(1, &dst_rbo); _mesa_DeleteFramebuffers(2, fbos); _mesa_meta_end(ctx); brw_emit_mi_flush(brw); }
void brw_meta_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt) { struct gl_context *ctx = &brw->ctx; GLuint fbo, rbo; struct rect rect; intel_batchbuffer_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(1, &fbo); rbo = brw_get_rb_for_slice(brw, mt, 0, 0, false); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); brw_fast_clear_init(brw); use_rectlist(brw, true); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE); mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED; get_resolve_rect(brw, mt, &rect); brw_draw_rectlist(ctx, &rect, 1); set_fast_clear_op(brw, 0); use_rectlist(brw, false); _mesa_DeleteRenderbuffers(1, &rbo); _mesa_DeleteFramebuffers(1, &fbo); _mesa_meta_end(ctx); /* We're typically called from intel_update_state() and we're supposed to * return with the state all updated to what it was before * brw_meta_resolve_color() was called. The meta rendering will have * messed up the state and we need to call _mesa_update_state() again to * get back to where we were supposed to be when resolve was called. */ if (ctx->NewState) _mesa_update_state(ctx); }
/** A partial implementation of glCopyImageSubData * * This is a partial implementation of glCopyImageSubData that works only * if both textures are uncompressed and the destination texture is * renderable. It uses a slight abuse of a texture view (see make_view) to * turn the source texture into the destination texture type and then uses * _mesa_meta_BlitFramebuffers to do the copy. */ bool _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, struct gl_texture_image *src_tex_image, struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { mesa_format src_format, dst_format; GLint src_internal_format, dst_internal_format; GLuint src_view_texture = 0; struct gl_texture_image *src_view_tex_image; struct gl_framebuffer *readFb; struct gl_framebuffer *drawFb = NULL; bool success = false; GLbitfield mask; GLenum status, attachment; if (src_renderbuffer) { src_format = src_renderbuffer->Format; src_internal_format = src_renderbuffer->InternalFormat; } else { assert(src_tex_image); src_format = src_tex_image->TexFormat; src_internal_format = src_tex_image->InternalFormat; } if (dst_renderbuffer) { dst_format = dst_renderbuffer->Format; dst_internal_format = dst_renderbuffer->InternalFormat; } else { assert(dst_tex_image); dst_format = dst_tex_image->TexFormat; dst_internal_format = dst_tex_image->InternalFormat; } if (_mesa_is_format_compressed(src_format)) return false; if (_mesa_is_format_compressed(dst_format)) return false; if (src_internal_format == dst_internal_format) { src_view_tex_image = src_tex_image; } else { if (src_renderbuffer) { assert(src_tex_image == NULL); src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer); } if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture, dst_internal_format)) goto cleanup; } /* We really only need to stash the bound framebuffers and scissor. */ _mesa_meta_begin(ctx, MESA_META_SCISSOR); readFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (readFb == NULL) goto meta_end; drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (drawFb == NULL) goto meta_end; _mesa_bind_framebuffers(ctx, drawFb, readFb); switch (_mesa_get_format_base_format(src_format)) { case GL_DEPTH_COMPONENT: attachment = GL_DEPTH_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT; break; case GL_DEPTH_STENCIL: attachment = GL_DEPTH_STENCIL_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; break; case GL_STENCIL_INDEX: attachment = GL_STENCIL_ATTACHMENT; mask = GL_STENCIL_BUFFER_BIT; break; default: attachment = GL_COLOR_ATTACHMENT0; mask = GL_COLOR_BUFFER_BIT; _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0); } if (src_view_tex_image) { /* Prefer the tex image because, even if we have a renderbuffer, we may * have had to wrap it in a texture view. */ _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, attachment, src_view_tex_image, src_z); } else { _mesa_framebuffer_renderbuffer(ctx, ctx->ReadBuffer, attachment, src_renderbuffer); } status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; if (dst_renderbuffer) { _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, attachment, dst_renderbuffer); } else { _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, attachment, dst_tex_image, dst_z); } status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; /* Explicitly disable sRGB encoding */ ctx->DrawBuffer->Visual.sRGBCapable = false; /* Since we've bound a new draw framebuffer, we need to update its * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to * be correct. */ _mesa_update_state(ctx); /* We skip the core BlitFramebuffer checks for format consistency. * We have already created views to ensure that the texture formats * match. */ ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, src_x, src_y, src_x + src_width, src_y + src_height, dst_x, dst_y, dst_x + src_width, dst_y + src_height, mask, GL_NEAREST); success = true; meta_end: _mesa_reference_framebuffer(&readFb, NULL); _mesa_reference_framebuffer(&drawFb, NULL); _mesa_meta_end(ctx); cleanup: _mesa_DeleteTextures(1, &src_view_texture); /* If we got a renderbuffer source, delete the temporary texture */ if (src_renderbuffer && src_tex_image) ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject); return success; }
/** * 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) _mesa_BindTexture(target, texObj->Name); if (!mipmap->Sampler) { _mesa_GenSamplers(1, &mipmap->Sampler); _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _mesa_SamplerParameteri(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) { _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); } } else { _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); } assert(mipmap->FBO != 0); _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); _mesa_TexParameteri(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; _mesa_TexParameteriv(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; 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_TexParameteri(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 */ _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); /* 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, 1, /* width, height never used here */ verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, GL_DYNAMIC_DRAW_ARB); _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (_mesa_CheckFramebufferStatus(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); } _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } } _mesa_lock_texture(ctx, texObj); /* relock */ _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); _mesa_meta_end(ctx); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); if (genMipmapSave) _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); if (swizzleSaved) _mesa_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); }
/** A partial implementation of glCopyImageSubData * * This is a partial implementation of glCopyImageSubData that works only * if both textures are uncompressed and the destination texture is * renderable. It uses a slight abuse of a texture view (see make_view) to * turn the source texture into the destination texture type and then uses * _mesa_meta_BlitFramebuffers to do the copy. */ bool _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, struct gl_texture_image *src_tex_image, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { GLuint src_view_texture = 0; struct gl_texture_image *src_view_tex_image; GLuint fbos[2]; bool success = false; GLbitfield mask; GLenum status, attachment; if (_mesa_is_format_compressed(dst_tex_image->TexFormat)) return false; if (_mesa_is_format_compressed(src_tex_image->TexFormat)) return false; if (src_tex_image->InternalFormat == dst_tex_image->InternalFormat) { src_view_tex_image = src_tex_image; } else { if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture, dst_tex_image->InternalFormat)) goto cleanup; } /* We really only need to stash the bound framebuffers. */ _mesa_meta_begin(ctx, 0); _mesa_GenFramebuffers(2, fbos); _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); switch (_mesa_get_format_base_format(src_tex_image->TexFormat)) { case GL_DEPTH_COMPONENT: attachment = GL_DEPTH_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT; break; case GL_DEPTH_STENCIL: attachment = GL_DEPTH_STENCIL_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; break; case GL_STENCIL_INDEX: attachment = GL_STENCIL_ATTACHMENT; mask = GL_STENCIL_BUFFER_BIT; break; default: attachment = GL_COLOR_ATTACHMENT0; mask = GL_COLOR_BUFFER_BIT; _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0); } _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment, src_view_tex_image, src_z); status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment, dst_tex_image, dst_z); status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; /* Since we've bound a new draw framebuffer, we need to update its * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to * be correct. */ _mesa_update_state(ctx); /* We skip the core BlitFramebuffer checks for format consistency. * We have already created views to ensure that the texture formats * match. */ ctx->Driver.BlitFramebuffer(ctx, src_x, src_y, src_x + src_width, src_y + src_height, dst_x, dst_y, dst_x + src_width, dst_y + src_height, mask, GL_NEAREST); success = true; meta_end: _mesa_DeleteFramebuffers(2, fbos); _mesa_meta_end(ctx); cleanup: _mesa_DeleteTextures(1, &src_view_texture); return success; }
/** * 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); }
/** * Perform glClear where mask contains only color, depth, and/or stencil. * * The implementation is based on calling into Mesa to set GL state and * performing normal triangle rendering. The intent of this path is to * have as generic a path as possible, so that any driver could make use of * it. */ void intel_clear_tris(GLcontext *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); GLfloat dst_z; struct gl_framebuffer *fb = ctx->DrawBuffer; int i; GLboolean saved_fp_enable = GL_FALSE, saved_vp_enable = GL_FALSE; GLuint saved_shader_program = 0; unsigned int saved_active_texture; struct gl_array_object *arraySave = NULL; if (!intel->clear.arrayObj) init_clear(ctx); assert((mask & ~(TRI_CLEAR_COLOR_BITS | BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) == 0); _mesa_PushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT); saved_active_texture = ctx->Texture.CurrentUnit; /* Disable existing GL state we don't want to apply to a clear. */ _mesa_Disable(GL_ALPHA_TEST); _mesa_Disable(GL_BLEND); _mesa_Disable(GL_CULL_FACE); _mesa_Disable(GL_FOG); _mesa_Disable(GL_POLYGON_SMOOTH); _mesa_Disable(GL_POLYGON_STIPPLE); _mesa_Disable(GL_POLYGON_OFFSET_FILL); _mesa_Disable(GL_LIGHTING); _mesa_Disable(GL_CLIP_PLANE0); _mesa_Disable(GL_CLIP_PLANE1); _mesa_Disable(GL_CLIP_PLANE2); _mesa_Disable(GL_CLIP_PLANE3); _mesa_Disable(GL_CLIP_PLANE4); _mesa_Disable(GL_CLIP_PLANE5); _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (ctx->Extensions.ARB_fragment_program && ctx->FragmentProgram.Enabled) { saved_fp_enable = GL_TRUE; _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB); } if (ctx->Extensions.ARB_vertex_program && ctx->VertexProgram.Enabled) { saved_vp_enable = GL_TRUE; _mesa_Disable(GL_VERTEX_PROGRAM_ARB); } if (ctx->Extensions.ARB_shader_objects && ctx->Shader.CurrentProgram) { saved_shader_program = ctx->Shader.CurrentProgram->Name; _mesa_UseProgramObjectARB(0); } if (ctx->Texture._EnabledUnits != 0) { int i; for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { _mesa_ActiveTextureARB(GL_TEXTURE0 + i); _mesa_Disable(GL_TEXTURE_1D); _mesa_Disable(GL_TEXTURE_2D); _mesa_Disable(GL_TEXTURE_3D); if (ctx->Extensions.ARB_texture_cube_map) _mesa_Disable(GL_TEXTURE_CUBE_MAP_ARB); if (ctx->Extensions.NV_texture_rectangle) _mesa_Disable(GL_TEXTURE_RECTANGLE_NV); if (ctx->Extensions.MESA_texture_array) { _mesa_Disable(GL_TEXTURE_1D_ARRAY_EXT); _mesa_Disable(GL_TEXTURE_2D_ARRAY_EXT); } } } /* save current array object, bind our private one */ _mesa_reference_array_object(ctx, &arraySave, ctx->Array.ArrayObj); _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, intel->clear.arrayObj); intel_meta_set_passthrough_transform(intel); for (i = 0; i < 4; i++) { COPY_4FV(intel->clear.color[i], ctx->Color.ClearColor); } /* convert clear Z from [0,1] to NDC coord in [-1,1] */ dst_z = -1.0 + 2.0 * ctx->Depth.Clear; /* Prepare the vertices, which are the same regardless of which buffer we're * drawing to. */ intel->clear.vertices[0][0] = fb->_Xmin; intel->clear.vertices[0][1] = fb->_Ymin; intel->clear.vertices[0][2] = dst_z; intel->clear.vertices[1][0] = fb->_Xmax; intel->clear.vertices[1][1] = fb->_Ymin; intel->clear.vertices[1][2] = dst_z; intel->clear.vertices[2][0] = fb->_Xmax; intel->clear.vertices[2][1] = fb->_Ymax; intel->clear.vertices[2][2] = dst_z; intel->clear.vertices[3][0] = fb->_Xmin; intel->clear.vertices[3][1] = fb->_Ymax; intel->clear.vertices[3][2] = dst_z; while (mask != 0) { GLuint this_mask = 0; GLuint color_bit; color_bit = _mesa_ffs(mask & TRI_CLEAR_COLOR_BITS); if (color_bit != 0) this_mask |= (1 << (color_bit - 1)); /* Clear depth/stencil in the same pass as color. */ this_mask |= (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)); /* Select the current color buffer and use the color write mask if * we have one, otherwise don't write any color channels. */ if (this_mask & BUFFER_BIT_FRONT_LEFT) _mesa_DrawBuffer(GL_FRONT_LEFT); else if (this_mask & BUFFER_BIT_BACK_LEFT) _mesa_DrawBuffer(GL_BACK_LEFT); else if (color_bit != 0) _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0 + (color_bit - BUFFER_COLOR0 - 1)); else _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* Control writing of the depth clear value to depth. */ if (this_mask & BUFFER_BIT_DEPTH) { _mesa_DepthFunc(GL_ALWAYS); _mesa_Enable(GL_DEPTH_TEST); } else { _mesa_Disable(GL_DEPTH_TEST); _mesa_DepthMask(GL_FALSE); } /* Control writing of the stencil clear value to stencil. */ if (this_mask & BUFFER_BIT_STENCIL) { _mesa_Enable(GL_STENCIL_TEST); _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, GL_REPLACE, GL_REPLACE, GL_REPLACE); _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, ctx->Stencil.Clear, ctx->Stencil.WriteMask[0]); } else { _mesa_Disable(GL_STENCIL_TEST); } _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); mask &= ~this_mask; } intel_meta_restore_transform(intel); _mesa_ActiveTextureARB(GL_TEXTURE0 + saved_active_texture); if (saved_fp_enable) _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB); if (saved_vp_enable) _mesa_Enable(GL_VERTEX_PROGRAM_ARB); if (saved_shader_program) _mesa_UseProgramObjectARB(saved_shader_program); _mesa_PopAttrib(); /* restore current array object */ _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, arraySave); _mesa_reference_array_object(ctx, &arraySave, NULL); }
/* * 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; } }