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