Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / winsys / drm / vmware / core / vmw_screen_dri.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 #include "pipe/p_compiler.h"
28 #include "pipe/p_inlines.h"
29 #include "util/u_memory.h"
30 #include "vmw_screen.h"
31
32 #include "trace/tr_drm.h"
33
34 #include "vmw_screen.h"
35 #include "vmw_surface.h"
36 #include "vmw_fence.h"
37 #include "vmw_context.h"
38
39 #include <state_tracker/dri1_api.h>
40 #include <state_tracker/drm_api.h>
41 #include <vmwgfx_drm.h>
42 #include <xf86drm.h>
43
44 #include <stdio.h>
45
46 static struct dri1_api dri1_api_hooks;
47 static struct dri1_api_version ddx_required = { 0, 1, 0 };
48 static struct dri1_api_version ddx_compat = { 0, 0, 0 };
49 static struct dri1_api_version dri_required = { 4, 0, 0 };
50 static struct dri1_api_version dri_compat = { 4, 0, 0 };
51 static struct dri1_api_version drm_required = { 0, 1, 0 };
52 static struct dri1_api_version drm_compat = { 0, 0, 0 };
53
54 static boolean
55 vmw_dri1_check_version(const struct dri1_api_version *cur,
56 const struct dri1_api_version *required,
57 const struct dri1_api_version *compat,
58 const char component[])
59 {
60 if (cur->major > required->major && cur->major <= compat->major)
61 return TRUE;
62 if (cur->major == required->major && cur->minor >= required->minor)
63 return TRUE;
64
65 fprintf(stderr, "%s version failure.\n", component);
66 fprintf(stderr, "%s version is %d.%d.%d and this driver can only work\n"
67 "with versions %d.%d.x through %d.x.x.\n",
68 component,
69 cur->major,
70 cur->minor,
71 cur->patch_level, required->major, required->minor, compat->major);
72 return FALSE;
73 }
74
75 /* This is actually the entrypoint to the entire driver, called by the
76 * libGL (or EGL, or ...) code via the drm_api_hooks table at the
77 * bottom of the file.
78 */
79 static struct pipe_screen *
80 vmw_drm_create_screen(struct drm_api *drm_api,
81 int fd,
82 struct drm_create_screen_arg *arg)
83 {
84 struct vmw_winsys_screen *vws;
85 struct pipe_screen *screen;
86 struct dri1_create_screen_arg *dri1;
87
88 if (!arg || arg->mode == DRM_CREATE_NORMAL) {
89 struct dri1_api_version drm_ver;
90 drmVersionPtr ver;
91
92 ver = drmGetVersion(fd);
93 if (ver == NULL)
94 return NULL;
95
96 drm_ver.major = ver->version_major;
97 drm_ver.minor = ver->version_minor;
98
99 drmFreeVersion(ver);
100 if (!vmw_dri1_check_version(&drm_ver, &drm_required,
101 &drm_compat, "vmwgfx drm driver"))
102 return NULL;
103 }
104
105 if (arg != NULL) {
106 switch (arg->mode) {
107 case DRM_CREATE_NORMAL:
108 break;
109 case DRM_CREATE_DRI1:
110 dri1 = (struct dri1_create_screen_arg *)arg;
111 if (!vmw_dri1_check_version(&dri1->ddx_version, &ddx_required,
112 &ddx_compat, "ddx - driver api"))
113 return NULL;
114 if (!vmw_dri1_check_version(&dri1->dri_version, &dri_required,
115 &dri_compat, "dri info"))
116 return NULL;
117 if (!vmw_dri1_check_version(&dri1->drm_version, &drm_required,
118 &drm_compat, "vmwgfx drm driver"))
119 return NULL;
120 dri1->api = &dri1_api_hooks;
121 break;
122 default:
123 return NULL;
124 }
125 }
126
127 vws = vmw_winsys_create( fd );
128 if (!vws)
129 goto out_no_vws;
130
131 screen = svga_screen_create( &vws->base );
132 if (!screen)
133 goto out_no_screen;
134
135 return screen;
136
137 /* Failure cases:
138 */
139 out_no_screen:
140 vmw_winsys_destroy( vws );
141
142 out_no_vws:
143 return NULL;
144 }
145
146 static INLINE boolean
147 vmw_dri1_intersect_src_bbox(struct drm_clip_rect *dst,
148 int dst_x,
149 int dst_y,
150 const struct drm_clip_rect *src,
151 const struct drm_clip_rect *bbox)
152 {
153 int xy1;
154 int xy2;
155
156 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
157 (int)bbox->x1 + dst_x;
158 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
159 (int)bbox->x2 + dst_x;
160 if (xy1 >= xy2 || xy1 < 0)
161 return FALSE;
162
163 dst->x1 = xy1;
164 dst->x2 = xy2;
165
166 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
167 (int)bbox->y1 + dst_y;
168 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
169 (int)bbox->y2 + dst_y;
170 if (xy1 >= xy2 || xy1 < 0)
171 return FALSE;
172
173 dst->y1 = xy1;
174 dst->y2 = xy2;
175 return TRUE;
176 }
177
178 /**
179 * No fancy get-surface-from-sarea stuff here.
180 * Just use the present blit.
181 */
182
183 static void
184 vmw_dri1_present_locked(struct pipe_context *locked_pipe,
185 struct pipe_surface *surf,
186 const struct drm_clip_rect *rect,
187 unsigned int num_clip,
188 int x_draw, int y_draw,
189 const struct drm_clip_rect *bbox,
190 struct pipe_fence_handle **p_fence)
191 {
192 struct svga_winsys_surface *srf =
193 svga_screen_texture_get_winsys_surface(surf->texture);
194 struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
195 struct vmw_winsys_screen *vws =
196 vmw_winsys_screen(svga_winsys_screen(locked_pipe->screen));
197 struct drm_clip_rect clip;
198 int i;
199 struct
200 {
201 SVGA3dCmdHeader header;
202 SVGA3dCmdPresent body;
203 SVGA3dCopyRect rect;
204 } cmd;
205 boolean visible = FALSE;
206 uint32_t fence_seq = 0;
207
208 VMW_FUNC;
209 cmd.header.id = SVGA_3D_CMD_PRESENT;
210 cmd.header.size = sizeof cmd.body + sizeof cmd.rect;
211 cmd.body.sid = vsrf->sid;
212
213 for (i = 0; i < num_clip; ++i) {
214 if (!vmw_dri1_intersect_src_bbox(&clip, x_draw, y_draw, rect++, bbox))
215 continue;
216
217 cmd.rect.x = clip.x1;
218 cmd.rect.y = clip.y1;
219 cmd.rect.w = clip.x2 - clip.x1;
220 cmd.rect.h = clip.y2 - clip.y1;
221 cmd.rect.srcx = (int)clip.x1 - x_draw;
222 cmd.rect.srcy = (int)clip.y1 - y_draw;
223
224 vmw_printf("%s: Clip %d x %d y %d w %d h %d srcx %d srcy %d\n",
225 __FUNCTION__,
226 i,
227 cmd.rect.x,
228 cmd.rect.y,
229 cmd.rect.w, cmd.rect.h, cmd.rect.srcx, cmd.rect.srcy);
230
231 vmw_ioctl_command(vws, &cmd, sizeof cmd.header + cmd.header.size,
232 &fence_seq);
233 visible = TRUE;
234 }
235
236 *p_fence = (visible) ? vmw_pipe_fence(fence_seq) : NULL;
237 vmw_svga_winsys_surface_reference(&vsrf, NULL);
238 }
239
240 static struct pipe_texture *
241 vmw_drm_texture_from_handle(struct drm_api *drm_api,
242 struct pipe_screen *screen,
243 struct pipe_texture *templat,
244 const char *name,
245 unsigned stride,
246 unsigned handle)
247 {
248 struct vmw_svga_winsys_surface *vsrf;
249 struct svga_winsys_surface *ssrf;
250 struct vmw_winsys_screen *vws =
251 vmw_winsys_screen(svga_winsys_screen(screen));
252 struct pipe_texture *tex;
253 union drm_vmw_surface_reference_arg arg;
254 struct drm_vmw_surface_arg *req = &arg.req;
255 struct drm_vmw_surface_create_req *rep = &arg.rep;
256 int ret;
257 int i;
258
259 /**
260 * The vmware device specific handle is the hardware SID.
261 * FIXME: We probably want to move this to the ioctl implementations.
262 */
263
264 memset(&arg, 0, sizeof(arg));
265 req->sid = handle;
266
267 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
268 &arg, sizeof(arg));
269
270 if (ret) {
271 fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
272 "Error %d (%s).\n",
273 handle, ret, strerror(-ret));
274 return NULL;
275 }
276
277 if (rep->mip_levels[0] != 1) {
278 fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
279 " SID %d, levels %d\n",
280 handle, rep->mip_levels[0]);
281 goto out_mip;
282 }
283
284 for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
285 if (rep->mip_levels[i] != 0) {
286 fprintf(stderr, "Incorrect number of faces levels on shared surface."
287 " SID %d, face %d present.\n",
288 handle, i);
289 goto out_mip;
290 }
291 }
292
293 vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
294 if (!vsrf)
295 goto out_mip;
296
297 pipe_reference_init(&vsrf->refcnt, 1);
298 p_atomic_set(&vsrf->validated, 0);
299 vsrf->screen = vws;
300 vsrf->sid = handle;
301 ssrf = svga_winsys_surface(vsrf);
302 tex = svga_screen_texture_wrap_surface(screen, templat, rep->format, ssrf);
303 if (!tex)
304 vmw_svga_winsys_surface_reference(&vsrf, NULL);
305
306 return tex;
307 out_mip:
308 vmw_ioctl_surface_destroy(vws, handle);
309 return NULL;
310 }
311
312 static boolean
313 vmw_drm_handle_from_texture(struct drm_api *drm_api,
314 struct pipe_screen *screen,
315 struct pipe_texture *texture,
316 unsigned *stride,
317 unsigned *handle)
318 {
319 struct svga_winsys_surface *surface =
320 svga_screen_texture_get_winsys_surface(texture);
321 struct vmw_svga_winsys_surface *vsrf;
322
323 if (!surface)
324 return FALSE;
325
326 vsrf = vmw_svga_winsys_surface(surface);
327 *handle = vsrf->sid;
328 *stride = util_format_get_nblocksx(texture->format, texture->width0) *
329 util_format_get_blocksize(texture->format);
330
331 vmw_svga_winsys_surface_reference(&vsrf, NULL);
332 return TRUE;
333 }
334
335 static struct pipe_context*
336 vmw_drm_create_context(struct drm_api *drm_api,
337 struct pipe_screen *screen)
338 {
339 return vmw_svga_context_create(screen);
340 }
341
342 static struct dri1_api dri1_api_hooks = {
343 .front_srf_locked = NULL,
344 .present_locked = vmw_dri1_present_locked
345 };
346
347 static struct drm_api vmw_drm_api_hooks = {
348 .name = "vmwgfx",
349 .driver_name = "vmwgfx",
350 .create_screen = vmw_drm_create_screen,
351 .create_context = vmw_drm_create_context,
352 .texture_from_shared_handle = vmw_drm_texture_from_handle,
353 .shared_handle_from_texture = vmw_drm_handle_from_texture,
354 .local_handle_from_texture = vmw_drm_handle_from_texture,
355 };
356
357 struct drm_api* drm_api_create()
358 {
359 return trace_drm_create(&vmw_drm_api_hooks);
360 }