diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 748ef7c5a5..3d4c158a0b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -750,7 +750,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co const int text_y = -nameDynamicRect.height() / 2; // Compute background position/size - static const float SLIGHTLY_BEHIND = -0.05f; + static const float SLIGHTLY_IN_FRONT = 0.1f; const int border = 0.1f * nameDynamicRect.height(); const int left = text_x - border; const int bottom = text_y - border; @@ -765,16 +765,16 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co // Compute display name transform auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); - - // Render background slightly behind to avoid z-fighting - auto backgroundTransform = textTransform; - backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); - batch.setModelTransform(backgroundTransform); - DependencyManager::get()->bindSimpleProgram(batch); + batch.setModelTransform(textTransform); + + DependencyManager::get()->bindSimpleProgram(batch, false, true, true, true); DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor); // Render actual name QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); + + // Render text slightly in front to avoid z-fighting + textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize())); batch.setModelTransform(textTransform); renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); } diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 94f91a5ab7..fbfc3ea662 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -21,6 +21,7 @@ #include "Application.h" +#include "../octree/OctreePacketProcessor.h" #include "ui/OctreeStatsDialog.h" OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : @@ -53,7 +54,7 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _localElementsMemory = AddStatItem("Elements Memory"); _sendingMode = AddStatItem("Sending Mode"); - _processedPackets = AddStatItem("Processed Packets"); + _processedPackets = AddStatItem("Entity Packets"); _processedPacketsElements = AddStatItem("Processed Packets Elements"); _processedPacketsEntities = AddStatItem("Processed Packets Entities"); _processedPacketsTiming = AddStatItem("Processed Packets Timing"); @@ -155,6 +156,8 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { if (sinceLastRefresh < REFRESH_AFTER) { return QDialog::paintEvent(event); } + const int FLOATING_POINT_PRECISION = 3; + _lastRefresh = now; // Update labels @@ -245,7 +248,6 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { auto averageElementsPerPacket = entities->getAverageElementsPerPacket(); auto averageEntitiesPerPacket = entities->getAverageEntitiesPerPacket(); - auto averagePacketsPerSecond = entities->getAveragePacketsPerSecond(); auto averageElementsPerSecond = entities->getAverageElementsPerSecond(); auto averageEntitiesPerSecond = entities->getAverageEntitiesPerSecond(); @@ -253,21 +255,32 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { auto averageUncompressPerPacket = entities->getAverageUncompressPerPacket(); auto averageReadBitstreamPerPacket = entities->getAverageReadBitstreamPerPacket(); - QString averageElementsPerPacketString = locale.toString(averageElementsPerPacket); - QString averageEntitiesPerPacketString = locale.toString(averageEntitiesPerPacket); + QString averageElementsPerPacketString = locale.toString(averageElementsPerPacket, 'f', FLOATING_POINT_PRECISION); + QString averageEntitiesPerPacketString = locale.toString(averageEntitiesPerPacket, 'f', FLOATING_POINT_PRECISION); - QString averagePacketsPerSecondString = locale.toString(averagePacketsPerSecond); - QString averageElementsPerSecondString = locale.toString(averageElementsPerSecond); - QString averageEntitiesPerSecondString = locale.toString(averageEntitiesPerSecond); + QString averageElementsPerSecondString = locale.toString(averageElementsPerSecond, 'f', FLOATING_POINT_PRECISION); + QString averageEntitiesPerSecondString = locale.toString(averageEntitiesPerSecond, 'f', FLOATING_POINT_PRECISION); QString averageWaitLockPerPacketString = locale.toString(averageWaitLockPerPacket); QString averageUncompressPerPacketString = locale.toString(averageUncompressPerPacket); QString averageReadBitstreamPerPacketString = locale.toString(averageReadBitstreamPerPacket); label = _labels[_processedPackets]; + const OctreePacketProcessor& entitiesPacketProcessor = Application::getInstance()->getOctreePacketProcessor(); + + auto incomingPPS = entitiesPacketProcessor.getIncomingPPS(); + auto processedPPS = entitiesPacketProcessor.getProcessedPPS(); + auto treeProcessedPPS = entities->getAveragePacketsPerSecond(); + + QString incomingPPSString = locale.toString(incomingPPS, 'f', FLOATING_POINT_PRECISION); + QString processedPPSString = locale.toString(processedPPS, 'f', FLOATING_POINT_PRECISION); + QString treeProcessedPPSString = locale.toString(treeProcessedPPS, 'f', FLOATING_POINT_PRECISION); + statsValue.str(""); statsValue << - "" << qPrintable(averagePacketsPerSecondString) << " per second"; + "Network IN: " << qPrintable(incomingPPSString) << " PPS / " << + "Queue OUT: " << qPrintable(processedPPSString) << " PPS / " << + "Tree IN: " << qPrintable(treeProcessedPPSString) << " PPS"; label->setText(statsValue.str().c_str()); @@ -321,7 +334,7 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { } QString totalTrackedEditsString = locale.toString((uint)totalTrackedEdits); - QString updatesPerSecondString = locale.toString(updatesPerSecond); + QString updatesPerSecondString = locale.toString(updatesPerSecond, 'f', FLOATING_POINT_PRECISION); QString bytesPerEditString = locale.toString(bytesPerEdit); statsValue.str(""); diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 37774094de..17dc8d03a8 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -13,6 +13,7 @@ #include "Text3DOverlay.h" +#include #include #include @@ -114,6 +115,7 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); + DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); // Same font properties as textSize() diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 7603187e94..0c9b36dd87 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -36,10 +36,6 @@ void RenderableTextEntityItem::render(RenderArgs* args) { glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f); glm::vec3 dimensions = getDimensions(); - Transform transformToTopLeft = getTransformToCenter(); - transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left - transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed - // Render background glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND); glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND); @@ -48,15 +44,22 @@ void RenderableTextEntityItem::render(RenderArgs* args) { // Batch render calls Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + + Transform transformToTopLeft = getTransformToCenter(); + if (getFaceCamera()) { + //rotate about vertical to face the camera + glm::vec3 dPosition = args->_viewFrustum->getPosition() - getPosition(); + // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees + float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); + glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); + transformToTopLeft.setRotation(orientation); + } + transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left + transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed + batch.setModelTransform(transformToTopLeft); - //rotate about vertical to face the camera - if (getFaceCamera()) { - transformToTopLeft.postRotate(args->_viewFrustum->getOrientation()); - batch.setModelTransform(transformToTopLeft); - } - - DependencyManager::get()->bindSimpleProgram(batch, false, false); + DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true); DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, backgroundColor); float scale = _lineHeight / _textRenderer->getFontSize(); diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index ef272bb708..274e33a049 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -589,7 +589,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { void GLBackend::do_setStateDepthBias(Vec2 bias) { if ( (bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) { - if ((bias.x != 0.f) || (bias.y != 0.f)) { + if ((bias.x != 0.0f) || (bias.y != 0.0f)) { glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_POINT); diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 3c4b32b4ec..94dd04d44b 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -9,10 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "NodeList.h" #include "ReceivedPacketProcessor.h" #include "SharedUtil.h" +ReceivedPacketProcessor::ReceivedPacketProcessor() { + _lastWindowAt = usecTimestampNow(); +} + + void ReceivedPacketProcessor::terminating() { _hasPackets.wakeAll(); } @@ -25,6 +32,7 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendi lock(); _packets.push_back(networkPacket); _nodePacketCounts[sendingNode->getUUID()]++; + _lastWindowIncomingPackets++; unlock(); // Make sure to wake our actual processing thread because we now have packets for it to process. @@ -32,6 +40,24 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendi } bool ReceivedPacketProcessor::process() { + quint64 now = usecTimestampNow(); + quint64 sinceLastWindow = now - _lastWindowAt; + + + if (sinceLastWindow > USECS_PER_SECOND) { + lock(); + float secondsSinceLastWindow = sinceLastWindow / USECS_PER_SECOND; + float incomingPacketsPerSecondInWindow = (float)_lastWindowIncomingPackets / secondsSinceLastWindow; + _incomingPPS.updateAverage(incomingPacketsPerSecondInWindow); + + float processedPacketsPerSecondInWindow = (float)_lastWindowIncomingPackets / secondsSinceLastWindow; + _processedPPS.updateAverage(processedPacketsPerSecondInWindow); + + _lastWindowAt = now; + _lastWindowIncomingPackets = 0; + _lastWindowProcessedPackets = 0; + unlock(); + } if (_packets.size() == 0) { _waitingOnPacketsMutex.lock(); @@ -51,6 +77,7 @@ bool ReceivedPacketProcessor::process() { foreach(auto& packet, currentPackets) { processPacket(packet.getNode(), packet.getByteArray()); + _lastWindowProcessedPackets++; midProcess(); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index bcc9f9a1f5..84a954760c 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -21,7 +21,7 @@ class ReceivedPacketProcessor : public GenericThread { Q_OBJECT public: - ReceivedPacketProcessor() { } + ReceivedPacketProcessor(); /// Add packet from network receive thread to the processing queue. void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); @@ -47,6 +47,9 @@ public: /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } + float getIncomingPPS() const { return _incomingPPS.getAverage(); } + float getProcessedPPS() const { return _processedPPS.getAverage(); } + virtual void terminating(); public slots: @@ -80,6 +83,12 @@ protected: QWaitCondition _hasPackets; QMutex _waitingOnPacketsMutex; + + quint64 _lastWindowAt = 0; + int _lastWindowIncomingPackets = 0; + int _lastWindowProcessedPackets = 0; + SimpleMovingAverage _incomingPPS; + SimpleMovingAverage _processedPPS; }; #endif // hifi_ReceivedPacketProcessor_h diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index fee227600e..ba9e75bc74 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -50,37 +50,44 @@ static const std::string glowIntensityShaderHandle = "glowIntensity"; +gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) { + auto it = _simplePrograms.find(config); + if (it != _simplePrograms.end()) { + return it.value(); + } + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + if (config.isCulled()) { + state->setCullMode(gpu::State::CULL_BACK); + } else { + state->setCullMode(gpu::State::CULL_NONE); + } + state->setDepthTest(true, true, gpu::LESS_EQUAL); + if (config.hasDepthBias()) { + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _simplePrograms.insert(config, pipeline); + return pipeline; +} + void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - gpu::ShaderPointer programEmissive = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); + _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - gpu::Shader::makeProgram(*programEmissive, slotBindings); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - - gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State()); - stateCullNone->setCullMode(gpu::State::CULL_NONE); - stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL); - stateCullNone->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone)); - _simpleProgramEmissive = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, state)); - _simpleProgramEmissiveCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, stateCullNone)); + gpu::Shader::makeProgram(*_simpleShader, slotBindings); + gpu::Shader::makeProgram(*_emissiveShader, slotBindings); _viewState = viewState; loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); @@ -117,21 +124,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } -void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emmisive) { - if (emmisive) { - if (culled) { - batch.setPipeline(_simpleProgramEmissive); - } else { - batch.setPipeline(_simpleProgramEmissiveCullNone); - } - } else { - if (culled) { - batch.setPipeline(_simpleProgram); - } else { - batch.setPipeline(_simpleProgramCullNone); - } - } - if (!textured) { +void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, + bool emmisive, bool depthBias) { + SimpleProgramKey config{textured, culled, emmisive, depthBias}; + batch.setPipeline(getPipeline(config)); + + if (!config.isTextured()) { // If it is not textured, bind white texture and keep using textured pipeline batch.setUniformTexture(0, DependencyManager::get()->getWhiteTexture()); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index d948f2c305..53aac7ee93 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -24,6 +24,7 @@ class AbstractViewStateInterface; class RenderArgs; +class SimpleProgramKey; /// Handles deferred lighting for the bits that require it (voxels...) class DeferredLightingEffect : public Dependency { @@ -34,7 +35,8 @@ public: void init(AbstractViewStateInterface* viewState); /// Sets up the state necessary to render static untextured geometry with the simple program. - void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, bool emmisive = false); + void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, + bool emmisive = false, bool depthBias = false); //// Renders a solid sphere with the simple program. void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color); @@ -95,11 +97,11 @@ private: }; static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); + gpu::PipelinePointer getPipeline(SimpleProgramKey config); - gpu::PipelinePointer _simpleProgram; - gpu::PipelinePointer _simpleProgramCullNone; - gpu::PipelinePointer _simpleProgramEmissive; - gpu::PipelinePointer _simpleProgramEmissiveCullNone; + gpu::ShaderPointer _simpleShader; + gpu::ShaderPointer _emissiveShader; + QHash _simplePrograms; ProgramObject _directionalSkyboxLight; LightLocations _directionalSkyboxLightLocations; @@ -160,4 +162,53 @@ private: model::SkyboxPointer _skybox; }; +class SimpleProgramKey { +public: + enum FlagBit { + IS_TEXTURED_FLAG = 0, + IS_CULLED_FLAG, + IS_EMISSIVE_FLAG, + HAS_DEPTH_BIAS_FLAG, + + NUM_FLAGS, + }; + + enum Flag { + IS_TEXTURED = (1 << IS_TEXTURED_FLAG), + IS_CULLED = (1 << IS_CULLED_FLAG), + IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), + HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), + }; + typedef unsigned short Flags; + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTextured() const { return isFlag(IS_TEXTURED); } + bool isCulled() const { return isFlag(IS_CULLED); } + bool isEmissive() const { return isFlag(IS_EMISSIVE); } + bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() const { return *reinterpret_cast(this); } + + + SimpleProgramKey(bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false) { + _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | + (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); + } + + SimpleProgramKey(int bitmask) : _flags(bitmask) {} +}; + +inline uint qHash(const SimpleProgramKey& key, uint seed) { + return qHash(key.getRaw(), seed); +} + +inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { + return a.getRaw() == b.getRaw(); +} + #endif // hifi_DeferredLightingEffect_h