1use super::super::shader_source::{OPTIMIZED_SHADERS, UNOPTIMIZED_SHADERS};
6use api::{ImageDescriptor, ImageFormat, Parameter, BoolParameter, IntParameter, ImageRendering};
7use api::{MixBlendMode, ImageBufferKind, VoidPtrToSizeFn};
8use api::{CrashAnnotator, CrashAnnotation, CrashAnnotatorGuard};
9use api::units::*;
10use euclid::default::Transform3D;
11use gleam::gl;
12use crate::render_api::MemoryReport;
13use crate::internal_types::{FastHashMap, RenderTargetInfo, Swizzle, SwizzleSettings};
14use crate::util::round_up_to_multiple;
15use crate::profiler;
16use log::Level;
17use smallvec::SmallVec;
18use std::{
19 borrow::Cow,
20 cell::{Cell, RefCell},
21 cmp,
22 collections::hash_map::Entry,
23 marker::PhantomData,
24 mem,
25 num::NonZeroUsize,
26 os::raw::c_void,
27 ops::Add,
28 path::PathBuf,
29 ptr,
30 rc::Rc,
31 slice,
32 sync::Arc,
33 thread,
34 time::Duration,
35};
36use webrender_build::shader::{
37 ProgramSourceDigest, ShaderKind, ShaderVersion, build_shader_main_string,
38 build_shader_prefix_string, do_build_shader_string, shader_source_from_file,
39};
40use malloc_size_of::MallocSizeOfOps;
41
42#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)]
44#[cfg_attr(feature = "capture", derive(Serialize))]
45#[cfg_attr(feature = "replay", derive(Deserialize))]
46pub struct GpuFrameId(usize);
47
48impl GpuFrameId {
49 pub fn new(value: usize) -> Self {
50 GpuFrameId(value)
51 }
52}
53
54impl Add<usize> for GpuFrameId {
55 type Output = GpuFrameId;
56
57 fn add(self, other: usize) -> GpuFrameId {
58 GpuFrameId(self.0 + other)
59 }
60}
61
62pub struct TextureSlot(pub usize);
63
64const DEFAULT_TEXTURE: TextureSlot = TextureSlot(0);
66
67#[repr(u32)]
68pub enum DepthFunction {
69 Always = gl::ALWAYS,
70 Less = gl::LESS,
71 LessEqual = gl::LEQUAL,
72}
73
74#[repr(u32)]
75#[derive(Copy, Clone, Debug, Eq, PartialEq)]
76#[cfg_attr(feature = "capture", derive(Serialize))]
77#[cfg_attr(feature = "replay", derive(Deserialize))]
78pub enum TextureFilter {
79 Nearest,
80 Linear,
81 Trilinear,
82}
83
84#[derive(Clone, Debug)]
86#[cfg_attr(feature = "capture", derive(Serialize))]
87#[cfg_attr(feature = "replay", derive(Deserialize))]
88pub struct TextureFormatPair<T> {
89 pub internal: T,
91 pub external: T,
93}
94
95impl<T: Copy> From<T> for TextureFormatPair<T> {
96 fn from(value: T) -> Self {
97 TextureFormatPair {
98 internal: value,
99 external: value,
100 }
101 }
102}
103
104#[derive(Debug)]
105pub enum VertexAttributeKind {
106 F32,
107 U8Norm,
108 U16Norm,
109 I32,
110 U16,
111}
112
113#[derive(Debug)]
114pub struct VertexAttribute {
115 pub name: &'static str,
116 pub count: u32,
117 pub kind: VertexAttributeKind,
118}
119
120impl VertexAttribute {
121 pub const fn quad_instance_vertex() -> Self {
122 VertexAttribute {
123 name: "aPosition",
124 count: 2,
125 kind: VertexAttributeKind::U8Norm,
126 }
127 }
128
129 pub const fn gpu_buffer_address(name: &'static str) -> Self {
130 VertexAttribute {
131 name,
132 count: 1,
133 kind: VertexAttributeKind::I32,
134 }
135 }
136
137 pub const fn f32x4(name: &'static str) -> Self {
138 VertexAttribute {
139 name,
140 count: 4,
141 kind: VertexAttributeKind::F32,
142 }
143 }
144
145 pub const fn f32x3(name: &'static str) -> Self {
146 VertexAttribute {
147 name,
148 count: 3,
149 kind: VertexAttributeKind::F32,
150 }
151 }
152
153 pub const fn f32x2(name: &'static str) -> Self {
154 VertexAttribute {
155 name,
156 count: 2,
157 kind: VertexAttributeKind::F32,
158 }
159 }
160
161 pub const fn f32(name: &'static str) -> Self {
162 VertexAttribute {
163 name,
164 count: 1,
165 kind: VertexAttributeKind::F32,
166 }
167 }
168
169 pub const fn i32x4(name: &'static str) -> Self {
170 VertexAttribute {
171 name,
172 count: 4,
173 kind: VertexAttributeKind::I32,
174 }
175 }
176
177 pub const fn i32x2(name: &'static str) -> Self {
178 VertexAttribute {
179 name,
180 count: 2,
181 kind: VertexAttributeKind::I32,
182 }
183 }
184
185 pub const fn i32(name: &'static str) -> Self {
186 VertexAttribute {
187 name,
188 count: 1,
189 kind: VertexAttributeKind::I32,
190 }
191 }
192
193 pub const fn u16(name: &'static str) -> Self {
194 VertexAttribute {
195 name,
196 count: 1,
197 kind: VertexAttributeKind::U16,
198 }
199 }
200
201 pub const fn u16x2(name: &'static str) -> Self {
202 VertexAttribute {
203 name,
204 count: 2,
205 kind: VertexAttributeKind::U16,
206 }
207 }
208}
209
210#[derive(Debug)]
211pub struct VertexDescriptor {
212 pub vertex_attributes: &'static [VertexAttribute],
213 pub instance_attributes: &'static [VertexAttribute],
214}
215
216enum FBOTarget {
217 Read,
218 Draw,
219}
220
221#[derive(Debug, Clone)]
223pub enum UploadMethod {
224 Immediate,
226 PixelBuffer(VertexUsageHint),
228}
229
230pub unsafe trait Texel: Copy + Default {
232 fn image_format() -> ImageFormat;
233}
234
235unsafe impl Texel for u8 {
236 fn image_format() -> ImageFormat { ImageFormat::R8 }
237}
238
239fn depth_target_size_in_bytes(dimensions: &DeviceIntSize) -> usize {
241 let pixels = dimensions.width * dimensions.height;
244 (pixels as usize) * 4
245}
246
247pub fn get_gl_target(target: ImageBufferKind) -> gl::GLuint {
248 match target {
249 ImageBufferKind::Texture2D => gl::TEXTURE_2D,
250 ImageBufferKind::TextureRect => gl::TEXTURE_RECTANGLE,
251 ImageBufferKind::TextureExternal => gl::TEXTURE_EXTERNAL_OES,
252 ImageBufferKind::TextureExternalBT709 => gl::TEXTURE_EXTERNAL_OES,
253 }
254}
255
256pub fn from_gl_target(target: gl::GLuint) -> ImageBufferKind {
257 match target {
258 gl::TEXTURE_2D => ImageBufferKind::Texture2D,
259 gl::TEXTURE_RECTANGLE => ImageBufferKind::TextureRect,
260 gl::TEXTURE_EXTERNAL_OES => ImageBufferKind::TextureExternal,
261 _ => panic!("Unexpected target {:?}", target),
262 }
263}
264
265fn supports_extension(extensions: &[String], extension: &str) -> bool {
266 extensions.iter().any(|s| s == extension)
267}
268
269fn get_shader_version(gl: &dyn gl::Gl) -> ShaderVersion {
270 match gl.get_type() {
271 gl::GlType::Gl => ShaderVersion::Gl,
272 gl::GlType::Gles => ShaderVersion::Gles,
273 }
274}
275
276pub fn get_unoptimized_shader_source(shader_name: &str, base_path: Option<&PathBuf>) -> Cow<'static, str> {
279 if let Some(ref base) = base_path {
280 let shader_path = base.join(&format!("{}.glsl", shader_name));
281 Cow::Owned(shader_source_from_file(&shader_path))
282 } else {
283 Cow::Borrowed(
284 UNOPTIMIZED_SHADERS
285 .get(shader_name)
286 .expect("Shader not found")
287 .source
288 )
289 }
290}
291
292impl VertexAttributeKind {
293 fn size_in_bytes(&self) -> u32 {
294 match *self {
295 VertexAttributeKind::F32 => 4,
296 VertexAttributeKind::U8Norm => 1,
297 VertexAttributeKind::U16Norm => 2,
298 VertexAttributeKind::I32 => 4,
299 VertexAttributeKind::U16 => 2,
300 }
301 }
302}
303
304impl VertexAttribute {
305 fn size_in_bytes(&self) -> u32 {
306 self.count * self.kind.size_in_bytes()
307 }
308
309 fn bind_to_vao(
310 &self,
311 attr_index: gl::GLuint,
312 divisor: gl::GLuint,
313 stride: gl::GLint,
314 offset: gl::GLuint,
315 gl: &dyn gl::Gl,
316 ) {
317 gl.enable_vertex_attrib_array(attr_index);
318 gl.vertex_attrib_divisor(attr_index, divisor);
319
320 match self.kind {
321 VertexAttributeKind::F32 => {
322 gl.vertex_attrib_pointer(
323 attr_index,
324 self.count as gl::GLint,
325 gl::FLOAT,
326 false,
327 stride,
328 offset,
329 );
330 }
331 VertexAttributeKind::U8Norm => {
332 gl.vertex_attrib_pointer(
333 attr_index,
334 self.count as gl::GLint,
335 gl::UNSIGNED_BYTE,
336 true,
337 stride,
338 offset,
339 );
340 }
341 VertexAttributeKind::U16Norm => {
342 gl.vertex_attrib_pointer(
343 attr_index,
344 self.count as gl::GLint,
345 gl::UNSIGNED_SHORT,
346 true,
347 stride,
348 offset,
349 );
350 }
351 VertexAttributeKind::I32 => {
352 gl.vertex_attrib_i_pointer(
353 attr_index,
354 self.count as gl::GLint,
355 gl::INT,
356 stride,
357 offset,
358 );
359 }
360 VertexAttributeKind::U16 => {
361 gl.vertex_attrib_i_pointer(
362 attr_index,
363 self.count as gl::GLint,
364 gl::UNSIGNED_SHORT,
365 stride,
366 offset,
367 );
368 }
369 }
370 }
371}
372
373impl VertexDescriptor {
374 fn instance_stride(&self) -> u32 {
375 self.instance_attributes
376 .iter()
377 .map(|attr| attr.size_in_bytes())
378 .sum()
379 }
380
381 fn bind_attributes(
382 attributes: &[VertexAttribute],
383 start_index: usize,
384 divisor: u32,
385 gl: &dyn gl::Gl,
386 vbo: VBOId,
387 ) {
388 vbo.bind(gl);
389
390 let stride: u32 = attributes
391 .iter()
392 .map(|attr| attr.size_in_bytes())
393 .sum();
394
395 let mut offset = 0;
396 for (i, attr) in attributes.iter().enumerate() {
397 let attr_index = (start_index + i) as gl::GLuint;
398 attr.bind_to_vao(attr_index, divisor, stride as _, offset, gl);
399 offset += attr.size_in_bytes();
400 }
401 }
402
403 fn bind(&self, gl: &dyn gl::Gl, main: VBOId, instance: VBOId, instance_divisor: u32) {
404 Self::bind_attributes(self.vertex_attributes, 0, 0, gl, main);
405
406 if !self.instance_attributes.is_empty() {
407 Self::bind_attributes(
408 self.instance_attributes,
409 self.vertex_attributes.len(),
410 instance_divisor,
411 gl,
412 instance,
413 );
414 }
415 }
416}
417
418impl VBOId {
419 fn bind(&self, gl: &dyn gl::Gl) {
420 gl.bind_buffer(gl::ARRAY_BUFFER, self.0);
421 }
422}
423
424impl IBOId {
425 fn bind(&self, gl: &dyn gl::Gl) {
426 gl.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0);
427 }
428}
429
430impl FBOId {
431 fn bind(&self, gl: &dyn gl::Gl, target: FBOTarget) {
432 let target = match target {
433 FBOTarget::Read => gl::READ_FRAMEBUFFER,
434 FBOTarget::Draw => gl::DRAW_FRAMEBUFFER,
435 };
436 gl.bind_framebuffer(target, self.0);
437 }
438}
439
440pub struct Stream<'a> {
441 attributes: &'a [VertexAttribute],
442 vbo: VBOId,
443}
444
445pub struct VBO<V> {
446 id: gl::GLuint,
447 target: gl::GLenum,
448 allocated_count: usize,
449 marker: PhantomData<V>,
450}
451
452impl<V> VBO<V> {
453 pub fn allocated_count(&self) -> usize {
454 self.allocated_count
455 }
456
457 pub fn stream_with<'a>(&self, attributes: &'a [VertexAttribute]) -> Stream<'a> {
458 debug_assert_eq!(
459 mem::size_of::<V>(),
460 attributes.iter().map(|a| a.size_in_bytes() as usize).sum::<usize>()
461 );
462 Stream {
463 attributes,
464 vbo: VBOId(self.id),
465 }
466 }
467}
468
469impl<T> Drop for VBO<T> {
470 fn drop(&mut self) {
471 debug_assert!(thread::panicking() || self.id == 0);
472 }
473}
474
475#[cfg_attr(feature = "replay", derive(Clone))]
476#[derive(Debug)]
477pub struct ExternalTexture {
478 id: gl::GLuint,
479 target: gl::GLuint,
480 uv_rect: TexelRect,
481 image_rendering: ImageRendering,
482}
483
484impl ExternalTexture {
485 pub fn new(
486 id: u32,
487 target: ImageBufferKind,
488 uv_rect: TexelRect,
489 image_rendering: ImageRendering,
490 ) -> Self {
491 ExternalTexture {
492 id,
493 target: get_gl_target(target),
494 uv_rect,
495 image_rendering,
496 }
497 }
498
499 #[cfg(feature = "replay")]
500 pub fn internal_id(&self) -> gl::GLuint {
501 self.id
502 }
503
504 pub fn get_uv_rect(&self) -> TexelRect {
505 self.uv_rect
506 }
507}
508
509bitflags! {
510 #[derive(Default, Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
511 pub struct TextureFlags: u32 {
512 const IS_SHARED_TEXTURE_CACHE = 1 << 0;
514 }
515}
516
517#[derive(Debug)]
523pub struct Texture {
524 id: gl::GLuint,
525 target: gl::GLuint,
526 format: ImageFormat,
527 size: DeviceIntSize,
528 filter: TextureFilter,
529 flags: TextureFlags,
530 active_swizzle: Cell<Swizzle>,
532 fbo: Option<FBOId>,
536 fbo_with_depth: Option<FBOId>,
554 last_frame_used: GpuFrameId,
555}
556
557impl Texture {
558 pub fn get_dimensions(&self) -> DeviceIntSize {
559 self.size
560 }
561
562 pub fn get_format(&self) -> ImageFormat {
563 self.format
564 }
565
566 pub fn get_filter(&self) -> TextureFilter {
567 self.filter
568 }
569
570 pub fn get_target(&self) -> ImageBufferKind {
571 from_gl_target(self.target)
572 }
573
574 pub fn supports_depth(&self) -> bool {
575 self.fbo_with_depth.is_some()
576 }
577
578 pub fn last_frame_used(&self) -> GpuFrameId {
579 self.last_frame_used
580 }
581
582 pub fn used_in_frame(&self, frame_id: GpuFrameId) -> bool {
583 self.last_frame_used == frame_id
584 }
585
586 pub fn is_render_target(&self) -> bool {
587 self.fbo.is_some()
588 }
589
590 pub fn used_recently(&self, current_frame_id: GpuFrameId, threshold: usize) -> bool {
593 self.last_frame_used + threshold >= current_frame_id
594 }
595
596 pub fn flags(&self) -> &TextureFlags {
598 &self.flags
599 }
600
601 pub fn flags_mut(&mut self) -> &mut TextureFlags {
603 &mut self.flags
604 }
605
606 pub fn size_in_bytes(&self) -> usize {
609 let bpp = self.format.bytes_per_pixel() as usize;
610 let w = self.size.width as usize;
611 let h = self.size.height as usize;
612 bpp * w * h
613 }
614
615 #[cfg(feature = "replay")]
616 pub fn into_external(mut self) -> ExternalTexture {
617 let ext = ExternalTexture {
618 id: self.id,
619 target: self.target,
620 uv_rect: TexelRect::new(
622 0.0,
623 0.0,
624 self.size.width as f32,
625 self.size.height as f32,
626 ),
627 image_rendering: ImageRendering::Auto,
628 };
629 self.id = 0; ext
631 }
632}
633
634impl Drop for Texture {
635 fn drop(&mut self) {
636 debug_assert!(thread::panicking() || self.id == 0);
637 }
638}
639
640pub struct Program {
641 id: gl::GLuint,
642 u_transform: gl::GLint,
643 u_texture_size: gl::GLint,
644 source_info: ProgramSourceInfo,
645 is_initialized: bool,
646}
647
648impl Program {
649 pub fn is_initialized(&self) -> bool {
650 self.is_initialized
651 }
652}
653
654impl Drop for Program {
655 fn drop(&mut self) {
656 debug_assert!(
657 thread::panicking() || self.id == 0,
658 "renderer::deinit not called"
659 );
660 }
661}
662
663pub struct CustomVAO {
664 id: gl::GLuint,
665}
666
667impl Drop for CustomVAO {
668 fn drop(&mut self) {
669 debug_assert!(
670 thread::panicking() || self.id == 0,
671 "renderer::deinit not called"
672 );
673 }
674}
675
676pub struct VAO {
677 id: gl::GLuint,
678 ibo_id: IBOId,
679 main_vbo_id: VBOId,
680 instance_vbo_id: VBOId,
681 instance_stride: usize,
682 instance_divisor: u32,
683 owns_vertices_and_indices: bool,
684}
685
686impl Drop for VAO {
687 fn drop(&mut self) {
688 debug_assert!(
689 thread::panicking() || self.id == 0,
690 "renderer::deinit not called"
691 );
692 }
693}
694
695#[derive(Debug)]
696pub struct PBO {
697 id: gl::GLuint,
698 reserved_size: usize,
699}
700
701impl PBO {
702 pub fn get_reserved_size(&self) -> usize {
703 self.reserved_size
704 }
705}
706
707impl Drop for PBO {
708 fn drop(&mut self) {
709 debug_assert!(
710 thread::panicking() || self.id == 0,
711 "renderer::deinit not called or PBO not returned to pool"
712 );
713 }
714}
715
716pub struct BoundPBO<'a> {
717 device: &'a mut Device,
718 pub data: &'a [u8]
719}
720
721impl<'a> Drop for BoundPBO<'a> {
722 fn drop(&mut self) {
723 self.device.gl.unmap_buffer(gl::PIXEL_PACK_BUFFER);
724 self.device.gl.bind_buffer(gl::PIXEL_PACK_BUFFER, 0);
725 }
726}
727
728#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
729pub struct FBOId(gl::GLuint);
730
731#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
732pub struct RBOId(gl::GLuint);
733
734#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
735pub struct VBOId(gl::GLuint);
736
737#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
738struct IBOId(gl::GLuint);
739
740#[derive(Clone, Debug)]
741enum ProgramSourceType {
742 Unoptimized,
743 Optimized(ShaderVersion),
744}
745
746#[derive(Clone, Debug)]
747pub struct ProgramSourceInfo {
748 base_filename: &'static str,
749 features: Vec<&'static str>,
750 full_name_cstr: Rc<std::ffi::CString>,
751 source_type: ProgramSourceType,
752 digest: ProgramSourceDigest,
753}
754
755impl ProgramSourceInfo {
756 fn new(
757 device: &Device,
758 name: &'static str,
759 features: &[&'static str],
760 ) -> Self {
761
762 use std::collections::hash_map::DefaultHasher;
766 use std::hash::Hasher;
767
768 let mut hasher = DefaultHasher::new();
770 let gl_version = get_shader_version(&*device.gl());
771
772 hasher.write(device.capabilities.renderer_name.as_bytes());
774
775 let full_name = Self::make_full_name(name, features);
776
777 let optimized_source = if device.use_optimized_shaders {
778 OPTIMIZED_SHADERS.get(&(gl_version, &full_name)).or_else(|| {
779 warn!("Missing optimized shader source for {}", &full_name);
780 None
781 })
782 } else {
783 None
784 };
785
786 let source_type = match optimized_source {
787 Some(source_and_digest) => {
788 if cfg!(debug_assertions) {
792 let mut h = DefaultHasher::new();
793 h.write(source_and_digest.vert_source.as_bytes());
794 h.write(source_and_digest.frag_source.as_bytes());
795 let d: ProgramSourceDigest = h.into();
796 let digest = d.to_string();
797 debug_assert_eq!(digest, source_and_digest.digest);
798 hasher.write(digest.as_bytes());
799 } else {
800 hasher.write(source_and_digest.digest.as_bytes());
801 }
802
803 ProgramSourceType::Optimized(gl_version)
804 }
805 None => {
806 let override_path = device.resource_override_path.as_ref();
815 let source_and_digest = UNOPTIMIZED_SHADERS.get(&name).expect("Shader not found");
816
817 build_shader_prefix_string(
819 gl_version,
820 &features,
821 ShaderKind::Vertex,
822 &name,
823 &mut |s| hasher.write(s.as_bytes()),
824 );
825
826 if override_path.is_some() || cfg!(debug_assertions) {
829 let mut h = DefaultHasher::new();
830 build_shader_main_string(
831 &name,
832 &|f| get_unoptimized_shader_source(f, override_path),
833 &mut |s| h.write(s.as_bytes())
834 );
835 let d: ProgramSourceDigest = h.into();
836 let digest = format!("{}", d);
837 debug_assert!(override_path.is_some() || digest == source_and_digest.digest);
838 hasher.write(digest.as_bytes());
839 } else {
840 hasher.write(source_and_digest.digest.as_bytes());
841 }
842
843 ProgramSourceType::Unoptimized
844 }
845 };
846
847 ProgramSourceInfo {
849 base_filename: name,
850 features: features.to_vec(),
851 full_name_cstr: Rc::new(std::ffi::CString::new(full_name).unwrap()),
852 source_type,
853 digest: hasher.into(),
854 }
855 }
856
857 fn compute_source(&self, device: &Device, kind: ShaderKind) -> String {
858 let full_name = self.full_name();
859 match self.source_type {
860 ProgramSourceType::Optimized(gl_version) => {
861 let shader = OPTIMIZED_SHADERS
862 .get(&(gl_version, &full_name))
863 .unwrap_or_else(|| panic!("Missing optimized shader source for {}", full_name));
864
865 match kind {
866 ShaderKind::Vertex => shader.vert_source.to_string(),
867 ShaderKind::Fragment => shader.frag_source.to_string(),
868 }
869 },
870 ProgramSourceType::Unoptimized => {
871 let mut src = String::new();
872 device.build_shader_string(
873 &self.features,
874 kind,
875 self.base_filename,
876 |s| src.push_str(s),
877 );
878 src
879 }
880 }
881 }
882
883 fn make_full_name(base_filename: &'static str, features: &[&'static str]) -> String {
884 if features.is_empty() {
885 base_filename.to_string()
886 } else {
887 format!("{}_{}", base_filename, features.join("_"))
888 }
889 }
890
891 fn full_name(&self) -> String {
892 Self::make_full_name(self.base_filename, &self.features)
893 }
894}
895
896#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))]
897pub struct ProgramBinary {
898 bytes: Vec<u8>,
899 format: gl::GLenum,
900 source_digest: ProgramSourceDigest,
901}
902
903impl ProgramBinary {
904 fn new(bytes: Vec<u8>,
905 format: gl::GLenum,
906 source_digest: ProgramSourceDigest) -> Self {
907 ProgramBinary {
908 bytes,
909 format,
910 source_digest,
911 }
912 }
913
914 pub fn source_digest(&self) -> &ProgramSourceDigest {
916 &self.source_digest
917 }
918}
919
920pub trait ProgramCacheObserver {
922 fn save_shaders_to_disk(&self, entries: Vec<Arc<ProgramBinary>>);
923 fn set_startup_shaders(&self, entries: Vec<Arc<ProgramBinary>>);
924 fn try_load_shader_from_disk(&self, digest: &ProgramSourceDigest, program_cache: &Rc<ProgramCache>);
925 fn notify_program_binary_failed(&self, program_binary: &Arc<ProgramBinary>);
926}
927
928struct ProgramCacheEntry {
929 binary: Arc<ProgramBinary>,
931 linked: bool,
933}
934
935pub struct ProgramCache {
936 entries: RefCell<FastHashMap<ProgramSourceDigest, ProgramCacheEntry>>,
937
938 program_cache_handler: Option<Box<dyn ProgramCacheObserver>>,
941
942 pending_entries: RefCell<Vec<Arc<ProgramBinary>>>,
944}
945
946impl ProgramCache {
947 pub fn new(program_cache_observer: Option<Box<dyn ProgramCacheObserver>>) -> Rc<Self> {
948 Rc::new(
949 ProgramCache {
950 entries: RefCell::new(FastHashMap::default()),
951 program_cache_handler: program_cache_observer,
952 pending_entries: RefCell::new(Vec::default()),
953 }
954 )
955 }
956
957 fn update_disk_cache(&self, startup_complete: bool) {
960 if let Some(ref handler) = self.program_cache_handler {
961 if !self.pending_entries.borrow().is_empty() {
962 let pending_entries = self.pending_entries.replace(Vec::default());
963 handler.save_shaders_to_disk(pending_entries);
964 }
965
966 if startup_complete {
967 let startup_shaders = self.entries.borrow().values()
968 .filter(|e| e.linked).map(|e| e.binary.clone())
969 .collect::<Vec<_>>();
970 handler.set_startup_shaders(startup_shaders);
971 }
972 }
973 }
974
975 fn add_new_program_binary(&self, program_binary: Arc<ProgramBinary>) {
979 self.pending_entries.borrow_mut().push(program_binary.clone());
980
981 let digest = program_binary.source_digest.clone();
982 let entry = ProgramCacheEntry {
983 binary: program_binary,
984 linked: true,
985 };
986 self.entries.borrow_mut().insert(digest, entry);
987 }
988
989 #[cfg(feature = "serialize_program")]
992 pub fn load_program_binary(&self, program_binary: Arc<ProgramBinary>) {
993 let digest = program_binary.source_digest.clone();
994 let entry = ProgramCacheEntry {
995 binary: program_binary,
996 linked: false,
997 };
998 self.entries.borrow_mut().insert(digest, entry);
999 }
1000
1001 pub fn report_memory(&self, op: VoidPtrToSizeFn) -> usize {
1003 self.entries.borrow().values()
1004 .map(|e| unsafe { op(e.binary.bytes.as_ptr() as *const c_void ) })
1005 .sum()
1006 }
1007}
1008
1009#[derive(Debug, Copy, Clone)]
1010pub enum VertexUsageHint {
1011 Static,
1012 Dynamic,
1013 Stream,
1014}
1015
1016impl VertexUsageHint {
1017 fn to_gl(&self) -> gl::GLuint {
1018 match *self {
1019 VertexUsageHint::Static => gl::STATIC_DRAW,
1020 VertexUsageHint::Dynamic => gl::DYNAMIC_DRAW,
1021 VertexUsageHint::Stream => gl::STREAM_DRAW,
1022 }
1023 }
1024}
1025
1026#[derive(Copy, Clone, Debug)]
1027pub struct UniformLocation(#[allow(dead_code)] gl::GLint);
1028
1029impl UniformLocation {
1030 pub const INVALID: Self = UniformLocation(-1);
1031}
1032
1033#[derive(Debug)]
1034pub struct Capabilities {
1035 pub supports_multisampling: bool,
1037 pub supports_copy_image_sub_data: bool,
1039 pub supports_color_buffer_float: bool,
1041 pub supports_buffer_storage: bool,
1043 pub supports_advanced_blend_equation: bool,
1045 pub supports_dual_source_blending: bool,
1047 pub supports_khr_debug: bool,
1050 pub supports_texture_swizzle: bool,
1052 pub supports_nonzero_pbo_offsets: bool,
1055 pub supports_texture_usage: bool,
1057 pub supports_render_target_partial_update: bool,
1059 pub supports_shader_storage_object: bool,
1061 pub requires_batched_texture_uploads: Option<bool>,
1064 pub supports_alpha_target_clears: bool,
1067 pub requires_alpha_target_full_clear: bool,
1070 pub prefers_clear_scissor: bool,
1073 pub supports_render_target_invalidate: bool,
1076 pub supports_r8_texture_upload: bool,
1078 pub supports_qcom_tiled_rendering: bool,
1080 pub uses_native_clip_mask: bool,
1083 pub uses_native_antialiasing: bool,
1086 pub supports_image_external_essl3: bool,
1090 pub requires_vao_rebind_after_orphaning: bool,
1092 pub renderer_name: String,
1094}
1095
1096#[derive(Clone, Debug)]
1097pub enum ShaderError {
1098 Compilation(String, String), Link(String, String), }
1101
1102struct SharedDepthTarget {
1105 rbo_id: RBOId,
1107 refcount: usize,
1109}
1110
1111#[cfg(debug_assertions)]
1112impl Drop for SharedDepthTarget {
1113 fn drop(&mut self) {
1114 debug_assert!(thread::panicking() || self.refcount == 0);
1115 }
1116}
1117
1118#[derive(PartialEq, Debug)]
1121enum TexStorageUsage {
1122 Never,
1123 NonBGRA8,
1124 Always,
1125}
1126
1127#[derive(Copy, Clone, Debug)]
1130pub enum StrideAlignment {
1131 Bytes(NonZeroUsize),
1132 Pixels(NonZeroUsize),
1133}
1134
1135impl StrideAlignment {
1136 pub fn num_bytes(&self, format: ImageFormat) -> NonZeroUsize {
1137 match *self {
1138 Self::Bytes(bytes) => bytes,
1139 Self::Pixels(pixels) => {
1140 assert!(format.bytes_per_pixel() > 0);
1141 NonZeroUsize::new(pixels.get() * format.bytes_per_pixel() as usize).unwrap()
1142 }
1143 }
1144 }
1145}
1146
1147const RESERVE_DEPTH_BITS: i32 = 2;
1152
1153pub struct Device {
1154 gl: Rc<dyn gl::Gl>,
1155
1156 base_gl: Option<Rc<dyn gl::Gl>>,
1159
1160 bound_textures: [gl::GLuint; 16],
1162 bound_program: gl::GLuint,
1163 bound_program_name: Rc<std::ffi::CString>,
1164 bound_vao: gl::GLuint,
1165 bound_read_fbo: (FBOId, DeviceIntPoint),
1166 bound_draw_fbo: FBOId,
1167 default_read_fbo: FBOId,
1168 default_draw_fbo: FBOId,
1169
1170 depth_available: bool,
1173
1174 upload_method: UploadMethod,
1175 use_batched_texture_uploads: bool,
1176 use_draw_calls_for_texture_copy: bool,
1181 batched_upload_threshold: i32,
1183
1184 capabilities: Capabilities,
1186
1187 color_formats: TextureFormatPair<ImageFormat>,
1188 bgra_formats: TextureFormatPair<gl::GLuint>,
1189 bgra_pixel_type: gl::GLuint,
1190 swizzle_settings: SwizzleSettings,
1191 depth_format: gl::GLuint,
1192
1193 depth_targets: FastHashMap<DeviceIntSize, SharedDepthTarget>,
1198
1199 inside_frame: bool,
1201 crash_annotator: Option<Box<dyn CrashAnnotator>>,
1202 annotate_draw_call_crashes: bool,
1203
1204 resource_override_path: Option<PathBuf>,
1206
1207 use_optimized_shaders: bool,
1209
1210 max_texture_size: i32,
1211 cached_programs: Option<Rc<ProgramCache>>,
1212
1213 frame_id: GpuFrameId,
1216
1217 texture_storage_usage: TexStorageUsage,
1223
1224 required_pbo_stride: StrideAlignment,
1228
1229 requires_null_terminated_shader_source: bool,
1232
1233 requires_texture_external_unbind: bool,
1236
1237 is_software_webrender: bool,
1239
1240 extensions: Vec<String>,
1242
1243 dump_shader_source: Option<String>,
1245
1246 surface_origin_is_top_left: bool,
1247
1248 #[cfg(debug_assertions)]
1261 shader_is_ready: bool,
1262
1263 pub textures_created: u32,
1265 pub textures_deleted: u32,
1266}
1267
1268#[derive(Clone, Copy, Debug)]
1270pub enum DrawTarget {
1271 Default {
1274 rect: FramebufferIntRect,
1276 total_size: FramebufferIntSize,
1278 surface_origin_is_top_left: bool,
1279 },
1280 Texture {
1282 dimensions: DeviceIntSize,
1284 with_depth: bool,
1286 fbo_id: FBOId,
1288 id: gl::GLuint,
1290 target: gl::GLuint,
1292 },
1293 External {
1295 fbo: FBOId,
1296 size: FramebufferIntSize,
1297 },
1298 NativeSurface {
1300 offset: DeviceIntPoint,
1301 external_fbo_id: u32,
1302 dimensions: DeviceIntSize,
1303 },
1304}
1305
1306impl DrawTarget {
1307 pub fn new_default(size: DeviceIntSize, surface_origin_is_top_left: bool) -> Self {
1308 let total_size = device_size_as_framebuffer_size(size);
1309 DrawTarget::Default {
1310 rect: total_size.into(),
1311 total_size,
1312 surface_origin_is_top_left,
1313 }
1314 }
1315
1316 pub fn is_default(&self) -> bool {
1318 match *self {
1319 DrawTarget::Default {..} => true,
1320 _ => false,
1321 }
1322 }
1323
1324 pub fn from_texture(
1325 texture: &Texture,
1326 with_depth: bool,
1327 ) -> Self {
1328 let fbo_id = if with_depth {
1329 texture.fbo_with_depth.unwrap()
1330 } else {
1331 texture.fbo.unwrap()
1332 };
1333
1334 DrawTarget::Texture {
1335 dimensions: texture.get_dimensions(),
1336 fbo_id,
1337 with_depth,
1338 id: texture.id,
1339 target: texture.target,
1340 }
1341 }
1342
1343 pub fn dimensions(&self) -> DeviceIntSize {
1345 match *self {
1346 DrawTarget::Default { total_size, .. } => total_size.cast_unit(),
1347 DrawTarget::Texture { dimensions, .. } => dimensions,
1348 DrawTarget::External { size, .. } => size.cast_unit(),
1349 DrawTarget::NativeSurface { dimensions, .. } => dimensions,
1350 }
1351 }
1352
1353 pub fn offset(&self) -> DeviceIntPoint {
1354 match *self {
1355 DrawTarget::Default { .. } |
1356 DrawTarget::Texture { .. } |
1357 DrawTarget::External { .. } => {
1358 DeviceIntPoint::zero()
1359 }
1360 DrawTarget::NativeSurface { offset, .. } => offset,
1361 }
1362 }
1363
1364 pub fn to_framebuffer_rect(&self, device_rect: DeviceIntRect) -> FramebufferIntRect {
1365 let mut fb_rect = device_rect_as_framebuffer_rect(&device_rect);
1366 match *self {
1367 DrawTarget::Default { ref rect, surface_origin_is_top_left, .. } => {
1368 if !surface_origin_is_top_left {
1370 let w = fb_rect.width();
1371 let h = fb_rect.height();
1372 fb_rect.min.x = fb_rect.min.x + rect.min.x;
1373 fb_rect.min.y = rect.max.y - fb_rect.max.y;
1374 fb_rect.max.x = fb_rect.min.x + w;
1375 fb_rect.max.y = fb_rect.min.y + h;
1376 }
1377 }
1378 DrawTarget::Texture { .. } | DrawTarget::External { .. } | DrawTarget::NativeSurface { .. } => (),
1379 }
1380 fb_rect
1381 }
1382
1383 pub fn surface_origin_is_top_left(&self) -> bool {
1384 match *self {
1385 DrawTarget::Default { surface_origin_is_top_left, .. } => surface_origin_is_top_left,
1386 DrawTarget::Texture { .. } | DrawTarget::External { .. } | DrawTarget::NativeSurface { .. } => true,
1387 }
1388 }
1389
1390 pub fn build_scissor_rect(
1394 &self,
1395 scissor_rect: Option<DeviceIntRect>,
1396 ) -> FramebufferIntRect {
1397 let dimensions = self.dimensions();
1398
1399 match scissor_rect {
1400 Some(scissor_rect) => match *self {
1401 DrawTarget::Default { ref rect, .. } => {
1402 self.to_framebuffer_rect(scissor_rect)
1403 .intersection(rect)
1404 .unwrap_or_else(FramebufferIntRect::zero)
1405 }
1406 DrawTarget::NativeSurface { offset, .. } => {
1407 device_rect_as_framebuffer_rect(&scissor_rect.translate(offset.to_vector()))
1408 }
1409 DrawTarget::Texture { .. } | DrawTarget::External { .. } => {
1410 device_rect_as_framebuffer_rect(&scissor_rect)
1411 }
1412 }
1413 None => {
1414 FramebufferIntRect::from_size(
1415 device_size_as_framebuffer_size(dimensions),
1416 )
1417 }
1418 }
1419 }
1420}
1421
1422#[derive(Clone, Copy, Debug)]
1424pub enum ReadTarget {
1425 Default,
1427 Texture {
1429 fbo_id: FBOId,
1431 },
1432 External {
1434 fbo: FBOId,
1435 },
1436 NativeSurface {
1438 fbo_id: FBOId,
1439 offset: DeviceIntPoint,
1440 },
1441}
1442
1443impl ReadTarget {
1444 pub fn from_texture(
1445 texture: &Texture,
1446 ) -> Self {
1447 ReadTarget::Texture {
1448 fbo_id: texture.fbo.unwrap(),
1449 }
1450 }
1451
1452 fn offset(&self) -> DeviceIntPoint {
1453 match *self {
1454 ReadTarget::Default |
1455 ReadTarget::Texture { .. } |
1456 ReadTarget::External { .. } => {
1457 DeviceIntPoint::zero()
1458 }
1459
1460 ReadTarget::NativeSurface { offset, .. } => {
1461 offset
1462 }
1463 }
1464 }
1465}
1466
1467impl From<DrawTarget> for ReadTarget {
1468 fn from(t: DrawTarget) -> Self {
1469 match t {
1470 DrawTarget::Default { .. } => {
1471 ReadTarget::Default
1472 }
1473 DrawTarget::NativeSurface { external_fbo_id, offset, .. } => {
1474 ReadTarget::NativeSurface {
1475 fbo_id: FBOId(external_fbo_id),
1476 offset,
1477 }
1478 }
1479 DrawTarget::Texture { fbo_id, .. } => {
1480 ReadTarget::Texture { fbo_id }
1481 }
1482 DrawTarget::External { fbo, .. } => {
1483 ReadTarget::External { fbo }
1484 }
1485 }
1486 }
1487}
1488
1489fn parse_mali_version(version_string: &str) -> Option<(u32, u32, u32)> {
1494 let (_prefix, version_string) = version_string.split_once("v")?;
1495 let (v_str, version_string) = version_string.split_once(".r")?;
1496 let v = v_str.parse().ok()?;
1497
1498 let (r_str, version_string) = version_string.split_once("p")?;
1499 let r = r_str.parse().ok()?;
1500
1501 let (p_str, _) = version_string.split_once("-").unwrap_or((version_string, ""));
1503 let p = p_str.parse().ok()?;
1504
1505 Some((v, r, p))
1506}
1507
1508fn is_mali_midgard(renderer_name: &str) -> bool {
1510 renderer_name.starts_with("Mali-T")
1511}
1512
1513fn is_mali_bifrost(renderer_name: &str) -> bool {
1515 renderer_name == "Mali-G31"
1516 || renderer_name == "Mali-G51"
1517 || renderer_name == "Mali-G71"
1518 || renderer_name == "Mali-G52"
1519 || renderer_name == "Mali-G72"
1520 || renderer_name == "Mali-G76"
1521}
1522
1523fn is_mali_valhall(renderer_name: &str) -> bool {
1525 renderer_name.starts_with("Mali-G") && !is_mali_bifrost(renderer_name)
1528}
1529#[inline(never)]
1530fn gl_error_string(code: u32) -> &'static str {
1531 match code {
1532 gl::INVALID_ENUM => "GL_INVALID_ENUM",
1533 gl::INVALID_VALUE => "GL_INVALID_VALUE",
1534 gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
1535 gl::STACK_OVERFLOW => "GL_STACK_OVERFLOW",
1536 gl::STACK_UNDERFLOW => "GL_STACK_UNDERFLOW",
1537 gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
1538 gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
1539 0x507 => "GL_CONTEXT_LOST",
1540 _ => "(unknown error code)",
1541 }
1542}
1543
1544impl Device {
1545 pub fn new(
1546 mut gl: Rc<dyn gl::Gl>,
1547 crash_annotator: Option<Box<dyn CrashAnnotator>>,
1548 resource_override_path: Option<PathBuf>,
1549 use_optimized_shaders: bool,
1550 upload_method: UploadMethod,
1551 batched_upload_threshold: i32,
1552 cached_programs: Option<Rc<ProgramCache>>,
1553 allow_texture_storage_support: bool,
1554 allow_texture_swizzling: bool,
1555 dump_shader_source: Option<String>,
1556 surface_origin_is_top_left: bool,
1557 panic_on_gl_error: bool,
1558 ) -> Device {
1559 let mut max_texture_size = [0];
1560 unsafe {
1561 gl.get_integer_v(gl::MAX_TEXTURE_SIZE, &mut max_texture_size);
1562 }
1563
1564 let max_texture_size = max_texture_size[0].min(16384);
1568
1569 let renderer_name = gl.get_string(gl::RENDERER);
1570 info!("Renderer: {}", renderer_name);
1571 let version_string = gl.get_string(gl::VERSION);
1572 info!("Version: {}", version_string);
1573 info!("Max texture size: {}", max_texture_size);
1574
1575 let mut extension_count = [0];
1576 unsafe {
1577 gl.get_integer_v(gl::NUM_EXTENSIONS, &mut extension_count);
1578 }
1579 let extension_count = extension_count[0] as gl::GLuint;
1580 let mut extensions = Vec::new();
1581 for i in 0 .. extension_count {
1582 extensions.push(gl.get_string_i(gl::EXTENSIONS, i));
1583 }
1584
1585 let supports_khr_debug = supports_extension(&extensions, "GL_KHR_debug")
1588 && !is_mali_valhall(&renderer_name);
1589
1590 if panic_on_gl_error || cfg!(debug_assertions) {
1594 gl = gl::ErrorReactingGl::wrap(gl, move |gl, name, code| {
1595 if supports_khr_debug {
1596 Self::log_driver_messages(gl);
1597 }
1598 let err_name = gl_error_string(code);
1599 error!("Caught GL error 0x{:x} {} at {}", code, err_name, name);
1600 panic!("Caught GL error 0x{:x} {} at {}", code, err_name, name);
1601 });
1602 }
1603
1604 if supports_extension(&extensions, "GL_ANGLE_provoking_vertex") {
1605 gl.provoking_vertex_angle(gl::FIRST_VERTEX_CONVENTION);
1606 }
1607
1608 let supports_texture_usage = supports_extension(&extensions, "GL_ANGLE_texture_usage");
1609
1610 let is_emulator = renderer_name.starts_with("Android Emulator");
1653 let avoid_tex_image = is_emulator;
1654 let mut gl_version = [0; 2];
1655 unsafe {
1656 gl.get_integer_v(gl::MAJOR_VERSION, &mut gl_version[0..1]);
1657 gl.get_integer_v(gl::MINOR_VERSION, &mut gl_version[1..2]);
1658 }
1659 info!("GL context {:?} {}.{}", gl.get_type(), gl_version[0], gl_version[1]);
1660
1661 let supports_texture_storage = allow_texture_storage_support && !cfg!(target_os = "macos") &&
1663 match gl.get_type() {
1664 gl::GlType::Gl => supports_extension(&extensions, "GL_ARB_texture_storage"),
1665 gl::GlType::Gles => true,
1666 };
1667
1668 let supports_gles_bgra = supports_extension(&extensions, "GL_EXT_texture_format_BGRA8888");
1676 let supports_texture_storage_with_gles_bgra = supports_gles_bgra
1677 && supports_extension(&extensions, "GL_EXT_texture_storage")
1678 && !renderer_name.starts_with("Intel(R) HD Graphics for BayTrail")
1679 && !renderer_name.starts_with("Intel(R) HD Graphics for Atom(TM) x5/x7");
1680
1681 let supports_texture_swizzle = allow_texture_swizzling &&
1682 match gl.get_type() {
1683 gl::GlType::Gl => gl_version >= [3, 3] ||
1685 supports_extension(&extensions, "GL_ARB_texture_swizzle"),
1686 gl::GlType::Gles => true,
1687 };
1688
1689 let (color_formats, bgra_formats, bgra_pixel_type, bgra8_sampling_swizzle, texture_storage_usage) = match gl.get_type() {
1690 gl::GlType::Gl if supports_texture_storage && supports_texture_swizzle => (
1692 TextureFormatPair::from(ImageFormat::RGBA8),
1693 TextureFormatPair { internal: gl::RGBA8, external: gl::RGBA },
1694 gl::UNSIGNED_BYTE,
1695 Swizzle::Bgra, TexStorageUsage::Always
1697 ),
1698 gl::GlType::Gl => (
1700 TextureFormatPair { internal: ImageFormat::BGRA8, external: ImageFormat::BGRA8 },
1701 TextureFormatPair { internal: gl::RGBA, external: gl::BGRA },
1702 gl::UNSIGNED_INT_8_8_8_8_REV,
1703 Swizzle::Rgba, TexStorageUsage::Never
1705 ),
1706 gl::GlType::Gles if supports_texture_storage_with_gles_bgra => (
1710 TextureFormatPair::from(ImageFormat::BGRA8),
1711 TextureFormatPair { internal: gl::BGRA8_EXT, external: gl::BGRA_EXT },
1712 gl::UNSIGNED_BYTE,
1713 Swizzle::Rgba, TexStorageUsage::Always,
1715 ),
1716 gl::GlType::Gles if supports_texture_swizzle => (
1720 TextureFormatPair::from(ImageFormat::RGBA8),
1721 TextureFormatPair { internal: gl::RGBA8, external: gl::RGBA },
1722 gl::UNSIGNED_BYTE,
1723 Swizzle::Bgra, TexStorageUsage::Always,
1725 ),
1726 gl::GlType::Gles if supports_gles_bgra && !avoid_tex_image => (
1730 TextureFormatPair::from(ImageFormat::BGRA8),
1731 TextureFormatPair::from(gl::BGRA_EXT),
1732 gl::UNSIGNED_BYTE,
1733 Swizzle::Rgba, TexStorageUsage::NonBGRA8,
1735 ),
1736 gl::GlType::Gles => {
1740 warn!("Neither BGRA or texture swizzling are supported. Images may be rendered incorrectly.");
1741 (
1742 TextureFormatPair::from(ImageFormat::RGBA8),
1743 TextureFormatPair { internal: gl::RGBA8, external: gl::RGBA },
1744 gl::UNSIGNED_BYTE,
1745 Swizzle::Rgba,
1746 TexStorageUsage::Always,
1747 )
1748 }
1749 };
1750
1751 let is_software_webrender = renderer_name.starts_with("Software WebRender");
1752 let upload_method = if is_software_webrender {
1753 UploadMethod::Immediate
1755 } else {
1756 upload_method
1757 };
1758 let depth_format = gl::DEPTH_COMPONENT24;
1760
1761 info!("GL texture cache {:?}, bgra {:?} swizzle {:?}, texture storage {:?}, depth {:?}",
1762 color_formats, bgra_formats, bgra8_sampling_swizzle, texture_storage_usage, depth_format);
1763
1764 let supports_copy_image_sub_data = if renderer_name.starts_with("Mali") {
1770 false
1771 } else {
1772 supports_extension(&extensions, "GL_EXT_copy_image") ||
1773 supports_extension(&extensions, "GL_ARB_copy_image")
1774 };
1775
1776 let is_x86_powervr_rogue_g6430 = renderer_name.starts_with("PowerVR Rogue G6430")
1780 && cfg!(target_arch = "x86");
1781 let supports_color_buffer_float = match gl.get_type() {
1782 gl::GlType::Gl => true,
1783 gl::GlType::Gles if is_x86_powervr_rogue_g6430 => false,
1784 gl::GlType::Gles => supports_extension(&extensions, "GL_EXT_color_buffer_float"),
1785 };
1786
1787 let is_adreno = renderer_name.starts_with("Adreno");
1788
1789 let supports_buffer_storage = if is_adreno {
1794 false
1795 } else {
1796 supports_extension(&extensions, "GL_EXT_buffer_storage") ||
1797 supports_extension(&extensions, "GL_ARB_buffer_storage")
1798 };
1799
1800 let supports_advanced_blend_equation =
1804 supports_extension(&extensions, "GL_KHR_blend_equation_advanced") &&
1805 !is_adreno;
1806
1807 let supports_dual_source_blending = match gl.get_type() {
1808 gl::GlType::Gl => supports_extension(&extensions,"GL_ARB_blend_func_extended") &&
1809 supports_extension(&extensions,"GL_ARB_explicit_attrib_location"),
1810 gl::GlType::Gles => supports_extension(&extensions,"GL_EXT_blend_func_extended"),
1811 };
1812
1813 let use_optimized_shaders = use_optimized_shaders && !is_software_webrender;
1815
1816 let requires_null_terminated_shader_source = is_emulator || renderer_name == "Mali-T628"
1823 || renderer_name == "Mali-T720" || renderer_name == "Mali-T760"
1824 || renderer_name == "Mali-G57" || renderer_name == "Adreno (TM) 750";
1825
1826 let requires_texture_external_unbind = is_emulator;
1829
1830 let is_macos = cfg!(target_os = "macos");
1831 let is_windows_angle = cfg!(target_os = "windows")
1835 && renderer_name.starts_with("ANGLE");
1836 let is_adreno_3xx = renderer_name.starts_with("Adreno (TM) 3");
1837
1838 let required_pbo_stride = if is_adreno_3xx {
1842 StrideAlignment::Bytes(NonZeroUsize::new(128).unwrap())
1845 } else if is_adreno {
1846 StrideAlignment::Pixels(NonZeroUsize::new(64).unwrap())
1850 } else if is_macos {
1851 StrideAlignment::Bytes(NonZeroUsize::new(256).unwrap())
1854 } else if is_windows_angle {
1855 StrideAlignment::Bytes(NonZeroUsize::new(1).unwrap())
1858 } else {
1859 StrideAlignment::Bytes(NonZeroUsize::new(4).unwrap())
1862 };
1863
1864 let supports_nonzero_pbo_offsets = !is_macos;
1867
1868 let supports_render_target_partial_update = !is_mali_midgard(&renderer_name)
1874 && !is_mali_bifrost(&renderer_name)
1875 && !renderer_name.starts_with("PowerVR D-Series");
1876
1877 let supports_shader_storage_object = match gl.get_type() {
1878 gl::GlType::Gl => supports_extension(&extensions, "GL_ARB_shader_storage_buffer_object"),
1880 gl::GlType::Gles => gl_version >= [3, 1],
1881 };
1882
1883 let uses_native_clip_mask = is_software_webrender;
1888
1889 let uses_native_antialiasing = is_software_webrender;
1892
1893 let mut android_mesa_version = None;
1895 if cfg!(target_os = "android") && renderer_name.starts_with("Mesa") {
1896 if let Some((_, mesa_version)) = version_string.split_once("Mesa ") {
1897 if let Some((major_str, _)) = mesa_version.split_once(".") {
1898 if let Ok(major) = major_str.parse::<i32>() {
1899 android_mesa_version = Some(major);
1900 }
1901 }
1902 }
1903 }
1904
1905 let supports_image_external_essl3 = match android_mesa_version {
1911 Some(major) if major < 20 => false,
1912 _ => supports_extension(&extensions, "GL_OES_EGL_image_external_essl3"),
1913 };
1914
1915 let mut requires_batched_texture_uploads = None;
1916 if is_software_webrender {
1917 requires_batched_texture_uploads = Some(false);
1919 } else if renderer_name.starts_with("Mali-G") {
1920 requires_batched_texture_uploads = Some(true);
1923 }
1924
1925 let is_adreno_510 = renderer_name.starts_with("Adreno (TM) 510");
1931 let supports_alpha_target_clears = !is_mali_midgard(&renderer_name) && !is_adreno_510;
1932
1933 let is_adreno_4xx = renderer_name.starts_with("Adreno (TM) 4");
1936 let requires_alpha_target_full_clear = is_adreno_4xx;
1937
1938 let prefers_clear_scissor = !cfg!(target_os = "android") || is_software_webrender;
1944
1945 let mut supports_render_target_invalidate = true;
1946
1947 let is_powervr_rogue = renderer_name.starts_with("PowerVR Rogue");
1951 if is_powervr_rogue {
1952 supports_render_target_invalidate = false;
1953 }
1954
1955 if is_mali_valhall(&renderer_name) {
1959 match parse_mali_version(&version_string) {
1960 Some(version) if version >= (1, 36, 0) => supports_render_target_invalidate = false,
1961 _ => {}
1962 }
1963 }
1964
1965 let supports_r8_texture_upload = if cfg!(target_os = "linux")
1969 && renderer_name.starts_with("AMD Radeon RX")
1970 {
1971 false
1972 } else {
1973 true
1974 };
1975
1976 let supports_qcom_tiled_rendering = if is_adreno && version_string.contains("V@0490") {
1977 false
1980 } else if renderer_name == "Adreno (TM) 308" {
1981 false
1985 } else {
1986 supports_extension(&extensions, "GL_QCOM_tiled_rendering")
1987 };
1988
1989 let requires_vao_rebind_after_orphaning = is_adreno_3xx;
1992
1993 Device {
1994 gl,
1995 base_gl: None,
1996 crash_annotator,
1997 annotate_draw_call_crashes: false,
1998 resource_override_path,
1999 use_optimized_shaders,
2000 upload_method,
2001 use_batched_texture_uploads: requires_batched_texture_uploads.unwrap_or(false),
2002 use_draw_calls_for_texture_copy: false,
2003 batched_upload_threshold,
2004
2005 inside_frame: false,
2006
2007 capabilities: Capabilities {
2008 supports_multisampling: false, supports_copy_image_sub_data,
2010 supports_color_buffer_float,
2011 supports_buffer_storage,
2012 supports_advanced_blend_equation,
2013 supports_dual_source_blending,
2014 supports_khr_debug,
2015 supports_texture_swizzle,
2016 supports_nonzero_pbo_offsets,
2017 supports_texture_usage,
2018 supports_render_target_partial_update,
2019 supports_shader_storage_object,
2020 requires_batched_texture_uploads,
2021 supports_alpha_target_clears,
2022 requires_alpha_target_full_clear,
2023 prefers_clear_scissor,
2024 supports_render_target_invalidate,
2025 supports_r8_texture_upload,
2026 supports_qcom_tiled_rendering,
2027 uses_native_clip_mask,
2028 uses_native_antialiasing,
2029 supports_image_external_essl3,
2030 requires_vao_rebind_after_orphaning,
2031 renderer_name,
2032 },
2033
2034 color_formats,
2035 bgra_formats,
2036 bgra_pixel_type,
2037 swizzle_settings: SwizzleSettings {
2038 bgra8_sampling_swizzle,
2039 },
2040 depth_format,
2041
2042 depth_targets: FastHashMap::default(),
2043
2044 bound_textures: [0; 16],
2045 bound_program: 0,
2046 bound_program_name: Rc::new(std::ffi::CString::new("").unwrap()),
2047 bound_vao: 0,
2048 bound_read_fbo: (FBOId(0), DeviceIntPoint::zero()),
2049 bound_draw_fbo: FBOId(0),
2050 default_read_fbo: FBOId(0),
2051 default_draw_fbo: FBOId(0),
2052
2053 depth_available: true,
2054
2055 max_texture_size,
2056 cached_programs,
2057 frame_id: GpuFrameId(0),
2058 extensions,
2059 texture_storage_usage,
2060 requires_null_terminated_shader_source,
2061 requires_texture_external_unbind,
2062 is_software_webrender,
2063 required_pbo_stride,
2064 dump_shader_source,
2065 surface_origin_is_top_left,
2066
2067 #[cfg(debug_assertions)]
2068 shader_is_ready: false,
2069
2070 textures_created: 0,
2071 textures_deleted: 0,
2072 }
2073 }
2074
2075 pub fn gl(&self) -> &dyn gl::Gl {
2076 &*self.gl
2077 }
2078
2079 pub fn rc_gl(&self) -> &Rc<dyn gl::Gl> {
2080 &self.gl
2081 }
2082
2083 pub fn set_parameter(&mut self, param: &Parameter) {
2084 match param {
2085 Parameter::Bool(BoolParameter::PboUploads, enabled) => {
2086 if !self.is_software_webrender {
2087 self.upload_method = if *enabled {
2088 UploadMethod::PixelBuffer(crate::ONE_TIME_USAGE_HINT)
2089 } else {
2090 UploadMethod::Immediate
2091 };
2092 }
2093 }
2094 Parameter::Bool(BoolParameter::BatchedUploads, enabled) => {
2095 if self.capabilities.requires_batched_texture_uploads.is_none() {
2096 self.use_batched_texture_uploads = *enabled;
2097 }
2098 }
2099 Parameter::Bool(BoolParameter::DrawCallsForTextureCopy, enabled) => {
2100 self.use_draw_calls_for_texture_copy = *enabled;
2101 }
2102 Parameter::Int(IntParameter::BatchedUploadThreshold, threshold) => {
2103 self.batched_upload_threshold = *threshold;
2104 }
2105 _ => {}
2106 }
2107 }
2108
2109 pub fn clamp_max_texture_size(&mut self, size: i32) {
2113 self.max_texture_size = self.max_texture_size.min(size);
2114 }
2115
2116 pub fn max_texture_size(&self) -> i32 {
2118 self.max_texture_size
2119 }
2120
2121 pub fn surface_origin_is_top_left(&self) -> bool {
2122 self.surface_origin_is_top_left
2123 }
2124
2125 pub fn get_capabilities(&self) -> &Capabilities {
2126 &self.capabilities
2127 }
2128
2129 pub fn preferred_color_formats(&self) -> TextureFormatPair<ImageFormat> {
2130 self.color_formats.clone()
2131 }
2132
2133 pub fn swizzle_settings(&self) -> Option<SwizzleSettings> {
2134 if self.capabilities.supports_texture_swizzle {
2135 Some(self.swizzle_settings)
2136 } else {
2137 None
2138 }
2139 }
2140
2141 pub fn depth_bits(&self) -> i32 {
2142 match self.depth_format {
2143 gl::DEPTH_COMPONENT16 => 16,
2144 gl::DEPTH_COMPONENT24 => 24,
2145 _ => panic!("Unknown depth format {:?}", self.depth_format),
2146 }
2147 }
2148
2149 pub fn max_depth_ids(&self) -> i32 {
2152 return 1 << (self.depth_bits() - RESERVE_DEPTH_BITS);
2153 }
2154
2155 pub fn ortho_near_plane(&self) -> f32 {
2156 return -self.max_depth_ids() as f32;
2157 }
2158
2159 pub fn ortho_far_plane(&self) -> f32 {
2160 return (self.max_depth_ids() - 1) as f32;
2161 }
2162
2163 pub fn required_pbo_stride(&self) -> StrideAlignment {
2164 self.required_pbo_stride
2165 }
2166
2167 pub fn upload_method(&self) -> &UploadMethod {
2168 &self.upload_method
2169 }
2170
2171 pub fn use_batched_texture_uploads(&self) -> bool {
2172 self.use_batched_texture_uploads
2173 }
2174
2175 pub fn use_draw_calls_for_texture_copy(&self) -> bool {
2176 self.use_draw_calls_for_texture_copy
2177 }
2178
2179 pub fn batched_upload_threshold(&self) -> i32 {
2180 self.batched_upload_threshold
2181 }
2182
2183 pub fn reset_state(&mut self) {
2184 for i in 0 .. self.bound_textures.len() {
2185 self.bound_textures[i] = 0;
2186 self.gl.active_texture(gl::TEXTURE0 + i as gl::GLuint);
2187 self.gl.bind_texture(gl::TEXTURE_2D, 0);
2188 }
2189
2190 self.bound_vao = 0;
2191 self.gl.bind_vertex_array(0);
2192
2193 self.bound_read_fbo = (self.default_read_fbo, DeviceIntPoint::zero());
2194 self.gl.bind_framebuffer(gl::READ_FRAMEBUFFER, self.default_read_fbo.0);
2195
2196 self.bound_draw_fbo = self.default_draw_fbo;
2197 self.gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.bound_draw_fbo.0);
2198 }
2199
2200 #[cfg(debug_assertions)]
2201 fn print_shader_errors(source: &str, log: &str) {
2202 if !log.starts_with("0:") && !log.starts_with("0(") {
2204 return;
2205 }
2206 let end_pos = match log[2..].chars().position(|c| !c.is_digit(10)) {
2207 Some(pos) => 2 + pos,
2208 None => return,
2209 };
2210 let base_line_number = match log[2 .. end_pos].parse::<usize>() {
2211 Ok(number) if number >= 2 => number - 2,
2212 _ => return,
2213 };
2214 for (line, prefix) in source.lines().skip(base_line_number).zip(&["|",">","|"]) {
2215 error!("{}\t{}", prefix, line);
2216 }
2217 }
2218
2219 pub fn compile_shader(
2220 &self,
2221 name: &str,
2222 shader_type: gl::GLenum,
2223 source: &String,
2224 ) -> Result<gl::GLuint, ShaderError> {
2225 debug!("compile {}", name);
2226 let id = self.gl.create_shader(shader_type);
2227
2228 let mut new_source = Cow::from(source.as_str());
2229 if self.requires_null_terminated_shader_source {
2232 new_source.to_mut().push('\0');
2233 }
2234
2235 self.gl.shader_source(id, &[new_source.as_bytes()]);
2236 self.gl.compile_shader(id);
2237 let log = self.gl.get_shader_info_log(id);
2238 let mut status = [0];
2239 unsafe {
2240 self.gl.get_shader_iv(id, gl::COMPILE_STATUS, &mut status);
2241 }
2242 if status[0] == 0 {
2243 let type_str = match shader_type {
2244 gl::VERTEX_SHADER => "vertex",
2245 gl::FRAGMENT_SHADER => "fragment",
2246 _ => panic!("Unexpected shader type {:x}", shader_type),
2247 };
2248 error!("Failed to compile {} shader: {}\n{}", type_str, name, log);
2249 #[cfg(debug_assertions)]
2250 Self::print_shader_errors(source, &log);
2251 Err(ShaderError::Compilation(name.to_string(), log))
2252 } else {
2253 if !log.is_empty() {
2254 warn!("Warnings detected on shader: {}\n{}", name, log);
2255 }
2256 Ok(id)
2257 }
2258 }
2259
2260 pub fn begin_frame(&mut self) -> GpuFrameId {
2261 debug_assert!(!self.inside_frame);
2262 self.inside_frame = true;
2263 #[cfg(debug_assertions)]
2264 {
2265 self.shader_is_ready = false;
2266 }
2267
2268 self.textures_created = 0;
2269 self.textures_deleted = 0;
2270
2271 let being_profiled = profiler::thread_is_being_profiled();
2274 let using_wrapper = self.base_gl.is_some();
2275
2276 if cfg!(any(target_arch = "arm", target_arch = "aarch64"))
2281 && cfg!(target_os = "android")
2282 && being_profiled
2283 && !using_wrapper
2284 {
2285 fn note(name: &str, duration: Duration) {
2286 profiler::add_text_marker("OpenGL Calls", name, duration);
2287 }
2288 let threshold = Duration::from_millis(1);
2289 let wrapped = gl::ProfilingGl::wrap(self.gl.clone(), threshold, note);
2290 let base = mem::replace(&mut self.gl, wrapped);
2291 self.base_gl = Some(base);
2292 } else if !being_profiled && using_wrapper {
2293 self.gl = self.base_gl.take().unwrap();
2294 }
2295
2296 let mut default_read_fbo = [0];
2298 unsafe {
2299 self.gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING, &mut default_read_fbo);
2300 }
2301 self.default_read_fbo = FBOId(default_read_fbo[0] as gl::GLuint);
2302 let mut default_draw_fbo = [0];
2303 unsafe {
2304 self.gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING, &mut default_draw_fbo);
2305 }
2306 self.default_draw_fbo = FBOId(default_draw_fbo[0] as gl::GLuint);
2307
2308 self.bound_program = 0;
2310 self.gl.use_program(0);
2311
2312 self.reset_state();
2314
2315 self.gl.pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
2317 self.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
2318
2319 self.gl.active_texture(gl::TEXTURE0);
2321
2322 self.frame_id
2323 }
2324
2325 fn bind_texture_impl(
2326 &mut self,
2327 slot: TextureSlot,
2328 id: gl::GLuint,
2329 target: gl::GLenum,
2330 set_swizzle: Option<Swizzle>,
2331 image_rendering: Option<ImageRendering>,
2332 ) {
2333 debug_assert!(self.inside_frame);
2334
2335 if self.bound_textures[slot.0] != id || set_swizzle.is_some() || image_rendering.is_some() {
2336 self.gl.active_texture(gl::TEXTURE0 + slot.0 as gl::GLuint);
2337 if target == gl::TEXTURE_2D && self.requires_texture_external_unbind {
2340 self.gl.bind_texture(gl::TEXTURE_EXTERNAL_OES, 0);
2341 }
2342 self.gl.bind_texture(target, id);
2343 if let Some(swizzle) = set_swizzle {
2344 if self.capabilities.supports_texture_swizzle {
2345 let components = match swizzle {
2346 Swizzle::Rgba => [gl::RED, gl::GREEN, gl::BLUE, gl::ALPHA],
2347 Swizzle::Bgra => [gl::BLUE, gl::GREEN, gl::RED, gl::ALPHA],
2348 };
2349 self.gl.tex_parameter_i(target, gl::TEXTURE_SWIZZLE_R, components[0] as i32);
2350 self.gl.tex_parameter_i(target, gl::TEXTURE_SWIZZLE_G, components[1] as i32);
2351 self.gl.tex_parameter_i(target, gl::TEXTURE_SWIZZLE_B, components[2] as i32);
2352 self.gl.tex_parameter_i(target, gl::TEXTURE_SWIZZLE_A, components[3] as i32);
2353 } else {
2354 debug_assert_eq!(swizzle, Swizzle::default());
2355 }
2356 }
2357 if let Some(image_rendering) = image_rendering {
2358 let filter = match image_rendering {
2359 ImageRendering::Auto | ImageRendering::CrispEdges => gl::LINEAR,
2360 ImageRendering::Pixelated => gl::NEAREST,
2361 };
2362 self.gl.tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, filter as i32);
2363 self.gl.tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, filter as i32);
2364 }
2365 self.gl.active_texture(gl::TEXTURE0);
2366 self.bound_textures[slot.0] = id;
2367 }
2368 }
2369
2370 pub fn bind_texture<S>(&mut self, slot: S, texture: &Texture, swizzle: Swizzle)
2371 where
2372 S: Into<TextureSlot>,
2373 {
2374 let old_swizzle = texture.active_swizzle.replace(swizzle);
2375 let set_swizzle = if old_swizzle != swizzle {
2376 Some(swizzle)
2377 } else {
2378 None
2379 };
2380 self.bind_texture_impl(slot.into(), texture.id, texture.target, set_swizzle, None);
2381 }
2382
2383 pub fn bind_external_texture<S>(&mut self, slot: S, external_texture: &ExternalTexture)
2384 where
2385 S: Into<TextureSlot>,
2386 {
2387 self.bind_texture_impl(
2388 slot.into(),
2389 external_texture.id,
2390 external_texture.target,
2391 None,
2392 Some(external_texture.image_rendering),
2393 );
2394 }
2395
2396 pub fn bind_read_target_impl(
2397 &mut self,
2398 fbo_id: FBOId,
2399 offset: DeviceIntPoint,
2400 ) {
2401 debug_assert!(self.inside_frame);
2402
2403 if self.bound_read_fbo != (fbo_id, offset) {
2404 fbo_id.bind(self.gl(), FBOTarget::Read);
2405 }
2406
2407 self.bound_read_fbo = (fbo_id, offset);
2408 }
2409
2410 pub fn bind_read_target(&mut self, target: ReadTarget) {
2411 let fbo_id = match target {
2412 ReadTarget::Default => self.default_read_fbo,
2413 ReadTarget::Texture { fbo_id } => fbo_id,
2414 ReadTarget::External { fbo } => fbo,
2415 ReadTarget::NativeSurface { fbo_id, .. } => fbo_id,
2416 };
2417
2418 self.bind_read_target_impl(fbo_id, target.offset())
2419 }
2420
2421 fn bind_draw_target_impl(&mut self, fbo_id: FBOId) {
2422 debug_assert!(self.inside_frame);
2423
2424 if self.bound_draw_fbo != fbo_id {
2425 self.bound_draw_fbo = fbo_id;
2426 fbo_id.bind(self.gl(), FBOTarget::Draw);
2427 }
2428 }
2429
2430 pub fn reset_read_target(&mut self) {
2431 let fbo = self.default_read_fbo;
2432 self.bind_read_target_impl(fbo, DeviceIntPoint::zero());
2433 }
2434
2435
2436 pub fn reset_draw_target(&mut self) {
2437 let fbo = self.default_draw_fbo;
2438 self.bind_draw_target_impl(fbo);
2439 self.depth_available = true;
2440 }
2441
2442 pub fn bind_draw_target(
2443 &mut self,
2444 target: DrawTarget,
2445 ) {
2446 let (fbo_id, rect, depth_available) = match target {
2447 DrawTarget::Default { rect, .. } => {
2448 (self.default_draw_fbo, rect, false)
2449 }
2450 DrawTarget::Texture { dimensions, fbo_id, with_depth, .. } => {
2451 let rect = FramebufferIntRect::from_size(
2452 device_size_as_framebuffer_size(dimensions),
2453 );
2454 (fbo_id, rect, with_depth)
2455 },
2456 DrawTarget::External { fbo, size } => {
2457 (fbo, size.into(), false)
2458 }
2459 DrawTarget::NativeSurface { external_fbo_id, offset, dimensions, .. } => {
2460 (
2461 FBOId(external_fbo_id),
2462 device_rect_as_framebuffer_rect(&DeviceIntRect::from_origin_and_size(offset, dimensions)),
2463 true
2464 )
2465 }
2466 };
2467
2468 self.depth_available = depth_available;
2469 self.bind_draw_target_impl(fbo_id);
2470 self.gl.viewport(
2471 rect.min.x,
2472 rect.min.y,
2473 rect.width(),
2474 rect.height(),
2475 );
2476 }
2477
2478 pub fn create_fbo(&mut self) -> FBOId {
2481 FBOId(self.gl.gen_framebuffers(1)[0])
2482 }
2483
2484 pub fn create_fbo_for_external_texture(&mut self, texture_id: u32) -> FBOId {
2486 let fbo = self.create_fbo();
2487 fbo.bind(self.gl(), FBOTarget::Draw);
2488 self.gl.framebuffer_texture_2d(
2489 gl::DRAW_FRAMEBUFFER,
2490 gl::COLOR_ATTACHMENT0,
2491 gl::TEXTURE_2D,
2492 texture_id,
2493 0,
2494 );
2495 debug_assert_eq!(
2496 self.gl.check_frame_buffer_status(gl::DRAW_FRAMEBUFFER),
2497 gl::FRAMEBUFFER_COMPLETE,
2498 "Incomplete framebuffer",
2499 );
2500 self.bound_draw_fbo.bind(self.gl(), FBOTarget::Draw);
2501 fbo
2502 }
2503
2504 pub fn delete_fbo(&mut self, fbo: FBOId) {
2505 self.gl.delete_framebuffers(&[fbo.0]);
2506 }
2507
2508 pub fn bind_external_draw_target(&mut self, fbo_id: FBOId) {
2509 debug_assert!(self.inside_frame);
2510
2511 if self.bound_draw_fbo != fbo_id {
2512 self.bound_draw_fbo = fbo_id;
2513 fbo_id.bind(self.gl(), FBOTarget::Draw);
2514 }
2515 }
2516
2517 pub fn link_program(
2529 &mut self,
2530 program: &mut Program,
2531 descriptor: &VertexDescriptor,
2532 ) -> Result<(), ShaderError> {
2533 profile_scope!("compile shader");
2534
2535 let _guard = CrashAnnotatorGuard::new(
2536 &self.crash_annotator,
2537 CrashAnnotation::CompileShader,
2538 &program.source_info.full_name_cstr
2539 );
2540
2541 assert!(!program.is_initialized());
2542 let mut build_program = true;
2543 let info = &program.source_info;
2544
2545 if let Some(ref cached_programs) = self.cached_programs {
2547 if cached_programs.entries.borrow().get(&program.source_info.digest).is_none() {
2549 if let Some(ref handler) = cached_programs.program_cache_handler {
2550 handler.try_load_shader_from_disk(&program.source_info.digest, cached_programs);
2551 if let Some(entry) = cached_programs.entries.borrow().get(&program.source_info.digest) {
2552 self.gl.program_binary(program.id, entry.binary.format, &entry.binary.bytes);
2553 }
2554 }
2555 }
2556
2557 if let Some(entry) = cached_programs.entries.borrow_mut().get_mut(&info.digest) {
2558 let mut link_status = [0];
2559 unsafe {
2560 self.gl.get_program_iv(program.id, gl::LINK_STATUS, &mut link_status);
2561 }
2562 if link_status[0] == 0 {
2563 let error_log = self.gl.get_program_info_log(program.id);
2564 error!(
2565 "Failed to load a program object with a program binary: {} renderer {}\n{}",
2566 &info.base_filename,
2567 self.capabilities.renderer_name,
2568 error_log
2569 );
2570 if let Some(ref program_cache_handler) = cached_programs.program_cache_handler {
2571 program_cache_handler.notify_program_binary_failed(&entry.binary);
2572 }
2573 } else {
2574 entry.linked = true;
2575 build_program = false;
2576 }
2577 }
2578 }
2579
2580 if build_program {
2582 let vs_source = info.compute_source(self, ShaderKind::Vertex);
2584 let vs_id = match self.compile_shader(&info.full_name(), gl::VERTEX_SHADER, &vs_source) {
2585 Ok(vs_id) => vs_id,
2586 Err(err) => return Err(err),
2587 };
2588
2589 let fs_source = info.compute_source(self, ShaderKind::Fragment);
2591 let fs_id =
2592 match self.compile_shader(&info.full_name(), gl::FRAGMENT_SHADER, &fs_source) {
2593 Ok(fs_id) => fs_id,
2594 Err(err) => {
2595 self.gl.delete_shader(vs_id);
2596 return Err(err);
2597 }
2598 };
2599
2600 if Some(info.base_filename) == self.dump_shader_source.as_ref().map(String::as_ref) {
2602 let path = std::path::Path::new(info.base_filename);
2603 std::fs::write(path.with_extension("vert"), vs_source).unwrap();
2604 std::fs::write(path.with_extension("frag"), fs_source).unwrap();
2605 }
2606
2607 self.gl.attach_shader(program.id, vs_id);
2609 self.gl.attach_shader(program.id, fs_id);
2610
2611 for (i, attr) in descriptor
2613 .vertex_attributes
2614 .iter()
2615 .chain(descriptor.instance_attributes.iter())
2616 .enumerate()
2617 {
2618 self.gl
2619 .bind_attrib_location(program.id, i as gl::GLuint, attr.name);
2620 }
2621
2622 if self.cached_programs.is_some() {
2623 self.gl.program_parameter_i(program.id, gl::PROGRAM_BINARY_RETRIEVABLE_HINT, gl::TRUE as gl::GLint);
2624 }
2625
2626 self.gl.link_program(program.id);
2628
2629 self.gl.detach_shader(program.id, vs_id);
2633 self.gl.detach_shader(program.id, fs_id);
2634 self.gl.delete_shader(vs_id);
2635 self.gl.delete_shader(fs_id);
2636
2637 let mut link_status = [0];
2638 unsafe {
2639 self.gl.get_program_iv(program.id, gl::LINK_STATUS, &mut link_status);
2640 }
2641 if link_status[0] == 0 {
2642 let error_log = self.gl.get_program_info_log(program.id);
2643 error!(
2644 "Failed to link shader program: {}\n{}",
2645 &info.base_filename,
2646 error_log
2647 );
2648 self.gl.delete_program(program.id);
2649 return Err(ShaderError::Link(info.base_filename.to_owned(), error_log));
2650 }
2651
2652 if let Some(ref cached_programs) = self.cached_programs {
2653 if !cached_programs.entries.borrow().contains_key(&info.digest) {
2654 let (buffer, format) = self.gl.get_program_binary(program.id);
2655 if buffer.len() > 0 {
2656 let binary = Arc::new(ProgramBinary::new(buffer, format, info.digest.clone()));
2657 cached_programs.add_new_program_binary(binary);
2658 }
2659 }
2660 }
2661 }
2662
2663 program.is_initialized = true;
2665 program.u_transform = self.gl.get_uniform_location(program.id, "uTransform");
2666 program.u_texture_size = self.gl.get_uniform_location(program.id, "uTextureSize");
2667
2668 Ok(())
2669 }
2670
2671 pub fn bind_program(&mut self, program: &Program) -> bool {
2672 debug_assert!(self.inside_frame);
2673 debug_assert!(program.is_initialized());
2674 if !program.is_initialized() {
2675 return false;
2676 }
2677 #[cfg(debug_assertions)]
2678 {
2679 self.shader_is_ready = true;
2680 }
2681
2682 if self.bound_program != program.id {
2683 self.gl.use_program(program.id);
2684 self.bound_program = program.id;
2685 self.bound_program_name = program.source_info.full_name_cstr.clone();
2686 }
2687 true
2688 }
2689
2690 pub fn create_texture(
2691 &mut self,
2692 target: ImageBufferKind,
2693 format: ImageFormat,
2694 mut width: i32,
2695 mut height: i32,
2696 filter: TextureFilter,
2697 render_target: Option<RenderTargetInfo>,
2698 ) -> Texture {
2699 debug_assert!(self.inside_frame);
2700
2701 if width > self.max_texture_size || height > self.max_texture_size {
2702 error!("Attempting to allocate a texture of size {}x{} above the limit, trimming", width, height);
2703 width = width.min(self.max_texture_size);
2704 height = height.min(self.max_texture_size);
2705 }
2706
2707 let mut texture = Texture {
2709 id: self.gl.gen_textures(1)[0],
2710 target: get_gl_target(target),
2711 size: DeviceIntSize::new(width, height),
2712 format,
2713 filter,
2714 active_swizzle: Cell::default(),
2715 fbo: None,
2716 fbo_with_depth: None,
2717 last_frame_used: self.frame_id,
2718 flags: TextureFlags::default(),
2719 };
2720 self.bind_texture(DEFAULT_TEXTURE, &texture, Swizzle::default());
2721 self.set_texture_parameters(texture.target, filter);
2722
2723 if self.capabilities.supports_texture_usage && render_target.is_some() {
2724 self.gl.tex_parameter_i(texture.target, gl::TEXTURE_USAGE_ANGLE, gl::FRAMEBUFFER_ATTACHMENT_ANGLE as gl::GLint);
2725 }
2726
2727 let desc = self.gl_describe_format(texture.format);
2729
2730 let mipmap_levels = if texture.filter == TextureFilter::Trilinear {
2734 let max_dimension = cmp::max(width, height);
2735 ((max_dimension) as f64).log2() as gl::GLint + 1
2736 } else {
2737 1
2738 };
2739
2740 self.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
2742
2743 let use_texture_storage = match self.texture_storage_usage {
2747 TexStorageUsage::Always => true,
2748 TexStorageUsage::NonBGRA8 => texture.format != ImageFormat::BGRA8,
2749 TexStorageUsage::Never => false,
2750 };
2751 if use_texture_storage {
2752 self.gl.tex_storage_2d(
2753 texture.target,
2754 mipmap_levels,
2755 desc.internal,
2756 texture.size.width as gl::GLint,
2757 texture.size.height as gl::GLint,
2758 );
2759 } else {
2760 self.gl.tex_image_2d(
2761 texture.target,
2762 0,
2763 desc.internal as gl::GLint,
2764 texture.size.width as gl::GLint,
2765 texture.size.height as gl::GLint,
2766 0,
2767 desc.external,
2768 desc.pixel_type,
2769 None,
2770 );
2771 }
2772
2773 if let Some(rt_info) = render_target {
2775 self.init_fbos(&mut texture, false);
2776 if rt_info.has_depth {
2777 self.init_fbos(&mut texture, true);
2778 }
2779 }
2780
2781 self.textures_created += 1;
2782
2783 texture
2784 }
2785
2786 fn set_texture_parameters(&mut self, target: gl::GLuint, filter: TextureFilter) {
2787 let mag_filter = match filter {
2788 TextureFilter::Nearest => gl::NEAREST,
2789 TextureFilter::Linear | TextureFilter::Trilinear => gl::LINEAR,
2790 };
2791
2792 let min_filter = match filter {
2793 TextureFilter::Nearest => gl::NEAREST,
2794 TextureFilter::Linear => gl::LINEAR,
2795 TextureFilter::Trilinear => gl::LINEAR_MIPMAP_LINEAR,
2796 };
2797
2798 self.gl
2799 .tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, mag_filter as gl::GLint);
2800 self.gl
2801 .tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, min_filter as gl::GLint);
2802
2803 self.gl
2804 .tex_parameter_i(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint);
2805 self.gl
2806 .tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
2807 }
2808
2809 pub fn copy_entire_texture(
2813 &mut self,
2814 dst: &mut Texture,
2815 src: &Texture,
2816 ) {
2817 debug_assert!(self.inside_frame);
2818 debug_assert!(dst.size.width >= src.size.width);
2819 debug_assert!(dst.size.height >= src.size.height);
2820
2821 self.copy_texture_sub_region(
2822 src,
2823 0,
2824 0,
2825 dst,
2826 0,
2827 0,
2828 src.size.width as _,
2829 src.size.height as _,
2830 );
2831 }
2832
2833 pub fn copy_texture_sub_region(
2835 &mut self,
2836 src_texture: &Texture,
2837 src_x: usize,
2838 src_y: usize,
2839 dest_texture: &Texture,
2840 dest_x: usize,
2841 dest_y: usize,
2842 width: usize,
2843 height: usize,
2844 ) {
2845 if self.capabilities.supports_copy_image_sub_data {
2846 assert_ne!(
2847 src_texture.id, dest_texture.id,
2848 "glCopyImageSubData's behaviour is undefined if src and dst images are identical and the rectangles overlap."
2849 );
2850 unsafe {
2851 self.gl.copy_image_sub_data(
2852 src_texture.id,
2853 src_texture.target,
2854 0,
2855 src_x as _,
2856 src_y as _,
2857 0,
2858 dest_texture.id,
2859 dest_texture.target,
2860 0,
2861 dest_x as _,
2862 dest_y as _,
2863 0,
2864 width as _,
2865 height as _,
2866 1,
2867 );
2868 }
2869 } else {
2870 let src_offset = FramebufferIntPoint::new(src_x as i32, src_y as i32);
2871 let dest_offset = FramebufferIntPoint::new(dest_x as i32, dest_y as i32);
2872 let size = FramebufferIntSize::new(width as i32, height as i32);
2873
2874 self.blit_render_target(
2875 ReadTarget::from_texture(src_texture),
2876 FramebufferIntRect::from_origin_and_size(src_offset, size),
2877 DrawTarget::from_texture(dest_texture, false),
2878 FramebufferIntRect::from_origin_and_size(dest_offset, size),
2879 TextureFilter::Nearest,
2883 );
2884 }
2885 }
2886
2887 pub fn invalidate_render_target(&mut self, texture: &Texture) {
2890 if self.capabilities.supports_render_target_invalidate {
2891 let (fbo, attachments) = if texture.supports_depth() {
2892 (&texture.fbo_with_depth,
2893 &[gl::COLOR_ATTACHMENT0, gl::DEPTH_ATTACHMENT] as &[gl::GLenum])
2894 } else {
2895 (&texture.fbo, &[gl::COLOR_ATTACHMENT0] as &[gl::GLenum])
2896 };
2897
2898 if let Some(fbo_id) = fbo {
2899 let original_bound_fbo = self.bound_draw_fbo;
2900 self.bind_external_draw_target(*fbo_id);
2904 self.gl.invalidate_framebuffer(gl::FRAMEBUFFER, attachments);
2905 self.bind_external_draw_target(original_bound_fbo);
2906 }
2907 }
2908 }
2909
2910 pub fn invalidate_depth_target(&mut self) {
2916 assert!(self.depth_available);
2917 let attachments = if self.bound_draw_fbo == self.default_draw_fbo {
2918 &[gl::DEPTH] as &[gl::GLenum]
2919 } else {
2920 &[gl::DEPTH_ATTACHMENT] as &[gl::GLenum]
2921 };
2922 self.gl.invalidate_framebuffer(gl::DRAW_FRAMEBUFFER, attachments);
2923 }
2924
2925 pub fn reuse_render_target<T: Texel>(
2929 &mut self,
2930 texture: &mut Texture,
2931 rt_info: RenderTargetInfo,
2932 ) {
2933 texture.last_frame_used = self.frame_id;
2934
2935 if rt_info.has_depth && !texture.supports_depth() {
2937 self.init_fbos(texture, true);
2938 }
2939 }
2940
2941 fn init_fbos(&mut self, texture: &mut Texture, with_depth: bool) {
2942 let (fbo, depth_rb) = if with_depth {
2943 let depth_target = self.acquire_depth_target(texture.get_dimensions());
2944 (&mut texture.fbo_with_depth, Some(depth_target))
2945 } else {
2946 (&mut texture.fbo, None)
2947 };
2948
2949 assert!(fbo.is_none());
2951 let fbo_id = FBOId(*self.gl.gen_framebuffers(1).first().unwrap());
2952 *fbo = Some(fbo_id);
2953
2954 let original_bound_fbo = self.bound_draw_fbo;
2956
2957 self.bind_external_draw_target(fbo_id);
2958
2959 self.gl.framebuffer_texture_2d(
2960 gl::DRAW_FRAMEBUFFER,
2961 gl::COLOR_ATTACHMENT0,
2962 texture.target,
2963 texture.id,
2964 0,
2965 );
2966
2967 if let Some(depth_rb) = depth_rb {
2968 self.gl.framebuffer_renderbuffer(
2969 gl::DRAW_FRAMEBUFFER,
2970 gl::DEPTH_ATTACHMENT,
2971 gl::RENDERBUFFER,
2972 depth_rb.0,
2973 );
2974 }
2975
2976 debug_assert_eq!(
2977 self.gl.check_frame_buffer_status(gl::DRAW_FRAMEBUFFER),
2978 gl::FRAMEBUFFER_COMPLETE,
2979 "Incomplete framebuffer",
2980 );
2981
2982 self.bind_external_draw_target(original_bound_fbo);
2983 }
2984
2985 fn acquire_depth_target(&mut self, dimensions: DeviceIntSize) -> RBOId {
2986 let gl = &self.gl;
2987 let depth_format = self.depth_format;
2988 let target = self.depth_targets.entry(dimensions).or_insert_with(|| {
2989 let renderbuffer_ids = gl.gen_renderbuffers(1);
2990 let depth_rb = renderbuffer_ids[0];
2991 gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
2992 gl.renderbuffer_storage(
2993 gl::RENDERBUFFER,
2994 depth_format,
2995 dimensions.width as _,
2996 dimensions.height as _,
2997 );
2998 SharedDepthTarget {
2999 rbo_id: RBOId(depth_rb),
3000 refcount: 0,
3001 }
3002 });
3003 target.refcount += 1;
3004 target.rbo_id
3005 }
3006
3007 fn release_depth_target(&mut self, dimensions: DeviceIntSize) {
3008 let mut entry = match self.depth_targets.entry(dimensions) {
3009 Entry::Occupied(x) => x,
3010 Entry::Vacant(..) => panic!("Releasing unknown depth target"),
3011 };
3012 debug_assert!(entry.get().refcount != 0);
3013 entry.get_mut().refcount -= 1;
3014 if entry.get().refcount == 0 {
3015 let (_, target) = entry.remove_entry();
3016 self.gl.delete_renderbuffers(&[target.rbo_id.0]);
3017 }
3018 }
3019
3020 fn blit_render_target_impl(
3022 &mut self,
3023 src_rect: FramebufferIntRect,
3024 dest_rect: FramebufferIntRect,
3025 filter: TextureFilter,
3026 ) {
3027 debug_assert!(self.inside_frame);
3028
3029 let filter = match filter {
3030 TextureFilter::Nearest => gl::NEAREST,
3031 TextureFilter::Linear | TextureFilter::Trilinear => gl::LINEAR,
3032 };
3033
3034 let src_x0 = src_rect.min.x + self.bound_read_fbo.1.x;
3035 let src_y0 = src_rect.min.y + self.bound_read_fbo.1.y;
3036
3037 self.gl.blit_framebuffer(
3038 src_x0,
3039 src_y0,
3040 src_x0 + src_rect.width(),
3041 src_y0 + src_rect.height(),
3042 dest_rect.min.x,
3043 dest_rect.min.y,
3044 dest_rect.max.x,
3045 dest_rect.max.y,
3046 gl::COLOR_BUFFER_BIT,
3047 filter,
3048 );
3049 }
3050
3051 pub fn blit_render_target(
3054 &mut self,
3055 src_target: ReadTarget,
3056 src_rect: FramebufferIntRect,
3057 dest_target: DrawTarget,
3058 dest_rect: FramebufferIntRect,
3059 filter: TextureFilter,
3060 ) {
3061 debug_assert!(self.inside_frame);
3062
3063 self.bind_read_target(src_target);
3064
3065 self.bind_draw_target(dest_target);
3066
3067 self.blit_render_target_impl(src_rect, dest_rect, filter);
3068 }
3069
3070 pub fn blit_render_target_invert_y(
3074 &mut self,
3075 src_target: ReadTarget,
3076 src_rect: FramebufferIntRect,
3077 dest_target: DrawTarget,
3078 dest_rect: FramebufferIntRect,
3079 ) {
3080 debug_assert!(self.inside_frame);
3081
3082 let mut inverted_dest_rect = dest_rect;
3083 inverted_dest_rect.min.y = dest_rect.max.y;
3084 inverted_dest_rect.max.y = dest_rect.min.y;
3085
3086 self.blit_render_target(
3087 src_target,
3088 src_rect,
3089 dest_target,
3090 inverted_dest_rect,
3091 TextureFilter::Linear,
3092 );
3093 }
3094
3095 pub fn delete_texture(&mut self, mut texture: Texture) {
3096 debug_assert!(self.inside_frame);
3097 let had_depth = texture.supports_depth();
3098 if let Some(fbo) = texture.fbo {
3099 self.gl.delete_framebuffers(&[fbo.0]);
3100 texture.fbo = None;
3101 }
3102 if let Some(fbo) = texture.fbo_with_depth {
3103 self.gl.delete_framebuffers(&[fbo.0]);
3104 texture.fbo_with_depth = None;
3105 }
3106
3107 if had_depth {
3108 self.release_depth_target(texture.get_dimensions());
3109 }
3110
3111 self.gl.delete_textures(&[texture.id]);
3112
3113 for bound_texture in &mut self.bound_textures {
3114 if *bound_texture == texture.id {
3115 *bound_texture = 0;
3116 }
3117 }
3118
3119 self.textures_deleted += 1;
3120
3121 texture.id = 0;
3123 }
3124
3125 #[cfg(feature = "replay")]
3126 pub fn delete_external_texture(&mut self, external: ExternalTexture) {
3127 self.gl.delete_textures(&[external.id]);
3128 }
3129
3130 pub fn delete_program(&mut self, mut program: Program) {
3131 self.gl.delete_program(program.id);
3132 program.id = 0;
3133 }
3134
3135 pub fn create_program_linked(
3137 &mut self,
3138 base_filename: &'static str,
3139 features: &[&'static str],
3140 descriptor: &VertexDescriptor,
3141 ) -> Result<Program, ShaderError> {
3142 let mut program = self.create_program(base_filename, features)?;
3143 self.link_program(&mut program, descriptor)?;
3144 Ok(program)
3145 }
3146
3147 pub fn create_program(
3153 &mut self,
3154 base_filename: &'static str,
3155 features: &[&'static str],
3156 ) -> Result<Program, ShaderError> {
3157 debug_assert!(self.inside_frame);
3158
3159 let source_info = ProgramSourceInfo::new(self, base_filename, features);
3160
3161 let pid = self.gl.create_program();
3163
3164 if let Some(ref cached_programs) = self.cached_programs {
3166 if let Some(entry) = cached_programs.entries.borrow().get(&source_info.digest) {
3167 self.gl.program_binary(pid, entry.binary.format, &entry.binary.bytes);
3168 }
3169 }
3170
3171 let program = Program {
3173 id: pid,
3174 u_transform: 0,
3175 u_texture_size: 0,
3176 source_info,
3177 is_initialized: false,
3178 };
3179
3180 Ok(program)
3181 }
3182
3183 fn build_shader_string<F: FnMut(&str)>(
3184 &self,
3185 features: &[&'static str],
3186 kind: ShaderKind,
3187 base_filename: &str,
3188 output: F,
3189 ) {
3190 do_build_shader_string(
3191 get_shader_version(&*self.gl),
3192 features,
3193 kind,
3194 base_filename,
3195 &|f| get_unoptimized_shader_source(f, self.resource_override_path.as_ref()),
3196 output,
3197 )
3198 }
3199
3200 pub fn bind_shader_samplers<S>(&mut self, program: &Program, bindings: &[(&'static str, S)])
3201 where
3202 S: Into<TextureSlot> + Copy,
3203 {
3204 assert_eq!(self.bound_program, program.id);
3206
3207 for binding in bindings {
3208 let u_location = self.gl.get_uniform_location(program.id, binding.0);
3209 if u_location != -1 {
3210 self.bind_program(program);
3211 self.gl
3212 .uniform_1i(u_location, binding.1.into().0 as gl::GLint);
3213 }
3214 }
3215 }
3216
3217 pub fn get_uniform_location(&self, program: &Program, name: &str) -> UniformLocation {
3218 UniformLocation(self.gl.get_uniform_location(program.id, name))
3219 }
3220
3221 pub fn set_uniforms(
3222 &self,
3223 program: &Program,
3224 transform: &Transform3D<f32>,
3225 ) {
3226 debug_assert!(self.inside_frame);
3227 #[cfg(debug_assertions)]
3228 debug_assert!(self.shader_is_ready);
3229
3230 self.gl
3231 .uniform_matrix_4fv(program.u_transform, false, &transform.to_array());
3232 }
3233
3234 pub fn set_shader_texture_size(
3237 &self,
3238 program: &Program,
3239 texture_size: DeviceSize,
3240 ) {
3241 debug_assert!(self.inside_frame);
3242 #[cfg(debug_assertions)]
3243 debug_assert!(self.shader_is_ready);
3244
3245 if program.u_texture_size != -1 {
3246 self.gl.uniform_2f(program.u_texture_size, texture_size.width, texture_size.height);
3247 }
3248 }
3249
3250 pub fn create_pbo(&mut self) -> PBO {
3251 let id = self.gl.gen_buffers(1)[0];
3252 PBO {
3253 id,
3254 reserved_size: 0,
3255 }
3256 }
3257
3258 pub fn create_pbo_with_size(&mut self, size: usize) -> PBO {
3259 let mut pbo = self.create_pbo();
3260
3261 self.gl.bind_buffer(gl::PIXEL_PACK_BUFFER, pbo.id);
3262 self.gl.pixel_store_i(gl::PACK_ALIGNMENT, 1);
3263 self.gl.buffer_data_untyped(
3264 gl::PIXEL_PACK_BUFFER,
3265 size as _,
3266 ptr::null(),
3267 gl::STREAM_READ,
3268 );
3269 self.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
3270
3271 pbo.reserved_size = size;
3272 pbo
3273 }
3274
3275 pub fn read_pixels_into_pbo(
3276 &mut self,
3277 read_target: ReadTarget,
3278 rect: DeviceIntRect,
3279 format: ImageFormat,
3280 pbo: &PBO,
3281 ) {
3282 let byte_size = rect.area() as usize * format.bytes_per_pixel() as usize;
3283
3284 assert!(byte_size <= pbo.reserved_size);
3285
3286 self.bind_read_target(read_target);
3287
3288 self.gl.bind_buffer(gl::PIXEL_PACK_BUFFER, pbo.id);
3289 self.gl.pixel_store_i(gl::PACK_ALIGNMENT, 1);
3290
3291 let gl_format = self.gl_describe_format(format);
3292
3293 unsafe {
3294 self.gl.read_pixels_into_pbo(
3295 rect.min.x as _,
3296 rect.min.y as _,
3297 rect.width() as _,
3298 rect.height() as _,
3299 gl_format.read,
3300 gl_format.pixel_type,
3301 );
3302 }
3303
3304 self.gl.bind_buffer(gl::PIXEL_PACK_BUFFER, 0);
3305 }
3306
3307 pub fn map_pbo_for_readback<'a>(&'a mut self, pbo: &'a PBO) -> Option<BoundPBO<'a>> {
3308 self.gl.bind_buffer(gl::PIXEL_PACK_BUFFER, pbo.id);
3309
3310 let buf_ptr = match self.gl.get_type() {
3311 gl::GlType::Gl => {
3312 self.gl.map_buffer(gl::PIXEL_PACK_BUFFER, gl::READ_ONLY)
3313 }
3314
3315 gl::GlType::Gles => {
3316 self.gl.map_buffer_range(
3317 gl::PIXEL_PACK_BUFFER,
3318 0,
3319 pbo.reserved_size as _,
3320 gl::MAP_READ_BIT)
3321 }
3322 };
3323
3324 if buf_ptr.is_null() {
3325 return None;
3326 }
3327
3328 let buffer = unsafe { slice::from_raw_parts(buf_ptr as *const u8, pbo.reserved_size) };
3329
3330 Some(BoundPBO {
3331 device: self,
3332 data: buffer,
3333 })
3334 }
3335
3336 pub fn delete_pbo(&mut self, mut pbo: PBO) {
3337 self.gl.delete_buffers(&[pbo.id]);
3338 pbo.id = 0;
3339 pbo.reserved_size = 0
3340 }
3341
3342 pub fn required_upload_size_and_stride(&self, size: DeviceIntSize, format: ImageFormat) -> (usize, usize) {
3345 assert!(size.width >= 0);
3346 assert!(size.height >= 0);
3347
3348 let bytes_pp = format.bytes_per_pixel() as usize;
3349 let width_bytes = size.width as usize * bytes_pp;
3350
3351 let dst_stride = round_up_to_multiple(width_bytes, self.required_pbo_stride.num_bytes(format));
3352
3353 let dst_size = dst_stride * size.height as usize;
3359
3360 (dst_size, dst_stride)
3361 }
3362
3363 pub fn upload_texture<'a>(
3366 &mut self,
3367 pbo_pool: &'a mut UploadPBOPool,
3368 ) -> TextureUploader<'a> {
3369 debug_assert!(self.inside_frame);
3370
3371 pbo_pool.begin_frame(self);
3372
3373 TextureUploader {
3374 buffers: Vec::new(),
3375 pbo_pool,
3376 }
3377 }
3378
3379 pub fn upload_texture_immediate<T: Texel>(
3381 &mut self,
3382 texture: &Texture,
3383 pixels: &[T]
3384 ) {
3385 self.bind_texture(DEFAULT_TEXTURE, texture, Swizzle::default());
3386 let desc = self.gl_describe_format(texture.format);
3387 self.gl.tex_sub_image_2d(
3388 texture.target,
3389 0,
3390 0,
3391 0,
3392 texture.size.width as gl::GLint,
3393 texture.size.height as gl::GLint,
3394 desc.external,
3395 desc.pixel_type,
3396 texels_to_u8_slice(pixels),
3397 );
3398 }
3399
3400 pub fn read_pixels(&mut self, img_desc: &ImageDescriptor) -> Vec<u8> {
3401 let desc = self.gl_describe_format(img_desc.format);
3402 self.gl.read_pixels(
3403 0, 0,
3404 img_desc.size.width as i32,
3405 img_desc.size.height as i32,
3406 desc.read,
3407 desc.pixel_type,
3408 )
3409 }
3410
3411 pub fn read_pixels_into(
3413 &mut self,
3414 rect: FramebufferIntRect,
3415 format: ImageFormat,
3416 output: &mut [u8],
3417 ) {
3418 let bytes_per_pixel = format.bytes_per_pixel();
3419 let desc = self.gl_describe_format(format);
3420 let size_in_bytes = (bytes_per_pixel * rect.area()) as usize;
3421 assert_eq!(output.len(), size_in_bytes);
3422
3423 self.gl.flush();
3424 self.gl.read_pixels_into_buffer(
3425 rect.min.x as _,
3426 rect.min.y as _,
3427 rect.width() as _,
3428 rect.height() as _,
3429 desc.read,
3430 desc.pixel_type,
3431 output,
3432 );
3433 }
3434
3435 pub fn get_tex_image_into(
3437 &mut self,
3438 texture: &Texture,
3439 format: ImageFormat,
3440 output: &mut [u8],
3441 ) {
3442 self.bind_texture(DEFAULT_TEXTURE, texture, Swizzle::default());
3443 let desc = self.gl_describe_format(format);
3444 self.gl.get_tex_image_into_buffer(
3445 texture.target,
3446 0,
3447 desc.external,
3448 desc.pixel_type,
3449 output,
3450 );
3451 }
3452
3453 fn attach_read_texture_raw(&mut self, texture_id: gl::GLuint, target: gl::GLuint) {
3455 self.gl.framebuffer_texture_2d(
3456 gl::READ_FRAMEBUFFER,
3457 gl::COLOR_ATTACHMENT0,
3458 target,
3459 texture_id,
3460 0,
3461 )
3462 }
3463
3464 pub fn attach_read_texture_external(
3465 &mut self, texture_id: gl::GLuint, target: ImageBufferKind
3466 ) {
3467 self.attach_read_texture_raw(texture_id, get_gl_target(target))
3468 }
3469
3470 pub fn attach_read_texture(&mut self, texture: &Texture) {
3471 self.attach_read_texture_raw(texture.id, texture.target)
3472 }
3473
3474 fn bind_vao_impl(&mut self, id: gl::GLuint) {
3475 debug_assert!(self.inside_frame);
3476
3477 if self.bound_vao != id {
3478 self.bound_vao = id;
3479 self.gl.bind_vertex_array(id);
3480 }
3481 }
3482
3483 pub fn bind_vao(&mut self, vao: &VAO) {
3484 self.bind_vao_impl(vao.id)
3485 }
3486
3487 pub fn bind_custom_vao(&mut self, vao: &CustomVAO) {
3488 self.bind_vao_impl(vao.id)
3489 }
3490
3491 fn create_vao_with_vbos(
3492 &mut self,
3493 descriptor: &VertexDescriptor,
3494 main_vbo_id: VBOId,
3495 instance_vbo_id: VBOId,
3496 instance_divisor: u32,
3497 ibo_id: IBOId,
3498 owns_vertices_and_indices: bool,
3499 ) -> VAO {
3500 let instance_stride = descriptor.instance_stride() as usize;
3501 let vao_id = self.gl.gen_vertex_arrays(1)[0];
3502
3503 self.bind_vao_impl(vao_id);
3504
3505 descriptor.bind(self.gl(), main_vbo_id, instance_vbo_id, instance_divisor);
3506 ibo_id.bind(self.gl()); VAO {
3509 id: vao_id,
3510 ibo_id,
3511 main_vbo_id,
3512 instance_vbo_id,
3513 instance_stride,
3514 instance_divisor,
3515 owns_vertices_and_indices,
3516 }
3517 }
3518
3519 pub fn create_custom_vao(
3520 &mut self,
3521 streams: &[Stream],
3522 ) -> CustomVAO {
3523 debug_assert!(self.inside_frame);
3524
3525 let vao_id = self.gl.gen_vertex_arrays(1)[0];
3526 self.bind_vao_impl(vao_id);
3527
3528 let mut attrib_index = 0;
3529 for stream in streams {
3530 VertexDescriptor::bind_attributes(
3531 stream.attributes,
3532 attrib_index,
3533 0,
3534 self.gl(),
3535 stream.vbo,
3536 );
3537 attrib_index += stream.attributes.len();
3538 }
3539
3540 CustomVAO {
3541 id: vao_id,
3542 }
3543 }
3544
3545 pub fn delete_custom_vao(&mut self, mut vao: CustomVAO) {
3546 self.gl.delete_vertex_arrays(&[vao.id]);
3547 vao.id = 0;
3548 }
3549
3550 pub fn create_vbo<T>(&mut self) -> VBO<T> {
3551 let ids = self.gl.gen_buffers(1);
3552 VBO {
3553 id: ids[0],
3554 target: gl::ARRAY_BUFFER,
3555 allocated_count: 0,
3556 marker: PhantomData,
3557 }
3558 }
3559
3560 pub fn delete_vbo<T>(&mut self, mut vbo: VBO<T>) {
3561 self.gl.delete_buffers(&[vbo.id]);
3562 vbo.id = 0;
3563 }
3564
3565 pub fn create_vao(&mut self, descriptor: &VertexDescriptor, instance_divisor: u32) -> VAO {
3566 debug_assert!(self.inside_frame);
3567
3568 let buffer_ids = self.gl.gen_buffers(3);
3569 let ibo_id = IBOId(buffer_ids[0]);
3570 let main_vbo_id = VBOId(buffer_ids[1]);
3571 let intance_vbo_id = VBOId(buffer_ids[2]);
3572
3573 self.create_vao_with_vbos(descriptor, main_vbo_id, intance_vbo_id, instance_divisor, ibo_id, true)
3574 }
3575
3576 pub fn delete_vao(&mut self, mut vao: VAO) {
3577 self.gl.delete_vertex_arrays(&[vao.id]);
3578 vao.id = 0;
3579
3580 if vao.owns_vertices_and_indices {
3581 self.gl.delete_buffers(&[vao.ibo_id.0]);
3582 self.gl.delete_buffers(&[vao.main_vbo_id.0]);
3583 }
3584
3585 self.gl.delete_buffers(&[vao.instance_vbo_id.0])
3586 }
3587
3588 pub fn allocate_vbo<V>(
3589 &mut self,
3590 vbo: &mut VBO<V>,
3591 count: usize,
3592 usage_hint: VertexUsageHint,
3593 ) {
3594 debug_assert!(self.inside_frame);
3595 vbo.allocated_count = count;
3596
3597 self.gl.bind_buffer(vbo.target, vbo.id);
3598 self.gl.buffer_data_untyped(
3599 vbo.target,
3600 (count * mem::size_of::<V>()) as _,
3601 ptr::null(),
3602 usage_hint.to_gl(),
3603 );
3604 }
3605
3606 pub fn fill_vbo<V>(
3607 &mut self,
3608 vbo: &VBO<V>,
3609 data: &[V],
3610 offset: usize,
3611 ) {
3612 debug_assert!(self.inside_frame);
3613 assert!(offset + data.len() <= vbo.allocated_count);
3614 let stride = mem::size_of::<V>();
3615
3616 self.gl.bind_buffer(vbo.target, vbo.id);
3617 self.gl.buffer_sub_data_untyped(
3618 vbo.target,
3619 (offset * stride) as _,
3620 (data.len() * stride) as _,
3621 data.as_ptr() as _,
3622 );
3623 }
3624
3625 fn update_vbo_data<V>(
3626 &mut self,
3627 vbo: VBOId,
3628 vertices: &[V],
3629 usage_hint: VertexUsageHint,
3630 ) {
3631 debug_assert!(self.inside_frame);
3632
3633 vbo.bind(self.gl());
3634 gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, vertices, usage_hint.to_gl());
3635 }
3636
3637 pub fn create_vao_with_new_instances(
3638 &mut self,
3639 descriptor: &VertexDescriptor,
3640 base_vao: &VAO,
3641 ) -> VAO {
3642 debug_assert!(self.inside_frame);
3643
3644 let buffer_ids = self.gl.gen_buffers(1);
3645 let intance_vbo_id = VBOId(buffer_ids[0]);
3646
3647 self.create_vao_with_vbos(
3648 descriptor,
3649 base_vao.main_vbo_id,
3650 intance_vbo_id,
3651 base_vao.instance_divisor,
3652 base_vao.ibo_id,
3653 false,
3654 )
3655 }
3656
3657 pub fn update_vao_main_vertices<V>(
3658 &mut self,
3659 vao: &VAO,
3660 vertices: &[V],
3661 usage_hint: VertexUsageHint,
3662 ) {
3663 debug_assert_eq!(self.bound_vao, vao.id);
3664 self.update_vbo_data(vao.main_vbo_id, vertices, usage_hint)
3665 }
3666
3667 pub fn update_vao_instances<V: Clone>(
3668 &mut self,
3669 vao: &VAO,
3670 instances: &[V],
3671 usage_hint: VertexUsageHint,
3672 repeat: Option<NonZeroUsize>,
3674 ) {
3675 debug_assert_eq!(self.bound_vao, vao.id);
3676 debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>());
3677
3678 match repeat {
3679 Some(count) => {
3680 let target = gl::ARRAY_BUFFER;
3681 self.gl.bind_buffer(target, vao.instance_vbo_id.0);
3682 let size = instances.len() * count.get() * mem::size_of::<V>();
3683 self.gl.buffer_data_untyped(
3684 target,
3685 size as _,
3686 ptr::null(),
3687 usage_hint.to_gl(),
3688 );
3689
3690 let ptr = match self.gl.get_type() {
3691 gl::GlType::Gl => {
3692 self.gl.map_buffer(target, gl::WRITE_ONLY)
3693 }
3694 gl::GlType::Gles => {
3695 self.gl.map_buffer_range(target, 0, size as _, gl::MAP_WRITE_BIT)
3696 }
3697 };
3698 assert!(!ptr.is_null());
3699
3700 let buffer_slice = unsafe {
3701 slice::from_raw_parts_mut(ptr as *mut V, instances.len() * count.get())
3702 };
3703 for (quad, instance) in buffer_slice.chunks_mut(4).zip(instances) {
3704 quad[0] = instance.clone();
3705 quad[1] = instance.clone();
3706 quad[2] = instance.clone();
3707 quad[3] = instance.clone();
3708 }
3709 self.gl.unmap_buffer(target);
3710 }
3711 None => {
3712 self.update_vbo_data(vao.instance_vbo_id, instances, usage_hint);
3713 }
3714 }
3715
3716 if self.capabilities.requires_vao_rebind_after_orphaning {
3720 self.bind_vao_impl(0);
3721 self.bind_vao_impl(vao.id);
3722 }
3723 }
3724
3725 pub fn update_vao_indices<I>(&mut self, vao: &VAO, indices: &[I], usage_hint: VertexUsageHint) {
3726 debug_assert!(self.inside_frame);
3727 debug_assert_eq!(self.bound_vao, vao.id);
3728
3729 vao.ibo_id.bind(self.gl());
3730 gl::buffer_data(
3731 self.gl(),
3732 gl::ELEMENT_ARRAY_BUFFER,
3733 indices,
3734 usage_hint.to_gl(),
3735 );
3736 }
3737
3738 pub fn draw_triangles_u16(&mut self, first_vertex: i32, index_count: i32) {
3739 debug_assert!(self.inside_frame);
3740 #[cfg(debug_assertions)]
3741 debug_assert!(self.shader_is_ready);
3742
3743 let _guard = if self.annotate_draw_call_crashes {
3744 Some(CrashAnnotatorGuard::new(
3745 &self.crash_annotator,
3746 CrashAnnotation::DrawShader,
3747 &self.bound_program_name,
3748 ))
3749 } else {
3750 None
3751 };
3752
3753 self.gl.draw_elements(
3754 gl::TRIANGLES,
3755 index_count,
3756 gl::UNSIGNED_SHORT,
3757 first_vertex as u32 * 2,
3758 );
3759 }
3760
3761 pub fn draw_triangles_u32(&mut self, first_vertex: i32, index_count: i32) {
3762 debug_assert!(self.inside_frame);
3763 #[cfg(debug_assertions)]
3764 debug_assert!(self.shader_is_ready);
3765
3766 let _guard = if self.annotate_draw_call_crashes {
3767 Some(CrashAnnotatorGuard::new(
3768 &self.crash_annotator,
3769 CrashAnnotation::DrawShader,
3770 &self.bound_program_name,
3771 ))
3772 } else {
3773 None
3774 };
3775
3776 self.gl.draw_elements(
3777 gl::TRIANGLES,
3778 index_count,
3779 gl::UNSIGNED_INT,
3780 first_vertex as u32 * 4,
3781 );
3782 }
3783
3784 pub fn draw_nonindexed_points(&mut self, first_vertex: i32, vertex_count: i32) {
3785 debug_assert!(self.inside_frame);
3786 #[cfg(debug_assertions)]
3787 debug_assert!(self.shader_is_ready);
3788
3789 let _guard = if self.annotate_draw_call_crashes {
3790 Some(CrashAnnotatorGuard::new(
3791 &self.crash_annotator,
3792 CrashAnnotation::DrawShader,
3793 &self.bound_program_name,
3794 ))
3795 } else {
3796 None
3797 };
3798
3799 self.gl.draw_arrays(gl::POINTS, first_vertex, vertex_count);
3800 }
3801
3802 pub fn draw_nonindexed_lines(&mut self, first_vertex: i32, vertex_count: i32) {
3803 debug_assert!(self.inside_frame);
3804 #[cfg(debug_assertions)]
3805 debug_assert!(self.shader_is_ready);
3806
3807 let _guard = if self.annotate_draw_call_crashes {
3808 Some(CrashAnnotatorGuard::new(
3809 &self.crash_annotator,
3810 CrashAnnotation::DrawShader,
3811 &self.bound_program_name,
3812 ))
3813 } else {
3814 None
3815 };
3816
3817 self.gl.draw_arrays(gl::LINES, first_vertex, vertex_count);
3818 }
3819
3820 pub fn draw_indexed_triangles(&mut self, index_count: i32) {
3821 debug_assert!(self.inside_frame);
3822 #[cfg(debug_assertions)]
3823 debug_assert!(self.shader_is_ready);
3824
3825 let _guard = if self.annotate_draw_call_crashes {
3826 Some(CrashAnnotatorGuard::new(
3827 &self.crash_annotator,
3828 CrashAnnotation::DrawShader,
3829 &self.bound_program_name,
3830 ))
3831 } else {
3832 None
3833 };
3834
3835 self.gl.draw_elements(
3836 gl::TRIANGLES,
3837 index_count,
3838 gl::UNSIGNED_SHORT,
3839 0,
3840 );
3841 }
3842
3843 pub fn draw_indexed_triangles_instanced_u16(&mut self, index_count: i32, instance_count: i32) {
3844 debug_assert!(self.inside_frame);
3845 #[cfg(debug_assertions)]
3846 debug_assert!(self.shader_is_ready);
3847
3848 let _guard = if self.annotate_draw_call_crashes {
3849 Some(CrashAnnotatorGuard::new(
3850 &self.crash_annotator,
3851 CrashAnnotation::DrawShader,
3852 &self.bound_program_name,
3853 ))
3854 } else {
3855 None
3856 };
3857
3858 self.gl.draw_elements_instanced(
3859 gl::TRIANGLES,
3860 index_count,
3861 gl::UNSIGNED_SHORT,
3862 0,
3863 instance_count,
3864 );
3865 }
3866
3867 pub fn end_frame(&mut self) {
3868 self.reset_draw_target();
3869 self.reset_read_target();
3870
3871 debug_assert!(self.inside_frame);
3872 self.inside_frame = false;
3873
3874 self.gl.bind_texture(gl::TEXTURE_2D, 0);
3875 self.gl.use_program(0);
3876
3877 for i in 0 .. self.bound_textures.len() {
3878 self.gl.active_texture(gl::TEXTURE0 + i as gl::GLuint);
3879 self.gl.bind_texture(gl::TEXTURE_2D, 0);
3880 }
3881
3882 self.gl.active_texture(gl::TEXTURE0);
3883
3884 self.frame_id.0 += 1;
3885
3886 if let Some(ref cache) = self.cached_programs {
3890 cache.update_disk_cache(self.frame_id.0 == 10);
3891 }
3892 }
3893
3894 pub fn clear_target(
3895 &self,
3896 color: Option<[f32; 4]>,
3897 depth: Option<f32>,
3898 rect: Option<FramebufferIntRect>,
3899 ) {
3900 let mut clear_bits = 0;
3901
3902 if let Some(color) = color {
3903 self.gl.clear_color(color[0], color[1], color[2], color[3]);
3904 clear_bits |= gl::COLOR_BUFFER_BIT;
3905 }
3906
3907 if let Some(depth) = depth {
3908 if cfg!(debug_assertions) {
3909 let mut mask = [0];
3910 unsafe {
3911 self.gl.get_boolean_v(gl::DEPTH_WRITEMASK, &mut mask);
3912 }
3913 assert_ne!(mask[0], 0);
3914 }
3915 self.gl.clear_depth(depth as f64);
3916 clear_bits |= gl::DEPTH_BUFFER_BIT;
3917 }
3918
3919 if clear_bits != 0 {
3920 match rect {
3921 Some(rect) => {
3922 self.gl.enable(gl::SCISSOR_TEST);
3923 self.gl.scissor(
3924 rect.min.x,
3925 rect.min.y,
3926 rect.width(),
3927 rect.height(),
3928 );
3929 self.gl.clear(clear_bits);
3930 self.gl.disable(gl::SCISSOR_TEST);
3931 }
3932 None => {
3933 self.gl.clear(clear_bits);
3934 }
3935 }
3936 }
3937 }
3938
3939 pub fn enable_depth(&self, depth_func: DepthFunction) {
3940 assert!(self.depth_available, "Enabling depth test without depth target");
3941 self.gl.enable(gl::DEPTH_TEST);
3942 self.gl.depth_func(depth_func as gl::GLuint);
3943 }
3944
3945 pub fn disable_depth(&self) {
3946 self.gl.disable(gl::DEPTH_TEST);
3947 }
3948
3949 pub fn enable_depth_write(&self) {
3950 assert!(self.depth_available, "Enabling depth write without depth target");
3951 self.gl.depth_mask(true);
3952 }
3953
3954 pub fn disable_depth_write(&self) {
3955 self.gl.depth_mask(false);
3956 }
3957
3958 pub fn disable_stencil(&self) {
3959 self.gl.disable(gl::STENCIL_TEST);
3960 }
3961
3962 pub fn set_scissor_rect(&self, rect: FramebufferIntRect) {
3963 self.gl.scissor(
3964 rect.min.x,
3965 rect.min.y,
3966 rect.width(),
3967 rect.height(),
3968 );
3969 }
3970
3971 pub fn enable_scissor(&self) {
3972 self.gl.enable(gl::SCISSOR_TEST);
3973 }
3974
3975 pub fn disable_scissor(&self) {
3976 self.gl.disable(gl::SCISSOR_TEST);
3977 }
3978
3979 pub fn enable_color_write(&self) {
3980 self.gl.color_mask(true, true, true, true);
3981 }
3982
3983 pub fn disable_color_write(&self) {
3984 self.gl.color_mask(false, false, false, false);
3985 }
3986
3987 pub fn set_blend(&mut self, enable: bool) {
3988 if enable {
3989 self.gl.enable(gl::BLEND);
3990 } else {
3991 self.gl.disable(gl::BLEND);
3992 }
3993 #[cfg(debug_assertions)]
3994 {
3995 self.shader_is_ready = false;
3996 }
3997 }
3998
3999 fn set_blend_factors(
4000 &mut self,
4001 color: (gl::GLenum, gl::GLenum),
4002 alpha: (gl::GLenum, gl::GLenum),
4003 ) {
4004 self.gl.blend_equation(gl::FUNC_ADD);
4005 if color == alpha {
4006 self.gl.blend_func(color.0, color.1);
4007 } else {
4008 self.gl.blend_func_separate(color.0, color.1, alpha.0, alpha.1);
4009 }
4010 #[cfg(debug_assertions)]
4011 {
4012 self.shader_is_ready = false;
4013 }
4014 }
4015
4016 pub fn set_blend_mode_alpha(&mut self) {
4017 self.set_blend_factors(
4018 (gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA),
4019 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4020 );
4021 }
4022
4023 pub fn set_blend_mode_premultiplied_alpha(&mut self) {
4024 self.set_blend_factors(
4025 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4026 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4027 );
4028 }
4029
4030 pub fn set_blend_mode_premultiplied_dest_out(&mut self) {
4031 self.set_blend_factors(
4032 (gl::ZERO, gl::ONE_MINUS_SRC_ALPHA),
4033 (gl::ZERO, gl::ONE_MINUS_SRC_ALPHA),
4034 );
4035 }
4036
4037 pub fn set_blend_mode_multiply(&mut self) {
4038 self.set_blend_factors(
4039 (gl::ZERO, gl::SRC_COLOR),
4040 (gl::ZERO, gl::SRC_ALPHA),
4041 );
4042 }
4043 pub fn set_blend_mode_subpixel_pass0(&mut self) {
4044 self.set_blend_factors(
4045 (gl::ZERO, gl::ONE_MINUS_SRC_COLOR),
4046 (gl::ZERO, gl::ONE_MINUS_SRC_ALPHA),
4047 );
4048 }
4049 pub fn set_blend_mode_subpixel_pass1(&mut self) {
4050 self.set_blend_factors(
4051 (gl::ONE, gl::ONE),
4052 (gl::ONE, gl::ONE),
4053 );
4054 }
4055 pub fn set_blend_mode_subpixel_dual_source(&mut self) {
4056 self.set_blend_factors(
4057 (gl::ONE, gl::ONE_MINUS_SRC1_COLOR),
4058 (gl::ONE, gl::ONE_MINUS_SRC1_ALPHA),
4059 );
4060 }
4061 pub fn set_blend_mode_multiply_dual_source(&mut self) {
4062 self.set_blend_factors(
4063 (gl::ONE_MINUS_DST_ALPHA, gl::ONE_MINUS_SRC1_COLOR),
4064 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4065 );
4066 }
4067 pub fn set_blend_mode_screen(&mut self) {
4068 self.set_blend_factors(
4069 (gl::ONE, gl::ONE_MINUS_SRC_COLOR),
4070 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4071 );
4072 }
4073 pub fn set_blend_mode_plus_lighter(&mut self) {
4074 self.set_blend_factors(
4075 (gl::ONE, gl::ONE),
4076 (gl::ONE, gl::ONE),
4077 );
4078 }
4079 pub fn set_blend_mode_exclusion(&mut self) {
4080 self.set_blend_factors(
4081 (gl::ONE_MINUS_DST_COLOR, gl::ONE_MINUS_SRC_COLOR),
4082 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4083 );
4084 }
4085 pub fn set_blend_mode_show_overdraw(&mut self) {
4086 self.set_blend_factors(
4087 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4088 (gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
4089 );
4090 }
4091
4092 pub fn set_blend_mode_max(&mut self) {
4093 self.gl
4094 .blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE);
4095 self.gl.blend_equation_separate(gl::MAX, gl::FUNC_ADD);
4096 #[cfg(debug_assertions)]
4097 {
4098 self.shader_is_ready = false;
4099 }
4100 }
4101 pub fn set_blend_mode_min(&mut self) {
4102 self.gl
4103 .blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE);
4104 self.gl.blend_equation_separate(gl::MIN, gl::FUNC_ADD);
4105 #[cfg(debug_assertions)]
4106 {
4107 self.shader_is_ready = false;
4108 }
4109 }
4110 pub fn set_blend_mode_advanced(&mut self, mode: MixBlendMode) {
4111 self.gl.blend_equation(match mode {
4112 MixBlendMode::Normal => {
4113 self.gl.blend_func_separate(gl::ZERO, gl::SRC_COLOR, gl::ZERO, gl::SRC_ALPHA);
4115 gl::FUNC_ADD
4116 },
4117 MixBlendMode::PlusLighter => {
4118 return self.set_blend_mode_plus_lighter();
4119 },
4120 MixBlendMode::Multiply => gl::MULTIPLY_KHR,
4121 MixBlendMode::Screen => gl::SCREEN_KHR,
4122 MixBlendMode::Overlay => gl::OVERLAY_KHR,
4123 MixBlendMode::Darken => gl::DARKEN_KHR,
4124 MixBlendMode::Lighten => gl::LIGHTEN_KHR,
4125 MixBlendMode::ColorDodge => gl::COLORDODGE_KHR,
4126 MixBlendMode::ColorBurn => gl::COLORBURN_KHR,
4127 MixBlendMode::HardLight => gl::HARDLIGHT_KHR,
4128 MixBlendMode::SoftLight => gl::SOFTLIGHT_KHR,
4129 MixBlendMode::Difference => gl::DIFFERENCE_KHR,
4130 MixBlendMode::Exclusion => gl::EXCLUSION_KHR,
4131 MixBlendMode::Hue => gl::HSL_HUE_KHR,
4132 MixBlendMode::Saturation => gl::HSL_SATURATION_KHR,
4133 MixBlendMode::Color => gl::HSL_COLOR_KHR,
4134 MixBlendMode::Luminosity => gl::HSL_LUMINOSITY_KHR,
4135 });
4136 #[cfg(debug_assertions)]
4137 {
4138 self.shader_is_ready = false;
4139 }
4140 }
4141
4142 pub fn supports_extension(&self, extension: &str) -> bool {
4143 supports_extension(&self.extensions, extension)
4144 }
4145
4146 pub fn echo_driver_messages(&self) {
4147 if self.capabilities.supports_khr_debug {
4148 Device::log_driver_messages(self.gl());
4149 }
4150 }
4151
4152 fn log_driver_messages(gl: &dyn gl::Gl) {
4153 for msg in gl.get_debug_messages() {
4154 let level = match msg.severity {
4155 gl::DEBUG_SEVERITY_HIGH => Level::Error,
4156 gl::DEBUG_SEVERITY_MEDIUM => Level::Warn,
4157 gl::DEBUG_SEVERITY_LOW => Level::Info,
4158 gl::DEBUG_SEVERITY_NOTIFICATION => Level::Debug,
4159 _ => Level::Trace,
4160 };
4161 let ty = match msg.ty {
4162 gl::DEBUG_TYPE_ERROR => "error",
4163 gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "deprecated",
4164 gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "undefined",
4165 gl::DEBUG_TYPE_PORTABILITY => "portability",
4166 gl::DEBUG_TYPE_PERFORMANCE => "perf",
4167 gl::DEBUG_TYPE_MARKER => "marker",
4168 gl::DEBUG_TYPE_PUSH_GROUP => "group push",
4169 gl::DEBUG_TYPE_POP_GROUP => "group pop",
4170 gl::DEBUG_TYPE_OTHER => "other",
4171 _ => "?",
4172 };
4173 log!(level, "({}) {}", ty, msg.message);
4174 }
4175 }
4176
4177 pub fn gl_describe_format(&self, format: ImageFormat) -> FormatDesc {
4178 match format {
4179 ImageFormat::R8 => FormatDesc {
4180 internal: gl::R8,
4181 external: gl::RED,
4182 read: gl::RED,
4183 pixel_type: gl::UNSIGNED_BYTE,
4184 },
4185 ImageFormat::R16 => FormatDesc {
4186 internal: gl::R16,
4187 external: gl::RED,
4188 read: gl::RED,
4189 pixel_type: gl::UNSIGNED_SHORT,
4190 },
4191 ImageFormat::BGRA8 => {
4192 FormatDesc {
4193 internal: self.bgra_formats.internal,
4194 external: self.bgra_formats.external,
4195 read: gl::BGRA,
4196 pixel_type: self.bgra_pixel_type,
4197 }
4198 },
4199 ImageFormat::RGBA8 => {
4200 FormatDesc {
4201 internal: gl::RGBA8,
4202 external: gl::RGBA,
4203 read: gl::RGBA,
4204 pixel_type: gl::UNSIGNED_BYTE,
4205 }
4206 },
4207 ImageFormat::RGBAF32 => FormatDesc {
4208 internal: gl::RGBA32F,
4209 external: gl::RGBA,
4210 read: gl::RGBA,
4211 pixel_type: gl::FLOAT,
4212 },
4213 ImageFormat::RGBAI32 => FormatDesc {
4214 internal: gl::RGBA32I,
4215 external: gl::RGBA_INTEGER,
4216 read: gl::RGBA_INTEGER,
4217 pixel_type: gl::INT,
4218 },
4219 ImageFormat::RG8 => FormatDesc {
4220 internal: gl::RG8,
4221 external: gl::RG,
4222 read: gl::RG,
4223 pixel_type: gl::UNSIGNED_BYTE,
4224 },
4225 ImageFormat::RG16 => FormatDesc {
4226 internal: gl::RG16,
4227 external: gl::RG,
4228 read: gl::RG,
4229 pixel_type: gl::UNSIGNED_SHORT,
4230 },
4231 }
4232 }
4233
4234 pub fn report_memory(&self, size_op_funs: &MallocSizeOfOps, swgl: *mut c_void) -> MemoryReport {
4236 let mut report = MemoryReport::default();
4237 report.depth_target_textures += self.depth_targets_memory();
4238
4239 #[cfg(feature = "sw_compositor")]
4240 if !swgl.is_null() {
4241 report.swgl += swgl::Context::from(swgl).report_memory(size_op_funs.size_of_op);
4242 }
4243 let _ = size_op_funs;
4245 let _ = swgl;
4246 report
4247 }
4248
4249 pub fn depth_targets_memory(&self) -> usize {
4250 let mut total = 0;
4251 for dim in self.depth_targets.keys() {
4252 total += depth_target_size_in_bytes(dim);
4253 }
4254
4255 total
4256 }
4257}
4258
4259pub struct FormatDesc {
4260 pub internal: gl::GLenum,
4262 pub external: gl::GLuint,
4264 pub read: gl::GLuint,
4267 pub pixel_type: gl::GLuint,
4269}
4270
4271#[derive(Debug)]
4272struct UploadChunk<'a> {
4273 rect: DeviceIntRect,
4274 stride: Option<i32>,
4275 offset: usize,
4276 format_override: Option<ImageFormat>,
4277 texture: &'a Texture,
4278}
4279
4280#[derive(Debug)]
4281struct PixelBuffer<'a> {
4282 size_used: usize,
4283 chunks: SmallVec<[UploadChunk<'a>; 1]>,
4285 inner: UploadPBO,
4286 mapping: &'a mut [mem::MaybeUninit<u8>],
4287}
4288
4289impl<'a> PixelBuffer<'a> {
4290 fn new(
4291 pbo: UploadPBO,
4292 ) -> Self {
4293 let mapping = unsafe {
4294 slice::from_raw_parts_mut(pbo.mapping.get_ptr().as_ptr(), pbo.pbo.reserved_size)
4295 };
4296 Self {
4297 size_used: 0,
4298 chunks: SmallVec::new(),
4299 inner: pbo,
4300 mapping,
4301 }
4302 }
4303
4304 fn flush_chunks(&mut self, device: &mut Device) {
4305 for chunk in self.chunks.drain(..) {
4306 TextureUploader::update_impl(device, chunk);
4307 }
4308 }
4309}
4310
4311impl<'a> Drop for PixelBuffer<'a> {
4312 fn drop(&mut self) {
4313 assert_eq!(self.chunks.len(), 0, "PixelBuffer must be flushed before dropping.");
4314 }
4315}
4316
4317#[derive(Debug)]
4318enum PBOMapping {
4319 Unmapped,
4320 Transient(ptr::NonNull<mem::MaybeUninit<u8>>),
4321 Persistent(ptr::NonNull<mem::MaybeUninit<u8>>),
4322}
4323
4324impl PBOMapping {
4325 fn get_ptr(&self) -> ptr::NonNull<mem::MaybeUninit<u8>> {
4326 match self {
4327 PBOMapping::Unmapped => unreachable!("Cannot get pointer to unmapped PBO."),
4328 PBOMapping::Transient(ptr) => *ptr,
4329 PBOMapping::Persistent(ptr) => *ptr,
4330 }
4331 }
4332}
4333
4334#[derive(Debug)]
4336struct UploadPBO {
4337 pbo: PBO,
4338 mapping: PBOMapping,
4339 can_recycle: bool,
4340}
4341
4342impl UploadPBO {
4343 fn empty() -> Self {
4344 Self {
4345 pbo: PBO {
4346 id: 0,
4347 reserved_size: 0,
4348 },
4349 mapping: PBOMapping::Unmapped,
4350 can_recycle: false,
4351 }
4352 }
4353}
4354
4355pub struct UploadPBOPool {
4359 usage_hint: VertexUsageHint,
4361 default_size: usize,
4363 available_buffers: Vec<UploadPBO>,
4365 returned_buffers: Vec<UploadPBO>,
4368 waiting_buffers: Vec<(gl::GLsync, Vec<UploadPBO>)>,
4371 orphaned_buffers: Vec<PBO>,
4374}
4375
4376impl UploadPBOPool {
4377 pub fn new(device: &mut Device, default_size: usize) -> Self {
4378 let usage_hint = match device.upload_method {
4379 UploadMethod::Immediate => VertexUsageHint::Stream,
4380 UploadMethod::PixelBuffer(usage_hint) => usage_hint,
4381 };
4382 Self {
4383 usage_hint,
4384 default_size,
4385 available_buffers: Vec::new(),
4386 returned_buffers: Vec::new(),
4387 waiting_buffers: Vec::new(),
4388 orphaned_buffers: Vec::new(),
4389 }
4390 }
4391
4392 pub fn begin_frame(&mut self, device: &mut Device) {
4395 let mut first_not_signalled = self.waiting_buffers.len();
4400 for (i, (sync, buffers)) in self.waiting_buffers.iter_mut().enumerate() {
4401 match device.gl.client_wait_sync(*sync, 0, 0) {
4402 gl::TIMEOUT_EXPIRED => {
4403 first_not_signalled = i;
4404 break;
4405 },
4406 gl::ALREADY_SIGNALED | gl::CONDITION_SATISFIED => {
4407 self.available_buffers.extend(buffers.drain(..));
4408 }
4409 gl::WAIT_FAILED | _ => {
4410 warn!("glClientWaitSync error in UploadPBOPool::begin_frame()");
4411 for buffer in buffers.drain(..) {
4412 device.delete_pbo(buffer.pbo);
4413 }
4414 }
4415 }
4416 }
4417
4418 for (sync, _) in self.waiting_buffers.drain(0..first_not_signalled) {
4420 device.gl.delete_sync(sync);
4421 }
4422 }
4423
4424 pub fn end_frame(&mut self, device: &mut Device) {
4427 if !self.returned_buffers.is_empty() {
4428 let sync = device.gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
4429 if !sync.is_null() {
4430 self.waiting_buffers.push((sync, mem::replace(&mut self.returned_buffers, Vec::new())))
4431 } else {
4432 warn!("glFenceSync error in UploadPBOPool::end_frame()");
4433
4434 for buffer in self.returned_buffers.drain(..) {
4435 device.delete_pbo(buffer.pbo);
4436 }
4437 }
4438 }
4439 }
4440
4441 fn get_pbo(&mut self, device: &mut Device, min_size: usize) -> Result<UploadPBO, String> {
4445
4446 let (can_recycle, size) = if min_size <= self.default_size && device.capabilities.supports_nonzero_pbo_offsets {
4451 (true, self.default_size)
4452 } else {
4453 (false, min_size)
4454 };
4455
4456 if can_recycle {
4458 if let Some(mut buffer) = self.available_buffers.pop() {
4459 assert_eq!(buffer.pbo.reserved_size, size);
4460 assert!(buffer.can_recycle);
4461
4462 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer.pbo.id);
4463
4464 match buffer.mapping {
4465 PBOMapping::Unmapped => {
4466 let ptr = device.gl.map_buffer_range(
4468 gl::PIXEL_UNPACK_BUFFER,
4469 0,
4470 buffer.pbo.reserved_size as _,
4471 gl::MAP_WRITE_BIT | gl::MAP_UNSYNCHRONIZED_BIT,
4472 ) as *mut _;
4473
4474 let ptr = ptr::NonNull::new(ptr).ok_or_else(
4475 || format!("Failed to transiently map PBO of size {} bytes", buffer.pbo.reserved_size)
4476 )?;
4477
4478 buffer.mapping = PBOMapping::Transient(ptr);
4479 }
4480 PBOMapping::Transient(_) => {
4481 unreachable!("Transiently mapped UploadPBO must be unmapped before returning to pool.");
4482 }
4483 PBOMapping::Persistent(_) => {
4484 }
4485 }
4486
4487 return Ok(buffer);
4488 }
4489 }
4490
4491 let mut pbo = match self.orphaned_buffers.pop() {
4494 Some(pbo) => pbo,
4495 None => device.create_pbo(),
4496 };
4497
4498 assert_eq!(pbo.reserved_size, 0);
4499 pbo.reserved_size = size;
4500
4501 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, pbo.id);
4502 let mapping = if device.capabilities.supports_buffer_storage && can_recycle {
4503 device.gl.buffer_storage(
4504 gl::PIXEL_UNPACK_BUFFER,
4505 pbo.reserved_size as _,
4506 ptr::null(),
4507 gl::MAP_WRITE_BIT | gl::MAP_PERSISTENT_BIT,
4508 );
4509 let ptr = device.gl.map_buffer_range(
4510 gl::PIXEL_UNPACK_BUFFER,
4511 0,
4512 pbo.reserved_size as _,
4513 gl::MAP_WRITE_BIT | gl::MAP_PERSISTENT_BIT | gl::MAP_FLUSH_EXPLICIT_BIT,
4517 ) as *mut _;
4518
4519 let ptr = ptr::NonNull::new(ptr).ok_or_else(
4520 || format!("Failed to transiently map PBO of size {} bytes", pbo.reserved_size)
4521 )?;
4522
4523 PBOMapping::Persistent(ptr)
4524 } else {
4525 device.gl.buffer_data_untyped(
4526 gl::PIXEL_UNPACK_BUFFER,
4527 pbo.reserved_size as _,
4528 ptr::null(),
4529 self.usage_hint.to_gl(),
4530 );
4531 let ptr = device.gl.map_buffer_range(
4532 gl::PIXEL_UNPACK_BUFFER,
4533 0,
4534 pbo.reserved_size as _,
4535 gl::MAP_WRITE_BIT,
4538 ) as *mut _;
4539
4540 let ptr = ptr::NonNull::new(ptr).ok_or_else(
4541 || format!("Failed to transiently map PBO of size {} bytes", pbo.reserved_size)
4542 )?;
4543
4544 PBOMapping::Transient(ptr)
4545 };
4546
4547 Ok(UploadPBO { pbo, mapping, can_recycle })
4548 }
4549
4550 fn return_pbo(&mut self, device: &mut Device, mut buffer: UploadPBO) {
4553 assert!(
4554 !matches!(buffer.mapping, PBOMapping::Transient(_)),
4555 "Transiently mapped UploadPBO must be unmapped before returning to pool.",
4556 );
4557
4558 if buffer.can_recycle {
4559 self.returned_buffers.push(buffer);
4560 } else {
4561 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer.pbo.id);
4562 device.gl.buffer_data_untyped(
4563 gl::PIXEL_UNPACK_BUFFER,
4564 0,
4565 ptr::null(),
4566 gl::STREAM_DRAW,
4567 );
4568 buffer.pbo.reserved_size = 0;
4569 self.orphaned_buffers.push(buffer.pbo);
4570 }
4571
4572 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
4573 }
4574
4575 pub fn on_memory_pressure(&mut self, device: &mut Device) {
4577 for buffer in self.available_buffers.drain(..) {
4578 device.delete_pbo(buffer.pbo);
4579 }
4580 for buffer in self.returned_buffers.drain(..) {
4581 device.delete_pbo(buffer.pbo)
4582 }
4583 for (sync, buffers) in self.waiting_buffers.drain(..) {
4584 device.gl.delete_sync(sync);
4585 for buffer in buffers {
4586 device.delete_pbo(buffer.pbo)
4587 }
4588 }
4589 }
4591
4592 pub fn report_memory(&self) -> MemoryReport {
4594 let mut report = MemoryReport::default();
4595 for buffer in &self.available_buffers {
4596 report.texture_upload_pbos += buffer.pbo.reserved_size;
4597 }
4598 for buffer in &self.returned_buffers {
4599 report.texture_upload_pbos += buffer.pbo.reserved_size;
4600 }
4601 for (_, buffers) in &self.waiting_buffers {
4602 for buffer in buffers {
4603 report.texture_upload_pbos += buffer.pbo.reserved_size;
4604 }
4605 }
4606 report
4607 }
4608
4609 pub fn deinit(&mut self, device: &mut Device) {
4610 for buffer in self.available_buffers.drain(..) {
4611 device.delete_pbo(buffer.pbo);
4612 }
4613 for buffer in self.returned_buffers.drain(..) {
4614 device.delete_pbo(buffer.pbo)
4615 }
4616 for (sync, buffers) in self.waiting_buffers.drain(..) {
4617 device.gl.delete_sync(sync);
4618 for buffer in buffers {
4619 device.delete_pbo(buffer.pbo)
4620 }
4621 }
4622 for pbo in self.orphaned_buffers.drain(..) {
4623 device.delete_pbo(pbo);
4624 }
4625 }
4626}
4627
4628pub struct TextureUploader<'a> {
4632 buffers: Vec<PixelBuffer<'a>>,
4634 pub pbo_pool: &'a mut UploadPBOPool,
4636}
4637
4638impl<'a> Drop for TextureUploader<'a> {
4639 fn drop(&mut self) {
4640 assert!(
4641 thread::panicking() || self.buffers.is_empty(),
4642 "TextureUploader must be flushed before it is dropped."
4643 );
4644 }
4645}
4646
4647#[derive(Debug)]
4650pub struct UploadStagingBuffer<'a> {
4651 buffer: PixelBuffer<'a>,
4653 offset: usize,
4655 size: usize,
4657 stride: usize,
4659}
4660
4661impl<'a> UploadStagingBuffer<'a> {
4662 pub fn get_stride(&self) -> usize {
4664 self.stride
4665 }
4666
4667 pub fn get_mapping(&mut self) -> &mut [mem::MaybeUninit<u8>] {
4669 &mut self.buffer.mapping[self.offset..self.offset + self.size]
4670 }
4671}
4672
4673impl<'a> TextureUploader<'a> {
4674 pub fn stage(
4677 &mut self,
4678 device: &mut Device,
4679 format: ImageFormat,
4680 size: DeviceIntSize,
4681 ) -> Result<UploadStagingBuffer<'a>, String> {
4682 assert!(matches!(device.upload_method, UploadMethod::PixelBuffer(_)), "Texture uploads should only be staged when using pixel buffers.");
4683
4684 let (dst_size, dst_stride) = device.required_upload_size_and_stride(
4687 size,
4688 format,
4689 );
4690
4691 let buffer_index = self.buffers.iter().position(|buffer| {
4693 buffer.size_used + dst_size <= buffer.inner.pbo.reserved_size
4694 });
4695 let buffer = match buffer_index {
4696 Some(i) => self.buffers.swap_remove(i),
4697 None => PixelBuffer::new(self.pbo_pool.get_pbo(device, dst_size)?),
4698 };
4699
4700 if !device.capabilities.supports_nonzero_pbo_offsets {
4701 assert_eq!(buffer.size_used, 0, "PBO uploads from non-zero offset are not supported.");
4702 }
4703 assert!(buffer.size_used + dst_size <= buffer.inner.pbo.reserved_size, "PixelBuffer is too small");
4704
4705 let offset = buffer.size_used;
4706
4707 Ok(UploadStagingBuffer {
4708 buffer,
4709 offset,
4710 size: dst_size,
4711 stride: dst_stride,
4712 })
4713 }
4714
4715 pub fn upload_staged(
4717 &mut self,
4718 device: &mut Device,
4719 texture: &'a Texture,
4720 rect: DeviceIntRect,
4721 format_override: Option<ImageFormat>,
4722 mut staging_buffer: UploadStagingBuffer<'a>,
4723 ) -> usize {
4724 let size = staging_buffer.size;
4725
4726 staging_buffer.buffer.chunks.push(UploadChunk {
4727 rect,
4728 stride: Some(staging_buffer.stride as i32),
4729 offset: staging_buffer.offset,
4730 format_override,
4731 texture,
4732 });
4733 staging_buffer.buffer.size_used += staging_buffer.size;
4734
4735 if staging_buffer.buffer.size_used < staging_buffer.buffer.inner.pbo.reserved_size {
4737 self.buffers.push(staging_buffer.buffer);
4738 } else {
4739 Self::flush_buffer(device, self.pbo_pool, staging_buffer.buffer);
4740 }
4741
4742 size
4743 }
4744
4745 pub fn upload<T>(
4747 &mut self,
4748 device: &mut Device,
4749 texture: &'a Texture,
4750 mut rect: DeviceIntRect,
4751 stride: Option<i32>,
4752 format_override: Option<ImageFormat>,
4753 data: *const T,
4754 len: usize,
4755 ) -> usize {
4756 let cropped = rect.intersection(
4759 &DeviceIntRect::from_size(texture.get_dimensions())
4760 );
4761 if cfg!(debug_assertions) && cropped.map_or(true, |r| r != rect) {
4762 warn!("Cropping texture upload {:?} to {:?}", rect, cropped);
4763 }
4764 rect = match cropped {
4765 None => return 0,
4766 Some(r) => r,
4767 };
4768
4769 let bytes_pp = texture.format.bytes_per_pixel() as usize;
4770 let width_bytes = rect.width() as usize * bytes_pp;
4771
4772 let src_stride = stride.map_or(width_bytes, |stride| {
4773 assert!(stride >= 0);
4774 stride as usize
4775 });
4776 let src_size = (rect.height() as usize - 1) * src_stride + width_bytes;
4777 assert!(src_size <= len * mem::size_of::<T>());
4778
4779 match device.upload_method {
4780 UploadMethod::Immediate => {
4781 if cfg!(debug_assertions) {
4782 let mut bound_buffer = [0];
4783 unsafe {
4784 device.gl.get_integer_v(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut bound_buffer);
4785 }
4786 assert_eq!(bound_buffer[0], 0, "GL_PIXEL_UNPACK_BUFFER must not be bound for immediate uploads.");
4787 }
4788
4789 Self::update_impl(device, UploadChunk {
4790 rect,
4791 stride: Some(src_stride as i32),
4792 offset: data as _,
4793 format_override,
4794 texture,
4795 });
4796
4797 width_bytes * rect.height() as usize
4798 }
4799 UploadMethod::PixelBuffer(_) => {
4800 let mut staging_buffer = match self.stage(device, texture.format, rect.size()) {
4801 Ok(staging_buffer) => staging_buffer,
4802 Err(_) => return 0,
4803 };
4804 let dst_stride = staging_buffer.get_stride();
4805
4806 unsafe {
4807 let src: &[mem::MaybeUninit<u8>] = slice::from_raw_parts(data as *const _, src_size);
4808
4809 if src_stride == dst_stride {
4810 staging_buffer.get_mapping()[..src_size].copy_from_slice(src);
4813 } else {
4814 for y in 0..rect.height() as usize {
4817 let src_start = y * src_stride;
4818 let src_end = src_start + width_bytes;
4819 let dst_start = y * staging_buffer.get_stride();
4820 let dst_end = dst_start + width_bytes;
4821
4822 staging_buffer.get_mapping()[dst_start..dst_end].copy_from_slice(&src[src_start..src_end])
4823 }
4824 }
4825 }
4826
4827 self.upload_staged(device, texture, rect, format_override, staging_buffer)
4828 }
4829 }
4830 }
4831
4832 fn flush_buffer(device: &mut Device, pbo_pool: &mut UploadPBOPool, mut buffer: PixelBuffer) {
4833 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer.inner.pbo.id);
4834 match buffer.inner.mapping {
4835 PBOMapping::Unmapped => unreachable!("UploadPBO should be mapped at this stage."),
4836 PBOMapping::Transient(_) => {
4837 device.gl.unmap_buffer(gl::PIXEL_UNPACK_BUFFER);
4838 buffer.inner.mapping = PBOMapping::Unmapped;
4839 }
4840 PBOMapping::Persistent(_) => {
4841 device.gl.flush_mapped_buffer_range(gl::PIXEL_UNPACK_BUFFER, 0, buffer.size_used as _);
4842 }
4843 }
4844 buffer.flush_chunks(device);
4845 let pbo = mem::replace(&mut buffer.inner, UploadPBO::empty());
4846 pbo_pool.return_pbo(device, pbo);
4847 }
4848
4849 pub fn flush(mut self, device: &mut Device) {
4852 for buffer in self.buffers.drain(..) {
4853 Self::flush_buffer(device, self.pbo_pool, buffer);
4854 }
4855
4856 device.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
4857 }
4858
4859 fn update_impl(device: &mut Device, chunk: UploadChunk) {
4860 device.bind_texture(DEFAULT_TEXTURE, chunk.texture, Swizzle::default());
4861
4862 let format = chunk.format_override.unwrap_or(chunk.texture.format);
4863 let (gl_format, bpp, data_type) = match format {
4864 ImageFormat::R8 => (gl::RED, 1, gl::UNSIGNED_BYTE),
4865 ImageFormat::R16 => (gl::RED, 2, gl::UNSIGNED_SHORT),
4866 ImageFormat::BGRA8 => (device.bgra_formats.external, 4, device.bgra_pixel_type),
4867 ImageFormat::RGBA8 => (gl::RGBA, 4, gl::UNSIGNED_BYTE),
4868 ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
4869 ImageFormat::RG16 => (gl::RG, 4, gl::UNSIGNED_SHORT),
4870 ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
4871 ImageFormat::RGBAI32 => (gl::RGBA_INTEGER, 16, gl::INT),
4872 };
4873
4874 let row_length = match chunk.stride {
4875 Some(value) => value / bpp,
4876 None => chunk.texture.size.width,
4877 };
4878
4879 if chunk.stride.is_some() {
4880 device.gl.pixel_store_i(
4881 gl::UNPACK_ROW_LENGTH,
4882 row_length as _,
4883 );
4884 }
4885
4886 let pos = chunk.rect.min;
4887 let size = chunk.rect.size();
4888
4889 match chunk.texture.target {
4890 gl::TEXTURE_2D | gl::TEXTURE_RECTANGLE | gl::TEXTURE_EXTERNAL_OES => {
4891 device.gl.tex_sub_image_2d_pbo(
4892 chunk.texture.target,
4893 0,
4894 pos.x as _,
4895 pos.y as _,
4896 size.width as _,
4897 size.height as _,
4898 gl_format,
4899 data_type,
4900 chunk.offset,
4901 );
4902 }
4903 _ => panic!("BUG: Unexpected texture target!"),
4904 }
4905
4906 if chunk.texture.filter == TextureFilter::Trilinear {
4908 device.gl.generate_mipmap(chunk.texture.target);
4909 }
4910
4911 if chunk.stride.is_some() {
4913 device.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, 0 as _);
4914 }
4915 }
4916}
4917
4918fn texels_to_u8_slice<T: Texel>(texels: &[T]) -> &[u8] {
4919 unsafe {
4920 slice::from_raw_parts(texels.as_ptr() as *const u8, texels.len() * mem::size_of::<T>())
4921 }
4922}