1use {
2 std::{
3 fs::File,
4 io::prelude::*,
5 mem,
6 ptr,
7 ffi::CStr,
8 },
9 self::super::gl_sys,
10 crate::{
11 makepad_live_id::*,
12 makepad_error_log::*,
13 makepad_shader_compiler::generate_glsl,
14 cx::Cx,
15 texture::{TextureId, TextureDesc, TextureFormat},
16 makepad_math::{Mat4, DVec2, Vec4},
17 pass::{PassClearColor, PassClearDepth, PassId},
18 draw_list::DrawListId,
19 draw_shader::{CxDrawShaderMapping, DrawShaderTextureInput},
20 },
21};
22
23impl Cx {
24
25 pub (crate) fn render_view(
26 &mut self,
27 pass_id: PassId,
28 draw_list_id: DrawListId,
29 zbias: &mut f32,
30 zbias_step: f32,
31 ) {
32 let draw_items_len = self.draw_lists[draw_list_id].draw_items.len();
34 self.draw_lists[draw_list_id].uniform_view_transform(&Mat4::identity());
36
37 for draw_item_id in 0..draw_items_len {
38 if let Some(sub_list_id) = self.draw_lists[draw_list_id].draw_items[draw_item_id].kind.sub_list() {
39 self.render_view(
40 pass_id,
41 sub_list_id,
42 zbias,
43 zbias_step,
44 );
45 }
46 else {
47 let draw_list = &mut self.draw_lists[draw_list_id];
48 let draw_item = &mut draw_list.draw_items[draw_item_id];
49
50 let draw_call = if let Some(draw_call) = draw_item.kind.draw_call_mut() {
51 draw_call
52 }else {
53 continue;
54 };
55
56 let sh = &self.draw_shaders.shaders[draw_call.draw_shader.draw_shader_id];
57 if sh.os_shader_id.is_none() { continue;
59 }
60 let shp = &mut self.draw_shaders.os_shaders[sh.os_shader_id.unwrap()];
61
62 if shp.gl_shader.is_none(){
63 shp.gl_shader = Some(GlShader::new(
64 &shp.vertex,
65 &shp.pixel,
66 &sh.mapping,
67 self.os_type.get_cache_dir().as_ref()
68 ));
69 }
70 let shgl = shp.gl_shader.as_ref().unwrap();
71
72 if draw_call.instance_dirty || draw_item.os.inst_vb.gl_buffer.is_none(){
73 draw_call.instance_dirty = false;
74 draw_item.os.inst_vb.update_with_f32_data(draw_item.instances.as_ref().unwrap());
75 }
76
77 draw_call.draw_uniforms.set_zbias(*zbias);
79 *zbias += zbias_step;
80
81 let instances = (draw_item.instances.as_ref().unwrap().len() / sh.mapping.instances.total_slots) as u64;
82
83 if instances == 0 {
84 continue;
85 }
86
87 let geometry_id = if let Some(geometry_id) = draw_call.geometry_id {geometry_id}
88 else {
89 continue;
90 };
91
92 let geometry = &mut self.geometries[geometry_id];
93 if geometry.dirty || geometry.os.vb.gl_buffer.is_none() || geometry.os.ib.gl_buffer.is_none() {
94 geometry.os.vb.update_with_f32_data(&geometry.vertices);
95 geometry.os.ib.update_with_u32_data(&geometry.indices);
96 geometry.dirty = false;
97 }
98
99 let indices = geometry.indices.len();
100
101 if draw_call.uniforms_dirty {
102 draw_call.uniforms_dirty = false;
103 }
104
105 let geometry = &mut self.geometries[geometry_id];
107
108 if draw_item.os.vao.is_none() {
110 draw_item.os.vao = Some(CxOsDrawCallVao {
111 vao: None,
112 shader_id: None,
113 inst_vb: None,
114 geom_vb: None,
115 geom_ib: None,
116 });
117 }
118
119 let vao = draw_item.os.vao.as_mut().unwrap();
120 if vao.inst_vb != draw_item.os.inst_vb.gl_buffer
121 || vao.geom_vb != geometry.os.vb.gl_buffer
122 || vao.geom_ib != geometry.os.ib.gl_buffer
123 || vao.shader_id != Some(draw_call.draw_shader.draw_shader_id) {
124
125 if let Some(vao) = vao.vao.take(){
126 unsafe{gl_sys::DeleteVertexArrays(1, &vao)};
127 }
128
129 vao.vao = Some(unsafe {
130 let mut vao = 0u32;
131 gl_sys::GenVertexArrays(1, &mut vao);
132 vao
133 });
134
135 vao.shader_id = Some(draw_call.draw_shader.draw_shader_id);
136 vao.inst_vb = draw_item.os.inst_vb.gl_buffer;
137 vao.geom_vb = geometry.os.vb.gl_buffer;
138 vao.geom_ib = geometry.os.ib.gl_buffer;
139 unsafe {
140 gl_sys::BindVertexArray(vao.vao.unwrap());
141
142 gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, vao.geom_vb.unwrap());
144 for attr in &shgl.geometries {
145 gl_sys::VertexAttribPointer(attr.loc, attr.size, gl_sys::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
146 gl_sys::EnableVertexAttribArray(attr.loc);
147 }
148
149 gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, vao.inst_vb.unwrap());
150
151 for attr in &shgl.instances {
152 gl_sys::VertexAttribPointer(attr.loc, attr.size, gl_sys::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
153 gl_sys::EnableVertexAttribArray(attr.loc);
154 gl_sys::VertexAttribDivisor(attr.loc, 1 as gl_sys::GLuint);
155 }
156
157 gl_sys::BindBuffer(gl_sys::ELEMENT_ARRAY_BUFFER, vao.geom_ib.unwrap());
159 gl_sys::BindVertexArray(0);
160 }
161 }
162
163 unsafe {
164 gl_sys::UseProgram(shgl.program);
165
166 gl_sys::BindVertexArray(draw_item.os.vao.as_ref().unwrap().vao.unwrap());
167 let instances = (draw_item.instances.as_ref().unwrap().len() / sh.mapping.instances.total_slots) as u64;
168
169 let pass_uniforms = self.passes[pass_id].pass_uniforms.as_slice();
170 let draw_list_uniforms = draw_list.draw_list_uniforms.as_slice();
171 let draw_uniforms = draw_call.draw_uniforms.as_slice();
172
173 GlShader::set_uniform_array(&shgl.pass_uniforms, pass_uniforms);
174 GlShader::set_uniform_array(&shgl.view_uniforms, draw_list_uniforms);
175 GlShader::set_uniform_array(&shgl.draw_uniforms, draw_uniforms);
176 GlShader::set_uniform_array(&shgl.user_uniforms, &draw_call.user_uniforms);
177 GlShader::set_uniform_array(&shgl.live_uniforms, &sh.mapping.live_uniforms_buf);
178
179 let ct = &sh.mapping.const_table.table;
180 if ct.len()>0 {
181 GlShader::set_uniform_array(&shgl.const_table_uniform, ct);
182 }
183
184 for i in 0..sh.mapping.textures.len() {
186 let texture_id = if let Some(texture_id) = draw_call.texture_slots[i] {
187 texture_id
188 }else {
189 continue;
190 };
191 let cxtexture = &mut self.textures[texture_id];
192
193 if cxtexture.update_image || cxtexture.image_u32.len() != 0 && cxtexture.os.gl_texture.is_none(){
194 cxtexture.update_image = false;
195 cxtexture.os.update_platform_texture_image2d(
196 cxtexture.desc.width.unwrap() as u32,
197 cxtexture.desc.height.unwrap() as u32,
198 &cxtexture.image_u32
199 );
200 }
201 }
202 for i in 0..sh.mapping.textures.len() {
203 let texture_id = if let Some(texture_id) = draw_call.texture_slots[i] {
204 texture_id
205 }else {
206 continue;
207 };
208 let cxtexture = &mut self.textures[texture_id];
209 gl_sys::ActiveTexture(gl_sys::TEXTURE0 + i as u32);
211 if let Some(texture) = cxtexture.os.gl_texture {
212 gl_sys::BindTexture(gl_sys::TEXTURE_2D, texture);
213 }
214 else {
215 gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
216 }
217 gl_sys::Uniform1i(shgl.textures[i].loc, i as i32);
218 }
219
220 gl_sys::DrawElementsInstanced(
221 gl_sys::TRIANGLES,
222 indices as i32,
223 gl_sys::UNSIGNED_INT,
224 ptr::null(),
225 instances as i32
226 );
227
228 gl_sys::BindVertexArray(0);
229 }
230
231 }
232 }
233 }
234
235 pub fn set_default_depth_and_blend_mode() {
236 unsafe {
237 gl_sys::Enable(gl_sys::DEPTH_TEST);
238 gl_sys::DepthFunc(gl_sys::LEQUAL);
239 gl_sys::BlendEquationSeparate(gl_sys::FUNC_ADD, gl_sys::FUNC_ADD);
240 gl_sys::BlendFuncSeparate(gl_sys::ONE, gl_sys::ONE_MINUS_SRC_ALPHA, gl_sys::ONE, gl_sys::ONE_MINUS_SRC_ALPHA);
241 gl_sys::Enable(gl_sys::BLEND);
242 }
243 }
244
245 pub fn setup_render_pass(&mut self, pass_id: PassId,) -> Option<DVec2> {
246
247 let dpi_factor = self.passes[pass_id].dpi_factor.unwrap();
248 let pass_rect = self.get_pass_rect2(pass_id, dpi_factor).unwrap();
249 self.passes[pass_id].paint_dirty = false;
250
251 if pass_rect.size.x <0.5 || pass_rect.size.y < 0.5 {
252 return None
253 }
254
255 self.passes[pass_id].set_matrix(pass_rect.pos, pass_rect.size);
256 self.passes[pass_id].set_dpi_factor(dpi_factor);
257 Some(pass_rect.size)
258 }
259
260 pub fn draw_pass_to_texture(&mut self, pass_id: PassId, texture_id: TextureId) {
261 self.draw_pass_to_texture_inner(pass_id, Some(texture_id))
262 }
263
264 pub fn draw_pass_to_magic_texture(&mut self, pass_id: PassId) {
265 self.draw_pass_to_texture_inner(pass_id, None)
266 }
267
268 fn draw_pass_to_texture_inner(
269 &mut self,
270 pass_id: PassId,
271 maybe_texture_id: Option<TextureId>,
272 ) {
273 let draw_list_id = self.passes[pass_id].main_draw_list_id.unwrap();
274
275 let pass_size = if let Some(pz) = self.setup_render_pass(pass_id) {
276 pz
277 }
278 else {
279 return
280 };
281
282 let dpi_factor = self.passes[pass_id].dpi_factor.unwrap();
283
284 self.passes[pass_id].set_dpi_factor(dpi_factor);
285
286 let mut clear_color = Vec4::default();
287 let mut clear_depth = 1.0;
288 let mut clear_flags = 0;
289
290 if self.passes[pass_id].os.gl_framebuffer.is_none() {
292 unsafe {
293 let mut gl_framebuffer = std::mem::MaybeUninit::uninit();
294 gl_sys::GenFramebuffers(1, gl_framebuffer.as_mut_ptr());
295 self.passes[pass_id].os.gl_framebuffer = Some(gl_framebuffer.assume_init());
296 }
297 }
298
299 unsafe {
301 gl_sys::BindFramebuffer(gl_sys::FRAMEBUFFER, self.passes[pass_id].os.gl_framebuffer.unwrap());
302 }
303
304 let color_textures_from_fb_texture = maybe_texture_id.map(|texture_id| {
305 [crate::pass::CxPassColorTexture {
306 clear_color: PassClearColor::ClearWith(self.passes[pass_id].clear_color),
307 texture_id,
308 }]
309 });
310 let color_textures = color_textures_from_fb_texture
311 .as_ref().map_or(&self.passes[pass_id].color_textures[..], |xs| &xs[..]);
312
313 for (index, color_texture) in color_textures.iter().enumerate() {
314 match color_texture.clear_color {
315 PassClearColor::InitWith(_clear_color) => {
316 let cxtexture = &mut self.textures[color_texture.texture_id];
317 if cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, false) {
318 clear_color = _clear_color;
319 clear_flags |= gl_sys::COLOR_BUFFER_BIT;
320 }
321 },
322 PassClearColor::ClearWith(_clear_color) => {
323 let cxtexture = &mut self.textures[color_texture.texture_id];
324 cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, false);
325 clear_color = _clear_color;
326 clear_flags |= gl_sys::COLOR_BUFFER_BIT;
327 }
328 }
329 if let Some(gl_texture) = self.textures[color_texture.texture_id].os.gl_texture {
330 unsafe {
331 gl_sys::FramebufferTexture2D(gl_sys::FRAMEBUFFER, gl_sys::COLOR_ATTACHMENT0 + index as u32, gl_sys::TEXTURE_2D, gl_texture, 0);
332 }
333 }
334 }
335
336 if let Some(depth_texture_id) = self.passes[pass_id].depth_texture {
338 match self.passes[pass_id].clear_depth {
339 PassClearDepth::InitWith(_clear_depth) => {
340 let cxtexture = &mut self.textures[depth_texture_id];
341 if cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, true) {
342 clear_depth = _clear_depth;
343 clear_flags |= gl_sys::DEPTH_BUFFER_BIT;
344 }
345 },
346 PassClearDepth::ClearWith(_clear_depth) => {
347 let cxtexture = &mut self.textures[depth_texture_id];
348 cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, true);
349 clear_depth = _clear_depth;
350 clear_flags |= gl_sys::DEPTH_BUFFER_BIT;
351 }
352 }
353 }
354 else {
355 }
376
377 while unsafe { gl_sys::GetError() } != 0 {}
379
380 unsafe {
381 let (x, mut y) = (0, 0);
382 let width = (pass_size.x * dpi_factor) as u32;
383 let height = (pass_size.y * dpi_factor) as u32;
384
385 if let [color_texture] = color_textures {
388 let cxtexture = &mut self.textures[color_texture.texture_id];
389 if cxtexture.os.gl_texture.is_some() {
390 if let Some(alloc_height) = cxtexture.os.alloc_desc.height {
391 let alloc_height = alloc_height as u32;
392 if alloc_height > height {
393 y = alloc_height - height;
394 }
395 }
396 }
397 }
398
399 gl_sys::Viewport(x as i32, y as i32, width as i32, height as i32);
400 assert_eq!(gl_sys::GetError(), 0, "glViewport({x}, {y}, {width}, {height}) failed");
401 }
402
403 if clear_flags != 0 {
404 unsafe {
405 if clear_flags & gl_sys::DEPTH_BUFFER_BIT != 0 {
406 gl_sys::ClearDepthf(clear_depth);
407 }
408 gl_sys::ClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
409 gl_sys::Clear(clear_flags);
410 }
411 }
412 Self::set_default_depth_and_blend_mode();
413
414 let mut zbias = 0.0;
415 let zbias_step = self.passes[pass_id].zbias_step;
416
417 self.render_view(
418 pass_id,
419 draw_list_id,
420 &mut zbias,
421 zbias_step,
422 );
423
424 unsafe {
425 gl_sys::BindFramebuffer(gl_sys::FRAMEBUFFER, 0);
426 }
428 }
429
430 pub fn opengl_compile_shaders(&mut self) {
431 for draw_shader_ptr in &self.draw_shaders.compile_set {
433 if let Some(item) = self.draw_shaders.ptr_to_item.get(&draw_shader_ptr) {
434 let cx_shader = &mut self.draw_shaders.shaders[item.draw_shader_id];
435 let draw_shader_def = self.shader_registry.draw_shader_defs.get(&draw_shader_ptr);
436
437 let vertex = generate_glsl::generate_vertex_shader(
438 draw_shader_def.as_ref().unwrap(),
439 &cx_shader.mapping.const_table,
440 &self.shader_registry
441 );
442 let pixel = generate_glsl::generate_pixel_shader(
443 draw_shader_def.as_ref().unwrap(),
444 &cx_shader.mapping.const_table,
445 &self.shader_registry
446 );
447
448 if cx_shader.mapping.flags.debug {
449 log!("{}\n{}", vertex, pixel);
450 }
451
452 for (index, ds) in self.draw_shaders.os_shaders.iter().enumerate() {
454 if ds.vertex == vertex && ds.pixel == pixel {
455 cx_shader.os_shader_id = Some(index);
456 break;
457 }
458 }
459
460 if cx_shader.os_shader_id.is_none() {
461 let shp = CxOsDrawShader::new(&vertex, &pixel);
462 cx_shader.os_shader_id = Some(self.draw_shaders.os_shaders.len());
463 self.draw_shaders.os_shaders.push(shp);
464 }
465 }
466 }
467 self.draw_shaders.compile_set.clear();
468 }
469}
470
471
472#[derive(Clone)]
473pub struct CxOsDrawShader {
474 pub gl_shader: Option<GlShader>,
475 pub vertex: String,
476 pub pixel: String,
477}
478
479#[derive(Clone)]
480pub struct GlShader {
481 pub program: u32,
482 pub geometries: Vec<OpenglAttribute>,
483 pub instances: Vec<OpenglAttribute>,
484 pub textures: Vec<OpenglUniform>,
485 pub pass_uniforms: OpenglUniform,
486 pub view_uniforms: OpenglUniform,
487 pub draw_uniforms: OpenglUniform,
488 pub user_uniforms: OpenglUniform,
489 pub live_uniforms: OpenglUniform,
490 pub const_table_uniform: OpenglUniform,
491}
492
493impl GlShader{
494 pub fn new(vertex: &str, pixel: &str, mapping: &CxDrawShaderMapping, cache_dir: Option<&String>)->Self{
495 unsafe fn read_cache(vertex:&str, pixel:&str, cache_dir:Option<&String>)->Option<gl_sys::GLuint>{
496 if let Some(cache_dir) = cache_dir {
497 let shader_hash = live_id!(shader).str_append(&vertex).str_append(&pixel);
498 if let Ok(mut cache_file) = File::open(format!("{}/shader_{:08x}.bin", cache_dir, shader_hash.0)) {
499 let mut binary = Vec::new();
500 let mut format_bytes = [0u8; 4];
501 if cache_file.read(&mut format_bytes).is_ok() {
502 let binary_format = u32::from_be_bytes(format_bytes);
503 if cache_file.read_to_end(&mut binary).is_ok() {
504 let program = gl_sys::CreateProgram();
505 gl_sys::ProgramBinary(program, binary_format, binary.as_ptr() as *const _, binary.len() as i32);
506 return Some(program)
507 }
508 }
509 }
510 }
511 None
512 }
513
514 unsafe {
515 let program = if let Some(program) = read_cache(&vertex,&pixel,cache_dir){
516 program
517 }
518 else{
519 let vs = gl_sys::CreateShader(gl_sys::VERTEX_SHADER);
520 gl_sys::ShaderSource(vs, 1, [vertex.as_ptr() as *const _].as_ptr(), ptr::null());
521 gl_sys::CompileShader(vs);
522 if let Some(error) = Self::opengl_has_shader_error(true, vs as usize, &vertex) {
524 panic!("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n{}", error);
525 }
526 let fs = gl_sys::CreateShader(gl_sys::FRAGMENT_SHADER);
527 gl_sys::ShaderSource(fs, 1, [pixel.as_ptr() as *const _].as_ptr(), ptr::null());
528 gl_sys::CompileShader(fs);
529 if let Some(error) = Self::opengl_has_shader_error(true, fs as usize, &pixel) {
531 panic!("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}", error);
532 }
533
534 let program = gl_sys::CreateProgram();
535 gl_sys::AttachShader(program, vs);
536 gl_sys::AttachShader(program, fs);
537 gl_sys::LinkProgram(program);
538 if let Some(error) = Self::opengl_has_shader_error(false, program as usize, "") {
539 panic!("ERROR::SHADER::LINK::COMPILATION_FAILED\n{}", error);
540 }
541 gl_sys::DeleteShader(vs);
542 gl_sys::DeleteShader(fs);
543 program
544 };
545
546 if let Some(cache_dir) = cache_dir {
547 let mut binary = Vec::new();
548 let mut binary_len = 0;
549 gl_sys::GetProgramiv(program, gl_sys::PROGRAM_BINARY_LENGTH, &mut binary_len);
550 if binary_len != 0 {
551 binary.resize(binary_len as usize, 0u8);
552 let mut return_size = 0i32;
553 let mut binary_format = 0u32;
554 gl_sys::GetProgramBinary(program, binary.len() as i32, &mut return_size as *mut _, &mut binary_format as *mut _, binary.as_mut_ptr() as *mut _);
555 if return_size != 0 {
556 let shader_hash = live_id!(shader).str_append(&vertex).str_append(&pixel);
558 binary.resize(return_size as usize, 0u8);
559 if let Ok(mut cache) = File::create(format!("{}/shader_{:08x}.bin", cache_dir, shader_hash.0)) {
560 let _ = cache.write_all(&binary_format.to_be_bytes());
561 let _ = cache.write_all(&binary);
562 }
563 }
564 }
565 }
566
567 Self{
568 program,
569 geometries:Self::opengl_get_attributes(program, "packed_geometry_", mapping.geometries.total_slots),
570 instances: Self::opengl_get_attributes(program, "packed_instance_", mapping.instances.total_slots),
571 textures: Self::opengl_get_texture_slots(program, &mapping.textures),
572 pass_uniforms: Self::opengl_get_uniform(program, "pass_table"),
573 view_uniforms: Self::opengl_get_uniform(program, "view_table"),
574 draw_uniforms: Self::opengl_get_uniform(program, "draw_table"),
575 user_uniforms: Self::opengl_get_uniform(program, "user_table"),
576 live_uniforms: Self::opengl_get_uniform(program, "live_table"),
577 const_table_uniform: Self::opengl_get_uniform(program, "const_table"),
578 }
579 }
580 }
581
582
583 pub fn set_uniform_array(loc: &OpenglUniform, array: &[f32]) {
584 unsafe {
585 gl_sys::Uniform1fv(loc.loc as i32, array.len() as i32, array.as_ptr());
586 }
587 }
588
589 pub fn opengl_get_uniform(program: u32, name: &str) -> OpenglUniform {
590 let mut name0 = String::new();
591 name0.push_str(name);
592 name0.push_str("\0");
593 unsafe {
594 OpenglUniform {
595 loc: gl_sys::GetUniformLocation(program, name0.as_ptr() as *const _),
596 }
598 }
599 }
600
601 pub fn opengl_get_info_log(compile: bool, shader: usize, source: &str) -> String {
602 unsafe {
603 let mut length = 0;
604 if compile {
605 gl_sys::GetShaderiv(shader as u32, gl_sys::INFO_LOG_LENGTH, &mut length);
606 } else {
607 gl_sys::GetProgramiv(shader as u32, gl_sys::INFO_LOG_LENGTH, &mut length);
608 }
609 let mut log = Vec::with_capacity(length as usize);
610 if compile {
611 gl_sys::GetShaderInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
612 } else {
613 gl_sys::GetProgramInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
614 }
615 log.set_len(length as usize);
616 let mut r = "".to_string();
617 r.push_str(CStr::from_ptr(log.as_ptr()).to_str().unwrap());
618 r.push_str("\n");
619 let split = source.split("\n");
620 for (line, chunk) in split.enumerate() {
621 r.push_str(&(line + 1).to_string());
622 r.push_str(":");
623 r.push_str(chunk);
624 r.push_str("\n");
625 }
626 r
627 }
628 }
629
630 pub fn opengl_has_shader_error(compile: bool, shader: usize, source: &str) -> Option<String> {
631 unsafe {
633
634 let mut success = gl_sys::TRUE as i32;
635
636 if compile {
637 gl_sys::GetShaderiv(shader as u32, gl_sys::COMPILE_STATUS, &mut success);
638 }
639 else {
640 gl_sys::GetProgramiv(shader as u32, gl_sys::LINK_STATUS, &mut success);
641 };
642
643 if success != gl_sys::TRUE as i32 {
644 Some(Self::opengl_get_info_log(compile, shader, source))
645 }
646 else {
647 None
648 }
649 }
650 }
651
652 pub fn opengl_get_attributes(program: u32, prefix: &str, slots: usize) -> Vec<OpenglAttribute> {
653 let mut attribs = Vec::new();
654
655 fn ceil_div4(base: usize) -> usize {
656 let r = base >> 2;
657 if base & 3 != 0 {
658 return r + 1
659 }
660 r
661 }
662
663 let stride = (slots * mem::size_of::<f32>()) as i32;
664 let num_attr = ceil_div4(slots);
665 for i in 0..num_attr {
666 let mut name0 = prefix.to_string();
667 name0.push_str(&i.to_string());
668 name0.push_str("\0");
669
670 let mut size = ((slots - i * 4)) as i32;
671 if size > 4 {
672 size = 4;
673 }
674 unsafe {
675 attribs.push(
676 OpenglAttribute {
677 loc: {
678 let loc = gl_sys::GetAttribLocation(program, name0.as_ptr() as *const _) as u32;
679 loc
680 },
681 offset: (i * 4 * mem::size_of::<f32>()) as usize,
682 size: size,
683 stride: stride
684 }
685 )
686 }
687 }
688 attribs
689 }
690
691
692 pub fn opengl_get_texture_slots(program: u32, texture_slots: &Vec<DrawShaderTextureInput>) -> Vec<OpenglUniform> {
693 let mut gl_texture_slots = Vec::new();
694
695 for slot in texture_slots {
696 let mut name0 = "ds_".to_string();
697 name0.push_str(&slot.id.to_string());
698 name0.push_str("\0");
699 unsafe {
700 gl_texture_slots.push(OpenglUniform {
701 loc: gl_sys::GetUniformLocation(program, name0.as_ptr() as *const _),
702 })
703 }
704 }
705 gl_texture_slots
706 }
707
708 pub fn free_resources(self){
709 unsafe{
710 gl_sys::DeleteShader(self.program);
711 }
712 }
713}
714
715impl CxOsDrawShader {
716 pub fn new(vertex: &str, pixel: &str) -> Self {
717
718 let vertex = format!("
719 #version 100
720 precision highp float;
721 precision highp int;
722 vec4 sample2d(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, pos.y)).zyxw;}}
723 vec4 sample2d_rt(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}}
724 mat4 transpose(mat4 m){{return mat4(m[0][0],m[1][0],m[2][0],m[3][0],m[0][1],m[1][1],m[2][1],m[3][1],m[0][2],m[1][2],m[2][2],m[3][3], m[3][0], m[3][1], m[3][2], m[3][3]);}}
725 mat3 transpose(mat3 m){{return mat3(m[0][0],m[1][0],m[2][0],m[0][1],m[1][1],m[2][1],m[0][2],m[1][2],m[2][2]);}}
726 mat2 transpose(mat2 m){{return mat2(m[0][0],m[1][0],m[0][1],m[1][1]);}}
727 {}\0", vertex);
728
729 let pixel = format!("
730 #version 100
731 #extension GL_OES_standard_derivatives : enable
732 precision highp float;
733 precision highp int;
734 vec4 sample2d(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, pos.y)).zyxw;}}
735 vec4 sample2d_rt(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}}
736 mat4 transpose(mat4 m){{return mat4(m[0][0],m[1][0],m[2][0],m[3][0],m[0][1],m[1][1],m[2][1],m[3][1],m[0][2],m[1][2],m[2][2],m[3][3], m[3][0], m[3][1], m[3][2], m[3][3]);}}
737 mat3 transpose(mat3 m){{return mat3(m[0][0],m[1][0],m[2][0],m[0][1],m[1][1],m[2][1],m[0][2],m[1][2],m[2][2]);}}
738 mat2 transpose(mat2 m){{return mat2(m[0][0],m[1][0],m[0][1],m[1][1]);}}
739 {}\0", pixel);
740
741 CxOsDrawShader {
743 vertex,
744 pixel,
745 gl_shader: None,
746 }
747 }
748
749 pub fn free_resources(&mut self){
750 if let Some(gl_shader) = self.gl_shader.take(){
751 gl_shader.free_resources();
752 }
753 }
754}
755
756#[derive(Default, Clone)]
757pub struct OpenglAttribute {
758 pub loc: u32,
759 pub size: i32,
760 pub offset: usize,
761 pub stride: i32
762}
763
764#[derive(Debug, Default, Clone)]
765pub struct OpenglUniform {
766 pub loc: i32,
767 }
769
770
771#[derive(Clone, Default)]
772pub struct CxOsGeometry {
773 pub vb: OpenglBuffer,
774 pub ib: OpenglBuffer,
775}
776
777impl CxOsGeometry{
778 pub fn free_resources(&mut self){
779 self.vb.free_resources();
780 self.ib.free_resources();
781 }
782}
783
784
785#[derive(Clone, Default)]
793pub struct CxOsView {
794}
795
796#[derive(Default, Clone)]
797pub struct CxOsDrawCallVao {
798 pub vao: Option<u32>,
799 pub shader_id: Option<usize>,
800 pub inst_vb: Option<u32>,
801 pub geom_vb: Option<u32>,
802 pub geom_ib: Option<u32>,
803}
804
805impl CxOsDrawCallVao {
806 pub fn free(self){
807 if let Some(vao) = self.vao{
808 unsafe{gl_sys::DeleteVertexArrays(1, &vao)};
809 }
810 }
811}
812
813#[derive(Default, Clone)]
814pub struct CxOsDrawCall {
815 pub inst_vb: OpenglBuffer,
816 pub vao: Option<CxOsDrawCallVao>,
817}
818
819impl CxOsDrawCall {
820 pub fn free_resources(&mut self){
821 self.inst_vb.free_resources();
822 if let Some(vao) = self.vao.take(){
823 vao.free();
824 }
825 }
826}
827
828#[derive(Clone, Default)]
829pub struct CxOsTexture {
830 pub alloc_desc: TextureDesc,
831 pub width: u64,
832 pub height: u64,
833 pub gl_texture: Option<u32>,
834 pub gl_renderbuffer: Option<u32>,
835}
836
837impl CxOsTexture {
838
839 pub fn update_platform_texture_image2d(&mut self, width: u32, height: u32, image_u32: &Vec<u32>) {
840
841 if image_u32.len() != (width * height) as usize {
842 log!("update_platform_texture_image2d with wrong buffer_u32 size! {} {} {}", image_u32.len(), width, height);
843 return;
844 }
845
846 if self.gl_texture.is_none() {
847 unsafe {
848 let mut gl_texture = std::mem::MaybeUninit::uninit();
849 gl_sys::GenTextures(1, gl_texture.as_mut_ptr());
850 self.gl_texture = Some(gl_texture.assume_init());
851 }
852 }
853 unsafe {
854 gl_sys::BindTexture(gl_sys::TEXTURE_2D, self.gl_texture.unwrap());
855 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MIN_FILTER, gl_sys::LINEAR_MIPMAP_LINEAR as i32);
856 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAG_FILTER, gl_sys::NEAREST as i32);
857 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_WRAP_S, gl_sys::CLAMP_TO_EDGE as i32);
858 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_WRAP_T, gl_sys::CLAMP_TO_EDGE as i32);
859 gl_sys::TexImage2D(
860 gl_sys::TEXTURE_2D,
861 0,
862 gl_sys::RGBA as i32,
863 width as i32,
864 height as i32,
865 0,
866 gl_sys::RGBA,
867 gl_sys::UNSIGNED_BYTE,
868 image_u32.as_ptr() as *const _
869 );
870 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_BASE_LEVEL, 0);
871 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAX_LEVEL, 3);
872 gl_sys::GenerateMipmap(gl_sys::TEXTURE_2D);
873 gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
874 }
875 }
876
877 pub fn update_platform_render_target(&mut self, desc: &TextureDesc, default_size: DVec2, is_depth: bool) -> bool {
878 let width = desc.width.unwrap_or(default_size.x as usize) as u64;
879 let height = desc.height.unwrap_or(default_size.y as usize) as u64;
880
881 if (self.gl_texture.is_some() || self.gl_renderbuffer.is_some()) && self.width == width && self.height == height && self.alloc_desc == *desc {
882 return false
883 }
884
885 unsafe {
886
887 self.alloc_desc = desc.clone();
888 self.width = width;
889 self.height = height;
890
891 if !is_depth {
892 match desc.format {
893 TextureFormat::Default | TextureFormat::RenderBGRA => {
894 if self.gl_texture.is_none() {
895 let mut gl_texture = std::mem::MaybeUninit::uninit();
896 gl_sys::GenTextures(1, gl_texture.as_mut_ptr());
897 self.gl_texture = Some(gl_texture.assume_init());
898 }
899
900 gl_sys::BindTexture(gl_sys::TEXTURE_2D, self.gl_texture.unwrap());
901
902 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MIN_FILTER, gl_sys::NEAREST as i32);
905 gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAG_FILTER, gl_sys::NEAREST as i32);
906 gl_sys::TexImage2D(
907 gl_sys::TEXTURE_2D,
908 0,
909 gl_sys::RGBA as i32,
910 width as i32,
911 height as i32,
912 0,
913 gl_sys::RGBA,
914 gl_sys::UNSIGNED_BYTE,
915 ptr::null()
916 );
917 gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
918 },
919 _ => {
920 println!("update_platform_render_target unsupported texture format");
921 return false;
922 }
923 }
924 }
925 else {
926 match desc.format {
927 TextureFormat::Default | TextureFormat::Depth32Stencil8 => {
928
929 if self.gl_renderbuffer.is_none() {
930 let mut gl_renderbuf = std::mem::MaybeUninit::uninit();
931 gl_sys::GenRenderbuffers(1, gl_renderbuf.as_mut_ptr());
932 let gl_renderbuffer = gl_renderbuf.assume_init();
933 self.gl_renderbuffer = Some(gl_renderbuffer);
934 }
935
936 gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, self.gl_renderbuffer.unwrap());
937 gl_sys::RenderbufferStorage(
938 gl_sys::RENDERBUFFER,
939 gl_sys::DEPTH_COMPONENT32F,
940 width as i32,
941 height as i32
942 );
943 gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, 0);
944 },
945 _ => {
946 println!("update_platform_render_targete unsupported texture format");
947 return false;
948 }
949 }
950 }
951
952 }
953 return true;
954 }
955
956 pub fn free_resources(&mut self){
957 if let Some(gl_texture) = self.gl_texture.take(){
958 unsafe{gl_sys::DeleteTextures(1, &gl_texture)};
959 }
960 if let Some(gl_renderbuffer) = self.gl_renderbuffer.take(){
961 unsafe{gl_sys::DeleteRenderbuffers(1, &gl_renderbuffer)};
962 }
963 }
964
965}
966
967#[derive(Default, Clone)]
968pub struct CxOsPass {
969 pub gl_framebuffer: Option<u32>,
970}
971
972impl CxOsPass{
973
974 pub fn free_resources(&mut self){
975 if let Some(gl_framebuffer) = self.gl_framebuffer.take(){
976 unsafe{gl_sys::DeleteFramebuffers(1, &gl_framebuffer)};
977 }
978 }
979}
980
981#[derive(Default, Clone)]
982pub struct OpenglBuffer {
983 pub gl_buffer: Option<u32>
984}
985
986impl OpenglBuffer {
987
988 pub fn alloc_gl_buffer(&mut self) {
989 unsafe {
990 let mut gl_buffer = std::mem::MaybeUninit::uninit();
991 gl_sys::GenBuffers(1, gl_buffer.as_mut_ptr());
992 self.gl_buffer = Some(gl_buffer.assume_init());
993 }
994 }
995
996 pub fn update_with_f32_data(&mut self, data: &Vec<f32>) {
997 if self.gl_buffer.is_none() {
998 self.alloc_gl_buffer();
999 }
1000 unsafe {
1001 gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, self.gl_buffer.unwrap());
1002 gl_sys::BufferData(
1003 gl_sys::ARRAY_BUFFER,
1004 (data.len() * mem::size_of::<f32>()) as gl_sys::types::GLsizeiptr,
1005 data.as_ptr() as *const _,
1006 gl_sys::STATIC_DRAW
1007 );
1008 }
1009 }
1010
1011 pub fn update_with_u32_data(&mut self, data: &Vec<u32>) {
1012 if self.gl_buffer.is_none() {
1013 self.alloc_gl_buffer();
1014 }
1015 unsafe {
1016 gl_sys::BindBuffer(gl_sys::ELEMENT_ARRAY_BUFFER, self.gl_buffer.unwrap());
1017 gl_sys::BufferData(
1018 gl_sys::ELEMENT_ARRAY_BUFFER,
1019 (data.len() * mem::size_of::<u32>()) as gl_sys::types::GLsizeiptr,
1020 data.as_ptr() as *const _,
1021 gl_sys::STATIC_DRAW
1022 );
1023 }
1024 }
1025
1026 pub fn free_resources(&mut self){
1027 if let Some(gl_buffer) = self.gl_buffer.take(){
1028 unsafe{gl_sys::DeleteBuffers(1, &gl_buffer)};
1029 }
1030 }
1031
1032}
1033
1034