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 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 = drm_api_hooks.buffer_from_handle(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(int fd, struct drm_create_screen_arg *arg)
74 {
75 struct dri1_create_screen_arg *dri1 = (void *)arg;
76 struct nouveau_winsys *nvws;
77 struct pipe_winsys *ws;
78 struct nouveau_device *dev = NULL;
79 struct pipe_screen *(*init)(struct pipe_winsys *,
80 struct nouveau_device *);
81 int ret;
82
83 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
84 if (ret)
85 return NULL;
86
87 switch (dev->chipset & 0xf0) {
88 case 0x00:
89 init = nv04_screen_create;
90 break;
91 case 0x10:
92 init = nv10_screen_create;
93 break;
94 case 0x20:
95 init = nv20_screen_create;
96 break;
97 case 0x30:
98 init = nv30_screen_create;
99 break;
100 case 0x40:
101 case 0x60:
102 init = nv40_screen_create;
103 break;
104 case 0x80:
105 case 0x90:
106 case 0xa0:
107 init = nv50_screen_create;
108 break;
109 default:
110 debug_printf("%s: unknown chipset nv%02x\n", __func__,
111 dev->chipset);
112 return NULL;
113 }
114
115 nvws = CALLOC_STRUCT(nouveau_winsys);
116 if (!nvws) {
117 nouveau_device_close(&dev);
118 return NULL;
119 }
120 ws = &nvws->base;
121
122 nvws->pscreen = init(ws, dev);
123 if (!nvws->pscreen) {
124 ws->destroy(ws);
125 return NULL;
126 }
127
128 if (arg->mode == DRM_CREATE_DRI1) {
129 struct nouveau_dri *nvdri = dri1->ddx_info;
130 enum pipe_format format;
131
132 if (nvdri->bpp == 16)
133 format = PIPE_FORMAT_R5G6B5_UNORM;
134 else
135 format = PIPE_FORMAT_A8R8G8B8_UNORM;
136
137 nvws->front = dri_surface_from_handle(nvws->pscreen,
138 nvdri->front_offset,
139 format,
140 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 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 pipe_texture *pt, struct pipe_buffer **ppb,
210 unsigned *stride)
211 {
212 return false;
213 }
214
215 static struct pipe_buffer *
216 nouveau_drm_pb_from_handle(struct pipe_screen *pscreen, const char *name,
217 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 pipe_screen *pscreen, struct pipe_buffer *pb,
246 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 pipe_screen *pscreen, struct pipe_buffer *pb,
259 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