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