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 #include <stdint.h>
37 #include <sys/ioctl.h>
38 #include <sys/mman.h>
39
40 #include "svga_cmd.h"
41 #include "svga3d_caps.h"
42
43 #include "util/os_file.h"
44 #include "util/u_inlines.h"
45 #include "util/u_math.h"
46 #include "util/u_memory.h"
47 #include "pipebuffer/pb_buffer.h"
48 #include "pipebuffer/pb_bufmgr.h"
49 #include "svga_winsys.h"
50 #include "vmw_context.h"
51 #include "vmw_screen.h"
52 #include "vmw_surface.h"
53 #include "vmw_buffer.h"
54 #include "vmw_fence.h"
55 #include "vmw_msg.h"
56 #include "vmw_shader.h"
57 #include "vmw_query.h"
58 #include "vmwgfx_drm.h"
59 #include "svga3d_surfacedefs.h"
60 #include "xf86drm.h"
61
62 /**
63 * Try to get a surface backing buffer from the cache
64 * if it's this size or smaller.
65 */
66 #define VMW_TRY_CACHED_SIZE (2*1024*1024)
67
68 #ifdef VMX86_STATS
69 static const char* const vmw_svga_winsys_stats_count_names[] = {
70 SVGA_STATS_COUNT_NAMES
71 };
72
73 static const char* const vmw_svga_winsys_stats_time_names[] = {
74 SVGA_STATS_TIME_NAMES
75 };
76
77 /*
78 * It's imperative that the above two arrays are const, so that the next
79 * function can be optimized to a constant.
80 */
81 static inline size_t
vmw_svga_winsys_stats_names_len(void)82 vmw_svga_winsys_stats_names_len(void)
83 {
84 size_t i, res = 0;
85 for (i = 0; i < ARRAY_SIZE(vmw_svga_winsys_stats_count_names); ++i)
86 res += strlen(vmw_svga_winsys_stats_count_names[i]) + 1;
87 for (i = 0; i < ARRAY_SIZE(vmw_svga_winsys_stats_time_names); ++i)
88 res += strlen(vmw_svga_winsys_stats_time_names[i]) + 1;
89 return res;
90 }
91
92 typedef struct Atomic_uint64 {
93 uint64_t value;
94 } Atomic_uint64;
95
96 typedef struct MKSGuestStatCounter {
97 Atomic_uint64 count;
98 } MKSGuestStatCounter;
99
100 typedef struct MKSGuestStatCounterTime {
101 MKSGuestStatCounter counter;
102 Atomic_uint64 selfCycles;
103 Atomic_uint64 totalCycles;
104 } MKSGuestStatCounterTime;
105
106 #define MKS_GUEST_STAT_FLAG_NONE 0
107 #define MKS_GUEST_STAT_FLAG_TIME (1U << 0)
108
109 typedef __attribute__((aligned(32))) struct MKSGuestStatInfoEntry {
110 union {
111 const char *s;
112 uint64_t u;
113 } name;
114 union {
115 const char *s;
116 uint64_t u;
117 } description;
118 uint64_t flags;
119 union {
120 MKSGuestStatCounter *counter;
121 MKSGuestStatCounterTime *counterTime;
122 uint64_t u;
123 } stat;
124 } MKSGuestStatInfoEntry;
125
126 static __thread struct svga_winsys_stats_timeframe *mksstat_tls_global = NULL;
127
128 #define ALIGN(x, power_of_two) (((x) + (power_of_two) - 1) & ~((power_of_two) - 1))
129
130 static const size_t mksstat_area_size_info = sizeof(MKSGuestStatInfoEntry) * (SVGA_STATS_COUNT_MAX + SVGA_STATS_TIME_MAX);
131 static const size_t mksstat_area_size_stat = sizeof(MKSGuestStatCounter) * SVGA_STATS_COUNT_MAX +
132 sizeof(MKSGuestStatCounterTime) * SVGA_STATS_TIME_MAX;
133
134 size_t
vmw_svga_winsys_stats_len(void)135 vmw_svga_winsys_stats_len(void)
136 {
137 const size_t pg_size = getpagesize();
138 const size_t area_size_stat_pg = ALIGN(mksstat_area_size_stat, pg_size);
139 const size_t area_size_info_pg = ALIGN(mksstat_area_size_info, pg_size);
140 const size_t area_size_strs = vmw_svga_winsys_stats_names_len();
141 const size_t area_size = area_size_stat_pg + area_size_info_pg + area_size_strs;
142
143 return area_size;
144 }
145
146 /**
147 * vmw_mksstat_get_pstat: Computes the address of the MKSGuestStatCounter
148 * array from the address of the base page.
149 *
150 * @page_addr: Pointer to the base page.
151 * @page_size: Size of page.
152 * Return: Pointer to the MKSGuestStatCounter array.
153 */
154
155 static inline MKSGuestStatCounter *
vmw_mksstat_get_pstat(uint8_t * page_addr,size_t page_size)156 vmw_mksstat_get_pstat(uint8_t *page_addr, size_t page_size)
157 {
158 return (MKSGuestStatCounter *)page_addr;
159 }
160
161 /**
162 * vmw_mksstat_get_pstat_time: Computes the address of the MKSGuestStatCounterTime
163 * array from the address of the base page.
164 *
165 * @page_addr: Pointer to the base page.
166 * @page_size: Size of page.
167 * Return: Pointer to the MKSGuestStatCounterTime array.
168 */
169
170 static inline MKSGuestStatCounterTime *
vmw_mksstat_get_pstat_time(uint8_t * page_addr,size_t page_size)171 vmw_mksstat_get_pstat_time(uint8_t *page_addr, size_t page_size)
172 {
173 return (MKSGuestStatCounterTime *)(page_addr + sizeof(MKSGuestStatCounter) * SVGA_STATS_COUNT_MAX);
174 }
175
176 /**
177 * vmw_mksstat_get_pinfo: Computes the address of the MKSGuestStatInfoEntry
178 * array from the address of the base page.
179 *
180 * @page_addr: Pointer to the base page.
181 * @page_size: Size of page.
182 * Return: Pointer to the MKSGuestStatInfoEntry array.
183 */
184
185 static inline MKSGuestStatInfoEntry *
vmw_mksstat_get_pinfo(uint8_t * page_addr,size_t page_size)186 vmw_mksstat_get_pinfo(uint8_t *page_addr, size_t page_size)
187 {
188 const size_t area_size_stat_pg = ALIGN(mksstat_area_size_stat, page_size);
189 return (MKSGuestStatInfoEntry *)(page_addr + area_size_stat_pg);
190 }
191
192 /**
193 * vmw_mksstat_get_pstrs: Computes the address of the mksGuestStat strings
194 * sequence from the address of the base page.
195 *
196 * @page_addr: Pointer to the base page.
197 * @page_size: Size of page.
198 * Return: Pointer to the mksGuestStat strings sequence.
199 */
200
201 static inline char *
vmw_mksstat_get_pstrs(uint8_t * page_addr,const size_t page_size)202 vmw_mksstat_get_pstrs(uint8_t *page_addr, const size_t page_size)
203 {
204 const size_t area_size_info_pg = ALIGN(mksstat_area_size_info, page_size);
205 const size_t area_size_stat_pg = ALIGN(mksstat_area_size_stat, page_size);
206 return (char *)(page_addr + area_size_info_pg + area_size_stat_pg);
207 }
208
209 /**
210 * Add all known mksGuestStats counters for tracking by the host.
211 */
212 static int
vmw_svga_winsys_add_stats(struct vmw_winsys_screen * vws,int slot)213 vmw_svga_winsys_add_stats(struct vmw_winsys_screen *vws, int slot)
214 {
215 const size_t pg_size = getpagesize();
216 const size_t area_size = vmw_svga_winsys_stats_len();
217
218 MKSGuestStatInfoEntry *pinfo;
219 MKSGuestStatCounter *pstat;
220 MKSGuestStatCounterTime *pstatTime;
221 char *pstrs;
222 uint64_t id;
223 size_t i;
224
225 /* Allocate a contiguous area of pages for all info entries, counters and strings. */
226 void *area = mmap(NULL, area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE, -1, 0);
227
228 if (area == MAP_FAILED) {
229 fprintf(stderr, "%s could not mmap memory: %s\n", __FUNCTION__, strerror(errno));
230 return -1;
231 }
232
233 pinfo = vmw_mksstat_get_pinfo(area, pg_size);
234 pstat = vmw_mksstat_get_pstat(area, pg_size);
235 pstrs = vmw_mksstat_get_pstrs(area, pg_size);
236 pstatTime = vmw_mksstat_get_pstat_time(area, pg_size);
237
238 if (mlock(area, area_size)) {
239 fprintf(stderr, "%s could not mlock memory: %s\n", __FUNCTION__, strerror(errno));
240 goto error;
241 }
242
243 /* Suppress pages copy-on-write; for MAP_SHARED this should not really matter; it would if we go MAP_PRIVATE */
244 if (madvise(area, area_size, MADV_DONTFORK)) {
245 fprintf(stderr, "%s could not madvise memory: %s\n", __FUNCTION__, strerror(errno));
246 goto error;
247 }
248
249 /* Set up regular counters first */
250 for (i = 0; i < SVGA_STATS_COUNT_MAX; ++i) {
251 pinfo->name.s = pstrs;
252 pinfo->description.s = pstrs;
253 pinfo->flags = MKS_GUEST_STAT_FLAG_NONE;
254 pinfo->stat.counter = pstat + i;
255 pinfo++;
256
257 memcpy(pstrs, vmw_svga_winsys_stats_count_names[i], strlen(vmw_svga_winsys_stats_count_names[i]));
258 pstrs += strlen(vmw_svga_winsys_stats_count_names[i]) + 1;
259 }
260
261 /* Set up time counters second */
262 for (i = 0; i < SVGA_STATS_TIME_MAX; ++i) {
263 pinfo->name.s = pstrs;
264 pinfo->description.s = pstrs;
265 pinfo->flags = MKS_GUEST_STAT_FLAG_TIME;
266 pinfo->stat.counterTime = pstatTime + i;
267 pinfo++;
268
269 memcpy(pstrs, vmw_svga_winsys_stats_time_names[i], strlen(vmw_svga_winsys_stats_time_names[i]));
270 pstrs += strlen(vmw_svga_winsys_stats_time_names[i]) + 1;
271 }
272
273 { /* ioctl(DRM_VMW_MKSSTAT_ADD) */
274 char desc[64];
275 snprintf(desc, sizeof(desc) - 1, "vmw_winsys_screen=%p pid=%d", vws, gettid());
276
277 struct drm_vmw_mksstat_add_arg arg = {
278 .stat = (uintptr_t)pstat,
279 .info = (uintptr_t)vmw_mksstat_get_pinfo(area, pg_size),
280 .strs = (uintptr_t)vmw_mksstat_get_pstrs(area, pg_size),
281 .stat_len = mksstat_area_size_stat,
282 .info_len = mksstat_area_size_info,
283 .strs_len = vmw_svga_winsys_stats_names_len(),
284 .description = (uintptr_t)desc,
285 .id = -1U
286 };
287 if (drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_MKSSTAT_ADD, &arg, sizeof(arg))) {
288 fprintf(stderr, "%s could not ioctl: %s\n", __FUNCTION__, strerror(errno));
289 goto error;
290 }
291 id = arg.id;
292 }
293
294 vws->mksstat_tls[slot].stat_pages = area;
295 vws->mksstat_tls[slot].stat_id = id;
296 /* Don't update vws->mksstat_tls[].pid as it's reserved. */
297 return 0;
298
299 error:
300 munmap(area, area_size);
301 return -1;
302 }
303
304 /**
305 * Acquire a mksstat TLS slot making it immutable by other parties.
306 */
307 static inline int
vmw_winsys_screen_mksstat_acq_slot(struct vmw_winsys_screen * vws)308 vmw_winsys_screen_mksstat_acq_slot(struct vmw_winsys_screen *vws)
309 {
310 const pid_t pid = gettid();
311 const size_t base = (size_t)pid % ARRAY_SIZE(vws->mksstat_tls);
312 size_t i;
313
314 if (mksstat_tls_global && vmw_winsys_screen(mksstat_tls_global->sws) == vws) {
315 const size_t slot = mksstat_tls_global->slot;
316 uint32_t expecpid = pid;
317 if (__atomic_compare_exchange_n(&vws->mksstat_tls[slot].pid, &expecpid, -1U, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
318 return (int)slot;
319 }
320
321 for (i = 0; i < ARRAY_SIZE(vws->mksstat_tls); ++i) {
322 const size_t slot = (i + base) % ARRAY_SIZE(vws->mksstat_tls);
323 uint32_t expecpid = pid;
324 uint32_t expected = 0;
325
326 /* Check if pid is already present */
327 if (__atomic_compare_exchange_n(&vws->mksstat_tls[slot].pid, &expecpid, -1U, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
328 return (int)slot;
329
330 /* Try to set up a new mksstat for this pid */
331 if (__atomic_compare_exchange_n(&vws->mksstat_tls[slot].pid, &expected, -1U, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
332 const int ret = vmw_svga_winsys_add_stats(vws, slot);
333
334 if (!ret)
335 return (int)slot;
336
337 __atomic_store_n(&vws->mksstat_tls[slot].pid, 0, __ATOMIC_RELEASE);
338 return ret;
339 }
340 }
341
342 return -1;
343 }
344
345 /**
346 * Release a mksstat TLS slot -- caller still owns the slot but now it is erasable by other parties.
347 */
348 static inline void
vmw_winsys_screen_mksstat_rel_slot(struct vmw_winsys_screen * vws,int slot)349 vmw_winsys_screen_mksstat_rel_slot(struct vmw_winsys_screen *vws, int slot)
350 {
351 assert(slot < ARRAY_SIZE(vws->mksstat_tls));
352
353 __atomic_store_n(&vws->mksstat_tls[slot].pid, gettid(), __ATOMIC_RELEASE);
354 }
355
356 static inline uint64_t
rdtsc(void)357 rdtsc(void)
358 {
359 uint32_t hi, lo;
360 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
361 return (uint64_t)lo | ((uint64_t)hi << 32);
362 }
363
364 #endif /* VMX86_STATS */
365
366 static struct svga_winsys_buffer *
vmw_svga_winsys_buffer_create(struct svga_winsys_screen * sws,unsigned alignment,unsigned usage,unsigned size)367 vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
368 unsigned alignment,
369 unsigned usage,
370 unsigned size)
371 {
372 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
373 struct vmw_buffer_desc desc;
374 struct pb_manager *provider;
375 struct pb_buffer *buffer;
376
377 memset(&desc, 0, sizeof desc);
378 desc.pb_desc.alignment = alignment;
379 desc.pb_desc.usage = usage;
380
381 if (usage == SVGA_BUFFER_USAGE_PINNED) {
382 if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
383 return NULL;
384 provider = vws->pools.query_fenced;
385 } else if (usage == SVGA_BUFFER_USAGE_SHADER) {
386 provider = vws->pools.mob_shader_slab_fenced;
387 } else {
388 if (size > VMW_GMR_POOL_SIZE)
389 return NULL;
390 provider = vws->pools.gmr_fenced;
391 }
392
393 assert(provider);
394 buffer = provider->create_buffer(provider, size, &desc.pb_desc);
395
396 if(!buffer && provider == vws->pools.gmr_fenced) {
397
398 assert(provider);
399 provider = vws->pools.gmr_slab_fenced;
400 buffer = provider->create_buffer(provider, size, &desc.pb_desc);
401 }
402
403 if (!buffer)
404 return NULL;
405
406 return vmw_svga_winsys_buffer_wrap(buffer);
407 }
408
409
410 static void
vmw_svga_winsys_fence_reference(struct svga_winsys_screen * sws,struct pipe_fence_handle ** pdst,struct pipe_fence_handle * src)411 vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
412 struct pipe_fence_handle **pdst,
413 struct pipe_fence_handle *src)
414 {
415 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
416
417 vmw_fence_reference(vws, pdst, src);
418 }
419
420
421 static int
vmw_svga_winsys_fence_signalled(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,unsigned flag)422 vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,
423 struct pipe_fence_handle *fence,
424 unsigned flag)
425 {
426 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
427
428 return vmw_fence_signalled(vws, fence, flag);
429 }
430
431
432 static int
vmw_svga_winsys_fence_finish(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,uint64_t timeout,unsigned flag)433 vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
434 struct pipe_fence_handle *fence,
435 uint64_t timeout,
436 unsigned flag)
437 {
438 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
439
440 return vmw_fence_finish(vws, fence, timeout, flag);
441 }
442
443
444 static int
vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,boolean duplicate)445 vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen *sws,
446 struct pipe_fence_handle *fence,
447 boolean duplicate)
448 {
449 if (duplicate)
450 return os_dupfd_cloexec(vmw_fence_get_fd(fence));
451 else
452 return vmw_fence_get_fd(fence);
453 }
454
455
456 static void
vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen * sws,struct pipe_fence_handle ** fence,int32_t fd)457 vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen *sws,
458 struct pipe_fence_handle **fence,
459 int32_t fd)
460 {
461 *fence = vmw_fence_create(NULL, 0, 0, 0, os_dupfd_cloexec(fd));
462 }
463
464 static int
vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen * sws,int32_t * context_fd,struct pipe_fence_handle * fence)465 vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen *sws,
466 int32_t *context_fd,
467 struct pipe_fence_handle *fence)
468 {
469 int32_t fd = sws->fence_get_fd(sws, fence, FALSE);
470
471 /* If we don't have fd, we don't need to merge fd into the context's fd. */
472 if (fd == -1)
473 return 0;
474
475 return sync_accumulate("vmwgfx", context_fd, fd);
476 }
477
478
479 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)480 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
481 SVGA3dSurfaceAllFlags flags,
482 SVGA3dSurfaceFormat format,
483 unsigned usage,
484 SVGA3dSize size,
485 uint32 numLayers,
486 uint32 numMipLevels,
487 unsigned sampleCount)
488 {
489 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
490 struct vmw_svga_winsys_surface *surface;
491 struct vmw_buffer_desc desc;
492 struct pb_manager *provider;
493 uint32_t buffer_size;
494 uint32_t num_samples = 1;
495 SVGA3dMSPattern multisample_pattern = SVGA3D_MS_PATTERN_NONE;
496 SVGA3dMSQualityLevel quality_level = SVGA3D_MS_QUALITY_NONE;
497
498 memset(&desc, 0, sizeof(desc));
499 surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
500 if(!surface)
501 goto no_surface;
502
503 pipe_reference_init(&surface->refcnt, 1);
504 p_atomic_set(&surface->validated, 0);
505 surface->screen = vws;
506 (void) mtx_init(&surface->mutex, mtx_plain);
507 surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
508 provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
509
510 /*
511 * When multisampling is not supported sample count received is 0,
512 * otherwise should have a valid sample count.
513 */
514 if ((flags & SVGA3D_SURFACE_MULTISAMPLE) != 0) {
515 if (sampleCount == 0)
516 goto no_sid;
517 num_samples = sampleCount;
518 multisample_pattern = SVGA3D_MS_PATTERN_STANDARD;
519 quality_level = SVGA3D_MS_QUALITY_FULL;
520 }
521
522 /*
523 * Used for the backing buffer GB surfaces, and to approximate
524 * when to flush on non-GB hosts.
525 */
526 buffer_size = svga3dsurface_get_serialized_size_extended(format, size,
527 numMipLevels,
528 numLayers,
529 num_samples);
530 if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
531 buffer_size += sizeof(SVGA3dDXSOState);
532
533 if (buffer_size > vws->ioctl.max_texture_size) {
534 goto no_sid;
535 }
536
537 if (sws->have_gb_objects) {
538 SVGAGuestPtr ptr = {0,0};
539
540 /*
541 * If the backing buffer size is small enough, try to allocate a
542 * buffer out of the buffer cache. Otherwise, let the kernel allocate
543 * a suitable buffer for us.
544 */
545 if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
546 struct pb_buffer *pb_buf;
547
548 surface->size = buffer_size;
549 desc.pb_desc.alignment = 4096;
550 desc.pb_desc.usage = 0;
551 pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
552 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
553 if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
554 assert(0);
555 }
556
557 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
558 size, numLayers,
559 numMipLevels, sampleCount,
560 ptr.gmrId,
561 multisample_pattern,
562 quality_level,
563 surface->buf ? NULL :
564 &desc.region);
565
566 if (surface->sid == SVGA3D_INVALID_ID) {
567 if (surface->buf == NULL) {
568 goto no_sid;
569 } else {
570 /*
571 * Kernel refused to allocate a surface for us.
572 * Perhaps something was wrong with our buffer?
573 * This is really a guard against future new size requirements
574 * on the backing buffers.
575 */
576 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
577 surface->buf = NULL;
578 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
579 size, numLayers,
580 numMipLevels, sampleCount,
581 0, multisample_pattern,
582 quality_level,
583 &desc.region);
584 if (surface->sid == SVGA3D_INVALID_ID)
585 goto no_sid;
586 }
587 }
588
589 /*
590 * If the kernel created the buffer for us, wrap it into a
591 * vmw_svga_winsys_buffer.
592 */
593 if (surface->buf == NULL) {
594 struct pb_buffer *pb_buf;
595
596 surface->size = vmw_region_size(desc.region);
597 desc.pb_desc.alignment = 4096;
598 desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
599 pb_buf = provider->create_buffer(provider, surface->size,
600 &desc.pb_desc);
601 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
602 if (surface->buf == NULL) {
603 vmw_ioctl_region_destroy(desc.region);
604 vmw_ioctl_surface_destroy(vws, surface->sid);
605 goto no_sid;
606 }
607 }
608 } else {
609 /* Legacy surface only support 32-bit svga3d flags */
610 surface->sid = vmw_ioctl_surface_create(vws, (SVGA3dSurface1Flags)flags,
611 format, usage, size, numLayers,
612 numMipLevels, sampleCount);
613 if(surface->sid == SVGA3D_INVALID_ID)
614 goto no_sid;
615
616 /* Best estimate for surface size, used for early flushing. */
617 surface->size = buffer_size;
618 surface->buf = NULL;
619 }
620
621 return svga_winsys_surface(surface);
622
623 no_sid:
624 if (surface->buf)
625 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
626
627 FREE(surface);
628 no_surface:
629 return NULL;
630 }
631
632 static boolean
vmw_svga_winsys_surface_can_create(struct svga_winsys_screen * sws,SVGA3dSurfaceFormat format,SVGA3dSize size,uint32 numLayers,uint32 numMipLevels,uint32 numSamples)633 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
634 SVGA3dSurfaceFormat format,
635 SVGA3dSize size,
636 uint32 numLayers,
637 uint32 numMipLevels,
638 uint32 numSamples)
639 {
640 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
641 uint32_t buffer_size;
642
643 buffer_size = svga3dsurface_get_serialized_size(format, size,
644 numMipLevels,
645 numLayers);
646 if (numSamples > 1)
647 buffer_size *= numSamples;
648
649 if (buffer_size > vws->ioctl.max_texture_size) {
650 return FALSE;
651 }
652 return TRUE;
653 }
654
655
656 static boolean
vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen * sws,struct svga_winsys_surface * surface)657 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
658 struct svga_winsys_surface *surface)
659 {
660 struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
661 return (p_atomic_read(&vsurf->validated) == 0);
662 }
663
664
665 static void
vmw_svga_winsys_surface_ref(struct svga_winsys_screen * sws,struct svga_winsys_surface ** pDst,struct svga_winsys_surface * src)666 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
667 struct svga_winsys_surface **pDst,
668 struct svga_winsys_surface *src)
669 {
670 struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
671 struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
672
673 vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
674 *pDst = svga_winsys_surface(d_vsurf);
675 }
676
677
678 static void
vmw_svga_winsys_destroy(struct svga_winsys_screen * sws)679 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
680 {
681 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
682
683 vmw_winsys_destroy(vws);
684 }
685
686
687 static SVGA3dHardwareVersion
vmw_svga_winsys_get_hw_version(struct svga_winsys_screen * sws)688 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
689 {
690 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
691
692 if (sws->have_gb_objects)
693 return SVGA3D_HWVERSION_WS8_B1;
694
695 return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
696 }
697
698
699 static boolean
vmw_svga_winsys_get_cap(struct svga_winsys_screen * sws,SVGA3dDevCapIndex index,SVGA3dDevCapResult * result)700 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
701 SVGA3dDevCapIndex index,
702 SVGA3dDevCapResult *result)
703 {
704 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
705
706 if (index > vws->ioctl.num_cap_3d ||
707 index >= SVGA3D_DEVCAP_MAX ||
708 !vws->ioctl.cap_3d[index].has_cap)
709 return FALSE;
710
711 *result = vws->ioctl.cap_3d[index].result;
712 return TRUE;
713 }
714
715 struct svga_winsys_gb_shader *
vmw_svga_winsys_shader_create(struct svga_winsys_screen * sws,SVGA3dShaderType type,const uint32 * bytecode,uint32 bytecodeLen)716 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
717 SVGA3dShaderType type,
718 const uint32 *bytecode,
719 uint32 bytecodeLen)
720 {
721 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
722 struct vmw_svga_winsys_shader *shader;
723 void *code;
724
725 shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
726 if(!shader)
727 goto out_no_shader;
728
729 pipe_reference_init(&shader->refcnt, 1);
730 p_atomic_set(&shader->validated, 0);
731 shader->screen = vws;
732 shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
733 SVGA_BUFFER_USAGE_SHADER,
734 bytecodeLen);
735 if (!shader->buf)
736 goto out_no_buf;
737
738 code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_MAP_WRITE);
739 if (!code)
740 goto out_no_buf;
741
742 memcpy(code, bytecode, bytecodeLen);
743 vmw_svga_winsys_buffer_unmap(sws, shader->buf);
744
745 if (!sws->have_vgpu10) {
746 shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
747 if (shader->shid == SVGA3D_INVALID_ID)
748 goto out_no_shid;
749 }
750
751 return svga_winsys_shader(shader);
752
753 out_no_shid:
754 vmw_svga_winsys_buffer_destroy(sws, shader->buf);
755 out_no_buf:
756 FREE(shader);
757 out_no_shader:
758 return NULL;
759 }
760
761 void
vmw_svga_winsys_shader_destroy(struct svga_winsys_screen * sws,struct svga_winsys_gb_shader * shader)762 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
763 struct svga_winsys_gb_shader *shader)
764 {
765 struct vmw_svga_winsys_shader *d_shader =
766 vmw_svga_winsys_shader(shader);
767
768 vmw_svga_winsys_shader_reference(&d_shader, NULL);
769 }
770
771 #ifdef VMX86_STATS
772 static void
vmw_svga_winsys_stats_inc(struct svga_winsys_screen * sws,enum svga_stats_count index)773 vmw_svga_winsys_stats_inc(struct svga_winsys_screen *sws,
774 enum svga_stats_count index)
775 {
776 struct vmw_winsys_screen *const vws = vmw_winsys_screen(sws);
777 const int slot = vmw_winsys_screen_mksstat_acq_slot(vws);
778 assert(index < SVGA_STATS_COUNT_MAX);
779
780 if (slot >= 0) {
781 MKSGuestStatCounter *pstat;
782 assert(vws->mksstat_tls[slot].stat_pages);
783 assert(vws->mksstat_tls[slot].stat_id != -1UL);
784
785 pstat = vmw_mksstat_get_pstat(vws->mksstat_tls[slot].stat_pages, getpagesize());
786
787 __atomic_fetch_add(&pstat[index].count.value, 1, __ATOMIC_ACQ_REL);
788
789 vmw_winsys_screen_mksstat_rel_slot(vws, slot);
790 }
791 }
792
793 static void
vmw_svga_winsys_stats_time_push(struct svga_winsys_screen * sws,enum svga_stats_time index,struct svga_winsys_stats_timeframe * tf)794 vmw_svga_winsys_stats_time_push(struct svga_winsys_screen *sws,
795 enum svga_stats_time index,
796 struct svga_winsys_stats_timeframe *tf)
797 {
798 struct vmw_winsys_screen *const vws = vmw_winsys_screen(sws);
799 const int slot = vmw_winsys_screen_mksstat_acq_slot(vws);
800
801 if (slot < 0)
802 return;
803
804 assert(vws->mksstat_tls[slot].stat_pages);
805 assert(vws->mksstat_tls[slot].stat_id != -1UL);
806
807 tf->counterTime = vmw_mksstat_get_pstat_time(vws->mksstat_tls[slot].stat_pages, getpagesize()) + index;
808
809 vmw_winsys_screen_mksstat_rel_slot(vws, slot);
810
811 tf->startTime = rdtsc();
812 tf->enclosing = mksstat_tls_global;
813 tf->sws = sws;
814 tf->slot = slot;
815
816 mksstat_tls_global = tf;
817 }
818
819 static void
vmw_svga_winsys_stats_time_pop(struct svga_winsys_screen * sws)820 vmw_svga_winsys_stats_time_pop(struct svga_winsys_screen *sws)
821 {
822 struct svga_winsys_stats_timeframe *const tf = mksstat_tls_global;
823 struct vmw_winsys_screen *const vws = vmw_winsys_screen(sws);
824 const int slot = tf->slot;
825 uint32_t expected = gettid();
826
827 mksstat_tls_global = tf->enclosing;
828
829 if (slot < 0)
830 return;
831
832 if (__atomic_compare_exchange_n(&vws->mksstat_tls[slot].pid, &expected, -1U, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
833 const uint64_t dt = rdtsc() - tf->startTime;
834 MKSGuestStatCounterTime *const counterTime = tf->counterTime;
835
836 assert(vws->mksstat_tls[slot].stat_pages);
837 assert(vws->mksstat_tls[slot].stat_id != -1UL);
838
839 __atomic_fetch_add(&counterTime->counter.count.value, 1, __ATOMIC_ACQ_REL);
840 __atomic_fetch_add(&counterTime->selfCycles.value, dt, __ATOMIC_ACQ_REL);
841 __atomic_fetch_add(&counterTime->totalCycles.value, dt, __ATOMIC_ACQ_REL);
842
843 if (tf->enclosing) {
844 MKSGuestStatCounterTime *const counterTime = tf->enclosing->counterTime;
845
846 assert(counterTime);
847
848 __atomic_fetch_sub(&counterTime->selfCycles.value, dt, __ATOMIC_ACQ_REL);
849 }
850
851 __atomic_store_n(&vws->mksstat_tls[slot].pid, expected, __ATOMIC_RELEASE);
852 }
853 }
854
855 #endif /* VMX86_STATS */
856 static void
vmw_svga_winsys_stats_inc_noop(struct svga_winsys_screen * sws,enum svga_stats_count index)857 vmw_svga_winsys_stats_inc_noop(struct svga_winsys_screen *sws,
858 enum svga_stats_count index)
859 {
860 /* noop */
861 }
862
863 static void
vmw_svga_winsys_stats_time_push_noop(struct svga_winsys_screen * sws,enum svga_stats_time index,struct svga_winsys_stats_timeframe * tf)864 vmw_svga_winsys_stats_time_push_noop(struct svga_winsys_screen *sws,
865 enum svga_stats_time index,
866 struct svga_winsys_stats_timeframe *tf)
867 {
868 /* noop */
869 }
870
871 static void
vmw_svga_winsys_stats_time_pop_noop(struct svga_winsys_screen * sws)872 vmw_svga_winsys_stats_time_pop_noop(struct svga_winsys_screen *sws)
873 {
874 /* noop */
875 }
876
877 boolean
vmw_winsys_screen_init_svga(struct vmw_winsys_screen * vws)878 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
879 {
880 vws->base.destroy = vmw_svga_winsys_destroy;
881 vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
882 vws->base.get_cap = vmw_svga_winsys_get_cap;
883 vws->base.context_create = vmw_svga_winsys_context_create;
884 vws->base.surface_create = vmw_svga_winsys_surface_create;
885 vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
886 vws->base.surface_reference = vmw_svga_winsys_surface_ref;
887 vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
888 vws->base.buffer_create = vmw_svga_winsys_buffer_create;
889 vws->base.buffer_map = vmw_svga_winsys_buffer_map;
890 vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
891 vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
892 vws->base.surface_init = vmw_svga_winsys_surface_init;
893 vws->base.fence_reference = vmw_svga_winsys_fence_reference;
894 vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
895 vws->base.shader_create = vmw_svga_winsys_shader_create;
896 vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
897 vws->base.fence_finish = vmw_svga_winsys_fence_finish;
898 vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd;
899 vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd;
900 vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync;
901
902 vws->base.query_create = vmw_svga_winsys_query_create;
903 vws->base.query_init = vmw_svga_winsys_query_init;
904 vws->base.query_destroy = vmw_svga_winsys_query_destroy;
905 vws->base.query_get_result = vmw_svga_winsys_query_get_result;
906
907 #ifdef VMX86_STATS
908 if (vws->ioctl.have_drm_2_19) {
909 vws->base.stats_inc = vmw_svga_winsys_stats_inc;
910 vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;
911 vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;
912 } else {
913 vws->base.stats_inc = vmw_svga_winsys_stats_inc_noop;
914 vws->base.stats_time_push = vmw_svga_winsys_stats_time_push_noop;
915 vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop_noop;
916 }
917
918 #else
919 vws->base.stats_inc = vmw_svga_winsys_stats_inc_noop;
920 vws->base.stats_time_push = vmw_svga_winsys_stats_time_push_noop;
921 vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop_noop;
922
923 #endif
924 vws->base.host_log = vmw_svga_winsys_host_log;
925
926 return TRUE;
927 }
928
929
930