void updatescreen(void) { /* update sound */ sound_frame_update(); /* if we're not skipping this frame, draw the screen */ if (!osd_skip_this_frame()) { profiler_mark(PROFILER_VIDEO); draw_screen(); profiler_mark(PROFILER_END); } /* the user interface must be called between vh_update() and osd_update_video_and_audio(), */ /* to allow it to overlay things on the game display. We must call it even */ /* if the frame is skipped, to keep a consistent timing. */ ui_update_and_render(artwork_get_ui_bitmap()); /* update our movie recording state */ if (!mame_is_paused()) record_movie_frame(scrbitmap[0]); /* blit to the screen */ update_video_and_audio(); /* call the end-of-frame callback */ if (Machine->drv->video_eof && !mame_is_paused()) { profiler_mark(PROFILER_VIDEO); (*Machine->drv->video_eof)(); profiler_mark(PROFILER_END); } }
void video_manager::frame_update(bool debug) { // only render sound and video if we're in the running phase int phase = machine().phase(); bool skipped_it = m_skipping_this_frame; if (phase == MACHINE_PHASE_RUNNING && (!machine().paused() || machine().options().update_in_pause())) { bool anything_changed = finish_screen_updates(); // if none of the screens changed and we haven't skipped too many frames in a row, // mark this frame as skipped to prevent throttling; this helps for games that // don't update their screen at the monitor refresh rate if (!anything_changed && !m_auto_frameskip && m_frameskip_level == 0 && m_empty_skip_count++ < 3) skipped_it = true; else m_empty_skip_count = 0; } // draw the user interface ui_update_and_render(machine(), &machine().render().ui_container()); // update the internal render debugger debugint_update_during_game(machine()); // if we're throttling, synchronize before rendering attotime current_time = machine().time(); if (!debug && !skipped_it && effective_throttle()) update_throttle(current_time); // ask the OSD to update g_profiler.start(PROFILER_BLIT); machine().osd().update(!debug && skipped_it); g_profiler.stop(); // perform tasks for this frame if (!debug) machine().call_notifiers(MACHINE_NOTIFY_FRAME); // update frameskipping if (!debug) update_frameskip(); // update speed computations if (!debug && !skipped_it) recompute_speed(current_time); // call the end-of-frame callback if (phase == MACHINE_PHASE_RUNNING) { // reset partial updates if we're paused or if the debugger is active if (machine().primary_screen != NULL && (machine().paused() || debug || debugger_within_instruction_hook(machine()))) machine().primary_screen->reset_partial_updates(); } }
void video_frame_update(void) { int skipped_it = video_skip_this_frame(); int paused = mame_is_paused(Machine); int phase = mame_get_phase(Machine); int livemask; int scrnum; /* only render sound and video if we're in the running phase */ if (phase == MAME_PHASE_RUNNING) { /* update sound */ sound_frame_update(); /* finish updating the screens */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) if (Machine->drv->screen[scrnum].tag != NULL) video_screen_update_partial(scrnum, Machine->screen[scrnum].visarea.max_y); /* now add the quads for all the screens */ livemask = render_get_live_screens_mask(); for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) { if (livemask & (1 << scrnum)) { internal_screen_info *screen = &scrinfo[scrnum]; /* only update if empty and not a vector game; otherwise assume the driver did it directly */ if (render_container_is_empty(render_container_get_screen(scrnum)) && !(Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)) { mame_bitmap *bitmap = screen->bitmap[screen->curbitmap]; if (!skipping_this_frame && screen->changed) { rectangle fixedvis = Machine->screen[scrnum].visarea; fixedvis.max_x++; fixedvis.max_y++; render_texture_set_bitmap(screen->texture, bitmap, &fixedvis, Machine->drv->screen[scrnum].palette_base, screen->format); screen->curbitmap = 1 - screen->curbitmap; } render_screen_add_quad(scrnum, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), screen->texture, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1)); } } } /* update our movie recording state */ if (!paused) movie_record_frame(0); /* reset the screen changed flags */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) scrinfo[scrnum].changed = 0; } /* draw any crosshairs */ crosshair_render(); /* draw the user interface */ ui_update_and_render(); /* call the OSD to update */ skipping_this_frame = osd_update(mame_timer_get_time()); /* empty the containers */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) if (Machine->drv->screen[scrnum].tag != NULL) render_container_empty(render_container_get_screen(scrnum)); /* update FPS */ recompute_fps(skipped_it); /* call the end-of-frame callback */ if (phase == MAME_PHASE_RUNNING) { /* reset partial updates if we're paused or if the debugger is active */ if (paused || mame_debug_is_active()) video_reset_partial_updates(); /* otherwise, call the video EOF callback */ else if (Machine->drv->video_eof != NULL) { profiler_mark(PROFILER_VIDEO); (*Machine->drv->video_eof)(Machine); profiler_mark(PROFILER_END); } } }
void Server::initialSync(const RakNet::SystemAddress &sa,running_machine *machine) { unsigned char checksum = 0; waitingForClientCatchup=true; machine->osd().pauseAudio(true); int syncBytes; { RakNet::BitStream uncompressedStream; uncompressedStream.Write(startupTime); uncompressedStream.Write(globalCurtime); if(getSecondsBetweenSync()) { while(memoryBlocksLocked) { ; } memoryBlocksLocked=true; cout << "IN CRITICAL SECTION\n"; cout << "SERVER: Sending initial snapshot\n"; int numBlocks = int(blocks.size()); cout << "NUMBLOCKS: " << numBlocks << endl; uncompressedStream.Write(numBlocks); // NOTE: The server must send stale data to the client for the first time // So that future syncs will be accurate for(int blockIndex=0; blockIndex<int(initialBlocks.size()); blockIndex++) { //cout << "BLOCK SIZE FOR INDEX " << blockIndex << ": " << staleBlocks[blockIndex].size << endl; uncompressedStream.Write(initialBlocks[blockIndex].size); cout << "BLOCK " << blockIndex << ": "; for(int a=0; a<staleBlocks[blockIndex].size; a++) { checksum = checksum ^ staleBlocks[blockIndex].data[a]; //cout << int(staleBlocks[blockIndex].data[a]) << ' '; unsigned char value = initialBlocks[blockIndex].data[a] ^ staleBlocks[blockIndex].data[a]; uncompressedStream.WriteBits(&value,8); } cout << int(checksum) << endl; } } for( map<int,vector< string > >::iterator it = peerInputs.begin(); it != peerInputs.end(); it++ ) { uncompressedStream.Write(it->first); uncompressedStream.Write(int(oldPeerInputs[it->first].size()) + int(it->second.size())); for(int a=0; a<(int)it->second.size(); a++) { uncompressedStream.Write(int(it->second[a].length())); uncompressedStream.WriteBits((const unsigned char*)it->second[a].c_str(),it->second[a].length()*8); for(int b=0;b<it->second[a].length();b++) { checksum = checksum ^ it->second[a][b]; } } for(int a=0; a<int(oldPeerInputs[it->first].size()); a++) { uncompressedStream.Write(int(oldPeerInputs[it->first][a].length())); uncompressedStream.WriteBits((const unsigned char*)oldPeerInputs[it->first][a].c_str(),oldPeerInputs[it->first][a].length()*8); for(int b=0;b<oldPeerInputs[it->first][a].length();b++) { checksum = checksum ^ oldPeerInputs[it->first][a][b]; } } } uncompressedStream.Write(int(-1)); uncompressedStream.Write(checksum); cout << "CHECKSUM: " << int(checksum) << endl; if(uncompressedBufferSize<uncompressedStream.GetNumberOfBytesUsed()+sizeof(int)) { uncompressedBufferSize = uncompressedStream.GetNumberOfBytesUsed()+sizeof(int); free(uncompressedBuffer); uncompressedBuffer = (unsigned char*)malloc(uncompressedBufferSize); if(!uncompressedBuffer) { cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n"; exit(1); } } syncBytes = uncompressedStream.GetNumberOfBytesUsed(); memcpy(uncompressedBuffer,uncompressedStream.GetData(),uncompressedStream.GetNumberOfBytesUsed()); int uncompressedStateSize = (int)uncompressedStream.GetNumberOfBytesUsed(); printf("INITIAL UNCOMPRESSED STATE SIZE: %d\n",uncompressedStateSize); } cout << "PUTTING NVRAM AT LOCATION " << syncBytes << endl; // open the file; if it exists, call everyone to read from it emu_file file(machine->options().nvram_directory(), OPEN_FLAG_READ); if (file.open(machine->basename(), ".nv") == FILERR_NONE && file.size()<=1024*1024*64) //Don't bother sending huge NVRAM's { int nvramSize = file.size(); if(uncompressedBufferSize<syncBytes+sizeof(int)+nvramSize) { uncompressedBufferSize = syncBytes+sizeof(int)+nvramSize; free(uncompressedBuffer); uncompressedBuffer = (unsigned char*)malloc(uncompressedBufferSize); if(!uncompressedBuffer) { cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n"; exit(1); } } cout << "SENDING NVRAM OF SIZE: " << nvramSize << endl; memcpy(uncompressedBuffer+syncBytes,&nvramSize,sizeof(int)); file.read(uncompressedBuffer+syncBytes+sizeof(int),nvramSize); file.close(); syncBytes += sizeof(int) + nvramSize; } else { int dummy=0; memcpy(uncompressedBuffer+syncBytes,&dummy,sizeof(int)); syncBytes += sizeof(int); } cout << "BYTES USED: " << syncBytes << endl; //The application should ensure that this value be at least (sourceLen 1.001) + 12. //JJG: Doing more than that to account for header and provide some padding //vector<unsigned char> compressedInitialSyncBuffer( //sizeof(int)*2 + lzmaGetMaxCompressedSize(uncompressedStream.GetNumberOfBytesUsed()), '\0'); //JJG: Take a risk and assume the compressed size will be smaller than the uncompressed size int newCompressedSize = max(1024*1024,int(sizeof(int)*2 + lzmaGetMaxCompressedSize(syncBytes))); if(compressedBufferSize < newCompressedSize ) { compressedBufferSize = newCompressedSize; cout << "NEW COMPRESSED BUFFER SIZE: " << compressedBufferSize << endl; free(compressedBuffer); compressedBuffer = (unsigned char*)malloc(compressedBufferSize); if(!compressedBuffer) { cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n"; exit(1); } } int compressedSizeLong = compressedBufferSize; //FILE *stateptr = fopen("initialState.dat","wb"); //fwrite(uncompressedStream.GetData(),uncompressedStream.GetNumberOfBytesUsed(),1,stateptr); //fclose(stateptr); lzmaCompress( compressedBuffer+sizeof(int)+sizeof(int), compressedSizeLong, uncompressedBuffer, syncBytes, 6 ); int uncompressedSize = (int)syncBytes; memcpy(compressedBuffer,&uncompressedSize,sizeof(int)); int compressedSize = (int)compressedSizeLong; memcpy(compressedBuffer+sizeof(int),&compressedSize,sizeof(int)); printf("INITIAL UNCOMPRESSED SIZE: %d\n",uncompressedSize); printf("INITIAL COMPRESSED SIZE: %d\n",compressedSize); /* rakInterface->Send( (char*)(&compressedInitialSyncBuffer[0]), compressedSize+1+sizeof(int), HIGH_PRIORITY, RELIABLE_ORDERED, ORDERING_CHANNEL_SYNC, guid, false ); */ // unsigned char *sendPtr = compressedBuffer; int sizeRemaining = compressedSize+sizeof(int)+sizeof(int); printf("INITIAL COMPRESSED SIZE: %dKB\n",sizeRemaining/1024); int packetSize = max(256,min(1024,sizeRemaining/100)); oldInputTime.seconds = oldInputTime.attoseconds = 0; while(sizeRemaining>packetSize) { RakNet::BitStream bitStreamPart(65536); unsigned char header = ID_INITIAL_SYNC_PARTIAL; bitStreamPart.WriteBits((const unsigned char*)&header,8*sizeof(unsigned char)); bitStreamPart.WriteBits((const unsigned char*)sendPtr,8*packetSize); sizeRemaining -= packetSize; sendPtr += packetSize; rakInterface->Send( &bitStreamPart, HIGH_PRIORITY, RELIABLE_ORDERED, ORDERING_CHANNEL_SYNC, sa, false ); ui_update_and_render(*machine, &machine->render().ui_container()); machine->osd().update(false); RakSleep(10); } { RakNet::BitStream bitStreamPart(65536); unsigned char header = ID_INITIAL_SYNC_COMPLETE; bitStreamPart.WriteBits((const unsigned char*)&header,8*sizeof(unsigned char)); bitStreamPart.WriteBits((const unsigned char*)sendPtr,8*sizeRemaining); rakInterface->Send( &bitStreamPart, HIGH_PRIORITY, RELIABLE_ORDERED, ORDERING_CHANNEL_SYNC, sa, false ); ui_update_and_render(*machine, &machine->render().ui_container()); machine->osd().update(false); RakSleep(10); } // cout << "FINISHED SENDING BLOCKS TO CLIENT\n"; cout << "SERVER: Done with initial snapshot\n"; cout << "OUT OF CRITICAL AREA\n"; cout.flush(); memoryBlocksLocked=false; }