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