1 /********************************************************** 2 * Copyright 2009-2015 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 /** 27 * @file 28 * This file implements the SVGA interface into this winsys, defined 29 * in drivers/svga/svga_winsys.h. 30 * 31 * @author Keith Whitwell 32 * @author Jose Fonseca 33 */ 34 35 #include <libsync.h> 36 37 #include "svga_cmd.h" 38 #include "svga3d_caps.h" 39 40 #include "util/u_inlines.h" 41 #include "util/u_math.h" 42 #include "util/u_memory.h" 43 #include "pipebuffer/pb_buffer.h" 44 #include "pipebuffer/pb_bufmgr.h" 45 #include "svga_winsys.h" 46 #include "vmw_context.h" 47 #include "vmw_screen.h" 48 #include "vmw_surface.h" 49 #include "vmw_buffer.h" 50 #include "vmw_fence.h" 51 #include "vmw_shader.h" 52 #include "vmw_query.h" 53 #include "svga3d_surfacedefs.h" 54 55 /** 56 * Try to get a surface backing buffer from the cache 57 * if it's this size or smaller. 58 */ 59 #define VMW_TRY_CACHED_SIZE (2*1024*1024) 60 61 static struct svga_winsys_buffer * 62 vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws, 63 unsigned alignment, 64 unsigned usage, 65 unsigned size) 66 { 67 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 68 struct vmw_buffer_desc desc; 69 struct pb_manager *provider; 70 struct pb_buffer *buffer; 71 72 memset(&desc, 0, sizeof desc); 73 desc.pb_desc.alignment = alignment; 74 desc.pb_desc.usage = usage; 75 76 if (usage == SVGA_BUFFER_USAGE_PINNED) { 77 if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws)) 78 return NULL; 79 provider = vws->pools.query_fenced; 80 } else if (usage == SVGA_BUFFER_USAGE_SHADER) { 81 provider = vws->pools.mob_shader_slab_fenced; 82 } else 83 provider = vws->pools.gmr_fenced; 84 85 assert(provider); 86 buffer = provider->create_buffer(provider, size, &desc.pb_desc); 87 88 if(!buffer && provider == vws->pools.gmr_fenced) { 89 90 assert(provider); 91 provider = vws->pools.gmr_slab_fenced; 92 buffer = provider->create_buffer(provider, size, &desc.pb_desc); 93 } 94 95 if (!buffer) 96 return NULL; 97 98 return vmw_svga_winsys_buffer_wrap(buffer); 99 } 100 101 102 static void 103 vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws, 104 struct pipe_fence_handle **pdst, 105 struct pipe_fence_handle *src) 106 { 107 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 108 109 vmw_fence_reference(vws, pdst, src); 110 } 111 112 113 static int 114 vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws, 115 struct pipe_fence_handle *fence, 116 unsigned flag) 117 { 118 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 119 120 return vmw_fence_signalled(vws, fence, flag); 121 } 122 123 124 static int 125 vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws, 126 struct pipe_fence_handle *fence, 127 uint64_t timeout, 128 unsigned flag) 129 { 130 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 131 132 return vmw_fence_finish(vws, fence, timeout, flag); 133 } 134 135 136 static int 137 vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen *sws, 138 struct pipe_fence_handle *fence, 139 boolean duplicate) 140 { 141 if (duplicate) 142 return dup(vmw_fence_get_fd(fence)); 143 else 144 return vmw_fence_get_fd(fence); 145 } 146 147 148 static void 149 vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen *sws, 150 struct pipe_fence_handle **fence, 151 int32_t fd) 152 { 153 *fence = vmw_fence_create(NULL, 0, 0, 0, dup(fd)); 154 } 155 156 static int 157 vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen *sws, 158 int32_t *context_fd, 159 struct pipe_fence_handle *fence) 160 { 161 return sync_accumulate("vmwgfx", context_fd, 162 sws->fence_get_fd(sws, fence, FALSE)); 163 } 164 165 166 static struct svga_winsys_surface * 167 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws, 168 SVGA3dSurfaceFlags flags, 169 SVGA3dSurfaceFormat format, 170 unsigned usage, 171 SVGA3dSize size, 172 uint32 numLayers, 173 uint32 numMipLevels, 174 unsigned sampleCount) 175 { 176 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 177 struct vmw_svga_winsys_surface *surface; 178 struct vmw_buffer_desc desc; 179 struct pb_manager *provider; 180 uint32_t buffer_size; 181 182 memset(&desc, 0, sizeof(desc)); 183 surface = CALLOC_STRUCT(vmw_svga_winsys_surface); 184 if(!surface) 185 goto no_surface; 186 187 pipe_reference_init(&surface->refcnt, 1); 188 p_atomic_set(&surface->validated, 0); 189 surface->screen = vws; 190 (void) mtx_init(&surface->mutex, mtx_plain); 191 surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED); 192 provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced; 193 194 /* 195 * Used for the backing buffer GB surfaces, and to approximate 196 * when to flush on non-GB hosts. 197 */ 198 buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels, 199 numLayers); 200 if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) 201 buffer_size += sizeof(SVGA3dDXSOState); 202 203 if (buffer_size > vws->ioctl.max_texture_size) { 204 goto no_sid; 205 } 206 207 if (sws->have_gb_objects) { 208 SVGAGuestPtr ptr = {0,0}; 209 210 /* 211 * If the backing buffer size is small enough, try to allocate a 212 * buffer out of the buffer cache. Otherwise, let the kernel allocate 213 * a suitable buffer for us. 214 */ 215 if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) { 216 struct pb_buffer *pb_buf; 217 218 surface->size = buffer_size; 219 desc.pb_desc.alignment = 4096; 220 desc.pb_desc.usage = 0; 221 pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc); 222 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf); 223 if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr)) 224 assert(0); 225 } 226 227 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage, 228 size, numLayers, 229 numMipLevels, sampleCount, 230 ptr.gmrId, 231 surface->buf ? NULL : 232 &desc.region); 233 234 if (surface->sid == SVGA3D_INVALID_ID) { 235 if (surface->buf == NULL) { 236 goto no_sid; 237 } else { 238 /* 239 * Kernel refused to allocate a surface for us. 240 * Perhaps something was wrong with our buffer? 241 * This is really a guard against future new size requirements 242 * on the backing buffers. 243 */ 244 vmw_svga_winsys_buffer_destroy(sws, surface->buf); 245 surface->buf = NULL; 246 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage, 247 size, numLayers, 248 numMipLevels, sampleCount, 249 0, &desc.region); 250 if (surface->sid == SVGA3D_INVALID_ID) 251 goto no_sid; 252 } 253 } 254 255 /* 256 * If the kernel created the buffer for us, wrap it into a 257 * vmw_svga_winsys_buffer. 258 */ 259 if (surface->buf == NULL) { 260 struct pb_buffer *pb_buf; 261 262 surface->size = vmw_region_size(desc.region); 263 desc.pb_desc.alignment = 4096; 264 desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED; 265 pb_buf = provider->create_buffer(provider, surface->size, 266 &desc.pb_desc); 267 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf); 268 if (surface->buf == NULL) { 269 vmw_ioctl_region_destroy(desc.region); 270 vmw_ioctl_surface_destroy(vws, surface->sid); 271 goto no_sid; 272 } 273 } 274 } else { 275 surface->sid = vmw_ioctl_surface_create(vws, flags, format, usage, 276 size, numLayers, numMipLevels, 277 sampleCount); 278 if(surface->sid == SVGA3D_INVALID_ID) 279 goto no_sid; 280 281 /* Best estimate for surface size, used for early flushing. */ 282 surface->size = buffer_size; 283 surface->buf = NULL; 284 } 285 286 return svga_winsys_surface(surface); 287 288 no_sid: 289 if (surface->buf) 290 vmw_svga_winsys_buffer_destroy(sws, surface->buf); 291 292 FREE(surface); 293 no_surface: 294 return NULL; 295 } 296 297 static boolean 298 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws, 299 SVGA3dSurfaceFormat format, 300 SVGA3dSize size, 301 uint32 numLayers, 302 uint32 numMipLevels) 303 { 304 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 305 uint32_t buffer_size; 306 307 buffer_size = svga3dsurface_get_serialized_size(format, size, 308 numMipLevels, 309 numLayers); 310 if (buffer_size > vws->ioctl.max_texture_size) { 311 return FALSE; 312 } 313 return TRUE; 314 } 315 316 317 static boolean 318 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws, 319 struct svga_winsys_surface *surface) 320 { 321 struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface); 322 return (p_atomic_read(&vsurf->validated) == 0); 323 } 324 325 326 static void 327 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws, 328 struct svga_winsys_surface **pDst, 329 struct svga_winsys_surface *src) 330 { 331 struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst); 332 struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src); 333 334 vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf); 335 *pDst = svga_winsys_surface(d_vsurf); 336 } 337 338 339 static void 340 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws) 341 { 342 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 343 344 vmw_winsys_destroy(vws); 345 } 346 347 348 static SVGA3dHardwareVersion 349 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws) 350 { 351 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 352 353 if (sws->have_gb_objects) 354 return SVGA3D_HWVERSION_WS8_B1; 355 356 return (SVGA3dHardwareVersion) vws->ioctl.hwversion; 357 } 358 359 360 static boolean 361 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws, 362 SVGA3dDevCapIndex index, 363 SVGA3dDevCapResult *result) 364 { 365 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 366 367 if (index > vws->ioctl.num_cap_3d || 368 index >= SVGA3D_DEVCAP_MAX || 369 !vws->ioctl.cap_3d[index].has_cap) 370 return FALSE; 371 372 *result = vws->ioctl.cap_3d[index].result; 373 return TRUE; 374 } 375 376 struct svga_winsys_gb_shader * 377 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws, 378 SVGA3dShaderType type, 379 const uint32 *bytecode, 380 uint32 bytecodeLen) 381 { 382 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 383 struct vmw_svga_winsys_shader *shader; 384 void *code; 385 386 shader = CALLOC_STRUCT(vmw_svga_winsys_shader); 387 if(!shader) 388 goto out_no_shader; 389 390 pipe_reference_init(&shader->refcnt, 1); 391 p_atomic_set(&shader->validated, 0); 392 shader->screen = vws; 393 shader->buf = vmw_svga_winsys_buffer_create(sws, 64, 394 SVGA_BUFFER_USAGE_SHADER, 395 bytecodeLen); 396 if (!shader->buf) 397 goto out_no_buf; 398 399 code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE); 400 if (!code) 401 goto out_no_buf; 402 403 memcpy(code, bytecode, bytecodeLen); 404 vmw_svga_winsys_buffer_unmap(sws, shader->buf); 405 406 if (!sws->have_vgpu10) { 407 shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen); 408 if (shader->shid == SVGA3D_INVALID_ID) 409 goto out_no_shid; 410 } 411 412 return svga_winsys_shader(shader); 413 414 out_no_shid: 415 vmw_svga_winsys_buffer_destroy(sws, shader->buf); 416 out_no_buf: 417 FREE(shader); 418 out_no_shader: 419 return NULL; 420 } 421 422 void 423 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws, 424 struct svga_winsys_gb_shader *shader) 425 { 426 struct vmw_svga_winsys_shader *d_shader = 427 vmw_svga_winsys_shader(shader); 428 429 vmw_svga_winsys_shader_reference(&d_shader, NULL); 430 } 431 432 static void 433 vmw_svga_winsys_stats_inc(enum svga_stats_count index) 434 { 435 } 436 437 static void 438 vmw_svga_winsys_stats_time_push(enum svga_stats_time index, 439 struct svga_winsys_stats_timeframe *tf) 440 { 441 } 442 443 static void 444 vmw_svga_winsys_stats_time_pop() 445 { 446 } 447 448 boolean 449 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws) 450 { 451 vws->base.destroy = vmw_svga_winsys_destroy; 452 vws->base.get_hw_version = vmw_svga_winsys_get_hw_version; 453 vws->base.get_cap = vmw_svga_winsys_get_cap; 454 vws->base.context_create = vmw_svga_winsys_context_create; 455 vws->base.surface_create = vmw_svga_winsys_surface_create; 456 vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed; 457 vws->base.surface_reference = vmw_svga_winsys_surface_ref; 458 vws->base.surface_can_create = vmw_svga_winsys_surface_can_create; 459 vws->base.buffer_create = vmw_svga_winsys_buffer_create; 460 vws->base.buffer_map = vmw_svga_winsys_buffer_map; 461 vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap; 462 vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy; 463 vws->base.fence_reference = vmw_svga_winsys_fence_reference; 464 vws->base.fence_signalled = vmw_svga_winsys_fence_signalled; 465 vws->base.shader_create = vmw_svga_winsys_shader_create; 466 vws->base.shader_destroy = vmw_svga_winsys_shader_destroy; 467 vws->base.fence_finish = vmw_svga_winsys_fence_finish; 468 vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd; 469 vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd; 470 vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync; 471 472 vws->base.query_create = vmw_svga_winsys_query_create; 473 vws->base.query_init = vmw_svga_winsys_query_init; 474 vws->base.query_destroy = vmw_svga_winsys_query_destroy; 475 vws->base.query_get_result = vmw_svga_winsys_query_get_result; 476 477 vws->base.stats_inc = vmw_svga_winsys_stats_inc; 478 vws->base.stats_time_push = vmw_svga_winsys_stats_time_push; 479 vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop; 480 481 return TRUE; 482 } 483 484 485