mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
implement threaded voxel processing
This commit is contained in:
parent
996314012e
commit
b5e2bc2093
4 changed files with 174 additions and 40 deletions
|
@ -216,6 +216,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||||
#endif
|
#endif
|
||||||
_stopNetworkReceiveThread(false),
|
_stopNetworkReceiveThread(false),
|
||||||
|
_stopProcessVoxelsThread(false),
|
||||||
_packetCount(0),
|
_packetCount(0),
|
||||||
_packetsPerSecond(0),
|
_packetsPerSecond(0),
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
|
@ -240,7 +241,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
NodeList::getInstance()->addHook(this);
|
NodeList::getInstance()->addHook(this);
|
||||||
|
|
||||||
|
|
||||||
_enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
||||||
|
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
||||||
if (!_enableNetworkThread) {
|
if (!_enableNetworkThread) {
|
||||||
NodeList::getInstance()->getNodeSocket()->setBlocking(false);
|
NodeList::getInstance()->getNodeSocket()->setBlocking(false);
|
||||||
}
|
}
|
||||||
|
@ -364,6 +366,12 @@ void Application::initializeGL() {
|
||||||
pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL);
|
pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL);
|
||||||
qDebug("Network receive thread created.\n");
|
qDebug("Network receive thread created.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create thread for parsing of voxel data independent of the main network and rendering threads
|
||||||
|
if (_enableProcessVoxelsThread) {
|
||||||
|
pthread_create(&_processVoxelsThread, NULL, processVoxels, NULL);
|
||||||
|
qDebug("Voxel parsing thread created.\n");
|
||||||
|
}
|
||||||
|
|
||||||
// call terminate before exiting
|
// call terminate before exiting
|
||||||
connect(this, SIGNAL(aboutToQuit()), SLOT(terminate()));
|
connect(this, SIGNAL(aboutToQuit()), SLOT(terminate()));
|
||||||
|
@ -1169,6 +1177,11 @@ void Application::terminate() {
|
||||||
_stopNetworkReceiveThread = true;
|
_stopNetworkReceiveThread = true;
|
||||||
pthread_join(_networkReceiveThread, NULL);
|
pthread_join(_networkReceiveThread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_enableProcessVoxelsThread) {
|
||||||
|
_stopProcessVoxelsThread = true;
|
||||||
|
pthread_join(_processVoxelsThread, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||||
|
@ -2073,7 +2086,8 @@ void Application::initMenu() {
|
||||||
debugMenu->addAction("Calculate Tree Stats", this, SLOT(doTreeStats()), Qt::SHIFT | Qt::Key_S);
|
debugMenu->addAction("Calculate Tree Stats", this, SLOT(doTreeStats()), Qt::SHIFT | Qt::Key_S);
|
||||||
|
|
||||||
QMenu* renderDebugMenu = debugMenu->addMenu("Render Debugging Tools");
|
QMenu* renderDebugMenu = debugMenu->addMenu("Render Debugging Tools");
|
||||||
renderDebugMenu->addAction("Show Render Pipeline Warnings", this, SLOT(setRenderWarnings(bool)))->setCheckable(true);
|
(_renderPipelineWarnings = renderDebugMenu->addAction("Show Render Pipeline Warnings",
|
||||||
|
this, SLOT(setRenderWarnings(bool))))->setCheckable(true);
|
||||||
renderDebugMenu->addAction("Kill Local Voxels", this, SLOT(doKillLocalVoxels()), Qt::CTRL | Qt::Key_K);
|
renderDebugMenu->addAction("Kill Local Voxels", this, SLOT(doKillLocalVoxels()), Qt::CTRL | Qt::Key_K);
|
||||||
renderDebugMenu->addAction("Randomize Voxel TRUE Colors", this, SLOT(doRandomizeVoxelColors()), Qt::CTRL | Qt::Key_R);
|
renderDebugMenu->addAction("Randomize Voxel TRUE Colors", this, SLOT(doRandomizeVoxelColors()), Qt::CTRL | Qt::Key_R);
|
||||||
renderDebugMenu->addAction("FALSE Color Voxels Randomly", this, SLOT(doFalseRandomizeVoxelColors()));
|
renderDebugMenu->addAction("FALSE Color Voxels Randomly", this, SLOT(doFalseRandomizeVoxelColors()));
|
||||||
|
@ -2563,6 +2577,11 @@ void Application::update(float deltaTime) {
|
||||||
if (!_enableNetworkThread) {
|
if (!_enableNetworkThread) {
|
||||||
networkReceive(0);
|
networkReceive(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse voxel packets
|
||||||
|
if (!_enableProcessVoxelsThread) {
|
||||||
|
processVoxels(0);
|
||||||
|
}
|
||||||
|
|
||||||
//loop through all the other avatars and simulate them...
|
//loop through all the other avatars and simulate them...
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
@ -4015,6 +4034,75 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
||||||
return statsMessageLength;
|
return statsMessageLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Receive packets from other nodes/servers and decide what to do with them!
|
||||||
|
void* Application::processVoxels(void* args) {
|
||||||
|
Application* app = Application::getInstance();
|
||||||
|
while (!app->_stopProcessVoxelsThread) {
|
||||||
|
|
||||||
|
// check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that
|
||||||
|
if (app->_wantToKillLocalVoxels) {
|
||||||
|
app->_voxels.killLocalVoxels();
|
||||||
|
app->_wantToKillLocalVoxels = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (app->_voxelPackets.size() > 0) {
|
||||||
|
NetworkPacket& packet = app->_voxelPackets.front();
|
||||||
|
app->processVoxelPacket(packet.getSenderAddress(), packet.getData(), packet.getLength());
|
||||||
|
app->_voxelPackets.erase(app->_voxelPackets.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!app->_enableProcessVoxelsThread) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app->_enableProcessVoxelsThread) {
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::queueVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
_voxelPackets.push_back(NetworkPacket(senderAddress, packetData, packetLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::processVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
PerformanceWarning warn(_renderPipelineWarnings->isChecked(),"processVoxelPacket()");
|
||||||
|
ssize_t messageLength = packetLength;
|
||||||
|
|
||||||
|
// note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME
|
||||||
|
// immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first
|
||||||
|
// then process any remaining bytes as if it was another packet
|
||||||
|
if (packetData[0] == PACKET_TYPE_VOXEL_STATS) {
|
||||||
|
|
||||||
|
int statsMessageLength = parseVoxelStats(packetData, messageLength, senderAddress);
|
||||||
|
if (messageLength > statsMessageLength) {
|
||||||
|
packetData += statsMessageLength;
|
||||||
|
messageLength -= statsMessageLength;
|
||||||
|
if (!packetVersionMatch(packetData)) {
|
||||||
|
return; // bail since piggyback data doesn't match our versioning
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return; // bail since no piggyback data
|
||||||
|
}
|
||||||
|
} // fall through to piggyback message
|
||||||
|
|
||||||
|
if (_renderVoxels->isChecked()) {
|
||||||
|
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
|
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
||||||
|
voxelServer->lock();
|
||||||
|
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
||||||
|
_environment.parseData(&senderAddress, packetData, messageLength);
|
||||||
|
} else {
|
||||||
|
_voxels.setDataSourceID(voxelServer->getNodeID());
|
||||||
|
_voxels.parseData(packetData, messageLength);
|
||||||
|
_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
||||||
|
}
|
||||||
|
voxelServer->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Receive packets from other nodes/servers and decide what to do with them!
|
// Receive packets from other nodes/servers and decide what to do with them!
|
||||||
void* Application::networkReceive(void* args) {
|
void* Application::networkReceive(void* args) {
|
||||||
sockaddr senderAddress;
|
sockaddr senderAddress;
|
||||||
|
@ -4050,41 +4138,8 @@ void* Application::networkReceive(void* args) {
|
||||||
case PACKET_TYPE_ERASE_VOXEL:
|
case PACKET_TYPE_ERASE_VOXEL:
|
||||||
case PACKET_TYPE_VOXEL_STATS:
|
case PACKET_TYPE_VOXEL_STATS:
|
||||||
case PACKET_TYPE_ENVIRONMENT_DATA: {
|
case PACKET_TYPE_ENVIRONMENT_DATA: {
|
||||||
|
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||||
unsigned char* messageData = app->_incomingPacket;
|
app->queueVoxelPacket(senderAddress, app->_incomingPacket, bytesReceived);
|
||||||
ssize_t messageLength = bytesReceived;
|
|
||||||
|
|
||||||
// note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME
|
|
||||||
// immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first
|
|
||||||
// then process any remaining bytes as if it was another packet
|
|
||||||
if (messageData[0] == PACKET_TYPE_VOXEL_STATS) {
|
|
||||||
|
|
||||||
int statsMessageLength = app->parseVoxelStats(messageData, messageLength, senderAddress);
|
|
||||||
if (messageLength > statsMessageLength) {
|
|
||||||
messageData += statsMessageLength;
|
|
||||||
messageLength -= statsMessageLength;
|
|
||||||
if (!packetVersionMatch(messageData)) {
|
|
||||||
break; // bail since piggyback data doesn't match our versioning
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break; // bail since no piggyback data
|
|
||||||
}
|
|
||||||
} // fall through to piggyback message
|
|
||||||
|
|
||||||
if (app->_renderVoxels->isChecked()) {
|
|
||||||
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
|
||||||
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
|
||||||
voxelServer->lock();
|
|
||||||
if (messageData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
|
||||||
app->_environment.parseData(&senderAddress, messageData, messageLength);
|
|
||||||
} else {
|
|
||||||
app->_voxels.setDataSourceID(voxelServer->getNodeID());
|
|
||||||
app->_voxels.parseData(messageData, messageLength);
|
|
||||||
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
|
||||||
}
|
|
||||||
voxelServer->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_TYPE_BULK_AVATAR_DATA:
|
case PACKET_TYPE_BULK_AVATAR_DATA:
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
|
#include <NetworkPacket.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
||||||
|
@ -68,8 +69,6 @@ static const float NODE_KILLED_RED = 1.0f;
|
||||||
static const float NODE_KILLED_GREEN = 0.0f;
|
static const float NODE_KILLED_GREEN = 0.0f;
|
||||||
static const float NODE_KILLED_BLUE = 0.0f;
|
static const float NODE_KILLED_BLUE = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Application : public QApplication, public NodeListHook {
|
class Application : public QApplication, public NodeListHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -262,7 +261,11 @@ private:
|
||||||
QAction* checkedVoxelModeAction() const;
|
QAction* checkedVoxelModeAction() const;
|
||||||
|
|
||||||
static void attachNewHeadToNode(Node *newNode);
|
static void attachNewHeadToNode(Node *newNode);
|
||||||
static void* networkReceive(void* args);
|
static void* networkReceive(void* args); // network receive thread
|
||||||
|
|
||||||
|
static void* processVoxels(void* args); // voxel parsing thread
|
||||||
|
void processVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
void queueVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
// methodes handling menu settings
|
// methodes handling menu settings
|
||||||
typedef void(*settingsAction)(QSettings*, QAction*);
|
typedef void(*settingsAction)(QSettings*, QAction*);
|
||||||
|
@ -315,6 +318,7 @@ private:
|
||||||
QAction* _noise;
|
QAction* _noise;
|
||||||
QAction* _occlusionCulling;
|
QAction* _occlusionCulling;
|
||||||
QAction* _wantCollisionsOn;
|
QAction* _wantCollisionsOn;
|
||||||
|
QAction* _renderPipelineWarnings;
|
||||||
|
|
||||||
QAction* _renderCoverageMapV2;
|
QAction* _renderCoverageMapV2;
|
||||||
QAction* _renderCoverageMap;
|
QAction* _renderCoverageMap;
|
||||||
|
@ -452,6 +456,12 @@ private:
|
||||||
pthread_t _networkReceiveThread;
|
pthread_t _networkReceiveThread;
|
||||||
bool _stopNetworkReceiveThread;
|
bool _stopNetworkReceiveThread;
|
||||||
|
|
||||||
|
bool _enableProcessVoxelsThread;
|
||||||
|
pthread_t _processVoxelsThread;
|
||||||
|
bool _stopProcessVoxelsThread;
|
||||||
|
std::vector<NetworkPacket> _voxelPackets;
|
||||||
|
|
||||||
|
|
||||||
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
||||||
int _packetCount;
|
int _packetCount;
|
||||||
int _packetsPerSecond;
|
int _packetsPerSecond;
|
||||||
|
|
29
libraries/shared/src/NetworkPacket.cpp
Normal file
29
libraries/shared/src/NetworkPacket.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// NetworkPacket.cpp
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/9/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// A really simple class that stores a network packet between being received and being processed
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include "NetworkPacket.h"
|
||||||
|
|
||||||
|
NetworkPacket::NetworkPacket() : _packetLength(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkPacket::NetworkPacket(const NetworkPacket& packet) {
|
||||||
|
memcpy(&_senderAddress, &packet.getSenderAddress(), sizeof(_senderAddress));
|
||||||
|
_packetLength = packet.getLength();
|
||||||
|
memcpy(&_packetData[0], packet.getData(), _packetLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkPacket::NetworkPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
memcpy(&_senderAddress, &senderAddress, sizeof(_senderAddress));
|
||||||
|
_packetLength = packetLength;
|
||||||
|
memcpy(&_packetData[0], packetData, packetLength);
|
||||||
|
};
|
40
libraries/shared/src/NetworkPacket.h
Normal file
40
libraries/shared/src/NetworkPacket.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// NetworkPacket.h
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/9/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// A really simple class that stores a network packet between being received and being processed
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared_NetworkPacket__
|
||||||
|
#define __shared_NetworkPacket__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
|
||||||
|
#include "NodeList.h" // for MAX_PACKET_SIZE
|
||||||
|
|
||||||
|
class NetworkPacket {
|
||||||
|
public:
|
||||||
|
NetworkPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
NetworkPacket(const NetworkPacket& packet);
|
||||||
|
NetworkPacket();
|
||||||
|
//~NetworkPacket();
|
||||||
|
|
||||||
|
sockaddr& getSenderAddress() { return _senderAddress; };
|
||||||
|
ssize_t getLength() const { return _packetLength; };
|
||||||
|
unsigned char* getData() { return &_packetData[0]; };
|
||||||
|
|
||||||
|
const sockaddr& getSenderAddress() const { return _senderAddress; };
|
||||||
|
const unsigned char* getData() const { return &_packetData[0]; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
sockaddr _senderAddress;
|
||||||
|
ssize_t _packetLength;
|
||||||
|
unsigned char _packetData[MAX_PACKET_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__shared_NetworkPacket__) */
|
Loading…
Reference in a new issue