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