Merge branch 'upstream-gallium-0.1' into darktama-gallium-0.1
[mesa.git] / src / mesa / drivers / dri / nouveau_winsys / nouveau_bo.c
1 /*
2 * Copyright 2007 Nouveau Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <errno.h>
26
27 #include "nouveau_drmif.h"
28 #include "nouveau_dma.h"
29 #include "nouveau_local.h"
30
31 int
32 nouveau_bo_init(struct nouveau_device *userdev)
33 {
34 return 0;
35 }
36
37 void
38 nouveau_bo_takedown(struct nouveau_device *userdev)
39 {
40 }
41
42 static int
43 nouveau_bo_realloc_gpu(struct nouveau_bo_priv *bo, uint32_t flags, int size)
44 {
45 struct nouveau_device_priv *nv = nouveau_device(bo->base.device);
46 int ret;
47
48 if (bo->drm.size && bo->drm.size != size) {
49 struct drm_nouveau_mem_free f;
50
51 if (bo->map) {
52 drmUnmap(bo->map, bo->drm.size);
53 bo->map = NULL;
54 }
55
56 f.flags = bo->drm.flags;
57 f.offset = bo->drm.offset;
58 drmCommandWrite(nv->fd, DRM_NOUVEAU_MEM_FREE, &f, sizeof(f));
59
60 bo->drm.size = 0;
61 }
62
63 if (size && !bo->drm.size) {
64 if (flags) {
65 bo->drm.flags = 0;
66 if (flags & NOUVEAU_BO_VRAM)
67 bo->drm.flags |= NOUVEAU_MEM_FB;
68 if (flags & NOUVEAU_BO_GART)
69 bo->drm.flags |= (NOUVEAU_MEM_AGP |
70 NOUVEAU_MEM_PCI);
71 bo->drm.flags |= NOUVEAU_MEM_MAPPED;
72 }
73
74 bo->drm.size = size;
75
76 ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_MEM_ALLOC,
77 &bo->drm, sizeof(bo->drm));
78 if (ret) {
79 free(bo);
80 return ret;
81 }
82
83 ret = drmMap(nv->fd, bo->drm.map_handle, bo->drm.size,
84 &bo->map);
85 if (ret) {
86 bo->map = NULL;
87 nouveau_bo_del((void *)&bo);
88 return ret;
89 }
90 }
91
92 return 0;
93 }
94
95 int
96 nouveau_bo_new(struct nouveau_device *userdev, uint32_t flags, int align,
97 int size, struct nouveau_bo **userbo)
98 {
99 struct nouveau_bo_priv *bo;
100 int ret;
101
102 if (!userdev || !userbo || *userbo)
103 return -EINVAL;
104
105 bo = calloc(1, sizeof(*bo));
106 if (!bo)
107 return -ENOMEM;
108 bo->base.device = userdev;
109 bo->drm.alignment = align;
110
111 if (flags & NOUVEAU_BO_PIN) {
112 ret = nouveau_bo_realloc_gpu(bo, flags, size);
113 if (ret) {
114 free(bo);
115 return ret;
116 }
117 } else {
118 bo->sysmem = malloc(size);
119 if (!bo->sysmem) {
120 free(bo);
121 return -ENOMEM;
122 }
123 }
124
125 bo->base.size = size;
126 bo->base.offset = bo->drm.offset;
127 bo->base.handle = (unsigned long)bo;
128 bo->refcount = 1;
129 *userbo = &bo->base;
130 return 0;
131 }
132
133 int
134 nouveau_bo_user(struct nouveau_device *userdev, void *ptr, int size,
135 struct nouveau_bo **userbo)
136 {
137 struct nouveau_bo_priv *bo;
138
139 if (!userdev || !userbo || *userbo)
140 return -EINVAL;
141
142 bo = calloc(1, sizeof(*bo));
143 if (!bo)
144 return -ENOMEM;
145 bo->base.device = userdev;
146
147 bo->sysmem = ptr;
148 bo->user = 1;
149
150 bo->base.size = size;
151 bo->base.offset = bo->drm.offset;
152 bo->base.handle = (unsigned long)bo;
153 bo->refcount = 1;
154 *userbo = &bo->base;
155 return 0;
156 }
157
158 int
159 nouveau_bo_ref(struct nouveau_device *userdev, uint64_t handle,
160 struct nouveau_bo **userbo)
161 {
162 struct nouveau_bo_priv *bo = (void *)(unsigned long)handle;
163
164 if (!userdev || !userbo || *userbo)
165 return -EINVAL;
166
167 bo->refcount++;
168 *userbo = &bo->base;
169 return 0;
170 }
171
172 int
173 nouveau_bo_resize(struct nouveau_bo *userbo, int size)
174 {
175 struct nouveau_bo_priv *bo = nouveau_bo(userbo);
176 int ret;
177
178 if (!bo || bo->user)
179 return -EINVAL;
180
181 if (bo->sysmem) {
182 bo->sysmem = realloc(bo->sysmem, size);
183 if (!bo->sysmem)
184 return -ENOMEM;
185 } else {
186 ret = nouveau_bo_realloc_gpu(bo, 0, size);
187 if (ret)
188 return ret;
189 }
190
191 bo->base.size = size;
192 return 0;
193 }
194
195 void
196 nouveau_bo_del(struct nouveau_bo **userbo)
197 {
198 struct nouveau_bo_priv *bo;
199
200 if (!userbo || !*userbo)
201 return;
202 bo = nouveau_bo(*userbo);
203 *userbo = NULL;
204
205 if (--bo->refcount)
206 return;
207
208 if (bo->fence)
209 nouveau_fence_wait(&bo->fence);
210
211 nouveau_bo_realloc_gpu(bo, 0, 0);
212 if (bo->sysmem && !bo->user)
213 free(bo->sysmem);
214 free(bo);
215 }
216
217 int
218 nouveau_bo_map(struct nouveau_bo *userbo, uint32_t flags)
219 {
220 struct nouveau_bo_priv *bo = nouveau_bo(userbo);
221
222 if (!bo)
223 return -EINVAL;
224
225 if (bo->sysmem)
226 userbo->map = bo->sysmem;
227 else
228 userbo->map = bo->map;
229 return 0;
230 }
231
232 void
233 nouveau_bo_unmap(struct nouveau_bo *userbo)
234 {
235 userbo->map = NULL;
236 }
237
238 static int
239 nouveau_bo_upload(struct nouveau_bo_priv *bo)
240 {
241 if (bo->fence)
242 nouveau_fence_wait(&bo->fence);
243 memcpy(bo->map, bo->sysmem, bo->drm.size);
244 return 0;
245 }
246
247 int
248 nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo,
249 struct nouveau_fence *fence, uint32_t flags)
250 {
251 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
252
253 if (!nvbo->drm.size) {
254 nouveau_bo_realloc_gpu(nvbo, flags, nvbo->base.size);
255 nouveau_bo_upload(nvbo);
256 } else
257 if (nvbo->user) {
258 nouveau_bo_upload(nvbo);
259 } else
260 if (nvbo->base.map) {
261 nouveau_bo_upload(nvbo);
262 nvbo->sync_hack = 1;
263 }
264
265 if (!nvbo->user && !nvbo->base.map) {
266 free(nvbo->sysmem);
267 nvbo->sysmem = NULL;
268 }
269
270 if (nvbo->fence)
271 nouveau_fence_del(&nvbo->fence);
272 nouveau_fence_ref(fence, &nvbo->fence);
273
274 nvbo->base.offset = nvbo->drm.offset;
275 if (nvbo->drm.flags & NOUVEAU_MEM_AGP)
276 nvbo->base.flags = NOUVEAU_BO_GART;
277 else
278 nvbo->base.flags = NOUVEAU_BO_VRAM;
279
280 return 0;
281 }
282