1use std;
9use std::time::Instant;
10
11use gl;
12use egl;
13
14use cognitive_graphics::{egl_tools, gl_tools};
15use cognitive_graphics::attributes::{DmabufAttributes, EglAttributes};
16use qualia::{SurfaceViewer, SurfaceContext, Illusion, Size, PixelFormat, SurfaceId};
17use qualia::{Buffer, DataSource, Image, MemoryView, Pixmap};
18
19use cache_gl::CacheGl;
20
21const VERTEX_SHADER_100: &'static str = include_str!("vertex.100.glsl");
25
26const FRAGMENT_SHADER_100: &'static str = include_str!("fragment.100.glsl");
28
29const VERTEX_SHADER_300: &'static str = include_str!("vertex.300.glsl");
31
32const FRAGMENT_SHADER_300: &'static str = include_str!("fragment.300.glsl");
34
35pub struct RendererGl {
39 egl: egl_tools::EglBucket,
40 size: Size,
41 cache: CacheGl,
42
43 program: gl::types::GLuint,
45 loc_vertices: gl::types::GLint,
46 loc_texcoords: gl::types::GLint,
47 loc_texture: gl::types::GLint,
48 loc_screen_size: gl::types::GLint,
49 vbo_vertices: gl::types::GLuint,
50 vbo_texcoords: gl::types::GLuint,
51
52 image_target_texture: Option<egl_tools::ImageTargetTexture2DOesFn>,
54}
55
56impl RendererGl {
59 pub fn new(egl: egl_tools::EglBucket, size: Size) -> Self {
61 RendererGl {
62 egl: egl,
63 size: size,
64 cache: CacheGl::new(),
65 program: gl::types::GLuint::default(),
66 loc_vertices: gl::types::GLint::default(),
67 loc_texcoords: gl::types::GLint::default(),
68 loc_texture: gl::types::GLint::default(),
69 loc_screen_size: gl::types::GLint::default(),
70 vbo_vertices: gl::types::GLuint::default(),
71 vbo_texcoords: gl::types::GLuint::default(),
72 image_target_texture: None,
73 }
74 }
75
76 pub fn initialize(&mut self) -> Result<(), Illusion> {
82 gl::load_with(|s| egl::get_proc_address(s) as *const std::os::raw::c_void);
83
84 let _context = self.egl.make_current()?;
85
86 let (vshader_src, fshader_src) = match gl_tools::get_shading_lang_version() {
88 gl_tools::GlslVersion::Glsl100 => {
89 (VERTEX_SHADER_100.to_owned(), FRAGMENT_SHADER_100.to_owned())
90 }
91 gl_tools::GlslVersion::Glsl300 => {
92 (VERTEX_SHADER_300.to_owned(), FRAGMENT_SHADER_300.to_owned())
93 }
94 gl_tools::GlslVersion::Unknown => {
95 return Err(Illusion::General(format!("Could not figure out GLSL version")));
96 }
97 };
98
99 self.program = gl_tools::prepare_shader_program(vshader_src, fshader_src)?;
101 self.loc_vertices = gl_tools::get_attrib_location(self.program, "vertices".to_owned())?;
102 self.loc_texcoords = gl_tools::get_attrib_location(self.program, "texcoords".to_owned())?;
103 self.loc_texture = gl_tools::get_uniform_location(self.program, "texture".to_owned())?;
104 self.loc_screen_size = gl_tools::get_uniform_location(self.program,
105 "screen_size".to_owned())?;
106
107 unsafe {
109 gl::GenBuffers(1, &mut self.vbo_vertices);
110 gl::GenBuffers(1, &mut self.vbo_texcoords);
111 }
112
113 self.image_target_texture = egl_tools::get_proc_addr_of_image_target_texture_2d_oes();
115
116 Ok(())
117 }
118
119 pub fn draw(&mut self,
121 layunder: &Vec<SurfaceContext>,
122 surfaces: &Vec<SurfaceContext>,
123 layover: &Vec<SurfaceContext>,
124 viewer: &SurfaceViewer)
125 -> Result<(), Illusion> {
126 let _context = self.egl.make_current()?;
127 self.prepare_view();
128 self.draw_surfaces(layunder, viewer);
129 self.draw_surfaces(surfaces, viewer);
130 self.draw_surfaces(layover, viewer);
131 self.release_view();
132 Ok(())
133 }
134
135 pub fn swap_buffers(&mut self) -> Result<(), Illusion> {
137 let context = self.egl.make_current()?;
138 context.swap_buffers()?;
139 Ok(())
140 }
141
142 pub fn take_screenshot(&self) -> Result<Buffer, Illusion> {
144 let _context = self.egl.make_current()?;
145
146 let format = PixelFormat::ARGB8888;
147 let stride = format.get_size() * self.size.width;
148 let size = stride * self.size.height;
149 let mut dst: Vec<u8> = Vec::with_capacity(size);
150 unsafe { dst.set_len(size) };
151
152 unsafe {
153 gl::ReadBuffer(gl::BACK);
154 gl::ReadPixels(0,
155 0,
156 self.size.width as i32,
157 self.size.height as i32,
158 gl::RGBA,
159 gl::UNSIGNED_BYTE,
160 dst.as_mut_ptr() as *mut std::os::raw::c_void);
161 }
162
163 let mut data = Vec::new();
165 for chunk in dst.chunks(stride).rev() {
166 data.extend(chunk);
167 }
168
169 Ok(Buffer::new(format, self.size.width, self.size.height, stride, data))
170 }
171}
172
173impl RendererGl {
177 fn prepare_view(&self) {
179 unsafe {
180 gl::ClearColor(0.0, 0.3, 0.5, 1.0);
181 gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
182
183 gl::Enable(gl::BLEND);
184 gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
185
186 gl::UseProgram(self.program);
187 gl::Uniform2i(self.loc_screen_size, self.size.width as i32, self.size.height as i32);
188 }
189 }
190
191 fn load_buffer_as_texture(&mut self,
193 sid: SurfaceId,
194 buffer: &MemoryView,
195 time_stamp: Instant)
196 -> Option<Size> {
197 let format = {
198 match buffer.get_format() {
199 PixelFormat::XBGR8888 => gl::RGBA,
202 PixelFormat::ABGR8888 => gl::RGBA,
203 PixelFormat::XRGB8888 => gl::BGRA,
204 PixelFormat::ARGB8888 => gl::BGRA,
205 }
206 };
207
208 let texinfo = self.cache.get_or_generate_info(sid);
210 unsafe { gl::BindTexture(gl::TEXTURE_2D, texinfo.get_texture()) };
211
212 if texinfo.is_younger(time_stamp) {
214 unsafe {
215 gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as gl::types::GLint, buffer.get_width() as gl::types::GLint, buffer.get_height() as gl::types::GLint, 0, format, gl::UNSIGNED_BYTE, buffer.as_ptr() as *const _);
224 }
225 self.cache.update(sid, None);
226 }
227
228 Some(buffer.get_size())
229 }
230
231 fn load_image_as_texture(&mut self,
233 sid: SurfaceId,
234 attrs: &EglAttributes,
235 time_stamp: Instant)
236 -> Option<Size> {
237 let texinfo = self.cache.get_or_generate_info(sid);
239 unsafe { gl::BindTexture(gl::TEXTURE_2D, texinfo.get_texture()) };
240
241 if texinfo.is_younger(time_stamp) {
243 if let Some(image) = texinfo.get_image() {
245 let _ = egl_tools::destroy_image(self.egl.display, image);
246 }
247
248 if let Some(image_target_texture) = self.image_target_texture {
250 let image = egl_tools::create_image(self.egl.display, attrs);
251 if let Some(ref img) = image {
252 image_target_texture(gl::TEXTURE_2D, img.as_raw());
254 self.cache.update(sid, image.clone());
255 Some(attrs.get_size())
256 } else {
257 None
258 }
259 } else {
260 None
261 }
262 } else {
263 Some(attrs.get_size())
264 }
265 }
266
267 fn load_dmabuf_as_texture(&mut self,
269 sid: SurfaceId,
270 attrs: &DmabufAttributes,
271 time_stamp: Instant)
272 -> Option<Size> {
273 let texinfo = self.cache.get_or_generate_info(sid);
275 unsafe { gl::BindTexture(gl::TEXTURE_2D, texinfo.get_texture()) };
276
277 if texinfo.is_younger(time_stamp) {
279 if let Some(image) = texinfo.get_image() {
281 let _ = egl_tools::destroy_image(self.egl.display, image);
282 }
283
284 if let Some(image_target_texture) = self.image_target_texture {
286 let image = egl_tools::import_dmabuf(self.egl.display, attrs);
287 if let Some(ref img) = image {
288 image_target_texture(gl::TEXTURE_2D, img.as_raw());
290 self.cache.update(sid, image.clone());
291 Some(attrs.get_size())
292 } else {
293 None
294 }
295 } else {
296 None
297 }
298 } else {
299 Some(attrs.get_size())
300 }
301 }
302
303 fn load_texture_and_prepare_vertices(&mut self,
305 viewer: &SurfaceViewer,
306 context: &SurfaceContext,
307 vertices: &mut [gl::types::GLfloat],
308 texcoords: &mut [gl::types::GLfloat]) {
309 if let Some(ref surface) = viewer.get_surface(context.id) {
310 let size = {
311 match surface.data_source {
312 DataSource::Shm { ref source, time_stamp } => {
313 self.load_buffer_as_texture(context.id, source, time_stamp)
314 }
315 DataSource::EglImage { ref source, time_stamp } => {
316 self.load_image_as_texture(context.id, source, time_stamp)
317 }
318 DataSource::Dmabuf { ref source, time_stamp } => {
319 self.load_dmabuf_as_texture(context.id, source, time_stamp)
320 }
321 DataSource::None => None,
322 }
323 };
324
325 if let Some(size) = size {
326 let left = (context.pos.x - surface.offset.x) as gl::types::GLfloat;
327 let top = (context.pos.y - surface.offset.y) as gl::types::GLfloat;
328 let right = left + size.width as gl::types::GLfloat;
329 let bottom = top + size.height as gl::types::GLfloat;
330
331 vertices[0] = left;
332 vertices[1] = top;
333 vertices[2] = right;
334 vertices[3] = top;
335 vertices[4] = left;
336 vertices[5] = bottom;
337 vertices[6] = right;
338 vertices[7] = top;
339 vertices[8] = right;
340 vertices[9] = bottom;
341 vertices[10] = left;
342 vertices[11] = bottom;
343
344 texcoords[0] = 0.0;
346 texcoords[1] = 0.0;
347 texcoords[2] = 1.0;
348 texcoords[3] = 0.0;
349 texcoords[4] = 0.0;
350 texcoords[5] = 1.0;
351 texcoords[6] = 1.0;
352 texcoords[7] = 0.0;
353 texcoords[8] = 1.0;
354 texcoords[9] = 1.0;
355 texcoords[10] = 0.0;
356 texcoords[11] = 1.0;
357 } else {
358 log_warn3!("Renderer: No buffer for surface {}", context.id);
359 }
360 } else {
361 log_warn3!("Renderer: No info for surface {}", context.id);
362 }
363 }
364
365 fn draw_surfaces(&mut self, surfaces: &Vec<SurfaceContext>, viewer: &SurfaceViewer) {
367 if surfaces.len() == 0 {
368 return;
369 }
370
371 let vertices_len = 12 * surfaces.len();
373 let vertices_size = vertices_len * std::mem::size_of::<gl::types::GLfloat>();
374 let mut vertices = vec![0.0; vertices_len];
375 let mut texcoords = vec![0.0; vertices_len];
376
377 for i in 0..surfaces.len() {
378 unsafe { gl::ActiveTexture(gl::TEXTURE0 + i as u32) };
380
381 self.load_texture_and_prepare_vertices(viewer,
383 &surfaces[i],
384 &mut vertices[12 * i..12 * i + 12],
385 &mut texcoords[12 * i..12 * i + 12]);
386 }
387
388 unsafe {
389 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_vertices);
391 gl::EnableVertexAttribArray(self.loc_vertices as gl::types::GLuint);
392 gl::VertexAttribPointer(self.loc_vertices as gl::types::GLuint,
393 2,
394 gl::FLOAT,
395 gl::FALSE,
396 2 *
397 std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLint,
398 std::ptr::null());
399 gl::BufferData(gl::ARRAY_BUFFER,
400 vertices_size as isize,
401 vertices.as_ptr() as *const _,
402 gl::DYNAMIC_DRAW);
403
404 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_texcoords);
406 gl::EnableVertexAttribArray(self.loc_texcoords as gl::types::GLuint);
407 gl::VertexAttribPointer(self.loc_texcoords as gl::types::GLuint,
408 2,
409 gl::FLOAT,
410 gl::FALSE,
411 2 *
412 std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLint,
413 std::ptr::null());
414 gl::BufferData(gl::ARRAY_BUFFER,
415 vertices_size as isize,
416 texcoords.as_ptr() as *const _,
417 gl::DYNAMIC_DRAW);
418
419 for i in 0..surfaces.len() as i32 {
421 gl::Uniform1i(self.loc_texture, i);
422 gl::DrawArrays(gl::TRIANGLES, 6 * i, 6);
423 }
424
425 gl::DisableVertexAttribArray(self.loc_texcoords as gl::types::GLuint);
427 gl::DisableVertexAttribArray(self.loc_vertices as gl::types::GLuint);
428 }
429 }
430
431 fn release_view(&self) {
433 unsafe {
434 gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
435 gl::UseProgram(0);
436 }
437 }
438}
439
440