1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2014, 2015 Red Hat. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci#include "util/format/u_format.h" 24bf215546Sopenharmony_ci#include "util/u_inlines.h" 25bf215546Sopenharmony_ci#include "util/u_memory.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "virgl_context.h" 28bf215546Sopenharmony_ci#include "virgl_encode.h" 29bf215546Sopenharmony_ci#include "virgl_resource.h" 30bf215546Sopenharmony_ci#include "virgl_screen.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_cistatic void virgl_copy_region_with_blit(struct pipe_context *pipe, 33bf215546Sopenharmony_ci struct pipe_resource *dst, 34bf215546Sopenharmony_ci unsigned dst_level, 35bf215546Sopenharmony_ci const struct pipe_box *dst_box, 36bf215546Sopenharmony_ci struct pipe_resource *src, 37bf215546Sopenharmony_ci unsigned src_level, 38bf215546Sopenharmony_ci const struct pipe_box *src_box) 39bf215546Sopenharmony_ci{ 40bf215546Sopenharmony_ci struct pipe_blit_info blit; 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci memset(&blit, 0, sizeof(blit)); 43bf215546Sopenharmony_ci blit.src.resource = src; 44bf215546Sopenharmony_ci blit.src.format = src->format; 45bf215546Sopenharmony_ci blit.src.level = src_level; 46bf215546Sopenharmony_ci blit.src.box = *src_box; 47bf215546Sopenharmony_ci blit.dst.resource = dst; 48bf215546Sopenharmony_ci blit.dst.format = dst->format; 49bf215546Sopenharmony_ci blit.dst.level = dst_level; 50bf215546Sopenharmony_ci blit.dst.box.x = dst_box->x; 51bf215546Sopenharmony_ci blit.dst.box.y = dst_box->y; 52bf215546Sopenharmony_ci blit.dst.box.z = dst_box->z; 53bf215546Sopenharmony_ci blit.dst.box.width = dst_box->width; 54bf215546Sopenharmony_ci blit.dst.box.height = dst_box->height; 55bf215546Sopenharmony_ci blit.dst.box.depth = dst_box->depth; 56bf215546Sopenharmony_ci blit.mask = util_format_get_mask(src->format) & 57bf215546Sopenharmony_ci util_format_get_mask(dst->format); 58bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci if (blit.mask) { 61bf215546Sopenharmony_ci pipe->blit(pipe, &blit); 62bf215546Sopenharmony_ci } 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistatic unsigned temp_bind(unsigned orig) 66bf215546Sopenharmony_ci{ 67bf215546Sopenharmony_ci unsigned warn = ~(PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL | 68bf215546Sopenharmony_ci PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET); 69bf215546Sopenharmony_ci if (orig & warn) 70bf215546Sopenharmony_ci debug_printf("VIRGL: Warning, possibly unhandled bind: %x\n", 71bf215546Sopenharmony_ci orig & warn); 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci return orig & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET); 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic void virgl_init_temp_resource_from_box(struct pipe_resource *res, 77bf215546Sopenharmony_ci struct pipe_resource *orig, 78bf215546Sopenharmony_ci const struct pipe_box *box, 79bf215546Sopenharmony_ci unsigned level, unsigned flags, 80bf215546Sopenharmony_ci enum pipe_format fmt) 81bf215546Sopenharmony_ci{ 82bf215546Sopenharmony_ci memset(res, 0, sizeof(*res)); 83bf215546Sopenharmony_ci res->bind = temp_bind(orig->bind); 84bf215546Sopenharmony_ci res->format = fmt; 85bf215546Sopenharmony_ci res->width0 = box->width; 86bf215546Sopenharmony_ci res->height0 = box->height; 87bf215546Sopenharmony_ci res->depth0 = 1; 88bf215546Sopenharmony_ci res->array_size = 1; 89bf215546Sopenharmony_ci res->usage = PIPE_USAGE_STAGING; 90bf215546Sopenharmony_ci res->flags = flags; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci /* We must set the correct texture target and dimensions for a 3D box. */ 93bf215546Sopenharmony_ci if (box->depth > 1 && util_max_layer(orig, level) > 0) 94bf215546Sopenharmony_ci res->target = orig->target; 95bf215546Sopenharmony_ci else 96bf215546Sopenharmony_ci res->target = PIPE_TEXTURE_2D; 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (res->target != PIPE_BUFFER) 99bf215546Sopenharmony_ci res->bind = PIPE_BIND_RENDER_TARGET; 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci switch (res->target) { 102bf215546Sopenharmony_ci case PIPE_TEXTURE_1D_ARRAY: 103bf215546Sopenharmony_ci case PIPE_TEXTURE_2D_ARRAY: 104bf215546Sopenharmony_ci case PIPE_TEXTURE_CUBE_ARRAY: 105bf215546Sopenharmony_ci res->array_size = box->depth; 106bf215546Sopenharmony_ci break; 107bf215546Sopenharmony_ci case PIPE_TEXTURE_3D: 108bf215546Sopenharmony_ci res->depth0 = box->depth; 109bf215546Sopenharmony_ci break; 110bf215546Sopenharmony_ci default: 111bf215546Sopenharmony_ci break; 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic void *texture_transfer_map_resolve(struct pipe_context *ctx, 116bf215546Sopenharmony_ci struct pipe_resource *resource, 117bf215546Sopenharmony_ci unsigned level, 118bf215546Sopenharmony_ci unsigned usage, 119bf215546Sopenharmony_ci const struct pipe_box *box, 120bf215546Sopenharmony_ci struct pipe_transfer **transfer) 121bf215546Sopenharmony_ci{ 122bf215546Sopenharmony_ci struct virgl_context *vctx = virgl_context(ctx); 123bf215546Sopenharmony_ci struct virgl_resource *vtex = virgl_resource(resource); 124bf215546Sopenharmony_ci struct pipe_resource templ, *resolve_tmp; 125bf215546Sopenharmony_ci struct virgl_transfer *trans; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci trans = virgl_resource_create_transfer(vctx, resource, 128bf215546Sopenharmony_ci &vtex->metadata, level, usage, box); 129bf215546Sopenharmony_ci if (!trans) 130bf215546Sopenharmony_ci return NULL; 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci enum pipe_format fmt = resource->format; 133bf215546Sopenharmony_ci if (!virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt), true)) { 134bf215546Sopenharmony_ci if (util_format_fits_8unorm(util_format_description(fmt))) 135bf215546Sopenharmony_ci fmt = PIPE_FORMAT_R8G8B8A8_UNORM; 136bf215546Sopenharmony_ci else if (util_format_is_pure_sint(fmt)) 137bf215546Sopenharmony_ci fmt = PIPE_FORMAT_R32G32B32A32_SINT; 138bf215546Sopenharmony_ci else if (util_format_is_pure_uint(fmt)) 139bf215546Sopenharmony_ci fmt = PIPE_FORMAT_R32G32B32A32_UINT; 140bf215546Sopenharmony_ci else 141bf215546Sopenharmony_ci fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; 142bf215546Sopenharmony_ci assert(virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt), true)); 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci struct pipe_box dst_box = *box; 146bf215546Sopenharmony_ci dst_box.x = dst_box.y = dst_box.z = 0; 147bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 148bf215546Sopenharmony_ci /* readback should scale to the block size */ 149bf215546Sopenharmony_ci dst_box.width = align(dst_box.width, 150bf215546Sopenharmony_ci util_format_get_blockwidth(resource->format)); 151bf215546Sopenharmony_ci dst_box.height = align(dst_box.height, 152bf215546Sopenharmony_ci util_format_get_blockheight(resource->format)); 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci virgl_init_temp_resource_from_box(&templ, resource, &dst_box, level, 0, fmt); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci resolve_tmp = ctx->screen->resource_create(ctx->screen, &templ); 158bf215546Sopenharmony_ci if (!resolve_tmp) 159bf215546Sopenharmony_ci return NULL; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 162bf215546Sopenharmony_ci virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource, 163bf215546Sopenharmony_ci level, box); 164bf215546Sopenharmony_ci ctx->flush(ctx, NULL, 0); 165bf215546Sopenharmony_ci } 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci void *ptr = virgl_resource_transfer_map(ctx, resolve_tmp, 0, usage, &dst_box, 168bf215546Sopenharmony_ci &trans->resolve_transfer); 169bf215546Sopenharmony_ci if (!ptr) 170bf215546Sopenharmony_ci goto fail; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci /* trans->resolve_transfer owns resolve_tmp now */ 173bf215546Sopenharmony_ci pipe_resource_reference(&resolve_tmp, NULL); 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci *transfer = &trans->base; 176bf215546Sopenharmony_ci if (fmt == resource->format) { 177bf215546Sopenharmony_ci trans->base.stride = trans->resolve_transfer->stride; 178bf215546Sopenharmony_ci trans->base.layer_stride = trans->resolve_transfer->layer_stride; 179bf215546Sopenharmony_ci return ptr; 180bf215546Sopenharmony_ci } else { 181bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 182bf215546Sopenharmony_ci struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; 183bf215546Sopenharmony_ci void *src = ptr; 184bf215546Sopenharmony_ci ptr = vws->resource_map(vws, vtex->hw_res); 185bf215546Sopenharmony_ci if (!ptr) 186bf215546Sopenharmony_ci goto fail; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (!util_format_translate_3d(resource->format, 189bf215546Sopenharmony_ci ptr + vtex->metadata.level_offset[level], 190bf215546Sopenharmony_ci trans->base.stride, 191bf215546Sopenharmony_ci trans->base.layer_stride, 192bf215546Sopenharmony_ci box->x, box->y, box->z, 193bf215546Sopenharmony_ci fmt, 194bf215546Sopenharmony_ci src, 195bf215546Sopenharmony_ci trans->resolve_transfer->stride, 196bf215546Sopenharmony_ci trans->resolve_transfer->layer_stride, 197bf215546Sopenharmony_ci 0, 0, 0, 198bf215546Sopenharmony_ci dst_box.width, 199bf215546Sopenharmony_ci dst_box.height, 200bf215546Sopenharmony_ci dst_box.depth)) { 201bf215546Sopenharmony_ci debug_printf("failed to translate format %s to %s\n", 202bf215546Sopenharmony_ci util_format_short_name(fmt), 203bf215546Sopenharmony_ci util_format_short_name(resource->format)); 204bf215546Sopenharmony_ci goto fail; 205bf215546Sopenharmony_ci } 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci if ((usage & PIPE_MAP_WRITE) == 0) 209bf215546Sopenharmony_ci pipe_resource_reference(&trans->resolve_transfer->resource, NULL); 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci return ptr + trans->offset; 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cifail: 215bf215546Sopenharmony_ci pipe_resource_reference(&resolve_tmp, NULL); 216bf215546Sopenharmony_ci virgl_resource_destroy_transfer(vctx, trans); 217bf215546Sopenharmony_ci return NULL; 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_cistatic bool needs_resolve(struct pipe_screen *screen, 221bf215546Sopenharmony_ci struct pipe_resource *resource, unsigned usage) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci if (resource->nr_samples > 1) 224bf215546Sopenharmony_ci return true; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) 227bf215546Sopenharmony_ci return !util_format_is_depth_or_stencil(resource->format) && 228bf215546Sopenharmony_ci !virgl_has_readback_format(screen, pipe_to_virgl_format(resource->format), true); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci return false; 231bf215546Sopenharmony_ci} 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_civoid *virgl_texture_transfer_map(struct pipe_context *ctx, 234bf215546Sopenharmony_ci struct pipe_resource *resource, 235bf215546Sopenharmony_ci unsigned level, 236bf215546Sopenharmony_ci unsigned usage, 237bf215546Sopenharmony_ci const struct pipe_box *box, 238bf215546Sopenharmony_ci struct pipe_transfer **transfer) 239bf215546Sopenharmony_ci{ 240bf215546Sopenharmony_ci if (needs_resolve(ctx->screen, resource, usage)) 241bf215546Sopenharmony_ci return texture_transfer_map_resolve(ctx, resource, level, usage, box, 242bf215546Sopenharmony_ci transfer); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci return virgl_resource_transfer_map(ctx, resource, level, usage, box, transfer); 245bf215546Sopenharmony_ci} 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_cistatic void flush_data(struct pipe_context *ctx, 248bf215546Sopenharmony_ci struct virgl_transfer *trans, 249bf215546Sopenharmony_ci const struct pipe_box *box) 250bf215546Sopenharmony_ci{ 251bf215546Sopenharmony_ci struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; 252bf215546Sopenharmony_ci vws->transfer_put(vws, trans->hw_res, box, 253bf215546Sopenharmony_ci trans->base.stride, trans->l_stride, trans->offset, 254bf215546Sopenharmony_ci trans->base.level); 255bf215546Sopenharmony_ci} 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_civoid virgl_texture_transfer_unmap(struct pipe_context *ctx, 258bf215546Sopenharmony_ci struct pipe_transfer *transfer) 259bf215546Sopenharmony_ci{ 260bf215546Sopenharmony_ci struct virgl_context *vctx = virgl_context(ctx); 261bf215546Sopenharmony_ci struct virgl_transfer *trans = virgl_transfer(transfer); 262bf215546Sopenharmony_ci bool queue_unmap = false; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE && 265bf215546Sopenharmony_ci (transfer->usage & PIPE_MAP_FLUSH_EXPLICIT) == 0) { 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci if (trans->resolve_transfer && (trans->base.resource->format == 268bf215546Sopenharmony_ci trans->resolve_transfer->resource->format)) { 269bf215546Sopenharmony_ci flush_data(ctx, virgl_transfer(trans->resolve_transfer), 270bf215546Sopenharmony_ci &trans->resolve_transfer->box); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci /* FINISHME: In case the destination format isn't renderable here, the 273bf215546Sopenharmony_ci * blit here will currently fail. This could for instance happen if the 274bf215546Sopenharmony_ci * mapped resource is of a compressed format, and it's mapped with both 275bf215546Sopenharmony_ci * read and write usage. 276bf215546Sopenharmony_ci */ 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci virgl_copy_region_with_blit(ctx, 279bf215546Sopenharmony_ci trans->base.resource, trans->base.level, 280bf215546Sopenharmony_ci &transfer->box, 281bf215546Sopenharmony_ci trans->resolve_transfer->resource, 0, 282bf215546Sopenharmony_ci &trans->resolve_transfer->box); 283bf215546Sopenharmony_ci ctx->flush(ctx, NULL, 0); 284bf215546Sopenharmony_ci } else 285bf215546Sopenharmony_ci queue_unmap = true; 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci if (trans->resolve_transfer) { 289bf215546Sopenharmony_ci virgl_resource_destroy_transfer(vctx, 290bf215546Sopenharmony_ci virgl_transfer(trans->resolve_transfer)); 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci if (queue_unmap) { 294bf215546Sopenharmony_ci if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_TO_HOST) { 295bf215546Sopenharmony_ci virgl_encode_copy_transfer(vctx, trans); 296bf215546Sopenharmony_ci virgl_resource_destroy_transfer(vctx, trans); 297bf215546Sopenharmony_ci } else if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_FROM_HOST) { 298bf215546Sopenharmony_ci // if it is readback, then we have already encoded transfer 299bf215546Sopenharmony_ci virgl_resource_destroy_transfer(vctx, trans); 300bf215546Sopenharmony_ci } else { 301bf215546Sopenharmony_ci virgl_transfer_queue_unmap(&vctx->queue, trans); 302bf215546Sopenharmony_ci } 303bf215546Sopenharmony_ci } else { 304bf215546Sopenharmony_ci virgl_resource_destroy_transfer(vctx, trans); 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci} 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_civoid virgl_texture_init(struct virgl_resource *res) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci} 311