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); } }
/** * 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); }
/** * 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; }
/* * 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; } }