diff options
author | Zach Reizner <zachr@google.com> | 2015-10-23 13:26:43 -0700 |
---|---|---|
committer | Zach Reizner <zachr@google.com> | 2015-10-23 13:51:44 -0700 |
commit | d68353163dc72d2282c564379785dfca47b6df65 (patch) | |
tree | 229e774b77b558cefbef29afb6bc93bc7cd3cf73 | |
parent | 6f82f1d69d1194ee43dd9f36c0314afb6634cbbb (diff) |
drm_hwcomposer: lazily generate shaders for GLWorkerCompositor
This still generates the first shader at GLWorkerCompositor::Init() to check
for shader generation errors. It's the only time that shader compilation errors
will be shown on the log.
This change shortens GL initialization time from 2.8 seconds to about 450
milliseconds. Besides improving boot time by 2.3 seconds, less fence timeouts
should happen at boot time due to HWC blocking.
TEST=run and see no display glitches or glworker related errors in logs
BUG=chrome-os-partner:46739
Change-Id: Ia264e3f73a0ebe8558165ae3c215777ef6339ecc
-rw-r--r-- | glworker.cpp | 147 | ||||
-rw-r--r-- | glworker.h | 2 |
2 files changed, 79 insertions, 70 deletions
diff --git a/glworker.cpp b/glworker.cpp index f72c0e1..0b98a51 100644 --- a/glworker.cpp +++ b/glworker.cpp @@ -149,13 +149,15 @@ static bool HasExtension(const char *extension, const char *extensions) { static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count, const GLchar **sources, - std::string *shader_log) { + std::ostringstream *shader_log) { GLint status; AutoGLShader shader(glCreateShader(type)); if (shader.get() == 0) { - *shader_log = "glCreateShader failed"; + if (shader_log) + *shader_log << "Failed glCreateShader call"; return 0; } + glShaderSource(shader.get(), source_count, sources, NULL); glCompileShader(shader.get()); glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status); @@ -163,8 +165,14 @@ static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count, if (shader_log) { GLint log_length; glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &log_length); - shader_log->resize(log_length); - glGetShaderInfoLog(shader.get(), log_length, NULL, &(*shader_log)[0]); + std::string info_log(log_length, ' '); + glGetShaderInfoLog(shader.get(), log_length, NULL, &info_log.front()); + *shader_log << "Failed to compile shader:\n" << info_log.c_str() + << "\nShader Source:\n"; + for (unsigned i = 0; i < source_count; i++) { + *shader_log << sources[i]; + } + *shader_log << "\n"; } return 0; } @@ -236,73 +244,52 @@ static std::string GenerateFragmentShader(int layer_count) { return fragment_shader_stream.str(); } -static int GenerateShaders(std::vector<AutoGLProgram> *blend_programs) { - // Limits: GL_MAX_VARYING_COMPONENTS, GL_MAX_TEXTURE_IMAGE_UNITS, - // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - int i, ret = 1; - GLint max_texture_images, status; - AutoGLShader vertex_shader, fragment_shader; - AutoGLProgram program; - std::string shader_log; - - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_images); - - for (i = 1; i <= max_texture_images; i++) { - std::string vertex_shader_string = GenerateVertexShader(i); - const GLchar *vertex_shader_source = vertex_shader_string.c_str(); - vertex_shader = CompileAndCheckShader( - GL_VERTEX_SHADER, 1, &vertex_shader_source, ret ? &shader_log : NULL); - if (!vertex_shader.get()) { - if (ret) - ALOGE("Failed to make vertex shader:\n%sshader source:\n%s", - shader_log.c_str(), vertex_shader_source); - break; - } +static AutoGLProgram GenerateProgram(unsigned num_textures, + std::ostringstream *shader_log) { + std::string vertex_shader_string = GenerateVertexShader(num_textures); + const GLchar *vertex_shader_source = vertex_shader_string.c_str(); + AutoGLShader vertex_shader = CompileAndCheckShader( + GL_VERTEX_SHADER, 1, &vertex_shader_source, shader_log); + if (!vertex_shader.get()) + return 0; - std::string fragment_shader_string = GenerateFragmentShader(i); - const GLchar *fragment_shader_source = fragment_shader_string.c_str(); - fragment_shader = - CompileAndCheckShader(GL_FRAGMENT_SHADER, 1, &fragment_shader_source, - ret ? &shader_log : NULL); - if (!fragment_shader.get()) { - if (ret) - ALOGE("Failed to make fragment shader:\n%sshader source:\n%s", - shader_log.c_str(), fragment_shader_source); - break; - } + std::string fragment_shader_string = GenerateFragmentShader(num_textures); + const GLchar *fragment_shader_source = fragment_shader_string.c_str(); + AutoGLShader fragment_shader = CompileAndCheckShader( + GL_FRAGMENT_SHADER, 1, &fragment_shader_source, shader_log); + if (!fragment_shader.get()) + return 0; - program = AutoGLProgram(glCreateProgram()); - if (!program.get()) { - if (ret) - ALOGE("Failed to create program %s", GetGLError()); - break; - } + AutoGLProgram program(glCreateProgram()); + if (!program.get()) { + if (shader_log) + *shader_log << "Failed to create program: " << GetGLError() << "\n"; + return 0; + } - glAttachShader(program.get(), vertex_shader.get()); - glAttachShader(program.get(), fragment_shader.get()); - glBindAttribLocation(program.get(), 0, "vPosition"); - glBindAttribLocation(program.get(), 1, "vTexCoords"); - glLinkProgram(program.get()); - glDetachShader(program.get(), vertex_shader.get()); - glDetachShader(program.get(), fragment_shader.get()); - - glGetProgramiv(program.get(), GL_LINK_STATUS, &status); - if (!status) { - if (ret) { - GLint log_length; - glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length); - std::string program_log(log_length, ' '); - glGetProgramInfoLog(program.get(), log_length, NULL, &program_log[0]); - ALOGE("Failed to link program: \n%s", program_log.c_str()); - } - break; - } + glAttachShader(program.get(), vertex_shader.get()); + glAttachShader(program.get(), fragment_shader.get()); + glBindAttribLocation(program.get(), 0, "vPosition"); + glBindAttribLocation(program.get(), 1, "vTexCoords"); + glLinkProgram(program.get()); + glDetachShader(program.get(), vertex_shader.get()); + glDetachShader(program.get(), fragment_shader.get()); - ret = 0; - blend_programs->emplace_back(std::move(program)); + GLint status; + glGetProgramiv(program.get(), GL_LINK_STATUS, &status); + if (!status) { + if (shader_log) { + GLint log_length; + glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length); + std::string program_log(log_length, ' '); + glGetProgramInfoLog(program.get(), log_length, NULL, + &program_log.front()); + *shader_log << "Failed to link program:\n" << program_log.c_str() << "\n"; + } + return 0; } - return ret; + return program; } struct RenderingCommand { @@ -552,7 +539,10 @@ int GLWorkerCompositor::Init() { glBindBuffer(GL_ARRAY_BUFFER, 0); vertex_buffer_.reset(vertex_buffer); - if (GenerateShaders(&blend_programs_)) { + std::ostringstream shader_log; + blend_programs_.emplace_back(GenerateProgram(1, &shader_log)); + if (blend_programs_.back().get() == 0) { + ALOGE("%s", shader_log.str().c_str()); return 1; } @@ -634,19 +624,18 @@ int GLWorkerCompositor::Composite(DrmHwcLayer *layers, glEnable(GL_SCISSOR_TEST); for (const RenderingCommand &cmd : commands) { - if (cmd.texture_count <= 0) { + if (cmd.texture_count == 0) continue; - } // TODO(zachr): handle the case of too many overlapping textures for one // area by falling back to rendering as many layers as possible using // multiple blending passes. - if (cmd.texture_count > blend_programs_.size()) { + GLint program = PrepareAndCacheProgram(cmd.texture_count); + if (program == 0) { ALOGE("Too many layers to render in one area"); continue; } - GLint program = blend_programs_[cmd.texture_count - 1].get(); glUseProgram(program); GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport"); GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop"); @@ -799,4 +788,22 @@ GLWorkerCompositor::PrepareAndCacheFramebuffer( return &cached_framebuffers_.back(); } +GLint GLWorkerCompositor::PrepareAndCacheProgram(unsigned texture_count) { + if (blend_programs_.size() >= texture_count) { + GLint program = blend_programs_[texture_count - 1].get(); + if (program != 0) + return program; + } + + AutoGLProgram program = GenerateProgram(texture_count, NULL); + if (program.get() != 0) { + if (blend_programs_.size() < texture_count) + blend_programs_.resize(texture_count); + blend_programs_[texture_count - 1] = std::move(program); + return blend_programs_[texture_count - 1].get(); + } + + return 0; +} + } // namespace android @@ -68,6 +68,8 @@ class GLWorkerCompositor { CachedFramebuffer *PrepareAndCacheFramebuffer( const sp<GraphicBuffer> &framebuffer); + GLint PrepareAndCacheProgram(unsigned texture_count); + EGLDisplay egl_display_; EGLContext egl_ctx_; |