diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2019-10-18 14:35:40 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-11-14 06:37:38 +0100 |
commit | 50db67eb310fba162f73ac6fdf28a8457ce50b21 (patch) | |
tree | 788a6e72aac7ea848c443b6db4f25eb5215ef05d | |
parent | 38a3ceef605fb337066e441a4afeb4e460e6a26c (diff) |
PackUniformHash to QVector
Surprisingly it's hard to notice its effect in the speed of execution,
frame preparation looks to be more or less the same with the profiler.
However with vtune, the profiling traces show a huge difference with
QHash, mainly in time spent allocating memory. It shows a noticeable
reduction in CPU usage.
On bigscene-cpp with 600 entities
QHash -> On a 158s run, CPU time is 112s (70%)
free accounts for 26s (23%), malloc 24s (21%)
QVector -> On a 190s run, CPU time is 110s (58%)
free accounts for 5s (4.5%), malloc 4.7s (4.2%)
Change-Id: I880d44b1acf7f051e479ed356864c3caf407f23f
Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r-- | src/render/backend/commandexecuter.cpp | 6 | ||||
-rw-r--r-- | src/render/backend/uniform_p.h | 2 | ||||
-rw-r--r-- | src/render/materialsystem/shader.cpp | 6 | ||||
-rw-r--r-- | src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp | 6 | ||||
-rw-r--r-- | src/render/renderers/opengl/renderer/renderview.cpp | 16 | ||||
-rw-r--r-- | src/render/renderers/opengl/renderer/shaderparameterpack_p.h | 51 | ||||
-rw-r--r-- | tests/auto/render/renderviews/tst_renderviews.cpp | 13 |
7 files changed, 72 insertions, 28 deletions
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp index 3aea56ad0..5ed0c970d 100644 --- a/src/render/backend/commandexecuter.cpp +++ b/src/render/backend/commandexecuter.cpp @@ -248,10 +248,10 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack) const Render::PackUniformHash &uniforms = pack.uniforms(); QJsonArray uniformsArray; - for (auto it = uniforms.cbegin(), end = uniforms.cend(); it != end; ++it) { + for (int i = 0, m = uniforms.keys.size(); i < m; ++i) { QJsonObject uniformObj; - uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(it.key())); - const Render::UniformValue::ValueType type = it.value().valueType(); + uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(uniforms.keys.at(i))); + const Render::UniformValue::ValueType type = uniforms.values.at(i).valueType(); uniformObj.insert(QLatin1String("type"), type == Render::UniformValue::ScalarValue ? QLatin1String("value") diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h index 634c0cd96..c8731637c 100644 --- a/src/render/backend/uniform_p.h +++ b/src/render/backend/uniform_p.h @@ -227,7 +227,7 @@ public: return !(*this == other); } private: - // Allocate 4 floats on stack + // Allocate 16 floats on stack // For larger elements, heap allocation will be used QVarLengthArray<float, 16> m_data; diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index 017deabac..300a71b84 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -244,13 +244,13 @@ void Shader::prepareUniforms(ShaderParameterPack &pack) { const PackUniformHash &values = pack.uniforms(); - auto it = values.cbegin(); - const auto end = values.cend(); + auto it = values.keys.cbegin(); + const auto end = values.keys.cend(); while (it != end) { // Find if there's a uniform with the same name id for (const ShaderUniform &uniform : qAsConst(m_uniforms)) { - if (uniform.m_nameId == it.key()) { + if (uniform.m_nameId == *it) { pack.setSubmissionUniform(uniform); break; } diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index 991a8533d..47779dded 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -1171,7 +1171,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (uniformValues.contains(namedTex.glslNameId)) { GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.nodeId); if (t != nullptr) { - UniformValue &texUniform = uniformValues[namedTex.glslNameId]; + UniformValue &texUniform = uniformValues.value(namedTex.glslNameId); if (texUniform.valueType() == UniformValue::TextureValue) { const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, m_gl, t); texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; @@ -1201,7 +1201,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) qCWarning(Backend) << "Shader Image referencing invalid texture"; continue; } else { - UniformValue &imgUniform = uniformValues[namedTex.glslNameId]; + UniformValue &imgUniform = uniformValues.value(namedTex.glslNameId); if (imgUniform.valueType() == UniformValue::ShaderImageValue) { const int imgUnit = m_imageContext.activateImage(img, t); imgUniform.data<int>()[namedTex.uniformArrayIndex] = imgUnit; @@ -1260,7 +1260,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) for (const ShaderUniform &uniform : activeUniforms) { // We can use [] as we are sure the the uniform wouldn't // be un activeUniforms if there wasn't a matching value - const UniformValue &v = values[uniform.m_nameId]; + const UniformValue &v = values.value(uniform.m_nameId); // skip invalid textures/images if ((v.valueType() == UniformValue::TextureValue || diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index 97d494370..0ac4f876f 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -552,10 +552,8 @@ void RenderView::sort() // We need the reference here as we are modifying the original container // not the copy PackUniformHash &uniforms = m_commands[j].m_parameterPack.m_uniforms; - PackUniformHash::iterator it = uniforms.begin(); - const PackUniformHash::iterator end = uniforms.end(); - while (it != end) { + for (int u = 0; u < uniforms.keys.size();) { // We are comparing the values: // - raw uniform values // - the texture Node id if the uniform represents a texture @@ -563,15 +561,17 @@ void RenderView::sort() // sharing the same material (shader) are rendered, we can't have the case // where two uniforms, referencing the same texture eventually have 2 different // texture unit values - const UniformValue refValue = cachedUniforms.value(it.key()); - if (it.value() == refValue) { - it = uniforms.erase(it); + const int uniformNameId = uniforms.keys.at(u); + const UniformValue &refValue = cachedUniforms.value(uniformNameId); + const UniformValue &newValue = uniforms.values.at(u); + if (newValue == refValue) { + uniforms.erase(u); } else { // Record updated value so that subsequent comparison // for the next command will be made againts latest // uniform value - cachedUniforms.insert(it.key(), it.value()); - ++it; + cachedUniforms.insert(uniformNameId, newValue); + ++u; } } ++j; diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h index a5aee6ac4..cb599124c 100644 --- a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h +++ b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h @@ -89,7 +89,56 @@ struct BlockToSSBO { QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, BlockToSSBO, Q_PRIMITIVE_TYPE) -typedef QHash<int, UniformValue> PackUniformHash; +struct PackUniformHash +{ + QVector<int> keys; + QVector<UniformValue> values; + + PackUniformHash() + { + keys.reserve(10); + values.reserve(10); + } + + void insert(int key, const UniformValue &value) + { + const int idx = keys.indexOf(key); + if (idx != -1) { + values[idx] = value; + } else { + keys.push_back(key); + values.push_back(value); + } + } + + UniformValue value(int key) const + { + const int idx = keys.indexOf(key); + if (idx != -1) + return values.at(idx); + return UniformValue(); + } + + UniformValue& value(int key) + { + const int idx = keys.indexOf(key); + if (idx != -1) + return values[idx]; + insert(key, UniformValue()); + return value(key); + } + + void erase(int idx) + { + keys.removeAt(idx); + values.removeAt(idx); + } + + bool contains(int key) const + { + return keys.contains(key); + } +}; class Q_AUTOTEST_EXPORT ShaderParameterPack { diff --git a/tests/auto/render/renderviews/tst_renderviews.cpp b/tests/auto/render/renderviews/tst_renderviews.cpp index 17995659b..1558b68c9 100644 --- a/tests/auto/render/renderviews/tst_renderviews.cpp +++ b/tests/auto/render/renderviews/tst_renderviews.cpp @@ -51,16 +51,11 @@ void compareShaderParameterPacks(const ShaderParameterPack &t1, const PackUniformHash hash1 = t1.uniforms(); const PackUniformHash hash2 = t2.uniforms(); - QCOMPARE(hash1.size(), hash2.size()); + QCOMPARE(hash1.keys.size(), hash2.keys.size()); - auto it = hash1.constBegin(); - const auto end = hash1.constEnd(); - - while (it != end) { - const auto h2It = hash2.find(it.key()); - QVERIFY(h2It != hash2.cend()); - QCOMPARE(it.value(), h2It.value()); - ++it; + for (int i = 0, m = hash1.keys.size(); i < m; ++i) { + const int key = hash1.keys.at(i); + QCOMPARE(hash1.value(key), hash2.value(key)); } } |