Merge branch '7.8'
[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