1use std::ptr;
2use std::fmt;
3use std::error::Error;
4
5use crate::pixel_buffer::PixelBuffer;
6use crate::texture::ClientFormat;
7use crate::texture::PixelValue;
8use crate::image_format::{TextureFormatRequest, TextureFormat};
9
10use crate::fbo;
11use crate::fbo::FramebuffersContainer;
12
13use crate::buffer::BufferAny;
14use crate::BufferExt;
15use crate::Rect;
16use crate::context::CommandContext;
17use crate::gl;
18
19use crate::version::Version;
20use crate::version::Api;
21
22pub enum Source<'a> {
24 Attachment(&'a fbo::RegularAttachment<'a>),
26 DefaultFramebuffer(gl::types::GLenum),
28}
29
30impl<'a> From<&'a fbo::RegularAttachment<'a>> for Source<'a> {
31 #[inline]
32 fn from(a: &'a fbo::RegularAttachment<'a>) -> Source<'a> {
33 Source::Attachment(a)
34 }
35}
36
37pub enum Destination<'a, P> where P: PixelValue {
39 Memory(&'a mut Vec<P>),
40 PixelBuffer(&'a PixelBuffer<P>),
41 }
43
44impl<'a, P> From<&'a mut Vec<P>> for Destination<'a, P> where P: PixelValue {
45 #[inline]
46 fn from(mem: &'a mut Vec<P>) -> Destination<'a, P> {
47 Destination::Memory(mem)
48 }
49}
50
51impl<'a, P> From<&'a PixelBuffer<P>> for Destination<'a, P> where P: PixelValue {
52 #[inline]
53 fn from(pb: &'a PixelBuffer<P>) -> Destination<'a, P> {
54 Destination::PixelBuffer(pb)
55 }
56}
57
58#[derive(Debug)]
60pub enum ReadError {
61 OutputFormatNotSupported,
66
67 AttachmentTypeNotSupported,
72
73 ClampingNotSupported,
75
76 }
78
79impl fmt::Display for ReadError {
80 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
81 use self::ReadError::*;
82 let desc = match *self {
83 OutputFormatNotSupported =>
84 "The implementation doesn't support converting to the requested output format",
85 AttachmentTypeNotSupported =>
86 "The implementation doesn't support reading a depth, depth-stencil or stencil attachment",
87 ClampingNotSupported =>
88 "Clamping the values is not supported by the implementation",
89 };
90 fmt.write_str(desc)
91 }
92}
93
94impl Error for ReadError {}
95
96#[inline]
103pub fn read<'a, S, D, T>(mut ctxt: &mut CommandContext<'_>, source: S, rect: &Rect, dest: D,
104 clamp: bool) -> Result<(), ReadError>
105 where S: Into<Source<'a>>, D: Into<Destination<'a, T>>,
106 T: PixelValue
107{
108 let source = source.into();
109 let dest = dest.into();
110 let output_pixel_format = <T as PixelValue>::get_format();
111
112 let pixels_to_read = rect.width * rect.height;
113
114 if ctxt.version >= &Version(Api::GlEs, 2, 0) && output_pixel_format != ClientFormat::U8U8U8U8 {
118 return Err(ReadError::OutputFormatNotSupported);
121 }
122
123 if ctxt.version >= &Version(Api::Gl, 3, 0) {
125 unsafe {
126 if clamp && ctxt.state.clamp_color != gl::TRUE as gl::types::GLenum {
127 ctxt.gl.ClampColor(gl::CLAMP_READ_COLOR, gl::TRUE as gl::types::GLenum);
128 ctxt.state.clamp_color = gl::TRUE as gl::types::GLenum;
129
130 } else if !clamp && ctxt.state.clamp_color != gl::FALSE as gl::types::GLenum {
131 ctxt.gl.ClampColor(gl::CLAMP_READ_COLOR, gl::FALSE as gl::types::GLenum);
132 ctxt.state.clamp_color = gl::FALSE as gl::types::GLenum;
133 }
134 }
135 } else if clamp {
136 return Err(ReadError::ClampingNotSupported);
137 }
138
139 match source {
143 Source::Attachment(attachment) => {
144 unsafe { FramebuffersContainer::bind_framebuffer_for_reading(&mut ctxt, attachment) };
145 },
146 Source::DefaultFramebuffer(read_buffer) => {
147 FramebuffersContainer::bind_default_framebuffer_for_reading(&mut ctxt, read_buffer);
148 },
149 };
150
151 enum ReadSourceType { Color, Depth, Stencil, DepthStencil }
153 let (integer, read_src_type) = match source {
154 Source::Attachment(attachment) => {
155 match attachment {
156 fbo::RegularAttachment::Texture(ref tex) => {
157 let integer = match tex.get_texture().get_requested_format() {
158 TextureFormatRequest::Specific(TextureFormat::UncompressedIntegral(_)) => true,
159 TextureFormatRequest::Specific(TextureFormat::UncompressedUnsigned(_)) => true,
160 TextureFormatRequest::AnyIntegral => true,
161 TextureFormatRequest::AnyUnsigned => true,
162 _ => false,
163 };
164
165 (integer, ReadSourceType::Color) },
167 fbo::RegularAttachment::RenderBuffer(ref rb) => {
168 (false, ReadSourceType::Color) },
170 }
171 },
172 Source::DefaultFramebuffer(read_buffer) => {
173 (false, ReadSourceType::Color) },
175 };
176
177 if ctxt.version >= &Version(Api::GlEs, 2, 0) {
179 match read_src_type {
180 ReadSourceType::Color => (),
181 ReadSourceType::Depth => if !ctxt.extensions.gl_nv_read_depth {
182 return Err(ReadError::AttachmentTypeNotSupported);
183 },
184 ReadSourceType::DepthStencil => if !ctxt.extensions.gl_nv_read_depth_stencil {
185 return Err(ReadError::AttachmentTypeNotSupported);
186 },
187 ReadSourceType::Stencil => if !ctxt.extensions.gl_nv_read_stencil {
188 return Err(ReadError::AttachmentTypeNotSupported);
189 },
190 }
191 }
192
193 let (format, gltype) = match read_src_type {
195 ReadSourceType::Color => {
196 client_format_to_gl_enum(&output_pixel_format, integer)
197 },
198 ReadSourceType::Depth => {
199 unimplemented!() },
203 ReadSourceType::DepthStencil => unimplemented!(), ReadSourceType::Stencil => {
205 unimplemented!() },
208 };
209
210 unsafe {
212 match dest {
213 Destination::Memory(dest) => {
214 let mut buf = Vec::with_capacity(pixels_to_read as usize);
215
216 BufferAny::unbind_pixel_pack(ctxt);
217
218 let ptr = buf.as_mut_ptr() as *mut D;
220 let ptr = ptr as usize;
221 if (ptr % 8) == 0 {
222 } else if (ptr % 4) == 0 && ctxt.state.pixel_store_pack_alignment != 4 {
223 ctxt.state.pixel_store_pack_alignment = 4;
224 ctxt.gl.PixelStorei(gl::PACK_ALIGNMENT, 4);
225 } else if (ptr % 2) == 0 && ctxt.state.pixel_store_pack_alignment > 2 {
226 ctxt.state.pixel_store_pack_alignment = 2;
227 ctxt.gl.PixelStorei(gl::PACK_ALIGNMENT, 2);
228 } else if ctxt.state.pixel_store_pack_alignment != 1 {
229 ctxt.state.pixel_store_pack_alignment = 1;
230 ctxt.gl.PixelStorei(gl::PACK_ALIGNMENT, 1);
231 }
232
233 ctxt.gl.ReadPixels(rect.left as gl::types::GLint, rect.bottom as gl::types::GLint,
234 rect.width as gl::types::GLsizei,
235 rect.height as gl::types::GLsizei, format, gltype,
236 buf.as_mut_ptr() as *mut _);
237 buf.set_len(pixels_to_read as usize);
238
239 *dest = buf;
240 },
241
242 Destination::PixelBuffer(pixel_buffer) => {
243 assert!(pixel_buffer.len() >= pixels_to_read as usize);
244
245 pixel_buffer.prepare_and_bind_for_pixel_pack(&mut ctxt);
246 ctxt.gl.ReadPixels(rect.left as gl::types::GLint, rect.bottom as gl::types::GLint,
247 rect.width as gl::types::GLsizei,
248 rect.height as gl::types::GLsizei, format, gltype,
249 ptr::null_mut());
250
251 crate::pixel_buffer::store_infos(pixel_buffer, (rect.width, rect.height));
252 }
253 }
254 };
255
256 Ok(())
257}
258
259fn client_format_to_gl_enum(format: &ClientFormat, integer: bool)
260 -> (gl::types::GLenum, gl::types::GLenum)
261{
262 let (format, ty) = match *format {
263 ClientFormat::U8 => (gl::RED, gl::UNSIGNED_BYTE),
264 ClientFormat::U8U8 => (gl::RG, gl::UNSIGNED_BYTE),
265 ClientFormat::U8U8U8 => (gl::RGB, gl::UNSIGNED_BYTE),
266 ClientFormat::U8U8U8U8 => (gl::RGBA, gl::UNSIGNED_BYTE),
267 ClientFormat::I8 => (gl::RED, gl::BYTE),
268 ClientFormat::I8I8 => (gl::RG, gl::BYTE),
269 ClientFormat::I8I8I8 => (gl::RGB, gl::BYTE),
270 ClientFormat::I8I8I8I8 => (gl::RGBA, gl::BYTE),
271 ClientFormat::U16 => (gl::RED, gl::UNSIGNED_SHORT),
272 ClientFormat::U16U16 => (gl::RG, gl::UNSIGNED_SHORT),
273 ClientFormat::U16U16U16 => (gl::RGB, gl::UNSIGNED_SHORT),
274 ClientFormat::U16U16U16U16 => (gl::RGBA, gl::UNSIGNED_SHORT),
275 ClientFormat::I16 => (gl::RED, gl::SHORT),
276 ClientFormat::I16I16 => (gl::RG, gl::SHORT),
277 ClientFormat::I16I16I16 => (gl::RGB, gl::SHORT),
278 ClientFormat::I16I16I16I16 => (gl::RGBA, gl::SHORT),
279 ClientFormat::U32 => (gl::RED, gl::UNSIGNED_INT),
280 ClientFormat::U32U32 => (gl::RG, gl::UNSIGNED_INT),
281 ClientFormat::U32U32U32 => (gl::RGB, gl::UNSIGNED_INT),
282 ClientFormat::U32U32U32U32 => (gl::RGBA, gl::UNSIGNED_INT),
283 ClientFormat::I32 => (gl::RED, gl::INT),
284 ClientFormat::I32I32 => (gl::RG, gl::INT),
285 ClientFormat::I32I32I32 => (gl::RGB, gl::INT),
286 ClientFormat::I32I32I32I32 => (gl::RGBA, gl::INT),
287 ClientFormat::U3U3U2 => (gl::RGB, gl::UNSIGNED_BYTE_3_3_2),
288 ClientFormat::U5U6U5 => (gl::RGB, gl::UNSIGNED_SHORT_5_6_5),
289 ClientFormat::U4U4U4U4 => (gl::RGBA, gl::UNSIGNED_SHORT_4_4_4_4),
290 ClientFormat::U5U5U5U1 => (gl::RGBA, gl::UNSIGNED_SHORT_5_5_5_1),
291 ClientFormat::U1U5U5U5Reversed => (gl::RGBA, gl::UNSIGNED_SHORT_1_5_5_5_REV),
292 ClientFormat::U10U10U10U2 => (gl::RGBA, gl::UNSIGNED_INT_10_10_10_2),
293 ClientFormat::F16 => (gl::RED, gl::HALF_FLOAT),
294 ClientFormat::F16F16 => (gl::RG, gl::HALF_FLOAT),
295 ClientFormat::F16F16F16 => (gl::RGB, gl::HALF_FLOAT),
296 ClientFormat::F16F16F16F16 => (gl::RGBA, gl::HALF_FLOAT),
297 ClientFormat::F32 => (gl::RED, gl::FLOAT),
298 ClientFormat::F32F32 => (gl::RG, gl::FLOAT),
299 ClientFormat::F32F32F32 => (gl::RGB, gl::FLOAT),
300 ClientFormat::F32F32F32F32 => (gl::RGBA, gl::FLOAT),
301 };
302
303 let format = if integer {
304 match format {
305 gl::RED => gl::RED_INTEGER,
306 gl::RG => gl::RG_INTEGER,
307 gl::RGB => gl::RGB_INTEGER,
308 gl::RGBA => gl::RGBA_INTEGER,
309 _ => unreachable!()
310 }
311 } else {
312 format
313 };
314
315 (format, ty)
316}