Path: blob/21.2-virgl/src/gallium/drivers/iris/iris_blit.c
4565 views
/*1* Copyright © 2017 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included11* in all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS14* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING18* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER19* DEALINGS IN THE SOFTWARE.20*/2122#include <stdio.h>23#include "pipe/p_defines.h"24#include "pipe/p_state.h"25#include "pipe/p_context.h"26#include "pipe/p_screen.h"27#include "util/format/u_format.h"28#include "util/u_inlines.h"29#include "util/ralloc.h"30#include "intel/blorp/blorp.h"31#include "iris_context.h"32#include "iris_resource.h"33#include "iris_screen.h"3435/**36* Helper function for handling mirror image blits.37*38* If coord0 > coord1, swap them and return "true" (mirrored).39*/40static bool41apply_mirror(float *coord0, float *coord1)42{43if (*coord0 > *coord1) {44float tmp = *coord0;45*coord0 = *coord1;46*coord1 = tmp;47return true;48}49return false;50}5152/**53* Compute the number of pixels to clip for each side of a rect54*55* \param x0 The rect's left coordinate56* \param y0 The rect's bottom coordinate57* \param x1 The rect's right coordinate58* \param y1 The rect's top coordinate59* \param min_x The clipping region's left coordinate60* \param min_y The clipping region's bottom coordinate61* \param max_x The clipping region's right coordinate62* \param max_y The clipping region's top coordinate63* \param clipped_x0 The number of pixels to clip from the left side64* \param clipped_y0 The number of pixels to clip from the bottom side65* \param clipped_x1 The number of pixels to clip from the right side66* \param clipped_y1 The number of pixels to clip from the top side67*68* \return false if we clip everything away, true otherwise69*/70static inline bool71compute_pixels_clipped(float x0, float y0, float x1, float y1,72float min_x, float min_y, float max_x, float max_y,73float *clipped_x0, float *clipped_y0,74float *clipped_x1, float *clipped_y1)75{76/* If we are going to clip everything away, stop. */77if (!(min_x <= max_x &&78min_y <= max_y &&79x0 <= max_x &&80y0 <= max_y &&81min_x <= x1 &&82min_y <= y1 &&83x0 <= x1 &&84y0 <= y1)) {85return false;86}8788if (x0 < min_x)89*clipped_x0 = min_x - x0;90else91*clipped_x0 = 0;92if (max_x < x1)93*clipped_x1 = x1 - max_x;94else95*clipped_x1 = 0;9697if (y0 < min_y)98*clipped_y0 = min_y - y0;99else100*clipped_y0 = 0;101if (max_y < y1)102*clipped_y1 = y1 - max_y;103else104*clipped_y1 = 0;105106return true;107}108109/**110* Clips a coordinate (left, right, top or bottom) for the src or dst rect111* (whichever requires the largest clip) and adjusts the coordinate112* for the other rect accordingly.113*114* \param mirror true if mirroring is required115* \param src the source rect coordinate (for example src_x0)116* \param dst0 the dst rect coordinate (for example dst_x0)117* \param dst1 the opposite dst rect coordinate (for example dst_x1)118* \param clipped_dst0 number of pixels to clip from the dst coordinate119* \param clipped_dst1 number of pixels to clip from the opposite dst coordinate120* \param scale the src vs dst scale involved for that coordinate121* \param is_left_or_bottom true if we are clipping the left or bottom sides122* of the rect.123*/124static void125clip_coordinates(bool mirror,126float *src, float *dst0, float *dst1,127float clipped_dst0,128float clipped_dst1,129float scale,130bool is_left_or_bottom)131{132/* When clipping we need to add or subtract pixels from the original133* coordinates depending on whether we are acting on the left/bottom134* or right/top sides of the rect respectively. We assume we have to135* add them in the code below, and multiply by -1 when we should136* subtract.137*/138int mult = is_left_or_bottom ? 1 : -1;139140if (!mirror) {141*dst0 += clipped_dst0 * mult;142*src += clipped_dst0 * scale * mult;143} else {144*dst1 -= clipped_dst1 * mult;145*src += clipped_dst1 * scale * mult;146}147}148149/**150* Apply a scissor rectangle to blit coordinates.151*152* Returns true if the blit was entirely scissored away.153*/154static bool155apply_blit_scissor(const struct pipe_scissor_state *scissor,156float *src_x0, float *src_y0,157float *src_x1, float *src_y1,158float *dst_x0, float *dst_y0,159float *dst_x1, float *dst_y1,160bool mirror_x, bool mirror_y)161{162float clip_dst_x0, clip_dst_x1, clip_dst_y0, clip_dst_y1;163164/* Compute number of pixels to scissor away. */165if (!compute_pixels_clipped(*dst_x0, *dst_y0, *dst_x1, *dst_y1,166scissor->minx, scissor->miny,167scissor->maxx, scissor->maxy,168&clip_dst_x0, &clip_dst_y0,169&clip_dst_x1, &clip_dst_y1))170return true;171172// XXX: comments assume source clipping, which we don't do173174/* When clipping any of the two rects we need to adjust the coordinates175* in the other rect considering the scaling factor involved. To obtain176* the best precision we want to make sure that we only clip once per177* side to avoid accumulating errors due to the scaling adjustment.178*179* For example, if src_x0 and dst_x0 need both to be clipped we want to180* avoid the situation where we clip src_x0 first, then adjust dst_x0181* accordingly but then we realize that the resulting dst_x0 still needs182* to be clipped, so we clip dst_x0 and adjust src_x0 again. Because we are183* applying scaling factors to adjust the coordinates in each clipping184* pass we lose some precision and that can affect the results of the185* blorp blit operation slightly. What we want to do here is detect the186* rect that we should clip first for each side so that when we adjust187* the other rect we ensure the resulting coordinate does not need to be188* clipped again.189*190* The code below implements this by comparing the number of pixels that191* we need to clip for each side of both rects considering the scales192* involved. For example, clip_src_x0 represents the number of pixels193* to be clipped for the src rect's left side, so if clip_src_x0 = 5,194* clip_dst_x0 = 4 and scale_x = 2 it means that we are clipping more195* from the dst rect so we should clip dst_x0 only and adjust src_x0.196* This is because clipping 4 pixels in the dst is equivalent to197* clipping 4 * 2 = 8 > 5 in the src.198*/199200if (*src_x0 == *src_x1 || *src_y0 == *src_y1201|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1)202return true;203204float scale_x = (float) (*src_x1 - *src_x0) / (*dst_x1 - *dst_x0);205float scale_y = (float) (*src_y1 - *src_y0) / (*dst_y1 - *dst_y0);206207/* Clip left side */208clip_coordinates(mirror_x, src_x0, dst_x0, dst_x1,209clip_dst_x0, clip_dst_x1, scale_x, true);210211/* Clip right side */212clip_coordinates(mirror_x, src_x1, dst_x1, dst_x0,213clip_dst_x1, clip_dst_x0, scale_x, false);214215/* Clip bottom side */216clip_coordinates(mirror_y, src_y0, dst_y0, dst_y1,217clip_dst_y0, clip_dst_y1, scale_y, true);218219/* Clip top side */220clip_coordinates(mirror_y, src_y1, dst_y1, dst_y0,221clip_dst_y1, clip_dst_y0, scale_y, false);222223/* Check for invalid bounds224* Can't blit for 0-dimensions225*/226return *src_x0 == *src_x1 || *src_y0 == *src_y1227|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1;228}229230void231iris_blorp_surf_for_resource(struct isl_device *isl_dev,232struct blorp_surf *surf,233struct pipe_resource *p_res,234enum isl_aux_usage aux_usage,235unsigned level,236bool is_render_target)237{238struct iris_resource *res = (void *) p_res;239240assert(!iris_resource_unfinished_aux_import(res));241242*surf = (struct blorp_surf) {243.surf = &res->surf,244.addr = (struct blorp_address) {245.buffer = res->bo,246.offset = res->offset,247.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,248.mocs = iris_mocs(res->bo, isl_dev,249is_render_target ? ISL_SURF_USAGE_RENDER_TARGET_BIT250: ISL_SURF_USAGE_TEXTURE_BIT),251},252.aux_usage = aux_usage,253};254255if (aux_usage != ISL_AUX_USAGE_NONE) {256surf->aux_surf = &res->aux.surf;257surf->aux_addr = (struct blorp_address) {258.buffer = res->aux.bo,259.offset = res->aux.offset,260.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,261.mocs = iris_mocs(res->bo, isl_dev, 0),262};263surf->clear_color =264iris_resource_get_clear_color(res, NULL, NULL);265surf->clear_color_addr = (struct blorp_address) {266.buffer = res->aux.clear_color_bo,267.offset = res->aux.clear_color_offset,268.reloc_flags = 0,269.mocs = iris_mocs(res->aux.clear_color_bo, isl_dev, 0),270};271}272}273274static bool275is_astc(enum isl_format format)276{277return format != ISL_FORMAT_UNSUPPORTED &&278isl_format_get_layout(format)->txc == ISL_TXC_ASTC;279}280281static void282tex_cache_flush_hack(struct iris_batch *batch,283enum isl_format view_format,284enum isl_format surf_format)285{286const struct intel_device_info *devinfo = &batch->screen->devinfo;287288/* The WaSamplerCacheFlushBetweenRedescribedSurfaceReads workaround says:289*290* "Currently Sampler assumes that a surface would not have two291* different format associate with it. It will not properly cache292* the different views in the MT cache, causing a data corruption."293*294* We may need to handle this for texture views in general someday, but295* for now we handle it here, as it hurts copies and blits particularly296* badly because they ofter reinterpret formats.297*298* If the BO hasn't been referenced yet this batch, we assume that the299* texture cache doesn't contain any relevant data nor need flushing.300*301* Icelake (Gfx11+) claims to fix this issue, but seems to still have302* issues with ASTC formats.303*/304bool need_flush = devinfo->ver >= 11 ?305is_astc(surf_format) != is_astc(view_format) :306view_format != surf_format;307if (!need_flush)308return;309310const char *reason =311"workaround: WaSamplerCacheFlushBetweenRedescribedSurfaceReads";312313iris_emit_pipe_control_flush(batch, reason, PIPE_CONTROL_CS_STALL);314iris_emit_pipe_control_flush(batch, reason,315PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);316}317318static struct iris_resource *319iris_resource_for_aspect(struct pipe_resource *p_res, unsigned pipe_mask)320{321if (pipe_mask == PIPE_MASK_S) {322struct iris_resource *junk, *s_res;323iris_get_depth_stencil_resources(p_res, &junk, &s_res);324return s_res;325} else {326return (struct iris_resource *)p_res;327}328}329330static enum pipe_format331pipe_format_for_aspect(enum pipe_format format, unsigned pipe_mask)332{333if (pipe_mask == PIPE_MASK_S) {334return util_format_stencil_only(format);335} else if (pipe_mask == PIPE_MASK_Z) {336return util_format_get_depth_only(format);337} else {338return format;339}340}341342/**343* The pipe->blit() driver hook.344*345* This performs a blit between two surfaces, which copies data but may346* also perform format conversion, scaling, flipping, and so on.347*/348static void349iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)350{351struct iris_context *ice = (void *) ctx;352struct iris_screen *screen = (struct iris_screen *)ctx->screen;353const struct intel_device_info *devinfo = &screen->devinfo;354struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];355enum blorp_batch_flags blorp_flags = 0;356357/* We don't support color masking. */358assert((info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA ||359(info->mask & PIPE_MASK_RGBA) == 0);360361if (info->render_condition_enable) {362if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER)363return;364365if (ice->state.predicate == IRIS_PREDICATE_STATE_USE_BIT)366blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;367}368369float src_x0 = info->src.box.x;370float src_x1 = info->src.box.x + info->src.box.width;371float src_y0 = info->src.box.y;372float src_y1 = info->src.box.y + info->src.box.height;373float dst_x0 = info->dst.box.x;374float dst_x1 = info->dst.box.x + info->dst.box.width;375float dst_y0 = info->dst.box.y;376float dst_y1 = info->dst.box.y + info->dst.box.height;377bool mirror_x = apply_mirror(&src_x0, &src_x1);378bool mirror_y = apply_mirror(&src_y0, &src_y1);379enum blorp_filter filter;380381if (info->scissor_enable) {382bool noop = apply_blit_scissor(&info->scissor,383&src_x0, &src_y0, &src_x1, &src_y1,384&dst_x0, &dst_y0, &dst_x1, &dst_y1,385mirror_x, mirror_y);386if (noop)387return;388}389390if (abs(info->dst.box.width) == abs(info->src.box.width) &&391abs(info->dst.box.height) == abs(info->src.box.height)) {392if (info->src.resource->nr_samples > 1 &&393info->dst.resource->nr_samples <= 1) {394/* The OpenGL ES 3.2 specification, section 16.2.1, says:395*396* "If the read framebuffer is multisampled (its effective397* value of SAMPLE_BUFFERS is one) and the draw framebuffer398* is not (its value of SAMPLE_BUFFERS is zero), the samples399* corresponding to each pixel location in the source are400* converted to a single sample before being written to the401* destination. The filter parameter is ignored. If the402* source formats are integer types or stencil values, a403* single sample’s value is selected for each pixel. If the404* source formats are floating-point or normalized types,405* the sample values for each pixel are resolved in an406* implementation-dependent manner. If the source formats407* are depth values, sample values are resolved in an408* implementation-dependent manner where the result will be409* between the minimum and maximum depth values in the pixel."410*411* When selecting a single sample, we always choose sample 0.412*/413if (util_format_is_depth_or_stencil(info->src.format) ||414util_format_is_pure_integer(info->src.format)) {415filter = BLORP_FILTER_SAMPLE_0;416} else {417filter = BLORP_FILTER_AVERAGE;418}419} else {420/* The OpenGL 4.6 specification, section 18.3.1, says:421*422* "If the source and destination dimensions are identical,423* no filtering is applied."424*425* Using BLORP_FILTER_NONE will also handle the upsample case by426* replicating the one value in the source to all values in the427* destination.428*/429filter = BLORP_FILTER_NONE;430}431} else if (info->filter == PIPE_TEX_FILTER_LINEAR) {432filter = BLORP_FILTER_BILINEAR;433} else {434filter = BLORP_FILTER_NEAREST;435}436437struct blorp_batch blorp_batch;438blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);439440float src_z_step = (float)info->src.box.depth / (float)info->dst.box.depth;441442/* There is no interpolation to the pixel center during rendering, so443* add the 0.5 offset ourselves here.444*/445float depth_center_offset = 0;446if (info->src.resource->target == PIPE_TEXTURE_3D)447depth_center_offset = 0.5 / info->dst.box.depth * info->src.box.depth;448449/* Perform a blit for each aspect requested by the caller. PIPE_MASK_R is450* used to represent the color aspect. */451unsigned aspect_mask = info->mask & (PIPE_MASK_R | PIPE_MASK_ZS);452while (aspect_mask) {453unsigned aspect = 1 << u_bit_scan(&aspect_mask);454455struct iris_resource *src_res =456iris_resource_for_aspect(info->src.resource, aspect);457struct iris_resource *dst_res =458iris_resource_for_aspect(info->dst.resource, aspect);459460enum pipe_format src_pfmt =461pipe_format_for_aspect(info->src.format, aspect);462enum pipe_format dst_pfmt =463pipe_format_for_aspect(info->dst.format, aspect);464465if (iris_resource_unfinished_aux_import(src_res))466iris_resource_finish_aux_import(ctx->screen, src_res);467if (iris_resource_unfinished_aux_import(dst_res))468iris_resource_finish_aux_import(ctx->screen, dst_res);469470struct iris_format_info src_fmt =471iris_format_for_usage(devinfo, src_pfmt, ISL_SURF_USAGE_TEXTURE_BIT);472enum isl_aux_usage src_aux_usage =473iris_resource_texture_aux_usage(ice, src_res, src_fmt.fmt);474475iris_resource_prepare_texture(ice, src_res, src_fmt.fmt,476info->src.level, 1, info->src.box.z,477info->src.box.depth);478iris_emit_buffer_barrier_for(batch, src_res->bo,479IRIS_DOMAIN_OTHER_READ);480481struct iris_format_info dst_fmt =482iris_format_for_usage(devinfo, dst_pfmt,483ISL_SURF_USAGE_RENDER_TARGET_BIT);484enum isl_aux_usage dst_aux_usage =485iris_resource_render_aux_usage(ice, dst_res, info->dst.level,486dst_fmt.fmt, false);487488struct blorp_surf src_surf, dst_surf;489iris_blorp_surf_for_resource(&screen->isl_dev, &src_surf,490&src_res->base.b, src_aux_usage,491info->src.level, false);492iris_blorp_surf_for_resource(&screen->isl_dev, &dst_surf,493&dst_res->base.b, dst_aux_usage,494info->dst.level, true);495496iris_resource_prepare_render(ice, dst_res, info->dst.level,497info->dst.box.z, info->dst.box.depth,498dst_aux_usage);499iris_emit_buffer_barrier_for(batch, dst_res->bo,500IRIS_DOMAIN_RENDER_WRITE);501502if (iris_batch_references(batch, src_res->bo))503tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);504505if (dst_res->base.b.target == PIPE_BUFFER) {506util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range,507dst_x0, dst_x1);508}509510for (int slice = 0; slice < info->dst.box.depth; slice++) {511unsigned dst_z = info->dst.box.z + slice;512float src_z = info->src.box.z + slice * src_z_step +513depth_center_offset;514515iris_batch_maybe_flush(batch, 1500);516iris_batch_sync_region_start(batch);517518blorp_blit(&blorp_batch,519&src_surf, info->src.level, src_z,520src_fmt.fmt, src_fmt.swizzle,521&dst_surf, info->dst.level, dst_z,522dst_fmt.fmt, dst_fmt.swizzle,523src_x0, src_y0, src_x1, src_y1,524dst_x0, dst_y0, dst_x1, dst_y1,525filter, mirror_x, mirror_y);526527iris_batch_sync_region_end(batch);528}529530tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);531532iris_resource_finish_render(ice, dst_res, info->dst.level,533info->dst.box.z, info->dst.box.depth,534dst_aux_usage);535}536537blorp_batch_finish(&blorp_batch);538539iris_flush_and_dirty_for_history(ice, batch, (struct iris_resource *)540info->dst.resource,541PIPE_CONTROL_RENDER_TARGET_FLUSH,542"cache history: post-blit");543}544545static void546get_copy_region_aux_settings(struct iris_context *ice,547struct iris_resource *res,548unsigned level,549enum isl_aux_usage *out_aux_usage,550bool *out_clear_supported,551bool is_render_target)552{553struct iris_screen *screen = (void *) ice->ctx.screen;554struct intel_device_info *devinfo = &screen->devinfo;555556switch (res->aux.usage) {557case ISL_AUX_USAGE_HIZ:558case ISL_AUX_USAGE_HIZ_CCS:559case ISL_AUX_USAGE_HIZ_CCS_WT:560case ISL_AUX_USAGE_STC_CCS:561if (is_render_target) {562*out_aux_usage = iris_resource_render_aux_usage(ice, res, level,563res->surf.format,564false);565} else {566*out_aux_usage = iris_resource_texture_aux_usage(ice, res,567res->surf.format);568}569*out_clear_supported = isl_aux_usage_has_fast_clears(*out_aux_usage);570break;571case ISL_AUX_USAGE_MCS:572case ISL_AUX_USAGE_MCS_CCS:573if (!is_render_target &&574!iris_can_sample_mcs_with_clear(devinfo, res)) {575*out_aux_usage = res->aux.usage;576*out_clear_supported = false;577break;578}579FALLTHROUGH;580case ISL_AUX_USAGE_CCS_E:581case ISL_AUX_USAGE_GFX12_CCS_E:582*out_aux_usage = res->aux.usage;583584/* blorp_copy may reinterpret the surface format and has limited support585* for adjusting the clear color, so clear support may only be enabled586* in some cases:587*588* - On gfx11+, the clear color is indirect and comes in two forms: a589* 32bpc representation used for rendering and a pixel representation590* used for sampling. blorp_copy doesn't change indirect clear colors,591* so clears are only supported in the sampling case.592*593* - A clear color of zeroes holds the same meaning regardless of the594* format. Although it could avoid more resolves, we don't use595* isl_color_value_is_zero because the surface format used by596* blorp_copy isn't guaranteed to access the same components as the597* original format (e.g. A8_UNORM/R8_UINT).598*/599*out_clear_supported = (devinfo->ver >= 11 && !is_render_target) ||600(res->aux.clear_color.u32[0] == 0 &&601res->aux.clear_color.u32[1] == 0 &&602res->aux.clear_color.u32[2] == 0 &&603res->aux.clear_color.u32[3] == 0);604break;605default:606*out_aux_usage = ISL_AUX_USAGE_NONE;607*out_clear_supported = false;608break;609}610}611612/**613* Perform a GPU-based raw memory copy between compatible view classes.614*615* Does not perform any flushing - the new data may still be left in the616* render cache, and old data may remain in other caches.617*618* Wraps blorp_copy() and blorp_buffer_copy().619*/620void621iris_copy_region(struct blorp_context *blorp,622struct iris_batch *batch,623struct pipe_resource *dst,624unsigned dst_level,625unsigned dstx, unsigned dsty, unsigned dstz,626struct pipe_resource *src,627unsigned src_level,628const struct pipe_box *src_box)629{630struct blorp_batch blorp_batch;631struct iris_context *ice = blorp->driver_ctx;632struct iris_screen *screen = (void *) ice->ctx.screen;633struct iris_resource *src_res = (void *) src;634struct iris_resource *dst_res = (void *) dst;635636enum isl_aux_usage src_aux_usage, dst_aux_usage;637bool src_clear_supported, dst_clear_supported;638get_copy_region_aux_settings(ice, src_res, src_level, &src_aux_usage,639&src_clear_supported, false);640get_copy_region_aux_settings(ice, dst_res, dst_level, &dst_aux_usage,641&dst_clear_supported, true);642643if (iris_batch_references(batch, src_res->bo))644tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);645646if (dst->target == PIPE_BUFFER)647util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range, dstx, dstx + src_box->width);648649if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {650struct blorp_address src_addr = {651.buffer = iris_resource_bo(src), .offset = src_box->x,652};653struct blorp_address dst_addr = {654.buffer = iris_resource_bo(dst), .offset = dstx,655.reloc_flags = EXEC_OBJECT_WRITE,656};657658iris_emit_buffer_barrier_for(batch, iris_resource_bo(src),659IRIS_DOMAIN_OTHER_READ);660iris_emit_buffer_barrier_for(batch, iris_resource_bo(dst),661IRIS_DOMAIN_RENDER_WRITE);662663iris_batch_maybe_flush(batch, 1500);664665iris_batch_sync_region_start(batch);666blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);667blorp_buffer_copy(&blorp_batch, src_addr, dst_addr, src_box->width);668blorp_batch_finish(&blorp_batch);669iris_batch_sync_region_end(batch);670} else {671// XXX: what about one surface being a buffer and not the other?672673struct blorp_surf src_surf, dst_surf;674iris_blorp_surf_for_resource(&screen->isl_dev, &src_surf,675src, src_aux_usage, src_level, false);676iris_blorp_surf_for_resource(&screen->isl_dev, &dst_surf,677dst, dst_aux_usage, dst_level, true);678679iris_resource_prepare_access(ice, src_res, src_level, 1,680src_box->z, src_box->depth,681src_aux_usage, src_clear_supported);682iris_resource_prepare_access(ice, dst_res, dst_level, 1,683dstz, src_box->depth,684dst_aux_usage, dst_clear_supported);685686iris_emit_buffer_barrier_for(batch, iris_resource_bo(src),687IRIS_DOMAIN_OTHER_READ);688iris_emit_buffer_barrier_for(batch, iris_resource_bo(dst),689IRIS_DOMAIN_RENDER_WRITE);690691blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);692693for (int slice = 0; slice < src_box->depth; slice++) {694iris_batch_maybe_flush(batch, 1500);695696iris_batch_sync_region_start(batch);697blorp_copy(&blorp_batch, &src_surf, src_level, src_box->z + slice,698&dst_surf, dst_level, dstz + slice,699src_box->x, src_box->y, dstx, dsty,700src_box->width, src_box->height);701iris_batch_sync_region_end(batch);702}703blorp_batch_finish(&blorp_batch);704705iris_resource_finish_write(ice, dst_res, dst_level, dstz,706src_box->depth, dst_aux_usage);707}708709tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);710}711712static struct iris_batch *713get_preferred_batch(struct iris_context *ice, struct iris_bo *bo)714{715/* If the compute batch is already using this buffer, we'd prefer to716* continue queueing in the compute batch.717*/718if (iris_batch_references(&ice->batches[IRIS_BATCH_COMPUTE], bo))719return &ice->batches[IRIS_BATCH_COMPUTE];720721/* Otherwise default to the render batch. */722return &ice->batches[IRIS_BATCH_RENDER];723}724725726/**727* The pipe->resource_copy_region() driver hook.728*729* This implements ARB_copy_image semantics - a raw memory copy between730* compatible view classes.731*/732static void733iris_resource_copy_region(struct pipe_context *ctx,734struct pipe_resource *p_dst,735unsigned dst_level,736unsigned dstx, unsigned dsty, unsigned dstz,737struct pipe_resource *p_src,738unsigned src_level,739const struct pipe_box *src_box)740{741struct iris_context *ice = (void *) ctx;742struct iris_screen *screen = (void *) ctx->screen;743struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];744struct iris_resource *src = (void *) p_src;745struct iris_resource *dst = (void *) p_dst;746747if (iris_resource_unfinished_aux_import(src))748iris_resource_finish_aux_import(ctx->screen, src);749if (iris_resource_unfinished_aux_import(dst))750iris_resource_finish_aux_import(ctx->screen, dst);751752/* Use MI_COPY_MEM_MEM for tiny (<= 16 byte, % 4) buffer copies. */753if (p_src->target == PIPE_BUFFER && p_dst->target == PIPE_BUFFER &&754dstx % 4 == 0 && src_box->x % 4 == 0 &&755src_box->width % 4 == 0 && src_box->width <= 16) {756struct iris_bo *dst_bo = iris_resource_bo(p_dst);757batch = get_preferred_batch(ice, dst_bo);758iris_batch_maybe_flush(batch, 24 + 5 * (src_box->width / 4));759iris_emit_pipe_control_flush(batch,760"stall for MI_COPY_MEM_MEM copy_region",761PIPE_CONTROL_CS_STALL);762screen->vtbl.copy_mem_mem(batch, dst_bo, dstx, iris_resource_bo(p_src),763src_box->x, src_box->width);764return;765}766767iris_copy_region(&ice->blorp, batch, p_dst, dst_level, dstx, dsty, dstz,768p_src, src_level, src_box);769770if (util_format_is_depth_and_stencil(p_dst->format) &&771util_format_has_stencil(util_format_description(p_src->format))) {772struct iris_resource *junk, *s_src_res, *s_dst_res;773iris_get_depth_stencil_resources(p_src, &junk, &s_src_res);774iris_get_depth_stencil_resources(p_dst, &junk, &s_dst_res);775776iris_copy_region(&ice->blorp, batch, &s_dst_res->base.b, dst_level, dstx,777dsty, dstz, &s_src_res->base.b, src_level, src_box);778}779780iris_flush_and_dirty_for_history(ice, batch, dst,781PIPE_CONTROL_RENDER_TARGET_FLUSH,782"cache history: post copy_region");783}784785void786iris_init_blit_functions(struct pipe_context *ctx)787{788ctx->blit = iris_blit;789ctx->resource_copy_region = iris_resource_copy_region;790}791792793