【发布时间】:2014-06-14 11:50:20
【问题描述】:
我有两个函数,functionA 和 functionB,它们都遍历容器 (std::vector) 并执行一些工作:
void functionA() {
// ...........
auto meshIterator = mMeshes.begin();
for (const Renderable &renderable : renderQueue) {
if (renderable.mMesh == INVALID_MESH_ID) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
throw std::runtime_error("Renderable MeshID is invalid");
}
if (renderable.mMesh < meshIterator->first->mMeshID)
continue;
while (renderable.mMesh > meshIterator->first->mMeshID) {
meshIterator++;
if (meshIterator == mMeshes.end()) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
throw std::runtime_error("Renderable MeshID out of range");
}
}
const bool hasDiffuseTexture =
renderable.mDiffuseTexture != INVALID_TEXTURE_ID;
const bool hasNormalTexture =
renderable.mNormalTexture != INVALID_TEXTURE_ID;
mGeometryProgram.SetUniformData(
UnifGeometry(renderable.mWVPMatrix, renderable.mWorldMatrix,
hasDiffuseTexture, hasNormalTexture,
renderable.mTextureTilingFactor));
if (hasDiffuseTexture)
BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_DIFFUSE,
renderable.mDiffuseTexture, mTextures, mLogger);
if (hasNormalTexture)
BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_NORMAL,
renderable.mNormalTexture, mTextures, mLogger);
GLCALL(glBindVertexArray(meshIterator->second));
GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
GL_UNSIGNED_INT, 0));
GLCALL(glBindVertexArray(0));
}
// ...........
}
void functionB() {
//....................
// both containers are assumed to be sorted by MeshID ascending
auto meshIterator = mMeshes.begin();
for (const Renderable &renderable : renderQueue) {
if (renderable.mMesh == INVALID_MESH_ID) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
throw std::runtime_error("Renderable MeshID is invalid");
}
if (renderable.mMesh < meshIterator->first->mMeshID)
continue;
while (renderable.mMesh > meshIterator->first->mMeshID) {
meshIterator++;
if (meshIterator == mMeshes.end()) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
throw std::runtime_error("Renderable MeshID out of range");
}
}
const Mat4 wvp = lightVP * renderable.mWorldMatrix;
mNullProgram.SetUniformData(UnifNull(wvp));
GLCALL(glBindVertexArray(meshIterator->second));
GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
GL_UNSIGNED_INT, 0));
GLCALL(glBindVertexArray(0));
}
// ...............
}
它们迭代容器的方式非常相似,但它们在主体中所做的工作却非常不同。我想在一个函数中加入这两个(将来可能更多),如下所示:
void DrawModels(const std::function<
void(const Renderable &renderable)> &preDrawFunc) {
// both containers are assumed to be sorted by MeshID ascending
auto meshIterator = mMeshes.begin();
for (const Renderable &renderable : renderQueue) {
if (renderable.mMesh == INVALID_MESH_ID) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
throw std::runtime_error("Renderable MeshID is invalid");
}
if (renderable.mMesh < meshIterator->first->mMeshID)
continue;
while (renderable.mMesh > meshIterator->first->mMeshID) {
meshIterator++;
if (meshIterator == mMeshes.end()) {
JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
throw std::runtime_error("Renderable MeshID out of range");
}
}
preDrawFunc(renderable);
GLCALL(glBindVertexArray(meshIterator->second));
GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
GL_UNSIGNED_INT, 0));
GLCALL(glBindVertexArray(0));
}
}
我认为提供的 std::function 可用于根据调用者执行一些任意工作,如下所示:
void functionD() {
auto preDrawRenderable = [&](const Renderable &renderable) {
const bool hasDiffuseTexture =
renderable.mDiffuseTexture != INVALID_TEXTURE_ID;
const bool hasNormalTexture =
renderable.mNormalTexture != INVALID_TEXTURE_ID;
mGeometryProgram.SetUniformData(
UnifGeometry(renderable.mWVPMatrix, renderable.mWorldMatrix,
hasDiffuseTexture, hasNormalTexture,
renderable.mTextureTilingFactor));
if (hasDiffuseTexture)
BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_DIFFUSE,
renderable.mDiffuseTexture, mTextures, mLogger);
if (hasNormalTexture)
BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_NORMAL,
renderable.mNormalTexture, mTextures, mLogger);
};
DrawModels(preDrawRenderable);
}
void functionE() {
auto preDrawRenderable = [&](const Renderable &renderable) {
const Mat4 wvp = lightVP * renderable.mWorldMatrix;
mNullProgram.SetUniformData(UnifNull(wvp));
};
DrawModels(preDrawRenderable);
}
我的问题:
1) functionD 和 functionE 都需要每秒运行大约 60-100 次。使用 lambda 和 std::function 会导致任何显着的性能损失吗?例如,是否有任何隐藏的动态内存分配调用或虚拟查找或诸如此类会破坏性能的东西?我不知道使用 lambdas 和 std::function 的开销。
2) 有没有比我幼稚的解决方案更好/更快/更清洁的替代方案?
【问题讨论】:
-
实现
std::function的唯一合理方法是使用动态内存分配和虚函数调用。 Lambda 没有这个问题。 -
@nwp 这两个 lambdas 实际上并没有捕获任何东西(尽管有
[&],但它没有任何东西可以捕获),因此std::function的实现可以避免内存分配并简单地存储一个函数指针。 -
没有吗?什么是成员变量“mGeometryProgram”、“mTextures”、“mLogger”?
标签: c++ c++11 lambda iteration