Procházet zdrojové kódy

Improve error handling with OpenGL functions

Johannes Hofmann před 7 roky
rodič
revize
a7db860456
4 změnil soubory, kde provedl 208 přidání a 198 odebrání
  1. 0
    8
      src/buffer.rs
  2. 40
    5
      src/context.rs
  3. 42
    54
      src/map_view_gl.rs
  4. 126
    131
      src/program.rs

+ 0
- 8
src/buffer.rs Zobrazit soubor

38
                              (vertex_data.len() * mem::size_of::<f32>()) as context::gl::types::GLsizeiptr,
38
                              (vertex_data.len() * mem::size_of::<f32>()) as context::gl::types::GLsizeiptr,
39
                              vertex_data.as_ptr() as *const _,
39
                              vertex_data.as_ptr() as *const _,
40
                              context::gl::STATIC_DRAW);
40
                              context::gl::STATIC_DRAW);
41
-
42
-            //TODO call this only once
43
-            // VAOs are not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
44
-            if cx.gl.BindVertexArray.is_loaded() {
45
-                let mut vao = mem::uninitialized();
46
-                cx.gl.GenVertexArrays(1, &mut vao);
47
-                cx.gl.BindVertexArray(vao);
48
-            }
49
         }
41
         }
50
 
42
 
51
         Buffer {
43
         Buffer {

+ 40
- 5
src/context.rs Zobrazit soubor

1
 use glutin;
1
 use glutin;
2
+use std::mem;
3
+use std::ffi::CStr;
2
 
4
 
3
 pub(crate) mod gl {
5
 pub(crate) mod gl {
4
     #![allow(unknown_lints)]
6
     #![allow(unknown_lints)]
15
 impl ::std::fmt::Debug for Context {
17
 impl ::std::fmt::Debug for Context {
16
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
18
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
17
         let version = unsafe {
19
         let version = unsafe {
18
-            let data = ::std::ffi::CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
20
+            let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
19
             String::from_utf8(data).unwrap_or_else(|_| "".into())
21
             String::from_utf8(data).unwrap_or_else(|_| "".into())
20
         };
22
         };
21
         write!(f, "Context {{ version: {:?} }}", version)
23
         write!(f, "Context {{ version: {:?} }}", version)
31
 impl Context {
33
 impl Context {
32
     pub fn from_window(window: &glutin::Window) -> Context {
34
     pub fn from_window(window: &glutin::Window) -> Context {
33
         let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
35
         let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
34
-        let cx = Context {gl: gl};
36
+        let cx = Context { gl: gl };
37
+
38
+        // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
39
+        // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
40
+        if cx.gl.BindVertexArray.is_loaded() {
41
+            unsafe {
42
+                let mut vao = mem::uninitialized();
43
+                cx.gl.GenVertexArrays(1, &mut vao);
44
+                cx.gl.BindVertexArray(vao);
45
+            }
46
+        }
35
 
47
 
36
         info!("OpenGL version: {}", cx.gl_version());
48
         info!("OpenGL version: {}", cx.gl_version());
37
         debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
49
         debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
41
 
53
 
42
     pub fn gl_version(&self) -> String {
54
     pub fn gl_version(&self) -> String {
43
         unsafe {
55
         unsafe {
44
-            let data = ::std::ffi::CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
56
+            let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
45
             String::from_utf8(data).unwrap_or_else(|_| "".into())
57
             String::from_utf8(data).unwrap_or_else(|_| "".into())
46
         }
58
         }
47
     }
59
     }
54
         }
66
         }
55
     }
67
     }
56
 
68
 
57
-    pub unsafe fn check_errors(&self, file: &str, line: u32) {
69
+    pub fn check_errors(&self, file: &str, line: u32) {
70
+        let mut fail = false;
71
+
58
         loop {
72
         loop {
59
-            match self.gl.GetError() {
73
+            match unsafe { self.gl.GetError() } {
60
                 gl::NO_ERROR => break,
74
                 gl::NO_ERROR => break,
61
                 gl::INVALID_VALUE => {
75
                 gl::INVALID_VALUE => {
62
                     error!("{}:{}, invalid value error", file, line);
76
                     error!("{}:{}, invalid value error", file, line);
77
+                    fail = true;
63
                 },
78
                 },
64
                 gl::INVALID_ENUM => {
79
                 gl::INVALID_ENUM => {
65
                     error!("{}:{}, invalid enum error", file, line);
80
                     error!("{}:{}, invalid enum error", file, line);
81
+                    fail = true;
66
                 },
82
                 },
67
                 gl::INVALID_OPERATION => {
83
                 gl::INVALID_OPERATION => {
68
                     error!("{}:{}, invalid operation error", file, line);
84
                     error!("{}:{}, invalid operation error", file, line);
85
+                    fail = true;
69
                 },
86
                 },
70
                 gl::INVALID_FRAMEBUFFER_OPERATION => {
87
                 gl::INVALID_FRAMEBUFFER_OPERATION => {
71
                     error!("{}:{}, invalid framebuffer operation error", file, line);
88
                     error!("{}:{}, invalid framebuffer operation error", file, line);
89
+                    fail = true;
72
                 },
90
                 },
73
                 gl::OUT_OF_MEMORY => {
91
                 gl::OUT_OF_MEMORY => {
74
                     error!("{}:{}, out of memory error", file, line);
92
                     error!("{}:{}, out of memory error", file, line);
93
+                    fail = true;
75
                 },
94
                 },
76
                 x => {
95
                 x => {
77
                     error!("{}:{}, unknown error {}", file, line, x);
96
                     error!("{}:{}, unknown error {}", file, line, x);
97
+                    fail = true;
78
                 },
98
                 },
79
             }
99
             }
80
         }
100
         }
101
+
102
+        if fail {
103
+            panic!("OpenGL error");
104
+        }
81
     }
105
     }
82
 
106
 
83
     pub fn clear_color(&self, color: (f32, f32, f32, f32)) {
107
     pub fn clear_color(&self, color: (f32, f32, f32, f32)) {
86
             self.gl.Clear(gl::COLOR_BUFFER_BIT);
110
             self.gl.Clear(gl::COLOR_BUFFER_BIT);
87
         }
111
         }
88
     }
112
     }
113
+
114
+    pub fn set_viewport(&self, x: i32, y: i32, width: u32, height: u32) {
115
+        unsafe {
116
+            self.gl.Viewport(
117
+                x,
118
+                y,
119
+                width as gl::types::GLsizei,
120
+                height as gl::types::GLsizei,
121
+            );
122
+        }
123
+    }
89
 }
124
 }

+ 42
- 54
src/map_view_gl.rs Zobrazit soubor

1
-use ::context;
2
 use ::std::ffi::CStr;
1
 use ::std::ffi::CStr;
3
 use buffer::{Buffer, DrawMode};
2
 use buffer::{Buffer, DrawMode};
4
 use context::Context;
3
 use context::Context;
32
         ) -> MapViewGl
31
         ) -> MapViewGl
33
         where F: Fn() + Sync + Send + 'static,
32
         where F: Fn() + Sync + Send + 'static,
34
     {
33
     {
35
-        unsafe {
36
-            let mut program = Program::from_paths(cx, "shader/map.vert", "shader/map.frag");
37
-            check_gl_errors!(cx);
38
-
39
-            let tile_size = 256;
40
-
41
-            let atlas_size = {
42
-                let default_size = 2048;
43
-                let max_size = cx.max_texture_size() as u32;
44
-                if default_size <= max_size {
45
-                    default_size
46
-                } else {
47
-                    if tile_size * 3 > max_size {
48
-                        error!("maximal tile size ({}) is too small", max_size);
49
-                    }
34
+        let mut program = Program::from_paths(cx, "shader/map.vert", "shader/map.frag").unwrap();
35
+        check_gl_errors!(cx);
36
+
37
+        let tile_size = 256;
50
 
38
 
51
-                    max_size
39
+        let atlas_size = {
40
+            let default_size = 2048;
41
+            let max_size = cx.max_texture_size() as u32;
42
+            if default_size <= max_size {
43
+                default_size
44
+            } else {
45
+                if tile_size * 3 > max_size {
46
+                    error!("maximal tile size ({}) is too small", max_size);
52
                 }
47
                 }
53
-            };
54
 
48
 
55
-            let tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
56
-            check_gl_errors!(cx);
49
+                max_size
50
+            }
51
+        };
57
 
52
 
58
-            let buf = Buffer::new(cx, &[], 0);
53
+        let tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
54
+        check_gl_errors!(cx);
59
 
55
 
60
-            check_gl_errors!(cx);
56
+        let buf = Buffer::new(cx, &[], 0);
57
+        check_gl_errors!(cx);
61
 
58
 
62
-            program.add_texture(&tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
63
-            check_gl_errors!(cx);
59
+        program.add_texture(&tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
60
+        check_gl_errors!(cx);
64
 
61
 
65
-            program.add_attribute(CStr::from_bytes_with_nul(b"position\0").unwrap(), 2, 8, 0);
66
-            check_gl_errors!(cx);
67
-            program.add_attribute(CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(), 2, 8, 2);
68
-            check_gl_errors!(cx);
69
-            program.add_attribute(CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
70
-            check_gl_errors!(cx);
62
+        program.add_attribute(CStr::from_bytes_with_nul(b"position\0").unwrap(), 2, 8, 0);
63
+        program.add_attribute(CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(), 2, 8, 2);
64
+        program.add_attribute(CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
65
+        check_gl_errors!(cx);
71
 
66
 
72
-            program.before_render();
67
+        program.before_render();
73
 
68
 
74
-            let mut map_view = MapView::new(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
69
+        let mut map_view = MapView::new(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
75
 
70
 
76
-            // set initial zoom
77
-            {
78
-                let min_dimension = f64::from(initial_size.0.min(initial_size.1));
79
-                let zoom = (min_dimension / f64::from(tile_size)).log2().ceil();
80
-                map_view.set_zoom(zoom);
81
-            }
71
+        // set initial zoom
72
+        {
73
+            let min_dimension = f64::from(initial_size.0.min(initial_size.1));
74
+            let zoom = (min_dimension / f64::from(tile_size)).log2().ceil();
75
+            map_view.set_zoom(zoom);
76
+        }
82
 
77
 
83
-            MapViewGl {
84
-                cx: cx,
85
-                program: program,
86
-                buf: buf,
87
-                viewport_size: initial_size,
88
-                map_view: map_view,
89
-                tile_cache: TileCache::new(move |_tile| update_func(), use_network),
90
-                tile_atlas: TileAtlas::new(tex, 256, use_async),
91
-            }
78
+        MapViewGl {
79
+            cx: cx,
80
+            program: program,
81
+            buf: buf,
82
+            viewport_size: initial_size,
83
+            map_view: map_view,
84
+            tile_cache: TileCache::new(move |_tile| update_func(), use_network),
85
+            tile_atlas: TileAtlas::new(tex, 256, use_async),
92
         }
86
         }
93
     }
87
     }
94
 
88
 
95
     pub fn set_viewport_size(&mut self, width: u32, height: u32) {
89
     pub fn set_viewport_size(&mut self, width: u32, height: u32) {
96
         self.viewport_size = (width, height);
90
         self.viewport_size = (width, height);
97
         self.map_view.set_size(f64::from(width), f64::from(height));
91
         self.map_view.set_size(f64::from(width), f64::from(height));
98
-        unsafe {
99
-            self.cx.gl.Viewport(
100
-                0,
101
-                0,
102
-                width as context::gl::types::GLsizei,
103
-                height as context::gl::types::GLsizei);
104
-        }
92
+        self.cx.set_viewport(0, 0, width, height);
105
     }
93
     }
106
 
94
 
107
     pub fn increase_atlas_size(&mut self) -> Result<(), ()> {
95
     pub fn increase_atlas_size(&mut self) -> Result<(), ()> {

+ 126
- 131
src/program.rs Zobrazit soubor

1
 use ::context;
1
 use ::context;
2
 use context::Context;
2
 use context::Context;
3
+use std::error::Error;
3
 use std::ffi::CStr;
4
 use std::ffi::CStr;
4
 use std::fs::File;
5
 use std::fs::File;
5
 use std::io::BufReader;
6
 use std::io::BufReader;
8
 use std::path::Path;
9
 use std::path::Path;
9
 use texture::{Texture, TextureId};
10
 use texture::{Texture, TextureId};
10
 
11
 
12
+
11
 #[derive(Clone, Debug)]
13
 #[derive(Clone, Debug)]
12
 pub struct Program<'a> {
14
 pub struct Program<'a> {
13
     cx: &'a ::context::Context,
15
     cx: &'a ::context::Context,
24
 }
26
 }
25
 
27
 
26
 impl<'a> Program<'a> {
28
 impl<'a> Program<'a> {
27
-    pub unsafe fn from_paths<P: AsRef<Path>>(cx: &'a Context, vert_path: P, frag_path: P) -> Program<'a> {
29
+    pub fn from_paths<P: AsRef<Path>>(cx: &'a Context, vert_path: P, frag_path: P) -> Result<Program<'a>, String> {
28
         let vert_src = {
30
         let vert_src = {
29
-            let file = File::open(&vert_path).unwrap();
31
+            let file = File::open(&vert_path)
32
+                .map_err(|e| e.description().to_string())?;
30
             let mut reader = BufReader::new(file);
33
             let mut reader = BufReader::new(file);
31
             let mut buf: Vec<u8> = vec![];
34
             let mut buf: Vec<u8> = vec![];
32
-            reader.read_to_end(&mut buf).unwrap();
35
+            reader.read_to_end(&mut buf)
36
+                .map_err(|e| e.description().to_string())?;
33
             buf
37
             buf
34
         };
38
         };
35
 
39
 
36
         let frag_src = {
40
         let frag_src = {
37
-            let file = File::open(&frag_path).unwrap();
41
+            let file = File::open(&frag_path)
42
+                .map_err(|e| e.description().to_string())?;
38
             let mut reader = BufReader::new(file);
43
             let mut reader = BufReader::new(file);
39
             let mut buf: Vec<u8> = vec![];
44
             let mut buf: Vec<u8> = vec![];
40
-            reader.read_to_end(&mut buf).unwrap();
45
+            reader.read_to_end(&mut buf)
46
+                .map_err(|e| e.description().to_string())?;
41
             buf
47
             buf
42
         };
48
         };
43
 
49
 
44
         Self::new(cx, &vert_src, &frag_src)
50
         Self::new(cx, &vert_src, &frag_src)
45
     }
51
     }
46
 
52
 
47
-    pub unsafe fn new(cx: &'a Context, vert_src: &[u8], frag_src: &[u8]) -> Program<'a> {
48
-        let vert_obj = {
49
-            let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
50
-            let vert_len = vert_src.len() as i32;
51
-            cx.gl.ShaderSource(
52
-                vert_obj,
53
-                1,
54
-                [vert_src.as_ptr() as *const _].as_ptr(),
55
-                &vert_len as *const _);
56
-            cx.gl.CompileShader(vert_obj);
57
-            check_compile_errors(cx, vert_obj);
58
-            check_gl_errors!(cx);
59
-            vert_obj
60
-        };
61
-
62
-        let frag_obj = {
63
-            let frag_obj = cx.gl.CreateShader(context::gl::FRAGMENT_SHADER);
64
-            let frag_len = frag_src.len() as i32;
65
-            cx.gl.ShaderSource(
66
-                frag_obj,
67
-                1,
68
-                [frag_src.as_ptr() as *const _].as_ptr(),
69
-                &frag_len as *const _);
70
-            cx.gl.CompileShader(frag_obj);
71
-            check_compile_errors(cx, frag_obj);
72
-            check_gl_errors!(cx);
73
-            frag_obj
74
-        };
75
-
76
-        let program_obj = {
77
-            let prog = cx.gl.CreateProgram();
78
-            cx.gl.AttachShader(prog, vert_obj);
79
-            cx.gl.AttachShader(prog, frag_obj);
80
-            cx.gl.LinkProgram(prog);
81
-            check_link_errors(cx, prog);
82
-
83
-            cx.gl.UseProgram(prog);
84
-            check_gl_errors!(cx);
85
-            prog
86
-        };
87
-
88
-        Program {
89
-            cx: cx,
90
-            vert_obj: vert_obj,
91
-            frag_obj: frag_obj,
92
-            program_obj: program_obj,
93
-            tex_ids: vec![],
94
-            tex_locations: vec![],
53
+    pub fn new(cx: &'a Context, vert_src: &[u8], frag_src: &[u8]) -> Result<Program<'a>, String> {
54
+        unsafe {
55
+            let vert_obj = {
56
+                let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
57
+                let vert_len = vert_src.len() as i32;
58
+                cx.gl.ShaderSource(
59
+                    vert_obj,
60
+                    1,
61
+                    [vert_src.as_ptr() as *const _].as_ptr(),
62
+                    &vert_len as *const _);
63
+                cx.gl.CompileShader(vert_obj);
64
+                check_compile_errors(cx, vert_obj)?;
65
+                check_gl_errors!(cx);
66
+                vert_obj
67
+            };
68
+
69
+            let frag_obj = {
70
+                let frag_obj = cx.gl.CreateShader(context::gl::FRAGMENT_SHADER);
71
+                let frag_len = frag_src.len() as i32;
72
+                cx.gl.ShaderSource(
73
+                    frag_obj,
74
+                    1,
75
+                    [frag_src.as_ptr() as *const _].as_ptr(),
76
+                    &frag_len as *const _);
77
+                cx.gl.CompileShader(frag_obj);
78
+                check_compile_errors(cx, frag_obj)?;
79
+                check_gl_errors!(cx);
80
+                frag_obj
81
+            };
82
+
83
+            let program_obj = {
84
+                let prog = cx.gl.CreateProgram();
85
+                cx.gl.AttachShader(prog, vert_obj);
86
+                cx.gl.AttachShader(prog, frag_obj);
87
+                cx.gl.LinkProgram(prog);
88
+                check_link_errors(cx, prog)?;
89
+
90
+                cx.gl.UseProgram(prog);
91
+                check_gl_errors!(cx);
92
+                prog
93
+            };
94
+
95
+            Ok(Program {
96
+                cx: cx,
97
+                vert_obj: vert_obj,
98
+                frag_obj: frag_obj,
99
+                program_obj: program_obj,
100
+                tex_ids: vec![],
101
+                tex_locations: vec![],
102
+            })
95
         }
103
         }
96
     }
104
     }
97
 
105
 
98
-    pub unsafe fn add_texture(&mut self, texture: &Texture, uniform_name: &CStr) {
106
+    pub fn add_texture(&mut self, texture: &Texture, uniform_name: &CStr) {
99
         //TODO store reference to texture
107
         //TODO store reference to texture
100
-        let tex_loc = self.cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
101
-        check_gl_errors!(self.cx);
102
-
103
-        self.tex_ids.push(texture.id());
104
-        self.tex_locations.push(tex_loc);
108
+        unsafe {
109
+            let tex_loc = self.cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
110
+            check_gl_errors!(self.cx);
105
 
111
 
112
+            self.tex_ids.push(texture.id());
113
+            self.tex_locations.push(tex_loc);
114
+        }
106
     }
115
     }
107
 
116
 
108
-    pub unsafe fn add_attribute(&mut self, name: &CStr, number_components: u32, stride: usize, offset: usize) {
109
-        let attrib_id = self.cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
110
-        check_gl_errors!(self.cx);
111
-        self.cx.gl.VertexAttribPointer(
112
-            attrib_id as u32,
113
-            number_components as i32, // size
114
-            context::gl::FLOAT, // type
115
-            0, // normalized
116
-            (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
117
-            (offset * mem::size_of::<f32>()) as *const () as *const _);
118
-        check_gl_errors!(self.cx);
119
-        self.cx.gl.EnableVertexAttribArray(attrib_id as u32);
117
+    pub fn add_attribute(&mut self, name: &CStr, number_components: u32, stride: usize, offset: usize) {
118
+        unsafe {
119
+            let attrib_id = self.cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
120
+            self.cx.gl.VertexAttribPointer(
121
+                attrib_id as u32,
122
+                number_components as i32, // size
123
+                context::gl::FLOAT, // type
124
+                0, // normalized
125
+                (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
126
+                (offset * mem::size_of::<f32>()) as *const () as *const _);
127
+            self.cx.gl.EnableVertexAttribArray(attrib_id as u32);
128
+        }
120
         check_gl_errors!(self.cx);
129
         check_gl_errors!(self.cx);
121
     }
130
     }
122
 
131
 
123
-    pub unsafe fn before_render(&self) {
124
-        check_gl_errors!(self.cx);
125
-        //self.cx.gl.UseProgram(self.program_obj);
126
-        //TODO check max texture number
127
-        for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
128
-            self.cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
129
-            self.cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
130
-            self.cx.gl.Uniform1i(tex_loc, i as i32);
132
+    pub fn before_render(&self) {
133
+        unsafe {
134
+            //self.cx.gl.UseProgram(self.program_obj);
135
+            //TODO check max texture number
136
+            for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
137
+                self.cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
138
+                self.cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
139
+                self.cx.gl.Uniform1i(tex_loc, i as i32);
140
+            }
131
         }
141
         }
132
     }
142
     }
133
 
143
 
138
     }
148
     }
139
 }
149
 }
140
 
150
 
141
-unsafe fn check_link_errors(cx: &Context, program_obj: u32)
142
-{
143
-    let mut link_success: i32 = mem::uninitialized();
144
-
145
-    cx.gl.GetProgramiv(program_obj, context::gl::LINK_STATUS, &mut link_success);
146
-
147
-    if link_success == 0 {
148
-
149
-        match cx.gl.GetError() {
150
-            context::gl::NO_ERROR => (),
151
-            context::gl::INVALID_VALUE => {
152
-                error!("invalid value");
153
-                return;
154
-            },
155
-            context::gl::INVALID_OPERATION => {
156
-                error!("invalid operation");
157
-                return;
158
-            },
159
-            _ => {
160
-                error!("unknown error");
161
-                return;
162
-            }
163
-        };
164
-
165
-        let mut error_log_size: i32 = mem::uninitialized();
151
+fn check_link_errors(cx: &Context, program_obj: u32) -> Result<(), String> {
152
+    unsafe {
153
+        let mut link_success: i32 = mem::uninitialized();
166
 
154
 
167
-        cx.gl.GetProgramiv(program_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
155
+        cx.gl.GetProgramiv(program_obj, context::gl::LINK_STATUS, &mut link_success);
168
 
156
 
169
-        let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
157
+        if link_success == 0 {
158
+            let mut error_log_size: i32 = mem::uninitialized();
159
+            cx.gl.GetProgramiv(program_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
170
 
160
 
171
-        cx.gl.GetProgramInfoLog(program_obj, error_log_size, &mut error_log_size,
172
-                             error_log.as_mut_ptr() as *mut context::gl::types::GLchar);
161
+            let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
162
+            cx.gl.GetProgramInfoLog(program_obj, error_log_size, &mut error_log_size,
163
+                                    error_log.as_mut_ptr() as *mut context::gl::types::GLchar);
173
 
164
 
174
-        error_log.set_len(error_log_size as usize);
165
+            error_log.set_len(error_log_size as usize);
175
 
166
 
176
-        let msg = String::from_utf8(error_log).unwrap();
177
-        error!("{}", msg);
167
+            Err(String::from_utf8_lossy(&error_log).into())
168
+        } else {
169
+            Ok(())
170
+        }
178
     }
171
     }
179
 }
172
 }
180
 
173
 
181
-unsafe fn check_compile_errors(cx: &Context, shader_obj: u32) {
182
-    // checking compilation success by reading a flag on the shader
183
-    let compilation_success = {
184
-        let mut compilation_success: i32 = mem::uninitialized();
185
-        cx.gl.GetShaderiv(shader_obj, context::gl::COMPILE_STATUS, &mut compilation_success);
186
-        compilation_success
187
-    };
188
-
189
-    if compilation_success != 1 {
190
-        // compilation error
191
-        let mut error_log_size: i32 = mem::uninitialized();
192
-        cx.gl.GetShaderiv(shader_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
193
-        let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
194
-
195
-        cx.gl.GetShaderInfoLog(shader_obj, error_log_size, &mut error_log_size,
196
-                                 error_log.as_mut_ptr() as *mut _);
197
-        error_log.set_len(error_log_size as usize);
198
-
199
-        if let Ok(msg) = String::from_utf8(error_log) {
200
-            error!("{}", msg);
174
+fn check_compile_errors(cx: &Context, shader_obj: u32) -> Result<(), String> {
175
+    unsafe {
176
+        // checking compilation success by reading a flag on the shader
177
+        let compilation_success = {
178
+            let mut compilation_success: i32 = mem::uninitialized();
179
+            cx.gl.GetShaderiv(shader_obj, context::gl::COMPILE_STATUS, &mut compilation_success);
180
+            compilation_success
181
+        };
182
+
183
+        if compilation_success != 1 {
184
+            // compilation error
185
+            let mut error_log_size: i32 = mem::uninitialized();
186
+            cx.gl.GetShaderiv(shader_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
187
+            let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
188
+
189
+            cx.gl.GetShaderInfoLog(shader_obj, error_log_size, &mut error_log_size,
190
+                                     error_log.as_mut_ptr() as *mut _);
191
+            error_log.set_len(error_log_size as usize);
192
+
193
+            Err(String::from_utf8_lossy(&error_log).into())
194
+        } else {
195
+            Ok(())
201
         }
196
         }
202
     }
197
     }
203
 }
198
 }