2

I use a texture array to store texture atlases. For hardware which support OpenGL 4.2 I use the glTexStorage3D approach however I would like to use texture arrays pre 4.2 too.

I checked several other threads with the same problem like this or this. I tried to follow the solutions provided there however the texture array seems to be empty, no texture is visible during rendering.

My glTexStorage3D solution which works without any problem:

glTexStorage3D(GL_TEXTURE_2D_ARRAY,
                1,
                GL_R8,
                2048, 2048,
                100);

And the glTexImage3D which should be equivalent, however produces no display:

glTexImage3D(GL_TEXTURE_2D_ARRAY,
             0,
             GL_R8,
             2048, 2048, 100,
             0,
             GL_RED,
             GL_UNSIGNED_BYTE,
             0);

The texture data is uploaded to the specified index with the following snippet (atlas width and height are 2048 and depth is 1):

glBindTexture(GL_TEXTURE_2D_ARRAY, m_arrayTexture);

glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                0,
                0, 0, m_nextTextureLevel,
                atlas->width, atlas->height, atlas->depth,
                GL_RED,
                GL_UNSIGNED_BYTE,
                atlas->data);

What am I missing here? Any help would be highly appreciated.

Edit:
Uploading the texture data to the array right away is not an option as new textures can be added to the array during execution.

Edit v2, solution
As usually the problem was something trivial which I overlooked. I dived into Nazar554's solution and tried to compare it to my code. The problem was that I accidentally set the texture parameters using the wrong constant, so the glTexParameteri calls were made with GL_TEXTURE_2D instead of GL_TEXTURE_2D_ARRAY. After changing these values everything worked like a charm.

Community
  • 1
  • 1
load
  • 43
  • 1
  • 7

1 Answers1

0

You can take a look at my Texture.cpp I used in my project.

However I did not use glTexSubImage() in fallback case. Instead I uploaded the texture data immediately (you are passing a 0 to preallocate the buffer)

Functions that might be interesting to you: Texture::loadTexStorageInternal(const std::string& fileName) and bool Texture::loadTexInternal(const std::string& fileName)

Here is one of them, it handles fallback when glTexStorage3D is unavailable. It is quite long because it tries to handle compressed formats/mipmaps.

bool Texture::loadTexInternal(const std::string& fileName)
{
      gli::texture Texture = gli::load(fileName);
      if(Texture.empty())
          return 0;

      const gli::gl GL(gli::gl::PROFILE_GL33);
      const gli::gl::format Format = GL.translate(Texture.format(), Texture.swizzles());
      GLenum Target = static_cast<GLenum>(GL.translate(Texture.target()));

      Binder texBinder(*this, Target);
      glTexParameteri(Target, GL_TEXTURE_BASE_LEVEL, 0);
      glTexParameteri(Target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(Texture.levels() - 1));
      glTexParameteri(Target, GL_TEXTURE_SWIZZLE_R, Format.Swizzles[0]);
      glTexParameteri(Target, GL_TEXTURE_SWIZZLE_G, Format.Swizzles[1]);
      glTexParameteri(Target, GL_TEXTURE_SWIZZLE_B, Format.Swizzles[2]);
      glTexParameteri(Target, GL_TEXTURE_SWIZZLE_A, Format.Swizzles[3]);
      if(Texture.levels() >= 1)
          glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
      else
          glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      glTexParameteri(Target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

      //glm::tvec3<GLsizei> const Extent(Texture.extent());

      for(std::size_t Layer = 0; Layer < Texture.layers(); ++Layer)
      for(std::size_t Level = 0; Level < Texture.levels(); ++Level)
      for(std::size_t Face = 0; Face < Texture.faces(); ++Face)
      {
          GLsizei const LayerGL = static_cast<GLsizei>(Layer);
          glm::tvec3<GLsizei> loopExtent(Texture.extent(Level));
          Target = gli::is_target_cube(Texture.target())
              ? static_cast<GLenum>(static_cast<GLint>(GL_TEXTURE_CUBE_MAP_POSITIVE_X) + static_cast<GLint>(Face))
              : Target;

          switch(Texture.target())
          {
          case gli::TARGET_1D:
              if(gli::is_compressed(Texture.format()))
                  glCompressedTexImage1D(
                      Target,
                      static_cast<GLint>(Level),
                      static_cast<GLenum>(static_cast<GLenum>(Format.Internal)),
                      0, loopExtent.x,
                      static_cast<GLsizei>(Texture.size(Level)),
                      Texture.data(Layer, Face, Level));
              else
                  glTexImage1D(
                      Target, static_cast<GLint>(Level),
                      static_cast<GLenum>(Format.Internal),
                      loopExtent.x,
                      0,
                      static_cast<GLenum>(Format.External), static_cast<GLenum>(Format.Type),
                      Texture.data(Layer, Face, Level));
              break;
          case gli::TARGET_1D_ARRAY:
          case gli::TARGET_2D:
          case gli::TARGET_CUBE:
              if(gli::is_compressed(Texture.format()))
                  glCompressedTexImage2D(
                      Target, static_cast<GLint>(Level),
                      static_cast<GLenum>(Format.Internal),
                      loopExtent.x,
                      Texture.target() == gli::TARGET_1D_ARRAY ? LayerGL : loopExtent.y,
                      0,
                      static_cast<GLsizei>(Texture.size(Level)),
                      Texture.data(Layer, Face, Level));
              else
                  glTexImage2D(
                      Target, static_cast<GLint>(Level),
                      static_cast<GLenum>(Format.Internal),
                      loopExtent.x,
                      Texture.target() == gli::TARGET_1D_ARRAY ? LayerGL : loopExtent.y,
                      0,
                      static_cast<GLenum>(Format.External), static_cast<GLenum>(Format.Type),
                      Texture.data(Layer, Face, Level));
              break;
          case gli::TARGET_2D_ARRAY:
          case gli::TARGET_3D:
          case gli::TARGET_CUBE_ARRAY:
              if(gli::is_compressed(Texture.format()))
                  glCompressedTexImage3D(
                      Target, static_cast<GLint>(Level),
                      static_cast<GLenum>(Format.Internal),
                      loopExtent.x, loopExtent.y,
                      Texture.target() == gli::TARGET_3D ? loopExtent.z : LayerGL,
                      0,
                      static_cast<GLsizei>(Texture.size(Level)),
                      Texture.data(Layer, Face, Level));
              else
                  glTexImage3D(
                      Target, static_cast<GLint>(Level),
                      static_cast<GLenum>(Format.Internal),
                      loopExtent.x, loopExtent.y,
                      Texture.target() == gli::TARGET_3D ? loopExtent.z : LayerGL,
                      0,
                      static_cast<GLenum>(Format.External), static_cast<GLenum>(Format.Type),
                      Texture.data(Layer, Face, Level));
              break;
          default:
              return false;
          }
      }
      return true;
}
Nazar554
  • 4,105
  • 3
  • 27
  • 38
  • 1
    I forgot to add that uploading the texture data right away is not an option as new atlases can be inserted later during execution. – load Jan 31 '17 at 14:41