Repository: google/filament
File: filament/backend/src/opengl/ShaderCompilerService.cpp (C++)

Code before:
                version = "#version 310 es\n";
            }

            std::array<std::string_view, 5> sources = {
                version, prolog, specializationConstantString, packingFunctions,
                { body.data(), body.size() - 1 }// null-terminated
            };

            // Some of the sources may be zero-length. Remove them as to avoid passing lengths of
            // zero to glShaderSource(). glShaderSource should work with lengths of zero, but some
            // drivers instead interpret zero as a sentinel for a null-terminated string.
            auto const partitionPoint = std::stable_partition(sources.begin(), sources.end(),
                    [](std::string_view s) { return !s.empty(); });
            size_t const count = std::distance(sources.begin(), partitionPoint);

            std::array<const char*, 5> shaderStrings;
            std::array<GLint, 5> lengths;
            for (size_t j = 0; j < count; j++) {
                shaderStrings[j] = sources[j].data();
                lengths[j] = GLint(sources[j].size());
            }

            GLuint const shaderId = glCreateShader(glShaderType);
            glShaderSource(shaderId, GLsizei(count), shaderStrings.data(), lengths.data());
            glCompileShader(shaderId);
            token->gl.compilationCallResult = glGetError();
#ifndef NDEBUG
            // for debugging we return the original shader source (without the modifications we
            // made here), otherwise the line numbers wouldn't match.
            token->shaderSourceCode[i] = std::move(shader);
#endif
            token->gl.shaders[i] = shaderId;
        }
    }
}

/* static */ bool ShaderCompilerService::isCompileCompleted(program_token_t const& token) noexcept {
    GLenum param = GL_COMPLETION_STATUS;
    if (UTILS_UNLIKELY(token->compiler.mMode != Mode::ASYNCHRONOUS)) {
        param = GL_COMPILE_STATUS;
    }

    for (auto shader: token->gl.shaders) {
        if (!shader) {
            continue;
        }
        GLint status;
        glGetShaderiv(shader, param, &status);
        if (status == GL_FALSE) {
            return false;
        }

Review comment (bug):
I don't want to call glGetError() immediately after `glCompileShader` because that too might make `glCompileShader` synchronous. I'm actually not sure it will, but I think it's better to call glGetError() only once we see that the link has failed.

Code after:

            std::array<std::string_view, 5> sources = {
                version, prolog, specializationConstantString, packingFunctions,
                { body.data(), body.size() - 1 }// null-terminated
            };

            // Some of the sources may be zero-length. Remove them as to avoid passing lengths of
            // zero to glShaderSource(). glShaderSource should work with lengths of zero, but some
            // drivers instead interpret zero as a sentinel for a null-terminated string.
            auto const partitionPoint = std::stable_partition(sources.begin(), sources.end(),
                    [](std::string_view s) { return !s.empty(); });
            size_t const count = std::distance(sources.begin(), partitionPoint);

            std::array<const char*, 5> shaderStrings;
            std::array<GLint, 5> lengths;
            for (size_t j = 0; j < count; j++) {
                shaderStrings[j] = sources[j].data();
                lengths[j] = GLint(sources[j].size());
            }

            GLuint const shaderId = glCreateShader(glShaderType);
            glShaderSource(shaderId, GLsizei(count), shaderStrings.data(), lengths.data());
            glCompileShader(shaderId);
#ifndef NDEBUG
            // for debugging we return the original shader source (without the modifications we
            // made here), otherwise the line numbers wouldn't match.
            token->shaderSourceCode[i] = std::move(shader);
#endif
            token->gl.shaders[i] = shaderId;
        }
    }
}

/* static */ bool ShaderCompilerService::isCompileCompleted(program_token_t const& token) noexcept {
    GLenum param = GL_COMPLETION_STATUS;
    if (UTILS_UNLIKELY(token->compiler.mMode != Mode::ASYNCHRONOUS)) {
        param = GL_COMPILE_STATUS;
    }

    for (auto shader: token->gl.shaders) {
        if (!shader) {
            continue;
        }
        GLint status;
        glGetShaderiv(shader, param, &status);
        if (status == GL_FALSE) {
            return false;
        }
    }
    return true;
}