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