xref: /aosp_15_r20/external/mesa3d/src/gallium/winsys/svga/drm/vmw_screen_svga.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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