nouveau_screen.c revision ed7f73e161b93b4a83bb6ad6b6aa6cfcb65dc4b0
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
19static const char *
20nouveau_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
29static const char *
30nouveau_screen_get_vendor(struct pipe_screen *pscreen)
31{
32	return "nouveau";
33}
34
35static struct pipe_buffer *
36nouveau_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
56static struct pipe_buffer *
57nouveau_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
99static struct pipe_buffer *
100nouveau_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
113static inline uint32_t
114nouveau_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
133static void *
134nouveau_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
159static void *
160nouveau_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
188static void
189nouveau_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
197static void
198nouveau_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
205static void
206nouveau_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
214static void
215nouveau_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
222static int
223nouveau_screen_fence_signalled(struct pipe_screen *screen,
224			       struct pipe_fence_handle *pfence,
225			       unsigned flags)
226{
227	return 0;
228}
229
230static int
231nouveau_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 */
248static struct pipe_texture *
249nouveau_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
282static boolean
283nouveau_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
304int
305nouveau_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
337void
338nouveau_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
345