GLSL (OpenGL Shading Language)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 02:25, 22 мая 2016.
OpenGL Shading Language
GLSLlogo.jpg
Парадигма Функциональный, ленивый, модульный
Спроектировано Khronos Group
Первый   появившийся 2002
OS Кроссплатформенное
Расширение файла .glsl
Портал: https://www.opengl.org/
Под влиянием
C

Язык шейдеров OpenGL (GLSL(OpenGL Shading Language) или GLslang)[1] - это высокоуровневый язык шейдеров, основанный на синтаксисе языка C. Он был создан OpenGL ARB (OpenGL Architecture Review Board), чтобы предоставить разработчикам более четкий контроль графического потока без использования языка ассемблирования ARB или машинно-зависимых языков.

С продвижением графических карт появились новые особенности, позволяющие бОльшую гибкость на уровнях вершины и фрагмента в потоке отрисовки. Возможность программирования на этом уровне достигнуто с помощью шейдеров вершин и фрагментов.

Язык шейдеров OpenGL это по сути несколько близко связанных языков. Эти языки используются для создания шейдеров каждого программного процессора, содержащегося в потоке процессов OpenGL. В частности это процессоры вершин, контроля мощения, анализ мощения, геометрии, фрагментов и вычислительный процессор.

Язык применим ко всем языкам, и обычно он используется как отдельный язык. К специфическим языками обращение происходит по имени процессора, на который они нацелены: вершин, контроля и анализа мощения, геометрии, фрагментов или вычислений.

Большинство структур OpenGL не отслеживаются или доступны для шейдеров. Обычно переменные пользователя будут использованы для связи между различными состояниями потока OpenGL. Однако небольшое количество состояний будет отслежено и автоматически доступо для шейдеров. Есть несколько встроенных переменных для интерфейсов между различными стадями потока OpenGL.

История

Изначально эта функциональность былаполучена путем написания шейдеров в языке ассемблирования ARB - сложное и неявное задание. OpenGL ARB создал язык шейдеров OpenGL для предоставления более наглядных методов для программирования модуля графики, в то же время поддерживая преимущества открытых стандартов, которые принадлежат OpenGL.

Впервые язык был представлен как расширение OpenGL 1.4. GLSL был включен в ядро OpenGL 2.0. Это была первая основная переработка OpenGL с момента его основания в 1992.

Некоторые преимущества использования GLSL:

  • Кросс-платформенная совместимость на многих ОС, включая GNU/Linux, Mac OS X и Windows.
  • Возможность написания шейдеров, которые могут быть использованы на графических картах любых производителей, поддерживающих язык шейдеров OpenGL.
  • Все поставщики аппаратного обеспечения включают компилятор GLSL в драйверы, что позволяет каждому поставщику создать код, оптимизированный для их конкретной архитектуры графической карты.

Обзор

Процессор вершин

Процессор вершин это программируемый модуль, который обрабатывает входные вершины и данные, с ними связанные. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются шейдерами вершин. Когда набор шейдеров вершин успешно скомпилирован и слинкован, они формируют исполняемые шейдер вершин, который выполняется на процессоре.

Процессор вершин работает над одной вершиной в момент времени. Он не замещает графические операции, котрые требуют знания нескольких вершин одновременно.

Процессор контроля мощения

Процессор контроля мощения это программируемый модуль, который обрабатывает патчи входных вершин и данные, связанные с ними, выделяет новый выходной патч. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются шейдерами контроля мощения. Когда набор таких шейдеров успешно скомпилирован и слинкован, они формируют исполняемые шейдер контроля мощения, который выполняется на процессоре.

Такой шейдер вызывается для каждого выходного патча. Каждый вызов читает атрибуты каждой входной или выходной вершины в патче, но может записать только предварительные атрибуты для соответствия с выходной вершиной. Вызовы шейдера совместно производят набор атрибутов для каждого патча. После завершения всех вызовов выходные вершины и атрибуты патча ассемблируются для формирования патча, которые используется последовательными стадиями потока.

Вызовы шейдера выполняются в большинстве случаев независимо в неопределенном порядке. Н\Однако встроенная функция barrier() может быть использована для контроля порядка выполнения, синхронизируя вызовы, эффективно разделяя выполнение шейдера на набор фаз. Шейдер получит неопределенный результат, если один вызов читает атрибуты, в ттот же момент записываемые другим вызовом, или если два вызова пытаются записать различные значения в вывод одновременно.

Процессор анализа мощения

Процессор анализа мощения это программируемый модуль, который обрабатывает патчи входных вершин и данные, связанные с ними, выделяет новый выходной патч. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются шейдерами анализа мощения. Когда набор таких шейдеров успешно скомпилирован и слинкован, они формируют исполняемые шейдер анализа мощения, который выполняется на процессоре.

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

Геометрический процессор

Геометрический процессор это программируемый модуль, который оперирует с данными входных вершин для примитивов, ассемблированных после обработки вершины, и выдает последовательность вершин, формирующий выходные примитивы. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются геометрическими шейдерами. Когда ряд геометрических шейдеров успешно скомпилированы и слинкованы на процессоре, они образуют исполнительный файл геометрического шейдера, который выполняется на процессоре.

Единичный выов геометрического шейдера, выполняемого на геометрическом процессоре, операрирует на объявленных входных примитивах с фиксированным числом вершин. Этот вызов может выделять различное количество вершин, которые ассемблируются в примитивы, объявленные как выходные примитивы, в последовательность стадий потока.

Процессор фрагментов

Процессор фрагментов это программируемый модуль, который операрирует о значениями фрагментов и относящимися к ним данными. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются шейдерами фрагментов. Когда ряд шейдеров фрагментов успешно скомпилированы и слинкованы на процессоре, они образуют исполнительный файл шейдера фрагментов, который выполняется на процессоре.

Шейдер фрагментов не может менять позицию фрагмента (x, y). Доступ к соседним фрагментов запрещен. Значения, вычисленные шейдером фрагментов, окончательно используются для обновления буффера фрейма или буфера текстуры, в зависимости от текущего состояния OpenGL и команды OpenGL, которая вызвала создание фрагмента.

Вычислительный процессор

Вычислительный процессор это программируемый модуль, который выполняется независимо от других шейдерных процессоров. Модули компиляции, написанные на языке шейдеров OpenGL и используемые в процессоре, называются вычислительными шейдерами. Когда ряд шейдеров фрагментов успешно скомпилированы и слинкованы на процессоре, они образуют исполнительный файл вычислительного шейдера, который выполняется на процессоре.

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

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

Версии

Версии GLSL - это расширения версий OpenGL API. Только с версий 3.3 GLSL и OpenGL номера младших и старших версий совпадают. Отношения этих версий GLSL и OpenGL приведены в следующей таблице:

Версия GLSL Версия OpenGL Дата Шейдерный препроцессор
1.10.59 2.0 Апрель 2004 #версия 110
1.20.8 2.1 Сентябрь 2006 #версия 120
1.30.10 3.0 Август 2008 #версия 130
1.40.08 3.1 Март 2009 #версия 140
1.50.11 3.2 Август 2009 #версия 150
3.30.6 3.3 Февраль 2010 #версия 330
4.00.9 4.0 Март 2010 #версия 400
4.10.6 4.1 Июль 2010 #версия 410
4.20.11 4.2 Август 2011 #версия 420
4.30.8 4.3 Август 2012 #версия 430
4.40 4.4 Июль 2013 #версия 440
4.50 4.5 Август 2014 #версия 450

Версия 4.40

Независимые скомпилированные модули написаны на языке, называемый шейдерами. Программа это набор шейдеров, которые скомпилированы и слинкованы вместе, всецело создают один и более программных стадий потока OpenGL. Все шейдеры для отдельной программной стадии должен быть внутри похожей программы. Полный ряд стадий программы могут быть заложены в одну программу или стадии могут быть разделены несколькими программами[2].

Управление ошибками

В общем компиляторы принимают программы, неправильно сделанные, чтобы иметь возможность определить все неверные программы. Портативность обеспечивается только для правильно сделанных программ, которые описаны ниже. Компиляторы содействуют определению неправильных программ и выдают диагностические сообщения, но не требуется делать это во всех случаях. Ошибки времени компиляции должны вовращаться для лексически или грамматически некорретных шейдеров. О других ошибках сообщается во время компиляции или линковки, как и установлено. "Мертвый" код должен быть проверен на ошибки. Например:

if (false) // изменение false на true не покроет дополнительные ошибки
 statement; // statement должен быть в любом случае проверен на ошибки

Примеры

Тривиальный пример шейдера вершин GLSL

Преобразует входную вершну тем же способом, что и фиксированная функция потока.

void main(void) {
	gl_Position = ftransform();
}

Заметим, что ftransform() более недоступна с GLSL 1.40 и GLSL ES 1.0. Вместо этого программист должен управлять явно проекцией и матрицами видов модели, чтобы соответствовать новому стандарту OpenGL 3.1.

#version 140

uniform Transformation {
	mat4 projection_matrix;
	mat4 modelview_matrix;
};

in vec3 vertex;

void main(void) {
	gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
}

Тривиальный пример шейдера мощения GLSL

Простой пример сквозного шейдера контроля мощения для позиции.

#version 400

layout(vertices=3) out;

void main(void) {
	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;	gl_TessLevelOuter[0] = 1.0;
	gl_TessLevelOuter[1] = 1.0;
	gl_TessLevelOuter[2] = 1.0;
	gl_TessLevelInner[0] = 1.0;
	gl_TessLevelInner[1] = 1.0;
}

Простой пример сквозного шейдера анализа мощения для позиции.

#version 400

layout(triangles,equal_spacing) in;

void main(void) {
	vec4 p0 = gl_in[0].gl_Position;
	vec4 p1 = gl_in[1].gl_Position;
	vec4 p2 = gl_in[2].gl_Position;

	vec3 p = gl_TessCoord.xyz;

	gl_Position = p0*p.x + p1*p.y + p2*p.z;
}

Тривиальный пример геометрического шейдера GLSL

Простой пример сквозного шейдера для цвета и позиции.

#version 120
#extension GL_EXT_geometry_shader4 : enable

void main(void) {
	for (int i = 0; i < gl_VerticesIn; ++i) {
		gl_FrontColor = gl_FrontColorIn[i];
		gl_Position = gl_PositionIn[i];
		EmitVertex();
	}
}

Начиная с OpenGL 3.2 с GLSL 1.50 геометрические шейдеры были адаптированы к функционалу ядра, что означает, что больше нет необходимости использовать расширения.Однако синтаксис немного отличается. Ниже приведен простой пример сквозного шейдера она позиций вершины (для треугольника) в версии 1.50:

#version 150

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

void main(void) {
	for (int i = 0; i < gl_in.length(); ++i) {
		gl_Position = gl_in[i].gl_Position;
		EmitVertex();
	}
	EndPrimitive();
}

Тривиальный пример шейдера фрагментов GLSL

Создает красный фрагмент.

#version 120

void main(void) {
	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

В версиях GLSL 1.30 и поздних можно использовать следующее:

glBindFragDataLocation(Program, 0, "MyFragColor");

где:

  • Program – управляет шейдерной программой;
  • 0 – буфер номера цвета, ассоциированный с переменной; если вы не используете множественные отрисовки, то нужно ввести 0;
  • "MyFragColor" – название выходной переменной в шейдерной программе, с которой связан данный буфер.
#version 150

out vec4 MyFragColor;

void main(void) {
	MyFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Примечания

Ссылки

  1. Википедия