d6c2a0a199a1cfbbaaaa0f7f2c7b72b9ce080ba9
[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 #include "util/u_format_s3tc.h"
9 #include "util/u_string.h"
10
11 #include <stdio.h>
12 #include <errno.h>
13
14 #include "nouveau/nouveau_bo.h"
15 #include "nouveau_winsys.h"
16 #include "nouveau_screen.h"
17 #include "nouveau_fence.h"
18
19 /* XXX this should go away */
20 #include "state_tracker/drm_driver.h"
21 #include "util/u_simple_screen.h"
22
23 static const char *
24 nouveau_screen_get_name(struct pipe_screen *pscreen)
25 {
26 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
27 static char buffer[128];
28
29 util_snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset);
30 return buffer;
31 }
32
33 static const char *
34 nouveau_screen_get_vendor(struct pipe_screen *pscreen)
35 {
36 return "nouveau";
37 }
38
39
40
41 struct nouveau_bo *
42 nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
43 unsigned usage, unsigned bind, unsigned size)
44 {
45 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
46 struct nouveau_bo *bo = NULL;
47 uint32_t flags = NOUVEAU_BO_MAP, tile_mode = 0, tile_flags = 0;
48 int ret;
49
50 if (bind & PIPE_BIND_VERTEX_BUFFER)
51 flags |= nouveau_screen(pscreen)->vertex_buffer_flags;
52 else if (bind & PIPE_BIND_INDEX_BUFFER)
53 flags |= nouveau_screen(pscreen)->index_buffer_flags;
54
55 if (bind & (PIPE_BIND_RENDER_TARGET |
56 PIPE_BIND_DEPTH_STENCIL |
57 PIPE_BIND_SCANOUT |
58 PIPE_BIND_DISPLAY_TARGET |
59 PIPE_BIND_SAMPLER_VIEW))
60 {
61 /* TODO: this may be incorrect or suboptimal */
62 if (!(bind & PIPE_BIND_SCANOUT))
63 flags |= NOUVEAU_BO_GART;
64 if (usage != PIPE_USAGE_DYNAMIC)
65 flags |= NOUVEAU_BO_VRAM;
66
67 if (dev->chipset == 0x50 || dev->chipset >= 0x80) {
68 if (bind & PIPE_BIND_DEPTH_STENCIL)
69 tile_flags = 0x2800;
70 else
71 tile_flags = 0x7000;
72 }
73 }
74
75 ret = nouveau_bo_new_tile(dev, flags, alignment, size,
76 tile_mode, tile_flags, &bo);
77 if (ret)
78 return NULL;
79
80 return bo;
81 }
82
83 struct nouveau_bo *
84 nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes)
85 {
86 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
87 struct nouveau_bo *bo = NULL;
88 int ret;
89
90 ret = nouveau_bo_user(dev, ptr, bytes, &bo);
91 if (ret)
92 return NULL;
93
94 return bo;
95 }
96
97 void *
98 nouveau_screen_bo_map(struct pipe_screen *pscreen,
99 struct nouveau_bo *bo,
100 unsigned map_flags)
101 {
102 int ret;
103
104 ret = nouveau_bo_map(bo, map_flags);
105 if (ret) {
106 debug_printf("map failed: %d\n", ret);
107 return NULL;
108 }
109
110 return bo->map;
111 }
112
113 void *
114 nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
115 unsigned offset, unsigned length, unsigned flags)
116 {
117 int ret;
118
119 ret = nouveau_bo_map_range(bo, offset, length, flags);
120 if (ret) {
121 nouveau_bo_unmap(bo);
122 if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY)
123 debug_printf("map_range failed: %d\n", ret);
124 return NULL;
125 }
126
127 return (char *)bo->map - offset; /* why gallium? why? */
128 }
129
130 void
131 nouveau_screen_bo_map_flush_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
132 unsigned offset, unsigned length)
133 {
134 nouveau_bo_map_flush(bo, offset, length);
135 }
136
137 void
138 nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct nouveau_bo *bo)
139 {
140 nouveau_bo_unmap(bo);
141 }
142
143 void
144 nouveau_screen_bo_release(struct pipe_screen *pscreen, struct nouveau_bo *bo)
145 {
146 nouveau_bo_ref(NULL, &bo);
147 }
148
149 static void
150 nouveau_screen_fence_ref(struct pipe_screen *pscreen,
151 struct pipe_fence_handle **ptr,
152 struct pipe_fence_handle *pfence)
153 {
154 nouveau_fence_ref(nouveau_fence(pfence), (struct nouveau_fence **)ptr);
155 }
156
157 static int
158 nouveau_screen_fence_signalled(struct pipe_screen *screen,
159 struct pipe_fence_handle *pfence,
160 unsigned flags)
161 {
162 return !nouveau_fence_signalled(nouveau_fence(pfence));
163 }
164
165 static int
166 nouveau_screen_fence_finish(struct pipe_screen *screen,
167 struct pipe_fence_handle *pfence,
168 unsigned flags,
169 uint64_t timeout)
170 {
171 return !nouveau_fence_wait(nouveau_fence(pfence));
172 }
173
174
175 struct nouveau_bo *
176 nouveau_screen_bo_from_handle(struct pipe_screen *pscreen,
177 struct winsys_handle *whandle,
178 unsigned *out_stride)
179 {
180 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
181 struct nouveau_bo *bo = 0;
182 int ret;
183
184 ret = nouveau_bo_handle_ref(dev, whandle->handle, &bo);
185 if (ret) {
186 debug_printf("%s: ref name 0x%08x failed with %d\n",
187 __FUNCTION__, whandle->handle, ret);
188 return NULL;
189 }
190
191 *out_stride = whandle->stride;
192 return bo;
193 }
194
195
196 boolean
197 nouveau_screen_bo_get_handle(struct pipe_screen *pscreen,
198 struct nouveau_bo *bo,
199 unsigned stride,
200 struct winsys_handle *whandle)
201 {
202 whandle->stride = stride;
203
204 if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
205 return nouveau_bo_handle_get(bo, &whandle->handle) == 0;
206 } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
207 whandle->handle = bo->handle;
208 return TRUE;
209 } else {
210 return FALSE;
211 }
212 }
213
214 int
215 nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
216 {
217 struct pipe_screen *pscreen = &screen->base;
218 int ret;
219
220 ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202,
221 512*1024, &screen->channel);
222 if (ret)
223 return ret;
224 screen->device = dev;
225
226 pscreen->get_name = nouveau_screen_get_name;
227 pscreen->get_vendor = nouveau_screen_get_vendor;
228
229 pscreen->fence_reference = nouveau_screen_fence_ref;
230 pscreen->fence_signalled = nouveau_screen_fence_signalled;
231 pscreen->fence_finish = nouveau_screen_fence_finish;
232
233 util_format_s3tc_init();
234
235 screen->mm_GART = nouveau_mm_create(dev,
236 NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
237 0x000);
238 screen->mm_VRAM = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, 0x000);
239 return 0;
240 }
241
242 void
243 nouveau_screen_fini(struct nouveau_screen *screen)
244 {
245 struct pipe_winsys *ws = screen->base.winsys;
246
247 nouveau_mm_destroy(screen->mm_GART);
248 nouveau_mm_destroy(screen->mm_VRAM);
249
250 nouveau_channel_free(&screen->channel);
251
252 if (ws)
253 ws->destroy(ws);
254 }
255