Дебаггинг шейдеров — тяжелый труд. В шейдерах нет ничего подобного printf, и вряд ли будет, хотя инструменты разработчика с возможностями отладки уже появляются и будут совершенствоваться.
Действительно, сейчас вы можете использовать кое-какие трюки, но по некоторым причинам они не тривиальны. Но не всё потеряно, есть несколько функций для проверки, был ли код шейдера скомпилирован и прилинкован успешно.
Состояние шагов компилирования может быть запрошено в OpenGL 2.0 следующей функцией:
void glGetShaderiv(GLuint object, GLenum type, int *param);
// Параметры:
// object — Дескриптор обьекта. Либо шейдера, либо программы.
// type — GL_COMPILE_STATUS.
// param — возвращаемое значение, GL_TRUE если всё ОК, иначе GL_FALSE.
Состояние шагов линковки может быть запрошено в OpenGL 2.0 следующей функцией:
void glGetProgramiv(GLuint object, GLenum type, int *param);
// Параметры:
// object — Дескриптор обьекта. Либо шейдера, либо программы.
// type — GL_LINK_STATUS.
// param — возвращаемое значение, GL_TRUE если всё ОК, иначе GL_FALSE.
С расширениями шейдеров ARB одна и та же функция может быть использована для получения статуса обоих шагов, и линковки, и компилирования, в зависимости от параметров.
void glGetObjectParameterivARB(GLhandleARB object, GLenum type, int *param);
// Параметры:
// object — Дескриптор обьекта. Либо шейдера, либо программы.
// type — GL_OBJECT_LINK_STATUS_ARB или GL_OBJECT_COMPILE_STATUS_ARB.
// param — возвращаемое значение, 1 если всё ОК, иначе 0.
Существует много опций для второго параметра «type», однако здесь я их не буду объяснять.
Посетите сайт 3Dlabs для полной спецификации.
Если возвращена ошибка, существует возможность получить больше информации с помощью infoLog.
Этот лог хранит информацию о последней произведённой операции, такую как варнинги и ошибки при компиляции, или проблемы на этапе линковки. Этот лог может даже показать, были ли ваши шейдеры обработаны софтварно, что значит, что ваше железо не поддерживает что-то, что вы напрограммировали, или хардварно — идеальная ситуация. К сожалению, для сообщений InfoLog нет никакой спецификации, так что разные драйвера и железо могут выдавать разный текст.
Чтобы получить InfoLog для специфического шейдера или программы в OpenGL используйте следующие функции:
void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);// Параметры:// object — Дескриптор обьекта. Либо шейдера, либо программы.
// maxLen — макс. число получаемых символов от InfoLog.
// len — реальная длинна полученного InfoLog.
// log — Сам лог.
Опять же, в расширениях шейдеров ARB одна и та же функция используется для получения логов и шейдера, и программы:
void glGetInfoLogARB(GLhandleARB object, int maxLen, int *len, char *log);
// Параметры:
// object — Дескриптор обьекта. Либо шейдера, либо программы.
// maxLen — макс. число получаемых символов от InfoLog.
// len — реальная длинна полученного InfoLog.
// log — Сам лог.
В этом отношении спецификация GLSL могла бы быть и лучше… Чтобы получить лог, вы должны знать его длину.
Чтобы получить этот драгоценный бит информации, используйте следующие функции (OpenGL 2.0):
void glGetProgramiv(GLuint object, GLenum type, int *param);// Параметры:// object — Дескриптор обьекта. Либо шейдера, либо программы.
// type — GL_INFO_LOG_LENGTH.
// param — возвращаемое значение, длинна лога
Синтаксис расширений ARB в очередной раз проще — хватает одной функции:
void glGetObjectParameterivARB(GLhandleARB object, GLenum type, int *param);
// Параметры:
// object — Дескриптор обьекта. Либо шейдера, либо программы.
// type — GL_OBJECT_INFO_LOG_LENGTH_ARB.
// param — возвращаемое значение, длинна лога
Следующие функции могут быть использованы для вывода информации InfoLog В OpenGL 2.0:
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf(«%s
«,infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf(«%s
«,infoLog);
free(infoLog);
}
}
Использование шейдерных расширений ARB делает процесс проще:
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
&infologLength);if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
printf(«%s
«,infoLog);
free(infoLog);
}
}