i965: fix bugs in projective texture coordinates
[mesa.git] / src / mesa / drivers / dri / r300 / r300_mem.c
1 /*
2 * Copyright (C) 2005 Aapo Tahkola.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 /**
29 * \file
30 *
31 * \author Aapo Tahkola <aet@rasterburn.org>
32 */
33
34 #include <unistd.h>
35
36 #include "r300_context.h"
37 #include "r300_cmdbuf.h"
38 #include "r300_ioctl.h"
39 #include "r300_mem.h"
40 #include "radeon_ioctl.h"
41
42 #ifdef USER_BUFFERS
43
44 static void resize_u_list(r300ContextPtr rmesa)
45 {
46 void *temp;
47 int nsize;
48
49 temp = rmesa->rmm->u_list;
50 nsize = rmesa->rmm->u_size * 2;
51
52 rmesa->rmm->u_list = _mesa_malloc(nsize * sizeof(*rmesa->rmm->u_list));
53 _mesa_memset(rmesa->rmm->u_list, 0,
54 nsize * sizeof(*rmesa->rmm->u_list));
55
56 if (temp) {
57 r300FlushCmdBuf(rmesa, __FUNCTION__);
58
59 _mesa_memcpy(rmesa->rmm->u_list, temp,
60 rmesa->rmm->u_size * sizeof(*rmesa->rmm->u_list));
61 _mesa_free(temp);
62 }
63
64 rmesa->rmm->u_size = nsize;
65 }
66
67 void r300_mem_init(r300ContextPtr rmesa)
68 {
69 rmesa->rmm = malloc(sizeof(struct r300_memory_manager));
70 memset(rmesa->rmm, 0, sizeof(struct r300_memory_manager));
71
72 rmesa->rmm->u_size = 128;
73 resize_u_list(rmesa);
74 }
75
76 void r300_mem_destroy(r300ContextPtr rmesa)
77 {
78 _mesa_free(rmesa->rmm->u_list);
79 rmesa->rmm->u_list = NULL;
80
81 _mesa_free(rmesa->rmm);
82 rmesa->rmm = NULL;
83 }
84
85 void *r300_mem_ptr(r300ContextPtr rmesa, int id)
86 {
87 assert(id <= rmesa->rmm->u_last);
88 return rmesa->rmm->u_list[id].ptr;
89 }
90
91 int r300_mem_find(r300ContextPtr rmesa, void *ptr)
92 {
93 int i;
94
95 for (i = 1; i < rmesa->rmm->u_size + 1; i++)
96 if (rmesa->rmm->u_list[i].ptr &&
97 ptr >= rmesa->rmm->u_list[i].ptr &&
98 ptr <
99 rmesa->rmm->u_list[i].ptr + rmesa->rmm->u_list[i].size)
100 break;
101
102 if (i < rmesa->rmm->u_size + 1)
103 return i;
104
105 fprintf(stderr, "%p failed\n", ptr);
106 return 0;
107 }
108
109 //#define MM_DEBUG
110 int r300_mem_alloc(r300ContextPtr rmesa, int alignment, int size)
111 {
112 drm_radeon_mem_alloc_t alloc;
113 int offset = 0, ret;
114 int i, free = -1;
115 int done_age;
116 drm_radeon_mem_free_t memfree;
117 int tries = 0;
118 static int bytes_wasted = 0, allocated = 0;
119
120 if (size < 4096)
121 bytes_wasted += 4096 - size;
122
123 allocated += size;
124
125 #if 0
126 static int t = 0;
127 if (t != time(NULL)) {
128 t = time(NULL);
129 fprintf(stderr, "slots used %d, wasted %d kb, allocated %d\n",
130 rmesa->rmm->u_last, bytes_wasted / 1024,
131 allocated / 1024);
132 }
133 #endif
134
135 memfree.region = RADEON_MEM_REGION_GART;
136
137 again:
138
139 done_age = radeonGetAge((radeonContextPtr) rmesa);
140
141 if (rmesa->rmm->u_last + 1 >= rmesa->rmm->u_size)
142 resize_u_list(rmesa);
143
144 for (i = rmesa->rmm->u_last + 1; i > 0; i--) {
145 if (rmesa->rmm->u_list[i].ptr == NULL) {
146 free = i;
147 continue;
148 }
149
150 if (rmesa->rmm->u_list[i].h_pending == 0 &&
151 rmesa->rmm->u_list[i].pending
152 && rmesa->rmm->u_list[i].age <= done_age) {
153 memfree.region_offset =
154 (char *)rmesa->rmm->u_list[i].ptr -
155 (char *)rmesa->radeon.radeonScreen->gartTextures.
156 map;
157
158 ret =
159 drmCommandWrite(rmesa->radeon.radeonScreen->
160 driScreen->fd, DRM_RADEON_FREE,
161 &memfree, sizeof(memfree));
162
163 if (ret) {
164 fprintf(stderr, "Failed to free at %p\n",
165 rmesa->rmm->u_list[i].ptr);
166 fprintf(stderr, "ret = %s\n", strerror(-ret));
167 exit(1);
168 } else {
169 #ifdef MM_DEBUG
170 fprintf(stderr, "really freed %d at age %x\n",
171 i,
172 radeonGetAge((radeonContextPtr) rmesa));
173 #endif
174 if (i == rmesa->rmm->u_last)
175 rmesa->rmm->u_last--;
176
177 if (rmesa->rmm->u_list[i].size < 4096)
178 bytes_wasted -=
179 4096 - rmesa->rmm->u_list[i].size;
180
181 allocated -= rmesa->rmm->u_list[i].size;
182 rmesa->rmm->u_list[i].pending = 0;
183 rmesa->rmm->u_list[i].ptr = NULL;
184 free = i;
185 }
186 }
187 }
188 rmesa->rmm->u_head = i;
189
190 if (free == -1) {
191 WARN_ONCE("Ran out of slots!\n");
192 //usleep(100);
193 r300FlushCmdBuf(rmesa, __FUNCTION__);
194 tries++;
195 if (tries > 100) {
196 WARN_ONCE("Ran out of slots!\n");
197 exit(1);
198 }
199 goto again;
200 }
201
202 alloc.region = RADEON_MEM_REGION_GART;
203 alloc.alignment = alignment;
204 alloc.size = size;
205 alloc.region_offset = &offset;
206
207 ret =
208 drmCommandWriteRead(rmesa->radeon.dri.fd, DRM_RADEON_ALLOC, &alloc,
209 sizeof(alloc));
210 if (ret) {
211 #if 0
212 WARN_ONCE("Ran out of mem!\n");
213 r300FlushCmdBuf(rmesa, __FUNCTION__);
214 //usleep(100);
215 tries2++;
216 tries = 0;
217 if (tries2 > 100) {
218 WARN_ONCE("Ran out of GART memory!\n");
219 exit(1);
220 }
221 goto again;
222 #else
223 WARN_ONCE
224 ("Ran out of GART memory (for %d)!\nPlease consider adjusting GARTSize option.\n",
225 size);
226 return 0;
227 #endif
228 }
229
230 i = free;
231
232 if (i > rmesa->rmm->u_last)
233 rmesa->rmm->u_last = i;
234
235 rmesa->rmm->u_list[i].ptr =
236 ((GLubyte *) rmesa->radeon.radeonScreen->gartTextures.map) + offset;
237 rmesa->rmm->u_list[i].size = size;
238 rmesa->rmm->u_list[i].age = 0;
239 //fprintf(stderr, "alloc %p at id %d\n", rmesa->rmm->u_list[i].ptr, i);
240
241 #ifdef MM_DEBUG
242 fprintf(stderr, "allocated %d at age %x\n", i,
243 radeonGetAge((radeonContextPtr) rmesa));
244 #endif
245
246 return i;
247 }
248
249 void r300_mem_use(r300ContextPtr rmesa, int id)
250 {
251 uint64_t ull;
252 #ifdef MM_DEBUG
253 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id,
254 radeonGetAge((radeonContextPtr) rmesa));
255 #endif
256 drm_r300_cmd_header_t *cmd;
257
258 assert(id <= rmesa->rmm->u_last);
259
260 if (id == 0)
261 return;
262
263 cmd =
264 (drm_r300_cmd_header_t *) r300AllocCmdBuf(rmesa,
265 2 + sizeof(ull) / 4,
266 __FUNCTION__);
267 cmd[0].scratch.cmd_type = R300_CMD_SCRATCH;
268 cmd[0].scratch.reg = R300_MEM_SCRATCH;
269 cmd[0].scratch.n_bufs = 1;
270 cmd[0].scratch.flags = 0;
271 cmd++;
272
273 ull = (uint64_t) (intptr_t) & rmesa->rmm->u_list[id].age;
274 _mesa_memcpy(cmd, &ull, sizeof(ull));
275 cmd += sizeof(ull) / 4;
276
277 cmd[0].u = /*id */ 0;
278
279 LOCK_HARDWARE(&rmesa->radeon); /* Protect from DRM. */
280 rmesa->rmm->u_list[id].h_pending++;
281 UNLOCK_HARDWARE(&rmesa->radeon);
282 }
283
284 unsigned long r300_mem_offset(r300ContextPtr rmesa, int id)
285 {
286 unsigned long offset;
287
288 assert(id <= rmesa->rmm->u_last);
289
290 offset = (char *)rmesa->rmm->u_list[id].ptr -
291 (char *)rmesa->radeon.radeonScreen->gartTextures.map;
292 offset += rmesa->radeon.radeonScreen->gart_texture_offset;
293
294 return offset;
295 }
296
297 void *r300_mem_map(r300ContextPtr rmesa, int id, int access)
298 {
299 #ifdef MM_DEBUG
300 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id,
301 radeonGetAge((radeonContextPtr) rmesa));
302 #endif
303 void *ptr;
304 int tries = 0;
305
306 assert(id <= rmesa->rmm->u_last);
307
308 if (access == R300_MEM_R) {
309
310 if (rmesa->rmm->u_list[id].mapped == 1)
311 WARN_ONCE("buffer %d already mapped\n", id);
312
313 rmesa->rmm->u_list[id].mapped = 1;
314 ptr = r300_mem_ptr(rmesa, id);
315
316 return ptr;
317 }
318
319 if (rmesa->rmm->u_list[id].h_pending)
320 r300FlushCmdBuf(rmesa, __FUNCTION__);
321
322 if (rmesa->rmm->u_list[id].h_pending) {
323 return NULL;
324 }
325
326 while (rmesa->rmm->u_list[id].age >
327 radeonGetAge((radeonContextPtr) rmesa) && tries++ < 1000)
328 usleep(10);
329
330 if (tries >= 1000) {
331 fprintf(stderr, "Idling failed (%x vs %x)\n",
332 rmesa->rmm->u_list[id].age,
333 radeonGetAge((radeonContextPtr) rmesa));
334 return NULL;
335 }
336
337 if (rmesa->rmm->u_list[id].mapped == 1)
338 WARN_ONCE("buffer %d already mapped\n", id);
339
340 rmesa->rmm->u_list[id].mapped = 1;
341 ptr = r300_mem_ptr(rmesa, id);
342
343 return ptr;
344 }
345
346 void r300_mem_unmap(r300ContextPtr rmesa, int id)
347 {
348 #ifdef MM_DEBUG
349 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id,
350 radeonGetAge((radeonContextPtr) rmesa));
351 #endif
352
353 assert(id <= rmesa->rmm->u_last);
354
355 if (rmesa->rmm->u_list[id].mapped == 0)
356 WARN_ONCE("buffer %d not mapped\n", id);
357
358 rmesa->rmm->u_list[id].mapped = 0;
359 }
360
361 void r300_mem_free(r300ContextPtr rmesa, int id)
362 {
363 #ifdef MM_DEBUG
364 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id,
365 radeonGetAge((radeonContextPtr) rmesa));
366 #endif
367
368 assert(id <= rmesa->rmm->u_last);
369
370 if (id == 0)
371 return;
372
373 if (rmesa->rmm->u_list[id].ptr == NULL) {
374 WARN_ONCE("Not allocated!\n");
375 return;
376 }
377
378 if (rmesa->rmm->u_list[id].pending) {
379 WARN_ONCE("%p already pended!\n", rmesa->rmm->u_list[id].ptr);
380 return;
381 }
382
383 rmesa->rmm->u_list[id].pending = 1;
384 }
385 #endif