PVR question

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

PVR question

Post by OneThirty8 »

I've been playing with the Yeti3D engine a bit over the last few days, and I've sort of figured out how to render using the PVR instead of the framebuffer or SDL. However, I'm getting graphical glitches similar to what Vortexx had with his inital port. He said at the time that his problem was that he wasn't double-buffering, but I didn't think that was an issue when using PVR. Here's the code I've got that's giving me problems.

My main.c file:

Code: Select all

#include <stdlib.h>
#include <stdio.h>

#include <kos.h>
#include <dc/sound/sound.h>
#include <dc/sound/sfxmgr.h>
#include <oggvorbis/sndoggvorbis.h>
#include "pvrfuncts.h"

#include "../../src/game.h"
#include "patches.h"
#include "joymousekey.h"

extern pvr_ptr_t back_tex;

yeti_t yeti;
int done=0;    // Keeps track of whether or not we're still playing.


#define title (YETI_STR_TITLE "Yeti PVR Demo" YETI_STR_VERSION " - " YETI_STR_COPYRIGHT)
void keyboard_update()
{
  yeti.keyboard.up     = up_joy();
  yeti.keyboard.down   = down_joy();
  yeti.keyboard.left   = left_joy();
  yeti.keyboard.right  = right_joy();
  yeti.keyboard.a      = shoot_but();
  yeti.keyboard.b      = jump_but();
  yeti.keyboard.l      = ltrig_key();
  yeti.keyboard.r      = rtrig_key();
  yeti.keyboard.select = start_but();

}

int main(int argc, char *argv[])
{
fs_chdir("/cd");
   pvr_setup();

  snd_init();
  sndoggvorbis_init();

 
  enemyfire = snd_sfx_load("enemyfire.wav");
  if((dangerous = fopen("dangerous.ogg", "rb"))==NULL){fprintf(stdout,"the ogg file isn't there!!!111oneoneone");};

  //Initiallize Yeti3D
  lua_fix(); // fixes to render properly in RGB565
  sprite_fix(); // fixes sprites to render properly in RGB565
  yeti_init(&yeti, (framebuffer_t*)back_tex, (framebuffer_t*)back_tex, textures, palette, lua);

  game_init(&yeti);

  while(done==0) // While we're not done playing, keep looping.
  {
   game_loop(&yeti);
   draw_frame();
   keyboard_update();
   

  if(!sndoggvorbis_isplaying())
    {
     sndoggvorbis_start_fd(dangerous, 1);
    }

  }
  return 0;
}
my 'pvrfuncts.c' file, which should look remarkably similar to the png example (because aside from a few changes, that's what it is.)

Code: Select all

#include <kos.h>

/* textures */

pvr_ptr_t back_tex;

/* init background */
void back_init()
{

    back_tex = pvr_mem_malloc(512*512*2);
}



/* draw background */
void draw_back()
{

    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_RGB565|PVR_TXRFMT_NONTWIDDLED, 512, 512, back_tex, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);    
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;
    
    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = 1.0;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0;
    vert.v = 1.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = 1.0;
    vert.v = 1.0;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}


/* base y coordinate */
int y = 0;

/* draw one frame */
void draw_frame()
{
    pvr_wait_ready();
    pvr_scene_begin();

    pvr_list_begin(PVR_LIST_OP_POLY);

    draw_back();
    pvr_list_finish();

    pvr_scene_finish();
 
}

void pvr_setup()
{

    /* init kos  */
    pvr_init_defaults();
    
   
    /* init background */
    back_init();
}

...so, is it a bad idea to draw directly to the texture like I'm doing? This is the first time I've ever tried to use the PVR to do anything, so please forgive my n00bish appearance. :D Thanks in advance for any help.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

<unhelpful>I can't see anything wrong with it</unhelpful>

What you're trying to do is basically correct. It may not be the best way to do it (using the PVR to actually render everything would be best), but it should work just fine.

What kind of graphical glitches are you getting?
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Post by OneThirty8 »

It looks like it's starting to draw the next frame before it displays, so I can see through walls and stuff like that.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

I think I know why...

The PowerVR actually has three (I think - don't hold me to that) frames going on at the same time. You've got the finished frame, which is being displayed on screen. You have the being-drawn frame, which is being drawn into the backbuffer, and you've got the next frame, which you're currently sending the display list for.

When you tell the PVR to render a frame, it doesn't do it immediately. It does it while you're off preparing the next frame. However, the PVR is trying to read the previous frame from that texture, while you're overwriting it.

Basically, you're getting bits of the correct frame, and bits of the next frame.

You could try double-buffering the textures. You create two separate textures in VRAM, and change the framebuffer pointer Yeti uses. While the PVR is drawing from texture #1, you're drawing to texture #2. Send the display list, and switch to texture #1 while the PVR draws from texture #2.
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Post by OneThirty8 »

That makes sense. I'll try that. Thanks much! :D
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

This is nice example might help me convert the neogeo cd render to pvr. Sure need to get this done soon..
Dreamcast forever!!!
q_006
Mental DCEmu
Mental DCEmu
Posts: 415
Joined: Thu Oct 10, 2002 7:18 pm
Has thanked: 0
Been thanked: 0
Contact:

Post by q_006 »

i was wondering is this going to be the new standard now?
translating all 2d titles (ports) through the PVR and not the framebuffer?
i find it curious that there's been quite a buzz lately ever since Chanka came out.
but maybe i'm nuts?

anyway, good luck.
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Think you will find the buzz was there before that emulator.
Dreamcast forever!!!
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Post by OneThirty8 »

Yeah, I figure Chanka will support the framebuffer in future releases. The main consideration here for me is getting better speed out of my game, and I'm sure for Ian the same is true with regard to NeoCD.

Ian, you may also want to look at some other KOS examples. What I posted above is basically a slightly modified version of the PNG example. You might also want to look at the plasma example and a couple of others. Using the PVR will definitely give you a speed boost over SDL if what you've got can be ported easilly. Good luck with it. :)
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Post by OneThirty8 »

Alright, I couldn't get rid of the transparent wall problem when I was drawing directly to the textures in VRAM, even after making 2. Tried a few things (which were essentially the same - make 2 textures, draw to one while the other's displaying), all gave the same result. I then tried malloc-ing a spot in main memory, drawing to there, and then using pvr_txr_load(void * src, pvr_ptr_t dst, uint32 count); to load it. That didn't give me as many see-through walls and flickering sprites, but the problem was still there. So, what I did was basically do the same thing I tried before, except instead of setting up two textures in VRAM, I made two yeti viewports in main memory, drew to one of them, and loaded the other to VRAM and displayed. It's still nice and fast, too.

Here's what finally worked:
main.c

Code: Select all

#include <stdlib.h>
#include <stdio.h>

#include <kos.h>
#include <dc/sound/sound.h>
#include <dc/sound/sfxmgr.h>
#include <oggvorbis/sndoggvorbis.h>
#include "pvrfuncts.h"

#include "../../src/game.h"
#include "patches.h"
#include "joymousekey.h"


extern pvr_ptr_t front_tex;

uint16* frontbuffer[2];


yeti_t yeti;
int done=0;    // Keeps track of whether or not we're still playing.


#define title (YETI_STR_TITLE "Yeti PVR Demo" YETI_STR_VERSION " - " YETI_STR_COPYRIGHT)
void keyboard_update()
{
  yeti.keyboard.up     = up_joy();
  yeti.keyboard.down   = down_joy();
  yeti.keyboard.left   = left_joy();
  yeti.keyboard.right  = right_joy();
  yeti.keyboard.a      = shoot_but();
  yeti.keyboard.b      = jump_but();
  yeti.keyboard.l      = ltrig_key();
  yeti.keyboard.r      = rtrig_key();
  yeti.keyboard.select = start_but();

}

void initbuffers()
{
    frontbuffer[0] = (uint16 *)malloc(256*256*2);
    frontbuffer[1] = (uint16 *)malloc(256*256*2);
}

void swapbuffers()
{
  if(yeti.viewport.back==(framebuffer_t*)frontbuffer[0])
  {
      yeti.viewport.back=yeti.viewport.front=(framebuffer_t*)frontbuffer[1];
  }else{
      yeti.viewport.back=yeti.viewport.front=(framebuffer_t*)frontbuffer[0];
       }
}

int main(int argc, char *argv[])
{
fs_chdir("/cd");
   pvr_setup();

  snd_init();
  sndoggvorbis_init();
  
  initbuffers();
 
  enemyfire = snd_sfx_load("enemyfire.wav");
  if((dangerous = fopen("dangerous.ogg", "rb"))==NULL){fprintf(stdout,"the ogg file isn't there!!!111oneoneone");};

  //Initiallize Yeti3D
  lua_fix(); // fixes to render properly in RGB565
  sprite_fix(); // fixes sprites to render properly in RGB565
  yeti_init(&yeti, (framebuffer_t*)frontbuffer[0], (framebuffer_t*)frontbuffer[0], textures, palette, lua);

  game_init(&yeti);

  while(done==0) // While we're not done playing, keep looping.
  {
   game_loop(&yeti);
   draw_frame();
   keyboard_update();
   swapbuffers();

  if(!sndoggvorbis_isplaying())
    {
     sndoggvorbis_start_fd(dangerous, 1);
    }
  }
  return 0;
}
and pvrfuncts.c

Code: Select all

#include <kos.h>
#include "../../src/game.h"
/* textures */

pvr_ptr_t back_tex;
pvr_ptr_t front_tex;
//extern uint16* currentbuffer;
extern yeti_t yeti;

/* init background */
void back_init()
{
    back_tex = pvr_mem_malloc(256*256*2);
    front_tex = pvr_mem_malloc(256*256*2);

}



/* draw background */
void draw_back()
{
    //pvr_txr_load_dma(yeti.viewport.back, front_tex, 256*256*2, 1);
    pvr_txr_load    (yeti.viewport.back, front_tex, 256*256*2);    
    
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    
    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_RGB565|PVR_TXRFMT_NONTWIDDLED, 256, 256, front_tex, PVR_FILTER_BILINEAR);
                      
    pvr_poly_compile(&hdr, &cxt);
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);    
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;
    
    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = 1.0;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0;
    vert.v = 1.0;
    pvr_prim(&vert, sizeof(vert));
    
    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = 1.0;
    vert.v = 1.0;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}


/* base y coordinate */
//int y = 0;

/* draw one frame */
void draw_frame()
{
    pvr_wait_ready();
    pvr_scene_begin();

    pvr_list_begin(PVR_LIST_OP_POLY);

    draw_back();
    pvr_list_finish();

    pvr_scene_finish();
     
}

void pvr_setup()
{

    /* init kos  */
    pvr_init_defaults();
    pvr_dma_init();
   
    /* init background */
    back_init();
}
Thanks again BlackAura! What you said basically worked, I just had to allocate memory in a different place.
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Fantastic 138 congrats on doing that. So speed really was a lot better then SDL? intresting need all the speed i can get. Do you mind if i attempt to use your example on neogeo cd?
Dreamcast forever!!!
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Post by OneThirty8 »

Thanks. Speed was much better than SDL, although I'm currently only using a 256x256 texture and stretching it to 640x480. The PVR stuff I used was directly lifted from the KOS PNG example. I just modified a couple bits to make it work the way I needed it to, and removed most of the stuff I didn't need. It should probably work for NeoCD, so if it'll help you gain a speed boost then go for it. :D
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

It done know thanks to speud he got it to work only a slight problem like you were having with back grounds or other parts showing throu.

Great to see Neogeo CD with bi filter looks nice.
Dreamcast forever!!!
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

How's the speed?
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

With PVR_FILTER_TRILINEAR1 filter and DMA on about 5 fps faster guessing looking at it due to the smooth ness and less slow down. DMA| brings garbage over the txt and some sprites so cant really use it yet.

With out it i say it's 1 to 4 frames faster like you said. But the main aim is easy change the postion filters and res and one day not link SDL libs with it that will save code size and may have a speed up effect.

It looks so much nicer then SDL which is good. We have a background problem only on some games metal slug being one

here's the screen shot

http://www.geocities.com/gabbiangel2004/Pict0002.html

Error when i enable DMA at the console it says
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned

But really happy with the work speud did on it. The extra frames means a lot since i can turn frameskip down and gain smooth-ness.

One other side effect is it loads games faster now. Does not have to load the bitmap loading screen while loading off the cd it's much faster now the loading times.
Last edited by Ian Micheal on Fri Jun 11, 2004 8:54 am, edited 1 time in total.
Dreamcast forever!!!
doragasu
DCEmu Cool Poster
DCEmu Cool Poster
Posts: 1048
Joined: Thu May 16, 2002 5:01 pm
Location: Madrid, Spain
Has thanked: 0
Been thanked: 0

Post by doragasu »

Ian Micheal wrote:Error when i enable DMA at the console it says
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned
pvr_dma: Src is not 32-byte aligned
I don't know how to do it with GCC, but for sure there must be a directive or macro to align variables in memory. If you are using dynamically allocated memory you have also to align it for DMA to work properly.

Sure some of you guys know how to do it and can be a lot more helpful :wink:
Phantom
DC Developer
DC Developer
Posts: 1753
Joined: Thu Jan 16, 2003 4:01 am
Location: The Netherlands
Has thanked: 0
Been thanked: 0
Contact:

Post by Phantom »

For dynamically allocated memory you can use the memalign function.
"Nothing works" - Catweazle
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Assuming it's dynamically allocated (it looks like it), replace the malloc function with a memalign function:

Code: Select all

stuff = memalign(32, size_of_thing_you_want_to_allocate);
If you're still getting garbage all over the screen, you might have to flush the data cache over the buffer.
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Hmm I changed it to this

Code: Select all

   vidram_tex = pvr_mem_malloc(512*512*2); 
   vidram_buf = (unsigned short *)memalign(32,512*512);
I think that is right. The error went away but there was still Garbage on the txt and some sprites.

I guess ill search the forum for the fix for the DMA cache i remember some one posted the fix.

Garbage is all over the screen not at the bottom like genesis plus was so I dont think copying that is going to work i think you say how to fix it in this thread

http://www.dcemulation.org/phpBB/viewto ... ht=pvr+dma


Black aura says.
If the garbage is all over the screen, you have to use a different approach.

I don't know how Snes9x generates it's image, but this approach relies on the rendering code never needing to read back the image that you're writing to the buffer. What you do is move the buffer pointer into uncached memory.

Look at this memory map, and you'll see that you need to flip bit #30 (0x20000000) to disable the cache. So, instead of giving Snes9x's rendering code the pointer to the buffer you get from KOS, give it (pointer | 0x20000000). That way, any writes to that buffer will bypass the cache, and you won't have the image corruption problem at all. If Snes9x doesn't read the buffer, it should be faster. If it does read the buffer, it'll be a lot slower, and you should stick to store queues.
Not quiet sure how to do this on the video.c i have.

Only thing ive come up with is using this

Code: Select all

 dcache_flush_range(vidram_buf, 512*512*2); 
   pvr_txr_load_dma(vidram_buf, vidram_tex, 512*512*2,1); // dma
like that going to try it now
Dreamcast forever!!!
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Ok that fixed it reading, what you wrote, in the other topics i searched thanks Black aura Some one should take all the info you write and make it a dev book for dreamcast. I buy it! :D

I think the some one should be you. Really i buy a book that you write on programing and the dreamcast.
Dreamcast forever!!!
Post Reply