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