Shader::Shader(const char* name_, const char* vertexSource, const char* fragmentSource, gl::ObjectStore& store, Defines defines) : name(name_) , program(store.createProgram()) , vertexShader(store.createShader(GL_VERTEX_SHADER)) , fragmentShader(store.createShader(GL_FRAGMENT_SHADER)) { util::stopwatch stopwatch("shader compilation", Event::Shader); if (!compileShader(vertexShader, vertexSource)) { Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource); throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile"); } std::string fragment(fragmentSource); if (defines & Defines::Overdraw) { assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); } if (!compileShader(fragmentShader, fragment.c_str())) { Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource); throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile"); } // Attach shaders MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get())); MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get())); // Bind attribute variables MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_pos, "a_pos")); MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_extrude, "a_extrude")); MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_offset, "a_offset")); MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_data, "a_data")); MBGL_CHECK_ERROR(glBindAttribLocation(program.get(), a_texture_pos, "a_texture_pos")); // Link program GLint status; MBGL_CHECK_ERROR(glLinkProgram(program.get())); MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status)); if (status == 0) { GLint logLength; MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength)); const auto log = std::make_unique<GLchar[]>(logLength); if (logLength > 0) { MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get())); Log::Error(Event::Shader, "Program failed to link: %s", log.get()); } throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get()); } }
// Transfers this buffer to the GPU and binds the buffer to the GL context. void bind(gl::ObjectStore& store) { if (buffer) { MBGL_CHECK_ERROR(glBindBuffer(bufferType, *buffer)); } else { buffer = store.createBuffer(); MBGL_CHECK_ERROR(glBindBuffer(bufferType, *buffer)); if (array == nullptr) { Log::Debug(Event::OpenGL, "Buffer doesn't contain elements"); pos = 0; } MBGL_CHECK_ERROR(glBufferData(bufferType, pos, array, GL_STATIC_DRAW)); if (!retainAfterUpload) { cleanup(); } } }
void FrameHistory::bind(gl::ObjectStore& store) { if (!texture) { texture = store.createTexture(); MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); } else { MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); } }
void FrameHistory::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (!texture) { texture = store.createTexture(); config.activeTexture = unit; config.texture[unit] = *texture; #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); } else if (config.texture[unit] != *texture) { config.activeTexture = unit; config.texture[unit] = *texture; } }
void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) { if (!data) { return; // Empty atlas } if (!texture) { texture = objectStore.createTexture(); MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); fullUploadRequired = true; } else { MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); } GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST; if (filter_val != filter) { MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val)); filter = filter_val; } if (dirty) { std::lock_guard<std::recursive_mutex> lock(mtx); if (fullUploadRequired) { MBGL_CHECK_ERROR(glTexImage2D( GL_TEXTURE_2D, // GLenum target 0, // GLint level GL_RGBA, // GLint internalformat pixelWidth, // GLsizei width pixelHeight, // GLsizei height 0, // GLint border GL_RGBA, // GLenum format GL_UNSIGNED_BYTE, // GLenum type data.get() // const GLvoid * data )); fullUploadRequired = false; } else { MBGL_CHECK_ERROR(glTexSubImage2D( GL_TEXTURE_2D, // GLenum target 0, // GLint level 0, // GLint xoffset 0, // GLint yoffset pixelWidth, // GLsizei width pixelHeight, // GLsizei height GL_RGBA, // GLenum format GL_UNSIGNED_BYTE, // GLenum type data.get() // const GLvoid *pixels )); } dirty = false; #ifndef GL_ES_VERSION_2_0 // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char*>(data.get()), // pixelWidth, pixelHeight, pixelWidth, pixelHeight); #endif } };
Impl(gl::ObjectStore& store) : pool(store.createTexturePool()), availableIDs(gl::TextureMax) { std::copy(pool.get().begin(), pool.get().end(), availableIDs.begin()); }