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