1/********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26#include "svga_cmd.h" 27 28#include "pipe/p_state.h" 29#include "pipe/p_defines.h" 30#include "util/u_inlines.h" 31#include "os/os_thread.h" 32#include "util/u_format.h" 33#include "util/u_math.h" 34#include "util/u_memory.h" 35 36#include "svga_format.h" 37#include "svga_screen.h" 38#include "svga_context.h" 39#include "svga_resource_texture.h" 40#include "svga_resource_buffer.h" 41#include "svga_sampler_view.h" 42#include "svga_winsys.h" 43#include "svga_debug.h" 44 45 46/* XXX: This isn't a real hardware flag, but just a hack for kernel to 47 * know about primary surfaces. Find a better way to accomplish this. 48 */ 49#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9) 50 51 52static INLINE void 53svga_transfer_dma_band(struct svga_context *svga, 54 struct svga_transfer *st, 55 SVGA3dTransferType transfer, 56 unsigned y, unsigned h, unsigned srcy, 57 SVGA3dSurfaceDMAFlags flags) 58{ 59 struct svga_texture *texture = svga_texture(st->base.resource); 60 SVGA3dCopyBox box; 61 enum pipe_error ret; 62 63 box.x = st->base.box.x; 64 box.y = y; 65 box.z = st->base.box.z; 66 box.w = st->base.box.width; 67 box.h = h; 68 box.d = 1; 69 box.srcx = 0; 70 box.srcy = srcy; 71 box.srcz = 0; 72 73 if (st->base.resource->target == PIPE_TEXTURE_CUBE) { 74 st->face = st->base.box.z; 75 box.z = 0; 76 } 77 else 78 st->face = 0; 79 80 SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n", 81 transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", 82 texture->handle, 83 st->face, 84 st->base.box.x, 85 y, 86 box.z, 87 st->base.box.x + st->base.box.width, 88 y + h, 89 box.z + 1, 90 util_format_get_blocksize(texture->b.b.format) * 8 / 91 (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format))); 92 93 ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); 94 if(ret != PIPE_OK) { 95 svga_context_flush(svga, NULL); 96 ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); 97 assert(ret == PIPE_OK); 98 } 99} 100 101 102static INLINE void 103svga_transfer_dma(struct svga_context *svga, 104 struct svga_transfer *st, 105 SVGA3dTransferType transfer, 106 SVGA3dSurfaceDMAFlags flags) 107{ 108 struct svga_texture *texture = svga_texture(st->base.resource); 109 struct svga_screen *screen = svga_screen(texture->b.b.screen); 110 struct svga_winsys_screen *sws = screen->sws; 111 struct pipe_fence_handle *fence = NULL; 112 113 if (transfer == SVGA3D_READ_HOST_VRAM) { 114 SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__); 115 } 116 117 /* Ensure any pending operations on host surfaces are queued on the command 118 * buffer first. 119 */ 120 svga_surfaces_flush( svga ); 121 122 if(!st->swbuf) { 123 /* Do the DMA transfer in a single go */ 124 125 svga_transfer_dma_band(svga, st, transfer, 126 st->base.box.y, st->base.box.height, 0, 127 flags); 128 129 if(transfer == SVGA3D_READ_HOST_VRAM) { 130 svga_context_flush(svga, &fence); 131 sws->fence_finish(sws, fence, 0); 132 sws->fence_reference(sws, &fence, NULL); 133 } 134 } 135 else { 136 unsigned y, h, srcy; 137 unsigned blockheight = util_format_get_blockheight(st->base.resource->format); 138 h = st->hw_nblocksy * blockheight; 139 srcy = 0; 140 for(y = 0; y < st->base.box.height; y += h) { 141 unsigned offset, length; 142 void *hw, *sw; 143 144 if (y + h > st->base.box.height) 145 h = st->base.box.height - y; 146 147 /* Transfer band must be aligned to pixel block boundaries */ 148 assert(y % blockheight == 0); 149 assert(h % blockheight == 0); 150 151 offset = y * st->base.stride / blockheight; 152 length = h * st->base.stride / blockheight; 153 154 sw = (uint8_t *)st->swbuf + offset; 155 156 if (transfer == SVGA3D_WRITE_HOST_VRAM) { 157 unsigned usage = PIPE_TRANSFER_WRITE; 158 159 /* Wait for the previous DMAs to complete */ 160 /* TODO: keep one DMA (at half the size) in the background */ 161 if (y) { 162 svga_context_flush(svga, NULL); 163 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 164 } 165 166 hw = sws->buffer_map(sws, st->hwbuf, usage); 167 assert(hw); 168 if (hw) { 169 memcpy(hw, sw, length); 170 sws->buffer_unmap(sws, st->hwbuf); 171 } 172 } 173 174 svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags); 175 176 /* 177 * Prevent the texture contents to be discarded on the next band 178 * upload. 179 */ 180 181 flags.discard = FALSE; 182 183 if(transfer == SVGA3D_READ_HOST_VRAM) { 184 svga_context_flush(svga, &fence); 185 sws->fence_finish(sws, fence, 0); 186 187 hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ); 188 assert(hw); 189 if(hw) { 190 memcpy(sw, hw, length); 191 sws->buffer_unmap(sws, st->hwbuf); 192 } 193 } 194 } 195 } 196} 197 198 199static boolean 200svga_texture_get_handle(struct pipe_screen *screen, 201 struct pipe_resource *texture, 202 struct winsys_handle *whandle) 203{ 204 struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen); 205 unsigned stride; 206 207 assert(svga_texture(texture)->key.cachable == 0); 208 svga_texture(texture)->key.cachable = 0; 209 stride = util_format_get_nblocksx(texture->format, texture->width0) * 210 util_format_get_blocksize(texture->format); 211 return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle); 212} 213 214 215static void 216svga_texture_destroy(struct pipe_screen *screen, 217 struct pipe_resource *pt) 218{ 219 struct svga_screen *ss = svga_screen(screen); 220 struct svga_texture *tex = (struct svga_texture *)pt; 221 222 ss->texture_timestamp++; 223 224 svga_sampler_view_reference(&tex->cached_view, NULL); 225 226 /* 227 DBG("%s deleting %p\n", __FUNCTION__, (void *) tex); 228 */ 229 SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle); 230 svga_screen_surface_destroy(ss, &tex->key, &tex->handle); 231 232 FREE(tex); 233} 234 235 236/* XXX: Still implementing this as if it was a screen function, but 237 * can now modify it to queue transfers on the context. 238 */ 239static struct pipe_transfer * 240svga_texture_get_transfer(struct pipe_context *pipe, 241 struct pipe_resource *texture, 242 unsigned level, 243 unsigned usage, 244 const struct pipe_box *box) 245{ 246 struct svga_context *svga = svga_context(pipe); 247 struct svga_screen *ss = svga_screen(pipe->screen); 248 struct svga_winsys_screen *sws = ss->sws; 249 struct svga_transfer *st; 250 unsigned nblocksx = util_format_get_nblocksx(texture->format, box->width); 251 unsigned nblocksy = util_format_get_nblocksy(texture->format, box->height); 252 253 /* We can't map texture storage directly */ 254 if (usage & PIPE_TRANSFER_MAP_DIRECTLY) 255 return NULL; 256 257 assert(box->depth == 1); 258 st = CALLOC_STRUCT(svga_transfer); 259 if (!st) 260 return NULL; 261 262 pipe_resource_reference(&st->base.resource, texture); 263 st->base.level = level; 264 st->base.usage = usage; 265 st->base.box = *box; 266 st->base.stride = nblocksx*util_format_get_blocksize(texture->format); 267 st->base.layer_stride = 0; 268 269 st->hw_nblocksy = nblocksy; 270 271 st->hwbuf = svga_winsys_buffer_create(svga, 272 1, 273 0, 274 st->hw_nblocksy*st->base.stride); 275 while(!st->hwbuf && (st->hw_nblocksy /= 2)) { 276 st->hwbuf = svga_winsys_buffer_create(svga, 277 1, 278 0, 279 st->hw_nblocksy*st->base.stride); 280 } 281 282 if(!st->hwbuf) 283 goto no_hwbuf; 284 285 if(st->hw_nblocksy < nblocksy) { 286 /* We couldn't allocate a hardware buffer big enough for the transfer, 287 * so allocate regular malloc memory instead */ 288 if (0) { 289 debug_printf("%s: failed to allocate %u KB of DMA, " 290 "splitting into %u x %u KB DMA transfers\n", 291 __FUNCTION__, 292 (nblocksy*st->base.stride + 1023)/1024, 293 (nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy, 294 (st->hw_nblocksy*st->base.stride + 1023)/1024); 295 } 296 297 st->swbuf = MALLOC(nblocksy*st->base.stride); 298 if(!st->swbuf) 299 goto no_swbuf; 300 } 301 302 if (usage & PIPE_TRANSFER_READ) { 303 SVGA3dSurfaceDMAFlags flags; 304 memset(&flags, 0, sizeof flags); 305 svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags); 306 } 307 308 return &st->base; 309 310no_swbuf: 311 sws->buffer_destroy(sws, st->hwbuf); 312no_hwbuf: 313 FREE(st); 314 return NULL; 315} 316 317 318/* XXX: Still implementing this as if it was a screen function, but 319 * can now modify it to queue transfers on the context. 320 */ 321static void * 322svga_texture_transfer_map( struct pipe_context *pipe, 323 struct pipe_transfer *transfer ) 324{ 325 struct svga_screen *ss = svga_screen(pipe->screen); 326 struct svga_winsys_screen *sws = ss->sws; 327 struct svga_transfer *st = svga_transfer(transfer); 328 329 if(st->swbuf) 330 return st->swbuf; 331 else 332 /* The wait for read transfers already happened when svga_transfer_dma 333 * was called. */ 334 return sws->buffer_map(sws, st->hwbuf, transfer->usage); 335} 336 337 338/* XXX: Still implementing this as if it was a screen function, but 339 * can now modify it to queue transfers on the context. 340 */ 341static void 342svga_texture_transfer_unmap(struct pipe_context *pipe, 343 struct pipe_transfer *transfer) 344{ 345 struct svga_screen *ss = svga_screen(pipe->screen); 346 struct svga_winsys_screen *sws = ss->sws; 347 struct svga_transfer *st = svga_transfer(transfer); 348 349 if(!st->swbuf) 350 sws->buffer_unmap(sws, st->hwbuf); 351} 352 353 354static void 355svga_texture_transfer_destroy(struct pipe_context *pipe, 356 struct pipe_transfer *transfer) 357{ 358 struct svga_context *svga = svga_context(pipe); 359 struct svga_texture *tex = svga_texture(transfer->resource); 360 struct svga_screen *ss = svga_screen(pipe->screen); 361 struct svga_winsys_screen *sws = ss->sws; 362 struct svga_transfer *st = svga_transfer(transfer); 363 364 if (st->base.usage & PIPE_TRANSFER_WRITE) { 365 SVGA3dSurfaceDMAFlags flags; 366 367 memset(&flags, 0, sizeof flags); 368 if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 369 flags.discard = TRUE; 370 } 371 if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { 372 flags.unsynchronized = TRUE; 373 } 374 375 svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags); 376 ss->texture_timestamp++; 377 tex->view_age[transfer->level] = ++(tex->age); 378 if (transfer->resource->target == PIPE_TEXTURE_CUBE) 379 tex->defined[transfer->box.z][transfer->level] = TRUE; 380 else 381 tex->defined[0][transfer->level] = TRUE; 382 } 383 384 pipe_resource_reference(&st->base.resource, NULL); 385 FREE(st->swbuf); 386 sws->buffer_destroy(sws, st->hwbuf); 387 FREE(st); 388} 389 390 391struct u_resource_vtbl svga_texture_vtbl = 392{ 393 svga_texture_get_handle, /* get_handle */ 394 svga_texture_destroy, /* resource_destroy */ 395 svga_texture_get_transfer, /* get_transfer */ 396 svga_texture_transfer_destroy, /* transfer_destroy */ 397 svga_texture_transfer_map, /* transfer_map */ 398 u_default_transfer_flush_region, /* transfer_flush_region */ 399 svga_texture_transfer_unmap, /* transfer_unmap */ 400 u_default_transfer_inline_write /* transfer_inline_write */ 401}; 402 403 404struct pipe_resource * 405svga_texture_create(struct pipe_screen *screen, 406 const struct pipe_resource *template) 407{ 408 struct svga_screen *svgascreen = svga_screen(screen); 409 struct svga_texture *tex = CALLOC_STRUCT(svga_texture); 410 411 if (!tex) 412 goto error1; 413 414 tex->b.b = *template; 415 tex->b.vtbl = &svga_texture_vtbl; 416 pipe_reference_init(&tex->b.b.reference, 1); 417 tex->b.b.screen = screen; 418 419 assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS); 420 if(template->last_level >= SVGA_MAX_TEXTURE_LEVELS) 421 goto error2; 422 423 tex->key.flags = 0; 424 tex->key.size.width = template->width0; 425 tex->key.size.height = template->height0; 426 tex->key.size.depth = template->depth0; 427 428 if(template->target == PIPE_TEXTURE_CUBE) { 429 tex->key.flags |= SVGA3D_SURFACE_CUBEMAP; 430 tex->key.numFaces = 6; 431 } 432 else { 433 tex->key.numFaces = 1; 434 } 435 436 tex->key.cachable = 1; 437 438 if (template->bind & PIPE_BIND_SAMPLER_VIEW) 439 tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE; 440 441 if (template->bind & PIPE_BIND_DISPLAY_TARGET) { 442 tex->key.cachable = 0; 443 } 444 445 if (template->bind & PIPE_BIND_SHARED) { 446 tex->key.cachable = 0; 447 } 448 449 if (template->bind & (PIPE_BIND_SCANOUT | 450 PIPE_BIND_CURSOR)) { 451 tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT; 452 tex->key.cachable = 0; 453 } 454 455 /* 456 * Note: Previously we never passed the 457 * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot 458 * know beforehand whether a texture will be used as a rendertarget or not 459 * and it always requests PIPE_BIND_RENDER_TARGET, therefore 460 * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose. 461 * 462 * However, this was changed since other state trackers 463 * (XA for example) uses it accurately and certain device versions 464 * relies on it in certain situations to render correctly. 465 */ 466 if((template->bind & PIPE_BIND_RENDER_TARGET) && 467 !util_format_is_s3tc(template->format)) 468 tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET; 469 470 if(template->bind & PIPE_BIND_DEPTH_STENCIL) 471 tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL; 472 473 tex->key.numMipLevels = template->last_level + 1; 474 475 tex->key.format = svga_translate_format(svgascreen, template->format, template->bind); 476 if(tex->key.format == SVGA3D_FORMAT_INVALID) 477 goto error2; 478 479 SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle); 480 tex->handle = svga_screen_surface_create(svgascreen, &tex->key); 481 if (tex->handle) 482 SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle); 483 484 debug_reference(&tex->b.b.reference, 485 (debug_reference_descriptor)debug_describe_resource, 0); 486 487 return &tex->b.b; 488 489error2: 490 FREE(tex); 491error1: 492 return NULL; 493} 494 495 496struct pipe_resource * 497svga_texture_from_handle(struct pipe_screen *screen, 498 const struct pipe_resource *template, 499 struct winsys_handle *whandle) 500{ 501 struct svga_winsys_screen *sws = svga_winsys_screen(screen); 502 struct svga_winsys_surface *srf; 503 struct svga_texture *tex; 504 enum SVGA3dSurfaceFormat format = 0; 505 assert(screen); 506 507 /* Only supports one type */ 508 if ((template->target != PIPE_TEXTURE_2D && 509 template->target != PIPE_TEXTURE_RECT) || 510 template->last_level != 0 || 511 template->depth0 != 1) { 512 return NULL; 513 } 514 515 srf = sws->surface_from_handle(sws, whandle, &format); 516 517 if (!srf) 518 return NULL; 519 520 if (svga_translate_format(svga_screen(screen), template->format, template->bind) != format) { 521 unsigned f1 = svga_translate_format(svga_screen(screen), template->format, template->bind); 522 unsigned f2 = format; 523 524 /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */ 525 if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) || 526 (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) || 527 (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) || 528 (f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) { 529 debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2); 530 return NULL; 531 } 532 } 533 534 tex = CALLOC_STRUCT(svga_texture); 535 if (!tex) 536 return NULL; 537 538 tex->b.b = *template; 539 tex->b.vtbl = &svga_texture_vtbl; 540 pipe_reference_init(&tex->b.b.reference, 1); 541 tex->b.b.screen = screen; 542 543 if (format == SVGA3D_X8R8G8B8) 544 tex->b.b.format = PIPE_FORMAT_B8G8R8X8_UNORM; 545 else if (format == SVGA3D_A8R8G8B8) 546 tex->b.b.format = PIPE_FORMAT_B8G8R8A8_UNORM; 547 else { 548 /* ?? */ 549 } 550 551 SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf); 552 553 tex->key.cachable = 0; 554 tex->handle = srf; 555 556 return &tex->b.b; 557} 558