mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-07-25 20:24:32 +00:00
Using headless opengl context to lint files, removed last bits of glslangValidator
This commit is contained in:
parent
26c855f016
commit
dc1495686a
3 changed files with 107 additions and 241 deletions
|
@ -1,102 +0,0 @@
|
||||||
import * as unzip from 'adm-zip'
|
|
||||||
import { execSync } from 'child_process'
|
|
||||||
import * as fs from 'fs'
|
|
||||||
import { writeFileSync } from 'fs'
|
|
||||||
import fetch from 'node-fetch'
|
|
||||||
import { platform } from 'os'
|
|
||||||
import * as vscode from 'vscode'
|
|
||||||
import { Extension } from './extension'
|
|
||||||
import { log } from './log'
|
|
||||||
|
|
||||||
const url = {
|
|
||||||
'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip',
|
|
||||||
'linux': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip',
|
|
||||||
'darwin': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-osx-Release.zip'
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = vscode.workspace.getConfiguration()
|
|
||||||
|
|
||||||
export async function bootstrapGLSLangValidator(e: Extension): Promise<boolean> {
|
|
||||||
const glslangValidatorPath = config.get('mcglsl.glslangValidatorPath') as string
|
|
||||||
if (!testExecutable(glslangValidatorPath)) {
|
|
||||||
if(!await promptDownload(e, glslangValidatorPath)) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function promptDownload(e: Extension, glslangValidatorPath: string): Promise<boolean> {
|
|
||||||
const chosen = await vscode.window.showErrorMessage(
|
|
||||||
`[mc-glsl] glslangValidator not found at: '${glslangValidatorPath}'.`,
|
|
||||||
{title: 'Download'},
|
|
||||||
{title: 'Cancel'}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!chosen || chosen.title !== 'Download') return false
|
|
||||||
|
|
||||||
return await tryInstallExecutable(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function tryInstallExecutable(e: Extension): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
await installExecutable(e)
|
|
||||||
} catch (e) {
|
|
||||||
log.error(`failed downloading glslangValidator ${e}`)
|
|
||||||
vscode.window.showErrorMessage(`Failed to install glslangValidator: ${e}`)
|
|
||||||
e.clearStatus()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function installExecutable(e: Extension) {
|
|
||||||
fs.mkdirSync(e.context.globalStoragePath, { recursive: true })
|
|
||||||
|
|
||||||
e.updateStatus('$(cloud-download)', 'Downloading glslangValidator')
|
|
||||||
|
|
||||||
const glslangBin = '/glslangValidator' + (platform() === 'win32' ? '.exe' : '')
|
|
||||||
const glslangPath = e.context.globalStoragePath + glslangBin
|
|
||||||
|
|
||||||
const response = await fetch(url[platform()])
|
|
||||||
log.info('glslangValidator download response status: ' + response.status)
|
|
||||||
|
|
||||||
const zip = new unzip(await response.buffer())
|
|
||||||
|
|
||||||
const bin = zip.readFile('bin' + glslangBin)
|
|
||||||
log.info('buffer length ' + bin.length)
|
|
||||||
writeFileSync(glslangPath, bin, {encoding: null, mode: 0o755})
|
|
||||||
|
|
||||||
// Make sure download was successful
|
|
||||||
if (!testExecutable(glslangPath)) {
|
|
||||||
throw new Error(`Unexpected error occurred checking for binary at ${glslangPath}. Please try again`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done!
|
|
||||||
log.info(`successfully downloaded glslangValidator to ${glslangPath}`)
|
|
||||||
vscode.window.showInformationMessage(
|
|
||||||
`glslangValidator has been downloaded to ${glslangPath}. Your config should be updated automatically.`
|
|
||||||
)
|
|
||||||
await config.update('mcglsl.glslangValidatorPath', glslangPath, vscode.ConfigurationTarget.Global)
|
|
||||||
e.clearStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
function testExecutable(glslangPath: string): boolean {
|
|
||||||
let stdout = ''
|
|
||||||
try {
|
|
||||||
stdout = execSync(glslangPath, {
|
|
||||||
stdio: 'pipe',
|
|
||||||
}).toString()
|
|
||||||
} catch (e) {
|
|
||||||
stdout = (e.stdout.toString() as string)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info('glslangValidator first line stdout: "' + stdout.slice(0, stdout.indexOf('\n')) + '"')
|
|
||||||
const success = stdout.startsWith('Usage')
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
log.info(`glslangValidator found at ${glslangPath}`)
|
|
||||||
} else {
|
|
||||||
log.warn(`glslangValidator not found at ${glslangPath}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return success
|
|
||||||
}
|
|
|
@ -107,6 +107,18 @@ impl Display for IncludePosition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum TreeType {
|
||||||
|
Fragment, Vertex
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<&'static str> for TreeType {
|
||||||
|
fn into(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
TreeType::Vertex => "vert",
|
||||||
|
_ => "frag"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MinecraftShaderLanguageServer {
|
impl MinecraftShaderLanguageServer {
|
||||||
pub fn error_not_available<DATA>(data: DATA) -> MethodError<DATA> {
|
pub fn error_not_available<DATA>(data: DATA) -> MethodError<DATA> {
|
||||||
|
@ -252,14 +264,24 @@ impl MinecraftShaderLanguageServer {
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
eprintln!("ancestors for {}:\n{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
|
eprintln!("ancestors for {}:\n\t{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
|
||||||
|
|
||||||
|
// the set of all filepath->content. TODO: change to Url?
|
||||||
let mut all_sources: HashMap<String, String> = HashMap::new();
|
let mut all_sources: HashMap<String, String> = HashMap::new();
|
||||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::new();//Vec::new();
|
// the set of filepath->list of diagnostics to report
|
||||||
|
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::new();
|
||||||
|
|
||||||
|
// we want to backfill the diagnostics map with all linked sources
|
||||||
|
let back_fill = |all_sources: &HashMap<String, String>, diagnostics: &mut HashMap<Url, Vec<Diagnostic>>| {
|
||||||
|
for (path, _) in all_sources {
|
||||||
|
diagnostics.entry(Url::from_file_path(path).unwrap()).or_default();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if we are a top-level file (this has to be one of the set defined by Optifine, right?)
|
||||||
if file_ancestors.is_empty() {
|
if file_ancestors.is_empty() {
|
||||||
|
// gather the list of all descendants
|
||||||
let root = self.graph.borrow_mut().find_node(uri).unwrap();
|
let root = self.graph.borrow_mut().find_node(uri).unwrap();
|
||||||
|
|
||||||
let tree = match self.get_dfs_for_node(root) {
|
let tree = match self.get_dfs_for_node(root) {
|
||||||
Ok(tree) => tree,
|
Ok(tree) => tree,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -273,24 +295,42 @@ impl MinecraftShaderLanguageServer {
|
||||||
let graph = self.graph.borrow();
|
let graph = self.graph.borrow();
|
||||||
let views = merge_views::generate_merge_list(&tree, &all_sources, &graph);
|
let views = merge_views::generate_merge_list(&tree, &all_sources, &graph);
|
||||||
|
|
||||||
let views = merger.generate_merge_list(&tree);
|
let tree_type = if uri.ends_with(".fsh") {
|
||||||
|
TreeType::Fragment
|
||||||
|
} else {
|
||||||
|
TreeType::Vertex
|
||||||
|
};
|
||||||
|
|
||||||
let stdout = self.invoke_validator(views)?;
|
let stdout = match opengl::validate(tree_type, views) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
back_fill(&all_sources, &mut diagnostics);
|
||||||
|
return Ok(diagnostics)
|
||||||
|
},
|
||||||
|
};
|
||||||
eprintln!("glslangValidator output: {}\n", stdout);
|
eprintln!("glslangValidator output: {}\n", stdout);
|
||||||
diagnostics.extend(self.parse_validator_stdout(&stdout, ""));
|
diagnostics.extend(self.parse_validator_stdout(stdout, ""));
|
||||||
} else {
|
} else {
|
||||||
let mut all_trees = Vec::new();
|
let mut all_trees: Vec<(TreeType, Vec<(NodeIndex, Option<_>)>)> = Vec::new();
|
||||||
|
|
||||||
for root in &file_ancestors {
|
for root in &file_ancestors {
|
||||||
let nodes = match self.get_dfs_for_node(*root) {
|
let nodes = match self.get_dfs_for_node(*root) {
|
||||||
Ok(nodes) => nodes,
|
Ok(nodes) => nodes,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]);
|
diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]);
|
||||||
|
back_fill(&all_sources, &mut diagnostics); // TODO: confirm
|
||||||
return Ok(diagnostics);
|
return Ok(diagnostics);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let tree_type = if uri.ends_with(".fsh") {
|
||||||
|
TreeType::Fragment
|
||||||
|
} else {
|
||||||
|
TreeType::Vertex
|
||||||
|
};
|
||||||
|
|
||||||
let sources = self.load_sources(&nodes)?;
|
let sources = self.load_sources(&nodes)?;
|
||||||
all_trees.push(nodes);
|
all_trees.push((tree_type, nodes));
|
||||||
all_sources.extend(sources);
|
all_sources.extend(sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,20 +338,20 @@ impl MinecraftShaderLanguageServer {
|
||||||
let graph = self.graph.borrow();
|
let graph = self.graph.borrow();
|
||||||
let views = merge_views::generate_merge_list(&tree.1, &all_sources, &graph);
|
let views = merge_views::generate_merge_list(&tree.1, &all_sources, &graph);
|
||||||
|
|
||||||
let stdout = self.invoke_validator(views)?;
|
let stdout = match opengl::validate(tree.0, views) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
eprintln!("glslangValidator output: {}\n", stdout);
|
eprintln!("glslangValidator output: {}\n", stdout);
|
||||||
diagnostics.extend(self.parse_validator_stdout(&stdout, ""));
|
diagnostics.extend(self.parse_validator_stdout(stdout, ""));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (path, _) in all_sources {
|
back_fill(&all_sources, &mut diagnostics);
|
||||||
diagnostics.entry(Url::from_file_path(path).unwrap()).or_default();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(diagnostics)
|
Ok(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_validator_stdout(&self, stdout: &str, source: &str) -> HashMap<Url, Vec<Diagnostic>> {
|
fn parse_validator_stdout(&self, stdout: String, source: &str) -> HashMap<Url, Vec<Diagnostic>> {
|
||||||
let stdout_lines = stdout.split('\n');
|
let stdout_lines = stdout.split('\n');
|
||||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(stdout_lines.count());
|
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(stdout_lines.count());
|
||||||
let stdout_lines = stdout.split('\n');
|
let stdout_lines = stdout.split('\n');
|
||||||
|
@ -422,34 +462,6 @@ impl MinecraftShaderLanguageServer {
|
||||||
Ok(Some(roots))
|
Ok(Some(roots))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invoke_validator(&self, tree_type: TreeType, source: LinkedList<&str>) -> Result<String> {
|
|
||||||
/* let mut eventloop = glutin::event_loop::EventLoop::new();
|
|
||||||
let context = glutin::ContextBuilder::new().build_headless(&eventloop, glutin::dpi::PhysicalSize::new(1920, 1080)); */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok("".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fn invoke_validator(&self, tree_type: TreeType, source: LinkedList<&str>) -> Result<String> {
|
|
||||||
let cmd = process::Command::new(&self.config.glslang_validator_path)
|
|
||||||
.args(&["--stdin", "-S", tree_type.into()])
|
|
||||||
.stdin(process::Stdio::piped())
|
|
||||||
.stdout(process::Stdio::piped())
|
|
||||||
.spawn();
|
|
||||||
|
|
||||||
let mut child = cmd?;//.expect("glslangValidator failed to spawn");
|
|
||||||
let stdin = child.stdin.as_mut().expect("no stdin handle found");
|
|
||||||
|
|
||||||
let mut io_slices: Vec<std::io::IoSlice> = source.iter().map(|s| std::io::IoSlice::new(s.as_bytes())).collect();
|
|
||||||
|
|
||||||
stdin.write_all_vectored(&mut io_slices[..])?;//.expect("failed to write to stdin");
|
|
||||||
stdin.flush()?;
|
|
||||||
let output = child.wait_with_output()?;//.expect("expected output");
|
|
||||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
|
||||||
Ok(stdout.trim().to_string())
|
|
||||||
} */
|
|
||||||
|
|
||||||
pub fn publish_diagnostic(&self, diagnostics: HashMap<Url, Vec<Diagnostic>>, document_version: Option<i32>) {
|
pub fn publish_diagnostic(&self, diagnostics: HashMap<Url, Vec<Diagnostic>>, document_version: Option<i32>) {
|
||||||
eprintln!("DIAGNOSTICS:\n{:?}", diagnostics);
|
eprintln!("DIAGNOSTICS:\n{:?}", diagnostics);
|
||||||
for (uri, diagnostics) in diagnostics {
|
for (uri, diagnostics) in diagnostics {
|
||||||
|
|
|
@ -1,43 +1,11 @@
|
||||||
use std::mem;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str;
|
use std::ffi::{CString, CStr};
|
||||||
use std::os::raw::c_void;
|
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
const SCREEN_WIDTH: u32 = 800;
|
pub fn validate(tree_type: super::TreeType, source: String) -> Option<String> {
|
||||||
const SCREEN_HEIGHT: u32 = 600;
|
let events_loop = glutin::event_loop::EventLoop::new();
|
||||||
|
|
||||||
const VERTEX_SHADER_SOURCE: &str = r#"
|
|
||||||
#version 330 core
|
|
||||||
layout (location = 0) in vec3 aPos;
|
|
||||||
layout (location = 1) in vec3 aColor; // Specify a vertex attribute for color
|
|
||||||
out vec3 color;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
|
|
||||||
color = aColor; // pass the color along to the fragment shader
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
const FRAGMENT_SHADER_SOURCE: &str = r#"
|
|
||||||
#version 330 core
|
|
||||||
out vec4 FragColor;
|
|
||||||
in vec3 color;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Set the fragment color to the color passed from the vertex shader
|
|
||||||
FragColor = vec4(color, 1.0);
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
fn doit() {
|
|
||||||
let mut events_loop = glutin::event_loop::EventLoop::new();
|
|
||||||
let window = glutin::window::WindowBuilder::new()
|
|
||||||
.with_title("Glutin Triangle")
|
|
||||||
.with_inner_size(glutin::dpi::Size::Physical(glutin::dpi::PhysicalSize::new(1, 1)));
|
|
||||||
let gl_window = glutin::ContextBuilder::new().build_headless(&*events_loop, glutin::dpi::PhysicalSize::new(1, 1)).unwrap();
|
let gl_window = glutin::ContextBuilder::new().build_headless(&*events_loop, glutin::dpi::PhysicalSize::new(1, 1)).unwrap();
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
let gl_window = unsafe {
|
let gl_window = unsafe {
|
||||||
let gl_window = gl_window.make_current().unwrap();
|
let gl_window = gl_window.make_current().unwrap();
|
||||||
gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
|
gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
|
||||||
|
@ -45,69 +13,57 @@ fn doit() {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
eprintln!("{}", String::from_utf8(CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec()).unwrap());
|
||||||
|
eprintln!("{}", String::from_utf8(CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _).to_bytes().to_vec()).unwrap());
|
||||||
|
eprintln!("{}", String::from_utf8(CStr::from_ptr(gl::GetString(gl::RENDERER) as *const _).to_bytes().to_vec()).unwrap());
|
||||||
// Setup shader compilation checks
|
// Setup shader compilation checks
|
||||||
let mut success = i32::from(gl::FALSE);
|
let mut success = i32::from(gl::FALSE);
|
||||||
|
|
||||||
// Vertex shader
|
match tree_type {
|
||||||
let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
|
crate::TreeType::Fragment => {
|
||||||
let c_str_vert = CString::new(VERTEX_SHADER_SOURCE.as_bytes()).unwrap();
|
// Fragment shader
|
||||||
gl::ShaderSource(vertex_shader, 1, &c_str_vert.as_ptr(), ptr::null());
|
let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
|
||||||
gl::CompileShader(vertex_shader);
|
let c_str_frag = CString::new(source).unwrap();
|
||||||
|
gl::ShaderSource(fragment_shader, 1, &c_str_frag.as_ptr(), ptr::null());
|
||||||
|
gl::CompileShader(fragment_shader);
|
||||||
|
|
||||||
// Check for shader compilation errors
|
// Check for shader compilation errors
|
||||||
gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);
|
gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);
|
||||||
if success != i32::from(gl::TRUE) {
|
let result = if success != i32::from(gl::TRUE) {
|
||||||
let mut info_len: gl::types::GLint = 0;
|
let mut info_len: gl::types::GLint = 0;
|
||||||
gl::GetShaderiv(vertex_shader, gl::INFO_LOG_LENGTH, &mut info_len);
|
gl::GetShaderiv(fragment_shader, gl::INFO_LOG_LENGTH, &mut info_len);
|
||||||
let mut info = vec![0u8; info_len as usize];
|
let mut info = vec![0u8; info_len as usize];
|
||||||
gl::GetShaderInfoLog(vertex_shader, info_len as gl::types::GLsizei, ptr::null_mut(), info.as_mut_ptr() as *mut gl::types::GLchar);
|
gl::GetShaderInfoLog(fragment_shader, info_len as gl::types::GLsizei, ptr::null_mut(), info.as_mut_ptr() as *mut gl::types::GLchar);
|
||||||
info.set_len((info_len - 1) as usize); // ignore null for str::from_utf8
|
info.set_len((info_len - 1) as usize); // ignore null for str::from_utf8
|
||||||
println!(
|
Some(String::from_utf8(info).unwrap())
|
||||||
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}",
|
} else {
|
||||||
str::from_utf8_unchecked(&info)
|
None
|
||||||
);
|
};
|
||||||
|
gl::DeleteShader(fragment_shader);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
crate::TreeType::Vertex => {
|
||||||
|
// Vertex shader
|
||||||
|
let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
|
||||||
|
let c_str_vert = CString::new(source).unwrap();
|
||||||
|
gl::ShaderSource(vertex_shader, 1, &c_str_vert.as_ptr(), ptr::null());
|
||||||
|
gl::CompileShader(vertex_shader);
|
||||||
|
|
||||||
|
// Check for shader compilation errors
|
||||||
|
gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);
|
||||||
|
let result = if success != i32::from(gl::TRUE) {
|
||||||
|
let mut info_len: gl::types::GLint = 0;
|
||||||
|
gl::GetShaderiv(vertex_shader, gl::INFO_LOG_LENGTH, &mut info_len);
|
||||||
|
let mut info = vec![0u8; info_len as usize];
|
||||||
|
gl::GetShaderInfoLog(vertex_shader, info_len as gl::types::GLsizei, ptr::null_mut(), info.as_mut_ptr() as *mut gl::types::GLchar);
|
||||||
|
info.set_len((info_len - 1) as usize); // ignore null for str::from_utf8
|
||||||
|
Some(String::from_utf8(info).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
gl::DeleteShader(vertex_shader);
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Fragment shader
|
|
||||||
let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
|
|
||||||
let c_str_frag = CString::new(FRAGMENT_SHADER_SOURCE.as_bytes()).unwrap();
|
|
||||||
gl::ShaderSource(fragment_shader, 1, &c_str_frag.as_ptr(), ptr::null());
|
|
||||||
gl::CompileShader(fragment_shader);
|
|
||||||
|
|
||||||
// Check for shader compilation errors
|
|
||||||
gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);
|
|
||||||
if success != i32::from(gl::TRUE) {
|
|
||||||
let mut info_len: gl::types::GLint = 0;
|
|
||||||
gl::GetShaderiv(fragment_shader, gl::INFO_LOG_LENGTH, &mut info_len);
|
|
||||||
let mut info = vec![0u8; info_len as usize];
|
|
||||||
gl::GetShaderInfoLog(fragment_shader, info_len as gl::types::GLsizei, ptr::null_mut(), info.as_mut_ptr() as *mut gl::types::GLchar);
|
|
||||||
info.set_len((info_len - 1) as usize); // ignore null for str::from_utf8
|
|
||||||
println!(
|
|
||||||
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}",
|
|
||||||
str::from_utf8_unchecked(&info)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link Shaders
|
|
||||||
let shader_program = gl::CreateProgram();
|
|
||||||
gl::AttachShader(shader_program, vertex_shader);
|
|
||||||
gl::AttachShader(shader_program, fragment_shader);
|
|
||||||
gl::LinkProgram(shader_program);
|
|
||||||
|
|
||||||
// Check for linking errors
|
|
||||||
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
|
|
||||||
if success != i32::from(gl::TRUE) {
|
|
||||||
let mut info_len: gl::types::GLint = 0;
|
|
||||||
gl::GetProgramiv(shader_program, gl::INFO_LOG_LENGTH, &mut info_len);
|
|
||||||
let mut info = vec![0u8; info_len as usize];
|
|
||||||
gl::GetProgramInfoLog(shader_program, info_len as gl::types::GLsizei, ptr::null_mut(), info.as_mut_ptr() as *mut gl::types::GLchar);
|
|
||||||
info.set_len((info_len - 1) as usize); // ignore null for str::from_utf8
|
|
||||||
println!(
|
|
||||||
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}",
|
|
||||||
str::from_utf8_unchecked(&info)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/* gl::DeleteShader(vertex_shader);
|
|
||||||
gl::DeleteShader(fragment_shader);*/
|
|
||||||
};
|
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue