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