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