• Advertisement
Sign in to follow this  

Texture Storage + Texture Views AND mipmapping

This topic is 1231 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi there,

 

how do you do mipmapping with texture storage?
I tried the following on AMD Catalyst 14.7 rc3, but it didn't really seem to work.

//create immutable texture storage
glGenTextures( 1, &orig_tex );
float num_mips = std::log2( float( std::max( orig_tex_width, orig_tex_height ) ) ) + 1;
glBindTexture( GL_TEXTURE_2D, orig_tex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4);

//mipmapping doesn't work
glTexStorage2D( GL_TEXTURE_2D, num_mips, GL_RGBA8, orig_tex_width, orig_tex_height );
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, im.getSize().x, im.getSize().y, GL_RGBA, GL_UNSIGNED_BYTE, im.getPixelsPtr() );

//mipmapping works, but this is not immutable storage
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, orig_tex_width, orig_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data );

glGenerateMipmap( GL_TEXTURE_2D );

/**
.
.
.
/**/

//create texture views for the immutable storage
glGenTextures( 1, &tex );
glTextureView( tex, GL_TEXTURE_2D, orig_tex, GL_RGBA8, 0, num_mips, 0, 1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4);

//"texture view" workaround, as texstorage doesn't work
tex = orig_tex; //...

Best regards,

Yours3!f

Edited by Yours3!f

Share this post


Link to post
Share on other sites
Advertisement

Could you describe what you mean by


I tried the following on AMD Catalyst 14.7 rc3, but it didn't really seem to work.


Do you get a GL error ? Are mipmap not getting used ?.....saying something doesn't work gives no indication of what you are seeing/hear/ not seeing etc...

How did you verify that mipmapping is not working ?
 

Share this post


Link to post
Share on other sites

 

Could you describe what you mean by

 


I tried the following on AMD Catalyst 14.7 rc3, but it didn't really seem to work.


Do you get a GL error ? Are mipmap not getting used ?.....saying something doesn't work gives no indication of what you are seeing/hear/ not seeing etc...

How did you verify that mipmapping is not working ?
 

 

 

no GL errors, I would've mentioned that. 

I created two screenshots, it's quite obvious.

 

texstorage:
http://minus.com/i/AVUONR7EuQ0d

teximage:
http://minus.com/i/bm1HwuQt5y9rC

 

I've also verified this with CodeXL: with teximage the mipmaps are generated, I get all the 11 levels of mipmaps. With texstorage I get only one leve, so no mipmaps are generated.

 

(also I forgot to copy here one glTexSubImage, now the code above should be the same)

Share this post


Link to post
Share on other sites

I don't see any apparent issues. A while back I had an issue with glGenerateTextureMipmapEXT on AMD. In fact I had so many issues with random bugs in AMD's OpenGL drivers that I just gave up and ordered an Nvidia graphics card.

Share this post


Link to post
Share on other sites

I don't see any apparent issues. A while back I had an issue with glGenerateTextureMipmapEXT on AMD. In fact I had so many issues with random bugs in AMD's OpenGL drivers that I just gave up and ordered an Nvidia graphics card.

 

If you zoom in on the texstorage pic, you can see that it is pixelated where the lower mip levels should come. I get the same on nvidia (344.11 driver), so I suppose I'm doing it wrong.

Share this post


Link to post
Share on other sites

They both look mipmapped to me... except that in the 'texstorage' screenshot, it looks like the mipmaps have been generated using a worse algorithm than in the other screenshots.

 

Do you generate the mipmaps yourself, or do you just ask the GL driver to create them for you?

[edit]To answer my own question -- you're using glGenerateMipmap in your code snippet, so the driver is creating them for you biggrin.png

In that case, it just looks like that your drivers suck at creating mipmaps in some cases?

 

There's no special mipmap generation hardware in modern GPUs -- when you ask the driver to create them for you, you're actually just asking it to load up a built in shader program and dispatch a bunch of compute tasks, or draw a bunch of quads, filling in your mips with appropriate data.

IMHO, this is a really bad idea because every driver might use a different algorithm, landing you in situations like this... I'd prefer to just ship your own compute/fragment shaders for generating mips, or even better, to precompute them ahead of time using a very high quality algorithm and load them from disk.

Edited by Hodgman

Share this post


Link to post
Share on other sites

I could not fathom a reason for why immutable texture vs. mutable texture would have an effect on how the mipmaps are being generated. In the case of RTT you would have no choice but to use glGenerateMipmaps. Well, maybe you could do it yourself with a compute shader if that is available to you. I wonder what the performance difference would be if any.

 

Also, maybe try using glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST).

Share this post


Link to post
Share on other sites

They both look mipmapped to me... except that in the 'texstorage' screenshot, it looks like the mipmaps have been generated using a worse algorithm than in the other screenshots.

 

Do you generate the mipmaps yourself, or do you just ask the GL driver to create them for you?

[edit]To answer my own question -- you're using glGenerateMipmap in your code snippet, so the driver is creating them for you biggrin.png

In that case, it just looks like that your drivers suck at creating mipmaps in some cases?

 

There's no special mipmap generation hardware in modern GPUs -- when you ask the driver to create them for you, you're actually just asking it to load up a built in shader program and dispatch a bunch of compute tasks, or draw a bunch of quads, filling in your mips with appropriate data.

IMHO, this is a really bad idea because every driver might use a different algorithm, landing you in situations like this... I'd prefer to just ship your own compute/fragment shaders for generating mips, or even better, to precompute them ahead of time using a very high quality algorithm and load them from disk.

 

Thank you, I didn't know that, I always thought there's a fixed function unit that does this. I think I'll switch to custom mip generation :)

Share this post


Link to post
Share on other sites

I could not fathom a reason for why immutable texture vs. mutable texture would have an effect on how the mipmaps are being generated. In the case of RTT you would have no choice but to use glGenerateMipmaps. Well, maybe you could do it yourself with a compute shader if that is available to you. I wonder what the performance difference would be if any.

 

Also, maybe try using glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST).

 

Compute shaders are definitely available :)

glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST) didn't work, I'll try custom mip generation now.

Share this post


Link to post
Share on other sites

okay, found the error, see the code for the fix smile.png

//create immutable texture storage
glGenTextures( 1, &orig_tex );
float num_mips = std::log2( float( std::max( orig_tex_width, orig_tex_height ) ) ) + 1;
glBindTexture( GL_TEXTURE_2D, orig_tex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4);

//allocate texture storage (w/ mipmaps)
glTexStorage2D( GL_TEXTURE_2D, num_mips, GL_RGBA8, orig_tex_width, orig_tex_height );

//upload base texture
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, im.getSize().x, im.getSize().y, GL_RGBA, GL_UNSIGNED_BYTE, im.getPixelsPtr() );

//alternatively use manual mipmap generation here
glGenerateMipmap( GL_TEXTURE_2D );

/**
.
.
.
/**/

//create texture views for the immutable storage
glGenTextures( 1, &tex );
glTextureView( tex, GL_TEXTURE_2D, orig_tex, GL_RGBA8, 0, num_mips, 0, 1 );

//FIX: need to bind the texview to set the sampler state... DSA pls?
glBindTexture( GL_TEXTURE_2D, texview ); 

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4); 

I also wrote a small app for manual mipmap generation using point, bilinear, bicubic (with various interpolation) in the process. (got some help for bicubic from here: http://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL)

 

CPU side:

void set_workgroup_size( vec2& gws, vec2& lws, vec2& dispatch_size, const uvec2& screen )
{
  //set up work group sizes
  unsigned local_ws[2] = {16, 16};
  unsigned global_ws[2];
  unsigned gw = 0, gh = 0, count = 1;
  
  while( gw < screen.x )
  {
    gw = local_ws[0] * count;
    count++;
  }
  
  count = 1;
  
  while( gh < screen.y )
  {
    gh = local_ws[1] * count;
    count++;
  }

  global_ws[0] = gw;
  global_ws[1] = gh;

  gws = vec2( global_ws[0], global_ws[1] );
  lws = vec2( local_ws[0], local_ws[1] );
  dispatch_size = gws / lws;
}

void gen_mipmaps( GLuint shader, GLuint texture, GLenum internal_format, uvec2 size, unsigned miplevels)
{
  glUseProgram( shader );

  size.x /= 2;
  size.y /= 2;

  for( int d = 1; d < miplevels; ++d )
  {
    glBindImageTexture( 0, texture, d-1, GL_FALSE, 0, GL_READ_ONLY, internal_format );
    glBindImageTexture( 1, texture, d, GL_FALSE, 0, GL_WRITE_ONLY, internal_format );

    vec2 dispatch_size, gws, lws;
    set_workgroup_size( gws, lws, dispatch_size, size );

    glDispatchCompute( dispatch_size.x, dispatch_size.y, 1 );

    glMemoryBarrier( GL_SHADER_IMAGE_ACCESS_BARRIER_BIT );

    size.x /= 2;
    size.y /= 2;
  }
}

GPU side:

#version 430 core

layout(binding=0, rgba8) readonly uniform image2D src_tex;
layout(binding=1) writeonly uniform image2D dst_tex;

layout(local_size_x = 16, local_size_y = 16) in; //local workgroup size

vec4 sample_point( vec2 coord, vec2 size )
{
  return imageLoad( src_tex, ivec2(coord * size) );
}

vec4 sample_bilinear( vec2 coord, vec2 size )
{
  ivec2 final_coord = ivec2(coord * size);
  vec4 s00 = imageLoad( src_tex, final_coord + ivec2(0, 0) );
  vec4 s01 = imageLoad( src_tex, final_coord + ivec2(1, 0) );
  vec4 s10 = imageLoad( src_tex, final_coord + ivec2(0, 1) );
  vec4 s11 = imageLoad( src_tex, final_coord + ivec2(1, 1) );
  
  float xval = fract( coord.x * size.x );
  float yval = fract( coord.y * size.y );
  
  return mix( mix( s00, s10, xval ), mix( s01, s11, xval ), yval );
}

float triangular( float f )
{
  f *= 0.5;
  return f < 0 ? f + 1 : 1 - f;
}

float bell( float f )
{
  f = f * (0.5 * 1.5); //rescale [-2...2] to [-1.5...1.5]
  
  if( f >= -1.5 && f < -0.5 )
  {
    f += 1.5;
    return 0.5 * f * f;
  }
  else if( f >= -0.5 && f < 0.5 )
  {
    return 0.75 - ( f * f );
  }
  else if( f >= 0.5 && f < 1.5 )
  {
    f -= 1.5;
    return 0.5 * f * f;
  }
  else
  {
    return 0;
  }
}

float bspline( float f )
{
  f = abs(f);
  
  if( f >= 0 && f <= 1 )
  {
    return (2/3.0) + 0.5 * ( f * f * f ) - ( f * f );
  }
  else if( f > 1 && f <= 2 )
  {
    f = 2 - f;
    return (1/6.0) * f * f * f;
  }
  else
  {
    return 1;
  }
}

vec4 sample_bicubic( vec2 coord, vec2 size )
{
  vec4 sum = vec4(0);
  vec4 weight_sum = vec4(0);
  
  ivec2 final_coord = ivec2(coord * size);
  
  float xval = fract( coord.x * size.x );
  float yval = fract( coord.y * size.y );
  
  for( int y = -1; y <= 2; ++y )
  {
    for( int x = -1; x <= 2; ++x )
    {
      vec4 s = imageLoad( src_tex, final_coord + ivec2(x, y) );
      float fx = bspline( x - xval ); //can use bell or triangular as functions
      float fy = bspline( -(y - yval) );
      float weight = fx * fy;
      sum += s * weight;
      weight_sum += weight;
    }
  }
  
  return sum / weight_sum;
}

void main()
{
	ivec2 global_id = ivec2( gl_GlobalInvocationID.xy );
  ivec2 global_size = imageSize( dst_tex ).xy;
  ivec2 src_size = imageSize( src_tex ).xy;
  vec2 texcoord = vec2(global_id) / vec2(global_size);
  
  if( global_id.x <= global_size.x && global_id.y <= global_size.y )
	{  
    //point filtering
    //imageStore( dst_tex, global_id, sample_point( texcoord, src_size ) );
    
    //bilinear filtering
    //imageStore( dst_tex, global_id, sample_bilinear( texcoord, src_size ) );
    
    //bicubic filtering
    imageStore( dst_tex, global_id, sample_bicubic( texcoord, src_size ) );
  }
}
Edited by Yours3!f

Share this post


Link to post
Share on other sites
//FIX: need to bind the texview to set the sampler state... DSA pls?

 

There are DSA functions for this in GL4.5 smile.png

glTextureParameteri( texview, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTextureParameteri( texview, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTextureParameteri( texview, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTextureParameteri( texview, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

Share this post


Link to post
Share on other sites

 

//FIX: need to bind the texview to set the sampler state... DSA pls?

 

There are DSA functions for this in GL4.5 smile.png

glTextureParameteri( texview, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTextureParameteri( texview, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTextureParameteri( texview, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTextureParameteri( texview, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

 

yeah, I should start using the 4.5 beta drivers :)

Share this post


Link to post
Share on other sites

Ah, I see. It came down to a binding issue. I didn't catch it because I've been using EXT_direct_state_access all along since I cannot stand bind to edit one bit. Now I'm using the ARB version and I have to say it makes using OpenGL so much nicer.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement