New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added ordered dithering to gradient-like effects #966
Changes from 1 commit
File filter...
Jump to…
Add ordered dithering to gradient-like effects
- Loading branch information
| @@ -27,7 +27,7 @@ void main(void) { | ||
| vEndRadius = gradient.start_end_radius_extend_mode.y; | ||
|
|
||
| // V coordinate of gradient row in lookup texture. | ||
| vGradientIndex = float(prim.sub_index) + 0.5; | ||
| vGradientIndex = float(prim.sub_index) * 2.0 + 0.5; | ||
kvark
Member
|
||
|
|
||
| // Whether to repeat the gradient instead of clamping. | ||
| vGradientRepeat = float(int(gradient.start_end_radius_extend_mode.z) == EXTEND_MODE_REPEAT); | ||
| @@ -1547,6 +1547,10 @@ impl Device { | ||
| if u_color_2 != -1 { | ||
| self.gl.uniform_1i(u_color_2, TextureSampler::Color2 as i32); | ||
| } | ||
| let u_noise = self.gl.get_uniform_location(program.id, "sDither"); | ||
| if u_noise != -1 { | ||
| self.gl.uniform_1i(u_noise, TextureSampler::Dither as i32); | ||
| } | ||
| let u_mask = self.gl.get_uniform_location(program.id, "sMask"); | ||
| if u_mask != -1 { | ||
| self.gl.uniform_1i(u_mask, TextureSampler::Mask as i32); | ||
| @@ -1713,7 +1717,7 @@ impl Device { | ||
| } | ||
| ImageFormat::RGB8 => (gl::RGB, 3, data), | ||
| ImageFormat::RGBA8 => (get_gl_format_bgra(self.gl()), 4, data), | ||
| ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), | ||
| ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), | ||
|
||
| }; | ||
|
|
||
| let row_length = match stride { | ||
| @@ -2099,6 +2103,7 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: | ||
| } | ||
| } | ||
| } | ||
| ImageFormat::RGBA16 => (gl::RGBA16UI as gl::GLint, gl::RGBA_INTEGER), | ||
kvark
Member
|
||
| ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA), | ||
| ImageFormat::Invalid => unreachable!(), | ||
| } | ||
| @@ -2107,6 +2112,7 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: | ||
| fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint { | ||
| match format { | ||
| ImageFormat::RGBAF32 => gl::FLOAT, | ||
| ImageFormat::RGBA16 => gl::UNSIGNED_SHORT, | ||
| _ => gl::UNSIGNED_BYTE, | ||
| } | ||
| } | ||
| @@ -30,6 +30,7 @@ pub trait GpuStoreLayout { | ||
| fn texel_size() -> usize { | ||
| match Self::image_format() { | ||
| ImageFormat::RGBA8 => 4, | ||
| ImageFormat::RGBA16 => 8, | ||
| ImageFormat::RGBAF32 => 16, | ||
| _ => unreachable!(), | ||
| } | ||
| @@ -45,6 +46,10 @@ pub trait GpuStoreLayout { | ||
| fn items_per_row<T>() -> usize { | ||
| Self::texture_width::<T>() / Self::texels_per_item::<T>() | ||
| } | ||
|
|
||
| fn rows_per_item<T>() -> usize { | ||
| Self::texels_per_item::<T>() / Self::texture_width::<T>() | ||
| } | ||
| } | ||
|
|
||
| /// A CPU-side buffer storing content to be uploaded to the GPU. | ||
| @@ -81,8 +86,10 @@ impl<T: Clone + Default, L: GpuStoreLayout> GpuStore<T, L> { | ||
| // Extend the data array to be a multiple of the row size. | ||
| // This ensures memory safety when the array is passed to | ||
| // OpenGL to upload to the GPU. | ||
| while items.len() % items_per_row != 0 { | ||
| items.push(T::default()); | ||
| if items_per_row != 0 { | ||
| while items_per_row != 0 && items.len() % items_per_row != 0 { | ||
kvark
Member
|
||
| items.push(T::default()); | ||
| } | ||
| } | ||
|
|
||
| items | ||
| @@ -170,6 +170,7 @@ impl GLContextWrapper { | ||
| } | ||
|
|
||
| const COLOR_FLOAT_TO_FIXED: f32 = 255.0; | ||
| const COLOR_FLOAT_TO_FIXED_WIDE: f32 = 65535.0; | ||
| pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0; | ||
|
|
||
| pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; | ||
| @@ -198,6 +199,7 @@ pub enum TextureSampler { | ||
| Geometry, | ||
| ResourceRects, | ||
| Gradients, | ||
| Dither, | ||
| } | ||
|
|
||
| impl TextureSampler { | ||
| @@ -313,14 +315,23 @@ pub struct PackedTexel { | ||
| } | ||
|
|
||
| impl PackedTexel { | ||
| pub fn from_color(color: &ColorF) -> PackedTexel { | ||
| pub fn high_bytes(color: &ColorF) -> PackedTexel { | ||
| PackedTexel { | ||
| b: (0.5 + color.b * COLOR_FLOAT_TO_FIXED).floor() as u8, | ||
| g: (0.5 + color.g * COLOR_FLOAT_TO_FIXED).floor() as u8, | ||
| r: (0.5 + color.r * COLOR_FLOAT_TO_FIXED).floor() as u8, | ||
| a: (0.5 + color.a * COLOR_FLOAT_TO_FIXED).floor() as u8, | ||
| } | ||
| } | ||
|
|
||
| pub fn low_bytes(color: &ColorF) -> PackedTexel { | ||
| PackedTexel { | ||
| b: ((0.5 + color.b * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, | ||
kvark
Member
|
||
| g: ((0.5 + color.g * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, | ||
| r: ((0.5 + color.r * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, | ||
| a: ((0.5 + color.a * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug, Clone, Copy)] | ||
| @@ -154,15 +154,22 @@ impl<L: GpuStoreLayout> GpuDataTexture<L> { | ||
| } | ||
|
|
||
| let items_per_row = L::items_per_row::<T>(); | ||
| let rows_per_item = L::rows_per_item::<T>(); | ||
|
|
||
| // Extend the data array to be a multiple of the row size. | ||
| // This ensures memory safety when the array is passed to | ||
| // OpenGL to upload to the GPU. | ||
| while data.len() % items_per_row != 0 { | ||
| data.push(T::default()); | ||
| if items_per_row != 0 { | ||
| while data.len() % items_per_row != 0 { | ||
| data.push(T::default()); | ||
| } | ||
| } | ||
|
|
||
| let height = data.len() / items_per_row; | ||
| let height = if items_per_row != 0 { | ||
| data.len() / items_per_row | ||
| } else { | ||
| data.len() * rows_per_item | ||
squarewave
Author
Contributor
|
||
| }; | ||
|
|
||
| device.init_texture(self.id, | ||
| L::texture_width::<T>() as u32, | ||
| @@ -201,7 +208,7 @@ impl GpuStoreLayout for GradientDataTextureLayout { | ||
| } | ||
|
|
||
| fn texture_width<T>() -> usize { | ||
| mem::size_of::<GradientData>() / Self::texel_size() | ||
| mem::size_of::<GradientData>() / Self::texel_size() / 2 | ||
| } | ||
|
|
||
| fn texture_filter() -> TextureFilter { | ||
| @@ -513,6 +520,8 @@ pub struct Renderer { | ||
| /// when no target is yet provided as a cache texture input. | ||
| dummy_cache_texture_id: TextureId, | ||
|
|
||
| dither_matrix_texture_id: TextureId, | ||
|
|
||
| /// Optional trait object that allows the client | ||
| /// application to provide external buffers for image data. | ||
| external_image_handler: Option<Box<ExternalImageHandler>>, | ||
| @@ -749,6 +758,18 @@ impl Renderer { | ||
| 0xff, 0xff, | ||
| 0xff, 0xff, | ||
| ]; | ||
|
|
||
| let dither_matrix: [u8; 64] = [ | ||
| 00, 48, 12, 60, 03, 51, 15, 63, | ||
| 32, 16, 44, 28, 35, 19, 47, 31, | ||
| 08, 56, 04, 52, 11, 59, 07, 55, | ||
| 40, 24, 36, 20, 43, 27, 39, 23, | ||
| 02, 50, 14, 62, 01, 49, 13, 61, | ||
| 34, 18, 46, 30, 33, 17, 45, 29, | ||
| 10, 58, 06, 54, 09, 57, 05, 53, | ||
| 42, 26, 38, 22, 41, 25, 37, 21 | ||
| ]; | ||
|
|
||
| // TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction! | ||
| let white_image_id = texture_cache.new_item_id(); | ||
| texture_cache.insert(white_image_id, | ||
| @@ -773,6 +794,15 @@ impl Renderer { | ||
| RenderTargetMode::LayerRenderTarget(1), | ||
| None); | ||
|
|
||
| let dither_matrix_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0]; | ||
| device.init_texture(dither_matrix_texture_id, | ||
| 8, | ||
| 8, | ||
| ImageFormat::A8, | ||
| TextureFilter::Nearest, | ||
| RenderTargetMode::None, | ||
| Some(&dither_matrix)); | ||
|
|
||
| let debug_renderer = DebugRenderer::new(&mut device); | ||
|
|
||
| let gpu_data_textures = [ | ||
| @@ -914,6 +944,7 @@ impl Renderer { | ||
| main_thread_dispatcher: main_thread_dispatcher, | ||
| cache_texture_id_map: Vec::new(), | ||
| dummy_cache_texture_id: dummy_cache_texture_id, | ||
| dither_matrix_texture_id: dither_matrix_texture_id, | ||
| external_image_handler: None, | ||
| external_images: HashMap::with_hasher(Default::default()), | ||
| vr_compositor_handler: vr_compositor, | ||
| @@ -1254,6 +1285,9 @@ impl Renderer { | ||
| self.device.bind_texture(TextureSampler::color(i), texture_id); | ||
| } | ||
|
|
||
| // TODO: this probably isn't the best place for this. | ||
| self.device.bind_texture(TextureSampler::Dither, self.dither_matrix_texture_id); | ||
|
|
||
| self.device.update_vao_instances(vao, data, VertexUsageHint::Stream); | ||
| self.device.draw_indexed_triangles_instanced_u16(6, data.len() as i32); | ||
| self.profile_counters.vertices.add(6 * data.len()); | ||
I think it would be safer to use
gl_FragCoord.xyhere, given that without it you'd be asking for 2 conversions done: float to int and vec4 to vec2, which some GLSL compilers may not appreciate.