svga/winsys: Add support for VGPU10
[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 unsigned flag)
127 {
128 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
129
130 return vmw_fence_finish(vws, fence, flag);
131 }
132
133
134
135 static struct svga_winsys_surface *
136 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
137 SVGA3dSurfaceFlags flags,
138 SVGA3dSurfaceFormat format,
139 unsigned usage,
140 SVGA3dSize size,
141 uint32 numLayers,
142 uint32 numMipLevels,
143 unsigned sampleCount)
144 {
145 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
146 struct vmw_svga_winsys_surface *surface;
147 struct vmw_buffer_desc desc;
148 struct pb_manager *provider;
149 uint32_t buffer_size;
150
151 memset(&desc, 0, sizeof(desc));
152 surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
153 if(!surface)
154 goto no_surface;
155
156 pipe_reference_init(&surface->refcnt, 1);
157 p_atomic_set(&surface->validated, 0);
158 surface->screen = vws;
159 pipe_mutex_init(surface->mutex);
160 surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
161 provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
162
163 /*
164 * Used for the backing buffer GB surfaces, and to approximate
165 * when to flush on non-GB hosts.
166 */
167 buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels,
168 numLayers);
169 if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
170 buffer_size += sizeof(SVGA3dDXSOState);
171
172 if (buffer_size > vws->ioctl.max_texture_size) {
173 goto no_sid;
174 }
175
176 if (sws->have_gb_objects) {
177 SVGAGuestPtr ptr = {0,0};
178
179 /*
180 * If the backing buffer size is small enough, try to allocate a
181 * buffer out of the buffer cache. Otherwise, let the kernel allocate
182 * a suitable buffer for us.
183 */
184 if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
185 struct pb_buffer *pb_buf;
186
187 surface->size = buffer_size;
188 desc.pb_desc.alignment = 4096;
189 desc.pb_desc.usage = 0;
190 pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
191 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
192 if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
193 assert(0);
194 }
195
196 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
197 size, numLayers,
198 numMipLevels, sampleCount,
199 ptr.gmrId,
200 surface->buf ? NULL :
201 &desc.region);
202
203 if (surface->sid == SVGA3D_INVALID_ID && surface->buf) {
204
205 /*
206 * Kernel refused to allocate a surface for us.
207 * Perhaps something was wrong with our buffer?
208 * This is really a guard against future new size requirements
209 * on the backing buffers.
210 */
211 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
212 surface->buf = NULL;
213 surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
214 size, numLayers,
215 numMipLevels, sampleCount,
216 0, &desc.region);
217 if (surface->sid == SVGA3D_INVALID_ID)
218 goto no_sid;
219 }
220
221 /*
222 * If the kernel created the buffer for us, wrap it into a
223 * vmw_svga_winsys_buffer.
224 */
225 if (surface->buf == NULL) {
226 struct pb_buffer *pb_buf;
227
228 surface->size = vmw_region_size(desc.region);
229 desc.pb_desc.alignment = 4096;
230 desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
231 pb_buf = provider->create_buffer(provider, surface->size,
232 &desc.pb_desc);
233 surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
234 if (surface->buf == NULL) {
235 vmw_ioctl_region_destroy(desc.region);
236 vmw_ioctl_surface_destroy(vws, surface->sid);
237 goto no_sid;
238 }
239 }
240 } else {
241 surface->sid = vmw_ioctl_surface_create(vws, flags, format, usage,
242 size, numLayers, numMipLevels,
243 sampleCount);
244 if(surface->sid == SVGA3D_INVALID_ID)
245 goto no_sid;
246
247 /* Best estimate for surface size, used for early flushing. */
248 surface->size = buffer_size;
249 surface->buf = NULL;
250 }
251
252 return svga_winsys_surface(surface);
253
254 no_sid:
255 if (surface->buf)
256 vmw_svga_winsys_buffer_destroy(sws, surface->buf);
257
258 FREE(surface);
259 no_surface:
260 return NULL;
261 }
262
263 static boolean
264 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
265 SVGA3dSurfaceFormat format,
266 SVGA3dSize size,
267 uint32 numLayers,
268 uint32 numMipLevels)
269 {
270 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
271 uint32_t buffer_size;
272
273 buffer_size = svga3dsurface_get_serialized_size(format, size,
274 numMipLevels,
275 numLayers);
276 if (buffer_size > vws->ioctl.max_texture_size) {
277 return FALSE;
278 }
279 return TRUE;
280 }
281
282
283 static boolean
284 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
285 struct svga_winsys_surface *surface)
286 {
287 struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
288 return (p_atomic_read(&vsurf->validated) == 0);
289 }
290
291
292 static void
293 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
294 struct svga_winsys_surface **pDst,
295 struct svga_winsys_surface *src)
296 {
297 struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
298 struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
299
300 vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
301 *pDst = svga_winsys_surface(d_vsurf);
302 }
303
304
305 static void
306 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
307 {
308 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
309
310 vmw_winsys_destroy(vws);
311 }
312
313
314 static SVGA3dHardwareVersion
315 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
316 {
317 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
318
319 if (sws->have_gb_objects)
320 return SVGA3D_HWVERSION_WS8_B1;
321
322 return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
323 }
324
325
326 static boolean
327 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
328 SVGA3dDevCapIndex index,
329 SVGA3dDevCapResult *result)
330 {
331 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
332
333 if (index > vws->ioctl.num_cap_3d ||
334 index >= SVGA3D_DEVCAP_MAX ||
335 !vws->ioctl.cap_3d[index].has_cap)
336 return FALSE;
337
338 *result = vws->ioctl.cap_3d[index].result;
339 return TRUE;
340 }
341
342 struct svga_winsys_gb_shader *
343 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
344 SVGA3dShaderType type,
345 const uint32 *bytecode,
346 uint32 bytecodeLen)
347 {
348 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
349 struct vmw_svga_winsys_shader *shader;
350 void *code;
351
352 shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
353 if(!shader)
354 goto out_no_shader;
355
356 pipe_reference_init(&shader->refcnt, 1);
357 p_atomic_set(&shader->validated, 0);
358 shader->screen = vws;
359 shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
360 SVGA_BUFFER_USAGE_SHADER,
361 bytecodeLen);
362 if (!shader->buf)
363 goto out_no_buf;
364
365 code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
366 if (!code)
367 goto out_no_buf;
368
369 memcpy(code, bytecode, bytecodeLen);
370 vmw_svga_winsys_buffer_unmap(sws, shader->buf);
371
372 if (!sws->have_vgpu10) {
373 shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
374 if (shader->shid == SVGA3D_INVALID_ID)
375 goto out_no_shid;
376 }
377
378 return svga_winsys_shader(shader);
379
380 out_no_shid:
381 vmw_svga_winsys_buffer_destroy(sws, shader->buf);
382 out_no_buf:
383 FREE(shader);
384 out_no_shader:
385 return NULL;
386 }
387
388 void
389 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
390 struct svga_winsys_gb_shader *shader)
391 {
392 struct vmw_svga_winsys_shader *d_shader =
393 vmw_svga_winsys_shader(shader);
394
395 vmw_svga_winsys_shader_reference(&d_shader, NULL);
396 }
397
398 boolean
399 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
400 {
401 vws->base.destroy = vmw_svga_winsys_destroy;
402 vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
403 vws->base.get_cap = vmw_svga_winsys_get_cap;
404 vws->base.context_create = vmw_svga_winsys_context_create;
405 vws->base.surface_create = vmw_svga_winsys_surface_create;
406 vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
407 vws->base.surface_reference = vmw_svga_winsys_surface_ref;
408 vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
409 vws->base.buffer_create = vmw_svga_winsys_buffer_create;
410 vws->base.buffer_map = vmw_svga_winsys_buffer_map;
411 vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
412 vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
413 vws->base.fence_reference = vmw_svga_winsys_fence_reference;
414 vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
415 vws->base.shader_create = vmw_svga_winsys_shader_create;
416 vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
417 vws->base.fence_finish = vmw_svga_winsys_fence_finish;
418
419 vws->base.query_create = vmw_svga_winsys_query_create;
420 vws->base.query_init = vmw_svga_winsys_query_init;
421 vws->base.query_destroy = vmw_svga_winsys_query_destroy;
422 vws->base.query_get_result = vmw_svga_winsys_query_get_result;
423
424 return TRUE;
425 }
426
427