为 vscode 配置 glsl 插件:
pacman -S glslang
,/usr/bin/glslangValidatorglslangValidator -S vert test.vs
-查询着色器信息
void glGetShaderiv(GLuint shader,
GLenum pname,
GLint *params);
GL_SHADER_TYPE, GL_DELETE_STATUS, GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH -获取错误日志
void glGetShaderInfoLog(GLuint shader,
GLsizei maxLength,
GLsizei *length,
GLchar *infoLog);
-用 GL_COMPILE_STATUS
查询编译状态,如果编译失败,用 glGetShaderInfoLog()
存储错误信息:
# use sb7::application::*;
#
# #[derive(Default)]
# struct App;
#
# unsafe fn test_shader() -> Result<(), Box<dyn std::error::Error>> {
# let src = "#version 460 core
#
# layout (location = 0) out vec4 color;
#
# uniform scale;
# uniform vec3 bias;
#
# void main(void)
# {
# color = vec4(1.0, 0.5, 0.2, 1.0) * scale + bias;
# }";
# let src = std::ffi::CString::new(src)?;
#
# let shader = gl::CreateShader(gl::FRAGMENT_SHADER);
# gl::ShaderSource(shader, 1, &src.as_ptr(), std::ptr::null());
gl::CompileShader(shader);
// check shader compile status
let mut success = 0;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
if success != gl::TRUE as i32 {
// get log length
let mut len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
// alloc buffer to store log info
let mut log: Vec<u8> = Vec::with_capacity(len as _);
log.resize(len as _, 0);
// use glGetShaderInfoLog() to store log info
gl::GetShaderInfoLog(shader, len,
std::ptr::null_mut(),
log.as_mut_ptr() as _);
// print error log
let log = std::str::from_utf8(&log)?;
println!("{}", log);
}
#
# Ok(())
# }
#
# impl Application for App {
# fn startup(&mut self) {
# if let Err(e) = unsafe { test_shader() } {
# println!("err: {:?}", e);
# }
# }
# }
#
# fn main() {
# App.run();
# }
#
这是 docs.gl 里使用的方法,书里没有检查 COMPILE_STATUS,反正效果一样就是了:
# use sb7::application::*;
#
# #[derive(Default)]
# struct App;
#
# unsafe fn test_shader() -> Result<(), Box<dyn std::error::Error>> {
# let src = "#version 460 core
#
# layout (location = 0) out vec4 color;
#
# uniform scale;
# uniform vec3 bias;
#
# void main(void)
# {
# color = vec4(1.0, 0.5, 0.2, 1.0) * scale + bias;
# }";
# let vs_src = std::ffi::CString::new(src)?;
#
# let shader = gl::CreateShader(gl::FRAGMENT_SHADER);
# gl::ShaderSource(shader, 1, &vs_src.as_ptr(), std::ptr::null());
# gl::CompileShader(shader);
#
let mut len = 0;
let mut log: Vec<u8> = Vec::with_capacity(len as _);
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
log.resize(len as _, 0);
gl::GetShaderInfoLog(shader, len, std::ptr::null_mut(),
log.as_mut_ptr() as _);
let log = std::str::from_utf8(&log)?;
println!("{}", log);
#
# Ok(())
# }
#
# impl Application for App {
# fn startup(&mut self) {
# if let Err(e) = unsafe { test_shader() } {
# println!("err: {:?}", e);
# }
# }
# }
#
# fn main() {
# App.run();
# }
着色器:
version 460 core
layout (location = 0) out vec4 color;
uniform scale;
uniform vec3 bias;
void main(void)
{
color = vec4(1.0, 0.5, 0.2, 1.0) * scale + bias;
}
对应的错误输出,不同的 OpenGL 实现输出的信息不同:
0:5(15): error: syntax error, unexpected ';', expecting '{'
// todo webgl_demo
glGetProgramInfoLog()
glGetProgramiv()
:
# use sb7::application::*;
#
# #[derive(Default)]
# struct App;
#
# unsafe fn test_shader() -> Result<(), Box<dyn std::error::Error>> {
# let vs_src = "#version 460 core
#
# void main(void)
# {
# const vec4 vertices[3] = {
# vec4( 0.25, -0.25, 0.5, 1.0),
# vec4(-0.25, -0.25, 0.5, 1.0),
# vec4( 0.25, 0.25, 0.5, 1.0)
# };
#
# gl_Position = vertices[gl_VertexID];
# }";
# let vs_src = std::ffi::CString::new(vs_src)?;
#
# let vs = gl::CreateShader(gl::VERTEX_SHADER);
# gl::ShaderSource(vs, 1, &vs_src.as_ptr(), std::ptr::null());
# gl::CompileShader(vs);
#
# let fs_src = "#version 460 core
#
# layout (location = 0) out vec4 color;
#
# vec3 myFunction();
#
# void main(void)
# {
# color = vec4(myFunction(), 1.0);
# }";
#
# let fs_src = std::ffi::CString::new(fs_src)?;
#
# let fs = gl::CreateShader(gl::FRAGMENT_SHADER);
# gl::ShaderSource(fs, 1, &fs_src.as_ptr(), std::ptr::null());
# gl::CompileShader(fs);
#
let program = gl::CreateProgram();
gl::AttachShader(program, vs);
gl::AttachShader(program, fs);
gl::LinkProgram(program);
let mut len = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
let mut log: Vec<u8> = Vec::with_capacity(len as _);
log.resize(len as _, 0);
gl::GetProgramInfoLog(program, len, std::ptr::null_mut(),
log.as_ptr() as _);
println!("{}", std::str::from_utf8(&log)?);
# Ok(())
# }
#
# impl Application for App {
# fn startup(&mut self) {
# if let Err(e) = unsafe { test_shader() } {
# println!("err: {:?}", e);
# }
# }
# }
#
# fn main() {
# App.run();
# }
在 glLinkProgram()
前调用
void glProgramParameteri(GLuint program,
GLenum pname,
GLint value);
类似与 glTexParameteri()
,pname
= GL_PROGRAM_SEPARABLE
,value = GL_TRUE
,调用 glUseProgramStages()
将 program 添加到管线对象里。glBindProgramPipeline()
:使用管线对象进行渲染
# use sb7::application::*;
#
# #[derive(Default)]
# struct App {
# vao: u32,
# pipeline: u32,
# }
#
# unsafe fn init_pipeline() -> Result<u32, Box<dyn std::error::Error>> {
# let vs_src = std::ffi::CString::new(
# "#version 460 core
#
# out vec4 vs_color;
#
# void main(void)
# {
# const vec4 vertices[3] = {
# vec4( 0.5, -0.5, 0.0, 1.0),
# vec4(-0.5, -0.5, 0.0, 1.0),
# vec4( 0.0, 0.5, 0.0, 1.0)
# };
#
# const vec4 colors[3] = {
# vec4(1.0, 0.0, 0.0, 1.0),
# vec4(0.0, 1.0, 0.0, 1.0),
# vec4(0.0, 0.0, 1.0, 1.0),
# };
#
# gl_Position = vertices[gl_VertexID];
# vs_color = colors[gl_VertexID];
# }",
# )?;
#
let vs = gl::CreateShader(gl::VERTEX_SHADER);
gl::ShaderSource(vs, 1, &vs_src.as_ptr(), std::ptr::null());
gl::CompileShader(vs);
#
# let fs_src = std::ffi::CString::new(
# "#version 460 core
#
# layout (location = 0) out vec4 color;
# in vec4 vs_color;
#
# void main(void)
# {
# color = vs_color;
# }",
# )?;
#
let fs = gl::CreateShader(gl::FRAGMENT_SHADER);
gl::ShaderSource(fs, 1, &fs_src.as_ptr(), std::ptr::null());
gl::CompileShader(fs);
let vs_prog = gl::CreateProgram();
gl::AttachShader(vs_prog, vs);
gl::ProgramParameteri(vs_prog, gl::PROGRAM_SEPARABLE, gl::TRUE as _);
gl::LinkProgram(vs_prog);
let fs_prog = gl::CreateProgram();
gl::AttachShader(fs_prog, fs);
gl::ProgramParameteri(fs_prog, gl::PROGRAM_SEPARABLE, gl::TRUE as _);
gl::LinkProgram(fs_prog);
let mut pipeline = 0;
gl::CreateProgramPipelines(1, &mut pipeline);
gl::UseProgramStages(pipeline, gl::VERTEX_SHADER_BIT, vs_prog);
gl::UseProgramStages(pipeline, gl::FRAGMENT_SHADER_BIT, fs_prog);
gl::DeleteShader(vs);
gl::DeleteShader(fs);
gl::DeleteProgram(vs_prog);
gl::DeleteProgram(fs_prog);
# Ok(pipeline)
# }
#
# impl Application for App {
# fn startup(&mut self) {
# unsafe {
# let mut vao = 0;
# gl::CreateVertexArrays(1, &mut vao);
# gl::BindVertexArray(vao);
#
# let pipeline = init_pipeline().unwrap();
gl::BindProgramPipeline(pipeline);
#
# *self = Self { vao, pipeline }
# }
# }
#
# fn render(&self, _current_time: f64) {
# unsafe {
# gl::ClearBufferfv(gl::COLOR, 0, [0.0, 0.0, 0.0, 1.0].as_ptr());
# gl::DrawArrays(gl::TRIANGLES, 0, 3);
# }
# }
#
# fn shutdown(&mut self) {
# unsafe {
# gl::DeleteProgramPipelines(1, &self.pipeline);
# gl::DeleteVertexArrays(1, &self.vao);
# }
# }
# }
#
# fn main() {
# App::default().run();
# }
glCreateShaderProgram()
translate:
const GLuint shader = glCreateShader(type);
if (shader) {
glShaderSource(shader, count, strings, NULL);
glCompileShader(shader);
const GLuint program = glCreateProgram();
if (program) {
GLint compiled = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
if (compiled) {
glAttachShader(program, shader);
glLinkProgram(program);
glDetachShader(program, shader);
}
/* append-shader-info-log-to-program-info-log */
}
glDeleteShader(shader);
return program;
} else {
return 0;
}
# use sb7::application::*;
#
# #[derive(Default)]
# struct App {
# info: String,
# }
#
# impl Application for App {
# fn startup(&mut self) {
# unsafe {
# let src = std::ffi::CString::new(
# "#version 460 core
#
# out vec4 color;
# layout (location = 2) out ivec2 data;
# out float extra;
#
# void main() {
# color = vec4(1.0);
# data = ivec2(1, 2);
# extra = 1.0;
# }",
# )
# .unwrap();
#
# let prog = gl::CreateShaderProgramv(
# gl::FRAGMENT_SHADER, 1,
# &src.as_ptr()
# );
#
let mut counts = 0;
gl::GetProgramInterfaceiv(
prog,
gl::PROGRAM_OUTPUT,
gl::ACTIVE_RESOURCES,
&mut counts
);
#
# let name_of = |name| match name as u32 {
# gl::FLOAT_VEC4 => "vec4",
# gl::INT_VEC2 => "ivec2",
# gl::FLOAT => "float",
# _ => "unknown",
# };
for index in 0..counts {
let mut params = [0; 2];
let mut name = [0u8; 64];
gl::GetProgramResourceiv(
prog,
gl::PROGRAM_OUTPUT,
index as _,
2,
[gl::TYPE, gl::LOCATION].as_ptr(),
2,
std::ptr::null_mut(),
params.as_mut_ptr(),
);
gl::GetProgramResourceName(
prog,
gl::PROGRAM_OUTPUT,
index as _,
64,
std::ptr::null_mut(),
name.as_mut_ptr() as _,
);
self.info.push_str(&format!(
"Index {}: {} {} @ location {}\n",
index,
std::str::from_utf8(&name)
.unwrap_or("unknown")
.trim_matches('\u{0}'),
name_of(params[0]),
params[1]
));
}
#
# gl::DeleteProgram(prog);
#
# println!("{}", self.info);
# }
# }
#
# fn ui(&mut self, ui: &imgui_glfw_rs::imgui::Ui) {
# use imgui_glfw_rs::imgui;
# let win = imgui::Window::new("OpenGL - Information")
# .resizable(false)
# .no_decoration()
# .position([10., 10.], imgui::Condition::Always);
# if let Some(end) = win.begin(ui) {
# ui.text(format!("{}", self.info));
# end.end();
# }
# }
# }
#
# fn main() {
# App::default().run();
# }
Index 0: color vec4 @ location 0
Index 1: data ivec2 @ location 2
Index 2: extra float @ location 1
# use sb7::application::*;
#
# #[derive(Default)]
# struct Uniforms {
# subroutine1: i32,
# }
#
# #[derive(Default)]
# struct App {
# render_program: u32,
# vao: u32,
# subroutines: [u32; 2],
# uniforms: Uniforms,
# }
#
# impl App {
# fn load_shaders(&mut self) {
# if self.render_program != 0 {
# unsafe { gl::DeleteProgram(self.render_program) };
# }
#
# self.render_program = sb7::program::link_from_shaders(
# &[
# sb7::shader::load(
# "media/shaders/subroutines/subroutines.vs.glsl",
# gl::VERTEX_SHADER,
# true,
# ),
# sb7::shader::load(
# "media/shaders/subroutines/subroutines.fs.glsl",
# gl::FRAGMENT_SHADER,
# true,
# ),
# ],
# true,
# );
#
# unsafe {
// get counts of subroutine
let mut counts = 0;
gl::GetProgramStageiv(
self.render_program,
gl::FRAGMENT_SHADER,
gl::ACTIVE_SUBROUTINES,
&mut counts,
);
let mut name = [0u8; 256];
for i in 0..counts {
gl::GetProgramResourceName(
self.render_program,
gl::FRAGMENT_SUBROUTINE,
i as _,
256,
std::ptr::null_mut(),
name.as_mut_ptr() as _,
);
let name = std::ffi::CString::new(
std::str::from_utf8(&name).unwrap().trim_matches('\u{0}'),
)
.unwrap();
self.subroutines[i as usize] = gl::GetSubroutineIndex(
self.render_program,
gl::FRAGMENT_SHADER,
name.as_ptr()
);
}
let name = std::ffi::CString::new("mySubroutineUniform").unwrap();
self.uniforms.subroutine1 = gl::GetSubroutineUniformLocation(
self.render_program,
gl::FRAGMENT_SHADER,
name.as_ptr(),
);
# }
# }
# }
#
# impl Application for App {
# fn init(&self) -> AppConfig {
# AppConfig {
# title: "OpenGL SuperBible - Shader Subroutines".into(),
# ..Default::default()
# }
# }
#
# fn startup(&mut self) {
# self.load_shaders();
#
# unsafe {
# gl::GenVertexArrays(1, &mut self.vao);
# gl::BindVertexArray(self.vao);
# }
# }
#
# fn render(&self, current_time: f64) {
# let i = current_time as usize;
# unsafe {
# gl::UseProgram(self.render_program);
#
# gl::UniformSubroutinesuiv(
# gl::FRAGMENT_SHADER,
# 1,
# &self.subroutines[i & 1]
# );
#
# gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
# }
# }
#
# fn on_key(&mut self, key: imgui_glfw_rs::glfw::Key,
# press: imgui_glfw_rs::glfw::Action) {
# if let imgui_glfw_rs::glfw::Action::Press = press {
# match key {
# imgui_glfw_rs::glfw::Key::R => self.load_shaders(),
# _ => {}
# }
# }
# }
# }
#
# fn main() {
# App::default().run();
# }
TODO: