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