Commit 2570bf33 authored by David C. Lonie's avatar David C. Lonie

Add vtkOpenGLRenderTimer.

Uses GL_TIMESTAMP queries to provide asynch, nestable GPU timings.
parent c3f96385
Pipeline #27030 passed with stage
......@@ -50,6 +50,7 @@ set(Module_SRCS
vtkOpenGLPolyDataMapper2D.cxx
vtkOpenGLProperty.cxx
vtkOpenGLRenderPass.cxx
vtkOpenGLRenderTimer.cxx
vtkOpenGLRenderUtilities.cxx
vtkOpenGLRenderWindow.cxx
vtkOpenGLRenderer.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,108 +377,48 @@ 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;
timer->Start();
}
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)
void vtkOpenGLFXAAFilter::EndTimeQuery(vtkOpenGLRenderTimer *timer)
{
#ifdef FXAA_BENCHMARK
if (!tracker || queryId == 0)
{ // Shouldn't happen, but just in case...
return;
}
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)
{
#ifdef FXAA_BENCHMARK
if (queryId == 0)
{
return false;
}
GLint ready;
glGetQueryObjectiv(queryId, GL_QUERY_RESULT_AVAILABLE, &ready);
vtkOpenGLCheckErrorMacro("Error after checking GL_TIME_ELAPSED status.");
if (!ready)
// 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();
}
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 ptime = this->PreparationTimer->GetElapsedMilliseconds();
float ftime = this->FXAATimer->GetElapsedMilliseconds();
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;
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"
......@@ -505,4 +429,8 @@ void vtkOpenGLFXAAFilter::PrintBenchmark()
<< " - Total time: " << ttime << "ms ("
<< ttimePerPixel << "ns per pixel)\n";
#endif // FXAA_BENCHMARK
this->PreparationTimer->Reset();
this->FXAATimer->Reset();
}
}
......@@ -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;
......
/*=========================================================================
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);
}
/*=========================================================================
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment