[go: up one dir, main page]

gfx_core/
factory.rs

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//! # Resource factory
16//!
17//! This module exposes the `Factory` trait, used for creating and managing graphics resources, and
18//! includes several items to facilitate this.
19
20use std::error::Error;
21use std::{mem, fmt};
22use {buffer, handle, format, mapping, pso, shade, target, texture};
23use {Capabilities, Resources, ShaderSet,
24     VertexShader, HullShader, DomainShader, GeometryShader, PixelShader};
25use memory::{Bind, Usage, Typed, Pod, cast_slice};
26
27/// Error creating either a ShaderResourceView, or UnorderedAccessView.
28#[derive(Clone, Debug, PartialEq)]
29pub enum ResourceViewError {
30    /// The corresponding bind flag is not present in the texture.
31    NoBindFlag,
32    /// Selected channel type is not supported for this texture.
33    Channel(format::ChannelType),
34    /// Selected layer can not be viewed for this texture.
35    Layer(texture::LayerError),
36    /// The backend was refused for some reason.
37    Unsupported,
38}
39
40impl fmt::Display for ResourceViewError {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        match *self {
43            ResourceViewError::Channel(ref channel_type) => write!(f, "{}: {:?}", self.description(), channel_type),
44            ResourceViewError::Layer(ref le) => write!(f, "{}: {}", self.description(), le),
45            _ => write!(f, "{}", self.description())
46        }
47    }
48}
49
50impl Error for ResourceViewError {
51    fn description(&self) -> &str {
52        match *self {
53            ResourceViewError::NoBindFlag => "The corresponding bind flag is not present in the texture",
54            ResourceViewError::Channel(_) => "Selected channel type is not supported for this texture",
55            ResourceViewError::Layer(_) => "Selected layer can not be viewed for this texture",
56            ResourceViewError::Unsupported => "The backend was refused for some reason",
57        }
58    }
59
60    fn cause(&self) -> Option<&dyn Error> {
61        if let ResourceViewError::Layer(ref e) = *self {
62            Some(e)
63        } else {
64            None
65        }
66    }
67}
68
69/// Error creating either a RenderTargetView, or DepthStencilView.
70#[derive(Clone, Debug, PartialEq)]
71pub enum TargetViewError {
72    /// The `RENDER_TARGET`/`DEPTH_STENCIL` flag is not present in the texture.
73    NoBindFlag,
74    /// Selected mip level doesn't exist.
75    Level(target::Level),
76    /// Selected array layer doesn't exist.
77    Layer(texture::LayerError),
78    /// Selected channel type is not supported for this texture.
79    Channel(format::ChannelType),
80    /// The backend was refused for some reason.
81    Unsupported,
82    /// The RTV cannot be changed due to the references to it existing.
83    NotDetached
84}
85
86impl fmt::Display for TargetViewError {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        let description = self.description();
89        match *self {
90            TargetViewError::Level(ref level) => write!(f, "{}: {}", description, level),
91            TargetViewError::Layer(ref layer) => write!(f, "{}: {}", description, layer),
92            TargetViewError::Channel(ref channel)  => write!(f, "{}: {:?}", description, channel),
93            _ => write!(f, "{}", description)
94        }
95    }
96}
97
98impl Error for TargetViewError {
99    fn description(&self) -> &str {
100        match *self {
101            TargetViewError::NoBindFlag =>
102                "The `RENDER_TARGET`/`DEPTH_STENCIL` flag is not present in the texture",
103            TargetViewError::Level(_) =>
104                "Selected mip level doesn't exist",
105            TargetViewError::Layer(_) =>
106                "Selected array layer doesn't exist",
107            TargetViewError::Channel(_) =>
108                "Selected channel type is not supported for this texture",
109            TargetViewError::Unsupported =>
110                "The backend was refused for some reason",
111            TargetViewError::NotDetached =>
112                "The RTV cannot be changed due to the references to it existing",
113        }
114    }
115
116    fn cause(&self) -> Option<&dyn Error> {
117        if let TargetViewError::Layer(ref e) = *self {
118            Some(e)
119        } else {
120            None
121        }
122    }
123}
124
125/// An error from creating textures with views at the same time.
126#[derive(Clone, Debug, PartialEq)]
127pub enum CombinedError {
128    /// Failed to create the raw texture.
129    Texture(texture::CreationError),
130    /// Failed to create SRV or UAV.
131    Resource(ResourceViewError),
132    /// Failed to create RTV or DSV.
133    Target(TargetViewError),
134}
135
136impl fmt::Display for CombinedError {
137    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138        match *self {
139            CombinedError::Texture(ref e) => write!(f, "{}: {}", self.description(), e),
140            CombinedError::Resource(ref e) => write!(f, "{}: {}", self.description(), e),
141            CombinedError::Target(ref e) => write!(f, "{}: {}", self.description(), e),
142        }
143    }
144}
145
146impl Error for CombinedError {
147    fn description(&self) -> &str {
148        match *self {
149            CombinedError::Texture(_) => "Failed to create the raw texture",
150            CombinedError::Resource(_) => "Failed to create SRV or UAV",
151            CombinedError::Target(_) => "Failed to create RTV or DSV",
152        }
153    }
154
155    fn cause(&self) -> Option<&dyn Error> {
156        match *self {
157            CombinedError::Texture(ref e) => Some(e),
158            CombinedError::Resource(ref e) => Some(e),
159            CombinedError::Target(ref e) => Some(e),
160        }
161    }
162}
163
164impl From<texture::CreationError> for CombinedError {
165    fn from(e: texture::CreationError) -> CombinedError {
166        CombinedError::Texture(e)
167    }
168}
169impl From<ResourceViewError> for CombinedError {
170    fn from(e: ResourceViewError) -> CombinedError {
171        CombinedError::Resource(e)
172    }
173}
174impl From<TargetViewError> for CombinedError {
175    fn from(e: TargetViewError) -> CombinedError {
176        CombinedError::Target(e)
177    }
178}
179
180/// # Overview
181///
182/// A `Factory` is responsible for creating and managing resources for the context it was created
183/// with.
184///
185/// ## Construction and Handling
186///
187/// A `Factory` is typically created along with other objects using a helper function of the
188/// appropriate gfx_window module (e.g. gfx_window_glutin::init()).
189///
190/// This factory structure can then be used to create and manage different resources, like buffers,
191/// shader programs and textures. See the individual methods for more information.
192///
193/// This trait is extended by the [`gfx::FactoryExt` trait](https://docs.rs/gfx/*/gfx/traits/trait.FactoryExt.html).
194/// All types implementing `Factory` also implement `FactoryExt`.
195///
196/// ## Immutable resources
197///
198/// Immutable buffers and textures can only be read by the GPU. They cannot be written by the GPU and
199/// cannot be accessed at all by the CPU.
200///
201/// See:
202///  - [`Factory::create_texture_immutable`](trait.Factory.html#tymethod.create_texture_immutable),
203///  - [`Factory::create_buffer_immutable`](trait.Factory.html#tymethod.create_buffer_immutable).
204///
205/// ## Raw resources
206///
207/// The term "raw" is used in the context of types of functions that have a strongly typed and an
208/// untyped equivalent, to refer to the untyped equivalent.
209///
210/// For example ['Factory::create_buffer_raw'](trait.Factory.html#tymethod.create_buffer_raw) and
211/// ['Factory::create_buffer'](trait.Factory.html#tymethod.create_buffer)
212///
213/// ## Shader resource views and unordered access views
214///
215/// This terminology is borrowed from D3D.
216///
217/// Shader resource views typically wrap textures and buffers to provide read-only access in shaders.
218/// An unordered access view provides similar functionality, but enables reading and writing to
219/// the buffer or texture in any order.
220///
221/// See:
222///
223/// - [The gfx::UNORDERED_ACCESS bit in the gfx::Bind flags](../gfx/struct.Bind.html).
224/// - [Factory::view_buffer_as_unordered_access](trait.Factory.html#method.view_buffer_as_unordered_access).
225///
226#[allow(missing_docs)]
227pub trait Factory<R: Resources> {
228    /// Returns the capabilities of this `Factory`. This usually depends on the graphics API being
229    /// used.
230    fn get_capabilities(&self) -> &Capabilities;
231
232    // resource creation
233    fn create_buffer_raw(&mut self, buffer::Info) -> Result<handle::RawBuffer<R>, buffer::CreationError>;
234    fn create_buffer_immutable_raw(&mut self, data: &[u8], stride: usize, buffer::Role, Bind)
235                                   -> Result<handle::RawBuffer<R>, buffer::CreationError>;
236    fn create_buffer_immutable<T: Pod>(&mut self, data: &[T], role: buffer::Role, bind: Bind)
237                                       -> Result<handle::Buffer<R, T>, buffer::CreationError> {
238        self.create_buffer_immutable_raw(cast_slice(data), mem::size_of::<T>(), role, bind)
239            .map(|raw| Typed::new(raw))
240    }
241    fn create_buffer<T>(&mut self, num: usize, role: buffer::Role, usage: Usage, bind: Bind)
242                        -> Result<handle::Buffer<R, T>, buffer::CreationError> {
243        let stride = mem::size_of::<T>();
244        let info = buffer::Info {
245            role: role,
246            usage: usage,
247            bind: bind,
248            size: num * stride,
249            stride: stride,
250        };
251        self.create_buffer_raw(info).map(|raw| Typed::new(raw))
252    }
253
254    /// Creates a new `RawPipelineState`. To create a safely typed `PipelineState`, see the
255    /// `FactoryExt` trait and `pso` module, both in the `gfx` crate.
256    fn create_pipeline_state_raw(&mut self, &handle::Program<R>, &pso::Descriptor)
257                                 -> Result<handle::RawPipelineState<R>, pso::CreationError>;
258
259    /// Creates a new shader `Program` for the supplied `ShaderSet`.
260    fn create_program(&mut self, shader_set: &ShaderSet<R>)
261                      -> Result<handle::Program<R>, shade::CreateProgramError>;
262
263    /// Compiles a shader source into a `Shader` object that can be used to create a shader
264    /// `Program`.
265    fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
266                     Result<handle::Shader<R>, shade::CreateShaderError>;
267    /// Compiles a `VertexShader` from source.
268    fn create_shader_vertex(&mut self, code: &[u8]) -> Result<VertexShader<R>, shade::CreateShaderError> {
269        self.create_shader(shade::Stage::Vertex, code).map(|s| VertexShader(s))
270    }
271    /// Compiles a `HullShader` from source.
272    fn create_shader_hull(&mut self, code: &[u8]) -> Result<HullShader<R>, shade::CreateShaderError> {
273        self.create_shader(shade::Stage::Hull, code).map(|s| HullShader(s))
274    }
275    /// Compiles a `VertexShader` from source.
276    fn create_shader_domain(&mut self, code: &[u8]) -> Result<DomainShader<R>, shade::CreateShaderError> {
277        self.create_shader(shade::Stage::Domain, code).map(|s| DomainShader(s))
278    }
279    /// Compiles a `GeometryShader` from source.
280    fn create_shader_geometry(&mut self, code: &[u8]) -> Result<GeometryShader<R>, shade::CreateShaderError> {
281        self.create_shader(shade::Stage::Geometry, code).map(|s| GeometryShader(s))
282    }
283    /// Compiles a `PixelShader` from source. This is the same as what some APIs call a fragment
284    /// shader.
285    fn create_shader_pixel(&mut self, code: &[u8]) -> Result<PixelShader<R>, shade::CreateShaderError> {
286        self.create_shader(shade::Stage::Pixel, code).map(|s| PixelShader(s))
287    }
288
289    fn create_sampler(&mut self, texture::SamplerInfo) -> handle::Sampler<R>;
290
291    /// Acquire a mapping Reader
292    ///
293    /// See `write_mapping` for more information.
294    fn read_mapping<'a, 'b, T>(&'a mut self, buf: &'b handle::Buffer<R, T>)
295                               -> Result<mapping::Reader<'b, R, T>,
296                                         mapping::Error>
297        where T: Copy;
298
299    /// Acquire a mapping Writer
300    ///
301    /// While holding this writer, you hold CPU-side exclusive access.
302    /// Any access overlap will result in an error.
303    /// Submitting commands involving this buffer to the device
304    /// implicitly requires exclusive access. Additionally,
305    /// further access will be stalled until execution completion.
306    fn write_mapping<'a, 'b, T>(&'a mut self, buf: &'b handle::Buffer<R, T>)
307                                -> Result<mapping::Writer<'b, R, T>,
308                                          mapping::Error>
309        where T: Copy;
310
311    /// Create a new empty raw texture with no data. The channel type parameter is a hint,
312    /// required to assist backends that have no concept of typeless formats (OpenGL).
313    /// The initial data, if given, has to be provided for all mip levels and slices:
314    /// Slice0.Mip0, Slice0.Mip1, ..., Slice1.Mip0, ...
315    fn create_texture_raw(&mut self, texture::Info, Option<format::ChannelType>, Option<(&[&[u8]], texture::Mipmap)>)
316                          -> Result<handle::RawTexture<R>, texture::CreationError>;
317
318    fn view_buffer_as_shader_resource_raw(&mut self, &handle::RawBuffer<R>, format::Format)
319        -> Result<handle::RawShaderResourceView<R>, ResourceViewError>;
320    fn view_buffer_as_unordered_access_raw(&mut self, &handle::RawBuffer<R>)
321        -> Result<handle::RawUnorderedAccessView<R>, ResourceViewError>;
322    fn view_texture_as_shader_resource_raw(&mut self, &handle::RawTexture<R>, texture::ResourceDesc)
323        -> Result<handle::RawShaderResourceView<R>, ResourceViewError>;
324    fn view_texture_as_unordered_access_raw(&mut self, &handle::RawTexture<R>)
325        -> Result<handle::RawUnorderedAccessView<R>, ResourceViewError>;
326    fn view_texture_as_render_target_raw(&mut self, &handle::RawTexture<R>, texture::RenderDesc)
327        -> Result<handle::RawRenderTargetView<R>, TargetViewError>;
328    fn view_texture_as_depth_stencil_raw(&mut self, &handle::RawTexture<R>, texture::DepthStencilDesc)
329        -> Result<handle::RawDepthStencilView<R>, TargetViewError>;
330
331    fn create_texture<S>(&mut self, kind: texture::Kind, levels: target::Level,
332                      bind: Bind, usage: Usage, channel_hint: Option<format::ChannelType>)
333                      -> Result<handle::Texture<R, S>, texture::CreationError>
334    where S: format::SurfaceTyped
335    {
336        let desc = texture::Info {
337            kind: kind,
338            levels: levels,
339            format: S::get_surface_type(),
340            bind: bind,
341            usage: usage,
342        };
343        let raw = try!(self.create_texture_raw(desc, channel_hint, None));
344        Ok(Typed::new(raw))
345    }
346
347    fn view_buffer_as_shader_resource<T: format::Formatted>(&mut self, buf: &handle::Buffer<R, T>)
348                                      -> Result<handle::ShaderResourceView<R, T>, ResourceViewError>
349    {
350        //TODO: check bind flags
351        self.view_buffer_as_shader_resource_raw(buf.raw(), T::get_format()).map(Typed::new)
352    }
353
354    fn view_buffer_as_unordered_access<T>(&mut self, buf: &handle::Buffer<R, T>)
355                                      -> Result<handle::UnorderedAccessView<R, T>, ResourceViewError>
356    {
357        //TODO: check bind flags
358        self.view_buffer_as_unordered_access_raw(buf.raw()).map(Typed::new)
359    }
360
361    fn view_texture_as_shader_resource<T: format::TextureFormat>(&mut self, tex: &handle::Texture<R, T::Surface>,
362                                       levels: (target::Level, target::Level), swizzle: format::Swizzle)
363                                       -> Result<handle::ShaderResourceView<R, T::View>, ResourceViewError>
364    {
365        if !tex.get_info().bind.contains(Bind::SHADER_RESOURCE) {
366            return Err(ResourceViewError::NoBindFlag)
367        }
368        assert!(levels.0 <= levels.1);
369        let desc = texture::ResourceDesc {
370            channel: <T::Channel as format::ChannelTyped>::get_channel_type(),
371            layer: None,
372            min: levels.0,
373            max: levels.1,
374            swizzle: swizzle,
375        };
376        self.view_texture_as_shader_resource_raw(tex.raw(), desc)
377            .map(Typed::new)
378    }
379
380    fn view_texture_as_unordered_access<T: format::TextureFormat>(&mut self, tex: &handle::Texture<R, T::Surface>)
381                                        -> Result<handle::UnorderedAccessView<R, T::View>, ResourceViewError>
382    {
383        if !tex.get_info().bind.contains(Bind::UNORDERED_ACCESS) {
384            return Err(ResourceViewError::NoBindFlag)
385        }
386        self.view_texture_as_unordered_access_raw(tex.raw())
387            .map(Typed::new)
388    }
389
390    fn view_texture_as_render_target<T: format::RenderFormat>(&mut self, tex: &handle::Texture<R, T::Surface>,
391                                     level: target::Level, layer: Option<target::Layer>)
392                                     -> Result<handle::RenderTargetView<R, T>, TargetViewError>
393    {
394        if !tex.get_info().bind.contains(Bind::RENDER_TARGET) {
395            return Err(TargetViewError::NoBindFlag)
396        }
397        let desc = texture::RenderDesc {
398            channel: <T::Channel as format::ChannelTyped>::get_channel_type(),
399            level: level,
400            layer: layer,
401        };
402        self.view_texture_as_render_target_raw(tex.raw(), desc)
403            .map(Typed::new)
404    }
405
406    fn view_texture_as_depth_stencil<T: format::DepthFormat>(&mut self, tex: &handle::Texture<R, T::Surface>,
407                                     level: target::Level, layer: Option<target::Layer>, flags: texture::DepthStencilFlags)
408                                     -> Result<handle::DepthStencilView<R, T>, TargetViewError>
409    {
410        if !tex.get_info().bind.contains(Bind::DEPTH_STENCIL) {
411            return Err(TargetViewError::NoBindFlag)
412        }
413        let desc = texture::DepthStencilDesc {
414            level: level,
415            layer: layer,
416            flags: flags,
417        };
418        self.view_texture_as_depth_stencil_raw(tex.raw(), desc)
419            .map(Typed::new)
420    }
421
422    fn view_texture_as_depth_stencil_trivial<T: format::DepthFormat>(&mut self, tex: &handle::Texture<R, T::Surface>)
423                                            -> Result<handle::DepthStencilView<R, T>, TargetViewError>
424    {
425        self.view_texture_as_depth_stencil(tex, 0, None, texture::DepthStencilFlags::empty())
426    }
427
428    fn create_texture_immutable_u8<T: format::TextureFormat>(&mut self, kind: texture::Kind, mipmap: texture::Mipmap, data: &[&[u8]])
429                                   -> Result<(handle::Texture<R, T::Surface>,
430                                              handle::ShaderResourceView<R, T::View>),
431                                             CombinedError>
432    {
433        let surface = <T::Surface as format::SurfaceTyped>::get_surface_type();
434        let num_slices = kind.get_num_slices().unwrap_or(1) as usize;
435        let num_faces = if kind.is_cube() {6} else {1};
436        let levels = match mipmap {
437            texture::Mipmap::Allocated => if data.len() != num_slices * num_faces {
438                return Err(CombinedError::Texture(texture::CreationError::Level((num_slices * num_faces) as texture::Level)));
439            } else {
440                kind.get_num_levels()
441            },
442            texture::Mipmap::Provided => (data.len() / (num_slices * num_faces)) as texture::Level
443        };
444        let desc = texture::Info {
445            kind: kind,
446            levels: levels,
447            format: surface,
448            bind: Bind::SHADER_RESOURCE,
449            usage: Usage::Data,
450        };
451        let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
452        let raw = try!(self.create_texture_raw(desc, Some(cty), Some((data, mipmap))));
453        let levels = (0, raw.get_info().levels - 1);
454        let tex = Typed::new(raw);
455        let view = try!(self.view_texture_as_shader_resource::<T>(&tex, levels, format::Swizzle::new()));
456        Ok((tex, view))
457    }
458
459    fn create_texture_immutable<T: format::TextureFormat>(
460        &mut self,
461        kind: texture::Kind,
462        mipmap: texture::Mipmap,
463        data: &[&[<T::Surface as format::SurfaceTyped>::DataType]])
464        -> Result<(handle::Texture<R, T::Surface>, handle::ShaderResourceView<R, T::View>),
465                  CombinedError>
466    {
467        // we can use cast_slice on a 2D slice, have to use a temporary array of slices
468        let mut raw_data: [&[u8]; 0x100] = [&[]; 0x100];
469        assert!(data.len() <= raw_data.len());
470        for (rd, d) in raw_data.iter_mut().zip(data.iter()) {
471            *rd = cast_slice(*d);
472        }
473        self.create_texture_immutable_u8::<T>(kind, mipmap, &raw_data[.. data.len()])
474    }
475
476    fn create_render_target<T: format::RenderFormat + format::TextureFormat>
477                           (&mut self, width: texture::Size, height: texture::Size)
478                            -> Result<(handle::Texture<R, T::Surface>,
479                                       handle::ShaderResourceView<R, T::View>,
480                                       handle::RenderTargetView<R, T>
481                                ), CombinedError>
482    {
483        let kind = texture::Kind::D2(width, height, texture::AaMode::Single);
484        let levels = 1;
485        let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
486        let tex = try!(self.create_texture(kind, levels, Bind::SHADER_RESOURCE | Bind::RENDER_TARGET, Usage::Data, Some(cty)));
487        let resource = try!(self.view_texture_as_shader_resource::<T>(&tex, (0, levels-1), format::Swizzle::new()));
488        let target = try!(self.view_texture_as_render_target(&tex, 0, None));
489        Ok((tex, resource, target))
490    }
491
492    fn create_depth_stencil<T: format::DepthFormat + format::TextureFormat>
493                           (&mut self, width: texture::Size, height: texture::Size)
494                            -> Result<(handle::Texture<R, T::Surface>,
495                                       handle::ShaderResourceView<R, T::View>,
496                                       handle::DepthStencilView<R, T>
497                                ), CombinedError>
498    {
499        let kind = texture::Kind::D2(width, height, texture::AaMode::Single);
500        let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
501        let tex = try!(self.create_texture(kind, 1, Bind::SHADER_RESOURCE | Bind::DEPTH_STENCIL, Usage::Data, Some(cty)));
502        let resource = try!(self.view_texture_as_shader_resource::<T>(&tex, (0, 0), format::Swizzle::new()));
503        let target = try!(self.view_texture_as_depth_stencil_trivial(&tex));
504        Ok((tex, resource, target))
505    }
506
507    fn create_depth_stencil_view_only<T: format::DepthFormat + format::TextureFormat>
508                                     (&mut self, width: texture::Size, height: texture::Size)
509                                      -> Result<handle::DepthStencilView<R, T>, CombinedError>
510    {
511        let kind = texture::Kind::D2(width, height, texture::AaMode::Single);
512        let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
513        let tex = try!(self.create_texture(kind, 1, Bind::DEPTH_STENCIL, Usage::Data, Some(cty)));
514        let target = try!(self.view_texture_as_depth_stencil_trivial(&tex));
515        Ok(target)
516    }
517}