101e04c3fSmrg/* 201e04c3fSmrg * Copyright 2014, 2015 Red Hat. 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub 801e04c3fSmrg * license, and/or sell copies of the Software, and to permit persons to whom 901e04c3fSmrg * the Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 1901e04c3fSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2001e04c3fSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2101e04c3fSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 2201e04c3fSmrg */ 237ec681f3Smrg#include "util/format/u_format.h" 2401e04c3fSmrg#include "util/u_inlines.h" 2501e04c3fSmrg#include "util/u_memory.h" 2601e04c3fSmrg 2701e04c3fSmrg#include "virgl_context.h" 287ec681f3Smrg#include "virgl_encode.h" 2901e04c3fSmrg#include "virgl_resource.h" 3001e04c3fSmrg#include "virgl_screen.h" 3101e04c3fSmrg 3201e04c3fSmrgstatic void virgl_copy_region_with_blit(struct pipe_context *pipe, 3301e04c3fSmrg struct pipe_resource *dst, 3401e04c3fSmrg unsigned dst_level, 359f464c52Smaya const struct pipe_box *dst_box, 3601e04c3fSmrg struct pipe_resource *src, 3701e04c3fSmrg unsigned src_level, 3801e04c3fSmrg const struct pipe_box *src_box) 3901e04c3fSmrg{ 4001e04c3fSmrg struct pipe_blit_info blit; 4101e04c3fSmrg 4201e04c3fSmrg memset(&blit, 0, sizeof(blit)); 4301e04c3fSmrg blit.src.resource = src; 4401e04c3fSmrg blit.src.format = src->format; 4501e04c3fSmrg blit.src.level = src_level; 4601e04c3fSmrg blit.src.box = *src_box; 4701e04c3fSmrg blit.dst.resource = dst; 4801e04c3fSmrg blit.dst.format = dst->format; 4901e04c3fSmrg blit.dst.level = dst_level; 509f464c52Smaya blit.dst.box.x = dst_box->x; 519f464c52Smaya blit.dst.box.y = dst_box->y; 529f464c52Smaya blit.dst.box.z = dst_box->z; 537ec681f3Smrg blit.dst.box.width = dst_box->width; 547ec681f3Smrg blit.dst.box.height = dst_box->height; 557ec681f3Smrg blit.dst.box.depth = dst_box->depth; 5601e04c3fSmrg blit.mask = util_format_get_mask(src->format) & 5701e04c3fSmrg util_format_get_mask(dst->format); 5801e04c3fSmrg blit.filter = PIPE_TEX_FILTER_NEAREST; 5901e04c3fSmrg 6001e04c3fSmrg if (blit.mask) { 6101e04c3fSmrg pipe->blit(pipe, &blit); 6201e04c3fSmrg } 6301e04c3fSmrg} 649f464c52Smaya 659f464c52Smayastatic unsigned temp_bind(unsigned orig) 669f464c52Smaya{ 679f464c52Smaya unsigned warn = ~(PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL | 689f464c52Smaya PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET); 699f464c52Smaya if (orig & warn) 709f464c52Smaya debug_printf("VIRGL: Warning, possibly unhandled bind: %x\n", 719f464c52Smaya orig & warn); 729f464c52Smaya 739f464c52Smaya return orig & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET); 749f464c52Smaya} 759f464c52Smaya 7601e04c3fSmrgstatic void virgl_init_temp_resource_from_box(struct pipe_resource *res, 7701e04c3fSmrg struct pipe_resource *orig, 7801e04c3fSmrg const struct pipe_box *box, 799f464c52Smaya unsigned level, unsigned flags, 809f464c52Smaya enum pipe_format fmt) 8101e04c3fSmrg{ 8201e04c3fSmrg memset(res, 0, sizeof(*res)); 839f464c52Smaya res->bind = temp_bind(orig->bind); 849f464c52Smaya res->format = fmt; 8501e04c3fSmrg res->width0 = box->width; 8601e04c3fSmrg res->height0 = box->height; 8701e04c3fSmrg res->depth0 = 1; 8801e04c3fSmrg res->array_size = 1; 8901e04c3fSmrg res->usage = PIPE_USAGE_STAGING; 9001e04c3fSmrg res->flags = flags; 9101e04c3fSmrg 9201e04c3fSmrg /* We must set the correct texture target and dimensions for a 3D box. */ 9301e04c3fSmrg if (box->depth > 1 && util_max_layer(orig, level) > 0) 9401e04c3fSmrg res->target = orig->target; 9501e04c3fSmrg else 9601e04c3fSmrg res->target = PIPE_TEXTURE_2D; 9701e04c3fSmrg 989f464c52Smaya if (res->target != PIPE_BUFFER) 999f464c52Smaya res->bind = PIPE_BIND_RENDER_TARGET; 1009f464c52Smaya 10101e04c3fSmrg switch (res->target) { 10201e04c3fSmrg case PIPE_TEXTURE_1D_ARRAY: 10301e04c3fSmrg case PIPE_TEXTURE_2D_ARRAY: 10401e04c3fSmrg case PIPE_TEXTURE_CUBE_ARRAY: 10501e04c3fSmrg res->array_size = box->depth; 10601e04c3fSmrg break; 10701e04c3fSmrg case PIPE_TEXTURE_3D: 10801e04c3fSmrg res->depth0 = box->depth; 10901e04c3fSmrg break; 11001e04c3fSmrg default: 11101e04c3fSmrg break; 11201e04c3fSmrg } 11301e04c3fSmrg} 11401e04c3fSmrg 1159f464c52Smayastatic void *texture_transfer_map_resolve(struct pipe_context *ctx, 1169f464c52Smaya struct pipe_resource *resource, 1179f464c52Smaya unsigned level, 1189f464c52Smaya unsigned usage, 1199f464c52Smaya const struct pipe_box *box, 1209f464c52Smaya struct pipe_transfer **transfer) 12101e04c3fSmrg{ 12201e04c3fSmrg struct virgl_context *vctx = virgl_context(ctx); 1239f464c52Smaya struct virgl_resource *vtex = virgl_resource(resource); 1249f464c52Smaya struct pipe_resource templ, *resolve_tmp; 1259f464c52Smaya struct virgl_transfer *trans; 12601e04c3fSmrg 1277ec681f3Smrg trans = virgl_resource_create_transfer(vctx, resource, 1289f464c52Smaya &vtex->metadata, level, usage, box); 1299f464c52Smaya if (!trans) 1309f464c52Smaya return NULL; 13101e04c3fSmrg 1329f464c52Smaya enum pipe_format fmt = resource->format; 1337ec681f3Smrg if (!virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt))) { 1349f464c52Smaya if (util_format_fits_8unorm(util_format_description(fmt))) 1359f464c52Smaya fmt = PIPE_FORMAT_R8G8B8A8_UNORM; 1369f464c52Smaya else if (util_format_is_pure_sint(fmt)) 1379f464c52Smaya fmt = PIPE_FORMAT_R32G32B32A32_SINT; 1389f464c52Smaya else if (util_format_is_pure_uint(fmt)) 1399f464c52Smaya fmt = PIPE_FORMAT_R32G32B32A32_UINT; 1409f464c52Smaya else 1419f464c52Smaya fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; 1427ec681f3Smrg assert(virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt))); 14301e04c3fSmrg } 14401e04c3fSmrg 1457ec681f3Smrg struct pipe_box dst_box = *box; 1467ec681f3Smrg dst_box.x = dst_box.y = dst_box.z = 0; 1477ec681f3Smrg if (usage & PIPE_MAP_READ) { 1487ec681f3Smrg /* readback should scale to the block size */ 1497ec681f3Smrg dst_box.width = align(dst_box.width, 1507ec681f3Smrg util_format_get_blockwidth(resource->format)); 1517ec681f3Smrg dst_box.height = align(dst_box.height, 1527ec681f3Smrg util_format_get_blockheight(resource->format)); 1537ec681f3Smrg } 1547ec681f3Smrg 1557ec681f3Smrg virgl_init_temp_resource_from_box(&templ, resource, &dst_box, level, 0, fmt); 15601e04c3fSmrg 1579f464c52Smaya resolve_tmp = ctx->screen->resource_create(ctx->screen, &templ); 1589f464c52Smaya if (!resolve_tmp) 1599f464c52Smaya return NULL; 16001e04c3fSmrg 1617ec681f3Smrg if (usage & PIPE_MAP_READ) { 1629f464c52Smaya virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource, 1639f464c52Smaya level, box); 1649f464c52Smaya ctx->flush(ctx, NULL, 0); 1659f464c52Smaya } 16601e04c3fSmrg 1677ec681f3Smrg void *ptr = virgl_resource_transfer_map(ctx, resolve_tmp, 0, usage, &dst_box, 1687ec681f3Smrg &trans->resolve_transfer); 1699f464c52Smaya if (!ptr) 1709f464c52Smaya goto fail; 17101e04c3fSmrg 1727ec681f3Smrg /* trans->resolve_transfer owns resolve_tmp now */ 1737ec681f3Smrg pipe_resource_reference(&resolve_tmp, NULL); 1747ec681f3Smrg 1759f464c52Smaya *transfer = &trans->base; 1769f464c52Smaya if (fmt == resource->format) { 1779f464c52Smaya trans->base.stride = trans->resolve_transfer->stride; 1789f464c52Smaya trans->base.layer_stride = trans->resolve_transfer->layer_stride; 1799f464c52Smaya return ptr; 1809f464c52Smaya } else { 1817ec681f3Smrg if (usage & PIPE_MAP_READ) { 1829f464c52Smaya struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; 1839f464c52Smaya void *src = ptr; 1849f464c52Smaya ptr = vws->resource_map(vws, vtex->hw_res); 1859f464c52Smaya if (!ptr) 1869f464c52Smaya goto fail; 1879f464c52Smaya 1887ec681f3Smrg if (!util_format_translate_3d(resource->format, 1897ec681f3Smrg ptr + vtex->metadata.level_offset[level], 1909f464c52Smaya trans->base.stride, 1919f464c52Smaya trans->base.layer_stride, 1929f464c52Smaya box->x, box->y, box->z, 1939f464c52Smaya fmt, 1949f464c52Smaya src, 1959f464c52Smaya trans->resolve_transfer->stride, 1969f464c52Smaya trans->resolve_transfer->layer_stride, 1979f464c52Smaya 0, 0, 0, 1987ec681f3Smrg dst_box.width, 1997ec681f3Smrg dst_box.height, 2007ec681f3Smrg dst_box.depth)) { 2019f464c52Smaya debug_printf("failed to translate format %s to %s\n", 2029f464c52Smaya util_format_short_name(fmt), 2039f464c52Smaya util_format_short_name(resource->format)); 2049f464c52Smaya goto fail; 2059f464c52Smaya } 2069f464c52Smaya } 20701e04c3fSmrg 2087ec681f3Smrg if ((usage & PIPE_MAP_WRITE) == 0) 2099f464c52Smaya pipe_resource_reference(&trans->resolve_transfer->resource, NULL); 2109f464c52Smaya 2119f464c52Smaya return ptr + trans->offset; 21201e04c3fSmrg } 21301e04c3fSmrg 2149f464c52Smayafail: 2159f464c52Smaya pipe_resource_reference(&resolve_tmp, NULL); 2167ec681f3Smrg virgl_resource_destroy_transfer(vctx, trans); 2179f464c52Smaya return NULL; 2189f464c52Smaya} 2199f464c52Smaya 2209f464c52Smayastatic bool needs_resolve(struct pipe_screen *screen, 2219f464c52Smaya struct pipe_resource *resource, unsigned usage) 2229f464c52Smaya{ 2239f464c52Smaya if (resource->nr_samples > 1) 2249f464c52Smaya return true; 2259f464c52Smaya 2267ec681f3Smrg if (usage & PIPE_MAP_READ) 2279f464c52Smaya return !util_format_is_depth_or_stencil(resource->format) && 2287ec681f3Smrg !virgl_has_readback_format(screen, pipe_to_virgl_format(resource->format)); 2299f464c52Smaya 2309f464c52Smaya return false; 23101e04c3fSmrg} 23201e04c3fSmrg 2337ec681f3Smrgvoid *virgl_texture_transfer_map(struct pipe_context *ctx, 2347ec681f3Smrg struct pipe_resource *resource, 2357ec681f3Smrg unsigned level, 2367ec681f3Smrg unsigned usage, 2377ec681f3Smrg const struct pipe_box *box, 2387ec681f3Smrg struct pipe_transfer **transfer) 23901e04c3fSmrg{ 2409f464c52Smaya if (needs_resolve(ctx->screen, resource, usage)) 2419f464c52Smaya return texture_transfer_map_resolve(ctx, resource, level, usage, box, 2429f464c52Smaya transfer); 24301e04c3fSmrg 2447ec681f3Smrg return virgl_resource_transfer_map(ctx, resource, level, usage, box, transfer); 24501e04c3fSmrg} 24601e04c3fSmrg 2479f464c52Smayastatic void flush_data(struct pipe_context *ctx, 2489f464c52Smaya struct virgl_transfer *trans, 2499f464c52Smaya const struct pipe_box *box) 25001e04c3fSmrg{ 2519f464c52Smaya struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; 2527ec681f3Smrg vws->transfer_put(vws, trans->hw_res, box, 2539f464c52Smaya trans->base.stride, trans->l_stride, trans->offset, 2549f464c52Smaya trans->base.level); 2559f464c52Smaya} 2569f464c52Smaya 2577ec681f3Smrgvoid virgl_texture_transfer_unmap(struct pipe_context *ctx, 2587ec681f3Smrg struct pipe_transfer *transfer) 2599f464c52Smaya{ 2609f464c52Smaya struct virgl_context *vctx = virgl_context(ctx); 2619f464c52Smaya struct virgl_transfer *trans = virgl_transfer(transfer); 2629f464c52Smaya bool queue_unmap = false; 2639f464c52Smaya 2647ec681f3Smrg if (transfer->usage & PIPE_MAP_WRITE && 2657ec681f3Smrg (transfer->usage & PIPE_MAP_FLUSH_EXPLICIT) == 0) { 2669f464c52Smaya 2679f464c52Smaya if (trans->resolve_transfer && (trans->base.resource->format == 2689f464c52Smaya trans->resolve_transfer->resource->format)) { 2699f464c52Smaya flush_data(ctx, virgl_transfer(trans->resolve_transfer), 2709f464c52Smaya &trans->resolve_transfer->box); 2719f464c52Smaya 2729f464c52Smaya /* FINISHME: In case the destination format isn't renderable here, the 2739f464c52Smaya * blit here will currently fail. This could for instance happen if the 2749f464c52Smaya * mapped resource is of a compressed format, and it's mapped with both 2759f464c52Smaya * read and write usage. 2769f464c52Smaya */ 2779f464c52Smaya 2789f464c52Smaya virgl_copy_region_with_blit(ctx, 2799f464c52Smaya trans->base.resource, trans->base.level, 2809f464c52Smaya &transfer->box, 2819f464c52Smaya trans->resolve_transfer->resource, 0, 2829f464c52Smaya &trans->resolve_transfer->box); 2839f464c52Smaya ctx->flush(ctx, NULL, 0); 2849f464c52Smaya } else 2859f464c52Smaya queue_unmap = true; 2869f464c52Smaya } 2879f464c52Smaya 2889f464c52Smaya if (trans->resolve_transfer) { 2897ec681f3Smrg virgl_resource_destroy_transfer(vctx, 2909f464c52Smaya virgl_transfer(trans->resolve_transfer)); 2919f464c52Smaya } 2929f464c52Smaya 2937ec681f3Smrg if (queue_unmap) { 2947ec681f3Smrg if (trans->copy_src_hw_res) { 2957ec681f3Smrg virgl_encode_copy_transfer(vctx, trans); 2967ec681f3Smrg virgl_resource_destroy_transfer(vctx, trans); 2977ec681f3Smrg } else { 2987ec681f3Smrg virgl_transfer_queue_unmap(&vctx->queue, trans); 2997ec681f3Smrg } 3007ec681f3Smrg } else { 3017ec681f3Smrg virgl_resource_destroy_transfer(vctx, trans); 3027ec681f3Smrg } 30301e04c3fSmrg} 30401e04c3fSmrg 3059f464c52Smayavoid virgl_texture_init(struct virgl_resource *res) 30601e04c3fSmrg{ 30701e04c3fSmrg} 308