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