diff --git a/Rendering/OpenGL2/CMakeLists.txt b/Rendering/OpenGL2/CMakeLists.txt index 3e16cae7c2b36a521cd220dc4d466ce505f9a74a..b9f0ef9b2bbab953a7270806e123ee6f38eb4f2e 100644 --- a/Rendering/OpenGL2/CMakeLists.txt +++ b/Rendering/OpenGL2/CMakeLists.txt @@ -50,6 +50,7 @@ set(Module_SRCS vtkOpenGLPolyDataMapper2D.cxx vtkOpenGLProperty.cxx vtkOpenGLRenderPass.cxx + vtkOpenGLRenderTimer.cxx vtkOpenGLRenderUtilities.cxx vtkOpenGLRenderWindow.cxx vtkOpenGLRenderer.cxx diff --git a/Rendering/OpenGL2/vtkOpenGLFXAAFilter.cxx b/Rendering/OpenGL2/vtkOpenGLFXAAFilter.cxx index c2d77dd2752f650d5e1b813eb91299ec0e238bfc..cae8676745bed4cd2cc3f07bac1b4a9521c2c17c 100644 --- a/Rendering/OpenGL2/vtkOpenGLFXAAFilter.cxx +++ b/Rendering/OpenGL2/vtkOpenGLFXAAFilter.cxx @@ -22,6 +22,7 @@ #include "vtkOpenGLBufferObject.h" #include "vtkOpenGLError.h" #include "vtkOpenGLRenderer.h" +#include "vtkOpenGLRenderTimer.h" #include "vtkOpenGLRenderUtilities.h" #include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLShaderCache.h" @@ -97,21 +98,17 @@ void vtkOpenGLFXAAFilter::Execute(vtkOpenGLRenderer *ren) assert(ren); this->Renderer = ren; - this->StartTimeQuery(this->PreparationTimeQuery, - this->PreparationTimeQueryActive); - + this->StartTimeQuery(this->PreparationTimer); this->Prepare(); this->LoadInput(); + this->EndTimeQuery(this->PreparationTimer); - this->EndTimeQuery(this->PreparationTimeQuery, - this->PreparationTimeQueryActive); - this->StartTimeQuery(this->FXAATimeQuery, this->FXAATimeQueryActive); - + this->StartTimeQuery(this->FXAATimer); this->ApplyFilter(); - - this->EndTimeQuery(this->FXAATimeQuery, this->FXAATimeQueryActive); + this->EndTimeQuery(this->FXAATimer); this->Finalize(); + this->PrintBenchmark(); this->Renderer = NULL; } @@ -162,12 +159,8 @@ void vtkOpenGLFXAAFilter::SetDebugOptionValue(vtkFXAAOptions::DebugOption opt) vtkOpenGLFXAAFilter::vtkOpenGLFXAAFilter() : BlendState(false), DepthTestState(false), - PreparationTimeQueryActive(false), - FXAATimeQueryActive(false), - PreparationTimeQuery(0), - FXAATimeQuery(0), - PreparationTime(0), - FXAATime(0), + PreparationTimer(new vtkOpenGLRenderTimer), + FXAATimer(new vtkOpenGLRenderTimer), RelativeContrastThreshold(1.f/8.f), HardContrastThreshold(1.f/16.f), SubpixelBlendLimit(3.f/4.f), @@ -189,6 +182,8 @@ vtkOpenGLFXAAFilter::vtkOpenGLFXAAFilter() vtkOpenGLFXAAFilter::~vtkOpenGLFXAAFilter() { this->FreeGLObjects(); + delete PreparationTimer; + delete FXAATimer; } //------------------------------------------------------------------------------ @@ -243,17 +238,6 @@ void vtkOpenGLFXAAFilter::FreeGLObjects() // DeleteHelper(this->Program); // Managed by the shader cache DeleteHelper(this->VAO); DeleteHelper(this->VBO); - - if (this->FXAATimeQuery > 0) - { - glDeleteQueries(1, &this->FXAATimeQuery); - this->FXAATimeQuery = 0; - } - if (this->PreparationTimeQuery > 0) - { - glDeleteQueries(1, &this->PreparationTimeQuery); - this->PreparationTimeQuery = 0; - } } //------------------------------------------------------------------------------ @@ -393,116 +377,60 @@ void vtkOpenGLFXAAFilter::Finalize() } vtkOpenGLCheckErrorMacro("Error after restoring GL state."); - -#ifdef FXAA_BENCHMARK - if (this->GetTimeQueryResult(this->PreparationTimeQuery, - this->PreparationTime) || - this->GetTimeQueryResult(this->FXAATimeQuery, - this->FXAATime)) - { - this->PrintBenchmark(); - } -#endif // FXAA_BENCHMARK } //------------------------------------------------------------------------------ -void vtkOpenGLFXAAFilter::StartTimeQuery(unsigned int &queryId, bool &tracker) +void vtkOpenGLFXAAFilter::StartTimeQuery(vtkOpenGLRenderTimer *timer) { -#ifdef FXAA_BENCHMARK - // Don't start a new query until the old results are in: - if (tracker || queryId != 0) + // Since it may take a few frames for the results to become available, + // check if we've started the timer already. + if (!timer->Started()) { - return; - } - - glGenQueries(1, &queryId); - glBeginQuery(GL_TIME_ELAPSED, queryId); - tracker = true; - - vtkOpenGLCheckErrorMacro("Error after starting GL_TIME_ELAPSED query."); -#else // FXAA_BENCHMARK - (void)queryId; - (void)tracker; -#endif // FXAA_BENCHMARK -} - -//------------------------------------------------------------------------------ -void vtkOpenGLFXAAFilter::EndTimeQuery(unsigned int &queryId, bool &tracker) -{ -#ifdef FXAA_BENCHMARK - if (!tracker || queryId == 0) - { // Shouldn't happen, but just in case... - return; + timer->Start(); } - - glEndQuery(GL_TIME_ELAPSED); - tracker = false; - - vtkOpenGLCheckErrorMacro("Error after ending GL_TIME_ELAPSED query."); -#else // FXAA_BENCHMARK - (void)queryId; - (void)tracker; -#endif // FXAA_BENCHMARK } //------------------------------------------------------------------------------ -bool vtkOpenGLFXAAFilter::GetTimeQueryResult(unsigned int &queryId, - unsigned int &result) +void vtkOpenGLFXAAFilter::EndTimeQuery(vtkOpenGLRenderTimer *timer) { -#ifdef FXAA_BENCHMARK - if (queryId == 0) + // Since it may take a few frames for the results to become available, + // check if we've stopped the timer already. + if (!timer->Stopped()) { - return false; + timer->Stop(); } - - GLint ready; - glGetQueryObjectiv(queryId, GL_QUERY_RESULT_AVAILABLE, &ready); - vtkOpenGLCheckErrorMacro("Error after checking GL_TIME_ELAPSED status."); - if (!ready) - { - return false; - } - - glGetQueryObjectuiv(queryId, GL_QUERY_RESULT, &result); - vtkOpenGLCheckErrorMacro("Error after checking GL_TIME_ELAPSED result."); - - // Free the query: - glDeleteQueries(1, &queryId); - queryId = 0; - - return true; -#else // FXAA_BENCHMARK - (void)queryId; - (void)result; - return false; -#endif // FXAA_BENCHMARK } //------------------------------------------------------------------------------ void vtkOpenGLFXAAFilter::PrintBenchmark() { + if (this->PreparationTimer->Ready() && + this->FXAATimer->Ready()) + { + #ifdef FXAA_BENCHMARK - int numPixels = this->Input->GetWidth() * this->Input->GetHeight(); - float ptime = static_cast<float>(this->PreparationTime); - float ftime = static_cast<float>(this->FXAATime); - float ttime = ptime + ftime; - - float ptimePerPixel = ptime / numPixels; - float ftimePerPixel = ftime / numPixels; - float ttimePerPixel = ttime / numPixels; - - // Convert the non-per-pixel times to ms: - ptime *= 1e-6f; - ftime *= 1e-6f; - ttime *= 1e-6f; - - std::cerr << "FXAA Info:\n" - << " - Number of pixels: " << numPixels << "\n" - << " - Preparation time: " << ptime << "ms (" - << ptimePerPixel << "ns per pixel)\n" - << " - FXAA time: " << ftime << "ms (" - << ftimePerPixel << "ns per pixel)\n" - << " - Total time: " << ttime << "ms (" - << ttimePerPixel << "ns per pixel)\n"; + int numPixels = this->Input->GetWidth() * this->Input->GetHeight(); + float ptime = this->PreparationTimer->GetElapsedMilliseconds(); + float ftime = this->FXAATimer->GetElapsedMilliseconds(); + float ttime = ptime + ftime; + + float ptimePerPixel = (this->PreparationTimer->GetElapsedNanoseconds() / + static_cast<float>(numPixels)); + float ftimePerPixel = (this->FXAATimer->GetElapsedNanoseconds() / + static_cast<float>(numPixels)); + float ttimePerPixel = ptimePerPixel + ftimePerPixel; + + std::cerr << "FXAA Info:\n" + << " - Number of pixels: " << numPixels << "\n" + << " - Preparation time: " << ptime << "ms (" + << ptimePerPixel << "ns per pixel)\n" + << " - FXAA time: " << ftime << "ms (" + << ftimePerPixel << "ns per pixel)\n" + << " - Total time: " << ttime << "ms (" + << ttimePerPixel << "ns per pixel)\n"; #endif // FXAA_BENCHMARK + + this->PreparationTimer->Reset(); + this->FXAATimer->Reset(); + } } diff --git a/Rendering/OpenGL2/vtkOpenGLFXAAFilter.h b/Rendering/OpenGL2/vtkOpenGLFXAAFilter.h index 2e917cff5a1b4bf82d22298c5a6adfe257089e55..9f51b600f970b6d429582e9f16f7ec6b2d806159 100644 --- a/Rendering/OpenGL2/vtkOpenGLFXAAFilter.h +++ b/Rendering/OpenGL2/vtkOpenGLFXAAFilter.h @@ -45,6 +45,7 @@ class vtkFXAAOptions; class vtkOpenGLBufferObject; class vtkOpenGLVertexArrayObject; class vtkOpenGLRenderer; +class vtkOpenGLRenderTimer; class vtkShaderProgram; class vtkTextureObject; @@ -100,9 +101,8 @@ protected: void SubstituteFragmentShader(std::string &fragShader); void Finalize(); - void StartTimeQuery(unsigned int &queryId, bool &tracker); - void EndTimeQuery(unsigned int &queryId, bool &tracker); - bool GetTimeQueryResult(unsigned int &queryId, unsigned int &result); + void StartTimeQuery(vtkOpenGLRenderTimer *timer); + void EndTimeQuery(vtkOpenGLRenderTimer *timer); void PrintBenchmark(); // Cache GL state that we modify @@ -112,12 +112,8 @@ protected: int Viewport[4]; // x, y, width, height // Used to measure execution time: - bool PreparationTimeQueryActive; - bool FXAATimeQueryActive; - unsigned int PreparationTimeQuery; - unsigned int FXAATimeQuery; - unsigned int PreparationTime; - unsigned int FXAATime; + vtkOpenGLRenderTimer *PreparationTimer; + vtkOpenGLRenderTimer *FXAATimer; // Parameters: float RelativeContrastThreshold; diff --git a/Rendering/OpenGL2/vtkOpenGLRenderTimer.cxx b/Rendering/OpenGL2/vtkOpenGLRenderTimer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..512b49d0f256bcc0f5b50986ae19edced62c6474 --- /dev/null +++ b/Rendering/OpenGL2/vtkOpenGLRenderTimer.cxx @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkOpenGLRenderTimer.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "vtkOpenGLRenderTimer.h" + +#include "vtkObjectFactory.h" + +#include "vtk_glew.h" + +//------------------------------------------------------------------------------ +vtkOpenGLRenderTimer::vtkOpenGLRenderTimer() + : StartReady(false), + EndReady(false), + StartQuery(0), + EndQuery(0), + StartTime(0), + EndTime(0) +{ +} + +//------------------------------------------------------------------------------ +vtkOpenGLRenderTimer::~vtkOpenGLRenderTimer() +{ + this->Reset(); +} + +//------------------------------------------------------------------------------ +void vtkOpenGLRenderTimer::Reset() +{ + if (this->StartQuery != 0) + { + glDeleteQueries(1, static_cast<GLuint*>(&this->StartQuery)); + this->StartQuery = 0; + } + + if (this->EndQuery != 0) + { + glDeleteQueries(1, static_cast<GLuint*>(&this->EndQuery)); + this->EndQuery = 0; + } + + this->StartReady = false; + this->EndReady = false; + this->StartTime = 0; + this->EndTime = 0; +} + +//------------------------------------------------------------------------------ +void vtkOpenGLRenderTimer::Start() +{ + this->Reset(); + + glGenQueries(1, static_cast<GLuint*>(&this->StartQuery)); + glQueryCounter(static_cast<GLuint>(this->StartQuery), GL_TIMESTAMP); +} + +//------------------------------------------------------------------------------ +void vtkOpenGLRenderTimer::Stop() +{ + if (this->EndQuery != 0) + { + vtkGenericWarningMacro("vtkOpenGLRenderTimer::Stop called before " + "resetting. Ignoring."); + return; + } + + if (this->StartQuery == 0) + { + vtkGenericWarningMacro("vtkOpenGLRenderTimer::Stop called before " + "vtkOpenGLRenderTimer::Start. Ignoring."); + return; + } + + glGenQueries(1, static_cast<GLuint*>(&this->EndQuery)); + glQueryCounter(static_cast<GLuint>(this->EndQuery), GL_TIMESTAMP); +} + +//------------------------------------------------------------------------------ +bool vtkOpenGLRenderTimer::Started() +{ + return this->StartQuery != 0; +} + +//------------------------------------------------------------------------------ +bool vtkOpenGLRenderTimer::Stopped() +{ + return this->EndQuery != 0; +} + +//------------------------------------------------------------------------------ +bool vtkOpenGLRenderTimer::Ready() +{ + if (!this->StartReady) + { + GLint ready; + glGetQueryObjectiv(static_cast<GLuint>(this->StartQuery), + GL_QUERY_RESULT_AVAILABLE, &ready); + if (!ready) + { + return false; + } + + this->StartReady = true; + glGetQueryObjectui64v(static_cast<GLuint>(this->StartQuery), + GL_QUERY_RESULT, + reinterpret_cast<GLuint64*>(&this->StartTime)); + } + + if (!this->EndReady) + { + GLint ready; + glGetQueryObjectiv(static_cast<GLuint>(this->EndQuery), + GL_QUERY_RESULT_AVAILABLE, &ready); + if (!ready) + { + return false; + } + + this->EndReady = true; + glGetQueryObjectui64v(static_cast<GLuint>(this->EndQuery), + GL_QUERY_RESULT, + reinterpret_cast<GLuint64*>(&this->EndTime)); + } + + return true; +} + +//------------------------------------------------------------------------------ +float vtkOpenGLRenderTimer::GetElapsedSeconds() +{ + if (!this->Ready()) + { + return 0.f; + } + + return (this->EndTime - this->StartTime) * 1e-9f; +} + +//------------------------------------------------------------------------------ +float vtkOpenGLRenderTimer::GetElapsedMilliseconds() +{ + if (!this->Ready()) + { + return 0.f; + } + + return (this->EndTime - this->StartTime) * 1e-6f; +} + +//------------------------------------------------------------------------------ +vtkTypeUInt64 vtkOpenGLRenderTimer::GetElapsedNanoseconds() +{ + if (!this->Ready()) + { + return 0; + } + + return (this->EndTime - this->StartTime); +} diff --git a/Rendering/OpenGL2/vtkOpenGLRenderTimer.h b/Rendering/OpenGL2/vtkOpenGLRenderTimer.h new file mode 100644 index 0000000000000000000000000000000000000000..a9715250a4120d0e717abb44edd8f0e200216ffe --- /dev/null +++ b/Rendering/OpenGL2/vtkOpenGLRenderTimer.h @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkOpenGLRenderTimer.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +// .NAME vtkOpenGLRenderTimer - Asynchronously measures GPU execution time. +// +// .SECTION Description +// This class posts events to the OpenGL server to measure execution times +// of GPU processes. The queries are asynchronous and multiple +// vtkOpenGLRenderTimers may overlap / be nested. +// +// This uses GL_TIMESTAMP rather than GL_ELAPSED_TIME, since only one +// GL_ELAPSED_TIME query may be active at a time. + +#ifndef vtkOpenGLRenderTimer_h +#define vtkOpenGLRenderTimer_h + +#include "vtkRenderingOpenGL2Module.h" // For export macro +#include "vtkType.h" // For vtkTypeUint64, etc + +class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLRenderTimer +{ +public: + vtkOpenGLRenderTimer(); + ~vtkOpenGLRenderTimer(); + + // Description: + // Clear out any previous results and prepare for a new query. + void Reset(); + + // Description: + // Mark the start of a timed event. + void Start(); + + // Description: + // Mark the end of a timed event. + void Stop(); + + // Description: + // Returns true if the timer has been started. The query may not be ready yet. + bool Started(); + + // Description: + // Returns true if the timer has been stopped. The query may not be ready yet. + bool Stopped(); + + // Description: + // Returns true when the timing results are available. + bool Ready(); + + // Description: + // If Ready() returns true, get the elapsed time in the requested units. + float GetElapsedSeconds(); + float GetElapsedMilliseconds(); + vtkTypeUInt64 GetElapsedNanoseconds(); + +protected: + bool StartReady; + bool EndReady; + + vtkTypeUInt32 StartQuery; + vtkTypeUInt32 EndQuery; + + vtkTypeUInt64 StartTime; + vtkTypeUInt64 EndTime; + +private: + vtkOpenGLRenderTimer(const vtkOpenGLRenderTimer&) VTK_DELETE_FUNCTION; + void operator=(const vtkOpenGLRenderTimer&) VTK_DELETE_FUNCTION; +}; + +#endif // vtkOpenGLRenderTimer_h + +// VTK-HeaderTest-Exclude: vtkOpenGLRenderTimer.h