107#define MAX_PASS_COUNT 4
108#define STACK_SIZE (8 * 1024)
110GSQUEUE __DrawQueue[2];
111volatile u32 __iCurrentDrawQueue = 0;
112GSTEXTURE * __pTexture = NULL;
115s32 __hsync_callback_id = -1;
116volatile u32 __vsync_count = 0;
117volatile u32 __hsync_count = 0;
120u32 __iCurrentPass = 0;
121u32 __iCurrentRenderField = 0;
122SBuffer __buffer[MAX_PASS_COUNT];
123SPass __pass[MAX_PASS_COUNT];
125s32 __sema_vsync_id = 0;
126s32 __sema_hsync_id = 0;
127s32 __sema_queue_id = 0;
133static void gsKit_setpass(GSGLOBAL *
gsGlobal,
const SPass * __pass,
int yoff)
139 p_data = p_store = (u64*)gsKit_heap_alloc(
gsGlobal, qsize, (qsize * 16),
GIF_AD);
165static void gsKit_setpass_background(GSGLOBAL *
gsGlobal,
const SPass * __pass, GSTEXTURE * tex)
168 u16 height = __pass->DrawBuffer->bufferline_end - __pass->DrawBuffer->bufferline_begin + 1;
169 void * mem = &((u16*)tex->
Mem)[__pass->DrawBuffer->bufferline_begin*width];
172 gsKit_texture_send_inline(
gsGlobal, mem, width, height, __pass->DrawBuffer->addr, tex->
PSM, tex->
TBW, GS_CLUT_NONE);
175static void gsKit_create_pass(GSGLOBAL *
gsGlobal,
const SPass * __pass, GSQUEUE * Queue,
int yoff)
180 if (Queue->pool[0] == NULL)
186 gsKit_setpass(
gsGlobal, __pass, yoff);
193 if (__pTexture != NULL)
194 gsKit_setpass_background(
gsGlobal, __pass, __pTexture);
200void _gsKit_create_passes(GSGLOBAL *
gsGlobal)
206 for (iPass = 0; iPass < __iPassCount; iPass++) {
208 gsKit_create_pass(
gsGlobal, &__pass[iPass], &__pass[iPass].Queue, 0);
210 gsKit_create_pass(
gsGlobal, &__pass[iPass], &__pass[iPass].QueueIF, 8);
214 for (iPass = 0; iPass < __iPassCount; iPass++) {
215 gsKit_create_pass(
gsGlobal, &__pass[iPass], &__pass[iPass].Queue, 0);
223 while (PollSema(__sema_vsync_id) >= 0)
227 WaitSema(__sema_vsync_id);
236static u32 __last_flip_vsync_count = 0;
246 case GSFLIP_VSYNC: vsync_end = __vsync_count + 1;
break;
252 while (__vsync_count < vsync_end) {
253 WaitSema(__sema_vsync_id);
257 __last_flip_vsync_count = __vsync_count;
268 WaitSema(__sema_queue_id);
270 __iCurrentDrawQueue = (__iCurrentDrawQueue == 0) ? 1 : 0;
271 SignalSema(__sema_queue_id);
277static void gsKit_texture_to_interlaced_frame(GSTEXTURE * tex)
293 tex_new = (u16*)memalign(128, size);
294 tex_old = (u16*)tex->
Mem;
296 for(y=0; y < tex->
Height; y+=2) {
298 memcpy(&tex_new[(y/2)*tex->
Width], &tex_old[y*tex->
Width], tex->
Width * bpp);
304 tex->
Mem = (
void*)tex_new;
312 gsKit_texture_to_psm16(tex);
319 gsKit_texture_to_interlaced_frame(tex);
346 WaitSema(__sema_queue_id);
349 SignalSema(__sema_queue_id);
354static int hsync_callback(
int cause)
369 for (iPass = 0; iPass < __iPassCount; iPass++) {
370 if (__hsync_count == (__iYStart + __pass[iPass].CRTCBuffer->scanline_begin)) {
375 __iCurrentRenderField = (((GSREG*)
GS_CSR)->FIELD == 1) ? 0 : 1;
378 __iCurrentPass = iPass;
379 iSignalSema(__sema_hsync_id);
393static void gsKit_queue_send(GSGLOBAL *
gsGlobal, GSQUEUE *Queue)
398 *(u64 *)Queue->
dma_tag = DMA_TAG(Queue->
tag_size, 0, DMA_END, 0, 0, 0);
409static void dma_to_gs_thread(
void * data)
411 GSGLOBAL *
gsGlobal = (GSGLOBAL *)data;
417 while (PollSema(__sema_hsync_id) >= 0)
421 WaitSema(__sema_hsync_id);
423 WaitSema(__sema_queue_id);
431 if (__iCurrentRenderField == 1)
432 gsKit_queue_send(
gsGlobal, &__pass[__iCurrentPass].Queue);
434 gsKit_queue_send(
gsGlobal, &__pass[__iCurrentPass].QueueIF);
437 gsKit_queue_send(
gsGlobal, &__pass[__iCurrentPass].Queue);
441 iQueue = (__iCurrentDrawQueue == 0) ? 1 : 0;
442 gsKit_queue_send(
gsGlobal, &__DrawQueue[iQueue]);
448 SignalSema(__sema_queue_id);
451 if (__iCurrentPass == (__iPassCount-1))
452 SignalSema(__sema_vsync_id);
458 u8 ZBuffering_backup;
471 __iPassCount = passCount;
472 __iPassCount = __iPassCount < 2 ? 2 : __iPassCount;
473 __iPassCount = __iPassCount > 4 ? 4 : __iPassCount;
475 if (__iPassCount > 2) {
483 printf(
"gsKit_hires: ERROR: invalid PSM\n");
506 iPassHeight = (
gsGlobal->
Height + (__iPassCount-1)) / __iPassCount;
507 iPassHeight = (iPassHeight + (iHeightAlign-1)) & ~(iHeightAlign-1);
527 printf(
"gsKit_hires: Padding front buffer with %dKiB \n", iAlign/1024);
541 for (iPass = 0; iPass < __iPassCount; iPass++) {
546 __buffer[iPass].bufferline_begin = iBufferline;
547 iBufferline += iPassHeight;
550 __buffer[iPass].bufferline_end = iBufferline - 1;
553 __buffer[iPass].scanline_begin = __buffer[iPass].bufferline_begin;
554 __buffer[iPass].scanline_end = __buffer[iPass].bufferline_end;
564 __buffer[iPass].scanline_begin /= 2;
565 __buffer[iPass].scanline_end /= 2;
585 for (iPass = 0; iPass < __iPassCount; iPass++) {
586 int iPrevPass = (iPass == 0) ? (__iPassCount-1) : (iPass-1);
589 __pass[iPass].DrawBuffer = &__buffer[iPass];
591 __pass[iPass].CRTCBuffer = &__buffer[iPrevPass];
593 if (__iPassCount == 2) {
595 __pass[iPass].DepthBuffer = &__buffer[2];
596 __pass[iPass].TextBuffer = NULL;
598 else if (__iPassCount == 3) {
599 int iNextPass = (iPass == (__iPassCount-1)) ? 0 : (iPass+1);
602 __pass[iPass].DepthBuffer = &__buffer[iNextPass];
603 __pass[iPass].TextBuffer = NULL;
606 int iNextPass1 = (iPass == (__iPassCount-1)) ? 0 : (iPass+1);
607 int iNextPass2 = (iNextPass1 == (__iPassCount-1)) ? 0 : (iNextPass1+1);
613 __pass[iPass].DepthBuffer = &__buffer[((iPass & 1) == 0) ? iNextPass1 : iNextPass2];
614 __pass[iPass].TextBuffer = &__buffer[((iPass & 1) == 0) ? iNextPass2 : iNextPass1];
632 if ((__sema_hsync_id = CreateSema(&sema)) < 0)
633 printf(
"gsKit_hires: ERROR: creating __sema_hsync_id\n");
637 if ((__sema_vsync_id = CreateSema(&sema)) < 0)
638 printf(
"gsKit_hires: ERROR: creating __sema_vsync_id\n");
643 if ((__sema_queue_id = CreateSema(&sema)) < 0)
644 printf(
"gsKit_hires: ERROR: creating __sema_queue_id\n");
648 thread.initial_priority = 1;
649 thread.stack_size = STACK_SIZE;
650 thread.gp_reg = &_gp;
651 thread.func = (
void *)dma_to_gs_thread;
652 thread.stack = (
void *)__ThreadStack;
655 if ((__ThreadId = CreateThread(&thread)) < 0)
656 printf(
"gsKit_hires: ERROR: creating thread\n");
661 ChangeThreadPriority(GetThreadId(), 2);
666 printf(
"gsKit_hires: ERROR: registering hsync handler\n");
671 return gsKit_init_global();
678 if (__hsync_callback_id >= 0)
681 WaitSema(__sema_queue_id);
683 TerminateThread(__ThreadId);
684 DeleteThread(__ThreadId);
686 if (__sema_queue_id >= 0)
687 DeleteSema(__sema_queue_id);
689 if (__sema_vsync_id >= 0)
690 DeleteSema(__sema_vsync_id);
692 if (__sema_hsync_id >= 0)
693 DeleteSema(__sema_hsync_id);
698 for (iPass = 0; iPass < __iPassCount; iPass++) {
void dmaKit_wait_fast(void)
void dmaKit_send_chain_ucab(u16 channel, void *data)
void gsKit_queue_reset(GSQUEUE *Queue)
Reset specified drawqueue to it's initial state (Useful for clearing the Persistent Queue).
int gsKit_add_hsync_handler(int(*hsync_callback)(int))
Installs a hsync interrupt handler (hblank_start).
void gsKit_queue_set(GSGLOBAL *gsGlobal, GSQUEUE *Queue)
Set Current Draw Queue.
void gsKit_clear(GSGLOBAL *gsGlobal, u64 Color)
u32 gsKit_vram_alloc(GSGLOBAL *gsGlobal, u32 size, u8 type)
GS VRAM Allocation.
#define GS_ZTEST_ON
Turns on Z Testing.
void gsKit_remove_hsync_handler(int callback_id)
Removes a hsync interrupt handler.
void gsKit_queue_free(GSGLOBAL *gsGlobal, GSQUEUE *Queue)
Free Allocated Memory for Draw Queue.
GSFLIP_MODE
Flip mode for gsKit_hires_flip_ext.
@ GSFLIP_VSYNC
Wait for vsync before flipping.
@ GSFLIP_RATE_LIMIT_2
Limit to 30fps (2 vsyncs per frame).
@ GSFLIP_RATE_LIMIT_1
Limit to 60fps (1 vsync per frame).
@ GSFLIP_DIRECT
Flip immediately, no vsync wait.
void gsKit_set_test(GSGLOBAL *gsGlobal, u8 Preset)
void gsKit_queue_init(GSGLOBAL *gsGlobal, GSQUEUE *Queue, u8 mode, int size)
Initialize a Draw Queue (Allocates memory for the Queue).
#define GSKIT_ALLOC_SYSBUFFER
GS VRAM "System" Allocation (Framebuffer, ZBuffer, etc).
void gsKit_hires_flip_ext(GSGLOBAL *gsGlobal, GSFLIP_MODE mode)
Flips Draw Queue with specified flip mode.
void gsKit_hires_flip(GSGLOBAL *gsGlobal)
Flips Draw Queue.
void gsKit_hires_sync(GSGLOBAL *gsGlobal)
Wait for VSync.
int gsKit_hires_set_bg(GSGLOBAL *gsGlobal, GSTEXTURE *tex)
Set background texture, must be same size and PSM as display.
void gsKit_hires_prepare_bg(GSGLOBAL *gsGlobal, GSTEXTURE *tex)
Converts PSM and interlacing for use as background image.
GSGLOBAL * gsKit_hires_init_global()
Initialize gsGlobal.
void gsKit_hires_deinit_global(GSGLOBAL *gsGlobal)
De-initialize gsGlobal.
void gsKit_hires_init_screen(GSGLOBAL *gsGlobal, int passCount)
Initialize Screen and GS Registers, for multi pass high resolution mode.
#define GS_SETREG_XYOFFSET_1
See GS_SETREG_XYOFFSET.
#define GIF_TAG_AD(NLOOP)
A+D GIFTAG.
#define GS_FRAME_1
GS Frame Buffer (Context 1).
#define GS_PSMZ_16S
RGBA16 ZBuffer ?
#define GS_PSM_CT32
R8 G8 B8 A8 (RGBA32) Texture.
void gsKit_init_screen(GSGLOBAL *gsGlobal)
Initialize Screen and GS Registers.
#define GS_RENDER_QUEUE_PER_POOLSIZE
Size of Persistent drawbuffer (Single Buffered).
#define GS_FRAME_2
GS Frame Buffer (Context 2).
#define GS_PSM_CT16S
RGBA16 Texture ?
#define GS_PSMZ_32
R8 G8 B8 A8 (RGBA32) ZBuffer.
#define GS_FRAME
Frame Mode - Reads Every Line.
#define GS_SETREG_ZBUF_1
See GS_SETREG_ZBUF.
#define GS_SETREG_RGBAQ(r, g, b, a, q)
Object Creation Macro for RGBAQ Color Values.
#define GS_SETTING_OFF
Define a setting to be OFF.
#define GS_XYOFFSET_2
GS Offset Value.
#define GS_PSM_CT24
R8 G8 B8 (RGB24) Texture.
#define GS_SETTING_ON
Define a setting to be ON.
#define GS_ZBUF_1
GS Z Buffer (Context 1).
#define GIF_AD
GIF_TAG Address+Data Setting. (Used after GIF_TAG).
#define GS_PERSISTENT
Persistent Draw Queue.
#define GS_SCISSOR_2
GS Scissoring Area (Context 2).
#define GS_SCISSOR_1
GS Scissoring Area (Context 1).
#define GS_PSMZ_16
RGBA16 ZBuffer.
#define GS_SET_BGCOLOR(R, G, B)
GS Background Color Register Access Macro.
#define GS_SETREG_SCISSOR_1
See GS_SETREG_SCISSOR.
#define GS_XYOFFSET_1
GS Offset Value.
#define GS_ZBUF_2
GS Z Buffer (Context 2).
#define GS_SETREG_FRAME_1
See GS_SETREG_FRAME.
#define GS_INTERLACED
Interlaced Mode.
#define GS_FIELD
Field Mode - Reads Every Other Line.
#define GS_CSR
GS CSR (GS System Status) Register.
#define GS_PSM_CT16
RGBA16 Texture.
u8 ZBuffering
Enable/Disable Z Buffering.
int Width
Framebuffer Width (the mode's DW is a multiple of this value).
u32 CurrentPointer
Current VRAM Pointer.
GSQUEUE * CurQueue
Draw Queue (Current).
int PSMZ
ZBuffer Pixel Storage Method.
u32 TexturePointer
Pointer to beginning of Texture Buffer.
u8 DoubleBuffering
Enable/Disable Double Buffering.
int StartYOffset
Y Starting Coordinate (Used for Placement Correction) Additional correction.
int OffsetX
X Window Offset.
int PSM
Pixel Storage Method (Color Mode).
int MagV
Y Magnification Value (MAGV = DH / Height - 1).
int Height
Framebuffer Height (the mode's DH is a multiple of this value).
int OffsetY
Y Window Offset.
u32 ZBuffer
ZBuffer Pointer.
s16 Interlace
Interlace (On/Off).
int StartY
Y Starting Coordinate (Used for Placement Correction) Default value.
GSQUEUE * Per_Queue
Draw Queue (Persistent).
void * dma_tag
Pointer to last DMA_TAG.
int same_obj
Number of times in a row the same REGLIST enabled object has been added (Used for NLOOP fixup later).
void * last_tag
Pointer to the GIF_TAG of the last object in this draw queue.
int dbuf
Which of the pool[2] buffers we are using.
int last_type
Last type of object in this draw queue.
u32 tag_size
Quadwords in current DMA_TAG.
u32 TBW
Texture Base Width.
u32 * Mem
EE Memory Pointer.
u8 PSM
Pixel Storage Method (Color Format).
u32 Height
Height of the Texture.
u32 Width
Width of the Texture.