Merge branch 'mesa_7_7_branch'
[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
7 #include <errno.h>
8
9 #include "nouveau/nouveau_bo.h"
10 #include "nouveau_winsys.h"
11 #include "nouveau_screen.h"
12
13 static const char *
14 nouveau_screen_get_name(struct pipe_screen *pscreen)
15 {
16 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
17 static char buffer[128];
18
19 snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset);
20 return buffer;
21 }
22
23 static const char *
24 nouveau_screen_get_vendor(struct pipe_screen *pscreen)
25 {
26 return "nouveau";
27 }
28
29 static struct pipe_buffer *
30 nouveau_screen_bo_skel(struct pipe_screen *pscreen, struct nouveau_bo *bo,
31 unsigned alignment, unsigned usage, unsigned size)
32 {
33 struct pipe_buffer *pb;
34
35 pb = CALLOC(1, sizeof(struct pipe_buffer)+sizeof(struct nouveau_bo *));
36 if (!pb) {
37 nouveau_bo_ref(NULL, &bo);
38 return NULL;
39 }
40
41 pipe_reference_init(&pb->reference, 1);
42 pb->screen = pscreen;
43 pb->alignment = alignment;
44 pb->usage = usage;
45 pb->size = size;
46 *(struct nouveau_bo **)(pb + 1) = bo;
47 return pb;
48 }
49
50 static struct pipe_buffer *
51 nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
52 unsigned usage, unsigned size)
53 {
54 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
55 struct nouveau_bo *bo = NULL;
56 uint32_t flags = NOUVEAU_BO_MAP;
57 int ret;
58
59 if (usage & NOUVEAU_BUFFER_USAGE_TRANSFER)
60 flags |= NOUVEAU_BO_GART;
61 else
62 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
63 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF))
64 flags |= NOUVEAU_BO_GART;
65 } else
66 if (usage & PIPE_BUFFER_USAGE_INDEX) {
67 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF))
68 flags |= NOUVEAU_BO_GART;
69 }
70
71 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
72 if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE)
73 flags |= NOUVEAU_BO_GART;
74 if (!(usage & PIPE_BUFFER_USAGE_CPU_READ_WRITE))
75 flags |= NOUVEAU_BO_VRAM;
76
77 if (dev->chipset == 0x50 || dev->chipset >= 0x80) {
78 flags |= NOUVEAU_BO_TILED;
79 if (usage & NOUVEAU_BUFFER_USAGE_ZETA)
80 flags |= NOUVEAU_BO_ZTILE;
81 }
82 }
83
84 ret = nouveau_bo_new(dev, flags, alignment, size, &bo);
85 if (ret)
86 return NULL;
87
88 return nouveau_screen_bo_skel(pscreen, bo, alignment, usage, size);
89 }
90
91 static struct pipe_buffer *
92 nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes)
93 {
94 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
95 struct nouveau_bo *bo = NULL;
96 int ret;
97
98 ret = nouveau_bo_user(dev, ptr, bytes, &bo);
99 if (ret)
100 return NULL;
101
102 return nouveau_screen_bo_skel(pscreen, bo, 0, 0, bytes);
103 }
104
105 static inline uint32_t
106 nouveau_screen_map_flags(unsigned pipe)
107 {
108 uint32_t flags = 0;
109
110 if (pipe & PIPE_BUFFER_USAGE_CPU_READ)
111 flags |= NOUVEAU_BO_RD;
112 if (pipe & PIPE_BUFFER_USAGE_CPU_WRITE)
113 flags |= NOUVEAU_BO_WR;
114 if (pipe & PIPE_BUFFER_USAGE_DISCARD)
115 flags |= NOUVEAU_BO_INVAL;
116 if (pipe & PIPE_BUFFER_USAGE_DONTBLOCK)
117 flags |= NOUVEAU_BO_NOWAIT;
118 else
119 if (pipe & 0 /*PIPE_BUFFER_USAGE_UNSYNCHRONIZED*/)
120 flags |= NOUVEAU_BO_NOSYNC;
121
122 return flags;
123 }
124
125 static void *
126 nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb,
127 unsigned usage)
128 {
129 struct nouveau_bo *bo = nouveau_bo(pb);
130 struct nouveau_screen *nscreen = nouveau_screen(pscreen);
131 int ret;
132
133 if (nscreen->pre_pipebuffer_map_callback) {
134 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
135 if (ret) {
136 debug_printf("pre_pipebuffer_map_callback failed %d\n",
137 ret);
138 return NULL;
139 }
140 }
141
142 ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage));
143 if (ret) {
144 debug_printf("map failed: %d\n", ret);
145 return NULL;
146 }
147
148 return bo->map;
149 }
150
151 static void *
152 nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb,
153 unsigned offset, unsigned length, unsigned usage)
154 {
155 struct nouveau_bo *bo = nouveau_bo(pb);
156 struct nouveau_screen *nscreen = nouveau_screen(pscreen);
157 uint32_t flags = nouveau_screen_map_flags(usage);
158 int ret;
159
160 if (nscreen->pre_pipebuffer_map_callback) {
161 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
162 if (ret) {
163 debug_printf("pre_pipebuffer_map_callback failed %d\n",
164 ret);
165 return NULL;
166 }
167 }
168
169 ret = nouveau_bo_map_range(bo, offset, length, flags);
170 if (ret) {
171 nouveau_bo_unmap(bo);
172 if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY)
173 debug_printf("map_range failed: %d\n", ret);
174 return NULL;
175 }
176
177 return (char *)bo->map - offset; /* why gallium? why? */
178 }
179
180 static void
181 nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb,
182 unsigned offset, unsigned length)
183 {
184 struct nouveau_bo *bo = nouveau_bo(pb);
185
186 nouveau_bo_map_flush(bo, offset, length);
187 }
188
189 static void
190 nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb)
191 {
192 struct nouveau_bo *bo = nouveau_bo(pb);
193
194 nouveau_bo_unmap(bo);
195 }
196
197 static void
198 nouveau_screen_bo_del(struct pipe_buffer *pb)
199 {
200 struct nouveau_bo *bo = nouveau_bo(pb);
201
202 nouveau_bo_ref(NULL, &bo);
203 FREE(pb);
204 }
205
206 static void
207 nouveau_screen_fence_ref(struct pipe_screen *pscreen,
208 struct pipe_fence_handle **ptr,
209 struct pipe_fence_handle *pfence)
210 {
211 *ptr = pfence;
212 }
213
214 static int
215 nouveau_screen_fence_signalled(struct pipe_screen *screen,
216 struct pipe_fence_handle *pfence,
217 unsigned flags)
218 {
219 return 0;
220 }
221
222 static int
223 nouveau_screen_fence_finish(struct pipe_screen *screen,
224 struct pipe_fence_handle *pfence,
225 unsigned flags)
226 {
227 return 0;
228 }
229
230 int
231 nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
232 {
233 struct pipe_screen *pscreen = &screen->base;
234 int ret;
235
236 ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202,
237 &screen->channel);
238 if (ret)
239 return ret;
240 screen->device = dev;
241
242 pscreen->get_name = nouveau_screen_get_name;
243 pscreen->get_vendor = nouveau_screen_get_vendor;
244
245 pscreen->buffer_create = nouveau_screen_bo_new;
246 pscreen->user_buffer_create = nouveau_screen_bo_user;
247 pscreen->buffer_map = nouveau_screen_bo_map;
248 pscreen->buffer_map_range = nouveau_screen_bo_map_range;
249 pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush;
250 pscreen->buffer_unmap = nouveau_screen_bo_unmap;
251 pscreen->buffer_destroy = nouveau_screen_bo_del;
252
253 pscreen->fence_reference = nouveau_screen_fence_ref;
254 pscreen->fence_signalled = nouveau_screen_fence_signalled;
255 pscreen->fence_finish = nouveau_screen_fence_finish;
256
257 return 0;
258 }
259
260 void
261 nouveau_screen_fini(struct nouveau_screen *screen)
262 {
263 struct pipe_winsys *ws = screen->base.winsys;
264 nouveau_channel_free(&screen->channel);
265 ws->destroy(ws);
266 }
267