Original Post
During HDR rendering I have to calculate the average luminance. I iteratively downscale the scene to 2x2 pixels and call GetTexImage to read the values from framebuffere image. Now, the problem is it takes about 10 ms (which is 90% of CPU time of rendering). I thought it's because all previous GL commands have to be finished before reading the texture. So I moved reading before HDR pass, which is the same as skipping 1 frame. But it still takes about 10 ms. If I remove GetTexImage, it takes about 1 ms. Any ideas? Here's the relevant code:
void Renderer::renderHDR()
{
GPUTimerQuery::Scope tc(hdrTQ_);
CPUTimerQuery::Scope cc(hdrCQ_);
GLfloat lumValues[4];
{
PixelPackBuffer<GLfloat>::Unbind u(pbb2_);
pbb2_.bind();
logLBuffer2_.bindTexture();
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, 0);
const GLfloat *p = pbb2_.map(GL_READ_ONLY_ARB);
std::copy(p, p + 4, lumValues);
pbb2_.unmap();
}
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_BLEND);
const Shader& logLShader = shaderManager_[ShaderManager::LUMINANCE_LOG];
logLBuffer512_.bind();
setOrthoMatrices();
logLShader.use();
glContext_.glUniform1iARB(logLShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1fARB(logLShader.uniformLocation("ds_Sigma"), 0.001f);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
stencilBuffer_.bindTexture();
drawQuad(0, 0, 1, 1);
logLBuffer512_.unbind();
const Shader& downsampleShader = shaderManager_[ShaderManager::DOWNSAMPLE4x4];
logLBuffer128_.bind();
setOrthoMatrices();
downsampleShader.use();
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Size"), 512);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
logLBuffer512_.bindTexture();
drawQuad(0, 0, 1, 1);
logLBuffer128_.unbind();
logLBuffer32_.bind();
setOrthoMatrices();
downsampleShader.use();
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Size"), 128);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
logLBuffer128_.bindTexture();
drawQuad(0, 0, 1, 1);
logLBuffer32_.unbind();
logLBuffer8_.bind();
setOrthoMatrices();
downsampleShader.use();
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Size"), 32);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
logLBuffer32_.bindTexture();
drawQuad(0, 0, 1, 1);
logLBuffer8_.unbind();
logLBuffer2_.bind();
setOrthoMatrices();
downsampleShader.use();
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1iARB(downsampleShader.uniformLocation("ds_Size"), 8);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
logLBuffer8_.bindTexture();
drawQuad(0, 0, 1, 1);
logLBuffer2_.unbind();
GLfloat avLum = 0;
for (std::size_t i = 0; i < 4; ++i) avLum += lumValues;
avLum = std::exp(avLum / 4);
// tone mapping
const Shader& toneMappingShader = shaderManager_[ShaderManager::DEFERRED_TONE_MAP];
hdrBuffer_.bind();
setOrthoMatrices();
toneMappingShader.use();
glContext_.glUniform1iARB(toneMappingShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1fARB(toneMappingShader.uniformLocation("ds_WhitePoint2"), 5.0f);
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
stencilBuffer_.bindTexture();
float delta = 0.04f / (0.04f + avLum);
float t = delta * 0.4f + (1.0f - delta) * 0.1f;
double eyeTime = eyeTimer_.time();
luminance_ += (avLum - luminance_) * (1.0f - std::exp(float(lastEyeTime_ - eyeTime) / t));
lastEyeTime_ = eyeTime;
float key = std::max(0.0f, 1.5f - 1.5f / (luminance_ * 3.0f + 1.0f)) + 0.01f;
glContext_.glUniform1fARB(toneMappingShader.uniformLocation("ds_Exposure"), key / luminance_);
drawQuad(0, 0, 1, 1);
hdrBuffer_.unbind();
const Shader& lightPass = shaderManager_[ShaderManager::LIGHT_PASS];
highlightBuffer_.bind();
lightPass.use();
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
hdrBuffer_.bindTexture();
glContext_.glUniform1iARB(lightPass.uniformLocation("ds_Image"), 0);
drawQuad(0, 0, 1, 1);
highlightBuffer_.unbind();
const Shader& horzBlurShader = shaderManager_[ShaderManager::DEFERRED_HORIZONTAL_BLUR];
const Shader& vertBlurShader = shaderManager_[ShaderManager::DEFERRED_VERTICAL_BLUR];
blurBuffer0_.bind();
horzBlurShader.use();
glContext_.glUniform1iARB(horzBlurShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1fARB(horzBlurShader.uniformLocation("ds_Size"), GLfloat(window_.width()));
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
highlightBuffer_.bindTexture();
drawQuad(0, 0, 1, 1);
blurBuffer0_.unbind();
hdrBuffer_.bind();
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
vertBlurShader.use();
glContext_.glUniform1iARB(vertBlurShader.uniformLocation("ds_Image"), 0);
glContext_.glUniform1fARB(horzBlurShader.uniformLocation("ds_Size"), GLfloat(window_.height()));
glContext_.glActiveTextureARB(GL_TEXTURE0_ARB);
blurBuffer0_.bindTexture();
drawQuad(0, 0, 1, 1);
hdrBuffer_.unbind();
}