Merge pull request #3601 from ZappoMan/frustumCullModelParts

Implement "segregation" of mesh groups
This commit is contained in:
samcake 2014-10-15 18:09:48 -07:00
commit 01b64d78e3
5 changed files with 383 additions and 111 deletions

View file

@ -46,7 +46,8 @@ Model::Model(QObject* parent) :
_url("http://invalid.com"),
_blendNumber(0),
_appliedBlendNumber(0),
_calculatedMeshBoxesValid(false) {
_calculatedMeshBoxesValid(false),
_meshesGroupsKnown(false) {
// we may have been created in the network thread, but we live in the main thread
moveToThread(Application::getInstance()->thread());
@ -271,6 +272,8 @@ void Model::reset() {
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f);
}
_meshesGroupsKnown = false;
}
bool Model::updateGeometry() {
@ -320,6 +323,7 @@ bool Model::updateGeometry() {
deleteGeometry();
_dilatedTextures.clear();
_geometry = geometry;
_meshesGroupsKnown = false;
setJointStates(newJointStates);
needToRebuild = true;
} else if (_jointStates.isEmpty()) {
@ -421,6 +425,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
_dilatedTextures.append(dilated);
}
}
if (!_meshesGroupsKnown) {
segregateMeshGroups();
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
@ -451,11 +459,30 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
mode == DEFAULT_RENDER_MODE);
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args);
//renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args);
int opaqueMeshPartsRendered = 0;
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
// render translucent meshes afterwards
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
renderMeshes(mode, true, 0.75f, args);
int translucentMeshPartsRendered = 0;
const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
@ -465,7 +492,15 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
renderMeshes(mode, true, 0.0f, args);
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
}
glDepthMask(true);
@ -488,6 +523,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
// restore all the default material settings
Application::getInstance()->setupWorldLight();
if (args) {
args->_translucentMeshPartsRendered = translucentMeshPartsRendered;
args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
}
return true;
}
@ -1207,6 +1247,7 @@ void Model::applyNextGeometry() {
// we retain a reference to the base geometry so that its reference count doesn't fall to zero
_baseGeometry = _nextBaseGeometry;
_geometry = _nextGeometry;
_meshesGroupsKnown = false;
_nextBaseGeometry.reset();
_nextGeometry.reset();
}
@ -1238,21 +1279,218 @@ void Model::deleteGeometry() {
_blendedBlendshapeCoefficients.clear();
}
void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) {
void Model::segregateMeshGroups() {
_meshesTranslucentTangents.clear();
_meshesTranslucent.clear();
_meshesTranslucentTangentsSpecular.clear();
_meshesTranslucentSpecular.clear();
_meshesTranslucentTangentsSkinned.clear();
_meshesTranslucentSkinned.clear();
_meshesTranslucentTangentsSpecularSkinned.clear();
_meshesTranslucentSpecularSkinned.clear();
_meshesOpaqueTangents.clear();
_meshesOpaque.clear();
_meshesOpaqueTangentsSpecular.clear();
_meshesOpaqueSpecular.clear();
_meshesOpaqueTangentsSkinned.clear();
_meshesOpaqueSkinned.clear();
_meshesOpaqueTangentsSpecularSkinned.clear();
_meshesOpaqueSpecularSkinned.clear();
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
for (int i = 0; i < networkMeshes.size(); i++) {
const NetworkMesh& networkMesh = networkMeshes.at(i);
const FBXMesh& mesh = geometry.meshes.at(i);
const MeshState& state = _meshStates.at(i);
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
bool hasTangents = !mesh.tangents.isEmpty();
bool hasSpecular = mesh.hasSpecularTexture();
bool isSkinned = state.clusterMatrices.size() > 1;
if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) {
_meshesTranslucent.append(i);
} else if (translucentMesh && hasTangents && !hasSpecular && !isSkinned) {
_meshesTranslucentTangents.append(i);
} else if (translucentMesh && hasTangents && hasSpecular && !isSkinned) {
_meshesTranslucentTangentsSpecular.append(i);
} else if (translucentMesh && !hasTangents && hasSpecular && !isSkinned) {
_meshesTranslucentSpecular.append(i);
} else if (translucentMesh && hasTangents && !hasSpecular && isSkinned) {
_meshesTranslucentTangentsSkinned.append(i);
} else if (translucentMesh && !hasTangents && !hasSpecular && isSkinned) {
_meshesTranslucentSkinned.append(i);
} else if (translucentMesh && hasTangents && hasSpecular && isSkinned) {
_meshesTranslucentTangentsSpecularSkinned.append(i);
} else if (translucentMesh && !hasTangents && hasSpecular && isSkinned) {
_meshesTranslucentSpecularSkinned.append(i);
} else if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) {
_meshesOpaque.append(i);
} else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) {
_meshesOpaqueTangents.append(i);
} else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) {
_meshesOpaqueTangentsSpecular.append(i);
} else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) {
_meshesOpaqueSpecular.append(i);
} else if (!translucentMesh && hasTangents && !hasSpecular && isSkinned) {
_meshesOpaqueTangentsSkinned.append(i);
} else if (!translucentMesh && !hasTangents && !hasSpecular && isSkinned) {
_meshesOpaqueSkinned.append(i);
} else if (!translucentMesh && hasTangents && hasSpecular && isSkinned) {
_meshesOpaqueTangentsSpecularSkinned.append(i);
} else if (!translucentMesh && !hasTangents && hasSpecular && isSkinned) {
_meshesOpaqueSpecularSkinned.append(i);
} else {
qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???";
}
}
_meshesGroupsKnown = true;
}
int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold,
bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) {
int meshPartsRendered = 0;
updateVisibleJointStates();
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts);
// depending on which parameters we were called with, pick the correct mesh group to render
QList<int>* whichList = NULL;
if (translucent && !hasTangents && !hasSpecular && !isSkinned) {
whichList = &_meshesTranslucent;
} else if (translucent && hasTangents && !hasSpecular && !isSkinned) {
whichList = &_meshesTranslucentTangents;
} else if (translucent && hasTangents && hasSpecular && !isSkinned) {
whichList = &_meshesTranslucentTangentsSpecular;
} else if (translucent && !hasTangents && hasSpecular && !isSkinned) {
whichList = &_meshesTranslucentSpecular;
} else if (translucent && hasTangents && !hasSpecular && isSkinned) {
whichList = &_meshesTranslucentTangentsSkinned;
} else if (translucent && !hasTangents && !hasSpecular && isSkinned) {
whichList = &_meshesTranslucentSkinned;
} else if (translucent && hasTangents && hasSpecular && isSkinned) {
whichList = &_meshesTranslucentTangentsSpecularSkinned;
} else if (translucent && !hasTangents && hasSpecular && isSkinned) {
whichList = &_meshesTranslucentSpecularSkinned;
} else if (!translucent && !hasTangents && !hasSpecular && !isSkinned) {
whichList = &_meshesOpaque;
} else if (!translucent && hasTangents && !hasSpecular && !isSkinned) {
whichList = &_meshesOpaqueTangents;
} else if (!translucent && hasTangents && hasSpecular && !isSkinned) {
whichList = &_meshesOpaqueTangentsSpecular;
} else if (!translucent && !hasTangents && hasSpecular && !isSkinned) {
whichList = &_meshesOpaqueSpecular;
} else if (!translucent && hasTangents && !hasSpecular && isSkinned) {
whichList = &_meshesOpaqueTangentsSkinned;
} else if (!translucent && !hasTangents && !hasSpecular && isSkinned) {
whichList = &_meshesOpaqueSkinned;
} else if (!translucent && hasTangents && hasSpecular && isSkinned) {
whichList = &_meshesOpaqueTangentsSpecularSkinned;
} else if (!translucent && !hasTangents && hasSpecular && isSkinned) {
whichList = &_meshesOpaqueSpecularSkinned;
} else {
qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???";
}
for (int i = 0; i < networkMeshes.size(); i++) {
if (!whichList) {
qDebug() << "unexpected!!! we don't know which list of meshes to render...";
return 0;
}
QList<int>& list = *whichList;
ProgramObject* program = &_program;
Locations* locations = &_locations;
ProgramObject* skinProgram = &_skinProgram;
SkinLocations* skinLocations = &_skinLocations;
GLenum specularTextureUnit = 0;
if (mode == SHADOW_RENDER_MODE) {
program = &_shadowProgram;
skinProgram = &_skinShadowProgram;
skinLocations = &_skinShadowLocations;
} else if (translucent && alphaThreshold == 0.0f) {
program = &_translucentProgram;
locations = &_translucentLocations;
skinProgram = &_skinTranslucentProgram;
skinLocations = &_skinTranslucentLocations;
} else if (hasTangents) {
if (hasSpecular) {
program = &_normalSpecularMapProgram;
locations = &_normalSpecularMapLocations;
skinProgram = &_skinNormalSpecularMapProgram;
skinLocations = &_skinNormalSpecularMapLocations;
specularTextureUnit = GL_TEXTURE2;
} else {
program = &_normalMapProgram;
locations = &_normalMapLocations;
skinProgram = &_skinNormalMapProgram;
skinLocations = &_skinNormalMapLocations;
}
} else if (hasSpecular) {
program = &_specularMapProgram;
locations = &_specularMapLocations;
skinProgram = &_skinSpecularMapProgram;
skinLocations = &_skinSpecularMapLocations;
specularTextureUnit = GL_TEXTURE1;
}
ProgramObject* activeProgram = program;
Locations* activeLocations = locations;
if (isSkinned) {
skinProgram->bind();
activeProgram = skinProgram;
activeLocations = skinLocations;
} else {
program->bind();
}
activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
// i is the "index" from the original networkMeshes QVector...
foreach (int i, list) {
// exit early if the translucency doesn't match what we're drawing
const NetworkMesh& networkMesh = networkMeshes.at(i);
const FBXMesh& mesh = geometry.meshes.at(i);
if (translucent ? (networkMesh.getTranslucentPartCount(mesh) == 0) :
(networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size())) {
continue;
}
const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bind();
int vertexCount = mesh.vertices.size();
@ -1280,52 +1518,11 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
ProgramObject* program = &_program;
Locations* locations = &_locations;
ProgramObject* skinProgram = &_skinProgram;
SkinLocations* skinLocations = &_skinLocations;
GLenum specularTextureUnit = 0;
if (mode == SHADOW_RENDER_MODE) {
program = &_shadowProgram;
skinProgram = &_skinShadowProgram;
skinLocations = &_skinShadowLocations;
} else if (translucent && alphaThreshold == 0.0f) {
program = &_translucentProgram;
locations = &_translucentLocations;
skinProgram = &_skinTranslucentProgram;
skinLocations = &_skinTranslucentLocations;
} else if (!mesh.tangents.isEmpty()) {
if (mesh.hasSpecularTexture()) {
program = &_normalSpecularMapProgram;
locations = &_normalSpecularMapLocations;
skinProgram = &_skinNormalSpecularMapProgram;
skinLocations = &_skinNormalSpecularMapLocations;
specularTextureUnit = GL_TEXTURE2;
} else {
program = &_normalMapProgram;
locations = &_normalMapLocations;
skinProgram = &_skinNormalMapProgram;
skinLocations = &_skinNormalMapLocations;
}
} else if (mesh.hasSpecularTexture()) {
program = &_specularMapProgram;
locations = &_specularMapLocations;
skinProgram = &_skinSpecularMapProgram;
skinLocations = &_skinSpecularMapLocations;
specularTextureUnit = GL_TEXTURE1;
}
const MeshState& state = _meshStates.at(i);
ProgramObject* activeProgram = program;
Locations* activeLocations = locations;
glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation);
const MeshState& state = _meshStates.at(i);
if (state.clusterMatrices.size() > 1) {
skinProgram->bind();
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
(const float*)state.clusterMatrices.constData());
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
@ -1336,16 +1533,10 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
offset + vertexCount * sizeof(glm::vec4), 4);
skinProgram->enableAttributeArray(skinLocations->clusterIndices);
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
activeProgram = skinProgram;
activeLocations = skinLocations;
} else {
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
program->bind();
}
activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
if (mesh.blendshapes.isEmpty()) {
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
@ -1424,11 +1615,19 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
glActiveTexture(GL_TEXTURE0);
}
}
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
offset += part.quadIndices.size() * sizeof(int);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
GL_UNSIGNED_INT, (void*)offset);
offset += part.triangleIndices.size() * sizeof(int);
meshPartsRendered++;
if (part.quadIndices.size() > 0) {
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
offset += part.quadIndices.size() * sizeof(int);
}
if (part.triangleIndices.size() > 0) {
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
GL_UNSIGNED_INT, (void*)offset);
offset += part.triangleIndices.size() * sizeof(int);
}
if (args) {
const int INDICES_PER_TRIANGLE = 3;
@ -1465,8 +1664,10 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
}
glPopMatrix();
activeProgram->release();
}
activeProgram->release();
return meshPartsRendered;
}
void AnimationHandle::setURL(const QUrl& url) {

View file

@ -251,7 +251,7 @@ private:
void applyNextGeometry();
void deleteGeometry();
void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL);
int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL);
QVector<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms();
@ -332,6 +332,31 @@ private:
QVector<AABox> _calculatedMeshBoxes;
bool _calculatedMeshBoxesValid;
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
bool _meshesGroupsKnown;
QList<int> _meshesTranslucent;
QList<int> _meshesTranslucentTangents;
QList<int> _meshesTranslucentTangentsSpecular;
QList<int> _meshesTranslucentSpecular;
QList<int> _meshesTranslucentSkinned;
QList<int> _meshesTranslucentTangentsSkinned;
QList<int> _meshesTranslucentTangentsSpecularSkinned;
QList<int> _meshesTranslucentSpecularSkinned;
QList<int> _meshesOpaque;
QList<int> _meshesOpaqueTangents;
QList<int> _meshesOpaqueTangentsSpecular;
QList<int> _meshesOpaqueSpecular;
QList<int> _meshesOpaqueSkinned;
QList<int> _meshesOpaqueTangentsSkinned;
QList<int> _meshesOpaqueTangentsSpecularSkinned;
QList<int> _meshesOpaqueSpecularSkinned;
};
Q_DECLARE_METATYPE(QPointer<Model>)

View file

@ -221,8 +221,30 @@ void Stats::display(
int totalServers = NodeList::getInstance()->size();
lines = _expanded ? 5 : 3;
drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10);
int columnOneWidth = _generalStatsWidth;
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // make it 3 columns wide...
// we will also include room for 1 line per timing record and a header of 4 lines
lines += 4;
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
while (i.hasNext()) {
i.next();
if (includeTimingRecord(i.key())) {
lines++;
}
}
}
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, lines * STATS_PELS_PER_LINE + 10);
horizontalOffset += 5;
int columnOneHorizontalOffset = horizontalOffset;
char serverNodes[30];
sprintf(serverNodes, "Servers: %d", totalServers);
@ -249,6 +271,46 @@ void Stats::display(
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond, color);
}
// TODO: the display of these timing details should all be moved to JavaScript
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
// Timing details...
const int TIMER_OUTPUT_LINE_LENGTH = 1000;
char perfLine[TIMER_OUTPUT_LINE_LENGTH];
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 4 lines to be under the other columns
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
"-------------------------------------------------------- Function "
"------------------------------------------------------- --msecs- -calls--", color);
// First iterate all the records, and for the ones that should be included, insert them into
// a new Map sorted by average time...
QMap<float, QString> sortedRecords;
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
while (i.hasNext()) {
i.next();
if (includeTimingRecord(i.key())) {
float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
sortedRecords.insertMulti(averageTime, i.key());
}
}
QMapIterator<float, QString> j(sortedRecords);
j.toBack();
while (j.hasPrevious()) {
j.previous();
QString functionName = j.value();
const PerformanceTimerRecord& record = allRecords.value(functionName);
sprintf(perfLine, "%120s: %8.4f [%6llu]", qPrintable(functionName),
(float)record.getMovingAverage() / (float)USECS_PER_MSEC,
record.getCount());
verticalOffset += STATS_PELS_PER_LINE;
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine, color);
}
}
verticalOffset = 0;
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth +1;
@ -283,7 +345,11 @@ void Stats::display(
}
lines = _expanded ? 4 : 3;
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
// only draw our background if column one didn't draw a wide background
if (columnOneWidth == _generalStatsWidth) {
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
}
horizontalOffset += 5;
@ -319,7 +385,9 @@ void Stats::display(
lines = _expanded ? 8 : 3;
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
if (columnOneWidth == _generalStatsWidth) {
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
}
horizontalOffset += 5;
char avatarPosition[200];
@ -393,23 +461,9 @@ void Stats::display(
lines = _expanded ? 14 : 3;
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info
lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info
}
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
// we will also include room for 1 line per timing record and a header
lines += 1;
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
while (i.hasNext()) {
i.next();
if (includeTimingRecord(i.key())) {
lines++;
}
}
}
drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset,
lines * STATS_PELS_PER_LINE + 10);
horizontalOffset += 5;
@ -432,6 +486,12 @@ void Stats::display(
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
voxelStats.str("");
voxelStats << "Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered()
<< " Translucent:" << entities->getTranslucentMeshPartsRendered();
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
// Local Voxel Memory Usage
voxelStats.str("");
@ -585,32 +645,6 @@ void Stats::display(
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
}
PerformanceTimer::tallyAllTimerRecords();
// TODO: the display of these timing details should all be moved to JavaScript
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
// Timing details...
const int TIMER_OUTPUT_LINE_LENGTH = 300;
char perfLine[TIMER_OUTPUT_LINE_LENGTH];
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font,
"--------------------- Function -------------------- --msecs- -calls--", color);
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
while (i.hasNext()) {
i.next();
if (includeTimingRecord(i.key())) {
sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()),
(float)i.value().getMovingAverage() / (float)USECS_PER_MSEC,
i.value().getCount());
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color);
}
}
}
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
verticalOffset += STATS_PELS_PER_LINE; // space one line...

View file

@ -179,6 +179,9 @@ void OctreeRenderer::render(RenderMode renderMode) {
_trianglesRendered = args._trianglesRendered;
_quadsRendered = args._quadsRendered;
_translucentMeshPartsRendered = args._translucentMeshPartsRendered;
_opaqueMeshPartsRendered = args._opaqueMeshPartsRendered;
}
void OctreeRenderer::clear() {

View file

@ -74,7 +74,10 @@ public:
int getTrianglesRendered() const { return _trianglesRendered; }
int getQuadsRendered() const { return _quadsRendered; }
int getTranslucentMeshPartsRendered() const { return _translucentMeshPartsRendered; }
int getOpaqueMeshPartsRendered() const { return _opaqueMeshPartsRendered; }
protected:
Octree* _tree;
bool _managedTree;
@ -90,6 +93,9 @@ protected:
int _trianglesRendered;
int _quadsRendered;
int _translucentMeshPartsRendered;
int _opaqueMeshPartsRendered;
};
class RenderArgs {
@ -110,6 +116,9 @@ public:
int _trianglesRendered;
int _quadsRendered;
int _translucentMeshPartsRendered;
int _opaqueMeshPartsRendered;
};