b1ad686022a0905f838cca62dfb3804f3e2046c8
[profile/ivi/mesa.git] / src / gallium / drivers / nouveau / nouveau_screen.c
1 #include "pipe/p_defines.h"
2 #include "pipe/p_screen.h"
3 #include "pipe/p_state.h"
4
5 #include "util/u_memory.h"
6 #include "util/u_inlines.h"
7 #include "util/u_format.h"
8
9 #include <stdio.h>
10 #include <errno.h>
11
12 #include "nouveau/nouveau_bo.h"
13 #include "nouveau_winsys.h"
14 #include "nouveau_screen.h"
15
16 /* XXX this should go away */
17 #include "state_tracker/drm_api.h"
18
19 static const char *
20 nouveau_screen_get_name(struct pipe_screen *pscreen)
21 {
22         struct nouveau_device *dev = nouveau_screen(pscreen)->device;
23         static char buffer[128];
24
25         snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset);
26         return buffer;
27 }
28
29 static const char *
30 nouveau_screen_get_vendor(struct pipe_screen *pscreen)
31 {
32         return "nouveau";
33 }
34
35 static struct pipe_buffer *
36 nouveau_screen_bo_skel(struct pipe_screen *pscreen, struct nouveau_bo *bo,
37                        unsigned alignment, unsigned usage, unsigned size)
38 {
39         struct pipe_buffer *pb;
40
41         pb = CALLOC(1, sizeof(struct pipe_buffer)+sizeof(struct nouveau_bo *));
42         if (!pb) {
43                 nouveau_bo_ref(NULL, &bo);
44                 return NULL;
45         }
46
47         pipe_reference_init(&pb->reference, 1);
48         pb->screen = pscreen;
49         pb->alignment = alignment;
50         pb->usage = usage;
51         pb->size = size;
52         *(struct nouveau_bo **)(pb + 1) = bo;
53         return pb;
54 }
55
56 static struct pipe_buffer *
57 nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
58                       unsigned usage, unsigned size)
59 {
60         struct nouveau_device *dev = nouveau_screen(pscreen)->device;
61         struct nouveau_bo *bo = NULL;
62         uint32_t flags = NOUVEAU_BO_MAP, tile_mode = 0, tile_flags = 0;
63         int ret;
64
65         if (usage & NOUVEAU_BUFFER_USAGE_TRANSFER)
66                 flags |= NOUVEAU_BO_GART;
67         else
68         if (usage & PIPE_BUFFER_USAGE_VERTEX) {
69                 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF))
70                         flags |= NOUVEAU_BO_GART;
71         } else
72         if (usage & PIPE_BUFFER_USAGE_INDEX) {
73                 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF))
74                         flags |= NOUVEAU_BO_GART;
75         }
76
77         if (usage & PIPE_BUFFER_USAGE_PIXEL) {
78                 if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE)
79                         flags |= NOUVEAU_BO_GART;
80                 if (!(usage & PIPE_BUFFER_USAGE_CPU_READ_WRITE))
81                         flags |= NOUVEAU_BO_VRAM;
82
83                 if (dev->chipset == 0x50 || dev->chipset >= 0x80) {
84                         if (usage & NOUVEAU_BUFFER_USAGE_ZETA)
85                                 tile_flags = 0x2800;
86                         else
87                                 tile_flags = 0x7000;
88                 }
89         }
90
91         ret = nouveau_bo_new_tile(dev, flags, alignment, size,
92                                   tile_mode, tile_flags, &bo);
93         if (ret)
94                 return NULL;
95
96         return nouveau_screen_bo_skel(pscreen, bo, alignment, usage, size);
97 }
98
99 static struct pipe_buffer *
100 nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes)
101 {
102         struct nouveau_device *dev = nouveau_screen(pscreen)->device;
103         struct nouveau_bo *bo = NULL;
104         int ret;
105
106         ret = nouveau_bo_user(dev, ptr, bytes, &bo);
107         if (ret)
108                 return NULL;
109
110         return nouveau_screen_bo_skel(pscreen, bo, 0, 0, bytes);
111 }
112
113 static inline uint32_t
114 nouveau_screen_map_flags(unsigned pipe)
115 {
116         uint32_t flags = 0;
117
118         if (pipe & PIPE_BUFFER_USAGE_CPU_READ)
119                 flags |= NOUVEAU_BO_RD;
120         if (pipe & PIPE_BUFFER_USAGE_CPU_WRITE)
121                 flags |= NOUVEAU_BO_WR;
122         if (pipe & PIPE_BUFFER_USAGE_DISCARD)
123                 flags |= NOUVEAU_BO_INVAL;
124         if (pipe & PIPE_BUFFER_USAGE_DONTBLOCK)
125                 flags |= NOUVEAU_BO_NOWAIT;
126         else
127         if (pipe & PIPE_BUFFER_USAGE_UNSYNCHRONIZED)
128                 flags |= NOUVEAU_BO_NOSYNC;
129
130         return flags;
131 }
132
133 static void *
134 nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb,
135                       unsigned usage)
136 {
137         struct nouveau_bo *bo = nouveau_bo(pb);
138         struct nouveau_screen *nscreen = nouveau_screen(pscreen);
139         int ret;
140
141         if (nscreen->pre_pipebuffer_map_callback) {
142                 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
143                 if (ret) {
144                         debug_printf("pre_pipebuffer_map_callback failed %d\n",
145                                 ret);
146                         return NULL;
147                 }
148         }
149
150         ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage));
151         if (ret) {
152                 debug_printf("map failed: %d\n", ret);
153                 return NULL;
154         }
155
156         return bo->map;
157 }
158
159 static void *
160 nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb,
161                             unsigned offset, unsigned length, unsigned usage)
162 {
163         struct nouveau_bo *bo = nouveau_bo(pb);
164         struct nouveau_screen *nscreen = nouveau_screen(pscreen);
165         uint32_t flags = nouveau_screen_map_flags(usage);
166         int ret;
167
168         if (nscreen->pre_pipebuffer_map_callback) {
169                 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
170                 if (ret) {
171                         debug_printf("pre_pipebuffer_map_callback failed %d\n",
172                                 ret);
173                         return NULL;
174                 }
175         }
176
177         ret = nouveau_bo_map_range(bo, offset, length, flags);
178         if (ret) {
179                 nouveau_bo_unmap(bo);
180                 if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY)
181                         debug_printf("map_range failed: %d\n", ret);
182                 return NULL;
183         }
184
185         return (char *)bo->map - offset; /* why gallium? why? */
186 }
187
188 static void
189 nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb,
190                             unsigned offset, unsigned length)
191 {
192         struct nouveau_bo *bo = nouveau_bo(pb);
193
194         nouveau_bo_map_flush(bo, offset, length);
195 }
196
197 static void
198 nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb)
199 {
200         struct nouveau_bo *bo = nouveau_bo(pb);
201
202         nouveau_bo_unmap(bo);
203 }
204
205 static void
206 nouveau_screen_bo_del(struct pipe_buffer *pb)
207 {
208         struct nouveau_bo *bo = nouveau_bo(pb);
209
210         nouveau_bo_ref(NULL, &bo);
211         FREE(pb);
212 }
213
214 static void
215 nouveau_screen_fence_ref(struct pipe_screen *pscreen,
216                          struct pipe_fence_handle **ptr,
217                          struct pipe_fence_handle *pfence)
218 {
219         *ptr = pfence;
220 }
221
222 static int
223 nouveau_screen_fence_signalled(struct pipe_screen *screen,
224                                struct pipe_fence_handle *pfence,
225                                unsigned flags)
226 {
227         return 0;
228 }
229
230 static int
231 nouveau_screen_fence_finish(struct pipe_screen *screen,
232                             struct pipe_fence_handle *pfence,
233                             unsigned flags)
234 {
235         return 0;
236 }
237
238
239 /*
240  * Both texture_{from|get}_handle use drm api defines directly which they
241  * shouldn't do. The problem is that from|get are pipe functions and as
242  * such they should be defined in the pipe level. If nouveau had a propper
243  * winsys interface we would have added from|get to that interface using
244  * the winsys_handle struct as done with other drivers. However this code
245  * calls directly into the libdrm_nouveau.so functions (nouveau_bo_*). So
246  * we need to translate the handle into something they understand.
247  */
248 static struct pipe_texture *
249 nouveau_screen_texture_from_handle(struct pipe_screen *pscreen,
250                                    const struct pipe_texture *templ,
251                                    struct winsys_handle *whandle)
252 {
253         struct nouveau_device *dev = nouveau_screen(pscreen)->device;
254         struct pipe_texture *pt;
255         struct pipe_buffer *pb;
256         int ret;
257
258         pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*));
259         if (!pb)
260                 return NULL;
261
262         ret = nouveau_bo_handle_ref(dev, whandle->handle, (struct nouveau_bo**)(pb+1));
263         if (ret) {
264                 debug_printf("%s: ref name 0x%08x failed with %d\n",
265                              __func__, whandle->handle, ret);
266                 FREE(pb);
267                 return NULL;
268         }
269
270         pipe_reference_init(&pb->reference, 1);
271         pb->screen = pscreen;
272         pb->alignment = 0;
273         pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
274                     PIPE_BUFFER_USAGE_CPU_READ_WRITE;
275         pb->size = nouveau_bo(pb)->size;
276         pt = nouveau_screen(pscreen)->texture_blanket(pscreen, templ,
277                                                       &whandle->stride, pb);
278         pipe_buffer_reference(&pb, NULL);
279         return pt;
280 }
281
282 static boolean
283 nouveau_screen_texture_get_handle(struct pipe_screen *pscreen,
284                                   struct pipe_texture *pt,
285                                   struct winsys_handle *whandle)
286 {
287         struct nouveau_miptree *mt = nouveau_miptree(pt);
288
289         if (!mt || !mt->bo)
290                 return false;
291
292         whandle->stride = util_format_get_stride(mt->base.format, mt->base.width0);
293
294         if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { 
295                 return nouveau_bo_handle_get(mt->bo, &whandle->handle) == 0;
296         } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
297                 whandle->handle = mt->bo->handle;
298                 return TRUE;
299         } else {
300                 return FALSE;
301         }
302 }
303
304 int
305 nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
306 {
307         struct pipe_screen *pscreen = &screen->base;
308         int ret;
309
310         ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202,
311                                     &screen->channel);
312         if (ret)
313                 return ret;
314         screen->device = dev;
315
316         pscreen->get_name = nouveau_screen_get_name;
317         pscreen->get_vendor = nouveau_screen_get_vendor;
318
319         pscreen->buffer_create = nouveau_screen_bo_new;
320         pscreen->user_buffer_create = nouveau_screen_bo_user;
321         pscreen->buffer_map = nouveau_screen_bo_map;
322         pscreen->buffer_map_range = nouveau_screen_bo_map_range;
323         pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush;
324         pscreen->buffer_unmap = nouveau_screen_bo_unmap;
325         pscreen->buffer_destroy = nouveau_screen_bo_del;
326
327         pscreen->fence_reference = nouveau_screen_fence_ref;
328         pscreen->fence_signalled = nouveau_screen_fence_signalled;
329         pscreen->fence_finish = nouveau_screen_fence_finish;
330
331         pscreen->texture_from_handle = nouveau_screen_texture_from_handle;
332         pscreen->texture_get_handle = nouveau_screen_texture_get_handle;
333
334         return 0;
335 }
336
337 void
338 nouveau_screen_fini(struct nouveau_screen *screen)
339 {
340         struct pipe_winsys *ws = screen->base.winsys;
341         nouveau_channel_free(&screen->channel);
342         ws->destroy(ws);
343 }
344