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