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