void VDC_RunFrame()

in cores/pce/mednafen/pce_fast/vdc.cpp [730:1034]


void VDC_RunFrame(EmulateSpecStruct *espec, bool IsHES)
{
   int max_dc = 0;
   MDFN_Surface *surface = espec->surface;
   MDFN_Rect *DisplayRect = &espec->DisplayRect;
   int32 *LineWidths = espec->LineWidths;
   bool skip = espec->skip || IsHES;

   if(!skip){
      DisplayRect->y = MDFN_GetSettingUI("pce_fast.slstart");
      DisplayRect->h = MDFN_GetSettingUI("pce_fast.slend") - DisplayRect->y + 1;
   }
	
	//Change 352 mode width without restart
   if (defined_width[1] != MDFN_GetSettingUI("pce_fast.hoverscan"))
      defined_width[1] = MDFN_GetSettingUI("pce_fast.hoverscan");
	
   do
   {
      const bool SHOULD_DRAW = (!skip && (int)frame_counter >= (DisplayRect->y + 14) && (int)frame_counter < (DisplayRect->y + DisplayRect->h + 14));

      if(frame_counter == 0)
      {
         VDS = M_vdc_VDS;
         VSW = M_vdc_VSW;
         VDW = M_vdc_VDW;
         VCR = M_vdc_VCR;
         VBlankFL = VDS + VSW + VDW + 1;

         if(VBlankFL > 261)
            VBlankFL = 261;
      }

      need_vbi[0] = need_vbi[1] = 0;

#if 1
      line_leadin1 = 0;

      magical = M_vdc_HDS + (M_vdc_HDW + 1) + M_vdc_HDE;
      magical = (magical + 2) & ~1;
      magical -= M_vdc_HDW + 1;
      cyc_tot = magical * 8; //ClockPixelWidths[vce.dot_clock] - magical * 8;
      cyc_tot-=2;
      switch(vce.dot_clock)
      {
         case 0: cyc_tot = 4 * cyc_tot / 3; break;
         case 1: break;
         case 2: cyc_tot = 2 * cyc_tot / 3; break;
      }

      if(cyc_tot < 0) cyc_tot = 0;
      line_leadin1 = cyc_tot;
#endif

#if 0
      {
         int vdc_to_master = 4;

         line_leadin1 = 1365 - ((M_vdc_HDW + 1) * 8 - 4 + 6) * vdc_to_master;

         if(line_leadin1 < 0)
         {
            line_leadin1 = 0;
            puts("Eep");
         }

         if(M_vdc_HDS > 2)
            line_leadin1 += 2;

         line_leadin1 = line_leadin1 / 3;
      }

      if(line_leadin1 < 0)
         line_leadin1 = 0;
      else if(line_leadin1 > 400)
         line_leadin1 = 400;
#endif

      //printf("%d\n", line_leadin1);
      if(max_dc < vce.dot_clock)
         max_dc = vce.dot_clock;

      if(!skip)
      {
         DisplayRect->x = 0;
         DisplayRect->w = defined_width[vce.dot_clock];
      }

      int chip = 0;
      {
         if(frame_counter == 0)
         {
            vdc->display_counter = 0;
            vdc->burst_mode = !(vdc->CR & 0xC0);
         }

         if(vdc->display_counter == (VDS + VSW))
         {
            vdc->burst_mode = !(vdc->CR & 0xC0);
            vdc->RCRCount = 0;
         }
         int have_free_time = 1;

         if(!vdc->burst_mode && vdc->display_counter >= (VDS + VSW) && vdc->display_counter < (VDS + VSW + VDW + 1))
            have_free_time = 0;

         if(have_free_time) // We're outside of the active display area.  Weehee
         {
            if(vdc->DMARunning)
               DoDMA(vdc);
         }

         if(vdc->display_counter == VBlankFL)
         {
            need_vbi[0] = 1;
            if(vdc->SATBPending || (vdc->DCR & 0x10))
            {
               vdc->SATBPending = 0;
               vdc->sat_dma_slcounter = 2;

               DoSATDMA(vdc);
            }
         }
         if((int)vdc->RCRCount == ((int)vdc->RCR - 0x40) && (vdc->CR & 0x04))
         {
            VDC_DEBUG("RCR IRQ");
            vdc->status |= VDCS_RR;
            HuC6280_IRQBegin(MDFN_IQIRQ1); 
         }
      }

      HuC6280_Run(line_leadin1);

      const bool fc_vrm = (frame_counter >= 14 && frame_counter < (14 + 242 + 1));

      chip = 0;
      {
         MDFN_ALIGN(8) uint8 bg_linebuf[8 + 1024];
         MDFN_ALIGN(8) uint16 spr_linebuf[16 + 1024];

         uint16 *target_ptr16 = surface->pixels + (frame_counter - 14) * surface->pitch;

         if(fc_vrm && !skip)
            LineWidths[frame_counter - 14] = DisplayRect->w;

         if(vdc->burst_mode)
         {
            if(fc_vrm && SHOULD_DRAW)
            {
               DrawOverscan(vdc, target_ptr16, DisplayRect);
            }
         }
         else if(vdc->display_counter >= (VDS + VSW) && vdc->display_counter < (VDS + VSW + VDW + 1))
         {
            if(vdc->display_counter == (VDS + VSW))
               vdc->BG_YOffset = vdc->BYR;
            else
               vdc->BG_YOffset++;
            vdc->BG_XOffset = vdc->BXR;

            if(fc_vrm)
            {
               uint32 start = (M_vdc_HDS + 1) * 8;
               uint32 end = start + (M_vdc_HDW + 1) * 8;

               if((vdc->CR & 0x80) && SHOULD_DRAW)
               {
                  if(userle & (ULE_BG0))
                     DrawBG(vdc, end - start + (vdc->BG_XOffset & 7), bg_linebuf);
                  else
                     memset(bg_linebuf, 0, end - start + (vdc->BG_XOffset & 7));
               }

               if((vdc->CR & 0x40) && (SHOULD_DRAW || (vdc->CR & 0x03)))	// Don't skip sprite drawing if we can generate sprite #0 or sprite overflow IRQs.
               {
                  if((userle & (ULE_SPR0)) || (vdc->CR & 0x03))
                     DrawSprites(vdc, end - start, spr_linebuf + 0x20);

                  if(!(userle & (ULE_SPR0)))
                     memset(spr_linebuf + 0x20, 0, sizeof(uint16) * (end - start));
               }

               if(SHOULD_DRAW){
                  int32 width = end - start;
                  int32 source_offset = 0;
                  int32 target_offset = 0;
                  
                  //Centre any picture thinner than its display mode width
                  if(width > 0 && width < defined_width[vce.dot_clock]){
                     target_offset = (defined_width[vce.dot_clock] - width)/2;
                  }
				  
                  //Centre overscan cropping
                  if(vce.dot_clock == 1 && defined_width[1] < width){
                     target_offset += (defined_width[1] - width) / 2;
                  }
				  
                  // Align TV Sport Basketball
                  if(vce.dot_clock ==2 && width > 512){
                     target_offset = - 16;
                  }
		       
                  // Semi-hack for Asuka 120%
                  if(vce.dot_clock == 1 && M_vdc_HDS == 5 && M_vdc_HDE == 6 && M_vdc_HDW == 43 && M_vdc_HSW == 2)
                     target_offset += 8;
                  else if(vce.dot_clock == 0 && M_vdc_HDS == 2 && M_vdc_HDE == 3 && M_vdc_HDW == 33 && M_vdc_HSW == 2)
                     target_offset = 0;
                  // and for Addams Family
                  else if(vce.dot_clock == 1 && M_vdc_HDS == 4 && M_vdc_HDE == 4 && M_vdc_HDW == 43 && M_vdc_HSW == 9)
                     target_offset += 4;
		       
                  if(target_offset < 0)
                  {
                     width += target_offset;
                     source_offset += 0 - target_offset;
                     target_offset = 0;
                  }

                  if((target_offset + width) > DisplayRect->w)
                     width = (int32)DisplayRect->w - target_offset;

                  if(width > 0)
                  {
                     //else if(target_ptr16)
                     {
                        switch(vdc->CR & 0xC0)
                        {
                           case 0xC0:
                              MixBGSPR(width, bg_linebuf + (vdc->BG_XOffset & 7) + source_offset, spr_linebuf + 0x20 + source_offset, target_ptr16 + target_offset);
                              break;
                           case 0x80:
                              MixBGOnly(width, bg_linebuf + (vdc->BG_XOffset & 7) + source_offset, target_ptr16 + target_offset);
                              break;
                           case 0x40:
                              MixSPROnly(width, spr_linebuf + 0x20 + source_offset, target_ptr16 + target_offset);
                              break;
                           case 0x00:
                              MixNone(width, target_ptr16 + target_offset);
                              break;
                        }
                     }
                  }

                  //else if(target_ptr16)
                  DrawOverscan(vdc, target_ptr16, DisplayRect, false, target_offset, target_offset + width);
               } // end if(SHOULD_DRAW)
            }
         }
         else if(SHOULD_DRAW && fc_vrm) // Hmm, overscan...
         {
            //else if(target_ptr16)
            DrawOverscan(vdc, target_ptr16, DisplayRect);
         }
      }

      if((vdc->CR & 0x08) && need_vbi[0])
         vdc->status |= VDCS_VD;

      HuC6280_Run(2);

      if(vdc->status & VDCS_VD)
      {
         VDC_DEBUG("VBlank IRQ");
         HuC6280_IRQBegin(MDFN_IQIRQ1);   
      }

      HuC6280_Run(455 - line_leadin1 - 2);

      if(PCE_IsCD)
      {
         PCECD_Run(HuCPU.timestamp * 3);
      }

      {
         vdc->RCRCount++;

         //vdc->BG_YOffset = (vdc->BG_YOffset + 1);
         vdc->display_counter++;

         if(vdc->sat_dma_slcounter)
         {
            vdc->sat_dma_slcounter--;
            if(!vdc->sat_dma_slcounter)
            {
               if(vdc->DCR & 0x01)
               {
                  VDC_DEBUG("Sprite DMA IRQ");
                  vdc->status |= VDCS_DS;
                  HuC6280_IRQBegin(MDFN_IQIRQ1);
               }
            }
         }

         if(vdc->display_counter == (VDS + VSW + VDW + VCR + 3))
         {
            vdc->display_counter = 0;
         }
      }

      frame_counter = (frame_counter + 1) % (vce.lc263 ? 263 : 262);
      //printf("%d\n", vce.lc263);
   } while(frame_counter != VBlankFL); // big frame loop!

	DisplayRect->w = defined_width[vce.dot_clock];
}