Пример #1
0
/**
 * Try to do a blit using resource_copy_region. The function calls
 * resource_copy_region if the blit description is compatible with it.
 *
 * It returns TRUE if the blit was done using resource_copy_region.
 *
 * It returns FALSE otherwise and the caller must fall back to a more generic
 * codepath for the blit operation. (e.g. by using u_blitter)
 */
boolean
util_try_blit_via_copy_region(struct pipe_context *ctx,
                              const struct pipe_blit_info *blit)
{
   unsigned mask = util_format_get_mask(blit->dst.format);

   /* No format conversions. */
   if (blit->src.resource->format != blit->src.format ||
       blit->dst.resource->format != blit->dst.format ||
       !util_is_format_compatible(
          util_format_description(blit->src.resource->format),
          util_format_description(blit->dst.resource->format))) {
      return FALSE;
   }

   /* No masks, no filtering, no scissor. */
   if ((blit->mask & mask) != mask ||
       blit->filter != PIPE_TEX_FILTER_NEAREST ||
       blit->scissor_enable) {
      return FALSE;
   }

   /* No flipping. */
   if (blit->src.box.width < 0 ||
       blit->src.box.height < 0 ||
       blit->src.box.depth < 0) {
      return FALSE;
   }

   /* No scaling. */
   if (blit->src.box.width != blit->dst.box.width ||
       blit->src.box.height != blit->dst.box.height ||
       blit->src.box.depth != blit->dst.box.depth) {
      return FALSE;
   }

   /* No out-of-bounds access. */
   if (!is_box_inside_resource(blit->src.resource, &blit->src.box,
                               blit->src.level) ||
       !is_box_inside_resource(blit->dst.resource, &blit->dst.box,
                               blit->dst.level)) {
      return FALSE;
   }

   /* Sample counts must match. */
   if (get_sample_count(blit->src.resource) !=
       get_sample_count(blit->dst.resource)) {
      return FALSE;
   }

   if (blit->alpha_blend)
      return FALSE;

   ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level,
                             blit->dst.box.x, blit->dst.box.y, blit->dst.box.z,
                             blit->src.resource, blit->src.level,
                             &blit->src.box);
   return TRUE;
}
Пример #2
0
static bool do_hardware_msaa_resolve(struct pipe_context *ctx,
				     const struct pipe_blit_info *info)
{
	struct si_context *sctx = (struct si_context*)ctx;
	struct r600_texture *dst = (struct r600_texture*)info->dst.resource;
	unsigned dst_width = u_minify(info->dst.resource->width0, info->dst.level);
	unsigned dst_height = u_minify(info->dst.resource->height0, info->dst.level);
	enum pipe_format format = int_to_norm_format(info->dst.format);
	unsigned sample_mask = ~0;

	/* Hardware MSAA resolve doesn't work if SPI format = NORM16_ABGR and
	 * the format is R16G16. Use R16A16, which does work.
	 */
	if (format == PIPE_FORMAT_R16G16_UNORM)
		format = PIPE_FORMAT_R16A16_UNORM;
	if (format == PIPE_FORMAT_R16G16_SNORM)
		format = PIPE_FORMAT_R16A16_SNORM;

	if (info->src.resource->nr_samples > 1 &&
	    info->dst.resource->nr_samples <= 1 &&
	    util_max_layer(info->src.resource, 0) == 0 &&
	    util_max_layer(info->dst.resource, info->dst.level) == 0 &&
	    util_is_format_compatible(util_format_description(info->src.format),
				      util_format_description(info->dst.format)) &&
	    !util_format_is_pure_integer(format) &&
	    !util_format_is_depth_or_stencil(format) &&
	    !info->scissor_enable &&
	    (info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA &&
	    dst_width == info->src.resource->width0 &&
	    dst_height == info->src.resource->height0 &&
	    info->dst.box.x == 0 &&
	    info->dst.box.y == 0 &&
	    info->dst.box.width == dst_width &&
	    info->dst.box.height == dst_height &&
	    info->dst.box.depth == 1 &&
	    info->src.box.x == 0 &&
	    info->src.box.y == 0 &&
	    info->src.box.width == dst_width &&
	    info->src.box.height == dst_height &&
	    info->src.box.depth == 1 &&
	    dst->surface.level[info->dst.level].mode >= RADEON_SURF_MODE_1D &&
	    !(dst->surface.flags & RADEON_SURF_SCANOUT) &&
	    (!dst->cmask.size || !dst->dirty_level_mask) && /* dst cannot be fast-cleared */
	    !dst->dcc_offset) {
		si_blitter_begin(ctx, SI_COLOR_RESOLVE |
				 (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND));
		util_blitter_custom_resolve_color(sctx->blitter,
						  info->dst.resource, info->dst.level,
						  info->dst.box.z,
						  info->src.resource, info->src.box.z,
						  sample_mask, sctx->custom_blend_resolve,
						  format);
		si_blitter_end(ctx);
		return true;
	}
	return false;
}
Пример #3
0
/**
 * Can we blit from src format to dest format with a simple copy?
 */
static boolean
formats_compatible(enum pipe_format src_format,
                   enum pipe_format dst_format)
{
   if (src_format == dst_format) {
      return TRUE;
   }
   else {
      const struct util_format_description *src_desc =
         util_format_description(src_format);
      const struct util_format_description *dst_desc =
         util_format_description(dst_format);
      return util_is_format_compatible(src_desc, dst_desc);
   }
}
static void
galahad_context_resource_copy_region(struct pipe_context *_pipe,
                              struct pipe_resource *_dst,
                              unsigned dst_level,
                              unsigned dstx,
                              unsigned dsty,
                              unsigned dstz,
                              struct pipe_resource *_src,
                              unsigned src_level,
                              const struct pipe_box *src_box)
{
   struct galahad_context *glhd_pipe = galahad_context(_pipe);
   struct galahad_resource *glhd_resource_dst = galahad_resource(_dst);
   struct galahad_resource *glhd_resource_src = galahad_resource(_src);
   struct pipe_context *pipe = glhd_pipe->pipe;
   struct pipe_resource *dst = glhd_resource_dst->resource;
   struct pipe_resource *src = glhd_resource_src->resource;

   if (_dst->format != _src->format) {
      const struct util_format_description *src_desc =
         util_format_description(_src->format);
      const struct util_format_description *dst_desc =
         util_format_description(_dst->format);
      if (!util_is_format_compatible(src_desc, dst_desc))
         glhd_warn("Format mismatch: Source is %s, destination is %s",
            src_desc->short_name,
            dst_desc->short_name);
   }

   if ((_src->target == PIPE_BUFFER && _dst->target != PIPE_BUFFER) ||
       (_src->target != PIPE_BUFFER && _dst->target == PIPE_BUFFER)) {
      glhd_warn("Resource target mismatch: Source is %i, destination is %i",
                _src->target, _dst->target);
   }

   pipe->resource_copy_region(pipe,
                              dst,
                              dst_level,
                              dstx,
                              dsty,
                              dstz,
                              src,
                              src_level,
                              src_box);
}
Пример #5
0
/**
 * Check whether we can blit using the surface_copy command.
 */
static bool
can_blit_via_surface_copy(struct svga_context *svga,
                          const struct pipe_blit_info *blit_info)
{
   struct svga_texture *dtex, *stex;

   /* Mimic the format tests in util_can_blit_via_copy_region(), but
    * skip the other tests that have already been performed.
    */
   if (blit_info->src.format != blit_info->dst.format) {
      const struct util_format_description *src_desc, *dst_desc;

      src_desc = util_format_description(blit_info->src.resource->format);
      dst_desc = util_format_description(blit_info->dst.resource->format);

      if (blit_info->src.resource->format != blit_info->src.format ||
          blit_info->dst.resource->format != blit_info->dst.format ||
          !util_is_format_compatible(src_desc, dst_desc))
         return false;
   }

   if (svga->render_condition && blit_info->render_condition_enable)
      return false;

   /* can't copy between different resource types */
   if (svga_resource_type(blit_info->src.resource->target) !=
       svga_resource_type(blit_info->dst.resource->target))
      return false;

   stex = svga_texture(blit_info->src.resource);
   dtex = svga_texture(blit_info->dst.resource);

   if (stex->handle == dtex->handle)
      return false;

   /*
    * This is what we've been using before, but it can probably be
    * relaxed. The device checks are less stringent.
    */
   return (stex->b.b.format == dtex->b.b.format);
}
Пример #6
0
void
util_format_translate(enum pipe_format dst_format,
                      void *dst, unsigned dst_stride,
                      unsigned dst_x, unsigned dst_y,
                      enum pipe_format src_format,
                      const void *src, unsigned src_stride,
                      unsigned src_x, unsigned src_y,
                      unsigned width, unsigned height)
{
   const struct util_format_description *dst_format_desc;
   const struct util_format_description *src_format_desc;
   uint8_t *dst_row;
   const uint8_t *src_row;
   unsigned x_step, y_step;
   unsigned dst_step;
   unsigned src_step;

   dst_format_desc = util_format_description(dst_format);
   src_format_desc = util_format_description(src_format);

   if (util_is_format_compatible(src_format_desc, dst_format_desc)) {
      /*
       * Trivial case.
       */

      util_copy_rect(dst, dst_format, dst_stride,  dst_x, dst_y,
                     width, height, src, (int)src_stride,
                     src_x, src_y);
      return;
   }

   assert(dst_x % dst_format_desc->block.width == 0);
   assert(dst_y % dst_format_desc->block.height == 0);
   assert(src_x % src_format_desc->block.width == 0);
   assert(src_y % src_format_desc->block.height == 0);

   dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8);
   src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8);

   /*
    * This works because all pixel formats have pixel blocks with power of two
    * sizes.
    */

   y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height);
   x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width);
   assert(y_step % dst_format_desc->block.height == 0);
   assert(y_step % src_format_desc->block.height == 0);

   dst_step = y_step / dst_format_desc->block.height * dst_stride;
   src_step = y_step / src_format_desc->block.height * src_stride;

   /*
    * TODO: double formats will loose precision
    * TODO: Add a special case for formats that are mere swizzles of each other
    */

   if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS ||
       dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
      float *tmp_z = NULL;
      uint8_t *tmp_s = NULL;

      assert(x_step == 1);
      assert(y_step == 1);

      if (src_format_desc->unpack_z_float &&
          dst_format_desc->pack_z_float) {
         tmp_z = MALLOC(width * sizeof *tmp_z);
      }

      if (src_format_desc->unpack_s_8uint &&
          dst_format_desc->pack_s_8uint) {
         tmp_s = MALLOC(width * sizeof *tmp_s);
      }

      while (height--) {
         if (tmp_z) {
            src_format_desc->unpack_z_float(tmp_z, 0, src_row, src_stride, width, 1);
            dst_format_desc->pack_z_float(dst_row, dst_stride, tmp_z, 0, width, 1);
         }

         if (tmp_s) {
            src_format_desc->unpack_s_8uint(tmp_s, 0, src_row, src_stride, width, 1);
            dst_format_desc->pack_s_8uint(dst_row, dst_stride, tmp_s, 0, width, 1);
         }

         dst_row += dst_step;
         src_row += src_step;
      }

      FREE(tmp_s);

      FREE(tmp_z);

      return;
   }

   if (util_format_fits_8unorm(src_format_desc) ||
       util_format_fits_8unorm(dst_format_desc)) {
      unsigned tmp_stride;
      uint8_t *tmp_row;

      tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
      tmp_row = MALLOC(y_step * tmp_stride);
      if (!tmp_row)
         return;

      while (height >= y_step) {
         src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
         dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);

         dst_row += dst_step;
         src_row += src_step;
         height -= y_step;
      }

      if (height) {
         src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, height);
         dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
      }

      FREE(tmp_row);
   }
   else {
      unsigned tmp_stride;
      float *tmp_row;

      tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
      tmp_row = MALLOC(y_step * tmp_stride);
      if (!tmp_row)
         return;

      while (height >= y_step) {
         src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
         dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);

         dst_row += dst_step;
         src_row += src_step;
         height -= y_step;
      }

      if (height) {
         src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, height);
         dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
      }

      FREE(tmp_row);
   }
}
Пример #7
0
static bool do_hardware_msaa_resolve(struct pipe_context *ctx,
                                     const struct pipe_blit_info *info)
{
    struct r600_context *rctx = (struct r600_context*)ctx;
    struct r600_texture *dst = (struct r600_texture*)info->dst.resource;
    unsigned dst_width = u_minify(info->dst.resource->width0, info->dst.level);
    unsigned dst_height = u_minify(info->dst.resource->height0, info->dst.level);
    enum pipe_format format = info->src.format;
    unsigned sample_mask =
        rctx->b.chip_class == CAYMAN ? ~0 :
        ((1ull << MAX2(1, info->src.resource->nr_samples)) - 1);
    struct pipe_resource *tmp, templ;
    struct pipe_blit_info blit;

    /* Check basic requirements for hw resolve. */
    if (!(info->src.resource->nr_samples > 1 &&
            info->dst.resource->nr_samples <= 1 &&
            !util_format_is_pure_integer(format) &&
            !util_format_is_depth_or_stencil(format) &&
            util_max_layer(info->src.resource, 0) == 0))
        return false;

    /* Check the remaining requirements for hw resolve. */
    if (util_max_layer(info->dst.resource, info->dst.level) == 0 &&
            util_is_format_compatible(util_format_description(info->src.format),
                                      util_format_description(info->dst.format)) &&
            !info->scissor_enable &&
            (info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA &&
            dst_width == info->src.resource->width0 &&
            dst_height == info->src.resource->height0 &&
            info->dst.box.x == 0 &&
            info->dst.box.y == 0 &&
            info->dst.box.width == dst_width &&
            info->dst.box.height == dst_height &&
            info->dst.box.depth == 1 &&
            info->src.box.x == 0 &&
            info->src.box.y == 0 &&
            info->src.box.width == dst_width &&
            info->src.box.height == dst_height &&
            info->src.box.depth == 1 &&
            dst->surface.level[info->dst.level].mode >= RADEON_SURF_MODE_1D &&
            (!dst->cmask.size || !dst->dirty_level_mask) /* dst cannot be fast-cleared */) {
        r600_blitter_begin(ctx, R600_COLOR_RESOLVE |
                           (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND));
        util_blitter_custom_resolve_color(rctx->blitter,
                                          info->dst.resource, info->dst.level,
                                          info->dst.box.z,
                                          info->src.resource, info->src.box.z,
                                          sample_mask, rctx->custom_blend_resolve,
                                          format);
        r600_blitter_end(ctx);
        return true;
    }

    /* Shader-based resolve is VERY SLOW. Instead, resolve into
     * a temporary texture and blit.
     */
    memset(&templ, 0, sizeof(templ));
    templ.target = PIPE_TEXTURE_2D;
    templ.format = info->src.resource->format;
    templ.width0 = info->src.resource->width0;
    templ.height0 = info->src.resource->height0;
    templ.depth0 = 1;
    templ.array_size = 1;
    templ.usage = PIPE_USAGE_DEFAULT;
    templ.flags = R600_RESOURCE_FLAG_FORCE_TILING;

    tmp = ctx->screen->resource_create(ctx->screen, &templ);
    if (!tmp)
        return false;

    /* resolve */
    r600_blitter_begin(ctx, R600_COLOR_RESOLVE |
                       (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND));
    util_blitter_custom_resolve_color(rctx->blitter, tmp, 0, 0,
                                      info->src.resource, info->src.box.z,
                                      sample_mask, rctx->custom_blend_resolve,
                                      format);
    r600_blitter_end(ctx);

    /* blit */
    blit = *info;
    blit.src.resource = tmp;
    blit.src.box.z = 0;

    r600_blitter_begin(ctx, R600_BLIT |
                       (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND));
    util_blitter_blit(rctx->blitter, &blit);
    r600_blitter_end(ctx);

    pipe_resource_reference(&tmp, NULL);
    return true;
}
Пример #8
0
static bool do_hardware_msaa_resolve(struct pipe_context *ctx,
				     const struct pipe_blit_info *info)
{
	struct si_context *sctx = (struct si_context*)ctx;
	struct r600_texture *src = (struct r600_texture*)info->src.resource;
	struct r600_texture *dst = (struct r600_texture*)info->dst.resource;
	unsigned dst_width = u_minify(info->dst.resource->width0, info->dst.level);
	unsigned dst_height = u_minify(info->dst.resource->height0, info->dst.level);
	enum pipe_format format = info->src.format;
	unsigned sample_mask = ~0;
	struct pipe_resource *tmp, templ;
	struct pipe_blit_info blit;

	/* Check basic requirements for hw resolve. */
	if (!(info->src.resource->nr_samples > 1 &&
	      info->dst.resource->nr_samples <= 1 &&
	      !util_format_is_pure_integer(format) &&
	      !util_format_is_depth_or_stencil(format) &&
	      util_max_layer(info->src.resource, 0) == 0))
		return false;

	/* Hardware MSAA resolve doesn't work if SPI format = NORM16_ABGR and
	 * the format is R16G16. Use R16A16, which does work.
	 */
	if (format == PIPE_FORMAT_R16G16_UNORM)
		format = PIPE_FORMAT_R16A16_UNORM;
	if (format == PIPE_FORMAT_R16G16_SNORM)
		format = PIPE_FORMAT_R16A16_SNORM;

	/* Check the remaining requirements for hw resolve. */
	if (util_max_layer(info->dst.resource, info->dst.level) == 0 &&
	    !info->scissor_enable &&
	    (info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA &&
	    util_is_format_compatible(util_format_description(info->src.format),
				      util_format_description(info->dst.format)) &&
	    dst_width == info->src.resource->width0 &&
	    dst_height == info->src.resource->height0 &&
	    info->dst.box.x == 0 &&
	    info->dst.box.y == 0 &&
	    info->dst.box.width == dst_width &&
	    info->dst.box.height == dst_height &&
	    info->dst.box.depth == 1 &&
	    info->src.box.x == 0 &&
	    info->src.box.y == 0 &&
	    info->src.box.width == dst_width &&
	    info->src.box.height == dst_height &&
	    info->src.box.depth == 1 &&
	    dst->surface.level[info->dst.level].mode >= RADEON_SURF_MODE_1D &&
	    (!dst->cmask.size || !dst->dirty_level_mask)) { /* dst cannot be fast-cleared */
		/* Check the last constraint. */
		if (src->surface.micro_tile_mode != dst->surface.micro_tile_mode) {
			/* The next fast clear will switch to this mode to
			 * get direct hw resolve next time if the mode is
			 * different now.
			 */
			src->last_msaa_resolve_target_micro_mode =
				dst->surface.micro_tile_mode;
			goto resolve_to_temp;
		}

		/* Resolving into a surface with DCC is unsupported. Since
		 * it's being overwritten anyway, clear it to uncompressed.
		 * This is still the fastest codepath even with this clear.
		 */
		if (dst->dcc_offset &&
		    dst->surface.level[info->dst.level].dcc_enabled) {
			vi_dcc_clear_level(&sctx->b, dst, info->dst.level,
					   0xFFFFFFFF);
			dst->dirty_level_mask &= ~(1 << info->dst.level);
		}

		/* Resolve directly from src to dst. */
		si_blitter_begin(ctx, SI_COLOR_RESOLVE |
				 (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND));
		util_blitter_custom_resolve_color(sctx->blitter,
						  info->dst.resource, info->dst.level,
						  info->dst.box.z,
						  info->src.resource, info->src.box.z,
						  sample_mask, sctx->custom_blend_resolve,
						  format);
		si_blitter_end(ctx);
		return true;
	}

resolve_to_temp:
	/* Shader-based resolve is VERY SLOW. Instead, resolve into
	 * a temporary texture and blit.
	 */
	memset(&templ, 0, sizeof(templ));
	templ.target = PIPE_TEXTURE_2D;
	templ.format = info->src.resource->format;
	templ.width0 = info->src.resource->width0;
	templ.height0 = info->src.resource->height0;
	templ.depth0 = 1;
	templ.array_size = 1;
	templ.usage = PIPE_USAGE_DEFAULT;
	templ.flags = R600_RESOURCE_FLAG_FORCE_TILING |
		      R600_RESOURCE_FLAG_DISABLE_DCC;

	/* The src and dst microtile modes must be the same. */
	if (src->surface.micro_tile_mode == V_009910_ADDR_SURF_DISPLAY_MICRO_TILING)
		templ.bind = PIPE_BIND_SCANOUT;
	else
		templ.bind = 0;

	tmp = ctx->screen->resource_create(ctx->screen, &templ);
	if (!tmp)
		return false;

	assert(src->surface.micro_tile_mode ==
	       ((struct r600_texture*)tmp)->surface.micro_tile_mode);

	/* resolve */
	si_blitter_begin(ctx, SI_COLOR_RESOLVE |
			 (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND));
	util_blitter_custom_resolve_color(sctx->blitter, tmp, 0, 0,
					  info->src.resource, info->src.box.z,
					  sample_mask, sctx->custom_blend_resolve,
					  format);
	si_blitter_end(ctx);

	/* blit */
	blit = *info;
	blit.src.resource = tmp;
	blit.src.box.z = 0;

	si_blitter_begin(ctx, SI_BLIT |
			 (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND));
	util_blitter_blit(sctx->blitter, &blit);
	si_blitter_end(ctx);

	pipe_resource_reference(&tmp, NULL);
	return true;
}