diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3a6d88e307..72a6ab7afe 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -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& 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& 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* 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& 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(networkMesh.indexBuffer).bind(); int vertexCount = mesh.vertices.size(); @@ -1280,52 +1518,11 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold const_cast(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) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 2e11d2b75e..55a2eed9d1 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -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 createJointStates(const FBXGeometry& geometry); void initJointTransforms(); @@ -332,6 +332,31 @@ private: QVector _calculatedMeshBoxes; bool _calculatedMeshBoxesValid; + + void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes + + bool _meshesGroupsKnown; + + QList _meshesTranslucent; + QList _meshesTranslucentTangents; + QList _meshesTranslucentTangentsSpecular; + QList _meshesTranslucentSpecular; + + QList _meshesTranslucentSkinned; + QList _meshesTranslucentTangentsSkinned; + QList _meshesTranslucentTangentsSpecularSkinned; + QList _meshesTranslucentSpecularSkinned; + + QList _meshesOpaque; + QList _meshesOpaqueTangents; + QList _meshesOpaqueTangentsSpecular; + QList _meshesOpaqueSpecular; + + QList _meshesOpaqueSkinned; + QList _meshesOpaqueTangentsSkinned; + QList _meshesOpaqueTangentsSpecularSkinned; + QList _meshesOpaqueSpecularSkinned; + }; Q_DECLARE_METATYPE(QPointer) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ec5433c4c4..e78297323a 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -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& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator 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 sortedRecords; + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator 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 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& allRecords = PerformanceTimer::getAllTimerRecords(); - QMapIterator 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& allRecords = PerformanceTimer::getAllTimerRecords(); - QMapIterator 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... diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 9ea31077a5..21c085c5df 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -179,6 +179,9 @@ void OctreeRenderer::render(RenderMode renderMode) { _trianglesRendered = args._trianglesRendered; _quadsRendered = args._quadsRendered; + _translucentMeshPartsRendered = args._translucentMeshPartsRendered; + _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; + } void OctreeRenderer::clear() { diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index fbb02344af..6d734d113e 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -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; };