1 // Copyright 2015 The Gfx-rs Developers.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #![allow(missing_docs)]
16 
17 use gl;
18 use core::{self as c, command, state as s};
19 use core::target::{ColorValue, Depth, Mirror, Rect, Stencil};
20 use core::texture::TextureCopyRegion;
21 use {Buffer, BufferElement, Program, FrameBuffer, Texture,
22      NewTexture, Resources, PipelineState, ResourceView, TargetView};
23 
24 
primitive_to_gl(primitive: c::Primitive) -> gl::types::GLenum25 fn primitive_to_gl(primitive: c::Primitive) -> gl::types::GLenum {
26     use core::Primitive::*;
27     match primitive {
28         PointList => gl::POINTS,
29         LineList => gl::LINES,
30         LineStrip => gl::LINE_STRIP,
31         TriangleList => gl::TRIANGLES,
32         TriangleStrip => gl::TRIANGLE_STRIP,
33         LineListAdjacency => gl::LINES_ADJACENCY,
34         LineStripAdjacency => gl::LINE_STRIP_ADJACENCY,
35         TriangleListAdjacency => gl::TRIANGLES_ADJACENCY,
36         TriangleStripAdjacency => gl::TRIANGLE_STRIP_ADJACENCY,
37         //TriangleFan => gl::TRIANGLE_FAN,
38         PatchList(_) => gl::PATCHES
39     }
40 }
41 
42 pub type Access = gl::types::GLenum;
43 
44 #[derive(Clone, Copy, Debug)]
45 pub struct RawOffset(pub *const gl::types::GLvoid);
46 unsafe impl Send for RawOffset {}
47 
48 /// The place of some data in the data buffer.
49 #[derive(Clone, Copy, PartialEq, Debug)]
50 pub struct DataPointer {
51     offset: u32,
52     size: u32,
53 }
54 
55 pub struct DataBuffer(Vec<u8>);
56 impl DataBuffer {
57     /// Create a new empty data buffer.
new() -> DataBuffer58     pub fn new() -> DataBuffer {
59         DataBuffer(Vec::new())
60     }
61     /// Copy a given vector slice into the buffer.
add(&mut self, data: &[u8]) -> DataPointer62     fn add(&mut self, data: &[u8]) -> DataPointer {
63         self.0.extend_from_slice(data);
64         DataPointer {
65             offset: (self.0.len() - data.len()) as u32,
66             size: data.len() as u32,
67         }
68     }
69     /// Return a reference to a stored data object.
get(&self, ptr: DataPointer) -> &[u8]70     pub fn get(&self, ptr: DataPointer) -> &[u8] {
71         &self.0[ptr.offset as usize..(ptr.offset + ptr.size) as usize]
72     }
73 }
74 
75 
76 /// Serialized device command.
77 #[derive(Clone, Debug)]
78 pub enum Command {
79     // states
80     BindProgram(Program),
81     BindConstantBuffer(c::pso::ConstantBufferParam<Resources>),
82     BindResourceView(c::pso::ResourceViewParam<Resources>),
83     BindUnorderedView(c::pso::UnorderedViewParam<Resources>),
84     BindSampler(c::pso::SamplerParam<Resources>, Option<gl::types::GLenum>),
85     BindPixelTargets(c::pso::PixelTargetSet<Resources>),
86     BindVao,
87     BindAttribute(c::AttributeSlot, Buffer, BufferElement),
88     UnbindAttribute(c::AttributeSlot),
89     BindIndex(Buffer),
90     BindFrameBuffer(Access, FrameBuffer),
91     BindUniform(c::shade::Location, c::shade::UniformValue),
92     SetDrawColorBuffers(c::ColorSlot),
93     SetRasterizer(s::Rasterizer),
94     SetViewport(Rect),
95     SetScissor(Option<Rect>),
96     SetDepthState(Option<s::Depth>),
97     SetStencilState(Option<s::Stencil>, (Stencil, Stencil), s::CullFace),
98     SetBlendState(c::ColorSlot, s::Color),
99     SetBlendColor(ColorValue),
100     SetPatches(c::PatchSize),
101     SetOutputMasks { color: bool, depth: bool, stencil: bool },
102     CopyBuffer(Buffer, Buffer,
103                gl::types::GLintptr, gl::types::GLintptr,
104                gl::types::GLsizeiptr),
105     CopyBufferToTexture(Buffer, gl::types::GLintptr,
106                         TextureCopyRegion<Texture>),
107     CopyTextureToBuffer(TextureCopyRegion<NewTexture>,
108                         Buffer, gl::types::GLintptr,
109                         FrameBuffer),
110     CopyTextureToTexture(TextureCopyRegion<NewTexture>,
111                          TextureCopyRegion<Texture>,
112                          FrameBuffer),
113     // resource updates
114     UpdateBuffer(Buffer, DataPointer, usize),
115     UpdateTexture(TextureCopyRegion<Texture>, DataPointer),
116     GenerateMipmap(ResourceView),
117     // drawing
118     Clear(Option<command::ClearColor>, Option<Depth>, Option<Stencil>),
119     Draw(gl::types::GLenum, c::VertexCount, c::VertexCount, Option<command::InstanceParams>),
120     DrawIndexed(gl::types::GLenum,
121                 gl::types::GLenum,
122                 RawOffset,
123                 c::VertexCount,
124                 c::VertexCount,
125                 Option<command::InstanceParams>),
126     _Blit(Rect, Rect, Mirror, usize),
127 }
128 
generate_reset() -> Vec<Command>129 pub fn generate_reset() -> Vec<Command> {
130     let color = s::Color {
131         mask: s::ColorMask::all(),
132         blend: None,
133     };
134     vec![
135         Command::BindProgram(0),
136         Command::BindVao,
137         // Command::UnbindAttribute, //not needed, handled by the cache
138         Command::BindIndex(0),
139         Command::BindFrameBuffer(gl::FRAMEBUFFER, 0),
140         Command::SetRasterizer(s::Rasterizer {
141             front_face: s::FrontFace::CounterClockwise,
142             cull_face: s::CullFace::Back,
143             method: s::RasterMethod::Fill,
144             offset: None,
145             samples: None,
146         }),
147         Command::SetViewport(Rect {
148             x: 0,
149             y: 0,
150             w: 0,
151             h: 0,
152         }),
153         Command::SetScissor(None),
154         Command::SetDepthState(None),
155         Command::SetStencilState(None, (0, 0), s::CullFace::Nothing),
156         Command::SetBlendState(0, color),
157         Command::SetBlendState(1, color),
158         Command::SetBlendState(2, color),
159         Command::SetBlendState(3, color),
160         Command::SetBlendColor([0f32; 4]),
161     ]
162 }
163 
164 struct Cache {
165     primitive: gl::types::GLenum,
166     index_type: c::IndexType,
167     current_vbs: Option<c::pso::VertexBufferSet<Resources>>,
168     attributes: [Option<BufferElement>; c::MAX_VERTEX_ATTRIBUTES],
169     resource_binds: [Option<gl::types::GLenum>; c::MAX_RESOURCE_VIEWS],
170     scissor: bool,
171     target_dim: (u16, u16, u16),
172     stencil: Option<s::Stencil>,
173     // blend: Option<s::Blend>,
174     cull_face: s::CullFace,
175     draw_mask: u32,
176 
177     program: Program,
178     constant_buffer: Option<c::pso::ConstantBufferParam<Resources>>,
179     resource_view: Option<c::pso::ResourceViewParam<Resources>>,
180     scissor_test: Option<Rect>,
181     depth_state: Option<s::Depth>,
182     blend_state: Option<(c::ColorSlot, s::Color)>,
183     blend_color: Option<ColorValue>,
184     viewport: Option<Rect>,
185     rasterizer: Option<s::Rasterizer>,
186     framebuffer: Option<(Access, FrameBuffer)>,
187     index: Buffer,
188 }
189 
190 impl Cache {
new() -> Cache191     pub fn new() -> Cache {
192         Cache {
193             primitive: 0,
194             index_type: c::IndexType::U16,
195             current_vbs: None,
196             attributes: [None; c::MAX_VERTEX_ATTRIBUTES],
197             resource_binds: [None; c::MAX_RESOURCE_VIEWS],
198             scissor: false,
199             target_dim: (0, 0, 0),
200             stencil: None,
201             cull_face: s::CullFace::Nothing,
202             // blend: None,
203             draw_mask: 0,
204 
205             program: 0,
206             constant_buffer: None,
207             resource_view: None,
208             scissor_test: None,
209             depth_state: None,
210             blend_state: None,
211             blend_color: None,
212             viewport: None,
213             rasterizer: None,
214             framebuffer: None,
215             index: 0,
216         }
217     }
218 
bind_program(&mut self, program: Program) -> Option<Command>219     fn bind_program(&mut self, program: Program) -> Option<Command> {
220         if program == self.program {
221             return None;
222         }
223         self.program = program;
224         Some(Command::BindProgram(program))
225     }
226 
bind_constant_buffer(&mut self, constant_buffer: c::pso::ConstantBufferParam<Resources>) -> Option<Command>227     fn bind_constant_buffer(&mut self, constant_buffer: c::pso::ConstantBufferParam<Resources>) -> Option<Command> {
228         if self.constant_buffer == Some(constant_buffer) {
229             return None;
230         }
231         self.constant_buffer = Some(constant_buffer);
232         Some(Command::BindConstantBuffer(constant_buffer))
233     }
234 
bind_resource_view(&mut self, resource_view: c::pso::ResourceViewParam<Resources>) -> Option<Command>235     fn bind_resource_view(&mut self, resource_view: c::pso::ResourceViewParam<Resources>) -> Option<Command> {
236         if self.resource_view == Some(resource_view) {
237             return None;
238         }
239         self.resource_view = Some(resource_view);
240         Some(Command::BindResourceView(resource_view))
241     }
242 
bind_index(&mut self, buffer: Buffer, itype: c::IndexType) -> Option<Command>243     fn bind_index(&mut self, buffer: Buffer, itype: c::IndexType) -> Option<Command> {
244         if self.index == buffer && itype == self.index_type {
245             return None;
246         }
247         self.index_type = itype;
248         self.index = buffer;
249         Some(Command::BindIndex(buffer))
250     }
251 
bind_framebuffer(&mut self, access: Access, fb: FrameBuffer) -> Option<Command>252     fn bind_framebuffer(&mut self, access: Access, fb: FrameBuffer) -> Option<Command> {
253         if self.framebuffer == Some((access, fb)) {
254             return None;
255         }
256         self.framebuffer = Some((access, fb));
257         Some(Command::BindFrameBuffer(access, fb))
258     }
259 
set_rasterizer(&mut self, rasterizer: s::Rasterizer) -> Option<Command>260     fn set_rasterizer(&mut self, rasterizer: s::Rasterizer) -> Option<Command> {
261         if self.rasterizer == Some(rasterizer) {
262             return None;
263         }
264         self.rasterizer = Some(rasterizer);
265         Some(Command::SetRasterizer(rasterizer))
266     }
267 
set_viewport(&mut self, rect: Rect) -> Option<Command>268     fn set_viewport(&mut self, rect: Rect) -> Option<Command> {
269         if self.viewport == Some(rect) {
270             return None;
271         }
272         self.viewport = Some(rect);
273         Some(Command::SetViewport(rect))
274     }
275 
set_scissor(&mut self, rect: Option<Rect>) -> Option<Command>276     fn set_scissor(&mut self, rect: Option<Rect>) -> Option<Command> {
277         if self.scissor_test == rect {
278             return None;
279         }
280         self.scissor_test = rect;
281         Some(Command::SetScissor(rect))
282     }
set_depth_state(&mut self, depth: Option<s::Depth>) -> Option<Command>283     fn set_depth_state(&mut self, depth: Option<s::Depth>) -> Option<Command> {
284         if self.depth_state == depth {
285             return None;
286         }
287         self.depth_state = depth;
288         Some(Command::SetDepthState(depth))
289     }
set_stencil_state(&mut self, option_stencil: Option<s::Stencil>, stencils: (Stencil, Stencil), cullface: s:: CullFace) -> Option<Command>290     fn set_stencil_state(&mut self, option_stencil: Option<s::Stencil>, stencils: (Stencil, Stencil), cullface: s:: CullFace) -> Option<Command> {
291         // This is a little more complex 'cause if option_stencil
292         // is None the stencil state is disabled, it it's Some
293         // then it's enabled and parameters are set.
294         // That's actually bad because it makes it impossible
295         // to completely remove all redundant calls if the
296         // stencil is enabled;
297         // we'll be re-enabling it over and over.
298         // For now though, we just don't handle it.
299         Some(Command::SetStencilState(option_stencil, stencils, cullface))
300     }
set_blend_state(&mut self, color_slot: c::ColorSlot, color: s::Color) -> Option<Command>301     fn set_blend_state(&mut self, color_slot: c::ColorSlot, color: s::Color) -> Option<Command> {
302         if self.blend_state == Some((color_slot, color)) {
303             return None;
304         }
305         self.blend_state = Some((color_slot, color));
306         Some(Command::SetBlendState(color_slot, color))
307     }
set_blend_color(&mut self, color_value: ColorValue) -> Option<Command>308     fn set_blend_color(&mut self, color_value: ColorValue) -> Option<Command> {
309         if self.blend_color == Some(color_value) {
310             return None;
311         }
312         self.blend_color = Some(color_value);
313         Some(Command::SetBlendColor(color_value))
314     }
315 }
316 
317 #[derive(Clone, Debug, Default)]
318 pub struct Workarounds {
319     // On some systems (OSX), the driver may still output something even if the shader does not,
320     // so we need to explicitly mask out the outputs according to the views being bound.
321     pub main_fbo_mask: bool,
322 }
323 
324 /// A command buffer abstraction for OpenGL.
325 ///
326 /// Manages a list of commands that will be executed when submitted to a `Device`. Usually it is
327 /// best to use a `Encoder` to manage the command buffer which implements `From<CommandBuffer>`.
328 ///
329 /// If you want to display your rendered results to a framebuffer created externally, see the
330 /// `display_fb` field.
331 pub struct CommandBuffer {
332     pub buf: Vec<Command>,
333     pub data: DataBuffer,
334     fbo: FrameBuffer,
335     /// The framebuffer to use for rendering to the main targets (0 by default).
336     ///
337     /// Use this to set the framebuffer that will be used for the screen display targets created
338     /// with `create_main_targets_raw`. Usually you don't need to set this field directly unless
339     /// your OS doesn't provide a default framebuffer with name 0 and you have to render to a
340     /// different framebuffer object that can be made visible on the screen (iOS/tvOS need this).
341     ///
342     /// This framebuffer must exist and be configured correctly (with renderbuffer attachments,
343     /// etc.) so that rendering to it can occur immediately.
344     pub display_fb: FrameBuffer,
345     cache: Cache,
346     active_attribs: usize,
347     workarounds: Workarounds,
348 }
349 
350 impl CommandBuffer {
new(fbo: FrameBuffer, workarounds: Workarounds) -> CommandBuffer351     pub fn new(fbo: FrameBuffer, workarounds: Workarounds) -> CommandBuffer {
352         CommandBuffer {
353             buf: Vec::new(),
354             data: DataBuffer::new(),
355             fbo,
356             display_fb: 0 as FrameBuffer,
357             cache: Cache::new(),
358             active_attribs: 0,
359             workarounds,
360         }
361     }
is_main_target(&self, tv: Option<TargetView>) -> bool362     fn is_main_target(&self, tv: Option<TargetView>) -> bool {
363         match tv {
364             Some(TargetView::Surface(0)) |
365             None => true,
366             Some(_) => false,
367         }
368     }
369 }
370 
371 impl command::Buffer<Resources> for CommandBuffer {
reset(&mut self)372     fn reset(&mut self) {
373         self.buf.clear();
374         self.data.0.clear();
375         self.cache = Cache::new();
376         self.active_attribs = (1 << c::MAX_VERTEX_ATTRIBUTES) - 1;
377     }
378 
bind_pipeline_state(&mut self, pso: PipelineState)379     fn bind_pipeline_state(&mut self, pso: PipelineState) {
380         let cull = pso.rasterizer.cull_face;
381         self.cache.primitive = primitive_to_gl(pso.primitive);
382         self.cache.attributes = pso.input;
383         self.cache.stencil = pso.output.stencil;
384         self.cache.cull_face = cull;
385         self.cache.draw_mask = pso.output.draw_mask;
386         self.buf.extend(self.cache.bind_program(pso.program));
387         self.cache.scissor = pso.scissor;
388         self.buf.extend(self.cache.set_rasterizer(pso.rasterizer));
389         self.buf.extend(self.cache.set_depth_state(pso.output.depth));
390         self.buf.extend(self.cache.set_stencil_state(pso.output.stencil, (0, 0), cull));
391         for i in 0..c::MAX_COLOR_TARGETS {
392             if pso.output.draw_mask & (1 << i) != 0 {
393                 self.buf.extend(self.cache.set_blend_state(i as c::ColorSlot,
394                                            pso.output.colors[i]));
395             }
396         }
397         if let c::Primitive::PatchList(num) = pso.primitive {
398             self.buf.push(Command::SetPatches(num));
399         }
400     }
401 
bind_vertex_buffers(&mut self, vbs: c::pso::VertexBufferSet<Resources>)402     fn bind_vertex_buffers(&mut self, vbs: c::pso::VertexBufferSet<Resources>) {
403         if self.cache.current_vbs == Some(vbs) {
404             return;
405         }
406         self.cache.current_vbs = Some(vbs);
407         for i in 0..c::MAX_VERTEX_ATTRIBUTES {
408             match (vbs.0[i], self.cache.attributes[i]) {
409                 (None, Some(fm)) => {
410                     error!("No vertex input provided for slot {} of format {:?}", i, fm)
411                 }
412                 (Some((buffer, offset)), Some(mut bel)) => {
413                     bel.elem.offset += offset as gl::types::GLuint;
414                     self.buf.push(Command::BindAttribute(
415                         i as c::AttributeSlot,
416                         buffer,
417                         bel));
418                     self.active_attribs |= 1 << i;
419                 }
420                 (_, None) if self.active_attribs & (1 << i) != 0 => {
421                     self.buf.push(Command::UnbindAttribute(i as c::AttributeSlot));
422                     self.active_attribs ^= 1 << i;
423                 }
424                 (_, None) => (),
425             }
426         }
427     }
428 
bind_constant_buffers(&mut self, cbs: &[c::pso::ConstantBufferParam<Resources>])429     fn bind_constant_buffers(&mut self, cbs: &[c::pso::ConstantBufferParam<Resources>]) {
430         for param in cbs.iter() {
431             self.buf.extend(self.cache.bind_constant_buffer(param.clone()));
432         }
433     }
434 
bind_global_constant(&mut self, loc: c::shade::Location, value: c::shade::UniformValue)435     fn bind_global_constant(&mut self, loc: c::shade::Location, value: c::shade::UniformValue) {
436         self.buf.push(Command::BindUniform(loc, value));
437     }
438 
bind_resource_views(&mut self, srvs: &[c::pso::ResourceViewParam<Resources>])439     fn bind_resource_views(&mut self, srvs: &[c::pso::ResourceViewParam<Resources>]) {
440         for i in 0..c::MAX_RESOURCE_VIEWS {
441             self.cache.resource_binds[i] = None;
442         }
443         for param in srvs.iter() {
444             self.cache.resource_binds[param.2 as usize] = Some(param.0.bind);
445             self.buf.extend(self.cache.bind_resource_view(param.clone()));
446         }
447     }
448 
bind_unordered_views(&mut self, uavs: &[c::pso::UnorderedViewParam<Resources>])449     fn bind_unordered_views(&mut self, uavs: &[c::pso::UnorderedViewParam<Resources>]) {
450         for param in uavs.iter() {
451             self.buf.push(Command::BindUnorderedView(param.clone()));
452         }
453     }
454 
bind_samplers(&mut self, ss: &[c::pso::SamplerParam<Resources>])455     fn bind_samplers(&mut self, ss: &[c::pso::SamplerParam<Resources>]) {
456         for param in ss.iter() {
457             let bind = self.cache.resource_binds[param.2 as usize];
458             self.buf.push(Command::BindSampler(param.clone(), bind));
459         }
460     }
461 
bind_pixel_targets(&mut self, pts: c::pso::PixelTargetSet<Resources>)462     fn bind_pixel_targets(&mut self, pts: c::pso::PixelTargetSet<Resources>) {
463         let is_main = pts.colors.iter().skip(1).find(|c| c.is_some()).is_none() &&
464                       self.is_main_target(pts.colors[0]) &&
465                       self.is_main_target(pts.depth) &&
466                       self.is_main_target(pts.stencil);
467         if is_main {
468             self.buf.extend(self.cache.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.display_fb));
469             if self.workarounds.main_fbo_mask {
470                 // Note: this will only allow less stuff to reach the framebuffer, not more
471                 self.buf.push(Command::SetOutputMasks {
472                     color: pts.colors[0].is_some(),
473                     depth: pts.depth.is_some(),
474                     stencil: pts.stencil.is_some(),
475                 });
476                 // Now that we bound a different mask, invalidate the cached states.
477                 if pts.colors[0].is_none() {
478                     self.cache.blend_state = None;
479                 }
480                 if pts.depth.is_none() {
481                     self.cache.depth_state = None;
482                 }
483                 if pts.stencil.is_none() {
484                     //self.cache.stencil_state = None;
485                 }
486             }
487         } else {
488             let num = pts.colors
489                 .iter()
490                 .position(|c| c.is_none())
491                 .unwrap_or(pts.colors.len()) as c::ColorSlot;
492             self.buf.extend(self.cache.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.fbo));
493             self.buf.push(Command::BindPixelTargets(pts));
494             self.buf.push(Command::SetDrawColorBuffers(num));
495         }
496         let view = pts.get_view();
497         self.cache.target_dim = view;
498         self.buf.extend(
499             self.cache.set_viewport(Rect {
500                                     x: 0,
501                                     y: 0,
502                                     w: view.0,
503                                     h: view.1,
504                                 }));
505     }
506 
bind_index(&mut self, buf: Buffer, itype: c::IndexType)507     fn bind_index(&mut self, buf: Buffer, itype: c::IndexType) {
508         self.buf.extend(self.cache.bind_index(buf, itype));
509     }
510 
set_scissor(&mut self, rect: Rect)511     fn set_scissor(&mut self, rect: Rect) {
512         use std::cmp;
513         let scissor = self.cache.scissor;
514         let target_dim = self.cache.target_dim;
515         let scissor_rect = if scissor {
516            Some(Rect {
517                // inverting the Y axis in order to match D3D11
518                y: cmp::max(target_dim.1, rect.y + rect.h) -
519                    rect.y -
520                    rect.h,
521                ..rect
522            })
523        } else {
524             None //TODO: assert?
525        };
526         self.buf.extend(self.cache.set_scissor(scissor_rect));
527     }
528 
set_ref_values(&mut self, rv: s::RefValues)529     fn set_ref_values(&mut self, rv: s::RefValues) {
530         let stencil = self.cache.stencil;
531         let cull_face = self.cache.cull_face;
532         self.buf.extend(self.cache.set_stencil_state(stencil,
533                                                      rv.stencil,
534                                                      cull_face));
535         self.buf.extend(self.cache.set_blend_color(rv.blend));
536     }
537 
copy_buffer(&mut self, src: Buffer, dst: Buffer, src_offset_bytes: usize, dst_offset_bytes: usize, size_bytes: usize)538     fn copy_buffer(&mut self,
539                    src: Buffer,
540                    dst: Buffer,
541                    src_offset_bytes: usize,
542                    dst_offset_bytes: usize,
543                    size_bytes: usize) {
544         self.buf.push(Command::CopyBuffer(src, dst,
545                                           src_offset_bytes as gl::types::GLintptr,
546                                           dst_offset_bytes as gl::types::GLintptr,
547                                           size_bytes as gl::types::GLsizeiptr));
548     }
549 
copy_buffer_to_texture(&mut self, src: Buffer, src_offset_bytes: usize, dst: TextureCopyRegion<NewTexture>)550     fn copy_buffer_to_texture(&mut self,
551                               src: Buffer, src_offset_bytes: usize,
552                               dst: TextureCopyRegion<NewTexture>) {
553         match dst.texture {
554             NewTexture::Texture(raw) => {
555                 let dst = dst.with_texture(raw);
556                 self.buf.push(Command::CopyBufferToTexture(
557                     src, src_offset_bytes as _, dst
558                 ));
559             }
560             NewTexture::Surface(s) => {
561                 error!("GL: Cannot copy to a Surface({})", s)
562             }
563         }
564     }
565 
copy_texture_to_buffer(&mut self, src: TextureCopyRegion<NewTexture>, dst: Buffer, dst_offset_bytes: usize)566     fn copy_texture_to_buffer(&mut self,
567                               src: TextureCopyRegion<NewTexture>,
568                               dst: Buffer, dst_offset_bytes: usize) {
569         self.buf.push(Command::CopyTextureToBuffer(
570             src, dst, dst_offset_bytes as _, self.fbo
571         ));
572         self.cache.framebuffer = None; // reset in the cache
573     }
574 
copy_texture_to_texture(&mut self, src: TextureCopyRegion<NewTexture>, dst: TextureCopyRegion<NewTexture>)575     fn copy_texture_to_texture(&mut self,
576                                src: TextureCopyRegion<NewTexture>,
577                                dst: TextureCopyRegion<NewTexture>) {
578         match dst.texture {
579             NewTexture::Texture(raw) => {
580                 let dst = dst.with_texture(raw);
581                 self.buf.push(Command::CopyTextureToTexture(src, dst, self.fbo));
582                 self.cache.framebuffer = None; // reset in the cache
583             }
584             NewTexture::Surface(s) => {
585                 error!("GL: Cannot copy to a Surface({})", s)
586             }
587         }
588     }
589 
update_buffer(&mut self, buf: Buffer, data: &[u8], offset_bytes: usize)590     fn update_buffer(&mut self, buf: Buffer, data: &[u8], offset_bytes: usize) {
591         let ptr = self.data.add(data);
592         self.buf.push(Command::UpdateBuffer(buf, ptr, offset_bytes));
593     }
594 
update_texture(&mut self, dst: TextureCopyRegion<NewTexture>, data: &[u8])595     fn update_texture(&mut self,
596                       dst: TextureCopyRegion<NewTexture>,
597                       data: &[u8]) {
598         let ptr = self.data.add(data);
599         match dst.texture {
600             NewTexture::Texture(raw) => {
601                 let dst = dst.with_texture(raw);
602                 self.buf.push(Command::UpdateTexture(dst, ptr))
603             }
604             NewTexture::Surface(s) => {
605                 error!("GL: unable to update the contents of a Surface({})", s)
606             }
607         }
608     }
609 
generate_mipmap(&mut self, srv: ResourceView)610     fn generate_mipmap(&mut self, srv: ResourceView) {
611         self.buf.push(Command::GenerateMipmap(srv));
612     }
613 
clear_color(&mut self, target: TargetView, value: command::ClearColor)614     fn clear_color(&mut self, target: TargetView, value: command::ClearColor) {
615         // this could be optimized by deferring the actual clear call
616         let mut pts = c::pso::PixelTargetSet::new();
617         pts.colors[0] = Some(target);
618         self.bind_pixel_targets(pts);
619         self.buf.push(Command::Clear(Some(value), None, None));
620     }
621 
clear_depth_stencil(&mut self, target: TargetView, depth: Option<Depth>, stencil: Option<Stencil>)622     fn clear_depth_stencil(&mut self,
623                            target: TargetView,
624                            depth: Option<Depth>,
625                            stencil: Option<Stencil>) {
626         let mut pts = c::pso::PixelTargetSet::new();
627         if depth.is_some() {
628             pts.depth = Some(target);
629         }
630         if stencil.is_some() {
631             pts.stencil = Some(target);
632         }
633         self.bind_pixel_targets(pts);
634         self.buf.push(Command::Clear(None, depth, stencil));
635     }
636 
call_draw(&mut self, start: c::VertexCount, count: c::VertexCount, instances: Option<command::InstanceParams>)637     fn call_draw(&mut self,
638                  start: c::VertexCount,
639                  count: c::VertexCount,
640                  instances: Option<command::InstanceParams>) {
641         self.buf.push(Command::Draw(self.cache.primitive, start, count, instances));
642     }
643 
call_draw_indexed(&mut self, start: c::VertexCount, count: c::VertexCount, base: c::VertexCount, instances: Option<command::InstanceParams>)644     fn call_draw_indexed(&mut self,
645                          start: c::VertexCount,
646                          count: c::VertexCount,
647                          base: c::VertexCount,
648                          instances: Option<command::InstanceParams>) {
649         let (offset, gl_index) = match self.cache.index_type {
650             c::IndexType::U16 => (start * 2u32, gl::UNSIGNED_SHORT),
651             c::IndexType::U32 => (start * 4u32, gl::UNSIGNED_INT),
652         };
653         self.buf.push(
654                   Command::DrawIndexed(
655                       self.cache.primitive,
656                       gl_index,
657                       RawOffset(offset as *const gl::types::GLvoid),
658                       count,
659                       base,
660                       instances));
661     }
662 }
663