glDeleteShader - порядок не имеет значения?
В OpenGL заказ на glAttachShader
не имеет значения, это то же самое для glDeleteShader
? Я бы сказал, что да, если происходит какое-то динамическое распределение памяти, но, возможно, это обрабатывается по-другому в контексте opengl.
4 ответа
Нет, порядок удаления шейдеров в большинстве случаев не важен.
Я говорю в основном, потому что не имеет смысла удалять ваш шейдер, прежде чем присоединить его и связать вашу программу GLSL. Однако после того, как программа связана, вы можете делать с шейдерами все, что захотите.
Удаление объекта в OpenGL обрабатывается драйвером и не обязательно происходит немедленно. Это должно работать так, потому что OpenGL может ставить в очередь команды, которые все еще ссылаются на объект, который вы пытаетесь удалить. Если он немедленно удалил их, то команды, которые уже были выполнены, но еще не завершены, будут иметь неопределенные результаты. Вместо этого GL удаляет память объекта через некоторое время после вызова glDelete* (...)
когда ничто другое не имеет ссылки на это.
Единственное, что GL сделает сразу, когда вы позвоните glDelete* (..)
это освободить имя объекта для повторного использования glGen* (...)
команда (и отвязать его от текущего контекста). Восстановление памяти не произойдет до некоторого момента в будущем.
Ответ прост: это не имеет значения. Вы можете удалить их в любое время после их присоединения к программе, и они будут продолжать действовать до тех пор, пока на них больше не будут ссылаться.
Детали времени жизни шейдеров часто неправильно понимают. Ключевая формулировка из спецификации:
Когда шейдерный объект или программный объект удаляется, он помечается для удаления, но его имя остается действительным до тех пор, пока базовый объект не может быть удален, поскольку он больше не используется. Шейдерный объект используется, когда он присоединен к любому программному объекту. Программный объект используется, пока он является текущей программой в любом контексте.
Это находится в разделе 5.1.3 спецификации GL 4.4 и в добавлении D.1.2 спецификации GL 3.3.
Таким образом, вопреки распространенному мнению, имя шейдера остается действительным за пределами glDeleteShader()
позвоните, если он в данный момент используется. Это отличается от того, как обрабатываются имена для других типов объектов, таких как текстуры или буферы, где имя сразу становится недействительным после вызова удаления.
Это примерная последовательность вызовов для иллюстрации этих правил:
GLuint progA = glCreateProgram();
GLuint vertA = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(progA, vertA);
glDeleteShader(vertA);
// vertA remains alive, since it's attached to progA.
// Set and compile source for vertA.
GLuint fragA = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(progA, fragA);
glDeleteShader(fragA);
// fragA remains alive, since it's attached to progA.
// Set and compile source for fragA.
glLinkProgram(progA);
glUseProgram(progA);
GLuint progB = glCreateProgram();
GLuint vertB = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(progB, vertB);
glDeleteShader(vertB);
// vertB remains alive, since it's attached to progB.
// Set and compile source for vertB.
glAttachShader(progB, fragA);
// Even though we called delete for fragA, we can still use it, since the reference in progA kept it alive.
glLinkProgram(progB);
glUseProgram(progB);
// progA, vertA, fragA, progB, and vertB are all still alive.
glDeleteProgram(progA);
// progA is not referenced anywhere, so it is now deleted.
// Since progA contained the last reference to vertA, vertA is now also deleted.
// progB, vertB and fragA are still valid.
glDeleteProgram(progB);
// progB is the current program, so it remains alive, together with both its attached shaders.
GLint deleteStatus = GL_FALSE;
glGetShaderiv(fragA, GL_DELETE_STATUS, &deleteStatus);
// deleteStatus is GL_TRUE. Note that we could legally use fragA as a name, even though we called glDeleteShader() on it long ago.
glUseProgram(0);
// This releases the last reference to progB, so it is now deleted.
// progB being deleted releases the last reference to vertB and fragA, so both of them are now deleted.
glGetShaderiv(fragA, GL_DELETE_STATUS, &deleteStatus);
// This would now be an error, since fragA is not valid anymore.
Да, шейдеры могут быть удалены в любом порядке. Create
/Delete
следовать той же семантике, что и malloc
/free
сделать для сырых блоков памяти.
Не голосуйте, просто проходите мимо:)
void
DeleteShader
(uint
shader
)
Если шейдер не привязан ни к какому объекту программы, он немедленно удаляется. В противном случае шейдер помечается для удаления и будет удален, когда он больше не будет прикреплен к какому-либо программному объекту. Если объект помечен для удаления, его логический бит состояния
DELETE_STATUS
установлен в true.
Графическая система OpenGL®, версия 4.4, основной профиль, 19 марта 2014 г., с. 81. - §7.1 Шейдерные объекты.