mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-05 01:20:13 +02:00
Move Hide/Show local voxels to a dedicated thread so that it doesn't slow performance of voxel packet processing
This commit is contained in:
parent
14129cd86d
commit
76b3bd4e6e
7 changed files with 132 additions and 70 deletions
|
@ -140,6 +140,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
#endif
|
||||
_stopNetworkReceiveThread(false),
|
||||
_voxelProcessor(),
|
||||
_voxelHideShowThread(&_voxels),
|
||||
_voxelEditSender(this),
|
||||
_packetCount(0),
|
||||
_packetsPerSecond(0),
|
||||
|
@ -329,6 +330,7 @@ void Application::initializeGL() {
|
|||
// create thread for parsing of voxel data independent of the main network and rendering threads
|
||||
_voxelProcessor.initialize(_enableProcessVoxelsThread);
|
||||
_voxelEditSender.initialize(_enableProcessVoxelsThread);
|
||||
_voxelHideShowThread.initialize(_enableProcessVoxelsThread);
|
||||
if (_enableProcessVoxelsThread) {
|
||||
qDebug("Voxel parsing thread created.\n");
|
||||
}
|
||||
|
@ -1401,6 +1403,7 @@ void Application::terminate() {
|
|||
}
|
||||
|
||||
_voxelProcessor.terminate();
|
||||
_voxelHideShowThread.terminate();
|
||||
_voxelEditSender.terminate();
|
||||
}
|
||||
|
||||
|
@ -2249,6 +2252,7 @@ void Application::updateThreads(float deltaTime) {
|
|||
// parse voxel packets
|
||||
if (!_enableProcessVoxelsThread) {
|
||||
_voxelProcessor.threadRoutine();
|
||||
_voxelHideShowThread.threadRoutine();
|
||||
_voxelEditSender.threadRoutine();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "ViewFrustum.h"
|
||||
#include "VoxelFade.h"
|
||||
#include "VoxelEditPacketSender.h"
|
||||
#include "VoxelHideShowThread.h"
|
||||
#include "VoxelPacketProcessor.h"
|
||||
#include "VoxelSystem.h"
|
||||
#include "VoxelImporter.h"
|
||||
|
@ -442,8 +443,9 @@ private:
|
|||
bool _stopNetworkReceiveThread;
|
||||
|
||||
bool _enableProcessVoxelsThread;
|
||||
VoxelPacketProcessor _voxelProcessor;
|
||||
VoxelEditPacketSender _voxelEditSender;
|
||||
VoxelPacketProcessor _voxelProcessor;
|
||||
VoxelHideShowThread _voxelHideShowThread;
|
||||
VoxelEditPacketSender _voxelEditSender;
|
||||
|
||||
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
||||
int _packetCount;
|
||||
|
|
46
interface/src/VoxelHideShowThread.cpp
Normal file
46
interface/src/VoxelHideShowThread.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// VoxelHideShowThread.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/1/13
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree.
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "VoxelHideShowThread.h"
|
||||
|
||||
VoxelHideShowThread::VoxelHideShowThread(VoxelSystem* theSystem) :
|
||||
_theSystem(theSystem) {
|
||||
}
|
||||
|
||||
bool VoxelHideShowThread::process() {
|
||||
const uint64_t MSECS_TO_USECS = 1000;
|
||||
const uint64_t SECS_TO_USECS = 1000 * MSECS_TO_USECS;
|
||||
const uint64_t FRAME_RATE = 60;
|
||||
const uint64_t USECS_PER_FRAME = SECS_TO_USECS / FRAME_RATE; // every 60fps
|
||||
|
||||
uint64_t start = usecTimestampNow();
|
||||
_theSystem->checkForCulling();
|
||||
uint64_t end = usecTimestampNow();
|
||||
uint64_t elapsed = end - start;
|
||||
|
||||
bool showExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
|
||||
if (showExtraDebugging && elapsed > USECS_PER_FRAME) {
|
||||
printf("VoxelHideShowThread::process()... checkForCulling took %llu\n", elapsed);
|
||||
}
|
||||
|
||||
if (isStillRunning()) {
|
||||
if (elapsed < USECS_PER_FRAME) {
|
||||
uint64_t sleepFor = USECS_PER_FRAME - elapsed;
|
||||
usleep(sleepFor);
|
||||
}
|
||||
}
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
31
interface/src/VoxelHideShowThread.h
Normal file
31
interface/src/VoxelHideShowThread.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// VoxelHideShowThread.h
|
||||
// voxel-server
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/1/13
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Threaded or non-threaded voxel persistence
|
||||
//
|
||||
|
||||
#ifndef __interface__VoxelHideShowThread__
|
||||
#define __interface__VoxelHideShowThread__
|
||||
|
||||
#include <GenericThread.h>
|
||||
#include "VoxelSystem.h"
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class VoxelHideShowThread : public virtual GenericThread {
|
||||
public:
|
||||
|
||||
VoxelHideShowThread(VoxelSystem* theSystem);
|
||||
|
||||
protected:
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
||||
private:
|
||||
VoxelSystem* _theSystem;
|
||||
};
|
||||
|
||||
#endif // __interface__VoxelHideShowThread__
|
|
@ -592,14 +592,15 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
|
|||
}
|
||||
|
||||
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
bool showTimingDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData()",showTimingDetails);
|
||||
|
||||
unsigned char command = *sourceBuffer;
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
|
||||
switch(command) {
|
||||
case PACKET_TYPE_VOXEL_DATA: {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"readBitstreamToTree()");
|
||||
|
||||
PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() PACKET_TYPE_VOXEL_DATA part...",showTimingDetails);
|
||||
|
||||
unsigned char* dataAt = sourceBuffer + numBytesPacketHeader;
|
||||
|
||||
VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt));
|
||||
|
@ -641,7 +642,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
VoxelPacketData packetData(packetIsCompressed);
|
||||
packetData.loadFinalizedContent(dataAt, sectionLength);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
|
||||
qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
|
||||
qDebug("VoxelSystem::parseData() ... Got Packet Section"
|
||||
" color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
|
||||
" subsection:%d sectionLength:%d uncompressed:%d\n",
|
||||
debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
|
||||
sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize());
|
||||
|
@ -657,12 +659,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!_useFastVoxelPipeline || _writeRenderFullVBO) {
|
||||
setupNewVoxelsForDrawing();
|
||||
} else {
|
||||
checkForCulling();
|
||||
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
|
||||
}
|
||||
|
||||
|
@ -689,8 +688,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
|
||||
_inSetupNewVoxelsForDrawing = true;
|
||||
|
||||
checkForCulling(); // check for out of view and deleted voxels...
|
||||
|
||||
bool didWriteFullVBO = _writeRenderFullVBO;
|
||||
if (_tree->isDirty()) {
|
||||
static char buffer[64] = { 0 };
|
||||
|
@ -776,68 +773,44 @@ void VoxelSystem::checkForCulling() {
|
|||
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");
|
||||
uint64_t start = usecTimestampNow();
|
||||
uint64_t sinceLastViewCulling = (start - _lastViewCulling) / 1000;
|
||||
|
||||
// These items used to be menu options, we are not defaulting to and only supporting these modes.
|
||||
bool constantCulling = true;
|
||||
bool performHideOutOfViewLogic = true;
|
||||
bool performRemoveOutOfViewLogic = false;
|
||||
|
||||
// If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view
|
||||
if (constantCulling || (
|
||||
(sinceLastViewCulling >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS))
|
||||
&& !isViewChanging()
|
||||
)
|
||||
) {
|
||||
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
|
||||
// them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which
|
||||
// can be expensive).
|
||||
if (performHideOutOfViewLogic) {
|
||||
|
||||
// track how long its been since we were last moving. If we have recently moved then only use delta frustums, if
|
||||
// it's been a long time since we last moved, then go ahead and do a full frustum cull.
|
||||
if (isViewChanging()) {
|
||||
_lastViewIsChanging = start;
|
||||
}
|
||||
uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000;
|
||||
|
||||
bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS));
|
||||
|
||||
// These has changed events will occur before we stop. So we need to remember this for when we finally have stopped
|
||||
// moving long enough to be enoughTime
|
||||
if (hasViewChanged()) {
|
||||
_hasRecentlyChanged = true;
|
||||
}
|
||||
|
||||
// If we have recently changed, but it's been enough time since we last moved, then we will do a full frustum
|
||||
// hide/show culling pass
|
||||
bool forceFullFrustum = enoughTime && _hasRecentlyChanged;
|
||||
|
||||
// in hide mode, we only track the full frustum culls, because we don't care about the partials.
|
||||
if (forceFullFrustum) {
|
||||
_lastViewCulling = start;
|
||||
_hasRecentlyChanged = false;
|
||||
}
|
||||
|
||||
hideOutOfView(forceFullFrustum);
|
||||
|
||||
if (forceFullFrustum) {
|
||||
uint64_t endViewCulling = usecTimestampNow();
|
||||
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
|
||||
}
|
||||
|
||||
} else if (performRemoveOutOfViewLogic) {
|
||||
_lastViewCulling = start;
|
||||
removeOutOfView();
|
||||
uint64_t endViewCulling = usecTimestampNow();
|
||||
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
|
||||
}
|
||||
|
||||
// Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So,
|
||||
// we should consider putting this someplace else... as this might be able to occur less frequently, and save us on
|
||||
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
|
||||
cleanupRemovedVoxels();
|
||||
// track how long its been since we were last moving. If we have recently moved then only use delta frustums, if
|
||||
// it's been a long time since we last moved, then go ahead and do a full frustum cull.
|
||||
if (isViewChanging()) {
|
||||
_lastViewIsChanging = start;
|
||||
}
|
||||
uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000;
|
||||
|
||||
bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS));
|
||||
|
||||
// These has changed events will occur before we stop. So we need to remember this for when we finally have stopped
|
||||
// moving long enough to be enoughTime
|
||||
if (hasViewChanged()) {
|
||||
_hasRecentlyChanged = true;
|
||||
}
|
||||
|
||||
// If we have recently changed, but it's been enough time since we last moved, then we will do a full frustum
|
||||
// hide/show culling pass
|
||||
bool forceFullFrustum = enoughTime && _hasRecentlyChanged;
|
||||
|
||||
// in hide mode, we only track the full frustum culls, because we don't care about the partials.
|
||||
if (forceFullFrustum) {
|
||||
_lastViewCulling = start;
|
||||
_hasRecentlyChanged = false;
|
||||
}
|
||||
|
||||
hideOutOfView(forceFullFrustum);
|
||||
|
||||
if (forceFullFrustum) {
|
||||
uint64_t endViewCulling = usecTimestampNow();
|
||||
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
|
||||
}
|
||||
|
||||
// Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So,
|
||||
// we should consider putting this someplace else... as this might be able to occur less frequently, and save us on
|
||||
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
|
||||
cleanupRemovedVoxels();
|
||||
|
||||
uint64_t sinceLastAudit = (start - _lastAudit) / 1000;
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ struct VoxelShaderVBOData
|
|||
class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public VoxelNodeUpdateHook,
|
||||
public NodeListHook, public DomainChangeListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class VoxelHideShowThread;
|
||||
|
||||
public:
|
||||
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||
~VoxelSystem();
|
||||
|
|
|
@ -63,6 +63,9 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi
|
|||
int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
|
||||
|
||||
int branchStartBit = parentSections * 3;
|
||||
// Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes
|
||||
// long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one
|
||||
// byte long.
|
||||
return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue