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