Merge remote branch 'origin/mesa_7_6_branch'
[mesa.git] / src / gallium / winsys / drm / nouveau / drm / nouveau_drm_api.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_memory.h"
4
5 #include "nouveau_drm_api.h"
6
7 #include "nouveau_drmif.h"
8 #include "nouveau_channel.h"
9 #include "nouveau_bo.h"
10
11 #include "nouveau/nouveau_winsys.h"
12 #include "nouveau/nouveau_screen.h"
13
14 static struct pipe_surface *
15 dri_surface_from_handle(struct drm_api *api, struct pipe_screen *pscreen,
16 unsigned handle, enum pipe_format format,
17 unsigned width, unsigned height, unsigned pitch)
18 {
19 struct pipe_surface *ps = NULL;
20 struct pipe_texture *pt = NULL;
21 struct pipe_texture tmpl;
22
23 memset(&tmpl, 0, sizeof(tmpl));
24 tmpl.tex_usage = PIPE_TEXTURE_USAGE_PRIMARY;
25 tmpl.target = PIPE_TEXTURE_2D;
26 tmpl.last_level = 0;
27 tmpl.depth[0] = 1;
28 tmpl.format = format;
29 tmpl.width[0] = width;
30 tmpl.height[0] = height;
31 pf_get_block(tmpl.format, &tmpl.block);
32
33 pt = api->texture_from_shared_handle(api, pscreen, &tmpl,
34 "front buffer", pitch, handle);
35 if (!pt)
36 return NULL;
37
38 ps = pscreen->get_tex_surface(pscreen, pt, 0, 0, 0,
39 PIPE_BUFFER_USAGE_GPU_READ |
40 PIPE_BUFFER_USAGE_GPU_WRITE);
41
42 /* we don't need the texture from this point on */
43 pipe_texture_reference(&pt, NULL);
44 return ps;
45 }
46
47 static struct pipe_surface *
48 nouveau_dri1_front_surface(struct pipe_context *pipe)
49 {
50 return nouveau_winsys_screen(pipe->screen)->front;
51 }
52
53 static struct dri1_api nouveau_dri1_api = {
54 nouveau_dri1_front_surface,
55 };
56
57 static struct pipe_screen *
58 nouveau_drm_create_screen(struct drm_api *api, int fd,
59 struct drm_create_screen_arg *arg)
60 {
61 struct dri1_create_screen_arg *dri1 = (void *)arg;
62 struct nouveau_winsys *nvws;
63 struct pipe_winsys *ws;
64 struct nouveau_device *dev = NULL;
65 struct pipe_screen *(*init)(struct pipe_winsys *,
66 struct nouveau_device *);
67 int ret;
68
69 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
70 if (ret)
71 return NULL;
72
73 switch (dev->chipset & 0xf0) {
74 case 0x00:
75 init = nv04_screen_create;
76 break;
77 case 0x10:
78 init = nv10_screen_create;
79 break;
80 case 0x20:
81 init = nv20_screen_create;
82 break;
83 case 0x30:
84 init = nv30_screen_create;
85 break;
86 case 0x40:
87 case 0x60:
88 init = nv40_screen_create;
89 break;
90 case 0x80:
91 case 0x90:
92 case 0xa0:
93 init = nv50_screen_create;
94 break;
95 default:
96 debug_printf("%s: unknown chipset nv%02x\n", __func__,
97 dev->chipset);
98 return NULL;
99 }
100
101 nvws = CALLOC_STRUCT(nouveau_winsys);
102 if (!nvws) {
103 nouveau_device_close(&dev);
104 return NULL;
105 }
106 ws = &nvws->base;
107
108 nvws->pscreen = init(ws, dev);
109 if (!nvws->pscreen) {
110 ws->destroy(ws);
111 return NULL;
112 }
113
114 if (arg && arg->mode == DRM_CREATE_DRI1) {
115 struct nouveau_dri *nvdri = dri1->ddx_info;
116 enum pipe_format format;
117
118 if (nvdri->bpp == 16)
119 format = PIPE_FORMAT_R5G6B5_UNORM;
120 else
121 format = PIPE_FORMAT_A8R8G8B8_UNORM;
122
123 nvws->front = dri_surface_from_handle(api, nvws->pscreen,
124 nvdri->front_offset,
125 format, nvdri->width,
126 nvdri->height,
127 nvdri->front_pitch *
128 (nvdri->bpp / 8));
129 if (!nvws->front) {
130 debug_printf("%s: error referencing front buffer\n",
131 __func__);
132 ws->destroy(ws);
133 return NULL;
134 }
135
136 dri1->api = &nouveau_dri1_api;
137 }
138
139 return nvws->pscreen;
140 }
141
142 static struct pipe_context *
143 nouveau_drm_create_context(struct drm_api *api, struct pipe_screen *pscreen)
144 {
145 struct nouveau_winsys *nvws = nouveau_winsys_screen(pscreen);
146 struct pipe_context *(*init)(struct pipe_screen *, unsigned);
147 unsigned chipset = nouveau_screen(pscreen)->device->chipset;
148 int i;
149
150 switch (chipset & 0xf0) {
151 case 0x00:
152 init = nv04_create;
153 break;
154 case 0x10:
155 init = nv10_create;
156 break;
157 case 0x20:
158 init = nv20_create;
159 break;
160 case 0x30:
161 init = nv30_create;
162 break;
163 case 0x40:
164 case 0x60:
165 init = nv40_create;
166 break;
167 case 0x80:
168 case 0x90:
169 case 0xa0:
170 init = nv50_create;
171 break;
172 default:
173 debug_printf("%s: unknown chipset nv%02x\n", __func__, chipset);
174 return NULL;
175 }
176
177 /* Find a free slot for a pipe context, allocate a new one if needed */
178 for (i = 0; i < nvws->nr_pctx; i++) {
179 if (nvws->pctx[i] == NULL)
180 break;
181 }
182
183 if (i == nvws->nr_pctx) {
184 nvws->nr_pctx++;
185 nvws->pctx = realloc(nvws->pctx,
186 sizeof(*nvws->pctx) * nvws->nr_pctx);
187 }
188
189 nvws->pctx[i] = init(pscreen, i);
190 return nvws->pctx[i];
191 }
192
193 static struct pipe_texture *
194 nouveau_drm_pt_from_name(struct drm_api *api, struct pipe_screen *pscreen,
195 struct pipe_texture *templ, const char *name,
196 unsigned stride, unsigned handle)
197 {
198 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
199 struct pipe_texture *pt;
200 struct pipe_buffer *pb;
201 int ret;
202
203 pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*));
204 if (!pb)
205 return NULL;
206
207 ret = nouveau_bo_handle_ref(dev, handle, (struct nouveau_bo**)(pb+1));
208 if (ret) {
209 debug_printf("%s: ref name 0x%08x failed with %d\n",
210 __func__, handle, ret);
211 FREE(pb);
212 return NULL;
213 }
214
215 pipe_reference_init(&pb->reference, 1);
216 pb->screen = pscreen;
217 pb->alignment = 0;
218 pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
219 PIPE_BUFFER_USAGE_CPU_READ_WRITE;
220 pb->size = nouveau_bo(pb)->size;
221 pt = pscreen->texture_blanket(pscreen, templ, &stride, pb);
222 pipe_buffer_reference(&pb, NULL);
223 return pt;
224 }
225
226 static boolean
227 nouveau_drm_name_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
228 struct pipe_texture *pt, unsigned *stride,
229 unsigned *handle)
230 {
231 struct nouveau_miptree *mt = nouveau_miptree(pt);
232
233 if (!mt || !mt->bo)
234 return false;
235
236 return nouveau_bo_handle_get(mt->bo, handle) == 0;
237 }
238
239 static boolean
240 nouveau_drm_handle_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
241 struct pipe_texture *pt, unsigned *stride,
242 unsigned *handle)
243 {
244 struct nouveau_miptree *mt = nouveau_miptree(pt);
245
246 if (!mt || !mt->bo)
247 return false;
248
249 *handle = mt->bo->handle;
250 *stride = mt->base.nblocksx[0] * mt->base.block.size;
251 return true;
252 }
253
254 struct drm_api drm_api_hooks = {
255 .create_screen = nouveau_drm_create_screen,
256 .create_context = nouveau_drm_create_context,
257 .texture_from_shared_handle = nouveau_drm_pt_from_name,
258 .shared_handle_from_texture = nouveau_drm_name_from_pt,
259 .local_handle_from_texture = nouveau_drm_handle_from_pt,
260 };
261
262 struct drm_api *
263 drm_api_create() {
264 return &drm_api_hooks;
265 }
266