3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
10 #include "include/renderman.h"
11 #include "include/ioman.h"
13 // Allocateable space in vram, as indicated in GsKit's code
14 #define __VRAM_SIZE 4194304
19 /** Helper texture list */
20 struct rm_texture_list_t
{
23 struct rm_texture_list_t
*next
;
31 static struct rm_texture_list_t
*uploadedTextures
= NULL
;
33 static rm_clip_rect_t clipRect
;
37 static enum rm_vmode vmode
;
38 // GSKit side detected vmode...
39 static int defaultVMode
= GS_MODE_PAL
;
41 #define NUM_RM_VMODES 3
42 // RM Vmode -> GS Vmode conversion table
43 static const int rm_mode_table
[NUM_RM_VMODES
] = {
49 // inverse mode conversion table
50 #define MAX_GS_MODE 15
51 static int rm_gsmode_table
[MAX_GS_MODE
+1] = {
52 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
55 static int rm_height_table
[] = {
61 static float aspectWidth
;
62 static float aspectHeight
;
64 // Transposition values - all rendering can be transposed (moved on screen) by these
65 // this is a post-clipping operation
66 static float transX
= 0;
67 static float transY
= 0;
69 const u64 gColWhite
= GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x00);
70 const u64 gColBlack
= GS_SETREG_RGBA(0x00,0x00,0x00,0x00);
71 const u64 gColDarker
= GS_SETREG_RGBA(0x00,0x00,0x00,0x60);
72 const u64 gColFocus
= GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x50);
74 const u64 gDefaultCol
= GS_SETREG_RGBA(0x80,0x80,0x80,0x80);
75 const u64 gDefaultAlpha
= GS_SETREG_ALPHA(0,1,0,1,0);
77 static float shiftYVal
;
78 static float (*shiftY
)(float posY
);
80 static float shiftYFunc(float posY
) {
81 //return (int) ceil(shiftYVal * posY);
82 return (int) (shiftYVal
* posY
);
85 static float identityFunc(float posY
) {
89 static int rmClipQuad(rm_quad_t
* quad
) {
93 if (quad
->ul
.x
> clipRect
.x1
)
95 if (quad
->ul
.y
> clipRect
.y1
)
97 if (quad
->br
.x
< clipRect
.x
)
99 if (quad
->br
.y
< clipRect
.y
)
102 float dx
= quad
->br
.x
- quad
->ul
.x
;
103 float dy
= quad
->br
.y
- quad
->ul
.x
;
104 float du
= (quad
->br
.u
- quad
->ul
.u
) / dx
;
105 float dv
= (quad
->br
.v
- quad
->ul
.v
) / dy
;
107 if (quad
->ul
.x
< clipRect
.x
) {
109 float d
= clipRect
.x
- quad
->ul
.x
;
110 quad
->ul
.x
= clipRect
.x
;
111 quad
->ul
.u
+= d
* du
;
114 if (quad
->ul
.y
< clipRect
.y
) {
116 float d
= clipRect
.y
- quad
->ul
.y
;
117 quad
->ul
.y
= clipRect
.y
;
118 quad
->ul
.v
+= d
* dv
;
121 if (quad
->br
.x
> clipRect
.x1
) {
123 float d
= quad
->br
.x
- clipRect
.x1
;
124 quad
->br
.x
= clipRect
.x1
;
125 quad
->br
.u
-= d
* du
;
128 if (quad
->ul
.y
< clipRect
.y
) {
130 float d
= quad
->br
.y
- clipRect
.y1
;
131 quad
->br
.y
= clipRect
.y1
;
132 quad
->br
.v
-= d
* dv
;
138 static void rmAppendUploadedTextures(GSTEXTURE
*txt
) {
139 struct rm_texture_list_t
*entry
= (struct rm_texture_list_t
*)malloc(sizeof(struct rm_texture_list_t
));
142 entry
->next
= uploadedTextures
;
143 uploadedTextures
= entry
;
146 static void rmAppendUploadedCLUTs(GSCLUT
*clut
) {
147 struct rm_texture_list_t
*entry
= (struct rm_texture_list_t
*)malloc(sizeof(struct rm_texture_list_t
));
150 entry
->next
= uploadedTextures
;
151 uploadedTextures
= entry
;
154 static int rmClutSize(GSCLUT
*clut
, u32
*size
, u32
*w
, u32
*h
) {
168 switch(clut
->ClutPSM
) {
170 *size
= (*w
) * (*h
) * 4;
173 *size
= (*w
) * (*h
) * 4;
176 *size
= (*w
) * (*h
) * 2;
179 *size
= (*w
) * (*h
) * 2;
188 static int rmUploadClut(GSCLUT
*clut
) {
189 if (clut
->VramClut
&& clut
->VramClut
!= GSKIT_ALLOC_ERROR
) // already uploaded
195 if (!rmClutSize(clut
, &size
, &w
, &h
))
198 size
= (-GS_VRAM_BLOCKSIZE_256
)&(size
+GS_VRAM_BLOCKSIZE_256
-1);
200 // too large to fit VRAM with the currently allocated space?
201 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
204 if (size
>= __VRAM_SIZE
) {
205 // Only log this if the allocation is too large itself
206 LOG("RM: CLUT: Requested allocation is bigger than VRAM!\n");
207 // We won't allocate this, it's too large
208 clut
->VramClut
= GSKIT_ALLOC_ERROR
;
215 clut
->VramClut
= gsGlobal
->CurrentPointer
;
216 gsGlobal
->CurrentPointer
+= size
;
218 rmAppendUploadedCLUTs(clut
);
220 gsKit_texture_send(clut
->Clut
, w
, h
, clut
->VramClut
, clut
->ClutPSM
, 1, GS_CLUT_PALLETE
);
224 static int rmUploadTexture(GSTEXTURE
* txt
) {
225 // For clut based textures...
228 if (!rmUploadClut((GSCLUT
*)txt
->Clut
))
231 // copy the new VramClut
232 txt
->VramClut
= ((GSCLUT
*)txt
->Clut
)->VramClut
;
235 u32 size
= gsKit_texture_size(txt
->Width
, txt
->Height
, txt
->PSM
);
236 // alignment of the allocation
237 size
= (-GS_VRAM_BLOCKSIZE_256
)&(size
+GS_VRAM_BLOCKSIZE_256
-1);
239 // too large to fit VRAM with the currently allocated space?
240 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
243 if (size
>= __VRAM_SIZE
) {
244 // Only log this if the allocation is too large itself
245 LOG("RM: TXT: Requested allocation is bigger than VRAM!\n");
246 // We won't allocate this, it's too large
247 txt
->Vram
= GSKIT_ALLOC_ERROR
;
253 // Should not flush CLUT away. If this happenned we have to reupload
255 if (!rmUploadClut((GSCLUT
*)txt
->Clut
))
258 txt
->VramClut
= ((GSCLUT
*)txt
->Clut
)->VramClut
;
261 // only could fit CLUT but not the pixmap with it!
262 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
266 txt
->Vram
= gsGlobal
->CurrentPointer
;
267 gsGlobal
->CurrentPointer
+= size
;
269 rmAppendUploadedTextures(txt
);
271 // We can't do gsKit_texture_upload since it'd assume txt->Clut is the CLUT table directly
272 // whereas we're using it as a pointer to our structure containg clut data
273 gsKit_setup_tbw(txt
);
274 gsKit_texture_send(txt
->Mem
, txt
->Width
, txt
->Height
, txt
->Vram
, txt
->PSM
, txt
->TBW
, txt
->Clut
? GS_CLUT_TEXTURE
: GS_CLUT_NONE
);
279 int rmPrepareTexture(GSTEXTURE
* txt
) {
280 if (txt
->Vram
&& txt
->Vram
!= GSKIT_ALLOC_ERROR
) // already uploaded
283 return rmUploadTexture(txt
);
286 void rmDispatch(void) {
287 gsKit_queue_exec(gsGlobal
);
294 // release all the uploaded textures
295 gsKit_vram_clear(gsGlobal
);
297 while (uploadedTextures
) {
298 // free clut and txt if those are filled in
299 if (uploadedTextures
->txt
) {
300 uploadedTextures
->txt
->Vram
= 0;
301 uploadedTextures
->txt
->VramClut
= 0;
304 if (uploadedTextures
->clut
)
305 uploadedTextures
->clut
->VramClut
= 0;
307 struct rm_texture_list_t
*entry
= uploadedTextures
;
308 uploadedTextures
= uploadedTextures
->next
;
313 void rmStartFrame(void) {
317 void rmEndFrame(void) {
318 gsKit_set_finish(gsGlobal
);
322 // Wait for draw ops to finish
325 if(!gsGlobal
->FirstFrame
)
330 if(gsGlobal
->DoubleBuffering
== GS_SETTING_ON
)
332 GS_SET_DISPFB2( gsGlobal
->ScreenBuffer
[gsGlobal
->ActiveBuffer
& 1] / 8192,
333 gsGlobal
->Width
/ 64, gsGlobal
->PSM
, 0, 0 );
335 gsGlobal
->ActiveBuffer
^= 1;
336 gsGlobal
->PrimContext
^= 1;
341 gsKit_setactive(gsGlobal
);
344 static int rmOnVSync(void) {
346 iWakeupThread(guiThreadID
);
351 void rmInit(int vsyncon
, enum rm_vmode vmodeset
) {
352 gsGlobal
= gsKit_init_global();
354 defaultVMode
= gsGlobal
->Mode
;
357 for (mde
= 0; mde
< NUM_RM_VMODES
; ++mde
) {
358 int gsmde
= rm_mode_table
[mde
];
359 if (gsmde
>= 0 && gsmde
<= MAX_GS_MODE
)
360 rm_gsmode_table
[rm_mode_table
[mde
]] = mde
;
364 rm_height_table
[RM_VMODE_AUTO
] = rm_height_table
[gsGlobal
->Mode
];
366 dmaKit_init(D_CTRL_RELE_OFF
, D_CTRL_MFD_OFF
, D_CTRL_STS_UNSPEC
,
367 D_CTRL_STD_OFF
, D_CTRL_RCYC_8
, 1 << DMA_CHANNEL_GIF
);
369 // Initialize the DMAC
370 dmaKit_chan_init(DMA_CHANNEL_GIF
);
371 dmaKit_chan_init(DMA_CHANNEL_FROMSPR
);
372 dmaKit_chan_init(DMA_CHANNEL_TOSPR
);
374 rmSetMode(vsyncon
, vmodeset
);
384 shiftY
= &shiftYFunc
;
389 guiThreadID
= GetThreadId();
390 gsKit_add_vsync_handler(&rmOnVSync
);
393 void rmSetMode(int vsyncon
, enum rm_vmode vmodeset
) {
398 if (vmode
!= RM_VMODE_AUTO
) {
399 gsGlobal
->Mode
= rm_mode_table
[vmode
];
401 gsGlobal
->Mode
= defaultVMode
;
404 gsGlobal
->Height
= 512; // whatever...
406 if (gsGlobal
->Mode
<= MAX_GS_MODE
) {
407 // back to rm mode from gs mode
408 int rmmde
= rm_gsmode_table
[gsGlobal
->Mode
];
411 gsGlobal
->Height
= rm_height_table
[rmmde
];
414 gsGlobal
->PSM
= GS_PSM_CT24
;
415 gsGlobal
->PSMZ
= GS_PSMZ_16S
;
416 gsGlobal
->ZBuffering
= GS_SETTING_OFF
;
417 gsGlobal
->PrimAlphaEnable
= GS_SETTING_ON
;
418 gsGlobal
->DoubleBuffering
= GS_SETTING_ON
;
420 gsKit_init_screen(gsGlobal
);
422 gsKit_mode_switch(gsGlobal
, GS_ONESHOT
);
424 gsKit_set_test(gsGlobal
, GS_ZTEST_OFF
);
426 // reset the contents of the screen to avoid garbage being displayed
427 gsKit_clear(gsGlobal
, gColBlack
);
428 gsKit_sync_flip(gsGlobal
);
430 LOG("New vmode: %d x %d\n", gsGlobal
->Width
, gsGlobal
->Height
);
434 void rmGetScreenExtents(int *w
, int *h
) {
435 *w
= gsGlobal
->Width
;
436 *h
= gsGlobal
->Height
;
443 /** If txt is null, don't use DIM_ADAPT size */
444 void rmSetupQuad(GSTEXTURE
* txt
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
, rm_quad_t
* q
) {
453 dim
= aspectWidth
* (w
>> 1);
460 dim
= aspectHeight
* (h
>> 1);
463 q
->ul
.y
= shiftY(y
) - dim
;
464 q
->br
.y
= shiftY(y
) + dim
;
473 q
->br
.x
= x
+ aspectWidth
* w
;
479 q
->br
.y
= shiftY(y
) + aspectHeight
* h
;
481 q
->br
.y
= shiftY(y
) + h
;
490 q
->br
.u
= txt
->Width
;
491 q
->br
.v
= txt
->Height
;
495 void rmDrawQuad(rm_quad_t
* q
) { // NO scaling, NO shift, NO alignment
499 if (!rmPrepareTexture(q
->txt
)) // won't render if not ready!
502 if ((q
->txt
->PSM
== GS_PSM_CT32
) || (q
->txt
->Clut
&& q
->txt
->ClutPSM
== GS_PSM_CT32
))
504 gsKit_set_primalpha(gsGlobal
, gDefaultAlpha
, 0);
507 gsKit_prim_sprite_texture(gsGlobal
, q
->txt
,
508 q
->ul
.x
+ transX
, q
->ul
.y
+ transY
,
510 q
->br
.x
+ transX
, q
->br
.y
+ transY
,
511 q
->br
.u
, q
->br
.v
, order
, q
->color
);
514 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
517 void rmDrawPixmap(GSTEXTURE
* txt
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
) {
519 rmSetupQuad(txt
, x
, y
, aligned
, w
, h
, scaled
, color
, &quad
);
523 void rmDrawOverlayPixmap(GSTEXTURE
* overlay
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
,
524 GSTEXTURE
* inlay
, int ulx
, int uly
, int urx
, int ury
, int blx
, int bly
, int brx
, int bry
) {
527 rmSetupQuad(overlay
, x
, y
, aligned
, w
, h
, scaled
, color
, &quad
);
529 if (!rmPrepareTexture(inlay
))
532 if (inlay
->PSM
== GS_PSM_CT32
)
533 gsKit_set_primalpha(gsGlobal
, gDefaultAlpha
, 0);
535 gsKit_prim_quad_texture(gsGlobal
, inlay
, quad
.ul
.x
+ transX
+ aspectWidth
* ulx
, quad
.ul
.y
+ transY
+ uly
, 0, 0,
536 quad
.ul
.x
+ transX
+ aspectWidth
* urx
, quad
.ul
.y
+ transY
+ ury
, inlay
->Width
, 0,
537 quad
.ul
.x
+ transX
+ aspectWidth
* blx
, quad
.ul
.y
+ transY
+ bly
, 0, inlay
->Height
,
538 quad
.ul
.x
+ transX
+ aspectWidth
* brx
, quad
.ul
.y
+ transY
+ bry
, inlay
->Width
, inlay
->Height
, order
, gDefaultCol
);
540 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
545 void rmDrawRect(int x
, int y
, int w
, int h
, u64 color
) {
546 gsKit_set_primalpha(gsGlobal
, GS_SETREG_ALPHA(0,1,0,1,0), 0);
547 gsKit_prim_quad(gsGlobal
, x
+ transX
, shiftY(y
) + transY
, x
+ w
+ transX
, shiftY(y
) + transY
, x
+ transX
, shiftY(y
) + h
+ transY
, x
+ w
+ transX
, shiftY(y
) + h
+ transY
, order
, color
);
549 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
552 void rmDrawLine(int x
, int y
, int x1
, int y1
, u64 color
) {
553 gsKit_prim_line(gsGlobal
, x
+ transX
, shiftY(y
) + transY
, x1
+ transX
, shiftY(y1
) + transY
, order
, color
);
556 /** Sets the clipping rectangle */
557 void rmClip(int x
, int y
, int w
, int h
) {
561 clipRect
.x1
= gsGlobal
->Width
;
565 clipRect
.y1
= gsGlobal
->Height
;
571 /** Sets cipping to none */
572 void rmUnclip(void) {
576 void rmSetAspectRatio(float width
, float height
) {
578 aspectHeight
= height
;
581 void rmResetAspectRatio() {
586 void rmGetAspectRatio(float *w
, float *h
) {
591 void rmApplyAspectRatio(int* w
, int* h
) {
592 *w
= *w
* aspectWidth
;
593 *h
= *h
* aspectHeight
;
596 void rmSetShiftRatio(float shiftYRatio
) {
597 shiftYVal
= shiftYRatio
;
598 shiftY
= &shiftYFunc
;
601 void rmResetShiftRatio() {
602 shiftY
= &identityFunc
;
605 void rmApplyShiftRatio(int* y
) {
609 void rmSetTransposition(float x
, float y
) {