• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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