nouveau: Unreference state/buffer objects on context/screen destruction.
[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 int ret;
131
132 ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage));
133 if (ret) {
134 debug_printf("map failed: %d\n", ret);
135 return NULL;
136 }
137
138 return bo->map;
139 }
140
141 static void *
142 nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb,
143 unsigned offset, unsigned length, unsigned usage)
144 {
145 struct nouveau_bo *bo = nouveau_bo(pb);
146 uint32_t flags = nouveau_screen_map_flags(usage);
147 int ret;
148
149 ret = nouveau_bo_map_range(bo, offset, length, flags);
150 if (ret) {
151 if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY)
152 debug_printf("map_range failed: %d\n", ret);
153 return NULL;
154 }
155
156 return (char *)bo->map - offset; /* why gallium? why? */
157 }
158
159 static void
160 nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb,
161 unsigned offset, unsigned length)
162 {
163 struct nouveau_bo *bo = nouveau_bo(pb);
164
165 nouveau_bo_map_flush(bo, offset, length);
166 }
167
168 static void
169 nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb)
170 {
171 struct nouveau_bo *bo = nouveau_bo(pb);
172
173 nouveau_bo_unmap(bo);
174 }
175
176 static void
177 nouveau_screen_bo_del(struct pipe_buffer *pb)
178 {
179 struct nouveau_bo *bo = nouveau_bo(pb);
180
181 nouveau_bo_ref(NULL, &bo);
182 FREE(pb);
183 }
184
185 static void
186 nouveau_screen_fence_ref(struct pipe_screen *pscreen,
187 struct pipe_fence_handle **ptr,
188 struct pipe_fence_handle *pfence)
189 {
190 *ptr = pfence;
191 }
192
193 static int
194 nouveau_screen_fence_signalled(struct pipe_screen *screen,
195 struct pipe_fence_handle *pfence,
196 unsigned flags)
197 {
198 return 0;
199 }
200
201 static int
202 nouveau_screen_fence_finish(struct pipe_screen *screen,
203 struct pipe_fence_handle *pfence,
204 unsigned flags)
205 {
206 return 0;
207 }
208
209 int
210 nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
211 {
212 struct pipe_screen *pscreen = &screen->base;
213 int ret;
214
215 ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202,
216 &screen->channel);
217 if (ret)
218 return ret;
219 screen->device = dev;
220
221 pscreen->get_name = nouveau_screen_get_name;
222 pscreen->get_vendor = nouveau_screen_get_vendor;
223
224 pscreen->buffer_create = nouveau_screen_bo_new;
225 pscreen->user_buffer_create = nouveau_screen_bo_user;
226 pscreen->buffer_map = nouveau_screen_bo_map;
227 pscreen->buffer_map_range = nouveau_screen_bo_map_range;
228 pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush;
229 pscreen->buffer_unmap = nouveau_screen_bo_unmap;
230 pscreen->buffer_destroy = nouveau_screen_bo_del;
231
232 pscreen->fence_reference = nouveau_screen_fence_ref;
233 pscreen->fence_signalled = nouveau_screen_fence_signalled;
234 pscreen->fence_finish = nouveau_screen_fence_finish;
235
236 return 0;
237 }
238
239 void
240 nouveau_screen_fini(struct nouveau_screen *screen)
241 {
242 nouveau_channel_free(&screen->channel);
243 }
244