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