Frame timing 2

Technical discussion for those interested in Supermodel development and Model 3 reverse engineering. Prospective contributors welcome.
Forum rules
Keep it classy!

  • No ROM requests or links.
  • Do not ask to be a play tester.
  • Do not ask about release dates.
  • No drama!

Frame timing 2

Postby Ian » Sun Sep 25, 2016 1:49 pm

This is how frames are drawn

Code: Select all
signed int PRO_DisplayDatabase()
{
  signed int v0; // esi@1
  signed int v1; // edi@1
  int v2; // ebx@1
  int v3; // ecx@1
  int v4; // eax@3
  int v5; // eax@5
  PRO_Viewport *v6; // ecx@7
  PRO_Dynamic_Update *v7; // ecx@9
  int v8; // eax@12
  int v9; // edi@14
  int v10; // ebx@14
  __int32 v11; // ST00_4@15
  PRO_Vertex *v12; // eax@15

  v0 = 1;
  v1 = 1;
  v2 = *(_DWORD *)(*((_DWORD *)g_API_Data + 3) + 2316);
  v3 = *((_DWORD *)g_API_Data + 4859);
  if ( v3 )
  {
    v1 = *(_DWORD *)(v3 + 8);
    PRO_Dynamic_Update::DoUpdate((PRO_Dynamic_Update *)v3);
  }
  v4 = PRO_API_Data::FormatUserTextures(g_API_Data);
  if ( v4 != 1 )
    v0 = v4;
  v5 = PRO_API_Data::FormatUserMicroTextures(g_API_Data);
  if ( v5 != 1 )
    v0 = v5;
  PRO_SetScroll(0);
  PRO_ProcessAnimations();
  v6 = (PRO_Viewport *)*((_DWORD *)g_API_Data + 47);
  if ( v6 )
    PRO_Viewport::UpdateSiblingPointers(v6);
  PRO_Directional_Light_List::ProcessDirectionalLightList(*((PRO_Directional_Light_List **)g_API_Data + 323));
  PRO_Range_Node_List::ProcessRangeLodNodeList(*((PRO_Range_Node_List **)g_API_Data + 324));
  PRO_Memory_Manager::WriteDataToHardware(*((_DWORD *)g_API_Data + 2));
  PRO_Memory_Manager::WriteDataToHardware(*((_DWORD *)g_API_Data + 1));
  PRO_PingPong_Manager::WriteAllDataToHardware(*(_DWORD *)g_API_Data);
  v7 = (PRO_Dynamic_Update *)*((_DWORD *)g_API_Data + 4859);
  if ( v7 )
    PRO_Dynamic_Update::DoIO(v7);
  PRO_Flush();
  if ( *(_DWORD *)(*((_DWORD *)g_API_Data + 3) + 2316) - v2 > 1 )
  {
    v0 = 4;
    v8 = *((_DWORD *)g_API_Data + 4859);
    if ( v8 )
      ++*(_DWORD *)(v8 + 4 * v1 + 1048);
  }
  v9 = 0;
  v10 = *(_DWORD *)(*((_DWORD *)g_API_Data + 61) + 4);
  if ( v10 > 0 )
  {
    do
    {
      v11 = v9++;
      v12 = (PRO_Vertex *)PRO_Generic_List::GetEntryByIndex(*((PRO_Generic_List **)g_API_Data + 61), v11);
      PRO_Vertex::ResetChangeAttributes(v12);
    }
    while ( v10 > v9 );
  }
  *(_DWORD *)(*((_DWORD *)g_API_Data + 61) + 4) = 0;
  ++*((_DWORD *)g_API_Data + 329);
  ++*((_DWORD *)g_API_Data + 330);
  return v0;
}


The important lines are the memory order things get written

PRO_Memory_Manager::WriteDataToHardware(*((_DWORD *)g_API_Data + 2)); <--- Polygon ram update
PRO_Memory_Manager::WriteDataToHardware(*((_DWORD *)g_API_Data + 1)); <--- marked as '_static_MM'
PRO_PingPong_Manager::WriteAllDataToHardware(*(_DWORD *)g_API_Data); <--- Culling memory

So it should read as such ..

Polygon ram update
Culling memory update
SDL_SwapBuffers()

A lot of the games are coming out like this

WriteHighCullingRAM
flush 0x88000000 <- Swap buffers should happen here
WritePolygonRAM
SDL_SwapBuffers()

The culling memory updates are happening a frame late. I think this explains a lot of the mysterious bugs in daytona, magical truck, ocean hunter, and other games where things are visibly broken.

A lot of games are doing this as well

flush 88000000 < -- one swap buffer should happen
SDL_SwapBuffers() < -- same frame drawn twice
SDL_SwapBuffers()
WriteHighCullingRAM
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Re: Frame timing 2

Postby Ian » Sun Oct 16, 2016 8:55 am

Well
Daytona battle on the edge has many of these bad frames

Image

Anyway I changed the rendering a bit to that it only draws a complete frame after the 0x88 'flush' command
Anyway, those bad frames don't show up. So that eliminates a lot of potential sources of bugs I think
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Re: Frame timing 2

Postby Bart » Sun Oct 16, 2016 7:21 pm

Nice! Do you trigger rendering right when that command is written or do you simply check each frame that it has actually been written at all?
User avatar
Bart
Site Admin
 
Posts: 1841
Joined: Thu Sep 01, 2011 2:13 pm
Location: New York City

Re: Frame timing 2

Postby ferrarifan » Sun Oct 16, 2016 11:57 pm

Does the frame timing has to do something with fixing slow down on most games or the actual Model 3 Frame rate? I was just making sure.
User avatar
ferrarifan
 
Posts: 121
Joined: Sun Mar 29, 2015 7:38 pm

Re: Frame timing 2

Postby Ian » Mon Oct 17, 2016 12:42 am

I just drew a frame on that command to see if it would fix that error. It worked for Daytona but didn't fix magical truck attract mode.

It probably fixed the scudp video too but I haven't explicitly checked.

I think the command ox88 just says it's safe to render. If you draw on every x88 timing in some games is very broken like bass fishing. If you try it in name it works at like 10fps for that game.
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Re: Frame timing 2

Postby Ian » Mon Oct 17, 2016 3:19 am

Well,
I tried scudp only rendering after 0x88
and it looked like this

Image

Basically fixed.

Interestingly rendering after 0x88 the tilegen hasn't finished syncing the data. In the menus the transition effects basically look corrupted. Probably the same error we see in harley with the garbage in the transition scenes.
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Re: Frame timing 2

Postby Bart » Tue Oct 18, 2016 6:56 am

Ian wrote:Well,
I tried scudp only rendering after 0x88
and it looked like this

Image

Basically fixed.

Interestingly rendering after 0x88 the tilegen hasn't finished syncing the data. In the menus the transition effects basically look corrupted. Probably the same error we see in harley with the garbage in the transition scenes.


The tilegen outputs a video signal continuously during the monitor's active scan period. The CPU has to wait for a VBlank interrupt before it can safely draw to it. On Model 3, there are at least a couple of IRQs that appear tied to VBlank but only one of them is from the tilegen (not clear exactly which). The others may be driven by the Real3D. There's definitely something going on here with IRQ/frame timing...

I'm still a bit confused here. I thought there were cases where 0x88000000 was written multiple times per frame. What do you do in such cases? I can think of a number of possibilities of what the hardware might be doing:

- Initiate rendering/texture transfer, ignoring subsequent writes to 0x88000000 until the currently-processing frame is complete, then flip buffers.
- Initiate rendering during next active scan period, then swap after VBlank.
- Initiate texture transfer *or* render frame but not both.

There is almost certainly an IRQ fired after the operation is done but most of the relevant IRQ vectors don't do anything particularly interesting. I need to continue disassembling the ScudP code at some point because there may be some clues there. I recall that at least one of the unknown IRQ handlers was incrementing some sort of counter.

Note also that if you look at Real3D.cpp's handling of status registers, you will see that there is in fact a single bit in one of the Real3D registers that seems to be related to a busy signal.
User avatar
Bart
Site Admin
 
Posts: 1841
Joined: Thu Sep 01, 2011 2:13 pm
Location: New York City

Re: Frame timing 2

Postby Ian » Tue Oct 18, 2016 8:00 am

I think the 0x88 means it's safe to render at this point. Or it's safe to process this chunk of data, ie texture updates etc

But I don't think frame drawing or timing is directly related to the 0x88, as if you try games like bass fishing, it calls it multiple times per frame as you pointed out. Also daytona with its double 0x88.

I have a feeling the status bit might mean that's its done processing after a 0x88 command
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Re: Frame timing 2

Postby Bart » Tue Oct 18, 2016 8:19 am

The rendering could be synced to frame timing.
User avatar
Bart
Site Admin
 
Posts: 1841
Joined: Thu Sep 01, 2011 2:13 pm
Location: New York City

Re: Frame timing 2

Postby Ian » Tue Oct 18, 2016 2:01 pm

I would have thought frame timing would be done entirely on the cpu. The graphics card just draws whatever you give it. In opengl swapbuffers will only return once after the frame has been displayed.

On the real3d the database can be written to and updated as soon as the frame has been drawn into the frame buffer. This could happen well before the actual buffer swap to display the frame.
Ian
 
Posts: 883
Joined: Tue Feb 23, 2016 9:23 am

Next

Return to The Dark Room

Who is online

Users browsing this forum: No registered users and 3 guests