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"
12 #include "include/usbld.h"
14 // Allocateable space in vram, as indicated in GsKit's code
15 #define __VRAM_SIZE 4194304
20 /** Helper texture list */
21 struct rm_texture_list_t
{
24 struct rm_texture_list_t
*next
;
27 static struct rm_texture_list_t
*uploadedTextures
= NULL
;
31 static enum rm_vmode vmode
= RM_VMODE_AUTO
;
33 #define NUM_RM_VMODES 3
35 // RM Vmode -> GS Vmode conversion table
36 static int rm_mode_table
[NUM_RM_VMODES
] = {
42 static int rm_height_table
[] = {
48 static float aspectWidth
;
49 static float aspectHeight
;
51 // Transposition values - all rendering can be transposed (moved on screen) by these
52 static float transX
= 0;
53 static float transY
= 0;
55 const u64 gColWhite
= GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x00);
56 const u64 gColBlack
= GS_SETREG_RGBA(0x00,0x00,0x00,0x00);
57 const u64 gColDarker
= GS_SETREG_RGBA(0x00,0x00,0x00,0x60);
58 const u64 gColFocus
= GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x50);
60 const u64 gDefaultCol
= GS_SETREG_RGBA(0x80,0x80,0x80,0x80);
61 const u64 gDefaultAlpha
= GS_SETREG_ALPHA(0,1,0,1,0);
63 static float shiftYVal
;
64 static float (*shiftY
)(float posY
);
66 static float shiftYFunc(float posY
) {
67 //return (int) ceil(shiftYVal * posY);
68 return (int) (shiftYVal
* posY
);
71 static float identityFunc(float posY
) {
75 static void rmAppendUploadedTextures(GSTEXTURE
*txt
) {
76 struct rm_texture_list_t
*entry
= (struct rm_texture_list_t
*)malloc(sizeof(struct rm_texture_list_t
));
79 entry
->next
= uploadedTextures
;
80 uploadedTextures
= entry
;
83 static void rmAppendUploadedCLUTs(GSCLUT
*clut
) {
84 struct rm_texture_list_t
*entry
= (struct rm_texture_list_t
*)malloc(sizeof(struct rm_texture_list_t
));
87 entry
->next
= uploadedTextures
;
88 uploadedTextures
= entry
;
91 static int rmClutSize(GSCLUT
*clut
, u32
*size
, u32
*w
, u32
*h
) {
105 switch(clut
->ClutPSM
) {
107 *size
= (*w
) * (*h
) * 4;
110 *size
= (*w
) * (*h
) * 4;
113 *size
= (*w
) * (*h
) * 2;
116 *size
= (*w
) * (*h
) * 2;
125 static int rmUploadClut(GSCLUT
*clut
) {
126 if (clut
->VramClut
&& clut
->VramClut
!= GSKIT_ALLOC_ERROR
) // already uploaded
132 if (!rmClutSize(clut
, &size
, &w
, &h
))
135 size
= (-GS_VRAM_BLOCKSIZE_256
)&(size
+GS_VRAM_BLOCKSIZE_256
-1);
137 // too large to fit VRAM with the currently allocated space?
138 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
141 if (size
>= __VRAM_SIZE
) {
142 // Only log this if the allocation is too large itself
143 LOG("RM: CLUT: Requested allocation is bigger than VRAM!\n");
144 // We won't allocate this, it's too large
145 clut
->VramClut
= GSKIT_ALLOC_ERROR
;
152 clut
->VramClut
= gsGlobal
->CurrentPointer
;
153 gsGlobal
->CurrentPointer
+= size
;
155 rmAppendUploadedCLUTs(clut
);
157 gsKit_texture_send(clut
->Clut
, w
, h
, clut
->VramClut
, clut
->ClutPSM
, 1, GS_CLUT_PALLETE
);
161 static int rmUploadTexture(GSTEXTURE
* txt
) {
162 // For clut based textures...
165 if (!rmUploadClut((GSCLUT
*)txt
->Clut
))
168 // copy the new VramClut
169 txt
->VramClut
= ((GSCLUT
*)txt
->Clut
)->VramClut
;
172 u32 size
= gsKit_texture_size(txt
->Width
, txt
->Height
, txt
->PSM
);
173 // alignment of the allocation
174 size
= (-GS_VRAM_BLOCKSIZE_256
)&(size
+GS_VRAM_BLOCKSIZE_256
-1);
176 // too large to fit VRAM with the currently allocated space?
177 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
180 if (size
>= __VRAM_SIZE
) {
181 // Only log this if the allocation is too large itself
182 LOG("RM: TXT: Requested allocation is bigger than VRAM!\n");
183 // We won't allocate this, it's too large
184 txt
->Vram
= GSKIT_ALLOC_ERROR
;
190 // Should not flush CLUT away. If this happenned we have to reupload
192 if (!rmUploadClut((GSCLUT
*)txt
->Clut
))
195 txt
->VramClut
= ((GSCLUT
*)txt
->Clut
)->VramClut
;
198 // only could fit CLUT but not the pixmap with it!
199 if(gsGlobal
->CurrentPointer
+ size
>= __VRAM_SIZE
)
203 txt
->Vram
= gsGlobal
->CurrentPointer
;
204 gsGlobal
->CurrentPointer
+= size
;
206 rmAppendUploadedTextures(txt
);
208 // We can't do gsKit_texture_upload since it'd assume txt->Clut is the CLUT table directly
209 // whereas we're using it as a pointer to our structure containg clut data
210 gsKit_setup_tbw(txt
);
211 gsKit_texture_send(txt
->Mem
, txt
->Width
, txt
->Height
, txt
->Vram
, txt
->PSM
, txt
->TBW
, txt
->Clut
? GS_CLUT_TEXTURE
: GS_CLUT_NONE
);
216 int rmPrepareTexture(GSTEXTURE
* txt
) {
217 if (txt
->Vram
&& txt
->Vram
!= GSKIT_ALLOC_ERROR
) // already uploaded
220 return rmUploadTexture(txt
);
223 void rmDispatch(void) {
224 gsKit_queue_exec(gsGlobal
);
231 // release all the uploaded textures
232 gsKit_vram_clear(gsGlobal
);
234 while (uploadedTextures
) {
235 // free clut and txt if those are filled in
236 if (uploadedTextures
->txt
) {
237 uploadedTextures
->txt
->Vram
= 0;
238 uploadedTextures
->txt
->VramClut
= 0;
241 if (uploadedTextures
->clut
)
242 uploadedTextures
->clut
->VramClut
= 0;
244 struct rm_texture_list_t
*entry
= uploadedTextures
;
245 uploadedTextures
= uploadedTextures
->next
;
250 void rmStartFrame(void) {
254 void rmEndFrame(void) {
255 gsKit_set_finish(gsGlobal
);
259 // Wait for draw ops to finish
262 if(!gsGlobal
->FirstFrame
)
267 if(gsGlobal
->DoubleBuffering
== GS_SETTING_ON
)
269 GS_SET_DISPFB2( gsGlobal
->ScreenBuffer
[gsGlobal
->ActiveBuffer
& 1] / 8192,
270 gsGlobal
->Width
/ 64, gsGlobal
->PSM
, 0, 0 );
272 gsGlobal
->ActiveBuffer
^= 1;
273 gsGlobal
->PrimContext
^= 1;
278 gsKit_setactive(gsGlobal
);
281 static int rmOnVSync(void) {
283 iWakeupThread(guiThreadID
);
289 gsGlobal
= gsKit_init_global();
291 rm_mode_table
[RM_VMODE_AUTO
] = gsGlobal
->Mode
;
292 rm_height_table
[RM_VMODE_AUTO
] = gsGlobal
->Height
;
294 dmaKit_init(D_CTRL_RELE_OFF
, D_CTRL_MFD_OFF
, D_CTRL_STS_UNSPEC
,
295 D_CTRL_STD_OFF
, D_CTRL_RCYC_8
, 1 << DMA_CHANNEL_GIF
);
297 // Initialize the DMAC
298 dmaKit_chan_init(DMA_CHANNEL_GIF
);
299 dmaKit_chan_init(DMA_CHANNEL_FROMSPR
);
300 dmaKit_chan_init(DMA_CHANNEL_TOSPR
);
310 shiftY
= &shiftYFunc
;
315 guiThreadID
= GetThreadId();
316 gsKit_add_vsync_handler(&rmOnVSync
);
319 int rmSetMode(int force
) {
320 if (gVMode
< RM_VMODE_AUTO
|| gVMode
>= NUM_RM_VMODES
)
321 gVMode
= RM_VMODE_AUTO
;
323 // we don't want to set the vmode without a reason...
324 int changed
= (vmode
!= gVMode
|| vsync
!= gVSync
|| force
);
329 gsGlobal
->Mode
= rm_mode_table
[vmode
];
330 gsGlobal
->Height
= rm_height_table
[vmode
];
332 gsGlobal
->PSM
= GS_PSM_CT24
;
333 gsGlobal
->PSMZ
= GS_PSMZ_16S
;
334 gsGlobal
->ZBuffering
= GS_SETTING_OFF
;
335 gsGlobal
->PrimAlphaEnable
= GS_SETTING_ON
;
336 gsGlobal
->DoubleBuffering
= GS_SETTING_ON
;
338 gsKit_init_screen(gsGlobal
);
340 gsKit_mode_switch(gsGlobal
, GS_ONESHOT
);
342 gsKit_set_test(gsGlobal
, GS_ZTEST_OFF
);
344 // reset the contents of the screen to avoid garbage being displayed
345 gsKit_clear(gsGlobal
, gColBlack
);
346 gsKit_sync_flip(gsGlobal
);
348 LOG("New vmode: %d, %d x %d\n", vmode
, gsGlobal
->Width
, gsGlobal
->Height
);
353 void rmGetScreenExtents(int *w
, int *h
) {
354 *w
= gsGlobal
->Width
;
355 *h
= gsGlobal
->Height
;
362 /** If txt is null, don't use DIM_UNDEF size */
363 void rmSetupQuad(GSTEXTURE
* txt
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
, rm_quad_t
* q
) {
372 dim
= aspectWidth
* (w
>> 1);
379 dim
= aspectHeight
* (h
>> 1);
382 q
->ul
.y
= shiftY(y
) - dim
;
383 q
->br
.y
= shiftY(y
) + dim
;
392 q
->br
.x
= x
+ aspectWidth
* w
;
398 q
->br
.y
= shiftY(y
) + aspectHeight
* h
;
400 q
->br
.y
= shiftY(y
) + h
;
409 q
->br
.u
= txt
->Width
;
410 q
->br
.v
= txt
->Height
;
414 void rmDrawQuad(rm_quad_t
* q
) { // NO scaling, NO shift, NO alignment
415 if (!rmPrepareTexture(q
->txt
)) // won't render if not ready!
418 if ((q
->txt
->PSM
== GS_PSM_CT32
) || (q
->txt
->Clut
&& q
->txt
->ClutPSM
== GS_PSM_CT32
))
420 gsKit_set_primalpha(gsGlobal
, gDefaultAlpha
, 0);
423 gsKit_prim_sprite_texture(gsGlobal
, q
->txt
,
424 q
->ul
.x
+ transX
, q
->ul
.y
+ transY
,
426 q
->br
.x
+ transX
, q
->br
.y
+ transY
,
427 q
->br
.u
, q
->br
.v
, order
, q
->color
);
430 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
433 void rmDrawPixmap(GSTEXTURE
* txt
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
) {
435 rmSetupQuad(txt
, x
, y
, aligned
, w
, h
, scaled
, color
, &quad
);
439 void rmDrawOverlayPixmap(GSTEXTURE
* overlay
, int x
, int y
, short aligned
, int w
, int h
, short scaled
, u64 color
,
440 GSTEXTURE
* inlay
, int ulx
, int uly
, int urx
, int ury
, int blx
, int bly
, int brx
, int bry
) {
443 rmSetupQuad(overlay
, x
, y
, aligned
, w
, h
, scaled
, color
, &quad
);
445 if (!rmPrepareTexture(inlay
))
448 if (inlay
->PSM
== GS_PSM_CT32
)
449 gsKit_set_primalpha(gsGlobal
, gDefaultAlpha
, 0);
451 gsKit_prim_quad_texture(gsGlobal
, inlay
, quad
.ul
.x
+ transX
+ aspectWidth
* ulx
, quad
.ul
.y
+ transY
+ uly
, 0, 0,
452 quad
.ul
.x
+ transX
+ aspectWidth
* urx
, quad
.ul
.y
+ transY
+ ury
, inlay
->Width
, 0,
453 quad
.ul
.x
+ transX
+ aspectWidth
* blx
, quad
.ul
.y
+ transY
+ bly
, 0, inlay
->Height
,
454 quad
.ul
.x
+ transX
+ aspectWidth
* brx
, quad
.ul
.y
+ transY
+ bry
, inlay
->Width
, inlay
->Height
, order
, gDefaultCol
);
456 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
461 void rmDrawRect(int x
, int y
, int w
, int h
, u64 color
) {
462 gsKit_set_primalpha(gsGlobal
, GS_SETREG_ALPHA(0,1,0,1,0), 0);
463 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
);
465 gsKit_set_primalpha(gsGlobal
, GS_BLEND_BACK2FRONT
, 0);
468 void rmDrawLine(int x
, int y
, int x1
, int y1
, u64 color
) {
469 gsKit_prim_line(gsGlobal
, x
+ transX
, shiftY(y
) + transY
, x1
+ transX
, shiftY(y1
) + transY
, order
, color
);
472 void rmSetAspectRatio(float width
, float height
) {
474 aspectHeight
= height
;
477 void rmResetAspectRatio() {
482 void rmGetAspectRatio(float *w
, float *h
) {
487 void rmApplyAspectRatio(int* w
, int* h
) {
488 *w
= *w
* aspectWidth
;
489 *h
= *h
* aspectHeight
;
492 void rmSetShiftRatio(float shiftYRatio
) {
493 shiftYVal
= shiftYRatio
;
494 shiftY
= &shiftYFunc
;
497 void rmResetShiftRatio() {
498 shiftY
= &identityFunc
;
501 void rmApplyShiftRatio(int* y
) {
505 void rmSetTransposition(float x
, float y
) {