make u_list adjustable
[mesa.git] / src / mesa / drivers / dri / r300 / radeon_mm.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 * Authors:
30 * Aapo Tahkola <aet@rasterburn.org>
31 */
32 #include <unistd.h>
33
34 #include "r300_context.h"
35 #include "r300_cmdbuf.h"
36 #include "r300_ioctl.h"
37 #include "radeon_mm.h"
38 #include "radeon_ioctl.h"
39
40 #ifdef USER_BUFFERS
41
42 static void resize_u_list(r300ContextPtr rmesa)
43 {
44 void *temp;
45 int nsize;
46
47 temp = rmesa->rmm->u_list;
48 nsize = rmesa->rmm->u_size * 2;
49
50 rmesa->rmm->u_list = _mesa_malloc(nsize * sizeof(*rmesa->rmm->u_list));
51 _mesa_memset(rmesa->rmm->u_list, 0, nsize * sizeof(*rmesa->rmm->u_list));
52
53 if (temp) {
54 r300FlushCmdBuf(rmesa, __FUNCTION__);
55
56 _mesa_memcpy(rmesa->rmm->u_list, temp, rmesa->rmm->u_size * sizeof(*rmesa->rmm->u_list));
57 _mesa_free(temp);
58 }
59
60 rmesa->rmm->u_size = nsize;
61 }
62
63 void radeon_mm_init(r300ContextPtr rmesa)
64 {
65 rmesa->rmm = malloc(sizeof(struct radeon_memory_manager));
66 memset(rmesa->rmm, 0, sizeof(struct radeon_memory_manager));
67
68 rmesa->rmm->u_size = 128;
69 resize_u_list(rmesa);
70 }
71
72 void *radeon_mm_ptr(r300ContextPtr rmesa, int id)
73 {
74 assert(id <= rmesa->rmm->u_last);
75 return rmesa->rmm->u_list[id].ptr;
76 }
77
78 int radeon_mm_find(r300ContextPtr rmesa, void *ptr)
79 {
80 int i;
81
82 for (i=1; i < rmesa->rmm->u_size+1; i++)
83 if(rmesa->rmm->u_list[i].ptr &&
84 ptr >= rmesa->rmm->u_list[i].ptr &&
85 ptr < rmesa->rmm->u_list[i].ptr + rmesa->rmm->u_list[i].size)
86 break;
87
88 if (i < rmesa->rmm->u_size + 1)
89 return i;
90
91 fprintf(stderr, "%p failed\n", ptr);
92 return 0;
93 }
94
95 //#define MM_DEBUG
96 int radeon_mm_alloc(r300ContextPtr rmesa, int alignment, int size)
97 {
98 drm_radeon_mem_alloc_t alloc;
99 int offset, ret;
100 int i, free=-1;
101 int done_age;
102 drm_radeon_mem_free_t memfree;
103 int tries=0;
104 static int bytes_wasted=0, allocated=0;
105
106 if(size < 4096)
107 bytes_wasted += 4096 - size;
108
109 allocated += size;
110
111 #if 0
112 static int t=0;
113 if (t != time(NULL)) {
114 t = time(NULL);
115 fprintf(stderr, "slots used %d, wasted %d kb, allocated %d\n", rmesa->rmm->u_last, bytes_wasted/1024, allocated/1024);
116 }
117 #endif
118
119 memfree.region = RADEON_MEM_REGION_GART;
120
121 again:
122
123 done_age = radeonGetAge((radeonContextPtr)rmesa);
124
125 if (rmesa->rmm->u_last + 1 >= rmesa->rmm->u_size)
126 resize_u_list(rmesa);
127
128 for (i = rmesa->rmm->u_last + 1; i > 0; i --) {
129 if (rmesa->rmm->u_list[i].ptr == NULL) {
130 free = i;
131 continue;
132 }
133
134 if (rmesa->rmm->u_list[i].h_pending == 0 &&
135 rmesa->rmm->u_list[i].pending && rmesa->rmm->u_list[i].age <= done_age) {
136 memfree.region_offset = (char *)rmesa->rmm->u_list[i].ptr -
137 (char *)rmesa->radeon.radeonScreen->gartTextures.map;
138
139 ret = drmCommandWrite(rmesa->radeon.radeonScreen->driScreen->fd,
140 DRM_RADEON_FREE, &memfree, sizeof(memfree));
141
142 if (ret) {
143 fprintf(stderr, "Failed to free at %p\n", rmesa->rmm->u_list[i].ptr);
144 fprintf(stderr, "ret = %s\n", strerror(-ret));
145 exit(1);
146 } else {
147 #ifdef MM_DEBUG
148 fprintf(stderr, "really freed %d at age %x\n", i, radeonGetAge((radeonContextPtr)rmesa));
149 #endif
150 if (i == rmesa->rmm->u_last)
151 rmesa->rmm->u_last --;
152
153 if(rmesa->rmm->u_list[i].size < 4096)
154 bytes_wasted -= 4096 - rmesa->rmm->u_list[i].size;
155
156 allocated -= rmesa->rmm->u_list[i].size;
157 rmesa->rmm->u_list[i].pending = 0;
158 rmesa->rmm->u_list[i].ptr = NULL;
159
160 if (rmesa->rmm->u_list[i].fb) {
161 LOCK_HARDWARE(&(rmesa->radeon));
162 ret = mmFreeMem(rmesa->rmm->u_list[i].fb);
163 UNLOCK_HARDWARE(&(rmesa->radeon));
164
165 if (ret != 0)
166 fprintf(stderr, "failed to free!\n");
167 rmesa->rmm->u_list[i].fb = NULL;
168 }
169 rmesa->rmm->u_list[i].ref_count = 0;
170 free = i;
171 }
172 }
173 }
174 rmesa->rmm->u_head = i;
175
176 if (free == -1) {
177 WARN_ONCE("Ran out of slots!\n");
178 //usleep(100);
179 r300FlushCmdBuf(rmesa, __FUNCTION__);
180 tries++;
181 if(tries>100){
182 WARN_ONCE("Ran out of slots!\n");
183 exit(1);
184 }
185 goto again;
186 }
187
188 alloc.region = RADEON_MEM_REGION_GART;
189 alloc.alignment = alignment;
190 alloc.size = size;
191 alloc.region_offset = &offset;
192
193 ret = drmCommandWriteRead( rmesa->radeon.dri.fd, DRM_RADEON_ALLOC, &alloc, sizeof(alloc));
194 if (ret) {
195 #if 0
196 WARN_ONCE("Ran out of mem!\n");
197 r300FlushCmdBuf(rmesa, __FUNCTION__);
198 //usleep(100);
199 tries2++;
200 tries = 0;
201 if(tries2>100){
202 WARN_ONCE("Ran out of GART memory!\n");
203 exit(1);
204 }
205 goto again;
206 #else
207 WARN_ONCE("Ran out of GART memory!\nPlease consider adjusting GARTSize option.\n");
208 return 0;
209 #endif
210 }
211
212 i = free;
213
214 if (i > rmesa->rmm->u_last)
215 rmesa->rmm->u_last = i;
216
217 rmesa->rmm->u_list[i].ptr = ((GLubyte *)rmesa->radeon.radeonScreen->gartTextures.map) + offset;
218 rmesa->rmm->u_list[i].size = size;
219 rmesa->rmm->u_list[i].age = 0;
220 rmesa->rmm->u_list[i].fb = NULL;
221 //fprintf(stderr, "alloc %p at id %d\n", rmesa->rmm->u_list[i].ptr, i);
222
223 #ifdef MM_DEBUG
224 fprintf(stderr, "allocated %d at age %x\n", i, radeonGetAge((radeonContextPtr)rmesa));
225 #endif
226
227 return i;
228 }
229
230 #include "r300_emit.h"
231 static void emit_lin_cp(r300ContextPtr rmesa, unsigned long dst, unsigned long src, unsigned long size)
232 {
233 LOCAL_VARS
234 int cp_size;
235
236
237 while (size > 0){
238 cp_size = size;
239 if(cp_size > /*8190*/4096)
240 cp_size = /*8190*/4096;
241
242 reg_start(0x146c,1);
243 e32(0x52cc32fb);
244
245 reg_start(0x15ac,1);
246 e32(src);
247 e32(cp_size);
248
249 reg_start(0x1704,0);
250 e32(0x0);
251
252 reg_start(0x1404,1);
253 e32(dst);
254 e32(cp_size);
255
256 reg_start(0x1700,0);
257 e32(0x0);
258
259 reg_start(0x1640,3);
260 e32(0x00000000);
261 e32(0x00001fff);
262 e32(0x00000000);
263 e32(0x00001fff);
264
265 start_packet3(RADEON_CP_PACKET3_UNK1B, 2);
266 e32(0 << 16 | 0);
267 e32(0 << 16 | 0);
268 e32(cp_size << 16 | 0x1);
269
270 dst += cp_size;
271 src += cp_size;
272 size -= cp_size;
273 }
274
275 reg_start(0x4e4c,0);
276 e32(0x0000000a);
277
278 reg_start(0x342c,0);
279 e32(0x00000005);
280
281 reg_start(0x1720,0);
282 e32(0x00010000);
283 }
284
285 void radeon_mm_use(r300ContextPtr rmesa, int id)
286 {
287 uint64_t ull;
288 #ifdef MM_DEBUG
289 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id, radeonGetAge((radeonContextPtr)rmesa));
290 #endif
291 drm_r300_cmd_header_t *cmd;
292
293 assert(id <= rmesa->rmm->u_last);
294
295 if(id == 0)
296 return;
297
298 #if 0 /* FB VBOs. Needs further changes... */
299 rmesa->rmm->u_list[id].ref_count ++;
300 if (rmesa->rmm->u_list[id].ref_count > 100 && rmesa->rmm->u_list[id].fb == NULL &&
301 rmesa->rmm->u_list[id].size != RADEON_BUFFER_SIZE*16 /*&& rmesa->rmm->u_list[id].size > 40*/) {
302 driTexHeap *heap;
303 struct mem_block *mb;
304
305 LOCK_HARDWARE(&(rmesa->radeon));
306
307 heap = rmesa->texture_heaps[0];
308
309 mb = mmAllocMem(heap->memory_heap, rmesa->rmm->u_list[id].size, heap->alignmentShift, 0);
310
311 UNLOCK_HARDWARE(&(rmesa->radeon));
312
313 if (mb) {
314 rmesa->rmm->u_list[id].fb = mb;
315
316 emit_lin_cp(rmesa, rmesa->radeon.radeonScreen->texOffset[0] + rmesa->rmm->u_list[id].fb->ofs,
317 r300GartOffsetFromVirtual(rmesa, rmesa->rmm->u_list[id].ptr),
318 rmesa->rmm->u_list[id].size);
319 } else {
320 WARN_ONCE("Upload to fb failed, %d, %d\n", rmesa->rmm->u_list[id].size, id);
321 }
322 //fprintf(stderr, "Upload to fb! %d, %d\n", rmesa->rmm->u_list[id].ref_count, id);
323 }
324 /*if (rmesa->rmm->u_list[id].fb) {
325 emit_lin_cp(rmesa, rmesa->radeon.radeonScreen->texOffset[0] + rmesa->rmm->u_list[id].fb->ofs,
326 r300GartOffsetFromVirtual(rmesa, rmesa->rmm->u_list[id].ptr),
327 rmesa->rmm->u_list[id].size);
328 }*/
329 #endif
330
331 cmd = (drm_r300_cmd_header_t *)r300AllocCmdBuf(rmesa, 2 + sizeof(ull) / 4, __FUNCTION__);
332 cmd[0].scratch.cmd_type = R300_CMD_SCRATCH;
333 cmd[0].scratch.reg = RADEON_MM_SCRATCH;
334 cmd[0].scratch.n_bufs = 1;
335 cmd[0].scratch.flags = 0;
336 cmd ++;
337
338 ull = (uint64_t)(intptr_t)&rmesa->rmm->u_list[id].age;
339 _mesa_memcpy(cmd, &ull, sizeof(ull));
340 cmd += sizeof(ull) / 4;
341
342 cmd[0].u = /*id*/0;
343
344 LOCK_HARDWARE(&rmesa->radeon); /* Protect from DRM. */
345 rmesa->rmm->u_list[id].h_pending ++;
346 UNLOCK_HARDWARE(&rmesa->radeon);
347 }
348
349 unsigned long radeon_mm_offset(r300ContextPtr rmesa, int id)
350 {
351 unsigned long offset;
352
353 assert(id <= rmesa->rmm->u_last);
354
355 if (rmesa->rmm->u_list[id].fb) {
356 offset = rmesa->radeon.radeonScreen->texOffset[0] + rmesa->rmm->u_list[id].fb->ofs;
357 } else {
358 offset = (char *)rmesa->rmm->u_list[id].ptr -
359 (char *)rmesa->radeon.radeonScreen->gartTextures.map;
360 offset += rmesa->radeon.radeonScreen->gart_texture_offset;
361 }
362
363 return offset;
364 }
365
366 int radeon_mm_on_card(r300ContextPtr rmesa, int id)
367 {
368 assert(id <= rmesa->rmm->u_last);
369
370 if (rmesa->rmm->u_list[id].fb)
371 return GL_TRUE;
372
373 return GL_FALSE;
374 }
375
376 void *radeon_mm_map(r300ContextPtr rmesa, int id, int access)
377 {
378 #ifdef MM_DEBUG
379 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id, radeonGetAge((radeonContextPtr)rmesa));
380 #endif
381 void *ptr;
382 int tries = 0;
383
384 assert(id <= rmesa->rmm->u_last);
385
386 rmesa->rmm->u_list[id].ref_count = 0;
387 if (rmesa->rmm->u_list[id].fb) {
388 WARN_ONCE("Mapping fb!\n");
389 /* Idle gart only and do upload on unmap */
390 //rmesa->rmm->u_list[id].fb = NULL;
391
392
393 if(rmesa->rmm->u_list[id].mapped == 1)
394 WARN_ONCE("buffer %d already mapped\n", id);
395
396 rmesa->rmm->u_list[id].mapped = 1;
397 ptr = radeon_mm_ptr(rmesa, id);
398
399 return ptr;
400 }
401
402 if (access == RADEON_MM_R) {
403
404 if(rmesa->rmm->u_list[id].mapped == 1)
405 WARN_ONCE("buffer %d already mapped\n", id);
406
407 rmesa->rmm->u_list[id].mapped = 1;
408 ptr = radeon_mm_ptr(rmesa, id);
409
410 return ptr;
411 }
412
413
414 if (rmesa->rmm->u_list[id].h_pending)
415 r300FlushCmdBuf(rmesa, __FUNCTION__);
416
417 if (rmesa->rmm->u_list[id].h_pending) {
418 return NULL;
419 }
420
421 while(rmesa->rmm->u_list[id].age > radeonGetAge((radeonContextPtr)rmesa) && tries++ < 1000)
422 usleep(10);
423
424 if (tries >= 1000) {
425 fprintf(stderr, "Idling failed (%x vs %x)\n",
426 rmesa->rmm->u_list[id].age, radeonGetAge((radeonContextPtr)rmesa));
427 return NULL;
428 }
429
430 if(rmesa->rmm->u_list[id].mapped == 1)
431 WARN_ONCE("buffer %d already mapped\n", id);
432
433 rmesa->rmm->u_list[id].mapped = 1;
434 ptr = radeon_mm_ptr(rmesa, id);
435
436 return ptr;
437 }
438
439 void radeon_mm_unmap(r300ContextPtr rmesa, int id)
440 {
441 #ifdef MM_DEBUG
442 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id, radeonGetAge((radeonContextPtr)rmesa));
443 #endif
444
445 assert(id <= rmesa->rmm->u_last);
446
447 if(rmesa->rmm->u_list[id].mapped == 0)
448 WARN_ONCE("buffer %d not mapped\n", id);
449
450 rmesa->rmm->u_list[id].mapped = 0;
451
452 if (rmesa->rmm->u_list[id].fb)
453 emit_lin_cp(rmesa, rmesa->radeon.radeonScreen->texOffset[0] + rmesa->rmm->u_list[id].fb->ofs,
454 r300GartOffsetFromVirtual(rmesa, rmesa->rmm->u_list[id].ptr),
455 rmesa->rmm->u_list[id].size);
456 }
457
458 void radeon_mm_free(r300ContextPtr rmesa, int id)
459 {
460 #ifdef MM_DEBUG
461 fprintf(stderr, "%s: %d at age %x\n", __FUNCTION__, id, radeonGetAge((radeonContextPtr)rmesa));
462 #endif
463
464 assert(id <= rmesa->rmm->u_last);
465
466 if(id == 0)
467 return;
468
469 if(rmesa->rmm->u_list[id].ptr == NULL){
470 WARN_ONCE("Not allocated!\n");
471 return ;
472 }
473
474 if(rmesa->rmm->u_list[id].pending){
475 WARN_ONCE("%p already pended!\n", rmesa->rmm->u_list[id].ptr);
476 return ;
477 }
478
479 rmesa->rmm->u_list[id].pending = 1;
480 }
481 #endif