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