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