message: [terminal_renderer] OpenGLRenderer: adds bound(bindable, callable) as helper method for paired bind/release calls.
diff: #include <terminal_renderer/Atlas.h>
  #include <crispy/algorithm.h>
  +#include <crispy/utils.h>
  #include <algorithm>
  #include <vector>
  @@ -177,6 +178,19 @@ struct OpenGLRenderer::TextureScheduler : public atlas::CommandListener
  }
  };
  +template <typename T, typename Fn>
  +inline void bound(T& _bindable, Fn&& _callable) noexcept
  +{
  + _bindable.bind();
  + try {
  + _callable();
  + } catch (...) {
  + _bindable.release();
  + throw;
  + }
  + _bindable.release();
  +}
  +
  OpenGLRenderer::OpenGLRenderer(ShaderConfig const& _textShaderConfig,
  ShaderConfig const& _rectShaderConfig,
  Size _size,
  @@ -238,12 +252,12 @@ OpenGLRenderer::OpenGLRenderer(ShaderConfig const& _textShaderConfig,
  //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
  // //glBlendFunc(GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR);
  - CHECKED_GL( textShader_->bind() );
  + bound(*textShader_, [&]() noexcept {
  CHECKED_GL( textShader_->setUniformValue("fs_monochromeTextures", monochromeAtlasAllocator_.instanceBaseId()) );
  CHECKED_GL( textShader_->setUniformValue("fs_colorTextures", coloredAtlasAllocator_.instanceBaseId()) );
  CHECKED_GL( textShader_->setUniformValue("fs_lcdTexture", lcdAtlasAllocator_.instanceBaseId()) );
  CHECKED_GL( textShader_->setUniformValue("pixel_x", 1.0f / float(lcdAtlasAllocator_.width())) );
  - CHECKED_GL( textShader_->release() );
  + });
  initializeRectRendering();
  initializeTextureRendering();
  @@ -602,7 +616,7 @@ void OpenGLRenderer::execute()
  //
  if (!rectBuffer_.empty())
  {
  - rectShader_->bind();
  + bound(*rectShader_, [&]() noexcept {
  rectShader_->setUniformValue(rectProjectionLocation_, projectionMatrix_);
  glBindVertexArray(rectVAO_);
  @@ -610,22 +624,18 @@ void OpenGLRenderer::execute()
  glBufferData(GL_ARRAY_BUFFER, rectBuffer_.size() * sizeof(GLfloat), rectBuffer_.data(), GL_STREAM_DRAW);
  glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(rectBuffer_.size() / 7));
  -
  - rectShader_->release();
  glBindVertexArray(0);
  + });
  rectBuffer_.clear();
  }
  // render textures
  //
  - textShader_->bind();
  -
  + bound(*textShader_, [&]() noexcept {
  // TODO: only upload when it actually DOES change
  textShader_->setUniformValue(textProjectionLocation_, projectionMatrix_);
  -
  executeRenderTextures();
  -
  - textShader_->release();
  + });
  if (pendingScreenshotCallback_)
  {
  