План лекции. • API и Hardware. • Графический конвейер и шейдеры. • Связь с
предыдущей лекции. • Простой сэмпл. • Идеология DX и GL. • Особенности ...
Программные интерфейсы DirectX 11 и OpenGL 4 Advanced CG course, 2012
План лекции • API и Hardware • Графический конвейер и шейдеры • Связь с предыдущей лекции • Простой сэмпл
• Идеология DX и GL • Особенности программной реализации • Объекты и сущности DX и GL • DX Compute Shaders vs CUDA • Простой пример • Создание ресурсов • Привязка ресурсов к шейдерам • Эффекты в DX • Отладка и поиск ошибок • Аналоги механизма ООП
API программирования GPU • Графика • Вычисления общего назначения
API и Hardware • API: • DX9, DX10, OpenGL 1.0, OpenGL 2.0 • DX11, (OpenGL 3.0 & OpenGL 4.0) • Pipeline • Fixed Function Pipeline (DX7, OpenGL 1.0) • DX9 Pipeline (OpenGL 2.0+) • DX10 Pipeline (OpenGL 3.0+) • DX11 Pipeline (OpenGL 4.0+) • Hardware • DX7 hardware • DX8 hardware • DX9 hardware • DX10 hardware • DX11 hardware
Hardware, Pipeline и DirectX • Прямое соответствие • Фиксированный конвейер
• DX7 hardware = FFP. • Программируемый конвейер.
• DX10 hardware = VS-GS-PS;
GL 2.0 GL 3.0
• DX11 hardware = VS-HS-DS-GS-PS;
GL 4.0
• DX9 hardware = VS-PS;
DX11
GL 1.0
Как выбрать API? • На ОС какого типа должна работать моя программа? • Windows => DX или GL • Linux/Android => GL • MacOS => GL • На каком железе должна работать моя программа? • DX11 hardware => DX11 || GL 4.0 • DX10 hardware => DX11 || GL 3.0 • DX9 hardware => DX11 || DX9 (WinXP) || GL 2.0 • Везде => GL 1.0 || DX11 ()
Графичеcкий конвейер и шейдеры Vertex attribute fetch Resources (constants, textures, buffers)
Input Assembler vertex attributes tex fetches
Vertex Shader vs_output indices
struct VS_INPUT { float4 position : POSITION; float3 normal : NORMAL; float2 texCoord : TEXCOORD; float3 tangent : TANGENT; };
Primitive Assembly vs_output
Rasterizer
Early depth & stencil test
vs_output (interpolated) tex fetches
Pixel Shader render to texture
ps_output
Output Merger color
screen
Late depth test
GPU это
GPU это большой конвейер
GPU это большой конвейер
Как это использовать • Загрузка текста шейдеров из файла • Компиляция • Линковка
• Создание и загрузка данных • Привязка ресурсов • Draw call
Создание объекта программы в GL
Ray Marching на GL3 • http://courses.graphicon.ru/main/cg/2011/assigns/4
Ray Marching на GL3 • http://courses.graphicon.ru/main/cg/2011/assigns/4
Ray Marching на GL3 • http://courses.graphicon.ru/main/cg/2011/assigns/4
Ray Marching на GL3 • http://courses.graphicon.ru/main/cg/2011/assigns/4
Full screen quad на GL3 • http://courses.graphicon.ru/main/cg/2011/assigns/4
Full screen quad на GL3 std::ifstream vertSourceFile("../main/Vertex.vert"); std::ifstream fragSourceFile("../main/Fragment.frag"); std::string fragSource; std::string vertSource; … const char* tmpVertSource = vertSource.c_str(); const char* tmpFragSource = fragSource.c_str(); if (!glusBuildProgram(&g_program, &tmpVertSource, 0, 0, 0, &tmpFragSource)) throw std::runtime_error("shader compilation failed!");
Full screen quad на GL3 • glusBuildProgram(...)
Full screen quad на GL3 struct GLUSshaderprogram { GLUSuint program; GLUSuint vertex; GLUSuint control; GLUSint evaluation; GLUSuint geometry; GLUSuint fragment; };
Full screen quad на GL3 • g_pFullScreenQuad = new FullScreenQuad();
Full screen quad на GL3 • g_pFullScreenQuad = new FullScreenQuad();
float quadPos[] = { -1.0f, 1.0f, // v0 - top left corner -1.0f, -1.0f, // v1 - bottom left corner 1.0f, 1.0f, // v2 - top right corner 1.0f, -1.0f // v3 - bottom right corner }; m_vertexBufferObject = 0; m_vertexLocation = 0;
Full screen quad на GL3 • g_pFullScreenQuad = new FullScreenQuad();
Vertex Shader (1)
Full screen quad на GL3 glUseProgram(g_program.program); setUniform(g_program.program, "g_screenWidth", g_width); setUniform(g_program.program, "g_screenHeight", g_height); ... setUniform(g_program.program, "g_bgColor", float4(0,0,1,0)); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glViewport(0, 0, g_width, g_height); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); g_pFullScreenQuad->Draw();
Full screen quad на GL3 • g_pFullScreenQuad->Draw();
void FullScreenQuad::Draw() { glBindVertexArray(m_vertexArrayObject); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); }
Full screen quad на GL3 #version 330 in vec2 vertex; out vec2 fragmentTexCoord; void main(void) { fragmentTexCoord = vertex * 0.5 + 0.5; // [-1,1]-> [0,1] gl_Position = vec4(vertex, 0.0, 1.0); }
Full screen quad на GL3 #version 330 in vec2 fragmentTexCoord; out vec4 fragColor; void main(void) { fragColor = vec4(1,0,0,0); }
Реализации 4 задания
Реализации 4 задания
Графичеcкий конвейер и шейдеры Vertex attribute fetch Resources (constants, textures, buffers)
Input Assembler vertex attributes tex fetches
Vertex Shader vs_output indices
struct VS_INPUT { float4 position : POSITION; float3 normal : NORMAL; float2 texCoord : TEXCOORD; float3 tangent : TANGENT; };
Primitive Assembly vs_output
Rasterizer
Early depth & stencil test
vs_output (interpolated) tex fetches
Pixel Shader render to texture
ps_output
Output Merger color
screen
Late depth test
DirectX • API для доступа к функциональности GPU • ОС Windows и • Преимущественно С/C++, но
• COM (Component Object Model)/DLL • Для С# есть Managed DirectX
• Хотите использовать DX в вашем любимом ЯП? • Реализуйте поддержку COM объектов • http://www.rsdn.ru/article/com/introcom.xml
• Жесткая спецификация стандарта (DX9, DX10, DX11) • Каждая новая версия несовместима с предыдущей!
OpenGL • API для доступа к функциональности GPU • Мультиплатформенный • Мультиязыковой • Процедурный • Динамически расширяемый • Указатели на функции • wglGetProcAdress(…) • Доступ к объектам осуществляется при помощи
целочисленный имен • Понятие текущего объекта
glGenBuffers (1, &m_vbo); glBindBuffer(GL_ARRAY_BUFFER, m_vbo); glBufferData(…);
Объекты и сущности • Устройство (только в DX) • Контекст • VAO (Input Layout в DX) • Шейдеры • Буферы (VBO, PBO) • Текстуры • FBO (RTV в DX) • Sampler • *Image (UAV) • Состояния
*glBindImageTexture Image объекта нет
• Специальные объекты (много в OGL) • (типа Transform Feedback-Object, program-pipeline)
Объекты и сущности • Устройство (только в DX) • Контекст • VAO (Input Layout в DX) • Шейдеры • Буферы (VBO, PBO) • Текстуры • FBO (RTV в DX) • Sampler • *Image (UAV) • Состояния
*glBindImageTexture Image объекта нет
• Специальные объекты (много в OGL) • (типа Transform Feedback-Object, program-pipeline)
Transform feedback object
Stream Out & Transform feedback
Stream Out & Transform feedback • Работает как операция Append • В CUDA для этого необходимо делать scan • (префиксная сумма)
Константы • GL • Uniform переменные (uniform float3 lightDirection;) • UBO
На CPU:
float data[3] = {0.5f, 1.0f, 0.1f}; GLint location = glGetUniformLocation(a_program, “lightDirection”); if(location >= 0) glUniform3fv(location, 1, data); • DX11 • Константные буфера (= UBO в GL) • Эффекты упрощают жизнь (доступ к переменным по именам) cbuffer cbLights { float4 vLightColor[3] = {{1,0,0,0},{0,1,0,0},{0,0,1,0}}; float4 vLightPosition[3]; };
VS
CUDA Hello World
CUDA VectorAdd (CUDA_SDK) float* h_A = (float*)malloc(size); float* h_B = (float*)malloc(size); float* h_C = (float*)malloc(size); // Initialize input vectors RandomInit(h_A, N); RandomInit(h_B, N); // Allocate vectors in device memory cudaMalloc((void**)&d_A, size); cudaMalloc((void**)&d_B, size); cudaMalloc((void**)&d_C, size); // Copy vectors from host memory to device memory cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice); cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice); // Invoke kernel int threadsPerBlock = 256; int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; VecAdd(d_A, d_B, d_C, N);
// Copy result from device memory to host memory // h_C contains the result in host memory cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);
BasicCompute11
BasicCompute11
+ 500 строк С++ кода!
Привязка ресурсов к шейдерам • Ресурсы • Буферы • Текстуры • Константные буферы и константы • Шейдеры • Вершинные • Hull (Tesselation) • Domain (Evaluation) • Геометрические • Фрагментные (пиксельные) • Вычислительные (Compute Shaders, только в DX)
Привязка текстур в DX • Shader Resource View (SRV + Sampler) • Unordered Access View (UAV) • Render Target (RTV + DSV) • Render Target View • Depth Stencil View
Эффекты в DX • • • • •
Надстройка над DX, предоставляемая MS c DXSDK Свой компилятор Позволяет строить графический конвейер Определять sampler state, blend state, rasterizer state Позволяет обращаться к переменным по именам
technique11 RenderCubeMap { pass p0 { SetVertexShader (CompileShader(vs_5_0, VS_CubeMap())); SetHullShader(NULL); SetDomainShader(NULL); SetGeometryShader (CompileShader(gs_5_0, GS_CubeMap())); SetPixelShader (CompileShader(ps_5_0, PS_CubeMap())); SetBlendState (NoBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } };
Привязка текстур в GL void bindTexture (GLuint program, GLint unit, const GLchar *name, GLuint texture) { glActiveTexture (GL_TEXTURE0 + unit); glBindTexture (GL_TEXTURE_2D, texture); GLint location = glGetUniformLocation (program, name); if(location >=0) glUniform1i(location, unit); }
Привязка текстур в GL
OGL4 Sampler Object
Привязка тестур в GL • Отличия в 3 и 4 версии
Привязка тестур в GL • Отличия в 3 и 4 версии
OGL4 Sampler Object • В OGL3 текстуры и сэмплеры не разделены • В OGL4 добавлен объект “Sampler”
glGenSamplers (1, &s_id); glSamplerParameteri (s_id, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glSamplerParameteri (s_id, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glSamplerParameteri (s_id, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE) ….. ….. glActiveTexture (GL_TEXTURE0 + unit); glBindSampler (unit, g_gaussSampler);
Текстурная фильтрация
Текстурная филтрация • Билинейная
Текстурная фильтрация
Текстурная фильтрация • Mip-Map уровни
Билинейная фильтрация
Трилинейная фильтрация
Анизотропная филтрация
Трилинейная фильтрация • Интерполяция между mip уровнями
Текстурная фильтрация • Анизотропная
Текстурная фильтрация в GL glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, );
• When the second parameter is GL_TEXTURE_MIN_FILTER,
parameter three can be: • GL_NEAREST_MIPMAP_NEAREST • GL_LINEAR_MIPMAP_NEAREST • GL_NEAREST_MIPMAP_LINEAR • GL_LINEAR_MIPMAP_LINEAR • GL_NEAREST • GL_LINEAR
• When the second parameter is GL_TEXTURE_MAG_FILTER,
parameter three can be: • GL_LINEAR • GL_NEAREST
Текстурная фильтрация в DX • В коде шейдера (Эффекты) SamplerState g_samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; ... float4 vDiffuse = g_txDiffuse.Sample( g_samLinear, Input.vTexcoord );
• Или на CPU, но не в SRV ID3D11SamplerState* m_pSamLinear; pd3dDeviceContext->PSSetSamplers( 0, 1, &m_pSamLinear ); pd3dDeviceContext->PSSetSamplers( 1, 1, &m_pSamLinear );
Как выбирается мип-уровень? void main() { vec4 firstData = texture(someSampler, textureCoords); vec2 otherTexDx = dFdx(otherTexCoords); vec2 otherTexDy = dFdy(otherTexCoords); if (parameterValue < 20) { firstData += textureGrad(someOtherSampler, otherTexCoords, otherTexDx, otherTexDy); } }
Рендеринг в текстуру • OpenGL Frame Buffer Object (FBO)
Рендеринг в текстуру Texture1
Texture2
Shader
FBO
Texture2
Out_Texture1
Out_Texture2
Depth buffer1
Depth buffer2
Отладка в DirectX • DirectX Debug Layer
Отладка в DirectX • Nsight
Отладка в OpenGL • glGetError() • Удобно использовать макрос типа CHECK_GL_ERROR • Предположим glTexImage2D сгенерировала ошибку • GL_INVALID_VALUE
Отладка в OpenGL • gDebugger
Разработка сложных шейдеров • DirectX11 “Dynamic Shader Linkage” • OpenGL4 “Subroutine” • Аналог виртуальных функций, но (!!!) • Это не виртуальные функции!
OpenGL subroutine #version 400 subroutine vec3 shadeModelType( vec4 position, vec3 normal); subroutine uniform shadeModelType shadeModel; subroutine ( shadeModelType ) vec3 phongModel( vec4 position, vec3 norm ) { // The ADS shading calculations go here (see: "Using // functions in shaders," and "Implementing // per-vertex ambient, diffuse and specular (ADS) shading") … } subroutine ( shadeModelType ) vec3 diffuseOnly( vec4 position, vec3 norm ) { vec3 s = normalize( vec3(Light.Position - position) ); return Light.Ld * Material.Kd * max( dot(s, norm), 0.0 ); }
OpenGL subroutine void main() { vec3 eyeNorm; vec4 eyePosition; // Get the position and normal in eye space getEyeSpace(eyeNorm, eyePosition);
// Evaluate the shading equation. This will call one of // the functions: diffuseOnly or phongModel LightIntensity = shadeModel( eyePosition, eyeNorm ); gl_Position = MVP * vec4(VertexPosition,1.0); }
OpenGL subroutine glUseProgram (programHandle); GLuint adsIndex = glGetSubroutineIndex(programHandle, GL_VERTEX_SHADER,"phongModel"); GLuint diffuseIndex = glGetSubroutineIndex(programHandle, GL_VERTEX_SHADER, "diffuseOnly");
glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &adsIndex); ... // Render the left teapot glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &diffuseIndex); ... // Render the right teapot
DX11 Dynamic Shader Linkage • Почти то же самое, но линкуем сразу класс
interface iBaseLight { float3 IlluminateAmbient (float3 vNormal); float3 IlluminateDiffuse (float3 vNormal); float3 IlluminateSpecular(float3 vNormal, int specularPower ); };
// ... interface iBaseMaterial { float3 GetAmbientColor(float2 vTexcoord); float3 GetDiffuseColor (float2 vTexcoord); int GetSpecularPower(); };
DX11 Dynamic Shader Linkage • Почти то же самое, но линкуем сразу класс
class cAmbientLight : iBaseLight { float3 m_vLightColor; bool m_bEnable; float3 IlluminateAmbient (float3 vNormal); float3 IlluminateDiffuse (float3 vNormal); float3 IlluminateSpecular(float3 vNormal, int specularPower ); }; class cBaseMaterial : iBaseMaterial { float3 m_vColor; int m_iSpecPower; float3 GetAmbientColor (float2 vTexcoord); float3 GetDiffuseColor (float2 vTexcoord); int GetSpecularPower(); };
DX11 Dynamic Shader Linkage iBaseLight g_abstractAmbientLighting; iBaseLight g_abstractDirectLighting; iBaseMaterial g_abstractMaterial; float4 PSMain ( PS_INPUT Input ) : SV_TARGET { // Compute the Ambient term float3 Ambient = g_abstractMaterial.GetAmbientColor( Input.vTexcoord ) * g_abstractAmbientLighting.IlluminateAmbient( Input.vNormal ); // Accumulate the Diffuse contribution float3 Diffuse = g_abstractMaterial.GetDiffuseColor( Input.vTexcoord ) * g_abstractDirectLighting.IlluminateDiffuse( Input.vNormal ); // Compute the Specular contribution float3 Specular = g_abstractDirectLighting.IlluminateSpecular( Input.vNormal, g_abstractMaterial.GetSpecularPower() ); // Accumulate the lighting with saturation float3 Lighting = saturate( Ambient + Diffuse + Specular ); return float4(Lighting,1.0f); }
Ссылки • DirectX 11 • MS DirectX SDK (http://msdn.microsoft.com/directx) • http://geekswithblogs.net/JoshReuben/archive/2012/03/14/d3d-11programming-in-a-nutshell.aspx (краткий справочник) • OpenGL 3.0+ • http://steps3d.narod.ru • http://www.gamedev.ru/community/ogl/ • http://nopper.tv/opengl.html • http://www.arcsynthesis.org/gltut/
Задание