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#include "virgl_context.h" 27b8e80941Smrg#include "virgl_resource.h" 28b8e80941Smrg#include "virgl_screen.h" 29b8e80941Smrg 30b8e80941Smrgbool virgl_res_needs_flush(struct virgl_context *vctx, 31b8e80941Smrg struct virgl_transfer *trans) 32b8e80941Smrg{ 33b8e80941Smrg struct virgl_screen *vs = virgl_screen(vctx->base.screen); 34b8e80941Smrg struct virgl_resource *res = virgl_resource(trans->base.resource); 35b8e80941Smrg 36b8e80941Smrg if (trans->base.usage & PIPE_TRANSFER_UNSYNCHRONIZED) 37b8e80941Smrg return false; 38b8e80941Smrg if (!vs->vws->res_is_referenced(vs->vws, vctx->cbuf, res->hw_res)) 39b8e80941Smrg return false; 40b8e80941Smrg if (res->clean_mask & (1 << trans->base.level)) { 41b8e80941Smrg if (vctx->num_draws == 0 && vctx->num_compute == 0) 42b8e80941Smrg return false; 43b8e80941Smrg if (!virgl_transfer_queue_is_queued(&vctx->queue, trans)) 44b8e80941Smrg return false; 45b8e80941Smrg } 46b8e80941Smrg 47b8e80941Smrg return true; 48b8e80941Smrg} 49b8e80941Smrg 50b8e80941Smrgbool virgl_res_needs_readback(struct virgl_context *vctx, 51b8e80941Smrg struct virgl_resource *res, 52b8e80941Smrg unsigned usage, unsigned level) 53b8e80941Smrg{ 54b8e80941Smrg bool readback = true; 55b8e80941Smrg if (res->clean_mask & (1 << level)) 56b8e80941Smrg readback = false; 57b8e80941Smrg else if (usage & PIPE_TRANSFER_DISCARD_RANGE) 58b8e80941Smrg readback = false; 59b8e80941Smrg else if ((usage & (PIPE_TRANSFER_WRITE | PIPE_TRANSFER_FLUSH_EXPLICIT)) == 60b8e80941Smrg (PIPE_TRANSFER_WRITE | PIPE_TRANSFER_FLUSH_EXPLICIT)) 61b8e80941Smrg readback = false; 62b8e80941Smrg return readback; 63b8e80941Smrg} 64b8e80941Smrg 65b8e80941Smrgstatic struct pipe_resource *virgl_resource_create(struct pipe_screen *screen, 66b8e80941Smrg const struct pipe_resource *templ) 67b8e80941Smrg{ 68b8e80941Smrg unsigned vbind; 69b8e80941Smrg struct virgl_screen *vs = virgl_screen(screen); 70b8e80941Smrg struct virgl_resource *res = CALLOC_STRUCT(virgl_resource); 71b8e80941Smrg 72b8e80941Smrg res->u.b = *templ; 73b8e80941Smrg res->u.b.screen = &vs->base; 74b8e80941Smrg pipe_reference_init(&res->u.b.reference, 1); 75b8e80941Smrg vbind = pipe_to_virgl_bind(vs, templ->bind); 76b8e80941Smrg virgl_resource_layout(&res->u.b, &res->metadata); 77b8e80941Smrg res->hw_res = vs->vws->resource_create(vs->vws, templ->target, 78b8e80941Smrg templ->format, vbind, 79b8e80941Smrg templ->width0, 80b8e80941Smrg templ->height0, 81b8e80941Smrg templ->depth0, 82b8e80941Smrg templ->array_size, 83b8e80941Smrg templ->last_level, 84b8e80941Smrg templ->nr_samples, 85b8e80941Smrg res->metadata.total_size); 86b8e80941Smrg if (!res->hw_res) { 87b8e80941Smrg FREE(res); 88b8e80941Smrg return NULL; 89b8e80941Smrg } 90b8e80941Smrg 91b8e80941Smrg res->clean_mask = (1 << VR_MAX_TEXTURE_2D_LEVELS) - 1; 92b8e80941Smrg 93b8e80941Smrg if (templ->target == PIPE_BUFFER) 94b8e80941Smrg virgl_buffer_init(res); 95b8e80941Smrg else 96b8e80941Smrg virgl_texture_init(res); 97b8e80941Smrg 98b8e80941Smrg return &res->u.b; 99b8e80941Smrg 100b8e80941Smrg} 101b8e80941Smrg 102b8e80941Smrgstatic struct pipe_resource *virgl_resource_from_handle(struct pipe_screen *screen, 103b8e80941Smrg const struct pipe_resource *templ, 104b8e80941Smrg struct winsys_handle *whandle, 105b8e80941Smrg unsigned usage) 106b8e80941Smrg{ 107b8e80941Smrg struct virgl_screen *vs = virgl_screen(screen); 108b8e80941Smrg if (templ->target == PIPE_BUFFER) 109b8e80941Smrg return NULL; 110b8e80941Smrg 111b8e80941Smrg struct virgl_resource *res = CALLOC_STRUCT(virgl_resource); 112b8e80941Smrg res->u.b = *templ; 113b8e80941Smrg res->u.b.screen = &vs->base; 114b8e80941Smrg pipe_reference_init(&res->u.b.reference, 1); 115b8e80941Smrg virgl_resource_layout(&res->u.b, &res->metadata); 116b8e80941Smrg 117b8e80941Smrg res->hw_res = vs->vws->resource_create_from_handle(vs->vws, whandle); 118b8e80941Smrg if (!res->hw_res) { 119b8e80941Smrg FREE(res); 120b8e80941Smrg return NULL; 121b8e80941Smrg } 122b8e80941Smrg 123b8e80941Smrg virgl_texture_init(res); 124b8e80941Smrg 125b8e80941Smrg return &res->u.b; 126b8e80941Smrg} 127b8e80941Smrg 128b8e80941Smrgvoid virgl_init_screen_resource_functions(struct pipe_screen *screen) 129b8e80941Smrg{ 130b8e80941Smrg screen->resource_create = virgl_resource_create; 131b8e80941Smrg screen->resource_from_handle = virgl_resource_from_handle; 132b8e80941Smrg screen->resource_get_handle = u_resource_get_handle_vtbl; 133b8e80941Smrg screen->resource_destroy = u_resource_destroy_vtbl; 134b8e80941Smrg} 135b8e80941Smrg 136b8e80941Smrgstatic bool virgl_buffer_transfer_extend(struct pipe_context *ctx, 137b8e80941Smrg struct pipe_resource *resource, 138b8e80941Smrg unsigned usage, 139b8e80941Smrg const struct pipe_box *box, 140b8e80941Smrg const void *data) 141b8e80941Smrg{ 142b8e80941Smrg struct virgl_context *vctx = virgl_context(ctx); 143b8e80941Smrg struct virgl_resource *vbuf = virgl_resource(resource); 144b8e80941Smrg struct virgl_transfer dummy_trans = { 0 }; 145b8e80941Smrg bool flush; 146b8e80941Smrg struct virgl_transfer *queued; 147b8e80941Smrg 148b8e80941Smrg /* 149b8e80941Smrg * Attempts to short circuit the entire process of mapping and unmapping 150b8e80941Smrg * a resource if there is an existing transfer that can be extended. 151b8e80941Smrg * Pessimestically falls back if a flush is required. 152b8e80941Smrg */ 153b8e80941Smrg dummy_trans.base.resource = resource; 154b8e80941Smrg dummy_trans.base.usage = usage; 155b8e80941Smrg dummy_trans.base.box = *box; 156b8e80941Smrg dummy_trans.base.stride = vbuf->metadata.stride[0]; 157b8e80941Smrg dummy_trans.base.layer_stride = vbuf->metadata.layer_stride[0]; 158b8e80941Smrg dummy_trans.offset = box->x; 159b8e80941Smrg 160b8e80941Smrg flush = virgl_res_needs_flush(vctx, &dummy_trans); 161b8e80941Smrg if (flush) 162b8e80941Smrg return false; 163b8e80941Smrg 164b8e80941Smrg queued = virgl_transfer_queue_extend(&vctx->queue, &dummy_trans); 165b8e80941Smrg if (!queued || !queued->hw_res_map) 166b8e80941Smrg return false; 167b8e80941Smrg 168b8e80941Smrg memcpy(queued->hw_res_map + dummy_trans.offset, data, box->width); 169b8e80941Smrg 170b8e80941Smrg return true; 171b8e80941Smrg} 172b8e80941Smrg 173b8e80941Smrgstatic void virgl_buffer_subdata(struct pipe_context *pipe, 174b8e80941Smrg struct pipe_resource *resource, 175b8e80941Smrg unsigned usage, unsigned offset, 176b8e80941Smrg unsigned size, const void *data) 177b8e80941Smrg{ 178b8e80941Smrg struct pipe_box box; 179b8e80941Smrg 180b8e80941Smrg assert(!(usage & PIPE_TRANSFER_READ)); 181b8e80941Smrg 182b8e80941Smrg /* the write flag is implicit by the nature of buffer_subdata */ 183b8e80941Smrg usage |= PIPE_TRANSFER_WRITE; 184b8e80941Smrg 185b8e80941Smrg if (offset == 0 && size == resource->width0) 186b8e80941Smrg usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 187b8e80941Smrg else 188b8e80941Smrg usage |= PIPE_TRANSFER_DISCARD_RANGE; 189b8e80941Smrg 190b8e80941Smrg u_box_1d(offset, size, &box); 191b8e80941Smrg 192b8e80941Smrg if (usage & PIPE_TRANSFER_DISCARD_RANGE && 193b8e80941Smrg virgl_buffer_transfer_extend(pipe, resource, usage, &box, data)) 194b8e80941Smrg return; 195b8e80941Smrg 196b8e80941Smrg if (resource->width0 >= getpagesize()) 197b8e80941Smrg u_default_buffer_subdata(pipe, resource, usage, offset, size, data); 198b8e80941Smrg else 199b8e80941Smrg virgl_transfer_inline_write(pipe, resource, 0, usage, &box, data, 0, 0); 200b8e80941Smrg} 201b8e80941Smrg 202b8e80941Smrgvoid virgl_init_context_resource_functions(struct pipe_context *ctx) 203b8e80941Smrg{ 204b8e80941Smrg ctx->transfer_map = u_transfer_map_vtbl; 205b8e80941Smrg ctx->transfer_flush_region = u_transfer_flush_region_vtbl; 206b8e80941Smrg ctx->transfer_unmap = u_transfer_unmap_vtbl; 207b8e80941Smrg ctx->buffer_subdata = virgl_buffer_subdata; 208b8e80941Smrg ctx->texture_subdata = u_default_texture_subdata; 209b8e80941Smrg} 210b8e80941Smrg 211b8e80941Smrgvoid virgl_resource_layout(struct pipe_resource *pt, 212b8e80941Smrg struct virgl_resource_metadata *metadata) 213b8e80941Smrg{ 214b8e80941Smrg unsigned level, nblocksy; 215b8e80941Smrg unsigned width = pt->width0; 216b8e80941Smrg unsigned height = pt->height0; 217b8e80941Smrg unsigned depth = pt->depth0; 218b8e80941Smrg unsigned buffer_size = 0; 219b8e80941Smrg 220b8e80941Smrg for (level = 0; level <= pt->last_level; level++) { 221b8e80941Smrg unsigned slices; 222b8e80941Smrg 223b8e80941Smrg if (pt->target == PIPE_TEXTURE_CUBE) 224b8e80941Smrg slices = 6; 225b8e80941Smrg else if (pt->target == PIPE_TEXTURE_3D) 226b8e80941Smrg slices = depth; 227b8e80941Smrg else 228b8e80941Smrg slices = pt->array_size; 229b8e80941Smrg 230b8e80941Smrg nblocksy = util_format_get_nblocksy(pt->format, height); 231b8e80941Smrg metadata->stride[level] = util_format_get_stride(pt->format, width); 232b8e80941Smrg metadata->layer_stride[level] = nblocksy * metadata->stride[level]; 233b8e80941Smrg metadata->level_offset[level] = buffer_size; 234b8e80941Smrg 235b8e80941Smrg buffer_size += slices * metadata->layer_stride[level]; 236b8e80941Smrg 237b8e80941Smrg width = u_minify(width, 1); 238b8e80941Smrg height = u_minify(height, 1); 239b8e80941Smrg depth = u_minify(depth, 1); 240b8e80941Smrg } 241b8e80941Smrg 242b8e80941Smrg if (pt->nr_samples <= 1) 243b8e80941Smrg metadata->total_size = buffer_size; 244b8e80941Smrg else /* don't create guest backing store for MSAA */ 245b8e80941Smrg metadata->total_size = 0; 246b8e80941Smrg} 247b8e80941Smrg 248b8e80941Smrgstruct virgl_transfer * 249b8e80941Smrgvirgl_resource_create_transfer(struct slab_child_pool *pool, 250b8e80941Smrg struct pipe_resource *pres, 251b8e80941Smrg const struct virgl_resource_metadata *metadata, 252b8e80941Smrg unsigned level, unsigned usage, 253b8e80941Smrg const struct pipe_box *box) 254b8e80941Smrg{ 255b8e80941Smrg struct virgl_transfer *trans; 256b8e80941Smrg enum pipe_format format = pres->format; 257b8e80941Smrg const unsigned blocksy = box->y / util_format_get_blockheight(format); 258b8e80941Smrg const unsigned blocksx = box->x / util_format_get_blockwidth(format); 259b8e80941Smrg 260b8e80941Smrg unsigned offset = metadata->level_offset[level]; 261b8e80941Smrg if (pres->target == PIPE_TEXTURE_CUBE || 262b8e80941Smrg pres->target == PIPE_TEXTURE_CUBE_ARRAY || 263b8e80941Smrg pres->target == PIPE_TEXTURE_3D || 264b8e80941Smrg pres->target == PIPE_TEXTURE_2D_ARRAY) { 265b8e80941Smrg offset += box->z * metadata->layer_stride[level]; 266b8e80941Smrg } 267b8e80941Smrg else if (pres->target == PIPE_TEXTURE_1D_ARRAY) { 268b8e80941Smrg offset += box->z * metadata->stride[level]; 269b8e80941Smrg assert(box->y == 0); 270b8e80941Smrg } else if (pres->target == PIPE_BUFFER) { 271b8e80941Smrg assert(box->y == 0 && box->z == 0); 272b8e80941Smrg } else { 273b8e80941Smrg assert(box->z == 0); 274b8e80941Smrg } 275b8e80941Smrg 276b8e80941Smrg offset += blocksy * metadata->stride[level]; 277b8e80941Smrg offset += blocksx * util_format_get_blocksize(format); 278b8e80941Smrg 279b8e80941Smrg trans = slab_alloc(pool); 280b8e80941Smrg if (!trans) 281b8e80941Smrg return NULL; 282b8e80941Smrg 283b8e80941Smrg trans->base.resource = pres; 284b8e80941Smrg trans->base.level = level; 285b8e80941Smrg trans->base.usage = usage; 286b8e80941Smrg trans->base.box = *box; 287b8e80941Smrg trans->base.stride = metadata->stride[level]; 288b8e80941Smrg trans->base.layer_stride = metadata->layer_stride[level]; 289b8e80941Smrg trans->offset = offset; 290b8e80941Smrg util_range_init(&trans->range); 291b8e80941Smrg 292b8e80941Smrg if (trans->base.resource->target != PIPE_TEXTURE_3D && 293b8e80941Smrg trans->base.resource->target != PIPE_TEXTURE_CUBE && 294b8e80941Smrg trans->base.resource->target != PIPE_TEXTURE_1D_ARRAY && 295b8e80941Smrg trans->base.resource->target != PIPE_TEXTURE_2D_ARRAY && 296b8e80941Smrg trans->base.resource->target != PIPE_TEXTURE_CUBE_ARRAY) 297b8e80941Smrg trans->l_stride = 0; 298b8e80941Smrg else 299b8e80941Smrg trans->l_stride = trans->base.layer_stride; 300b8e80941Smrg 301b8e80941Smrg return trans; 302b8e80941Smrg} 303b8e80941Smrg 304b8e80941Smrgvoid virgl_resource_destroy_transfer(struct slab_child_pool *pool, 305b8e80941Smrg struct virgl_transfer *trans) 306b8e80941Smrg{ 307b8e80941Smrg util_range_destroy(&trans->range); 308b8e80941Smrg slab_free(pool, trans); 309b8e80941Smrg} 310b8e80941Smrg 311b8e80941Smrgvoid virgl_resource_destroy(struct pipe_screen *screen, 312b8e80941Smrg struct pipe_resource *resource) 313b8e80941Smrg{ 314b8e80941Smrg struct virgl_screen *vs = virgl_screen(screen); 315b8e80941Smrg struct virgl_resource *res = virgl_resource(resource); 316b8e80941Smrg vs->vws->resource_unref(vs->vws, res->hw_res); 317b8e80941Smrg FREE(res); 318b8e80941Smrg} 319b8e80941Smrg 320b8e80941Smrgboolean virgl_resource_get_handle(struct pipe_screen *screen, 321b8e80941Smrg struct pipe_resource *resource, 322b8e80941Smrg struct winsys_handle *whandle) 323b8e80941Smrg{ 324b8e80941Smrg struct virgl_screen *vs = virgl_screen(screen); 325b8e80941Smrg struct virgl_resource *res = virgl_resource(resource); 326b8e80941Smrg 327b8e80941Smrg if (res->u.b.target == PIPE_BUFFER) 328b8e80941Smrg return FALSE; 329b8e80941Smrg 330b8e80941Smrg return vs->vws->resource_get_handle(vs->vws, res->hw_res, 331b8e80941Smrg res->metadata.stride[0], 332b8e80941Smrg whandle); 333b8e80941Smrg} 334b8e80941Smrg 335b8e80941Smrgvoid virgl_resource_dirty(struct virgl_resource *res, uint32_t level) 336b8e80941Smrg{ 337b8e80941Smrg if (res) { 338b8e80941Smrg if (res->u.b.target == PIPE_BUFFER) 339b8e80941Smrg res->clean_mask &= ~1; 340b8e80941Smrg else 341b8e80941Smrg res->clean_mask &= ~(1 << level); 342b8e80941Smrg } 343b8e80941Smrg} 344