use std::borrow::Cow;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::iter;
use std::iter::Empty as EmptyIter;
use std::marker::PhantomData;
use std::mem;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use format::Format;
use pipeline::input_assembly::PrimitiveTopology;
use OomError;
use SafeDeref;
use VulkanObject;
use check_errors;
use device::Device;
use vk;
#[derive(Debug)]
pub struct ShaderModule<P = Arc<Device>>
where P: SafeDeref<Target = Device>
{
module: vk::ShaderModule,
device: P,
}
impl<P> ShaderModule<P>
where P: SafeDeref<Target = Device>
{
pub unsafe fn new(device: P, spirv: &[u8]) -> Result<Arc<ShaderModule<P>>, OomError> {
debug_assert!((spirv.len() % 4) == 0);
let module = {
let infos = vk::ShaderModuleCreateInfo {
sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
pNext: ptr::null(),
flags: 0, codeSize: spirv.len(),
pCode: spirv.as_ptr() as *const _,
};
let vk = device.pointers();
let mut output = mem::uninitialized();
check_errors(vk.CreateShaderModule(device.internal_object(),
&infos,
ptr::null(),
&mut output))?;
output
};
Ok(Arc::new(ShaderModule {
module: module,
device: device,
}))
}
pub unsafe fn vertex_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> VertexShaderEntryPoint<'a, S, I, O, L, P> {
VertexShaderEntryPoint {
module: self,
name: name,
input: input,
output: output,
layout: layout,
marker: PhantomData,
}
}
pub unsafe fn tess_control_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> TessControlShaderEntryPoint<'a, S, I, O, L, P> {
TessControlShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
marker: PhantomData,
}
}
pub unsafe fn tess_evaluation_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> TessEvaluationShaderEntryPoint<'a, S, I, O, L, P> {
TessEvaluationShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
marker: PhantomData,
}
}
pub unsafe fn geometry_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, primitives: GeometryShaderExecutionMode, input: I, output: O,
layout: L)
-> GeometryShaderEntryPoint<'a, S, I, O, L, P> {
GeometryShaderEntryPoint {
module: self,
name: name,
layout: layout,
primitives: primitives,
input: input,
output: output,
marker: PhantomData,
}
}
pub unsafe fn fragment_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> FragmentShaderEntryPoint<'a, S, I, O, L, P> {
FragmentShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
marker: PhantomData,
}
}
#[inline]
pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
-> ComputeShaderEntryPoint<'a, S, L, P> {
ComputeShaderEntryPoint {
module: self,
name: name,
layout: layout,
marker: PhantomData,
}
}
}
unsafe impl<P> VulkanObject for ShaderModule<P>
where P: SafeDeref<Target = Device>
{
type Object = vk::ShaderModule;
#[inline]
fn internal_object(&self) -> vk::ShaderModule {
self.module
}
}
impl<P> Drop for ShaderModule<P>
where P: SafeDeref<Target = Device>
{
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroyShaderModule(self.device.internal_object(), self.module, ptr::null());
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct VertexShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
input: I,
layout: L,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> VertexShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
#[inline]
pub fn input_definition(&self) -> &I {
&self.input
}
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
#[derive(Debug, Copy, Clone)]
pub struct TessControlShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> TessControlShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
#[inline]
pub fn input(&self) -> &I {
&self.input
}
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
#[derive(Debug, Copy, Clone)]
pub struct TessEvaluationShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> TessEvaluationShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
#[inline]
pub fn input(&self) -> &I {
&self.input
}
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
#[derive(Debug, Copy, Clone)]
pub struct GeometryShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
primitives: GeometryShaderExecutionMode,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> GeometryShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn primitives(&self) -> GeometryShaderExecutionMode {
self.primitives
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
#[inline]
pub fn input(&self) -> &I {
&self.input
}
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[doc(hidden)]
pub enum GeometryShaderExecutionMode {
Points,
Lines,
LinesWithAdjacency,
Triangles,
TrianglesWithAdjacency,
}
impl GeometryShaderExecutionMode {
#[inline]
pub fn matches(&self, input: PrimitiveTopology) -> bool {
match (*self, input) {
(GeometryShaderExecutionMode::Points, PrimitiveTopology::PointList) => true,
(GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineList) => true,
(GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineStrip) => true,
(GeometryShaderExecutionMode::LinesWithAdjacency,
PrimitiveTopology::LineListWithAdjacency) => true,
(GeometryShaderExecutionMode::LinesWithAdjacency,
PrimitiveTopology::LineStripWithAdjacency) => true,
(GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleList) => true,
(GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleStrip) => true,
(GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleFan) => true,
(GeometryShaderExecutionMode::TrianglesWithAdjacency,
PrimitiveTopology::TriangleListWithAdjacency) => true,
(GeometryShaderExecutionMode::TrianglesWithAdjacency,
PrimitiveTopology::TriangleStripWithAdjacency) => true,
_ => false,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct FragmentShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> FragmentShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
#[inline]
pub fn input(&self) -> &I {
&self.input
}
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
#[derive(Debug, Copy, Clone)]
pub struct ComputeShaderEntryPoint<'a, S, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
marker: PhantomData<S>,
}
impl<'a, S, L, P> ComputeShaderEntryPoint<'a, S, L, P>
where P: 'a + SafeDeref<Target = Device>
{
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
}
pub unsafe trait ShaderInterfaceDef {
type Iter: ExactSizeIterator<Item = ShaderInterfaceDefEntry>;
fn elements(&self) -> Self::Iter;
}
#[derive(Debug, Clone)]
pub struct ShaderInterfaceDefEntry {
pub location: Range<u32>,
pub format: Format,
pub name: Option<Cow<'static, str>>,
}
#[derive(Debug, Copy, Clone)]
pub struct EmptyShaderInterfaceDef;
unsafe impl ShaderInterfaceDef for EmptyShaderInterfaceDef {
type Iter = EmptyIter<ShaderInterfaceDefEntry>;
#[inline]
fn elements(&self) -> Self::Iter {
iter::empty()
}
}
pub unsafe trait ShaderInterfaceDefMatch<I>: ShaderInterfaceDef
where I: ShaderInterfaceDef
{
fn matches(&self, other: &I) -> Result<(), ShaderInterfaceMismatchError>;
}
unsafe impl<T, I> ShaderInterfaceDefMatch<I> for T
where T: ShaderInterfaceDef,
I: ShaderInterfaceDef
{
fn matches(&self, other: &I) -> Result<(), ShaderInterfaceMismatchError> {
if self.elements().len() != other.elements().len() {
return Err(ShaderInterfaceMismatchError::ElementsCountMismatch);
}
for a in self.elements() {
for loc in a.location.clone() {
let b = match other
.elements()
.find(|e| loc >= e.location.start && loc < e.location.end) {
None => return Err(ShaderInterfaceMismatchError::MissingElement {
location: loc,
}),
Some(b) => b,
};
if a.format != b.format {
return Err(ShaderInterfaceMismatchError::FormatMismatch);
}
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ShaderInterfaceMismatchError {
ElementsCountMismatch,
MissingElement { location: u32 },
FormatMismatch,
}
impl error::Error for ShaderInterfaceMismatchError {
#[inline]
fn description(&self) -> &str {
match *self {
ShaderInterfaceMismatchError::ElementsCountMismatch =>
"the number of elements mismatches",
ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
ShaderInterfaceMismatchError::FormatMismatch =>
"the format of an element does not match",
}
}
}
impl fmt::Display for ShaderInterfaceMismatchError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
pub unsafe trait SpecializationConstants {
fn descriptors() -> &'static [SpecializationMapEntry];
}
unsafe impl SpecializationConstants for () {
#[inline]
fn descriptors() -> &'static [SpecializationMapEntry] {
&[]
}
}
#[repr(C)]
pub struct SpecializationMapEntry {
pub constant_id: u32,
pub offset: u32,
pub size: usize,
}