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 "vmw_surface.h"
34 #include "svga_drm_public.h"
35 
36 #include "state_tracker/drm_driver.h"
37 
38 #include "vmwgfx_drm.h"
39 #include <xf86drm.h>
40 
41 #include <stdio.h>
42 
43 struct dri1_api_version {
44    int major;
45    int minor;
46    int patch_level;
47 };
48 
49 static struct svga_winsys_surface *
50 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
51 			    struct winsys_handle *whandle,
52 			    SVGA3dSurfaceFormat *format);
53 static boolean
54 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
55 			   struct svga_winsys_surface *surface,
56 			   unsigned stride,
57 			   struct winsys_handle *whandle);
58 
59 static struct dri1_api_version drm_required = { 2, 1, 0 };
60 static struct dri1_api_version drm_compat = { 2, 0, 0 };
61 
62 static boolean
vmw_dri1_check_version(const struct dri1_api_version * cur,const struct dri1_api_version * required,const struct dri1_api_version * compat,const char component[])63 vmw_dri1_check_version(const struct dri1_api_version *cur,
64 		       const struct dri1_api_version *required,
65 		       const struct dri1_api_version *compat,
66 		       const char component[])
67 {
68    if (cur->major > required->major && cur->major <= compat->major)
69       return TRUE;
70    if (cur->major == required->major && cur->minor >= required->minor)
71       return TRUE;
72 
73    fprintf(stderr, "%s version failure.\n", component);
74    fprintf(stderr, "%s version is %d.%d.%d and this driver can only work\n"
75 	   "with versions %d.%d.x through %d.x.x.\n",
76 	   component,
77 	   cur->major,
78 	   cur->minor,
79 	   cur->patch_level, required->major, required->minor, compat->major);
80    return FALSE;
81 }
82 
83 /* This is actually the entrypoint to the entire driver,
84  * called by the target bootstrap code.
85  */
86 struct svga_winsys_screen *
svga_drm_winsys_screen_create(int fd)87 svga_drm_winsys_screen_create(int fd)
88 {
89    struct vmw_winsys_screen *vws;
90    struct dri1_api_version drm_ver;
91    drmVersionPtr ver;
92 
93    ver = drmGetVersion(fd);
94    if (ver == NULL)
95       return NULL;
96 
97    drm_ver.major = ver->version_major;
98    drm_ver.minor = ver->version_minor;
99    drm_ver.patch_level = 0; /* ??? */
100 
101    drmFreeVersion(ver);
102    if (!vmw_dri1_check_version(&drm_ver, &drm_required,
103 			       &drm_compat, "vmwgfx drm driver"))
104       return NULL;
105 
106    vws = vmw_winsys_create( fd, FALSE );
107    if (!vws)
108       goto out_no_vws;
109 
110    /* XXX do this properly */
111    vws->base.surface_from_handle = vmw_drm_surface_from_handle;
112    vws->base.surface_get_handle = vmw_drm_surface_get_handle;
113 
114    return &vws->base;
115 
116 out_no_vws:
117    return NULL;
118 }
119 
120 static INLINE boolean
vmw_dri1_intersect_src_bbox(struct drm_clip_rect * dst,int dst_x,int dst_y,const struct drm_clip_rect * src,const struct drm_clip_rect * bbox)121 vmw_dri1_intersect_src_bbox(struct drm_clip_rect *dst,
122 			    int dst_x,
123 			    int dst_y,
124 			    const struct drm_clip_rect *src,
125 			    const struct drm_clip_rect *bbox)
126 {
127    int xy1;
128    int xy2;
129 
130    xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
131       (int)bbox->x1 + dst_x;
132    xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
133       (int)bbox->x2 + dst_x;
134    if (xy1 >= xy2 || xy1 < 0)
135       return FALSE;
136 
137    dst->x1 = xy1;
138    dst->x2 = xy2;
139 
140    xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
141       (int)bbox->y1 + dst_y;
142    xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
143       (int)bbox->y2 + dst_y;
144    if (xy1 >= xy2 || xy1 < 0)
145       return FALSE;
146 
147    dst->y1 = xy1;
148    dst->y2 = xy2;
149    return TRUE;
150 }
151 
152 static struct svga_winsys_surface *
vmw_drm_surface_from_handle(struct svga_winsys_screen * sws,struct winsys_handle * whandle,SVGA3dSurfaceFormat * format)153 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
154 			    struct winsys_handle *whandle,
155 			    SVGA3dSurfaceFormat *format)
156 {
157     struct vmw_svga_winsys_surface *vsrf;
158     struct svga_winsys_surface *ssrf;
159     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
160     union drm_vmw_surface_reference_arg arg;
161     struct drm_vmw_surface_arg *req = &arg.req;
162     struct drm_vmw_surface_create_req *rep = &arg.rep;
163     int ret;
164     int i;
165 
166     /**
167      * The vmware device specific handle is the hardware SID.
168      * FIXME: We probably want to move this to the ioctl implementations.
169      */
170 
171     memset(&arg, 0, sizeof(arg));
172     req->sid = whandle->handle;
173 
174     ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
175 			      &arg, sizeof(arg));
176 
177     if (ret) {
178 	fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
179 		"Error %d (%s).\n",
180 		whandle->handle, ret, strerror(-ret));
181 	return NULL;
182     }
183 
184     if (rep->mip_levels[0] != 1) {
185 	fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
186 		" SID %d, levels %d\n",
187 		whandle->handle, rep->mip_levels[0]);
188 	goto out_mip;
189     }
190 
191     for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
192 	if (rep->mip_levels[i] != 0) {
193 	    fprintf(stderr, "Incorrect number of faces levels on shared surface."
194 		    " SID %d, face %d present.\n",
195 		    whandle->handle, i);
196 	    goto out_mip;
197 	}
198    }
199 
200     vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
201     if (!vsrf)
202 	goto out_mip;
203 
204     pipe_reference_init(&vsrf->refcnt, 1);
205     p_atomic_set(&vsrf->validated, 0);
206     vsrf->screen = vws;
207     vsrf->sid = whandle->handle;
208     ssrf = svga_winsys_surface(vsrf);
209     *format = rep->format;
210 
211     return ssrf;
212 
213 out_mip:
214     vmw_ioctl_surface_destroy(vws, whandle->handle);
215     return NULL;
216 }
217 
218 static boolean
vmw_drm_surface_get_handle(struct svga_winsys_screen * sws,struct svga_winsys_surface * surface,unsigned stride,struct winsys_handle * whandle)219 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
220 			   struct svga_winsys_surface *surface,
221 			   unsigned stride,
222 			   struct winsys_handle *whandle)
223 {
224     struct vmw_svga_winsys_surface *vsrf;
225 
226     if (!surface)
227 	return FALSE;
228 
229     vsrf = vmw_svga_winsys_surface(surface);
230     whandle->handle = vsrf->sid;
231     whandle->stride = stride;
232 
233     return TRUE;
234 }
235