日別アーカイブ: 2012年8月27日

OpenGL / OpenGL ES ETC1 の互換性と KTX の落とし穴

昨日の記事に書いたように OpenGL / OpenGL ES の場合 KTX 形式の
テクスチャ読み込みが非常に簡単に出来ます。
ところが OpenGL ES 3.0 / OpenGL 4.3 の場合、ETC1 の読み込みに
問題がありました。

KTX のロード時に、ヘッダに GL_ETC1_RGB8_OES があれば
GL_COMPRESSED_RGB8_ETC2 に置き換える必要があります。
これは GPU が ETC2 に対応している場合だけです。

OpenGL ES 3.0 / OpenGL 4.3 で採用された ETC2 形式は ETC1 と
完全に上位互換性があります。
フォーマットも同一で、ETC1 は ETC2 の一部になりました。
そのため OpenGL ES 3.0 では事実上 ETC1 が無くなっています。

実際に Emulator (ES3 compatibility) で
glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS, lists )
を列挙すると↓ ETC1 が含まれていないことがわかります。

tc[00]=83f0  GL_COMPRESSED_RGB_S3TC_DXT1_EXT
tc[01]=83f2  GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
tc[02]=83f3  GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
tc[03]=8b90  GL_PALETTE4_RGB8
tc[04]=8b91  GL_PALETTE4_RGBA8
tc[05]=8b92  GL_PALETTE4_R5_G6_B5
tc[06]=8b93  GL_PALETTE4_RGBA4
tc[07]=8b94  GL_PALETTE4_RGB5_A1
tc[08]=8b95  GL_PALETTE8_RGB8
tc[09]=8b96  GL_PALETTE8_RGBA8
tc[10]=8b97  GL_PALETTE8_R5_G6_B5
tc[11]=8b98  GL_PALETTE8_RGBA4
tc[12]=8b99  GL_PALETTE8_RGB5_A1
tc[13]=9274  GL_COMPRESSED_RGB8_ETC2
tc[14]=9275  GL_COMPRESSED_SRGB8_ETC2
tc[15]=9276  GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
tc[16]=9277  GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
tc[17]=9278  GL_COMPRESSED_RGBA8_ETC2_EAC
tc[18]=9279  GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
tc[19]=9270  GL_COMPRESSED_R11_EAC
tc[20]=9271  GL_COMPRESSED_SIGNED_R11_EAC
tc[21]=9272  GL_COMPRESSED_RG11_EAC
tc[22]=9273  GL_COMPRESSED_SIGNED_RG11_EAC

ドキュメントによれば ETC1 画像を読み込む場合 API に
GL_COMPRESSED_RGB8_ETC2 を渡すことになっています。
そのため KTX に ETC1 が含まれている場合、OpenGL 4.3 / OpenGL ES 3.0
ではヘッダの値をそのまま使うとエラーになります。

bool HasFormat( GLenum format )
{
  GLint numformat= 0;
  glGetIntegerv( GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numformat );
  const int	MAX_TLISTBUFFER= 128;
  GLint lists[MAX_TLISTBUFFER];
  glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS, lists );
  for( int fi= 0 ; fi< numformat ; fi++ ){
    if( lists[fi] == format ){
      return  true;
    }
  }
  return  false;
}


GLuint KTX_Loader_Compressed( const void* memory, size_t memory_size )
{
  const KTX_Header*  hp= reinterpret_cast( memory );
  const void*        image_data= address_add( memory, sizeof(KTX_Header) + hp->bytesOfKeyValueData );

  unsigned int  image_size= *reinterpret_cast( image_data );
  image_data= address_add( image_data, sizeof(int32_t) );

  GLuint  texid= 0;
  glGenTextures( 1, &texid );
  glBindTexture( GL_TEXTURE_2D, texid );

  GLenum  cformat= dp->glInternalFormat;
  if( cformat == GL_ETC1_RGB8_OES && HasFormat( GL_COMPRESSED_RGB8_ETC2 ) ){
    // **** ここで ETC2 に置き換える ****
    cformat= GL_COMPRESSED_RGB8_ETC2;
  }

  glCompressedTexImage2D( GL_TEXTURE_2D, 0,
           cformat,
           hp->pixelWidth,
           hp->pixelHeight,
	   0,
	   image_size,
	   image_data );

  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

  return  texid;
}

関連エントリ
OpenGL / OpenGL ES KTX Texture の読み込み方