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