Ответ 1
Чтобы понять, что делает glTexStorage
, вам нужно понять, что делают функции glTexImage*
.
glTexImage2D
выполняет три функции:
- Он выделяет хранилище OpenGL для определенного уровня mipmap с определенным размером. Например, вы можете выделить 2D-изображение размером 64x64 как mipmap level 2.
- Он устанавливает внутренний формат для уровня mipmap.
- Он загружает пиксельные данные в текстуру. Последний шаг необязателен; если вы передаете значение NULL в качестве значения указателя (а объект буфера не привязан к
GL_PIXEL_UNPACK_BUFFER
), то передача пикселов не происходит.
Создание mipmapped текстуры вручную требует последовательности вызовов glTexImage
, по одному для каждого уровня mipmap. Каждый из размеров уровней mipmap должен быть правильного размера, основываясь на предыдущем размере уровня.
Теперь, если вы посмотрите на раздел 3.9.14 спецификации GL 4.2, вы увидите две страницы правил, которые должны следовать текстурному объекту, чтобы они были "полными". Доступ к объекту текстуры, который является неполным, не может быть доступен.
Среди этих правил такие вещи, как "mipmaps должны иметь соответствующий размер". Возьмем пример, который я привел выше: 2D-изображение размером 64x64, которое является уровнем mipmap 2. Было бы совершенно правильно использовать OpenGL-код для распределения уровня mipmap 1, который использовал текстуру 256x256. Или 16x16. Или 10x345. Все они были бы совершенно функциональными в отношении исходного кода. Очевидно, они создавали бы бессмыслицу как текстуру, так как текстура была бы неполной.
Снова рассмотрим mipmap 64x64 2. Я создаю это как свое первое изображение. Теперь я мог бы создать mipmap 128x128 1. Но я мог бы также создать mipmap с размером 128x12 9 1. Оба они полностью согласуются с уровнем mipmap 64x64 2 (размеры mipmap всегда округляются вниз). Хотя они оба последовательны, они также имеют разные размеры. Если драйвер должен распределить всю цепочку mipmap сразу (что вполне возможно), какой размер он выделяет? Он не знает. Он не может знать, пока вы явно не выделите остальных.
Вот еще одна проблема. Скажем, у меня есть текстура с полной цепью mipmap. Это, по правилам, полная текстура. И затем я снова назову glTexImage2D
. Что теперь? Я мог бы случайно изменить внутренний формат. Каждый уровень mipmap имеет отдельный внутренний формат; если они не все согласны, то текстура не завершена. Я мог бы случайно изменить размер текстуры, снова сделав текстуру незавершенной.
glTexStorage
предотвращает все эти возможные ошибки. Он создает все мипмапы, которые вы хотите передними, учитывая размер базового уровня. Он выделяет все эти mipmaps с одним и тем же форматом изображения, поэтому вы не можете его испортить. Это делает текстуру неизменной, поэтому вы не можете прийти и попытаться сломать текстуру с плохим вызовом glTexImage2D
. И это предотвращает другие ошибки, которые я даже не удосужился покрыть.
Вопрос не в том, что делает glTexStorage? Вопрос в том, "почему мы так долго прошли без него".
glTexStorage
не имеет отношения к glGenerateMipmap
; они являются ортогональными функциями. glTexStorage
выполняет именно то, что он говорит: он выделяет пространство для хранения текстур. Он не заполняет это пространство чем-либо. Таким образом, он создает текстуру с заданным размером, заполненным неинициализированными данными. Подобно glRenderbufferStorage
выделяет рендерингбуфер с заданным размером, заполненным неинициализированными данными. Если вы используете glTexStorage
, вам нужно загрузить данные с помощью glTexSubImage
(так как glTexImage
запрещено на неизменяемой текстуре).
glTexStorage
создает пространство для mipmaps. glGenerateMipmap
создает сами данные mipmap (меньшие версии базового слоя). Он также может создавать пространство для mipmaps, если это пространство еще не существует. Они используются для двух разных вещей.