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