2 * Copyright (C) 2005 Aapo Tahkola.
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:
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.
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.
30 * Aapo Tahkola <aet@rasterburn.org>
34 #include "r300_context.h"
35 #include "r300_cmdbuf.h"
36 #include "r300_ioctl.h"
38 #include "radeon_ioctl.h"
42 static void resize_u_list(r300ContextPtr rmesa
)
47 temp
= rmesa
->rmm
->u_list
;
48 nsize
= rmesa
->rmm
->u_size
* 2;
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
));
54 r300FlushCmdBuf(rmesa
, __FUNCTION__
);
56 _mesa_memcpy(rmesa
->rmm
->u_list
, temp
, rmesa
->rmm
->u_size
* sizeof(*rmesa
->rmm
->u_list
));
60 rmesa
->rmm
->u_size
= nsize
;
63 void r300_mem_init(r300ContextPtr rmesa
)
65 rmesa
->rmm
= malloc(sizeof(struct r300_memory_manager
));
66 memset(rmesa
->rmm
, 0, sizeof(struct r300_memory_manager
));
68 rmesa
->rmm
->u_size
= 128;
72 void r300_mem_destroy(r300ContextPtr rmesa
)
74 _mesa_free(rmesa
->rmm
->u_list
);
75 rmesa
->rmm
->u_list
= NULL
;
77 _mesa_free(rmesa
->rmm
);
81 void *r300_mem_ptr(r300ContextPtr rmesa
, int id
)
83 assert(id
<= rmesa
->rmm
->u_last
);
84 return rmesa
->rmm
->u_list
[id
].ptr
;
87 int r300_mem_find(r300ContextPtr rmesa
, void *ptr
)
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
)
97 if (i
< rmesa
->rmm
->u_size
+ 1)
100 fprintf(stderr
, "%p failed\n", ptr
);
105 int r300_mem_alloc(r300ContextPtr rmesa
, int alignment
, int size
)
107 drm_radeon_mem_alloc_t alloc
;
111 drm_radeon_mem_free_t memfree
;
113 static int bytes_wasted
=0, allocated
=0;
116 bytes_wasted
+= 4096 - size
;
122 if (t
!= time(NULL
)) {
124 fprintf(stderr
, "slots used %d, wasted %d kb, allocated %d\n", rmesa
->rmm
->u_last
, bytes_wasted
/1024, allocated
/1024);
128 memfree
.region
= RADEON_MEM_REGION_GART
;
132 done_age
= radeonGetAge((radeonContextPtr
)rmesa
);
134 if (rmesa
->rmm
->u_last
+ 1 >= rmesa
->rmm
->u_size
)
135 resize_u_list(rmesa
);
137 for (i
= rmesa
->rmm
->u_last
+ 1; i
> 0; i
--) {
138 if (rmesa
->rmm
->u_list
[i
].ptr
== NULL
) {
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
;
148 ret
= drmCommandWrite(rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
149 DRM_RADEON_FREE
, &memfree
, sizeof(memfree
));
152 fprintf(stderr
, "Failed to free at %p\n", rmesa
->rmm
->u_list
[i
].ptr
);
153 fprintf(stderr
, "ret = %s\n", strerror(-ret
));
157 fprintf(stderr
, "really freed %d at age %x\n", i
, radeonGetAge((radeonContextPtr
)rmesa
));
159 if (i
== rmesa
->rmm
->u_last
)
160 rmesa
->rmm
->u_last
--;
162 if(rmesa
->rmm
->u_list
[i
].size
< 4096)
163 bytes_wasted
-= 4096 - rmesa
->rmm
->u_list
[i
].size
;
165 allocated
-= rmesa
->rmm
->u_list
[i
].size
;
166 rmesa
->rmm
->u_list
[i
].pending
= 0;
167 rmesa
->rmm
->u_list
[i
].ptr
= NULL
;
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
));
175 fprintf(stderr
, "failed to free!\n");
176 rmesa
->rmm
->u_list
[i
].fb
= NULL
;
178 rmesa
->rmm
->u_list
[i
].ref_count
= 0;
183 rmesa
->rmm
->u_head
= i
;
186 WARN_ONCE("Ran out of slots!\n");
188 r300FlushCmdBuf(rmesa
, __FUNCTION__
);
191 WARN_ONCE("Ran out of slots!\n");
197 alloc
.region
= RADEON_MEM_REGION_GART
;
198 alloc
.alignment
= alignment
;
200 alloc
.region_offset
= &offset
;
202 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
, DRM_RADEON_ALLOC
, &alloc
, sizeof(alloc
));
205 WARN_ONCE("Ran out of mem!\n");
206 r300FlushCmdBuf(rmesa
, __FUNCTION__
);
211 WARN_ONCE("Ran out of GART memory!\n");
216 WARN_ONCE("Ran out of GART memory (for %d)!\nPlease consider adjusting GARTSize option.\n", size
);
223 if (i
> rmesa
->rmm
->u_last
)
224 rmesa
->rmm
->u_last
= i
;
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);
233 fprintf(stderr
, "allocated %d at age %x\n", i
, radeonGetAge((radeonContextPtr
)rmesa
));
239 #include "r300_emit.h"
240 static void emit_lin_cp(r300ContextPtr rmesa
, unsigned long dst
, unsigned long src
, unsigned long size
)
242 int cmd_reserved
= 0;
244 drm_radeon_cmd_header_t
*cmd
= NULL
;
250 if(cp_size
> /*8190*/4096)
251 cp_size
= /*8190*/4096;
276 start_packet3(RADEON_CP_PACKET3_UNK1B
, 2);
279 e32(cp_size
<< 16 | 0x1);
286 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
287 e32(R300_RB3D_DSTCACHE_UNKNOWN_0A
);
296 void r300_mem_use(r300ContextPtr rmesa
, int id
)
300 fprintf(stderr
, "%s: %d at age %x\n", __FUNCTION__
, id
, radeonGetAge((radeonContextPtr
)rmesa
));
302 drm_r300_cmd_header_t
*cmd
;
304 assert(id
<= rmesa
->rmm
->u_last
);
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*/) {
314 struct mem_block
*mb
;
316 LOCK_HARDWARE(&(rmesa
->radeon
));
318 heap
= rmesa
->texture_heaps
[0];
320 mb
= mmAllocMem(heap
->memory_heap
, rmesa
->rmm
->u_list
[id
].size
, heap
->alignmentShift
, 0);
322 UNLOCK_HARDWARE(&(rmesa
->radeon
));
325 rmesa
->rmm
->u_list
[id
].fb
= mb
;
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
);
331 WARN_ONCE("Upload to fb failed, %d, %d\n", rmesa
->rmm
->u_list
[id
].size
, id
);
333 //fprintf(stderr, "Upload to fb! %d, %d\n", rmesa->rmm->u_list[id].ref_count, id);
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);
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;
349 ull
= (uint64_t)(intptr_t)&rmesa
->rmm
->u_list
[id
].age
;
350 _mesa_memcpy(cmd
, &ull
, sizeof(ull
));
351 cmd
+= sizeof(ull
) / 4;
355 LOCK_HARDWARE(&rmesa
->radeon
); /* Protect from DRM. */
356 rmesa
->rmm
->u_list
[id
].h_pending
++;
357 UNLOCK_HARDWARE(&rmesa
->radeon
);
360 unsigned long r300_mem_offset(r300ContextPtr rmesa
, int id
)
362 unsigned long offset
;
364 assert(id
<= rmesa
->rmm
->u_last
);
366 if (rmesa
->rmm
->u_list
[id
].fb
) {
367 offset
= rmesa
->radeon
.radeonScreen
->texOffset
[0] + rmesa
->rmm
->u_list
[id
].fb
->ofs
;
369 offset
= (char *)rmesa
->rmm
->u_list
[id
].ptr
-
370 (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
371 offset
+= rmesa
->radeon
.radeonScreen
->gart_texture_offset
;
377 int r300_mem_on_card(r300ContextPtr rmesa
, int id
)
379 assert(id
<= rmesa
->rmm
->u_last
);
381 if (rmesa
->rmm
->u_list
[id
].fb
)
387 void *r300_mem_map(r300ContextPtr rmesa
, int id
, int access
)
390 fprintf(stderr
, "%s: %d at age %x\n", __FUNCTION__
, id
, radeonGetAge((radeonContextPtr
)rmesa
));
395 assert(id
<= rmesa
->rmm
->u_last
);
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;
404 if(rmesa
->rmm
->u_list
[id
].mapped
== 1)
405 WARN_ONCE("buffer %d already mapped\n", id
);
407 rmesa
->rmm
->u_list
[id
].mapped
= 1;
408 ptr
= r300_mem_ptr(rmesa
, id
);
413 if (access
== R300_MEM_R
) {
415 if(rmesa
->rmm
->u_list
[id
].mapped
== 1)
416 WARN_ONCE("buffer %d already mapped\n", id
);
418 rmesa
->rmm
->u_list
[id
].mapped
= 1;
419 ptr
= r300_mem_ptr(rmesa
, id
);
425 if (rmesa
->rmm
->u_list
[id
].h_pending
)
426 r300FlushCmdBuf(rmesa
, __FUNCTION__
);
428 if (rmesa
->rmm
->u_list
[id
].h_pending
) {
432 while(rmesa
->rmm
->u_list
[id
].age
> radeonGetAge((radeonContextPtr
)rmesa
) && tries
++ < 1000)
436 fprintf(stderr
, "Idling failed (%x vs %x)\n",
437 rmesa
->rmm
->u_list
[id
].age
, radeonGetAge((radeonContextPtr
)rmesa
));
441 if(rmesa
->rmm
->u_list
[id
].mapped
== 1)
442 WARN_ONCE("buffer %d already mapped\n", id
);
444 rmesa
->rmm
->u_list
[id
].mapped
= 1;
445 ptr
= r300_mem_ptr(rmesa
, id
);
450 void r300_mem_unmap(r300ContextPtr rmesa
, int id
)
453 fprintf(stderr
, "%s: %d at age %x\n", __FUNCTION__
, id
, radeonGetAge((radeonContextPtr
)rmesa
));
456 assert(id
<= rmesa
->rmm
->u_last
);
458 if(rmesa
->rmm
->u_list
[id
].mapped
== 0)
459 WARN_ONCE("buffer %d not mapped\n", id
);
461 rmesa
->rmm
->u_list
[id
].mapped
= 0;
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
);
469 void r300_mem_free(r300ContextPtr rmesa
, int id
)
472 fprintf(stderr
, "%s: %d at age %x\n", __FUNCTION__
, id
, radeonGetAge((radeonContextPtr
)rmesa
));
475 assert(id
<= rmesa
->rmm
->u_last
);
480 if(rmesa
->rmm
->u_list
[id
].ptr
== NULL
){
481 WARN_ONCE("Not allocated!\n");
485 if(rmesa
->rmm
->u_list
[id
].pending
){
486 WARN_ONCE("%p already pended!\n", rmesa
->rmm
->u_list
[id
].ptr
);
490 rmesa
->rmm
->u_list
[id
].pending
= 1;