0157f60c855a7399160912e5e537cff801acebb3
[mesa.git] / src / gallium / winsys / svga / drm / vmw_screen_svga.c
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 *
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
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
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
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
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
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
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 int32_t fd = sws->fence_get_fd(sws, fence, FALSE);
162
163 /* If we don't have fd, we don't need to merge fd into the context's fd. */
164 if (fd == -1)
165 return 0;
166
167 return sync_accumulate("vmwgfx", context_fd, fd);
168 }
169
170
171 static struct svga_winsys_surface *
172 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
173 SVGA3dSurfaceAllFlags allflags,
174 SVGA3dSurfaceFormat format,
175 unsigned usage,
176 SVGA3dSize size,
177 uint32 numLayers,
178 uint32 numMipLevels,
179 unsigned sampleCount)
180 {
181 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
182 struct vmw_svga_winsys_surface *surface;
183 struct vmw_buffer_desc desc;
184 struct pb_manager *provider;
185 uint32_t buffer_size;
186
187 /* Until the kernel supports 64 bits surface flag, the linux driver
188 * only honors the lower 32 bits of the surface flag.
189 */
190 SVGA3dSurface1Flags flags = (SVGA3dSurface1Flags)allflags;
191
192 memset(&desc, 0, sizeof(desc));
193 surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
194 if(!surface)
195 goto no_surface;
196
197 pipe_reference_init(&surface->refcnt, 1);
198 p_atomic_set(&surface->validated, 0);
199 surface->screen = vws;
200 (void) mtx_init(&surface->mutex, mtx_plain);
201 surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
202 provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
203
204 /*
205 * Used for the backing buffer GB surfaces, and to approximate
206 * when to flush on non-GB hosts.
207 */
208 buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels,
209 numLayers);
210 if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
211 buffer_size += sizeof(SVGA3dDXSOState);
212
213 if (buffer_size > vws->ioctl.max_texture_size) {
214 goto no_sid;
215 }
216
217 if (sws->have_gb_objects) {
218 SVGAGuestPtr ptr = {0,0};
219
220 /*
221 * If the backing buffer size is small enough, try to allocate a
222 * buffer out of the buffer cache. Otherwise, let the kernel allocate
223 * a suitable buffer for us.
224 */
225 if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
226 struct pb_buffer *pb_buf;
227
228 surface->size = buffer_size;
229 desc.pb_desc.alignment = 4096;
230 desc.pb_desc.usage = 0;
231 pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
232 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
233 if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
234 assert(0);
235 }
236
237 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
238 size, numLayers,
239 numMipLevels, sampleCount,
240 ptr.gmrId,
241 surface->buf ? NULL :
242 &desc.region);
243
244 if (surface->sid == SVGA3D_INVALID_ID) {
245 if (surface->buf == NULL) {
246 goto no_sid;
247 } else {
248 /*
249 * Kernel refused to allocate a surface for us.
250 * Perhaps something was wrong with our buffer?
251 * This is really a guard against future new size requirements
252 * on the backing buffers.
253 */
254 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
255 surface->buf = NULL;
256 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
257 size, numLayers,
258 numMipLevels, sampleCount,
259 0, &desc.region);
260 if (surface->sid == SVGA3D_INVALID_ID)
261 goto no_sid;
262 }
263 }
264
265 /*
266 * If the kernel created the buffer for us, wrap it into a
267 * vmw_svga_winsys_buffer.
268 */
269 if (surface->buf == NULL) {
270 struct pb_buffer *pb_buf;
271
272 surface->size = vmw_region_size(desc.region);
273 desc.pb_desc.alignment = 4096;
274 desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
275 pb_buf = provider->create_buffer(provider, surface->size,
276 &desc.pb_desc);
277 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
278 if (surface->buf == NULL) {
279 vmw_ioctl_region_destroy(desc.region);
280 vmw_ioctl_surface_destroy(vws, surface->sid);
281 goto no_sid;
282 }
283 }
284 } else {
285 surface->sid = vmw_ioctl_surface_create(vws, flags, format, usage,
286 size, numLayers, numMipLevels,
287 sampleCount);
288 if(surface->sid == SVGA3D_INVALID_ID)
289 goto no_sid;
290
291 /* Best estimate for surface size, used for early flushing. */
292 surface->size = buffer_size;
293 surface->buf = NULL;
294 }
295
296 return svga_winsys_surface(surface);
297
298 no_sid:
299 if (surface->buf)
300 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
301
302 FREE(surface);
303 no_surface:
304 return NULL;
305 }
306
307 static boolean
308 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
309 SVGA3dSurfaceFormat format,
310 SVGA3dSize size,
311 uint32 numLayers,
312 uint32 numMipLevels,
313 uint32 numSamples)
314 {
315 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
316 uint32_t buffer_size;
317
318 buffer_size = svga3dsurface_get_serialized_size(format, size,
319 numMipLevels,
320 numLayers);
321 if (numSamples > 1)
322 buffer_size *= numSamples;
323
324 if (buffer_size > vws->ioctl.max_texture_size) {
325 return FALSE;
326 }
327 return TRUE;
328 }
329
330
331 static boolean
332 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
333 struct svga_winsys_surface *surface)
334 {
335 struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
336 return (p_atomic_read(&vsurf->validated) == 0);
337 }
338
339
340 static void
341 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
342 struct svga_winsys_surface **pDst,
343 struct svga_winsys_surface *src)
344 {
345 struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
346 struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
347
348 vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
349 *pDst = svga_winsys_surface(d_vsurf);
350 }
351
352
353 static void
354 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
355 {
356 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
357
358 vmw_winsys_destroy(vws);
359 }
360
361
362 static SVGA3dHardwareVersion
363 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
364 {
365 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
366
367 if (sws->have_gb_objects)
368 return SVGA3D_HWVERSION_WS8_B1;
369
370 return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
371 }
372
373
374 static boolean
375 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
376 SVGA3dDevCapIndex index,
377 SVGA3dDevCapResult *result)
378 {
379 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
380
381 if (index > vws->ioctl.num_cap_3d ||
382 index >= SVGA3D_DEVCAP_MAX ||
383 !vws->ioctl.cap_3d[index].has_cap)
384 return FALSE;
385
386 *result = vws->ioctl.cap_3d[index].result;
387 return TRUE;
388 }
389
390 struct svga_winsys_gb_shader *
391 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
392 SVGA3dShaderType type,
393 const uint32 *bytecode,
394 uint32 bytecodeLen)
395 {
396 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
397 struct vmw_svga_winsys_shader *shader;
398 void *code;
399
400 shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
401 if(!shader)
402 goto out_no_shader;
403
404 pipe_reference_init(&shader->refcnt, 1);
405 p_atomic_set(&shader->validated, 0);
406 shader->screen = vws;
407 shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
408 SVGA_BUFFER_USAGE_SHADER,
409 bytecodeLen);
410 if (!shader->buf)
411 goto out_no_buf;
412
413 code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
414 if (!code)
415 goto out_no_buf;
416
417 memcpy(code, bytecode, bytecodeLen);
418 vmw_svga_winsys_buffer_unmap(sws, shader->buf);
419
420 if (!sws->have_vgpu10) {
421 shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
422 if (shader->shid == SVGA3D_INVALID_ID)
423 goto out_no_shid;
424 }
425
426 return svga_winsys_shader(shader);
427
428 out_no_shid:
429 vmw_svga_winsys_buffer_destroy(sws, shader->buf);
430 out_no_buf:
431 FREE(shader);
432 out_no_shader:
433 return NULL;
434 }
435
436 void
437 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
438 struct svga_winsys_gb_shader *shader)
439 {
440 struct vmw_svga_winsys_shader *d_shader =
441 vmw_svga_winsys_shader(shader);
442
443 vmw_svga_winsys_shader_reference(&d_shader, NULL);
444 }
445
446 static void
447 vmw_svga_winsys_stats_inc(enum svga_stats_count index)
448 {
449 }
450
451 static void
452 vmw_svga_winsys_stats_time_push(enum svga_stats_time index,
453 struct svga_winsys_stats_timeframe *tf)
454 {
455 }
456
457 static void
458 vmw_svga_winsys_stats_time_pop()
459 {
460 }
461
462 boolean
463 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
464 {
465 vws->base.destroy = vmw_svga_winsys_destroy;
466 vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
467 vws->base.get_cap = vmw_svga_winsys_get_cap;
468 vws->base.context_create = vmw_svga_winsys_context_create;
469 vws->base.surface_create = vmw_svga_winsys_surface_create;
470 vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
471 vws->base.surface_reference = vmw_svga_winsys_surface_ref;
472 vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
473 vws->base.buffer_create = vmw_svga_winsys_buffer_create;
474 vws->base.buffer_map = vmw_svga_winsys_buffer_map;
475 vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
476 vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
477 vws->base.fence_reference = vmw_svga_winsys_fence_reference;
478 vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
479 vws->base.shader_create = vmw_svga_winsys_shader_create;
480 vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
481 vws->base.fence_finish = vmw_svga_winsys_fence_finish;
482 vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd;
483 vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd;
484 vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync;
485
486 vws->base.query_create = vmw_svga_winsys_query_create;
487 vws->base.query_init = vmw_svga_winsys_query_init;
488 vws->base.query_destroy = vmw_svga_winsys_query_destroy;
489 vws->base.query_get_result = vmw_svga_winsys_query_get_result;
490
491 vws->base.stats_inc = vmw_svga_winsys_stats_inc;
492 vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;
493 vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;
494
495 return TRUE;
496 }
497
498