Implicit surface rendering via ray tracing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

203 lines
5.9 KiB

/*
* Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2013 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
//--------------------------------------------------------------------
#pragma once
#include <chrono>
#include <string>
#include <cstdarg>
#include "nvprint.hpp"
//-----------------------------------------------------------------------------
/// \struct TimeSampler
/// TimeSampler does time sampling work
//-----------------------------------------------------------------------------
struct TimeSampler
{
using Clock = std::chrono::steady_clock;
using TimePoint = typename Clock::time_point;
bool bNonStopRendering;
int renderCnt;
TimePoint start_time, end_time;
int timing_counter;
int maxTimeSamples;
int frameFPS;
double frameDT;
TimeSampler()
{
bNonStopRendering = true;
renderCnt = 1;
timing_counter = 0;
maxTimeSamples = 60;
frameDT = 1.0 / 60.0;
frameFPS = 0;
start_time = end_time = Clock::now();
}
inline double getFrameDT() { return frameDT; }
inline int getFPS() { return frameFPS; }
void resetSampling(int i = 10) { maxTimeSamples = i; }
bool update(bool bContinueToRender, bool* glitch = nullptr)
{
if(glitch)
*glitch = false;
bool updated = false;
if((timing_counter >= maxTimeSamples) && (maxTimeSamples > 0))
{
timing_counter = 0;
end_time = Clock::now();
// Get delta in seconds
frameDT = std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time).count();
// Linux/OSX etc. TODO
frameDT /= maxTimeSamples;
#define MAXDT (1.0 / 40.0)
#define MINDT (1.0 / 3000.0)
if(frameDT < MINDT)
{
frameDT = MINDT;
}
else if(frameDT > MAXDT)
{
frameDT = MAXDT;
if(glitch)
*glitch = true;
}
frameFPS = (int)(1.0 / frameDT);
// update the amount of samples to average, depending on the speed of the scene
maxTimeSamples = (int)(0.15 / (frameDT));
if(maxTimeSamples > 50)
maxTimeSamples = 50;
updated = true;
}
if(bContinueToRender || bNonStopRendering)
{
if(timing_counter == 0)
start_time = Clock::now();
timing_counter++;
}
return updated;
return true;
}
};
/**
\struct nvh::Stopwatch
\brief Timer in milliseconds.
Starts the timer at creation and the elapsed time is retrieved by calling `elapsed()`.
The timer can be reset if it needs to start timing later in the code execution.
Usage:
````cpp
nvh::Stopwatch sw;
...
LOGI("Elapsed: %f ms\n", sw.elapsed()); // --> Elapsed: 128.157 ms
````
*/
namespace nvh {
struct Stopwatch
{
Stopwatch() { reset(); }
void reset() { startTime = std::chrono::steady_clock::now(); }
double elapsed()
{
return std::chrono::duration<double>(std::chrono::steady_clock::now() - startTime).count() * 1000.;
}
std::chrono::time_point<std::chrono::steady_clock> startTime;
};
// Logging the time spent while alive in a scope.
// Usage: at beginning of a function:
// auto stimer = ScopedTimer("Time for doing X");
// Nesting timers is handled, but since the time is printed when it goes out of
// scope, printing anything else will break the output formatting.
struct ScopedTimer
{
ScopedTimer(const std::string& str) { init_(str); }
ScopedTimer(const char* fmt, ...)
{
std::string str(256, '\0'); // initial guess. ideally the first try fits
va_list args1, args2;
va_start(args1, fmt);
va_copy(args2, args1); // make a backup as vsnprintf may consume args1
int rc = vsnprintf(str.data(), str.size(), fmt, args1);
if(rc >= 0 && static_cast<size_t>(rc + 1) > str.size())
{
str.resize(rc + 1); // include storage for '\0'
rc = vsnprintf(str.data(), str.size(), fmt, args2);
}
va_end(args1);
assert(rc >= 0 && "vsnprintf error");
str.resize(rc >= 0 ? static_cast<size_t>(rc) : 0);
init_(str);
}
void init_(const std::string& str)
{
// If nesting timers, break the newline of the previous one
if(s_openNewline)
{
assert(s_nesting > 0);
LOGI("\n");
}
m_manualIndent = !str.empty() && (str[0] == ' ' || str[0] == '-' || str[0] == '|');
// Add indentation automatically if not already in str.
if(s_nesting > 0 && !m_manualIndent)
{
LOGI("%s", indent().c_str());
}
LOGI("%s", str.c_str());
s_openNewline = str.empty() || str[str.size() - 1] != '\n';
++s_nesting;
}
~ScopedTimer()
{
--s_nesting;
// If nesting timers and this is the second destructor in a row, indent and
// print "Total" as it won't be on the same line.
if(!s_openNewline && !m_manualIndent)
{
LOGI("%s|", indent().c_str());
}
else
{
LOGI(" ");
}
LOGI("-> %.3f ms\n", m_stopwatch.elapsed());
s_openNewline = false;
}
static std::string indent()
{
std::string result(static_cast<size_t>(s_nesting * 2), ' ');
for(int i = 0; i < s_nesting * 2; i += 2)
result[i] = '|';
return result;
}
nvh::Stopwatch m_stopwatch;
bool m_manualIndent = false;
static inline thread_local int s_nesting = 0;
static inline thread_local bool s_openNewline = false;
};
} // namespace nvh