From d7c1faf563760d219e084c536ec4ead5dd33ad4d Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 26 Jun 2016 15:27:57 +0200 Subject: [PATCH] gsdx ogl: add GPU timers to measure time between 2 vsync So far only basic stuff (min/mean/max frame rendering time) --- plugins/GSdx/GLLoader.cpp | 2 ++ plugins/GSdx/GLLoader.h | 2 ++ plugins/GSdx/GS.cpp | 7 +++-- plugins/GSdx/GSDeviceOGL.cpp | 60 ++++++++++++++++++++++++++++++++++++ plugins/GSdx/GSDeviceOGL.h | 10 +++++- plugins/GSdx/GSWnd.cpp | 20 ++++++------ 6 files changed, 88 insertions(+), 13 deletions(-) diff --git a/plugins/GSdx/GLLoader.cpp b/plugins/GSdx/GLLoader.cpp index d97d4b49af..46825cc2c7 100644 --- a/plugins/GSdx/GLLoader.cpp +++ b/plugins/GSdx/GLLoader.cpp @@ -100,6 +100,8 @@ PFNGLQUERYCOUNTERPROC glQueryCounter = NUL PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL; PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL; PFNGLGETINTEGER64VPROC glGetInteger64v = NULL; +PFNGLCREATEQUERIESPROC glCreateQueries = NULL; +PFNGLDELETEQUERIESPROC glDeleteQueries = NULL; // GL4.0 // GL4.1 PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline = NULL; diff --git a/plugins/GSdx/GLLoader.h b/plugins/GSdx/GLLoader.h index 0c9737d313..0bde209d4c 100644 --- a/plugins/GSdx/GLLoader.h +++ b/plugins/GSdx/GLLoader.h @@ -268,6 +268,8 @@ extern PFNGLQUERYCOUNTERPROC glQueryCounter; extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; extern PFNGLGETINTEGER64VPROC glGetInteger64v; +extern PFNGLCREATEQUERIESPROC glCreateQueries; +extern PFNGLDELETEQUERIESPROC glDeleteQueries; // GL4.0 // GL4.1 extern PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline; diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index bec2c8eab0..28a14f969a 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -1689,7 +1689,9 @@ EXPORT_C GSReplay(char* lpszCmdLine, int renderer) // Ensure the rendering is complete to measure correctly the time. glFinish(); - if (finished > 90) { + if (finished >= 200) { + ; // Nop for Nvidia Profiler + } else if (finished > 90) { sleep(1); } else { unsigned long end = timeGetTime(); @@ -1724,7 +1726,7 @@ EXPORT_C GSReplay(char* lpszCmdLine, int renderer) 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); + fprintf(stderr, "Standard deviation by frame: %fms\n", sd/(float)frame_number); } #ifdef ENABLE_OGL_DEBUG_MEM_BW total_frame_nb *= 1024; @@ -1748,4 +1750,3 @@ EXPORT_C GSReplay(char* lpszCmdLine, int renderer) GSshutdown(); } #endif - diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index 6c96ed2a78..86f27ead85 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -71,6 +71,7 @@ GSDeviceOGL::GSDeviceOGL() memset(&m_date, 0, sizeof(m_date)); memset(&m_shadeboost, 0, sizeof(m_shadeboost)); memset(&m_om_dss, 0, sizeof(m_om_dss)); + memset(&m_profiler, 0 , sizeof(m_profiler)); GLState::Clear(); // Reset the debug file @@ -94,6 +95,10 @@ GSDeviceOGL::~GSDeviceOGL() GL_PUSH("GSDeviceOGL destructor"); + if (GLLoader::in_replayer) { + GenerateProfilerData(); + } + // Clean vertex buffer state delete m_va; @@ -139,6 +144,51 @@ GSDeviceOGL::~GSDeviceOGL() m_shader = NULL; } +void GSDeviceOGL::GenerateProfilerData() +{ + if (m_profiler.last_query < 3) return; + + // Point to the last query + m_profiler.last_query--; + + // Wait latest quey to get valid result + GLuint available = 0; + while (!available) { + glGetQueryObjectuiv(m_profiler.timer(), GL_QUERY_RESULT_AVAILABLE, &available); + } + + uint64 time_start; + uint64 time_end; + + uint64 min_time = 0xFFFFFFFFFFFFFFFFull; + uint64 max_time = 0; + uint64 total = 0; + + glGetQueryObjectui64v(m_profiler.timer_query[0], GL_QUERY_RESULT, &time_start); + for (uint32 q = 1; q < m_profiler.last_query; q++) { + glGetQueryObjectui64v(m_profiler.timer_query[q], GL_QUERY_RESULT, &time_end); + uint64 t = time_end - time_start; + + min_time = std::min(t, min_time); + max_time = std::max(t, max_time); + total += t; + + time_start = time_end; + } + + glDeleteQueries(1 << 16, m_profiler.timer_query); + + // FIXME remove 1/linux_replay frame info + // Add fps, deviation + // remove glFinish + + double ms = 0.000001; + fprintf(stderr, "\nGenerateProfilerData:\n"); + fprintf(stderr, "Min %f\n", (double)min_time * ms); + fprintf(stderr, "Mean %f\n", (double)total/(double)m_profiler.last_query * ms); + fprintf(stderr, "Max %f\n", (double)max_time * ms); +} + GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int fmt) { GL_PUSH("Create surface"); @@ -248,6 +298,11 @@ bool GSDeviceOGL::Create(GSWnd* wnd) glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // Some timers to help profiling + if (GLLoader::in_replayer) { + glCreateQueries(GL_TIMESTAMP, 1 << 16, m_profiler.timer_query); + } } // **************************************************************** @@ -504,6 +559,11 @@ void GSDeviceOGL::Flip() #endif m_wnd->Flip(); + + if (GLLoader::in_replayer) { + glQueryCounter(m_profiler.timer(), GL_TIMESTAMP); + m_profiler.last_query++; + } } void GSDeviceOGL::BeforeDraw() diff --git a/plugins/GSdx/GSDeviceOGL.h b/plugins/GSdx/GSDeviceOGL.h index 3a16207bbf..b852bd6a07 100644 --- a/plugins/GSdx/GSDeviceOGL.h +++ b/plugins/GSdx/GSDeviceOGL.h @@ -449,6 +449,13 @@ public: GLuint ps; } m_shadeboost; + struct { + uint16 last_query; + GLuint timer_query[1<<16]; + + GLuint timer() { return timer_query[last_query]; } + } m_profiler; + GLuint m_vs[1]; GLuint m_gs[1<<2]; GLuint m_ps_ss[1<<4]; @@ -484,6 +491,8 @@ public: GSDeviceOGL(); virtual ~GSDeviceOGL(); + void GenerateProfilerData(); + static void CheckDebugLog(); // Used by OpenGL, so the same calling convention is required. static void APIENTRY DebugOutputToFile(GLenum gl_source, GLenum gl_type, GLuint id, GLenum gl_severity, GLsizei gl_length, const GLchar *gl_message, const void* userParam); @@ -555,7 +564,6 @@ public: void SelfShaderTestRun(const string& dir, const string& file, const PSSelector& sel, int& nb_shader); void SelfShaderTest(); - void SetupIA(const void* vertex, int vertex_count, const uint32* index, int index_count, int prim); void SetupPipeline(const VSSelector& vsel, const GSSelector& gsel, const PSSelector& psel); void SetupCB(const VSConstantBuffer* vs_cb, const PSConstantBuffer* ps_cb); diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index 67f9de19d4..ed2d1087cb 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -84,15 +84,17 @@ void GSWndGL::PopulateGlFunction() GL_EXT_LOAD(glClientWaitSync); GL_EXT_LOAD(glFlushMappedBufferRange); // Query object - GL_EXT_LOAD(glBeginQuery); - GL_EXT_LOAD(glEndQuery); - GL_EXT_LOAD(glGetQueryiv); - GL_EXT_LOAD(glGetQueryObjectiv); - GL_EXT_LOAD(glGetQueryObjectuiv); - GL_EXT_LOAD(glQueryCounter); - GL_EXT_LOAD(glGetQueryObjecti64v); - GL_EXT_LOAD(glGetQueryObjectui64v); - GL_EXT_LOAD(glGetInteger64v); + GL_EXT_LOAD_OPT(glBeginQuery); + GL_EXT_LOAD_OPT(glEndQuery); + GL_EXT_LOAD_OPT(glGetQueryiv); + GL_EXT_LOAD_OPT(glGetQueryObjectiv); + GL_EXT_LOAD_OPT(glGetQueryObjectuiv); + GL_EXT_LOAD_OPT(glQueryCounter); + GL_EXT_LOAD_OPT(glGetQueryObjecti64v); + GL_EXT_LOAD_OPT(glGetQueryObjectui64v); + GL_EXT_LOAD_OPT(glGetInteger64v); + GL_EXT_LOAD_OPT(glCreateQueries); + GL_EXT_LOAD_OPT(glDeleteQueries); // GL4.0 GL_EXT_LOAD_OPT(glBlendEquationSeparateiARB); GL_EXT_LOAD_OPT(glBlendFuncSeparateiARB);