// Note EXPORT_C GSReplay(char* lpszCmdLine, int renderer) { GLLoader::in_replayer = true; GSRendererType m_renderer; // Allow to easyly switch between SW/HW renderer -> this effectively removes the ability to select the renderer by function args m_renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer")); // alternatively: // m_renderer = static_cast<GSRendererType>(renderer); if (m_renderer != GSRendererType::OGL_HW && m_renderer != GSRendererType::OGL_SW) { fprintf(stderr, "wrong renderer selected %d\n", static_cast<int>(m_renderer)); return; } struct Packet {uint8 type, param; uint32 size, addr; vector<uint8> buff;}; list<Packet*> packets; vector<uint8> buff; vector<float> stats; stats.clear(); uint8 regs[0x2000]; GSinit(); GSsetBaseMem(regs); s_vsync = theApp.GetConfigB("vsync"); void* hWnd = NULL; int err = _GSopen((void**)&hWnd, "", m_renderer); if (err != 0) { fprintf(stderr, "Error failed to GSopen\n"); return; } if (s_gs->m_wnd == NULL) return; { // Read .gs content std::string f(lpszCmdLine); #ifdef LZMA_SUPPORTED GSDumpFile* file = (f.size() >= 4) && (f.compare(f.size()-3, 3, ".xz") == 0) ? (GSDumpFile*) new GSDumpLzma(lpszCmdLine) : (GSDumpFile*) new GSDumpRaw(lpszCmdLine); #else GSDumpFile* file = new GSDumpRaw(lpszCmdLine); #endif uint32 crc; file->Read(&crc, 4); GSsetGameCRC(crc, 0); GSFreezeData fd; file->Read(&fd.size, 4); fd.data = new uint8[fd.size]; file->Read(fd.data, fd.size); GSfreeze(FREEZE_LOAD, &fd); delete [] fd.data; file->Read(regs, 0x2000); GSvsync(1); while(!file->IsEof()) { uint8 type; file->Read(&type, 1); Packet* p = new Packet(); p->type = type; switch(type) { case 0: file->Read(&p->param, 1); file->Read(&p->size, 4); switch(p->param) { case 0: p->buff.resize(0x4000); p->addr = 0x4000 - p->size; file->Read(&p->buff[p->addr], p->size); break; case 1: case 2: case 3: p->buff.resize(p->size); file->Read(&p->buff[0], p->size); break; } break; case 1: file->Read(&p->param, 1); break; case 2: file->Read(&p->size, 4); break; case 3: p->buff.resize(0x2000); file->Read(&p->buff[0], 0x2000); break; } packets.push_back(p); } delete file; } sleep(1); //while(IsWindowVisible(hWnd)) //FIXME map? int finished = theApp.GetConfigI("linux_replay"); if (theApp.GetConfigI("dump")) { fprintf(stderr, "Dump is enabled. Replay will be disabled\n"); finished = 1; } unsigned long frame_number = 0; unsigned long total_frame_nb = 0; while(finished > 0) { frame_number = 0; unsigned long start = timeGetTime(); for(auto i = packets.begin(); i != packets.end(); i++) { Packet* p = *i; switch(p->type) { case 0: switch(p->param) { case 0: GSgifTransfer1(&p->buff[0], p->addr); break; case 1: GSgifTransfer2(&p->buff[0], p->size / 16); break; case 2: GSgifTransfer3(&p->buff[0], p->size / 16); break; case 3: GSgifTransfer(&p->buff[0], p->size / 16); break; } break; case 1: GSvsync(p->param); frame_number++; break; case 2: if(buff.size() < p->size) buff.resize(p->size); GSreadFIFO2(&buff[0], p->size / 16); break; case 3: memcpy(regs, &p->buff[0], 0x2000); break; } } // Ensure the rendering is complete to measure correctly the time. glFinish(); if (finished > 90) { sleep(1); } else { unsigned long end = timeGetTime(); frame_number = std::max(1ul, frame_number); // avoid a potential division by 0 fprintf(stderr, "The %ld frames of the scene was render on %ldms\n", frame_number, end - start); fprintf(stderr, "A means of %fms by frame\n", (float)(end - start)/(float)frame_number); stats.push_back((float)(end - start)); finished--; total_frame_nb += frame_number; } } if (theApp.GetConfigI("linux_replay") > 1) { // Print some nice stats // Skip first frame (shader compilation populate the result) // it divides by 10 the standard deviation... float n = (float)theApp.GetConfigI("linux_replay") - 1.0f; float mean = 0; float sd = 0; for (auto i = stats.begin()+1; i != stats.end(); i++) { mean += *i; } mean = mean/n; for (auto i = stats.begin()+1; i != stats.end(); i++) { sd += pow((*i)-mean, 2); } sd = sqrt(sd/n); fprintf(stderr, "\n\nMean: %fms\n", mean); fprintf(stderr, "Standard deviation: %fms\n", sd); fprintf(stderr, "Mean by frame: %fms (%ffps)\n", mean/(float)frame_number, 1000.0f*frame_number/mean); fprintf(stderr, "Standard deviatin by frame: %fms\n", sd/(float)frame_number); } #ifdef ENABLE_OGL_DEBUG_MEM_BW total_frame_nb *= 1024; fprintf(stderr, "memory bandwith. T: %f KB/f. V: %f KB/f. U: %f KB/f\n", (float)g_real_texture_upload_byte/(float)total_frame_nb, (float)g_vertex_upload_byte/(float)total_frame_nb, (float)g_uniform_upload_byte/(float)total_frame_nb ); #endif for(auto i = packets.begin(); i != packets.end(); i++) { delete *i; } packets.clear(); sleep(1); GSclose(); GSshutdown(); }
static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads = -1) { GSDevice* dev = NULL; if(renderer == GSRendererType::Undefined) { renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer")); } if(threads == -1) { threads = theApp.GetConfigI("extrathreads"); } GSWnd* wnd[2] = { NULL, NULL }; try { if (s_renderer != renderer) { // Emulator has made a render change request, which requires a completely // new s_gs -- if the emu doesn't save/restore the GS state across this // GSopen call then they'll get corrupted graphics, but that's not my problem. delete s_gs; s_gs = NULL; } const char* renderer_fullname = ""; const char* renderer_mode = ""; switch (renderer) { case GSRendererType::DX9_SW: case GSRendererType::DX1011_SW: case GSRendererType::OGL_SW: renderer_mode = "(Software mode)"; break; case GSRendererType::Null: renderer_mode = "(Null mode)"; break; case GSRendererType::DX9_OpenCL: case GSRendererType::DX1011_OpenCL: case GSRendererType::OGL_OpenCL: renderer_mode = "(OpenCL)"; break; default: renderer_mode = "(Hardware mode)"; break; } switch (renderer) { default: #ifdef _WIN32 case GSRendererType::DX9_HW: case GSRendererType::DX9_SW: case GSRendererType::DX9_OpenCL: dev = new GSDevice9(); s_renderer_name = " D3D9"; renderer_fullname = "Direct3D9"; break; case GSRendererType::DX1011_HW: case GSRendererType::DX1011_SW: case GSRendererType::DX1011_OpenCL: dev = new GSDevice11(); s_renderer_name = " D3D11"; renderer_fullname = "Direct3D11"; break; #endif case GSRendererType::Null: dev = new GSDeviceNull(); s_renderer_name = " Null"; renderer_fullname = "Null"; break; case GSRendererType::OGL_HW: case GSRendererType::OGL_SW: case GSRendererType::OGL_OpenCL: dev = new GSDeviceOGL(); s_renderer_name = " OGL"; renderer_fullname = "OpenGL"; break; } printf("Current Renderer: %s %s\n", renderer_fullname, renderer_mode); if (dev == NULL) { return -1; } if (s_gs == NULL) { switch (renderer) { default: #ifdef _WIN32 case GSRendererType::DX9_HW: s_gs = (GSRenderer*)new GSRendererDX9(); s_renderer_type = " HW"; break; case GSRendererType::DX1011_HW: s_gs = (GSRenderer*)new GSRendererDX11(); s_renderer_type = " HW"; break; #endif case GSRendererType::OGL_HW: s_gs = (GSRenderer*)new GSRendererOGL(); s_renderer_type = " HW"; break; case GSRendererType::DX9_SW: case GSRendererType::DX1011_SW: case GSRendererType::OGL_SW: s_gs = new GSRendererSW(threads); s_renderer_type = " SW"; break; case GSRendererType::Null: s_gs = new GSRendererNull(); s_renderer_type = " Null"; break; case GSRendererType::DX9_OpenCL: case GSRendererType::DX1011_OpenCL: case GSRendererType::OGL_OpenCL: #ifdef ENABLE_OPENCL s_gs = new GSRendererCL(); s_renderer_type = " OCL"; #else printf("GSdx error: OpenCL is disabled\n"); #endif break; } if (s_gs == NULL) return -1; s_renderer = renderer; } if (s_gs->m_wnd == NULL) { #ifdef _WIN32 switch (renderer) { case GSRendererType::OGL_HW: case GSRendererType::OGL_SW: case GSRendererType::OGL_OpenCL: s_gs->m_wnd = new GSWndWGL(); break; default: s_gs->m_wnd = new GSWndDX(); break; } #else #ifdef EGL_SUPPORTED wnd[0] = new GSWndEGL(); wnd[1] = new GSWndOGL(); #else wnd[0] = new GSWndOGL(); #endif #endif } } catch (std::exception& ex) { // Allowing std exceptions to escape the scope of the plugin callstack could // be problematic, because of differing typeids between DLL and EXE compilations. // ('new' could throw std::alloc) printf("GSdx error: Exception caught in GSopen: %s", ex.what()); return -1; } s_gs->SetRegsMem(s_basemem); s_gs->SetIrqCallback(s_irq); s_gs->SetVSync(s_vsync); s_gs->SetFrameLimit(s_framelimit); if(*dsp == NULL) { // old-style API expects us to create and manage our own window: int w = theApp.GetConfigI("ModeWidth"); int h = theApp.GetConfigI("ModeHeight"); #if defined(__unix__) for(uint32 i = 0; i < 2; i++) { try { if (wnd[i] == NULL) continue; wnd[i]->Create(title, w, h); s_gs->m_wnd = wnd[i]; if (i == 0) delete wnd[1]; break; } catch (GSDXRecoverableError) { wnd[i]->Detach(); delete wnd[i]; } } if (s_gs->m_wnd == NULL) { GSclose(); return -1; } #endif #ifdef _WIN32 if(!s_gs->CreateWnd(title, w, h)) { GSclose(); return -1; } #endif s_gs->m_wnd->Show(); *dsp = s_gs->m_wnd->GetDisplay(); } else { s_gs->SetMultithreaded(true); #if defined(__unix__) if (s_gs->m_wnd) { // A window was already attached to s_gs so we also // need to restore the window state (Attach) s_gs->m_wnd->Attach((void*)((uptr*)(dsp)+1), false); } else { // No window found, try to attach a GLX win and retry // with EGL win if failed. for(uint32 i = 0; i < 2; i++) { try { if (wnd[i] == NULL) continue; wnd[i]->Attach((void*)((uptr*)(dsp)+1), false); s_gs->m_wnd = wnd[i]; if (i == 0) delete wnd[1]; break; } catch (GSDXRecoverableError) { wnd[i]->Detach(); delete wnd[i]; } } } #endif #ifdef _WIN32 try { s_gs->m_wnd->Attach(*dsp, false); } catch (GSDXRecoverableError) { s_gs->m_wnd->Detach(); delete s_gs->m_wnd; s_gs->m_wnd = NULL; } #endif if (s_gs->m_wnd == NULL) { return -1; } } if(!s_gs->CreateDevice(dev)) { // This probably means the user has DX11 configured with a video card that is only DX9 // compliant. Cound mean drivr issues of some sort also, but to be sure, that's the most // common cause of device creation errors. :) --air GSclose(); return -1; } if (renderer == GSRendererType::OGL_HW && theApp.GetConfigI("debug_glsl_shader") == 2) { printf("GSdx: test OpenGL shader. Please wait...\n\n"); static_cast<GSDeviceOGL*>(s_gs->m_dev)->SelfShaderTest(); printf("\nGSdx: test OpenGL shader done. It will now exit\n"); return -1; } return 0; }
EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { GSRendererType renderer = GSRendererType::Undefined; { char* start = lpszCmdLine; char* end = NULL; long n = strtol(lpszCmdLine, &end, 10); if(end > start) {renderer = static_cast<GSRendererType>(n); lpszCmdLine = end;} } while(*lpszCmdLine == ' ') lpszCmdLine++; ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); if(FILE* fp = fopen(lpszCmdLine, "rb")) { Console console("GSdx", true); GSinit(); uint8 regs[0x2000]; GSsetBaseMem(regs); s_vsync = theApp.GetConfigB("vsync"); HWND hWnd = NULL; _GSopen((void**)&hWnd, "", renderer); uint32 crc; fread(&crc, 4, 1, fp); GSsetGameCRC(crc, 0); GSFreezeData fd; fread(&fd.size, 4, 1, fp); fd.data = new uint8[fd.size]; fread(fd.data, fd.size, 1, fp); GSfreeze(FREEZE_LOAD, &fd); delete [] fd.data; fread(regs, 0x2000, 1, fp); long start = ftell(fp); GSvsync(1); struct Packet {uint8 type, param; uint32 size, addr; vector<uint8> buff;}; list<Packet*> packets; vector<uint8> buff; int type; while((type = fgetc(fp)) != EOF) { Packet* p = new Packet(); p->type = (uint8)type; switch(type) { case 0: p->param = (uint8)fgetc(fp); fread(&p->size, 4, 1, fp); switch(p->param) { case 0: p->buff.resize(0x4000); p->addr = 0x4000 - p->size; fread(&p->buff[p->addr], p->size, 1, fp); break; case 1: case 2: case 3: p->buff.resize(p->size); fread(&p->buff[0], p->size, 1, fp); break; } break; case 1: p->param = (uint8)fgetc(fp); break; case 2: fread(&p->size, 4, 1, fp); break; case 3: p->buff.resize(0x2000); fread(&p->buff[0], 0x2000, 1, fp); break; } packets.push_back(p); } Sleep(100); while(IsWindowVisible(hWnd)) { for(list<Packet*>::iterator i = packets.begin(); i != packets.end(); i++) { Packet* p = *i; switch(p->type) { case 0: switch(p->param) { case 0: GSgifTransfer1(&p->buff[0], p->addr); break; case 1: GSgifTransfer2(&p->buff[0], p->size / 16); break; case 2: GSgifTransfer3(&p->buff[0], p->size / 16); break; case 3: GSgifTransfer(&p->buff[0], p->size / 16); break; } break; case 1: GSvsync(p->param); break; case 2: if(buff.size() < p->size) buff.resize(p->size); GSreadFIFO2(&buff[0], p->size / 16); break; case 3: memcpy(regs, &p->buff[0], 0x2000); break; } } } for(list<Packet*>::iterator i = packets.begin(); i != packets.end(); i++) { delete *i; } packets.clear(); Sleep(100); /* vector<uint8> buff; bool exit = false; int round = 0; while(!exit) { uint32 index; uint32 size; uint32 addr; int pos; switch(fgetc(fp)) { case EOF: fseek(fp, start, 0); exit = !IsWindowVisible(hWnd); //exit = ++round == 60; break; case 0: index = fgetc(fp); fread(&size, 4, 1, fp); switch(index) { case 0: if(buff.size() < 0x4000) buff.resize(0x4000); addr = 0x4000 - size; fread(&buff[addr], size, 1, fp); GSgifTransfer1(&buff[0], addr); break; case 1: if(buff.size() < size) buff.resize(size); fread(&buff[0], size, 1, fp); GSgifTransfer2(&buff[0], size / 16); break; case 2: if(buff.size() < size) buff.resize(size); fread(&buff[0], size, 1, fp); GSgifTransfer3(&buff[0], size / 16); break; case 3: if(buff.size() < size) buff.resize(size); fread(&buff[0], size, 1, fp); GSgifTransfer(&buff[0], size / 16); break; } break; case 1: GSvsync(fgetc(fp)); exit = !IsWindowVisible(hWnd); break; case 2: fread(&size, 4, 1, fp); if(buff.size() < size) buff.resize(size); GSreadFIFO2(&buff[0], size / 16); break; case 3: fread(regs, 0x2000, 1, fp); break; } } */ GSclose(); GSshutdown(); fclose(fp); } }
static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) { // I really don't know the impact on windows! It could work #ifdef __linux__ if (theApp.GetConfig("enable_nvidia_multi_thread", 1)) { setenv("__GL_THREADED_OPTIMIZATIONS", "1", 0); } #endif GSDevice* dev = NULL; if(renderer == -1) { renderer = theApp.GetConfig("renderer", 0); } if(threads == -1) { threads = theApp.GetConfig("extrathreads", 0); } GSWnd* wnd[2]; try { if(s_renderer != renderer) { // Emulator has made a render change request, which requires a completely // new s_gs -- if the emu doesn't save/restore the GS state across this // GSopen call then they'll get corrupted graphics, but that's not my problem. delete s_gs; s_gs = NULL; } switch(renderer) { default: #ifdef _WINDOWS case 0: case 1: case 2: case 14: dev = new GSDevice9(); break; case 3: case 4: case 5: case 15: dev = new GSDevice11(); break; #endif case 9: case 10: case 11: case 16: dev = new GSDeviceNull(); break; case 12: case 13: case 17: dev = new GSDeviceOGL(); break; } if(dev == NULL) { return -1; } if(s_gs == NULL) { switch(renderer) { default: #ifdef _WINDOWS case 0: s_gs = (GSRenderer*)new GSRendererDX9(); break; case 3: s_gs = (GSRenderer*)new GSRendererDX11(); break; #endif case 12: s_gs = (GSRenderer*)new GSRendererOGL(); break; case 1: case 4: case 10: case 13: s_gs = new GSRendererSW(threads); break; case 2: case 5: case 11: s_gs = new GSRendererNull(); break; case 14: case 15: case 16: case 17: #ifdef ENABLE_OPENCL s_gs = new GSRendererCL(); #else printf("GSdx error: opencl is disabled\n"); #endif break; } if (s_gs == NULL) return -1; s_renderer = renderer; } if (s_gs->m_wnd == NULL) { #ifdef _WINDOWS switch(renderer) { case 12: case 13: case 17: s_gs->m_wnd = new GSWndWGL(); break; default: s_gs->m_wnd = new GSWndDX(); break; } #else wnd[0] = new GSWndOGL(); #ifdef EGL_SUPPORTED wnd[1] = new GSWndEGL(); #else wnd[1] = NULL; #endif #endif } } catch(std::exception& ex) { // Allowing std exceptions to escape the scope of the plugin callstack could // be problematic, because of differing typeids between DLL and EXE compilations. // ('new' could throw std::alloc) printf("GSdx error: Exception caught in GSopen: %s", ex.what()); return -1; } s_gs->SetRegsMem(s_basemem); s_gs->SetIrqCallback(s_irq); s_gs->SetVSync(s_vsync); s_gs->SetFrameLimit(s_framelimit); if(*dsp == NULL) { // old-style API expects us to create and manage our own window: int w = theApp.GetConfig("ModeWidth", 0); int h = theApp.GetConfig("ModeHeight", 0); #ifdef __linux__ for(uint32 i = 0; i < 2; i++) { try { if (wnd[i] == NULL) continue; wnd[i]->Create(title, w, h); s_gs->m_wnd = wnd[i]; if (i == 0) delete wnd[1]; break; } catch (GSDXRecoverableError) { wnd[i]->Detach(); delete wnd[i]; } } if (s_gs->m_wnd == NULL) { GSclose(); return -1; } #endif #ifdef _WINDOWS if(!s_gs->CreateWnd(title, w, h)) { GSclose(); return -1; } #endif s_gs->m_wnd->Show(); *dsp = s_gs->m_wnd->GetDisplay(); } else { s_gs->SetMultithreaded(true); #ifdef __linux__ if (s_gs->m_wnd) { // A window was already attached to s_gs so we also // need to restore the window state (Attach) s_gs->m_wnd->Attach((void*)((uptr*)(dsp)+1), false); } else { // No window found, try to attach a GLX win and retry // with EGL win if failed. for(uint32 i = 0; i < 2; i++) { try { if (wnd[i] == NULL) continue; wnd[i]->Attach((void*)((uptr*)(dsp)+1), false); s_gs->m_wnd = wnd[i]; if (i == 0) delete wnd[1]; break; } catch (GSDXRecoverableError) { wnd[i]->Detach(); delete wnd[i]; } } } #endif #ifdef _WINDOWS try { s_gs->m_wnd->Attach(*dsp, false); } catch (GSDXRecoverableError) { s_gs->m_wnd->Detach(); delete s_gs->m_wnd; s_gs->m_wnd = NULL; } #endif if (s_gs->m_wnd == NULL) { return -1; } } if(!s_gs->CreateDevice(dev)) { // This probably means the user has DX11 configured with a video card that is only DX9 // compliant. Cound mean drivr issues of some sort also, but to be sure, that's the most // common cause of device creation errors. :) --air GSclose(); return -1; } return 0; }
// Note EXPORT_C GSReplay(char* lpszCmdLine, int renderer) { GLLoader::in_replayer = true; GSRendererType m_renderer; // Allow to easyly switch between SW/HW renderer -> this effectively removes the ability to select the renderer by function args m_renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer")); // alternatively: // m_renderer = static_cast<GSRendererType>(renderer); if (m_renderer != GSRendererType::OGL_HW && m_renderer != GSRendererType::OGL_SW) { fprintf(stderr, "wrong renderer selected %d\n", static_cast<int>(m_renderer)); return; } struct Packet {uint8 type, param; uint32 size, addr; vector<uint8> buff;}; list<Packet*> packets; vector<uint8> buff; uint8 regs[0x2000]; GSinit(); GSsetBaseMem(regs); s_vsync = theApp.GetConfigB("vsync"); void* hWnd = NULL; int err = _GSopen((void**)&hWnd, "", m_renderer); if (err != 0) { fprintf(stderr, "Error failed to GSopen\n"); return; } if (s_gs->m_wnd == NULL) return; { // Read .gs content std::string f(lpszCmdLine); #ifdef LZMA_SUPPORTED GSDumpFile* file = (f.size() >= 4) && (f.compare(f.size()-3, 3, ".xz") == 0) ? (GSDumpFile*) new GSDumpLzma(lpszCmdLine) : (GSDumpFile*) new GSDumpRaw(lpszCmdLine); #else GSDumpFile* file = new GSDumpRaw(lpszCmdLine); #endif uint32 crc; file->Read(&crc, 4); GSsetGameCRC(crc, 0); GSFreezeData fd; file->Read(&fd.size, 4); fd.data = new uint8[fd.size]; file->Read(fd.data, fd.size); GSfreeze(FREEZE_LOAD, &fd); delete [] fd.data; file->Read(regs, 0x2000); GSvsync(1); while(!file->IsEof()) { uint8 type; file->Read(&type, 1); Packet* p = new Packet(); p->type = type; switch(type) { case 0: file->Read(&p->param, 1); file->Read(&p->size, 4); switch(p->param) { case 0: p->buff.resize(0x4000); p->addr = 0x4000 - p->size; file->Read(&p->buff[p->addr], p->size); break; case 1: case 2: case 3: p->buff.resize(p->size); file->Read(&p->buff[0], p->size); break; } break; case 1: file->Read(&p->param, 1); break; case 2: file->Read(&p->size, 4); break; case 3: p->buff.resize(0x2000); file->Read(&p->buff[0], 0x2000); break; } packets.push_back(p); } delete file; } sleep(1); //while(IsWindowVisible(hWnd)) //FIXME map? int finished = theApp.GetConfigI("linux_replay"); if (theApp.GetConfigI("dump")) { fprintf(stderr, "Dump is enabled. Replay will be disabled\n"); finished = 1; } unsigned long frame_number = 0; while(finished > 0) { for(auto i = packets.begin(); i != packets.end(); i++) { Packet* p = *i; switch(p->type) { case 0: switch(p->param) { case 0: GSgifTransfer1(&p->buff[0], p->addr); break; case 1: GSgifTransfer2(&p->buff[0], p->size / 16); break; case 2: GSgifTransfer3(&p->buff[0], p->size / 16); break; case 3: GSgifTransfer(&p->buff[0], p->size / 16); break; } break; case 1: GSvsync(p->param); frame_number++; break; case 2: if(buff.size() < p->size) buff.resize(p->size); GSreadFIFO2(&buff[0], p->size / 16); break; case 3: memcpy(regs, &p->buff[0], 0x2000); break; } } if (finished >= 200) { ; // Nop for Nvidia Profiler } else if (finished > 90) { sleep(1); } else { finished--; } } #ifdef ENABLE_OGL_DEBUG_MEM_BW unsigned long total_frame_nb = std::max(1ul, frame_number) << 10; fprintf(stderr, "memory bandwith. T: %f KB/f. V: %f KB/f. U: %f KB/f\n", (float)g_real_texture_upload_byte/(float)total_frame_nb, (float)g_vertex_upload_byte/(float)total_frame_nb, (float)g_uniform_upload_byte/(float)total_frame_nb ); #endif for(auto i = packets.begin(); i != packets.end(); i++) { delete *i; } packets.clear(); sleep(1); GSclose(); GSshutdown(); }
// Note EXPORT_C GSReplay(char* lpszCmdLine, int renderer) { GLLoader::in_replayer = true; // lpszCmdLine: // First parameter is the renderer. // Second parameter is the gs file to load and run. //EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) #if 0 int renderer = -1; { char* start = lpszCmdLine; char* end = NULL; long n = strtol(lpszCmdLine, &end, 10); if(end > start) {renderer = n; lpszCmdLine = end;} } while(*lpszCmdLine == ' ') lpszCmdLine++; ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); #endif // Allow to easyly switch between SW/HW renderer renderer = theApp.GetConfig("renderer", 12); if (renderer != 12 && renderer != 13) { fprintf(stderr, "wrong renderer selected %d\n", renderer); return; } vector<float> stats; stats.clear(); if(FILE* fp = fopen(lpszCmdLine, "rb")) { //Console console("GSdx", true); GSinit(); uint8 regs[0x2000]; GSsetBaseMem(regs); s_vsync = !!theApp.GetConfig("vsync", 0); void* hWnd = NULL; int err = _GSopen((void**)&hWnd, "", renderer); if (err != 0) { fprintf(stderr, "Error failed to GSopen\n"); return; } if (s_gs->m_wnd == NULL) return; uint32 crc; fread(&crc, 4, 1, fp); GSsetGameCRC(crc, 0); GSFreezeData fd; fread(&fd.size, 4, 1, fp); fd.data = new uint8[fd.size]; fread(fd.data, fd.size, 1, fp); GSfreeze(FREEZE_LOAD, &fd); delete [] fd.data; fread(regs, 0x2000, 1, fp); GSvsync(1); struct Packet {uint8 type, param; uint32 size, addr; vector<uint8> buff;}; list<Packet*> packets; vector<uint8> buff; int type; while((type = fgetc(fp)) != EOF) { Packet* p = new Packet(); p->type = (uint8)type; switch(type) { case 0: p->param = (uint8)fgetc(fp); fread(&p->size, 4, 1, fp); switch(p->param) { case 0: p->buff.resize(0x4000); p->addr = 0x4000 - p->size; fread(&p->buff[p->addr], p->size, 1, fp); break; case 1: case 2: case 3: p->buff.resize(p->size); fread(&p->buff[0], p->size, 1, fp); break; } break; case 1: p->param = (uint8)fgetc(fp); break; case 2: fread(&p->size, 4, 1, fp); break; case 3: p->buff.resize(0x2000); fread(&p->buff[0], 0x2000, 1, fp); break; } packets.push_back(p); } sleep(1); //while(IsWindowVisible(hWnd)) //FIXME map? int finished = theApp.GetConfig("linux_replay", 1); unsigned long frame_number = 0; while(finished > 0) { frame_number = 0; unsigned long start = timeGetTime(); for(auto i = packets.begin(); i != packets.end(); i++) { Packet* p = *i; switch(p->type) { case 0: switch(p->param) { case 0: GSgifTransfer1(&p->buff[0], p->addr); break; case 1: GSgifTransfer2(&p->buff[0], p->size / 16); break; case 2: GSgifTransfer3(&p->buff[0], p->size / 16); break; case 3: GSgifTransfer(&p->buff[0], p->size / 16); break; } break; case 1: GSvsync(p->param); frame_number++; break; case 2: if(buff.size() < p->size) buff.resize(p->size); GSreadFIFO2(&buff[0], p->size / 16); break; case 3: memcpy(regs, &p->buff[0], 0x2000); break; } } unsigned long end = timeGetTime(); fprintf(stderr, "The %ld frames of the scene was render on %ldms\n", frame_number, end - start); fprintf(stderr, "A means of %fms by frame\n", (float)(end - start)/(float)frame_number); stats.push_back((float)(end - start)); sleep(1); finished--; } if (theApp.GetConfig("linux_replay", 1) > 1) { // Print some nice stats // Skip first frame (shader compilation populate the result) // it divides by 10 the standard deviation... float n = (float)theApp.GetConfig("linux_replay", 1) - 1.0f; float mean = 0; float sd = 0; for (auto i = stats.begin()+1; i != stats.end(); i++) { mean += *i; } mean = mean/n; for (auto i = stats.begin()+1; i != stats.end(); i++) { sd += pow((*i)-mean, 2); } sd = sqrt(sd/n); fprintf(stderr, "\n\nMean: %fms\n", mean); fprintf(stderr, "Standard deviation: %fms\n", sd); fprintf(stderr, "Mean by frame: %fms (%ffps)\n", mean/(float)frame_number, 1000.0f*frame_number/mean); fprintf(stderr, "Standard deviatin by frame: %fms\n", sd/(float)frame_number); } #ifdef ENABLE_OGL_DEBUG_MEM_BW fprintf(stderr, "memory bandwith. T: %f. V: %f\n", (float)g_texture_upload_byte/(float)frame_number/1024, (float)g_vertex_upload_byte/(float)frame_number/1024); #endif for(auto i = packets.begin(); i != packets.end(); i++) { delete *i; } packets.clear(); sleep(1); GSclose(); GSshutdown(); fclose(fp); } else { fprintf(stderr, "failed to open %s\n", lpszCmdLine); } }
static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads = -1) { GSDevice* dev = NULL; bool old_api = *dsp == NULL; // Fresh start up or config file changed if(renderer == GSRendererType::Undefined) { renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer")); #ifdef _WIN32 if (renderer == GSRendererType::Default) renderer = GSUtil::GetBestRenderer(); #endif } if(threads == -1) { threads = theApp.GetConfigI("extrathreads"); } try { if (theApp.GetCurrentRendererType() != renderer) { // Emulator has made a render change request, which requires a completely // new s_gs -- if the emu doesn't save/restore the GS state across this // GSopen call then they'll get corrupted graphics, but that's not my problem. delete s_gs; s_gs = NULL; theApp.SetCurrentRendererType(renderer); } std::shared_ptr<GSWnd> window; { // Select the window first to detect the GL requirement std::vector<std::shared_ptr<GSWnd>> wnds; switch (renderer) { case GSRendererType::OGL_HW: case GSRendererType::OGL_SW: case GSRendererType::OGL_OpenCL: #if defined(EGL_SUPPORTED) && defined(__unix__) // Note: EGL code use GLX otherwise maybe it could be also compatible with Windows // Yes OpenGL code isn't complicated enough ! switch (GSWndEGL::SelectPlatform()) { #if GS_EGL_X11 case EGL_PLATFORM_X11_KHR: wnds.push_back(std::make_shared<GSWndEGL_X11>()); break; #endif #if GS_EGL_WL case EGL_PLATFORM_WAYLAND_KHR: wnds.push_back(std::make_shared<GSWndEGL_WL>()); break; #endif default: break; } #endif #if defined(__unix__) wnds.push_back(std::make_shared<GSWndOGL>()); #else wnds.push_back(std::make_shared<GSWndWGL>()); #endif break; default: #ifdef _WIN32 wnds.push_back(std::make_shared<GSWndDX>()); #endif break; } int w = theApp.GetConfigI("ModeWidth"); int h = theApp.GetConfigI("ModeHeight"); #if defined(__unix__) void *win_handle = (void*)((uptr*)(dsp)+1); #else void *win_handle = *dsp; #endif for(auto& wnd : wnds) { try { if (old_api) { // old-style API expects us to create and manage our own window: wnd->Create(title, w, h); wnd->Show(); *dsp = wnd->GetDisplay(); } else { wnd->Attach(win_handle, false); } window = wnd; // Previous code will throw if window isn't supported break; } catch (GSDXRecoverableError) { wnd->Detach(); } } if(!window) { GSclose(); return -1; } } const char* renderer_fullname = ""; const char* renderer_mode = ""; switch (renderer) { case GSRendererType::DX9_SW: case GSRendererType::DX1011_SW: case GSRendererType::OGL_SW: renderer_mode = "(Software renderer)"; break; case GSRendererType::Null: renderer_mode = "(Null renderer)"; break; case GSRendererType::DX9_OpenCL: case GSRendererType::DX1011_OpenCL: case GSRendererType::OGL_OpenCL: renderer_mode = "(OpenCL)"; break; default: renderer_mode = "(Hardware renderer)"; break; } switch (renderer) { default: #ifdef _WIN32 case GSRendererType::DX9_HW: case GSRendererType::DX9_SW: case GSRendererType::DX9_OpenCL: dev = new GSDevice9(); s_renderer_name = " D3D9"; renderer_fullname = "Direct3D 9"; break; case GSRendererType::DX1011_HW: case GSRendererType::DX1011_SW: case GSRendererType::DX1011_OpenCL: dev = new GSDevice11(); s_renderer_name = " D3D11"; renderer_fullname = "Direct3D 11"; break; #endif case GSRendererType::Null: dev = new GSDeviceNull(); s_renderer_name = " Null"; renderer_fullname = "Null"; break; case GSRendererType::OGL_HW: case GSRendererType::OGL_SW: case GSRendererType::OGL_OpenCL: dev = new GSDeviceOGL(); s_renderer_name = " OGL"; renderer_fullname = "OpenGL"; break; } printf("Current Renderer: %s %s\n", renderer_fullname, renderer_mode); if (dev == NULL) { return -1; } if (s_gs == NULL) { switch (renderer) { default: #ifdef _WIN32 case GSRendererType::DX9_HW: s_gs = (GSRenderer*)new GSRendererDX9(); s_renderer_type = " HW"; break; case GSRendererType::DX1011_HW: s_gs = (GSRenderer*)new GSRendererDX11(); s_renderer_type = " HW"; break; #endif case GSRendererType::OGL_HW: s_gs = (GSRenderer*)new GSRendererOGL(); s_renderer_type = " HW"; break; case GSRendererType::DX9_SW: case GSRendererType::DX1011_SW: case GSRendererType::OGL_SW: s_gs = new GSRendererSW(threads); s_renderer_type = " SW"; break; case GSRendererType::Null: s_gs = new GSRendererNull(); s_renderer_type = ""; break; case GSRendererType::DX9_OpenCL: case GSRendererType::DX1011_OpenCL: case GSRendererType::OGL_OpenCL: #ifdef ENABLE_OPENCL s_gs = new GSRendererCL(); s_renderer_type = " OCL"; #else printf("GSdx error: OpenCL is disabled\n"); #endif break; } if (s_gs == NULL) return -1; } s_gs->m_wnd = window; } catch (std::exception& ex) { // Allowing std exceptions to escape the scope of the plugin callstack could // be problematic, because of differing typeids between DLL and EXE compilations. // ('new' could throw std::alloc) printf("GSdx error: Exception caught in GSopen: %s", ex.what()); return -1; } s_gs->SetRegsMem(s_basemem); s_gs->SetIrqCallback(s_irq); s_gs->SetVSync(s_vsync); s_gs->SetFrameLimit(s_framelimit); if(!old_api) s_gs->SetMultithreaded(true); if(!s_gs->CreateDevice(dev)) { // This probably means the user has DX11 configured with a video card that is only DX9 // compliant. Cound mean drivr issues of some sort also, but to be sure, that's the most // common cause of device creation errors. :) --air GSclose(); return -1; } if (renderer == GSRendererType::OGL_HW && theApp.GetConfigI("debug_glsl_shader") == 2) { printf("GSdx: test OpenGL shader. Please wait...\n\n"); static_cast<GSDeviceOGL*>(s_gs->m_dev)->SelfShaderTest(); printf("\nGSdx: test OpenGL shader done. It will now exit\n"); return -1; } return 0; }