mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
first cut at auto-LOD adjustment
This commit is contained in:
parent
d6b71f19a8
commit
20a6f4eea9
8 changed files with 108 additions and 28 deletions
|
@ -2720,7 +2720,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... voxels...");
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRenderVoxels)) {
|
||||
_voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures));
|
||||
_voxels.render();
|
||||
|
||||
// double check that our LOD doesn't need to be auto-adjusted
|
||||
Menu::getInstance()->autoAdjustLOD(_fps);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2811,7 +2814,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
_mouseVoxel.s,
|
||||
_mouseVoxel.s);
|
||||
|
||||
_sharedVoxelSystem.render(true);
|
||||
_sharedVoxelSystem.render();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,8 @@ Menu::Menu() :
|
|||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
_boundaryLevelAdjust(0),
|
||||
_maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS)
|
||||
_maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS),
|
||||
_lastAdjust(usecTimestampNow())
|
||||
{
|
||||
Application *appInstance = Application::getInstance();
|
||||
|
||||
|
@ -1096,14 +1097,38 @@ void Menu::voxelStatsDetailsClosed() {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::autoAdjustLOD(float currentFPS) {
|
||||
bool changed = false;
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 elapsed = now - _lastAdjust;
|
||||
|
||||
if (elapsed > ADJUST_LOD_DOWN_DELAY && currentFPS < ADJUST_LOD_DOWN_FPS && _voxelSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||
_voxelSizeScale *= ADJUST_LOD_DOWN_BY;
|
||||
changed = true;
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD down... currentFPS=" << currentFPS << "_voxelSizeScale=" << _voxelSizeScale;
|
||||
}
|
||||
|
||||
if (elapsed > ADJUST_LOD_UP_DELAY && currentFPS > ADJUST_LOD_UP_FPS && _voxelSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||
_voxelSizeScale *= ADJUST_LOD_UP_BY;
|
||||
changed = true;
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD up... currentFPS=" << currentFPS << "_voxelSizeScale=" << _voxelSizeScale;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (_lodToolsDialog) {
|
||||
_lodToolsDialog->reloadSliders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::setVoxelSizeScale(float sizeScale) {
|
||||
_voxelSizeScale = sizeScale;
|
||||
Application::getInstance()->getVoxels()->redrawInViewVoxels();
|
||||
}
|
||||
|
||||
void Menu::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
||||
_boundaryLevelAdjust = boundaryLevelAdjust;
|
||||
Application::getInstance()->getVoxels()->redrawInViewVoxels();
|
||||
}
|
||||
|
||||
void Menu::lodTools() {
|
||||
|
|
|
@ -16,6 +16,18 @@
|
|||
|
||||
#include <AbstractMenuInterface.h>
|
||||
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
const float ADJUST_LOD_UP_FPS = 55.0;
|
||||
|
||||
const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 5;
|
||||
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
|
||||
|
||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = TREE_SCALE * 1.0f;
|
||||
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
|
||||
enum FrustumDrawMode {
|
||||
FRUSTUM_DRAW_MODE_ALL,
|
||||
FRUSTUM_DRAW_MODE_VECTORS,
|
||||
|
@ -68,6 +80,7 @@ public:
|
|||
void handleViewFrustumOffsetKeyModifier(int key);
|
||||
|
||||
// User Tweakable LOD Items
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void setVoxelSizeScale(float sizeScale);
|
||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
|
@ -154,6 +167,7 @@ private:
|
|||
int _maxVoxelPacketsPerSecond;
|
||||
QMenu* _activeScriptsMenu;
|
||||
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
|
||||
quint64 _lastAdjust;
|
||||
};
|
||||
|
||||
namespace MenuOption {
|
||||
|
|
|
@ -99,6 +99,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
|||
|
||||
_culledOnce = false;
|
||||
_inhideOutOfView = false;
|
||||
|
||||
_lastKnownVoxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
_lastKnownBoundaryLevelAdjust = 0;
|
||||
}
|
||||
|
||||
void VoxelSystem::elementDeleted(OctreeElement* element) {
|
||||
|
@ -249,6 +252,9 @@ VoxelSystem::~VoxelSystem() {
|
|||
delete _tree;
|
||||
}
|
||||
|
||||
|
||||
// This is called by the main application thread on both the initialization of the application and when
|
||||
// the preferences dialog box is called/saved
|
||||
void VoxelSystem::setMaxVoxels(int maxVoxels) {
|
||||
if (maxVoxels == _maxVoxels) {
|
||||
return;
|
||||
|
@ -267,6 +273,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) {
|
|||
}
|
||||
}
|
||||
|
||||
// This is called by the main application thread on both the initialization of the application and when
|
||||
// the use voxel shader menu item is chosen
|
||||
void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
|
||||
if (_useVoxelShader == useVoxelShader) {
|
||||
return;
|
||||
|
@ -330,7 +338,7 @@ void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) {
|
|||
|
||||
void VoxelSystem::cleanupVoxelMemory() {
|
||||
if (_initialized) {
|
||||
_bufferWriteLock.lock();
|
||||
_readArraysLock.lockForWrite();
|
||||
_initialized = false; // no longer initialized
|
||||
if (_useVoxelShader) {
|
||||
// these are used when in VoxelShader mode.
|
||||
|
@ -368,7 +376,7 @@ void VoxelSystem::cleanupVoxelMemory() {
|
|||
delete[] _writeVoxelDirtyArray;
|
||||
delete[] _readVoxelDirtyArray;
|
||||
_writeVoxelDirtyArray = _readVoxelDirtyArray = NULL;
|
||||
_bufferWriteLock.unlock();
|
||||
_readArraysLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +409,7 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice
|
|||
}
|
||||
|
||||
void VoxelSystem::initVoxelMemory() {
|
||||
_bufferWriteLock.lock();
|
||||
_readArraysLock.lockForWrite();
|
||||
|
||||
_memoryUsageRAM = 0;
|
||||
_memoryUsageVBO = 0; // our VBO allocations as we know them
|
||||
|
@ -516,7 +524,7 @@ void VoxelSystem::initVoxelMemory() {
|
|||
|
||||
_initialized = true;
|
||||
|
||||
_bufferWriteLock.unlock();
|
||||
_readArraysLock.unlock();
|
||||
}
|
||||
|
||||
void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const {
|
||||
|
@ -646,7 +654,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
}
|
||||
|
||||
_inSetupNewVoxelsForDrawing = true;
|
||||
|
||||
|
||||
bool didWriteFullVBO = _writeRenderFullVBO;
|
||||
if (_tree->isDirty()) {
|
||||
static char buffer[64] = { 0 };
|
||||
|
@ -673,7 +681,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
}
|
||||
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
_bufferWriteLock.lock();
|
||||
_readArraysLock.lockForWrite();
|
||||
|
||||
if (_voxelsUpdated) {
|
||||
_voxelsDirty=true;
|
||||
|
@ -682,7 +690,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
// copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated
|
||||
copyWrittenDataToReadArrays(didWriteFullVBO);
|
||||
|
||||
_bufferWriteLock.unlock();
|
||||
_readArraysLock.unlock();
|
||||
|
||||
quint64 end = usecTimestampNow();
|
||||
int elapsedmsec = (end - start) / 1000;
|
||||
|
@ -713,8 +721,8 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
|||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
{
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" );
|
||||
_bufferWriteLock.lock();
|
||||
"setupNewVoxelsForDrawingSingleNode()... _readArraysLock.lockForWrite();" );
|
||||
_readArraysLock.lockForWrite();
|
||||
}
|
||||
|
||||
_voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
|
||||
|
@ -725,7 +733,7 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
|||
// after...
|
||||
_voxelsUpdated = 0;
|
||||
|
||||
_bufferWriteLock.unlock();
|
||||
_readArraysLock.unlock();
|
||||
|
||||
quint64 end = usecTimestampNow();
|
||||
int elapsedmsec = (end - start) / 1000;
|
||||
|
@ -733,8 +741,12 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
|||
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
|
||||
}
|
||||
|
||||
void VoxelSystem::checkForCulling() {
|
||||
void VoxelSystem::recreateVoxelGeometryInView() {
|
||||
// this is a temporary solution... we need a full implementation that actually does a full redraw into clean VBOs
|
||||
hideOutOfView(true);
|
||||
}
|
||||
|
||||
void VoxelSystem::checkForCulling() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");
|
||||
quint64 start = usecTimestampNow();
|
||||
|
||||
|
@ -762,7 +774,20 @@ void VoxelSystem::checkForCulling() {
|
|||
_hasRecentlyChanged = false;
|
||||
}
|
||||
|
||||
hideOutOfView(forceFullFrustum);
|
||||
// This would be a good place to do a special processing pass, for example, switching the LOD of the scene
|
||||
bool fullRedraw = (_lastKnownVoxelSizeScale != Menu::getInstance()->getVoxelSizeScale() ||
|
||||
_lastKnownBoundaryLevelAdjust != Menu::getInstance()->getBoundaryLevelAdjust());
|
||||
|
||||
// track that these values
|
||||
_lastKnownVoxelSizeScale = Menu::getInstance()->getVoxelSizeScale();
|
||||
_lastKnownBoundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust();
|
||||
|
||||
if (fullRedraw) {
|
||||
// this will remove all old geometry and recreate the correct geometry for all in view voxels
|
||||
recreateVoxelGeometryInView();
|
||||
} else {
|
||||
hideOutOfView(forceFullFrustum);
|
||||
}
|
||||
|
||||
if (forceFullFrustum) {
|
||||
quint64 endViewCulling = usecTimestampNow();
|
||||
|
@ -1197,7 +1222,8 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::render(bool texture) {
|
||||
void VoxelSystem::render() {
|
||||
bool texture = Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures);
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "render()");
|
||||
|
||||
|
@ -1404,11 +1430,7 @@ void VoxelSystem::killLocalVoxels() {
|
|||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
void VoxelSystem::redrawInViewVoxels() {
|
||||
hideOutOfView(true);
|
||||
}
|
||||
|
||||
|
||||
// only called on main thread
|
||||
bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData) {
|
||||
_nodeCount++;
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
|
||||
|
@ -1416,12 +1438,15 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void
|
|||
return true;
|
||||
}
|
||||
|
||||
// only called on main thread, and also always followed by a call to cleanupVoxelMemory()
|
||||
// you shouldn't be calling this on any other thread or without also cleaning up voxel memory
|
||||
void VoxelSystem::clearAllNodesBufferIndex() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"VoxelSystem::clearAllNodesBufferIndex()");
|
||||
_nodeCount = 0;
|
||||
_tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read
|
||||
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
|
||||
clearFreeBufferIndexes(); // this should be called too
|
||||
_tree->unlock();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
|
||||
qDebug("clearing buffer index of %d nodes", _nodeCount);
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
|
||||
virtual void init();
|
||||
void simulate(float deltaTime) { }
|
||||
void render(bool texture);
|
||||
void render();
|
||||
|
||||
void changeTree(VoxelTree* newTree);
|
||||
VoxelTree* getTree() const { return _tree; }
|
||||
|
@ -79,7 +79,6 @@ public:
|
|||
unsigned long getVoxelMemoryUsageGPU();
|
||||
|
||||
void killLocalVoxels();
|
||||
void redrawInViewVoxels();
|
||||
|
||||
virtual void removeOutOfView();
|
||||
virtual void hideOutOfView(bool forceFullFrustum = false);
|
||||
|
@ -151,6 +150,7 @@ protected:
|
|||
static const bool DONT_BAIL_EARLY; // by default we will bail early, if you want to force not bailing, then use this
|
||||
void setupNewVoxelsForDrawingSingleNode(bool allowBailEarly = true);
|
||||
void checkForCulling();
|
||||
void recreateVoxelGeometryInView();
|
||||
|
||||
glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const;
|
||||
|
||||
|
@ -211,6 +211,10 @@ private:
|
|||
|
||||
GLfloat* _readVerticesArray;
|
||||
GLubyte* _readColorsArray;
|
||||
|
||||
QReadWriteLock _readArraysLock;
|
||||
|
||||
|
||||
GLfloat* _writeVerticesArray;
|
||||
GLubyte* _writeColorsArray;
|
||||
bool* _writeVoxelDirtyArray;
|
||||
|
@ -253,9 +257,6 @@ private:
|
|||
GLuint _vboIndicesFront;
|
||||
GLuint _vboIndicesBack;
|
||||
|
||||
QMutex _bufferWriteLock;
|
||||
QMutex _treeLock;
|
||||
|
||||
ViewFrustum _lastKnownViewFrustum;
|
||||
ViewFrustum _lastStableViewFrustum;
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
@ -299,6 +300,9 @@ private:
|
|||
bool _useFastVoxelPipeline;
|
||||
|
||||
bool _inhideOutOfView;
|
||||
|
||||
float _lastKnownVoxelSizeScale;
|
||||
int _lastKnownBoundaryLevelAdjust;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -121,6 +121,12 @@ LodToolsDialog::~LodToolsDialog() {
|
|||
delete _boundaryLevelAdjust;
|
||||
}
|
||||
|
||||
void LodToolsDialog::reloadSliders() {
|
||||
_lodSize->setValue(Menu::getInstance()->getVoxelSizeScale() / TREE_SCALE);
|
||||
_boundaryLevelAdjust->setValue(Menu::getInstance()->getBoundaryLevelAdjust());
|
||||
_feedback->setText(getFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::sizeScaleValueChanged(int value) {
|
||||
float realValue = value * TREE_SCALE;
|
||||
Menu::getInstance()->setVoxelSizeScale(realValue);
|
||||
|
|
|
@ -28,6 +28,7 @@ public slots:
|
|||
void sizeScaleValueChanged(int value);
|
||||
void boundaryLevelValueChanged(int value);
|
||||
void resetClicked(bool checked);
|
||||
void reloadSliders();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
_alwaysDisplay(alwaysDisplay),
|
||||
_runningTotal(runningTotal),
|
||||
_totalCalls(totalCalls) { }
|
||||
|
||||
quint64 elapsed() const { return (usecTimestampNow() - _start); };
|
||||
|
||||
~PerformanceWarning();
|
||||
|
||||
|
|
Loading…
Reference in a new issue