Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Статьи / Работа с расширениями OpenGL с использованием NVIDIA OpenGL SDK 5.1. (Часть 7)

Работа с расширениями OpenGL с использованием NVIDIA OpenGL SDK 5.1. (Часть 7)

Автор:

В этой части мы будем использовать NVIDIA SDK 5.21. Если не учитывать необходимость исправления путей к заголовочным (.h) и библиотечным (.lib) файлам, переход на новую версию происходит без проблем. Однако в  этой версии исправлен ряд ошибок. Например, теперь не обязательно добавлять строку "#define GL_EXT_texture_compression_s3tc 1" для работы с расширением EXT_texture_compression_s3tc.

Работа со сжатыми текстурами
  Определение степени сжатия текстур.
  Увеличение производительности при использовании сжатых текстур
Сохранение сжатых текстур на диске
Загрузка сжатых текстур из файлов формата DDS.

Работа со сжатыми текстурами

Определение степени сжатия текстур.

В прошлой части статьи в таблице 2 были приведены коэффициенты сжатия различных форматов текстур. Но эти коэффициенты были получены на основе теоретических рассуждений - в реальных видеокартах эти цифры могут быть другими. В то же время, встречаются ситуации, когда программисту желательно точный объём текстур, например, чтобы не допустить так называемый texture trashing.

Реальный размер сжатой текстуры может быть определён при помощи функции glGetTexLevelParameteriv с параметром GL_TEXTURE_IMAGE_SIZE_ARB. Обратите внимание, что эта функция определяет размер указанного MipMap уровня, а не всей текстуры. Следовательно, для того, чтобы определить реальный объём текстуры при использовании MipMap-фильтрации, необходимо вызвать эту функцию для каждого MipMap-уровня и сложить полученные результаты. Если же вы попытаетесь определить таким способом реальный объём несжатой текстуры, то у вас ничего не получится - функция возвратит код ошибки INVALID_OPERATION.

Для демонстрации использования этой функции я написал небольшую программу, определяющую реальную степень сжатия текстур ускорителем (Точнее, первого MipMap уровня) (Ex01):

int CompressType[5]={ GL_RGB,
                      GL_COMPRESSED_RGB_ARB,
                      GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
                      GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
                      GL_COMPRESSED_RGBA_S3TC_DXT5_EXT};
string CompressString[5]={ "none",
                           "GL_COMPRESSED_RGB_ARB",
                           "GL_COMPRESSED_RGB_S3TC_DXT1_EXT",
                           "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT",
                           "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"};
//--------------------

//Пытаемся сжать текстуру
gluBuild2DMipmaps( texture0.target, CompressType[CompressIndex],
                   textureImage0.width, textureImage0.height,
                   textureImage0.format, GL_UNSIGNED_BYTE,   textureImage0.pixels);
//Проверяем, была ли сжата текстура
glGetTexLevelParameteriv(texture0.target, 0, GL_TEXTURE_COMPRESSED_ARB,
           &compressed);
//Текущий тип текстуры - сжатый
if (CompressIndex)
{
  if (compressed)
    console.add("Texture has been properly compressed");
  else
  {
    console.add("Texture has not been compressed");
    return;
  }
//Вычисляем размер текстуры
  int uncompressed_size = textureImage0.width * textureImage0.height *
            textureImage0.components;
  char str[200];
  sprintf(str, "Uncompress image size: %d", uncompressed_size);
  console.add(&str[0]);
// Вычисляем размер текстуры, при условии,
// что ускоритель хранит 24-битные текстуры как 32-х битные
  int real_uncompressed_size=uncompressed_size;
  if (textureImage0.components==3)
  {
    real_uncompressed_size=textureImage0.width*textureImage0.height*4;
    char str[200];
    sprintf(str, "Real uncompress image size: %d",
              real_uncompressed_size);
    console.add(&str[0]);
  };
//Получаем размер сжатой текстуры
  int compressed_size;
  glGetTexLevelParameteriv(texture0.target, 0, GL_TEXTURE_IMAGE_SIZE_ARB,
            &compressed_size);
  sprintf(str, "Compress image size: %d", compressed_size);
//Вычиляем коэффициенты сжатия
  console.add(&str[0]);
  sprintf(str, "Compression ration: %f",  float(uncompressed_size)/compressed_size);
  console.add(&str[0]);
  if (textureImage0.components==3)
  {
    sprintf(str, "Real compression ration: %f",
            float(real_uncompressed_size)/compressed_size);
      console.add(&str[0]);
  };
}

В программе вычисляются два коэффициента сжатия: обычный и реальный. Реальный коэффициент  сжатия основывается на предположении, что ускоритель хранит 24-х битные текстуры как 32-х битные (так поступают 99% современных ускорителей). Один из результатов работы программы показан на рисунке 1:

Изображение
Рисунок 1 - Информация о сжатии текстуры

Увеличение производительности при использовании сжатых текстур

Как известно, сжатые текстуры занимают намного меньше места, чем не сжатые, т.е их использование значительно снижает требования к полосе пропускания видеопамяти. Кроме того, операция декомпрессии очень проста (два умножения, которые могут выполняться параллельно, и сложение) и может быть легко конвейеризирована. Следовательно, использование сжатых текстур должно повышать производительность программы.

Для сравнения быстродействия сжатых и обычных текстур, я добавил в пример Ex03 (хромированный чайник) из второй части статьи поддержку сжатых текстур.

При помощи этой программы (Ex02) был проведен ряд измерений, результаты которых приведены в таблице 1. Измерения проводились на компьютере следующей конфигурации: Celeron 1.7GHz (Willamette-128), i845D+DDR PC2100, GeForce2MX 32MB (SDR, 175MHz) AGP4X. На компьютере были установлены Windows XP и драйверы Detonator 29.42.

Видеорежим  Параметры текстуры №1  Параметры текстуры №2  FPS в режиме RGB  FPS в режиме DXT1  FPS в режиме DXT5
640x480:32  256x128:32  256x256:32  144.8  185.4  184.7
640x480:32  2048x1024:32  2048:2048:32  62.5  106  76.3
640x480:32FSAAx2  2048x1024:32  2048:2048:32  9.6  51.3  35.9

Таблица 1. Сравнение производительности сжатых и несжатых текстур.

Как видно, при использовании текстур небольшого размера прирост скорости относительно небольшой и находится в пределах 30%. Но с ростом разрешения текстур (а это расширение целесообразно использовать только текстурами большого разрешения) преимущество DXT1 текстур растёт до 70%, а DXT5 - уменьшается до 20%. Одна из причин связана с тем, что DXT1 текстуры имеют в два раза меньший объём по сравнению с DXT5.

Но вот одно обстоятельство  является немного странным: текстура формата DXT5 занимает в 4 раза меньше места, чем несжатая 32-х битная текстура, но даёт прирост всего 20%. Как мне кажется, всё дело в том, что 4-х кратный прирост в скорости достижим только в том случае, когда текстурирование производится блоками по 16 текселей. Для декодирования большинства текселей ускоритель должен загрузить два 16-битных цвета и 2-х битный индекс коэффициент интерполяции. Т.е. для кодирования одного текселя из блока необходимо загрузить как минимум 16*2+2=34 бита и это без учёта альфа канала!!!. Т.е. мы получаем, что доступ к единичному пикселю из блока 4x4 S3TC текстуры проводится намного медленнее, чем доступ аналогичному пикселю несжатой текстуры. Следовательно, если  в процессе текстурирования ускоритель задействует не все 16 пикселей из блока 4x4 пикселя, то плановая скорость не будет достигнута.

Но, скорее всего, в действительности всё ещё сложнее. Дело в том, что почти все видеокарты семейства GeForce2 имеют 128 битную шину данных, которая состоит из 4-х независимых 32-х битных подшин. Следовательно, они могут обмениваться  с видеопамятью пакетами по 32 бит. В итоге, в ходе декодирования одного пикселя видеокарта будет в случае использования текстур форматов DXT1 и DXT5 загружать в видеопамять соответственно 64 и 128 бита информации.  Т.е. для декодирования одного пикселя формата DXT5 ускоритель должен обработать в 4 раза больше информации по сравнению с несжатой 32-х битной текстурой. С другой стороны, всё не так уж плохо: объём обрабатываемой информации не зависит от количества прочитанных текселей из блока 4x4 текселя.. А при использовании построчного текстурирования ускоритель обычно задействует подряд не менее 4-х текселей из одного блока. Следовательно, при использовании текстур формата DXT5 ускоритель в среднем считывает менее  32-х бит информации. Поэтому сжатые DXT5-текстуры всё же быстрее несжатых текстур, но не в 4 раза, а всего лишь на 20%. Тем не менее, из-за ошибки в видеокартах NVIDIA, мы вынуждены использовать именно этот формат для компрессии RGB-текстур.

Из всего этого можно сделать вывод, что если несжатые текстуры умещаются в видеопамяти, то компрессия текстур в большинстве случаев будет бессмысленна - прирост скорости будет очень мал, а качество пострадает ощутимо. Другое дело - использование сверхбольших текстур при большом разрешении экрана в условиях нехватки видеопамяти (последняя строка таблицы 1), когда сжатые текстуры позволяют избежать Texture Trashing. В этом случае, сжатые текстуры формата DXT5 дают 3.5-х кратный, а DXT1 - 5.5 кратный прирост производительности, причём на мощных видеокартах с более быстрой видеопамятью разница будет ещё сильнее: чем быстрее видеопамять, тем сильнее видеокарта страдает от Texture Trashing.

Страницы: 1 2 3 Следующая »

7 июня 2003

#расширения OpenGL, #NVIDIA, #OpenGL, #компрессия, #текстуры


Обновление: 13 ноября 2009

2001—2018 © GameDev.ru — Разработка игр