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