예제 #1
0
static void si_clear(struct pipe_context *ctx, unsigned buffers,
		     const union pipe_color_union *color,
		     double depth, unsigned stencil)
{
	struct si_context *sctx = (struct si_context *)ctx;
	struct pipe_framebuffer_state *fb = &sctx->framebuffer.state;

	if (buffers & PIPE_CLEAR_COLOR) {
		evergreen_do_fast_color_clear(&sctx->b, fb, &sctx->framebuffer.atom,
					      &buffers, color);
	}

	if (buffers & PIPE_CLEAR_COLOR) {
		int i;

		/* These buffers cannot use fast clear, make sure to disable expansion. */
		for (i = 0; i < fb->nr_cbufs; i++) {
			struct r600_texture *tex;

			/* If not clearing this buffer, skip. */
			if (!(buffers & (PIPE_CLEAR_COLOR0 << i)))
				continue;

			if (!fb->cbufs[i])
				continue;

			tex = (struct r600_texture *)fb->cbufs[i]->texture;
			if (tex->fmask.size == 0)
				tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level);
		}
	}

	si_blitter_begin(ctx, SI_CLEAR);
	util_blitter_clear(sctx->blitter, fb->width, fb->height,
			   util_framebuffer_get_num_layers(fb),
			   buffers, color, depth, stencil);
	si_blitter_end(ctx);
}
예제 #2
0
파일: r600_blit.c 프로젝트: iquiw/xsrc
static void r600_clear(struct pipe_context *ctx, unsigned buffers,
		       const union pipe_color_union *color,
		       double depth, unsigned stencil)
{
	struct r600_context *rctx = (struct r600_context *)ctx;
	struct pipe_framebuffer_state *fb = &rctx->framebuffer.state;

	if (buffers & PIPE_CLEAR_COLOR && rctx->b.chip_class >= EVERGREEN) {
		evergreen_do_fast_color_clear(&rctx->b, fb, &rctx->framebuffer.atom,
					      &buffers, color);
	}

	if (buffers & PIPE_CLEAR_COLOR) {
		int i;

		/* These buffers cannot use fast clear, make sure to disable expansion. */
		for (i = 0; i < fb->nr_cbufs; i++) {
			struct r600_texture *tex;

			/* If not clearing this buffer, skip. */
			if (!(buffers & (PIPE_CLEAR_COLOR0 << i)))
				continue;

			if (!fb->cbufs[i])
				continue;

			tex = (struct r600_texture *)fb->cbufs[i]->texture;
			if (tex->fmask.size == 0)
				tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level);
		}
	}

	/* if hyperz enabled just clear hyperz */
	if (fb->zsbuf && (buffers & PIPE_CLEAR_DEPTH)) {
		struct r600_texture *rtex;
		unsigned level = fb->zsbuf->u.tex.level;

		rtex = (struct r600_texture*)fb->zsbuf->texture;

		/* We can't use hyperz fast clear if each slice of a texture
		 * array are clear to different value. To simplify code just
		 * disable fast clear for texture array.
		 */
		/* Only use htile for first level */
		if (rtex->htile_buffer && !level &&
		    util_max_layer(&rtex->resource.b.b, level) == 0) {
			if (rtex->depth_clear_value != depth) {
				rtex->depth_clear_value = depth;
				rctx->db_state.atom.dirty = true;
			}
			rctx->db_misc_state.htile_clear = true;
			rctx->db_misc_state.atom.dirty = true;
		}
	}

	r600_blitter_begin(ctx, R600_CLEAR);
	util_blitter_clear(rctx->blitter, fb->width, fb->height,
			   util_framebuffer_get_num_layers(fb),
			   buffers, color, depth, stencil);
	r600_blitter_end(ctx);

	/* disable fast clear */
	if (rctx->db_misc_state.htile_clear) {
		rctx->db_misc_state.htile_clear = false;
		rctx->db_misc_state.atom.dirty = true;
	}
}
예제 #3
0
/**
 * Do glClear by drawing a quadrilateral.
 * The vertices of the quad will be computed from the
 * ctx->DrawBuffer->_X/Ymin/max fields.
 */
static void
clear_with_quad(struct gl_context *ctx, unsigned clear_buffers)
{
   struct st_context *st = st_context(ctx);
   const struct gl_framebuffer *fb = ctx->DrawBuffer;
   const GLfloat fb_width = (GLfloat) fb->Width;
   const GLfloat fb_height = (GLfloat) fb->Height;
   const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
   const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
   const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
   const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
   unsigned num_layers =
      util_framebuffer_get_num_layers(&st->state.framebuffer);

   /*
   printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, 
	  color ? "color, " : "",
	  depth ? "depth, " : "",
	  stencil ? "stencil" : "",
	  x0, y0,
	  x1, y1);
   */

   cso_save_blend(st->cso_context);
   cso_save_stencil_ref(st->cso_context);
   cso_save_depth_stencil_alpha(st->cso_context);
   cso_save_rasterizer(st->cso_context);
   cso_save_sample_mask(st->cso_context);
   cso_save_viewport(st->cso_context);
   cso_save_fragment_shader(st->cso_context);
   cso_save_stream_outputs(st->cso_context);
   cso_save_vertex_shader(st->cso_context);
   cso_save_geometry_shader(st->cso_context);
   cso_save_vertex_elements(st->cso_context);
   cso_save_aux_vertex_buffer_slot(st->cso_context);

   /* blend state: RGBA masking */
   {
      struct pipe_blend_state blend;
      memset(&blend, 0, sizeof(blend));
      if (clear_buffers & PIPE_CLEAR_COLOR) {
         int num_buffers = ctx->Extensions.EXT_draw_buffers2 ?
                           ctx->DrawBuffer->_NumColorDrawBuffers : 1;
         int i;

         blend.independent_blend_enable = num_buffers > 1;

         for (i = 0; i < num_buffers; i++) {
            if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
               continue;

            if (ctx->Color.ColorMask[i][0])
               blend.rt[i].colormask |= PIPE_MASK_R;
            if (ctx->Color.ColorMask[i][1])
               blend.rt[i].colormask |= PIPE_MASK_G;
            if (ctx->Color.ColorMask[i][2])
               blend.rt[i].colormask |= PIPE_MASK_B;
            if (ctx->Color.ColorMask[i][3])
               blend.rt[i].colormask |= PIPE_MASK_A;
         }

         if (st->ctx->Color.DitherFlag)
            blend.dither = 1;
      }
      cso_set_blend(st->cso_context, &blend);
   }

   /* depth_stencil state: always pass/set to ref value */
   {
      struct pipe_depth_stencil_alpha_state depth_stencil;
      memset(&depth_stencil, 0, sizeof(depth_stencil));
      if (clear_buffers & PIPE_CLEAR_DEPTH) {
         depth_stencil.depth.enabled = 1;
         depth_stencil.depth.writemask = 1;
         depth_stencil.depth.func = PIPE_FUNC_ALWAYS;
      }

      if (clear_buffers & PIPE_CLEAR_STENCIL) {
         struct pipe_stencil_ref stencil_ref;
         memset(&stencil_ref, 0, sizeof(stencil_ref));
         depth_stencil.stencil[0].enabled = 1;
         depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
         depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].valuemask = 0xff;
         depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
         stencil_ref.ref_value[0] = ctx->Stencil.Clear;
         cso_set_stencil_ref(st->cso_context, &stencil_ref);
      }

      cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil);
   }

   cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw);
   cso_set_stream_outputs(st->cso_context, 0, NULL, NULL);
   cso_set_sample_mask(st->cso_context, ~0);
   cso_set_rasterizer(st->cso_context, &st->clear.raster);

   /* viewport state: viewport matching window dims */
   {
      const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
      struct pipe_viewport_state vp;
      vp.scale[0] = 0.5f * fb_width;
      vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f);
      vp.scale[2] = 1.0f;
      vp.scale[3] = 1.0f;
      vp.translate[0] = 0.5f * fb_width;
      vp.translate[1] = 0.5f * fb_height;
      vp.translate[2] = 0.0f;
      vp.translate[3] = 0.0f;
      cso_set_viewport(st->cso_context, &vp);
   }

   set_fragment_shader(st);
   cso_set_geometry_shader_handle(st->cso_context, NULL);

   if (num_layers > 1)
      set_vertex_shader_layered(st);
   else
      set_vertex_shader(st);

   /* We can't translate the clear color to the colorbuffer format,
    * because different colorbuffers may have different formats.
    */

   /* draw quad matching scissor rect */
   draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, num_layers,
             (union pipe_color_union*)&ctx->Color.ClearColor);

   /* Restore pipe state */
   cso_restore_blend(st->cso_context);
   cso_restore_stencil_ref(st->cso_context);
   cso_restore_depth_stencil_alpha(st->cso_context);
   cso_restore_rasterizer(st->cso_context);
   cso_restore_sample_mask(st->cso_context);
   cso_restore_viewport(st->cso_context);
   cso_restore_fragment_shader(st->cso_context);
   cso_restore_vertex_shader(st->cso_context);
   cso_restore_geometry_shader(st->cso_context);
   cso_restore_vertex_elements(st->cso_context);
   cso_restore_aux_vertex_buffer_slot(st->cso_context);
   cso_restore_stream_outputs(st->cso_context);
}
예제 #4
0
/**
 * Update framebuffer state (color, depth, stencil, etc. buffers)
 */
void
st_update_framebuffer_state( struct st_context *st )
{
   struct pipe_framebuffer_state framebuffer;
   struct gl_framebuffer *fb = st->ctx->DrawBuffer;
   struct st_renderbuffer *strb;
   GLuint i;

   st_flush_bitmap_cache(st);
   st_invalidate_readpix_cache(st);

   st->state.fb_orientation = st_fb_orientation(fb);

   /**
    * Quantize the derived default number of samples:
    *
    * A query to the driver of supported MSAA values the
    * hardware supports is done as to legalize the number
    * of application requested samples, NumSamples.
    * See commit eb9cf3c for more information.
    */
   fb->DefaultGeometry._NumSamples =
      framebuffer_quantize_num_samples(st, fb->DefaultGeometry.NumSamples);

   framebuffer.width  = _mesa_geometric_width(fb);
   framebuffer.height = _mesa_geometric_height(fb);
   framebuffer.samples = _mesa_geometric_samples(fb);
   framebuffer.layers = _mesa_geometric_layers(fb);

   /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
    * to determine which surfaces to draw to
    */
   framebuffer.nr_cbufs = fb->_NumColorDrawBuffers;

   for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
      framebuffer.cbufs[i] = NULL;
      strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);

      if (strb) {
         if (strb->is_rtt || (strb->texture &&
             _mesa_get_format_color_encoding(strb->Base.Format) == GL_SRGB)) {
            /* rendering to a GL texture, may have to update surface */
            st_update_renderbuffer_surface(st, strb);
         }

         if (strb->surface) {
            framebuffer.cbufs[i] = strb->surface;
            update_framebuffer_size(&framebuffer, strb->surface);
         }
         strb->defined = GL_TRUE; /* we'll be drawing something */
      }
   }

   for (i = framebuffer.nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
      framebuffer.cbufs[i] = NULL;
   }

   /* Remove trailing GL_NONE draw buffers. */
   while (framebuffer.nr_cbufs &&
          !framebuffer.cbufs[framebuffer.nr_cbufs-1]) {
      framebuffer.nr_cbufs--;
   }

   /*
    * Depth/Stencil renderbuffer/surface.
    */
   strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
   if (!strb)
      strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);

   if (strb) {
      if (strb->is_rtt) {
         /* rendering to a GL texture, may have to update surface */
         st_update_renderbuffer_surface(st, strb);
      }
      framebuffer.zsbuf = strb->surface;
      update_framebuffer_size(&framebuffer, strb->surface);
   }
   else
      framebuffer.zsbuf = NULL;

#ifdef DEBUG
   /* Make sure the resource binding flags were set properly */
   for (i = 0; i < framebuffer.nr_cbufs; i++) {
      assert(!framebuffer.cbufs[i] ||
             framebuffer.cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
   }
   if (framebuffer.zsbuf) {
      assert(framebuffer.zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
   }
#endif

   if (framebuffer.width == USHRT_MAX)
      framebuffer.width = 0;
   if (framebuffer.height == USHRT_MAX)
      framebuffer.height = 0;

   cso_set_framebuffer(st->cso_context, &framebuffer);

   st->state.fb_width = framebuffer.width;
   st->state.fb_height = framebuffer.height;
   st->state.fb_num_samples = util_framebuffer_get_num_samples(&framebuffer);
   st->state.fb_num_layers = util_framebuffer_get_num_layers(&framebuffer);
   st->state.fb_num_cb = framebuffer.nr_cbufs;
}
예제 #5
0
파일: si_blit.c 프로젝트: ifzz/mesa
static void si_clear(struct pipe_context *ctx, unsigned buffers,
		     const union pipe_color_union *color,
		     double depth, unsigned stencil)
{
	struct si_context *sctx = (struct si_context *)ctx;
	struct pipe_framebuffer_state *fb = &sctx->framebuffer.state;
	struct pipe_surface *zsbuf = fb->zsbuf;
	struct r600_texture *zstex =
		zsbuf ? (struct r600_texture*)zsbuf->texture : NULL;

	if (buffers & PIPE_CLEAR_COLOR) {
		evergreen_do_fast_color_clear(&sctx->b, fb,
					      &sctx->framebuffer.atom, &buffers,
					      &sctx->framebuffer.dirty_cbufs,
					      color);
		if (!buffers)
			return; /* all buffers have been fast cleared */
	}

	if (buffers & PIPE_CLEAR_COLOR) {
		int i;

		/* These buffers cannot use fast clear, make sure to disable expansion. */
		for (i = 0; i < fb->nr_cbufs; i++) {
			struct r600_texture *tex;

			/* If not clearing this buffer, skip. */
			if (!(buffers & (PIPE_CLEAR_COLOR0 << i)))
				continue;

			if (!fb->cbufs[i])
				continue;

			tex = (struct r600_texture *)fb->cbufs[i]->texture;
			if (tex->fmask.size == 0)
				tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level);
		}
	}

	if (zstex && zstex->htile_buffer &&
	    zsbuf->u.tex.level == 0 &&
	    zsbuf->u.tex.first_layer == 0 &&
	    zsbuf->u.tex.last_layer == util_max_layer(&zstex->resource.b.b, 0)) {
		if (buffers & PIPE_CLEAR_DEPTH) {
			/* Need to disable EXPCLEAR temporarily if clearing
			 * to a new value. */
			if (!zstex->depth_cleared || zstex->depth_clear_value != depth) {
				sctx->db_depth_disable_expclear = true;
			}

			zstex->depth_clear_value = depth;
			sctx->framebuffer.dirty_zsbuf = true;
			si_mark_atom_dirty(sctx, &sctx->framebuffer.atom); /* updates DB_DEPTH_CLEAR */
			sctx->db_depth_clear = true;
			si_mark_atom_dirty(sctx, &sctx->db_render_state);
		}

		if (buffers & PIPE_CLEAR_STENCIL) {
			stencil &= 0xff;

			/* Need to disable EXPCLEAR temporarily if clearing
			 * to a new value. */
			if (!zstex->stencil_cleared || zstex->stencil_clear_value != stencil) {
				sctx->db_stencil_disable_expclear = true;
			}

			zstex->stencil_clear_value = stencil;
			sctx->framebuffer.dirty_zsbuf = true;
			si_mark_atom_dirty(sctx, &sctx->framebuffer.atom); /* updates DB_STENCIL_CLEAR */
			sctx->db_stencil_clear = true;
			si_mark_atom_dirty(sctx, &sctx->db_render_state);
		}
	}

	si_blitter_begin(ctx, SI_CLEAR);
	util_blitter_clear(sctx->blitter, fb->width, fb->height,
			   util_framebuffer_get_num_layers(fb),
			   buffers, color, depth, stencil);
	si_blitter_end(ctx);

	if (sctx->db_depth_clear) {
		sctx->db_depth_clear = false;
		sctx->db_depth_disable_expclear = false;
		zstex->depth_cleared = true;
		si_mark_atom_dirty(sctx, &sctx->db_render_state);
	}

	if (sctx->db_stencil_clear) {
		sctx->db_stencil_clear = false;
		sctx->db_stencil_disable_expclear = false;
		zstex->stencil_cleared = true;
		si_mark_atom_dirty(sctx, &sctx->db_render_state);
	}
}
예제 #6
0
/**
 * Do glClear by drawing a quadrilateral.
 * The vertices of the quad will be computed from the
 * ctx->DrawBuffer->_X/Ymin/max fields.
 */
static void
clear_with_quad(struct gl_context *ctx, unsigned clear_buffers)
{
   struct st_context *st = st_context(ctx);
   struct cso_context *cso = st->cso_context;
   const struct gl_framebuffer *fb = ctx->DrawBuffer;
   const GLfloat fb_width = (GLfloat) fb->Width;
   const GLfloat fb_height = (GLfloat) fb->Height;
   const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
   const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
   const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
   const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
   unsigned num_layers =
      util_framebuffer_get_num_layers(&st->state.framebuffer);

   /*
   printf("%s %s%s%s %f,%f %f,%f\n", __func__,
	  color ? "color, " : "",
	  depth ? "depth, " : "",
	  stencil ? "stencil" : "",
	  x0, y0,
	  x1, y1);
   */

   cso_save_state(cso, (CSO_BIT_BLEND |
                        CSO_BIT_STENCIL_REF |
                        CSO_BIT_DEPTH_STENCIL_ALPHA |
                        CSO_BIT_RASTERIZER |
                        CSO_BIT_SAMPLE_MASK |
                        CSO_BIT_MIN_SAMPLES |
                        CSO_BIT_VIEWPORT |
                        CSO_BIT_STREAM_OUTPUTS |
                        CSO_BIT_VERTEX_ELEMENTS |
                        CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
                        CSO_BIT_PAUSE_QUERIES |
                        CSO_BITS_ALL_SHADERS));

   /* blend state: RGBA masking */
   {
      struct pipe_blend_state blend;
      memset(&blend, 0, sizeof(blend));
      if (clear_buffers & PIPE_CLEAR_COLOR) {
         int num_buffers = ctx->Extensions.EXT_draw_buffers2 ?
                           ctx->DrawBuffer->_NumColorDrawBuffers : 1;
         int i;

         blend.independent_blend_enable = num_buffers > 1;

         for (i = 0; i < num_buffers; i++) {
            if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
               continue;

            if (ctx->Color.ColorMask[i][0])
               blend.rt[i].colormask |= PIPE_MASK_R;
            if (ctx->Color.ColorMask[i][1])
               blend.rt[i].colormask |= PIPE_MASK_G;
            if (ctx->Color.ColorMask[i][2])
               blend.rt[i].colormask |= PIPE_MASK_B;
            if (ctx->Color.ColorMask[i][3])
               blend.rt[i].colormask |= PIPE_MASK_A;
         }

         if (ctx->Color.DitherFlag)
            blend.dither = 1;
      }
      cso_set_blend(cso, &blend);
   }

   /* depth_stencil state: always pass/set to ref value */
   {
      struct pipe_depth_stencil_alpha_state depth_stencil;
      memset(&depth_stencil, 0, sizeof(depth_stencil));
      if (clear_buffers & PIPE_CLEAR_DEPTH) {
         depth_stencil.depth.enabled = 1;
         depth_stencil.depth.writemask = 1;
         depth_stencil.depth.func = PIPE_FUNC_ALWAYS;
      }

      if (clear_buffers & PIPE_CLEAR_STENCIL) {
         struct pipe_stencil_ref stencil_ref;
         memset(&stencil_ref, 0, sizeof(stencil_ref));
         depth_stencil.stencil[0].enabled = 1;
         depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
         depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
         depth_stencil.stencil[0].valuemask = 0xff;
         depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
         stencil_ref.ref_value[0] = ctx->Stencil.Clear;
         cso_set_stencil_ref(cso, &stencil_ref);
      }

      cso_set_depth_stencil_alpha(cso, &depth_stencil);
   }

   cso_set_vertex_elements(cso, 2, st->util_velems);
   cso_set_stream_outputs(cso, 0, NULL, NULL);
   cso_set_sample_mask(cso, ~0);
   cso_set_min_samples(cso, 1);
   cso_set_rasterizer(cso, &st->clear.raster);

   /* viewport state: viewport matching window dims */
   cso_set_viewport_dims(st->cso_context, fb_width, fb_height,
                         st_fb_orientation(fb) == Y_0_TOP);

   set_fragment_shader(st);
   cso_set_tessctrl_shader_handle(cso, NULL);
   cso_set_tesseval_shader_handle(cso, NULL);

   if (num_layers > 1)
      set_vertex_shader_layered(st);
   else
      set_vertex_shader(st);

   /* draw quad matching scissor rect.
    *
    * Note: if we're only clearing depth/stencil we still setup vertices
    * with color, but they'll be ignored.
    *
    * We can't translate the clear color to the colorbuffer format,
    * because different colorbuffers may have different formats.
    */
   if (!st_draw_quad(st, x0, y0, x1, y1,
                     ctx->Depth.Clear * 2.0f - 1.0f,
                     0.0f, 0.0f, 0.0f, 0.0f,
                     (const float *) &ctx->Color.ClearColor.f,
                     num_layers)) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear");
   }

   /* Restore pipe state */
   cso_restore_state(cso);
}
예제 #7
0
파일: si_clear.c 프로젝트: bminor/mesa-mesa
static void si_clear(struct pipe_context *ctx, unsigned buffers,
		     const union pipe_color_union *color,
		     double depth, unsigned stencil)
{
	struct si_context *sctx = (struct si_context *)ctx;
	struct pipe_framebuffer_state *fb = &sctx->framebuffer.state;
	struct pipe_surface *zsbuf = fb->zsbuf;
	struct si_texture *zstex =
		zsbuf ? (struct si_texture*)zsbuf->texture : NULL;

	if (buffers & PIPE_CLEAR_COLOR) {
		si_do_fast_color_clear(sctx, &buffers, color);
		if (!buffers)
			return; /* all buffers have been fast cleared */

		/* These buffers cannot use fast clear, make sure to disable expansion. */
		for (unsigned i = 0; i < fb->nr_cbufs; i++) {
			struct si_texture *tex;

			/* If not clearing this buffer, skip. */
			if (!(buffers & (PIPE_CLEAR_COLOR0 << i)) || !fb->cbufs[i])
				continue;

			tex = (struct si_texture *)fb->cbufs[i]->texture;
			if (tex->surface.fmask_size == 0)
				tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level);
		}
	}

	if (zstex &&
	    si_htile_enabled(zstex, zsbuf->u.tex.level) &&
	    zsbuf->u.tex.first_layer == 0 &&
	    zsbuf->u.tex.last_layer == util_max_layer(&zstex->buffer.b.b, 0)) {
		/* TC-compatible HTILE only supports depth clears to 0 or 1. */
		if (buffers & PIPE_CLEAR_DEPTH &&
		    (!zstex->tc_compatible_htile ||
		     depth == 0 || depth == 1)) {
			/* Need to disable EXPCLEAR temporarily if clearing
			 * to a new value. */
			if (!zstex->depth_cleared || zstex->depth_clear_value != depth) {
				sctx->db_depth_disable_expclear = true;
			}

			if (zstex->depth_clear_value != (float)depth) {
				/* Update DB_DEPTH_CLEAR. */
				zstex->depth_clear_value = depth;
				sctx->framebuffer.dirty_zsbuf = true;
				si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
			}
			sctx->db_depth_clear = true;
			si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
		}

		/* TC-compatible HTILE only supports stencil clears to 0. */
		if (buffers & PIPE_CLEAR_STENCIL &&
		    (!zstex->tc_compatible_htile || stencil == 0)) {
			stencil &= 0xff;

			/* Need to disable EXPCLEAR temporarily if clearing
			 * to a new value. */
			if (!zstex->stencil_cleared || zstex->stencil_clear_value != stencil) {
				sctx->db_stencil_disable_expclear = true;
			}

			if (zstex->stencil_clear_value != (uint8_t)stencil) {
				/* Update DB_STENCIL_CLEAR. */
				zstex->stencil_clear_value = stencil;
				sctx->framebuffer.dirty_zsbuf = true;
				si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
			}
			sctx->db_stencil_clear = true;
			si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
		}

		/* TODO: Find out what's wrong here. Fast depth clear leads to
		 * corruption in ARK: Survival Evolved, but that may just be
		 * a coincidence and the root cause is elsewhere.
		 *
		 * The corruption can be fixed by putting the DB flush before
		 * or after the depth clear. (surprisingly)
		 *
		 * https://bugs.freedesktop.org/show_bug.cgi?id=102955 (apitrace)
		 *
		 * This hack decreases back-to-back ClearDepth performance.
		 */
		if ((sctx->db_depth_clear || sctx->db_stencil_clear) &&
		    sctx->screen->options.clear_db_cache_before_clear)
			sctx->flags |= SI_CONTEXT_FLUSH_AND_INV_DB;
	}

	si_blitter_begin(sctx, SI_CLEAR);
	util_blitter_clear(sctx->blitter, fb->width, fb->height,
			   util_framebuffer_get_num_layers(fb),
			   buffers, color, depth, stencil);
	si_blitter_end(sctx);

	if (sctx->db_depth_clear) {
		sctx->db_depth_clear = false;
		sctx->db_depth_disable_expclear = false;
		zstex->depth_cleared = true;
		si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
	}

	if (sctx->db_stencil_clear) {
		sctx->db_stencil_clear = false;
		sctx->db_stencil_disable_expclear = false;
		zstex->stencil_cleared = true;
		si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
	}
}