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