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