2 Copyright © 2011-2017, The AROS Development Team. All rights reserved.
8 #include <aros/debug.h>
10 #include "intelgma_hidd.h"
11 #include "intelG45_regs.h"
12 #include "intelgma_winsys.h"
14 #include "util/u_memory.h"
15 #include "i915/i915_winsys.h"
16 #include "i915/i915_debug.h"
18 #include "i915/i915_reg.h"
21 #ifdef GALLIUM_SIMULATION
32 #define ADVANCE_RING()
36 #warning GALLIUM_SIMULATION MODE!
39 #define IMPLEMENT() bug("[GMA winsys]------IMPLEMENT(%s)\n", __func__)
47 static struct status hw_status
[1024];
48 //static APTR *bb_map;
49 static ULONG flush_num
;
50 ULONG allocated_mem
=0;
51 static struct SignalSemaphore BatchBufferLock
;
52 static struct SignalSemaphore UnusedBuffersListLock
;
53 struct List unusedbuffers
;
55 extern struct g45staticdata sd
;
56 #define sd ((struct g45staticdata*)&(sd))
57 #define LOCK_BB { ObtainSemaphore(&BatchBufferLock); }
58 #define UNLOCK_BB { ReleaseSemaphore(&BatchBufferLock); }
60 #define BASEADDRESS(p) ((IPTR)(p) - (IPTR)sd->Card.Framebuffer)
61 struct i915_winsys_batchbuffer
*batchbuffer_create(struct i915_winsys
*iws
);
63 ULONG
reserve_status_index()
69 if( ! hw_status
[i
].reserved
)
71 hw_status
[i
].reserved
= TRUE
;
72 hw_status
[i
].flush_num
= flush_num
;
73 D(bug("[GMA winsys] reserve_status_index=%d flush_num %d\n",i
,flush_num
));
77 (bug("[GMA winsys] reserve_status_index: not free index,wait a moment...\n"));
83 VOID
free_status_index(ULONG i
)
85 hw_status
[i
].reserved
= FALSE
;
86 hw_status
[i
].flush_num
= 0;
87 D(bug("[GMA winsys] free_status_index(%d)\n",i
));
90 BOOL
get_status(ULONG i
)
92 #ifdef GALLIUM_SIMULATION
95 if( ! hw_status
[i
].reserved
) bug("[GMA winsys] get_status ERROR,index not reserved %d\n",i
);
96 return readl( &sd
->HardwareStatusPage
[ i
]);
99 VOID
set_status(ULONG i
,ULONG v
)
101 #ifndef GALLIUM_SIMULATION
102 if( ! hw_status
[i
].reserved
) bug("[GMA winsys] set_status ERROR,index not reserved %d\n",i
);
103 writel( v
, &sd
->HardwareStatusPage
[ i
] );
104 readl( &sd
->HardwareStatusPage
[ i
] );
108 static APTR
alloc_gfx_mem(ULONG size
)
112 #ifdef GALLIUM_SIMULATION
116 result
= AllocGfxMem(sd
, size
);
124 destroy_unused_buffers();
126 result
= AllocGfxMem(sd
, size
);
132 D(bug("[GMA winsys] alloc_gfx_mem(%d) = %p allocated_mem %d\n",
133 size
, result
, allocated_mem
));
139 static VOID
free_gfx_mem(APTR ptr
, ULONG size
)
141 #ifdef GALLIUM_SIMULATION
145 FreeGfxMem(sd
, ptr
, size
);
147 D(bug("[GMA winsys] free_gfx_mem(%p, %d) allocated_mem %d\n", ptr
, size
, allocated_mem
));
150 VOID
init_aros_winsys()
152 // clean hw_status table, reserve first 100, (0-15 is reserved, and
153 // bitmapclass uses at least 16-20)
155 for(i
=100;i
<1024;i
++)
157 hw_status
[i
].reserved
= FALSE
;
160 NEWLIST(&unusedbuffers
);
161 InitSemaphore(&BatchBufferLock
);
162 InitSemaphore(&UnusedBuffersListLock
);
165 /*******************************************************************
166 * Batchbuffer functions.
167 ******************************************************************/
169 #define BATCH_RESERVED 16
171 static void batchbuffer_reset(struct aros_batchbuffer
*batch
)
174 D(bug("[GMA winsys] batchbuffer_reset\n"));
175 memset(batch
->base
.map
, 0, batch
->actual_size
);
176 batch
->base
.ptr
= batch
->base
.map
;
177 batch
->base
.size
= batch
->actual_size
- BATCH_RESERVED
;
178 batch
->base
.relocs
= 0;
182 * Create a new batchbuffer.
184 struct i915_winsys_batchbuffer
*batchbuffer_create(struct i915_winsys
*iws
)
186 D(bug("[GMA winsys] batchbuffer_create\n"));
187 struct aros_winsys
*idws
= aros_winsys(iws
);
188 struct aros_batchbuffer
*batch
= CALLOC_STRUCT(aros_batchbuffer
);
190 batch
->actual_size
= idws
->max_batch_size
;
191 batch
->base
.map
= MALLOC(batch
->actual_size
);
193 batch
->allocated_size
= batch
->actual_size
+ 4096;
194 if( !(batch
->allocated_map
= alloc_gfx_mem(batch
->allocated_size
) ) )
196 batch
->gfxmap
= (APTR
)(((IPTR
)batch
->allocated_map
+ 4095)& ~4095);
198 batch
->base
.ptr
= NULL
;
199 batch
->base
.size
= 0;
201 batch
->base
.relocs
= 0;
202 batch
->base
.iws
= iws
;
204 batchbuffer_reset(batch
);
210 * Validate buffers for usage in this batchbuffer.
211 * Does space-checking and assorted other book-keeping.
214 * @buffers array to buffers to validate
215 * @num_of_buffers size of the passed array
217 boolean
batchbuffer_validate_buffers(struct i915_winsys_batchbuffer
*batch
,
218 struct i915_winsys_buffer
**buffers
,
221 D(bug("[GMA winsys] batchbuffer_validate_buffers\n"));
223 for(i
=0;i
<num_of_buffers
;i
++)
225 D(bug(" buffer %p\n",buffers
[i
]));
226 MAGIC_WARNING(buffers
[i
]);
234 * Emit a relocation to a buffer.
235 * Target position in batchbuffer is the same as ptr.
238 * @reloc buffer address to be inserted into target.
239 * @usage how is the hardware going to use the buffer.
240 * @offset add this to the reloc buffers address
241 * @target buffer where to write the address, null for batchbuffer.
242 * @fenced relocation needs a fence.
244 int batchbuffer_reloc(struct i915_winsys_batchbuffer
*batch
,
245 struct i915_winsys_buffer
*reloc
,
246 enum i915_winsys_buffer_usage usage
,
247 unsigned offset
, boolean fenced
)
249 IF_BAD_MAGIC(reloc
) return -1;
251 struct reloc
*rl
= &aros_batchbuffer(batch
)->relocs
[ batch
->relocs
];
254 if( batch
->relocs
>= MAX_RELOCS
)
256 bug("[GMA winsys] MAX_RELOCS ERROR\n");
257 *(uint32_t *)(batch
->ptr
) = 0;
265 rl
->ptr
= (uint32_t *)batch
->ptr
;
266 *(uint32_t *)(batch
->ptr
) = RELOC_MAGIC
;
268 D(bug("[GMA winsys] batchbuffer_reloc reloc %p offset %d fenced %s base=%p \n",reloc
,offset
,fenced
? "true" : "false",*(uint32_t *)(batch
->ptr
)));
274 * Flush a bufferbatch.
277 #define MI_BATCH_NON_SECURE (1)
279 void batchbuffer_flush(struct i915_winsys_batchbuffer
*batch
,
280 struct pipe_fence_handle
**fence
)
282 D(bug("[GMA winsys] batchbuffer_flush size=%d\n",batch
->ptr
- batch
->map
));
283 struct aros_batchbuffer
*abatch
= aros_batchbuffer(batch
);
285 if( (batch
->ptr
- batch
->map
) & 4) {
286 *(uint32_t *)(batch
->ptr
) = 0; /* MI_NOOP */
290 *(uint32_t *)(batch
->ptr
) = MI_BATCH_BUFFER_END
;
292 // i915_dump_batchbuffer( batch );
294 #ifdef GALLIUM_SIMULATION
295 batchbuffer_reset( abatch
);
301 flush_num
++;if(flush_num
==0)flush_num
=1;
302 ULONG index
= reserve_status_index();
305 ObtainSemaphore(&UnusedBuffersListLock
);
307 for(i
=0;i
<batch
->relocs
;i
++)
309 struct reloc
*rl
= &abatch
->relocs
[ i
];
310 D(bug("[GMA winsys] batchbuffer_flush reloc %p\n",rl
->buf
));
312 if( i
>= MAX_RELOCS
||
314 rl
->buf
->magic
!= MAGIC
||
315 *(uint32_t *)(rl
->ptr
) != RELOC_MAGIC
318 batchbuffer_reset( abatch
);
320 ReleaseSemaphore(&UnusedBuffersListLock
);
321 bug("[GMA winsys] batchbuffer_flush ERROR:Rotten reloc, num %d buf %p map %p\n",i
,rl
->buf
,rl
->buf
->map
);
325 if( rl
->buf
->flush_num
!= flush_num
)
327 while( buffer_is_busy(0, rl
->buf
) ){}
330 rl
->buf
->flush_num
= flush_num
;
331 rl
->buf
->status_index
= index
;
333 *(uint32_t *)(rl
->ptr
) = BASEADDRESS( rl
->buf
->map
) + rl
->offset
;
335 ReleaseSemaphore(&UnusedBuffersListLock
);
338 memcpy(abatch
->gfxmap
, batch
->map
, batch
->ptr
- batch
->map
);
343 set_status( index
, 1 );
349 ULONG cmd
= MI_FLUSH
| MI_NO_WRITE_FLUSH
;
350 cmd
&= ~MI_NO_WRITE_FLUSH
;
351 cmd
|= MI_READ_FLUSH
;
357 OUT_RING( MI_BATCH_BUFFER_START
| (2 << 6) );
358 OUT_RING( BASEADDRESS( abatch
->gfxmap
) | MI_BATCH_NON_SECURE
);
364 OUT_RING((0x21 << 23) | 1);
365 OUT_RING( index
<< 2 );
373 batchbuffer_reset( abatch
);
380 * Destroy a batchbuffer.
382 void batchbuffer_destroy(struct i915_winsys_batchbuffer
*ibatch
)
384 (bug("[GMA winsys] batchbuffer_destroy %p\n",ibatch
));
385 struct aros_batchbuffer
*batch
= aros_batchbuffer(ibatch
);
387 free_gfx_mem(batch
->allocated_map
, batch
->allocated_size
);
393 ObtainSemaphore(&UnusedBuffersListLock
);
394 destroy_unused_buffers();
395 ReleaseSemaphore(&UnusedBuffersListLock
);
399 /*******************************************************************
401 *****************************************************************/
403 static char *i915_type_to_name(enum i915_winsys_buffer_type type
)
406 if (type
== I915_NEW_TEXTURE
) {
407 name
= "gallium3d_texture";
408 } else if (type
== I915_NEW_VERTEX
) {
409 name
= "gallium3d_vertex";
410 } else if (type
== I915_NEW_SCANOUT
) {
411 name
= "gallium3d_scanout";
413 name
= "gallium3d_unknown";
419 void destroy_unused_buffers()
422 D(bug("[GMA winsys] destroy_unused_buffers allocated_mem %d\n",allocated_mem
));
423 if( AttemptSemaphore(&UnusedBuffersListLock
) )
425 struct Node
*node
,*next
;
426 struct i915_winsys_buffer
*buf
;
428 ForeachNodeSafe(&unusedbuffers
,node
,next
)
431 buf
= (struct i915_winsys_buffer
*)node
;
433 if( ! buffer_is_busy(0, buf
) )
436 D(bug("[GMA winsys] destroy %p\n",buf
));
439 free_gfx_mem(buf
->allocated_map
, buf
->allocated_size
);
444 D(if(i
) bug("[GMA winsys] unused_buffers left:%d\n",i
));
445 ReleaseSemaphore(&UnusedBuffersListLock
);
453 struct i915_winsys_buffer
*
454 buffer_create(struct i915_winsys
*iws
,
456 enum i915_winsys_buffer_type type
)
459 struct i915_winsys_buffer
*buf
;
462 if( AttemptSemaphore(&UnusedBuffersListLock) )
464 if( (buf = (struct i915_winsys_buffer *)GetTail(&unusedbuffers)) )
466 if( buf->size == size )
468 if( ! buffer_is_busy(0, buf ) )
470 D(bug("[GMA winsys] buffer_create: cheap secondhand buffer found:%p\n", buf));
471 Remove((struct Node *)buf);
472 ReleaseSemaphore(&UnusedBuffersListLock);
477 ReleaseSemaphore(&UnusedBuffersListLock);
481 buf
= CALLOC_STRUCT(i915_winsys_buffer
);
485 // allocate page aligned gfx memory
486 buf
->allocated_size
= size
+ 4096;
487 if( !(buf
->allocated_map
= alloc_gfx_mem(buf
->allocated_size
) ) )
492 buf
->map
= (APTR
)(((IPTR
)buf
->allocated_map
+ 4095)& ~4095);
495 D(bug("[GMA winsys] buffer_create size %d type %s = %p map %p\n",size
,i915_type_to_name(type
),buf
,buf
->map
));
503 * Create a tiled buffer.
505 * *stride, height are in bytes. The winsys tries to allocate the buffer with
506 * the tiling mode provide in *tiling. If tiling is no possible, *tiling will
507 * be set to I915_TILE_NONE. The calculated stride (incorporateing hw/kernel
508 * requirements) is always returned in *stride.
510 struct i915_winsys_buffer
*
511 buffer_create_tiled(struct i915_winsys
*iws
,
512 unsigned *stride
, unsigned height
,
513 enum i915_winsys_buffer_tile
*tiling
,
514 enum i915_winsys_buffer_type type
)
516 D(bug("[GMA winsys] buffer_create_tiled stride=%d heigh=%d type:%s\n",*stride
,height
,i915_type_to_name(type
)));
517 // Tiling is not implemented.
518 *tiling
= I915_TILE_NONE
;
519 return buffer_create( iws
, *stride
* height
, type
);
524 * Creates a buffer from a handle.
525 * Used to implement pipe_screen::resource_from_handle.
526 * Also provides the stride information needed for the
527 * texture via the stride argument.
529 struct i915_winsys_buffer
*
530 buffer_from_handle(struct i915_winsys
*iws
,
531 struct winsys_handle
*whandle
,
532 enum i915_winsys_buffer_tile
*tiling
,
535 D(bug("[GMA winsys] buffer_from_handle\n"));
542 * Used to implement pipe_screen::resource_get_handle.
543 * The winsys might need the stride information.
545 boolean
buffer_get_handle(struct i915_winsys
*iws
,
546 struct i915_winsys_buffer
*buffer
,
547 struct winsys_handle
*whandle
,
550 D(bug("[GMA winsys] buffer_get_handle\n"));
559 void *buffer_map(struct i915_winsys
*iws
,
560 struct i915_winsys_buffer
*buffer
,
568 D(bug("[GMA winsys] buffer_map %p\n",buffer
));
569 while( buffer_is_busy(iws
, buffer
)){};
577 void buffer_unmap(struct i915_winsys
*iws
,
578 struct i915_winsys_buffer
*buffer
)
580 MAGIC_WARNING(buffer
);
581 D(bug("[GMA winsys] buffer_unmap %p\n",buffer
));
589 * Arguments follows pipe_buffer_write.
591 int buffer_write(struct i915_winsys
*iws
,
592 struct i915_winsys_buffer
*dst
,
597 D(bug("[GMA winsys] buffer_write offset=%d size=%d\n",offset
,size
));
603 void buffer_destroy(struct i915_winsys
*iws
,
604 struct i915_winsys_buffer
*buf
)
606 IF_BAD_MAGIC(buf
) return;
607 D(bug("[GMA winsys] buffer_destroy %p\n", buf
));
611 while( buffer_is_busy(0, buf
) ){};
613 free_gfx_mem(buf
->allocated_map
, buf
->allocated_size
);
618 ObtainSemaphore(&UnusedBuffersListLock
);
619 AddTail( &unusedbuffers
, (struct Node
*)buf
);
620 ReleaseSemaphore(&UnusedBuffersListLock
);
626 * Check if a buffer is busy.
628 boolean
buffer_is_busy(struct i915_winsys
*iws
,
629 struct i915_winsys_buffer
*buf
)
633 int i
=buf
->status_index
;
634 D(bug("[GMA winsys] buffer_is_busy %p index %d flush_num %d\n",buf
,i
,buf
->flush_num
));
637 if( hw_status
[i
].reserved
&&
638 hw_status
[i
].flush_num
== buf
->flush_num
)
646 buf
->status_index
= 0;
647 free_status_index(i
);
657 /****************************************************************
659 *************************************************************/
662 * Reference fence and set ptr to fence.
664 void fence_reference(struct i915_winsys
*iws
,
665 struct pipe_fence_handle
**ptr
,
666 struct pipe_fence_handle
*fence
)
668 D(bug("[GMA winsys] fence_reference\n"));
674 * Check if a fence has finished.
676 int fence_signalled(struct i915_winsys
*iws
,
677 struct pipe_fence_handle
*fence
)
679 D(bug("[GMA winsys] fence_signalled\n"));
686 * Wait on a fence to finish.
688 int fence_finish(struct i915_winsys
*iws
,
689 struct pipe_fence_handle
*fence
)
691 D(bug("[GMA winsys] fence_finish\n"));
697 void winsys_destroy(struct i915_winsys
*ws
)
699 D(bug("[GMA winsys] winsys_destroy\n"));
700 struct aros_winsys
*aws
= aros_winsys(ws
);
707 D(bug("[GMA winsys] winsys_create\n"));
708 struct aros_winsys
*aws
;
710 aws
= CALLOC_STRUCT(aros_winsys
);
711 if (!aws
) return NULL
;
713 aws
->base
.batchbuffer_create
= batchbuffer_create
;
714 aws
->base
.validate_buffers
= batchbuffer_validate_buffers
;
715 aws
->base
.batchbuffer_reloc
= batchbuffer_reloc
;
716 aws
->base
.batchbuffer_flush
= batchbuffer_flush
;
717 aws
->base
.batchbuffer_destroy
= batchbuffer_destroy
;
719 aws
->base
.buffer_create
= buffer_create
;
720 aws
->base
.buffer_create_tiled
= buffer_create_tiled
;
721 aws
->base
.buffer_from_handle
= buffer_from_handle
;
722 aws
->base
.buffer_get_handle
= buffer_get_handle
;
723 aws
->base
.buffer_map
= buffer_map
;
724 aws
->base
.buffer_unmap
= buffer_unmap
;
725 aws
->base
.buffer_write
= buffer_write
;
726 aws
->base
.buffer_destroy
= buffer_destroy
;
727 aws
->base
.buffer_is_busy
= buffer_is_busy
;
729 aws
->base
.fence_reference
= fence_reference
;
730 aws
->base
.fence_signalled
= fence_signalled
;
731 aws
->base
.fence_finish
= fence_finish
;
733 aws
->base
.destroy
= winsys_destroy
;
735 aws
->base
.pci_id
= sd
->ProductID
;
736 #ifdef GALLIUM_SIMULATION
737 aws
->base
.pci_id
= 0x27AE;
739 aws
->max_batch_size
= 16 * 4096;