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 
37 #include "svga_cmd.h"
38 #include "svga3d_caps.h"
39 
40 #include "util/os_file.h"
41 #include "util/u_inlines.h"
42 #include "util/u_math.h"
43 #include "util/u_memory.h"
44 #include "pipebuffer/pb_buffer.h"
45 #include "pipebuffer/pb_bufmgr.h"
46 #include "svga_winsys.h"
47 #include "vmw_context.h"
48 #include "vmw_screen.h"
49 #include "vmw_surface.h"
50 #include "vmw_buffer.h"
51 #include "vmw_fence.h"
52 #include "vmw_msg.h"
53 #include "vmw_shader.h"
54 #include "vmw_query.h"
55 #include "svga3d_surfacedefs.h"
56 
57 /**
58  * Try to get a surface backing buffer from the cache
59  * if it's this size or smaller.
60  */
61 #define VMW_TRY_CACHED_SIZE (2*1024*1024)
62 
63 static struct svga_winsys_buffer *
vmw_svga_winsys_buffer_create(struct svga_winsys_screen * sws,unsigned alignment,unsigned usage,unsigned size)64 vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
65                               unsigned alignment,
66                               unsigned usage,
67                               unsigned size)
68 {
69    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
70    struct vmw_buffer_desc desc;
71    struct pb_manager *provider;
72    struct pb_buffer *buffer;
73 
74    memset(&desc, 0, sizeof desc);
75    desc.pb_desc.alignment = alignment;
76    desc.pb_desc.usage = usage;
77 
78    if (usage == SVGA_BUFFER_USAGE_PINNED) {
79       if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
80 	 return NULL;
81       provider = vws->pools.query_fenced;
82    } else if (usage == SVGA_BUFFER_USAGE_SHADER) {
83       provider = vws->pools.mob_shader_slab_fenced;
84    } else {
85       if (size > VMW_GMR_POOL_SIZE)
86          return NULL;
87       provider = vws->pools.gmr_fenced;
88    }
89 
90    assert(provider);
91    buffer = provider->create_buffer(provider, size, &desc.pb_desc);
92 
93    if(!buffer && provider == vws->pools.gmr_fenced) {
94 
95       assert(provider);
96       provider = vws->pools.gmr_slab_fenced;
97       buffer = provider->create_buffer(provider, size, &desc.pb_desc);
98    }
99 
100    if (!buffer)
101       return NULL;
102 
103    return vmw_svga_winsys_buffer_wrap(buffer);
104 }
105 
106 
107 static void
vmw_svga_winsys_fence_reference(struct svga_winsys_screen * sws,struct pipe_fence_handle ** pdst,struct pipe_fence_handle * src)108 vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
109                                 struct pipe_fence_handle **pdst,
110                                 struct pipe_fence_handle *src)
111 {
112     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
113 
114     vmw_fence_reference(vws, pdst, src);
115 }
116 
117 
118 static int
vmw_svga_winsys_fence_signalled(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,unsigned flag)119 vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,
120                                 struct pipe_fence_handle *fence,
121                                 unsigned flag)
122 {
123    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
124 
125    return vmw_fence_signalled(vws, fence, flag);
126 }
127 
128 
129 static int
vmw_svga_winsys_fence_finish(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,uint64_t timeout,unsigned flag)130 vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
131                              struct pipe_fence_handle *fence,
132                              uint64_t timeout,
133                              unsigned flag)
134 {
135    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
136 
137    return vmw_fence_finish(vws, fence, timeout, flag);
138 }
139 
140 
141 static int
vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen * sws,struct pipe_fence_handle * fence,boolean duplicate)142 vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen *sws,
143                              struct pipe_fence_handle *fence,
144                              boolean duplicate)
145 {
146    if (duplicate)
147       return os_dupfd_cloexec(vmw_fence_get_fd(fence));
148    else
149       return vmw_fence_get_fd(fence);
150 }
151 
152 
153 static void
vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen * sws,struct pipe_fence_handle ** fence,int32_t fd)154 vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen *sws,
155                                 struct pipe_fence_handle **fence,
156                                 int32_t fd)
157 {
158    *fence = vmw_fence_create(NULL, 0, 0, 0, os_dupfd_cloexec(fd));
159 }
160 
161 static int
vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen * sws,int32_t * context_fd,struct pipe_fence_handle * fence)162 vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen *sws,
163                                   int32_t *context_fd,
164                                   struct pipe_fence_handle *fence)
165 {
166    int32_t fd = sws->fence_get_fd(sws, fence, FALSE);
167 
168    /* If we don't have fd, we don't need to merge fd into the context's fd. */
169    if (fd == -1)
170       return 0;
171 
172    return sync_accumulate("vmwgfx", context_fd, fd);
173 }
174 
175 
176 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)177 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
178                                SVGA3dSurfaceAllFlags flags,
179                                SVGA3dSurfaceFormat format,
180                                unsigned usage,
181                                SVGA3dSize size,
182                                uint32 numLayers,
183                                uint32 numMipLevels,
184                                unsigned sampleCount)
185 {
186    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
187    struct vmw_svga_winsys_surface *surface;
188    struct vmw_buffer_desc desc;
189    struct pb_manager *provider;
190    uint32_t buffer_size;
191    uint32_t num_samples = 1;
192    SVGA3dMSPattern multisample_pattern = SVGA3D_MS_PATTERN_NONE;
193    SVGA3dMSQualityLevel quality_level = SVGA3D_MS_QUALITY_NONE;
194 
195    memset(&desc, 0, sizeof(desc));
196    surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
197    if(!surface)
198       goto no_surface;
199 
200    pipe_reference_init(&surface->refcnt, 1);
201    p_atomic_set(&surface->validated, 0);
202    surface->screen = vws;
203    (void) mtx_init(&surface->mutex, mtx_plain);
204    surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
205    provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
206 
207    /*
208     * When multisampling is not supported sample count received is 0,
209     * otherwise should have a valid sample count.
210     */
211    if ((flags & SVGA3D_SURFACE_MULTISAMPLE) != 0) {
212       if (sampleCount == 0)
213          goto no_sid;
214       num_samples = sampleCount;
215       multisample_pattern = SVGA3D_MS_PATTERN_STANDARD;
216       quality_level = SVGA3D_MS_QUALITY_FULL;
217    }
218 
219    /*
220     * Used for the backing buffer GB surfaces, and to approximate
221     * when to flush on non-GB hosts.
222     */
223    buffer_size = svga3dsurface_get_serialized_size_extended(format, size,
224                                                             numMipLevels,
225                                                             numLayers,
226                                                             num_samples);
227    if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
228       buffer_size += sizeof(SVGA3dDXSOState);
229 
230    if (buffer_size > vws->ioctl.max_texture_size) {
231       goto no_sid;
232    }
233 
234    if (sws->have_gb_objects) {
235       SVGAGuestPtr ptr = {0,0};
236 
237       /*
238        * If the backing buffer size is small enough, try to allocate a
239        * buffer out of the buffer cache. Otherwise, let the kernel allocate
240        * a suitable buffer for us.
241        */
242       if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
243          struct pb_buffer *pb_buf;
244 
245          surface->size = buffer_size;
246          desc.pb_desc.alignment = 4096;
247          desc.pb_desc.usage = 0;
248          pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
249          surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
250          if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
251             assert(0);
252       }
253 
254       surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
255                                                  size, numLayers,
256                                                  numMipLevels, sampleCount,
257                                                  ptr.gmrId,
258                                                  multisample_pattern,
259                                                  quality_level,
260                                                  surface->buf ? NULL :
261                                                  &desc.region);
262 
263       if (surface->sid == SVGA3D_INVALID_ID) {
264          if (surface->buf == NULL) {
265             goto no_sid;
266          } else {
267             /*
268              * Kernel refused to allocate a surface for us.
269              * Perhaps something was wrong with our buffer?
270              * This is really a guard against future new size requirements
271              * on the backing buffers.
272              */
273             vmw_svga_winsys_buffer_destroy(sws, surface->buf);
274             surface->buf = NULL;
275             surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
276                                                        size, numLayers,
277                                                        numMipLevels, sampleCount,
278                                                        0, multisample_pattern,
279                                                        quality_level,
280                                                        &desc.region);
281             if (surface->sid == SVGA3D_INVALID_ID)
282                goto no_sid;
283          }
284       }
285 
286       /*
287        * If the kernel created the buffer for us, wrap it into a
288        * vmw_svga_winsys_buffer.
289        */
290       if (surface->buf == NULL) {
291          struct pb_buffer *pb_buf;
292 
293          surface->size = vmw_region_size(desc.region);
294          desc.pb_desc.alignment = 4096;
295          desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
296          pb_buf = provider->create_buffer(provider, surface->size,
297                                           &desc.pb_desc);
298          surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
299          if (surface->buf == NULL) {
300             vmw_ioctl_region_destroy(desc.region);
301             vmw_ioctl_surface_destroy(vws, surface->sid);
302             goto no_sid;
303          }
304       }
305    } else {
306       /* Legacy surface only support 32-bit svga3d flags */
307       surface->sid = vmw_ioctl_surface_create(vws, (SVGA3dSurface1Flags)flags,
308                                               format, usage, size, numLayers,
309                                               numMipLevels, sampleCount);
310       if(surface->sid == SVGA3D_INVALID_ID)
311          goto no_sid;
312 
313       /* Best estimate for surface size, used for early flushing. */
314       surface->size = buffer_size;
315       surface->buf = NULL;
316    }
317 
318    return svga_winsys_surface(surface);
319 
320 no_sid:
321    if (surface->buf)
322       vmw_svga_winsys_buffer_destroy(sws, surface->buf);
323 
324    FREE(surface);
325 no_surface:
326    return NULL;
327 }
328 
329 static boolean
vmw_svga_winsys_surface_can_create(struct svga_winsys_screen * sws,SVGA3dSurfaceFormat format,SVGA3dSize size,uint32 numLayers,uint32 numMipLevels,uint32 numSamples)330 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
331                                SVGA3dSurfaceFormat format,
332                                SVGA3dSize size,
333                                uint32 numLayers,
334                                uint32 numMipLevels,
335                                uint32 numSamples)
336 {
337    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
338    uint32_t buffer_size;
339 
340    buffer_size = svga3dsurface_get_serialized_size(format, size,
341                                                    numMipLevels,
342                                                    numLayers);
343    if (numSamples > 1)
344       buffer_size *= numSamples;
345 
346    if (buffer_size > vws->ioctl.max_texture_size) {
347 	return FALSE;
348    }
349    return TRUE;
350 }
351 
352 
353 static boolean
vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen * sws,struct svga_winsys_surface * surface)354 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
355                                    struct svga_winsys_surface *surface)
356 {
357    struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
358    return (p_atomic_read(&vsurf->validated) == 0);
359 }
360 
361 
362 static void
vmw_svga_winsys_surface_ref(struct svga_winsys_screen * sws,struct svga_winsys_surface ** pDst,struct svga_winsys_surface * src)363 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
364 			    struct svga_winsys_surface **pDst,
365 			    struct svga_winsys_surface *src)
366 {
367    struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
368    struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
369 
370    vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
371    *pDst = svga_winsys_surface(d_vsurf);
372 }
373 
374 
375 static void
vmw_svga_winsys_destroy(struct svga_winsys_screen * sws)376 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
377 {
378    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
379 
380    vmw_winsys_destroy(vws);
381 }
382 
383 
384 static SVGA3dHardwareVersion
vmw_svga_winsys_get_hw_version(struct svga_winsys_screen * sws)385 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
386 {
387    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
388 
389    if (sws->have_gb_objects)
390       return SVGA3D_HWVERSION_WS8_B1;
391 
392    return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
393 }
394 
395 
396 static boolean
vmw_svga_winsys_get_cap(struct svga_winsys_screen * sws,SVGA3dDevCapIndex index,SVGA3dDevCapResult * result)397 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
398                         SVGA3dDevCapIndex index,
399                         SVGA3dDevCapResult *result)
400 {
401    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
402 
403    if (index > vws->ioctl.num_cap_3d ||
404        index >= SVGA3D_DEVCAP_MAX ||
405        !vws->ioctl.cap_3d[index].has_cap)
406       return FALSE;
407 
408    *result = vws->ioctl.cap_3d[index].result;
409    return TRUE;
410 }
411 
412 struct svga_winsys_gb_shader *
vmw_svga_winsys_shader_create(struct svga_winsys_screen * sws,SVGA3dShaderType type,const uint32 * bytecode,uint32 bytecodeLen)413 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
414 			      SVGA3dShaderType type,
415 			      const uint32 *bytecode,
416 			      uint32 bytecodeLen)
417 {
418    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
419    struct vmw_svga_winsys_shader *shader;
420    void *code;
421 
422    shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
423    if(!shader)
424       goto out_no_shader;
425 
426    pipe_reference_init(&shader->refcnt, 1);
427    p_atomic_set(&shader->validated, 0);
428    shader->screen = vws;
429    shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
430 					       SVGA_BUFFER_USAGE_SHADER,
431 					       bytecodeLen);
432    if (!shader->buf)
433       goto out_no_buf;
434 
435    code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
436    if (!code)
437       goto out_no_buf;
438 
439    memcpy(code, bytecode, bytecodeLen);
440    vmw_svga_winsys_buffer_unmap(sws, shader->buf);
441 
442    if (!sws->have_vgpu10) {
443       shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
444       if (shader->shid == SVGA3D_INVALID_ID)
445          goto out_no_shid;
446    }
447 
448    return svga_winsys_shader(shader);
449 
450 out_no_shid:
451    vmw_svga_winsys_buffer_destroy(sws, shader->buf);
452 out_no_buf:
453    FREE(shader);
454 out_no_shader:
455    return NULL;
456 }
457 
458 void
vmw_svga_winsys_shader_destroy(struct svga_winsys_screen * sws,struct svga_winsys_gb_shader * shader)459 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
460 			       struct svga_winsys_gb_shader *shader)
461 {
462    struct vmw_svga_winsys_shader *d_shader =
463       vmw_svga_winsys_shader(shader);
464 
465    vmw_svga_winsys_shader_reference(&d_shader, NULL);
466 }
467 
468 static void
vmw_svga_winsys_stats_inc(enum svga_stats_count index)469 vmw_svga_winsys_stats_inc(enum svga_stats_count index)
470 {
471 }
472 
473 static void
vmw_svga_winsys_stats_time_push(enum svga_stats_time index,struct svga_winsys_stats_timeframe * tf)474 vmw_svga_winsys_stats_time_push(enum svga_stats_time index,
475                                 struct svga_winsys_stats_timeframe *tf)
476 {
477 }
478 
479 static void
vmw_svga_winsys_stats_time_pop()480 vmw_svga_winsys_stats_time_pop()
481 {
482 }
483 
484 boolean
vmw_winsys_screen_init_svga(struct vmw_winsys_screen * vws)485 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
486 {
487    vws->base.destroy = vmw_svga_winsys_destroy;
488    vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
489    vws->base.get_cap = vmw_svga_winsys_get_cap;
490    vws->base.context_create = vmw_svga_winsys_context_create;
491    vws->base.surface_create = vmw_svga_winsys_surface_create;
492    vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
493    vws->base.surface_reference = vmw_svga_winsys_surface_ref;
494    vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
495    vws->base.buffer_create = vmw_svga_winsys_buffer_create;
496    vws->base.buffer_map = vmw_svga_winsys_buffer_map;
497    vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
498    vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
499    vws->base.surface_init = vmw_svga_winsys_surface_init;
500    vws->base.fence_reference = vmw_svga_winsys_fence_reference;
501    vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
502    vws->base.shader_create = vmw_svga_winsys_shader_create;
503    vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
504    vws->base.fence_finish = vmw_svga_winsys_fence_finish;
505    vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd;
506    vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd;
507    vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync;
508 
509    vws->base.query_create = vmw_svga_winsys_query_create;
510    vws->base.query_init = vmw_svga_winsys_query_init;
511    vws->base.query_destroy = vmw_svga_winsys_query_destroy;
512    vws->base.query_get_result = vmw_svga_winsys_query_get_result;
513 
514    vws->base.stats_inc = vmw_svga_winsys_stats_inc;
515    vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;
516    vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;
517 
518    vws->base.host_log = vmw_svga_winsys_host_log;
519 
520    return TRUE;
521 }
522 
523 
524