[SOLVED]PVR Rendering Code not producing Output on Dreamcast
Posted: Wed Jan 29, 2014 4:59 pm
Hey everyone,
First of all a big "Thank You" to all of you, especially the Development Team for kinda "lighting the Dreamcast - Spark inside me", in other words having made me interested in a Dreamcast, buy a Dreamcast and now program for a Dreamcast
Now to my Problem...
While flawlessly compiling and - after conversion to a .cdi Image with BootDreams - also running on nullDC w/ Chankast as Rendering Plugin, my .cdi just won't show any graphical output on the Dreamcast itself when burned on a Disk using Alocohol 120%.
What drives me crazy about this is, that the CD-R boots without problems, shows a red border and even receives Controller Input (i can close my Program using [START] as implemented).
This means the Application actually RUNS, but somehow no graphical output is to be seen. (besides the borders)
Can anyone maybe point me to what the Problem could be?
I'm gonna receive an SD-Adapter anytime near the next 3 weeks, but i'd really like to get something up running on a CD-R just as - you know - somewhat like a proof of concept.
Any help is appreciated.
Thanks alot, shmup.
[EDIT]
Okay so I've hunted It down and am now definitely able to blame my Code, as other KOS Example Projects run normally even when burned to CD-R and thrown into my DC.
Right now my Code looks like the following:
Here they are. I'm initializing the PVR as follows:
[Inside the Header File]
So the next possible Source of Problems is the actual Rendering Code, this basically uses the technique demonstrated by Falco in his DMA / Store Queue Tutorial.
Inside the draw Function i'm basically doing this:
Prepare the next Frame:
Because I'm somewhat new to the whole KOS / PVR Stuff I hope I'm just forgetting about something really obvious that needs to be done manually on the actual Hardware and is done automatically on the Emulator or such.
Sorry for spamming such a shitload of Code but i really wasn't able to spot the possible Problem more precisely.
Thanks in Advance,
shmup.
First of all a big "Thank You" to all of you, especially the Development Team for kinda "lighting the Dreamcast - Spark inside me", in other words having made me interested in a Dreamcast, buy a Dreamcast and now program for a Dreamcast
Now to my Problem...
While flawlessly compiling and - after conversion to a .cdi Image with BootDreams - also running on nullDC w/ Chankast as Rendering Plugin, my .cdi just won't show any graphical output on the Dreamcast itself when burned on a Disk using Alocohol 120%.
What drives me crazy about this is, that the CD-R boots without problems, shows a red border and even receives Controller Input (i can close my Program using [START] as implemented).
This means the Application actually RUNS, but somehow no graphical output is to be seen. (besides the borders)
Can anyone maybe point me to what the Problem could be?
I'm gonna receive an SD-Adapter anytime near the next 3 weeks, but i'd really like to get something up running on a CD-R just as - you know - somewhat like a proof of concept.
Any help is appreciated.
Thanks alot, shmup.
[EDIT]
Okay so I've hunted It down and am now definitely able to blame my Code, as other KOS Example Projects run normally even when burned to CD-R and thrown into my DC.
Right now my Code looks like the following:
int main(int argc, char **argv) { //Quit Flag int finished = 0; srand(timer_ms_gettime64()); //Reposition Cubes & Triangles randomly on Screen updatePrimitives(); //Initialize Video Settings if(!castInitVideo()){ return CAST_ERR_INITPVR; } //Main Loop while(!finished){ //Update Controller Status castUpdateControllers(); if(castGetButtonState(CAST_CONTROLLER_SLOT_1, CAST_BUTTON_RIGHT)){ updatePrimitives(); } //Exit Program with [START] Button if(castGetButtonState(CAST_CONTROLLER_SLOT_1, CAST_BUTTON_START)){ ++finished; } //Draw Scene draw(); } //Give the PVR his deserved Break pvr_shutdown(); return CAST_ERR_NONE; }The Segments that are interesting for you are obviously the castInitVideo(void) and draw(void) Functions.
Here they are. I'm initializing the PVR as follows:
[Inside the Header File]
/****************************************************************************************************************/ #define CAST_VBUFSZ_TOTAL (1024 * 1024) //1MB of Geometry VRAM #define CAST_VBUFSZ_OPPOLY (1024 * 1024) #define CAST_VBUFSZ_OPMOD (256 * 1024) #define CAST_VBUFSZ_TRPOLY (512 * 1024) #define CAST_VBUFSZ_TRMOD (256 * 1024) #define CAST_VBUFSZ_PTPOLY (512 * 1024) /****************************************************************************************************************/[Inside the Source File]
/****************************************************************************************************************/ static uint8 CAST_VBUF_OPPOLY[CAST_VBUFSZ_OPPOLY] __attribute__((aligned(32))); //Opaque Polygon Buffer static uint8 CAST_VBUF_OPMOD [CAST_VBUFSZ_OPMOD] __attribute__((aligned(32))); //Opaque Modifier Buffer static uint8 CAST_VBUF_TRPOLY[CAST_VBUFSZ_TRPOLY] __attribute__((aligned(32))); //Transparent Polygon Buffer static uint8 CAST_VBUF_TRMOD [CAST_VBUFSZ_TRMOD] __attribute__((aligned(32))); //Transparent Modifier Buffer static uint8 CAST_VBUF_PTPOLY[CAST_VBUFSZ_PTPOLY] __attribute__((aligned(32))); //Punch-Thru Polygon Buffer /****************************************************************************************************************/ /****************************************************************************************************************/ int castInitVideo(void){ //Init PowerVR Rendering Features pvr_init_params_t pvrParams; pvrParams.dma_enabled = 1; pvrParams.fsaa_enabled = 0; pvrParams.vertex_buf_size = CAST_VBUFSZ_TOTAL; pvrParams.opb_sizes[PVR_LIST_OP_POLY] = PVR_BINSIZE_32; pvrParams.opb_sizes[PVR_LIST_OP_MOD] = PVR_BINSIZE_8; pvrParams.opb_sizes[PVR_LIST_TR_POLY] = PVR_BINSIZE_16; pvrParams.opb_sizes[PVR_LIST_TR_MOD] = PVR_BINSIZE_8; pvrParams.opb_sizes[PVR_LIST_PT_POLY] = PVR_BINSIZE_16; //Abort on Failure if( pvr_init(&pvrParams) < 0 ){ printf("Error Initializing PVR!\n"); return CAST_ERR_INITPVR; }else{ printf("Initialized PVR successfully!\n"); } //Link Vertex Buffers pvr_set_vertbuf(PVR_LIST_OP_POLY, CAST_VBUF_OPPOLY, CAST_VBUFSZ_OPPOLY); printf("Set Vertex Buffer for Opaque Polygons to %ukB\n", CAST_VBUFSZ_OPPOLY / 1024); pvr_set_vertbuf(PVR_LIST_OP_MOD , CAST_VBUF_OPMOD, CAST_VBUFSZ_OPMOD ); printf("Set Vertex Buffer for Opaque Polygon Modifiers to %ukB\n", CAST_VBUFSZ_OPMOD / 1024); pvr_set_vertbuf(PVR_LIST_TR_POLY, CAST_VBUF_TRPOLY, CAST_VBUFSZ_TRPOLY); printf("Set Vertex Buffer for Transparent Polygons to %ukB\n", CAST_VBUFSZ_TRPOLY / 1024); pvr_set_vertbuf(PVR_LIST_TR_MOD , CAST_VBUF_TRMOD, CAST_VBUFSZ_TRMOD ); printf("Set Vertex Buffer for Transparent Polygon Modifiers to %ukB\n", CAST_VBUFSZ_TRMOD / 1024); pvr_set_vertbuf(PVR_LIST_PT_POLY, CAST_VBUF_PTPOLY, CAST_VBUFSZ_PTPOLY); printf("Set Vertex Buffer for Punch-Thru Polygons to %ukB\n", CAST_VBUFSZ_PTPOLY / 1024); pvr_set_pal_format(PVR_PAL_ARGB8888); pvr_set_bg_color(0, 0, 0); //Success return 1; } /****************************************************************************************************************/This seems to run fine, as It doesn't throw any Errors, neither on nullDC nor on the Dreamcast.
So the next possible Source of Problems is the actual Rendering Code, this basically uses the technique demonstrated by Falco in his DMA / Store Queue Tutorial.
Inside the draw Function i'm basically doing this:
Prepare the next Frame:
void castBeginScene(void){ vid_border_color(0xff, 0, 0); pvr_wait_ready(); vid_border_color(0, 0xff, 0); pvr_scene_begin(); }Prepare Geometry Transfer: (in my Case called with PVR_LIST_TR_POLY)
/****************************************************************************************************************/ static uint32 CAST_CURRENT_LIST = 0; //Current Vertex Buffer Type to write to static uint32 *CAST_SUBMIT_START_PTR = NULL; //Address of the Begin of the current Vertex Data Batch static uint32 *CAST_SUBMIT_CURRENT_PTR = NULL; //Address of Vertex Data currently pointed to /****************************************************************************************************************/ void castStartSubmit(uint32 pvrListType){ CAST_CURRENT_LIST = pvrListType; //Retrieve current Position in selected Vertex Buffer uint32 *ptr = (uint32*)pvr_vertbuf_tail(CAST_CURRENT_LIST); QACR0 = ((((uint32)ptr) >> 26) << 2) & 0x1c; QACR1 = ((((uint32)ptr) >> 26) << 2) & 0x1c; //Update Start & current Pointer CAST_SUBMIT_START_PTR = CAST_SUBMIT_CURRENT_PTR = (uint32 *) (0xe0000000 | (((uint32)ptr) & 0x03ffffe0)); }What happens next is the actual Geometry, e.g. a Cube that get's sent this way:
void castDrawQuad(const Cast_Quad *quad, uint32 color){ Cast_PolyHeader header; Cast_PolyContext context; castCreatePolyContextColored(&context, PVR_LIST_TR_POLY); castCompilePolyHeader(&header, &context); castSendPolyHeader(&header); //Begin Transparent Vertex List Cast_Vertex vertex; castVertexColor(&vertex, color); castVertexDepth(&vertex, 0); castVertexUV(&vertex, 0, 0); //Lower Left Corner castVertexPos( &vertex, quad->pos.x, quad->pos.y + quad->h); castSendVertex(&vertex, PVR_CMD_VERTEX); //Upper Left Corner castVertexPos( &vertex, quad->pos.x, quad->pos.y); castSendVertex(&vertex, PVR_CMD_VERTEX); //Lower Right Corner castVertexPos( &vertex, quad->pos.x + quad->w, quad->pos.y + quad->h); castSendVertex(&vertex, PVR_CMD_VERTEX); //Upper Right Corner castVertexPos( &vertex, quad->pos.x + quad->w, quad->pos.y); castSendVertex(&vertex, PVR_CMD_VERTEX_EOL); }Where most of the Functions and Types you see pretty much directly wrap PVR Functions, only to make them more readable. What should be more interesting for you though, as I think, are the castSendVertex- & PolyHeader Methods.
/****************************************************************************************************************/ #define CAST_PREFETCH( PTR ) __asm__ __volatile__( "pref @%0" : : "r" (PTR) ) /****************************************************************************************************************/ /****************************************************************************************************************/ void castSendPolyHeader(const Cast_PolyHeader *header){ register uint32 *ptr = (uint32*)( CAST_SUBMIT_CURRENT_PTR + 8 ); *--ptr = header->d4; //Written 04 Bytes *--ptr = header->d3; //Written 08 Bytes *--ptr = header->d2; //Written 12 Bytes *--ptr = header->d1; //Written 16 Bytes *--ptr = header->mode3; //Written 20 Bytes *--ptr = header->mode2; //Written 24 Bytes *--ptr = header->mode1; //Written 28 Bytes *--ptr = header->cmd; //Written 32 Bytes CAST_PREFETCH((void *)ptr); //Prefetch CAST_SUBMIT_CURRENT_PTR = (uint32*)( ptr + 8 ); //Point to next Position in Vertex Buffer } /****************************************************************************************************************/ /****************************************************************************************************************/ void castSendVertex(const Cast_Vertex *vertex, uint32 flags){ register uint32 *ptr = (uint32*)( CAST_SUBMIT_CURRENT_PTR + 8 ); *--ptr = vertex->oargb; //Written 04 Bytes *--ptr = vertex->argb; //Written 08 Bytes *(float*)--ptr = vertex->v; //Written 12 Bytes *(float*)--ptr = vertex->u; //Written 16 Bytes *(float*)--ptr = vertex->z; //Written 20 Bytes *(float*)--ptr = vertex->y; //Written 24 Bytes *(float*)--ptr = vertex->x; //Written 28 Bytes *--ptr = flags; //Written 32 Bytes CAST_PREFETCH((void *)ptr); //Prefetch CAST_SUBMIT_CURRENT_PTR = (uint32*)( ptr + 8 ); //Point to next Position in Vertex Buffer } /****************************************************************************************************************/After all of that, the Frame is ended by a Call to
void castFinishSubmit(void){ uint32 writtenBytes = (uint32)CAST_SUBMIT_CURRENT_PTR - (uint32)CAST_SUBMIT_START_PTR; //Send Information about written Data Size to PVR if(writtenBytes){ pvr_vertbuf_written(CAST_CURRENT_LIST, writtenBytes); } }And finally
void castEndScene(void){ vid_border_color(0, 0, 0xff); pvr_scene_finish(); }All of this works perfectly fine on the Emulator, but as soon as I burn it and run it on the DC all I can see are the red border Lines telling me that pvr_wait_ready() never ever finishes (on the other hand the main loop obviously ...loops... ..as I receive "Live" controller input.
Because I'm somewhat new to the whole KOS / PVR Stuff I hope I'm just forgetting about something really obvious that needs to be done manually on the actual Hardware and is done automatically on the Emulator or such.
Sorry for spamming such a shitload of Code but i really wasn't able to spot the possible Problem more precisely.
Thanks in Advance,
shmup.