Implement vkCreateGraphicsPipeline and vkDestroyGraphicsPipeline

This commit is contained in:
msiglreith 2018-01-13 01:10:24 +01:00
parent f422eb24d1
commit ea0714cf39
3 changed files with 430 additions and 12 deletions

View file

@ -1,4 +1,5 @@
use hal::{adapter, buffer, command, format, image, memory, pass, pso, window};
use hal::{PatchSize, Primitive};
use std::mem;
@ -440,3 +441,85 @@ pub fn map_subpass_contents(contents: VkSubpassContents) -> command::SubpassCont
_ => panic!("Unexpected subpass contents: {:?}", contents),
}
}
pub fn map_polygon_mode(mode: VkPolygonMode, line_width: f32) -> pso::PolygonMode {
match mode {
VkPolygonMode::VK_POLYGON_MODE_FILL => pso::PolygonMode::Fill,
VkPolygonMode::VK_POLYGON_MODE_LINE => pso::PolygonMode::Line(line_width),
VkPolygonMode::VK_POLYGON_MODE_POINT => pso::PolygonMode::Point,
_ => panic!("Unexpected polygon mode: {:?}", mode),
}
}
pub fn map_cull_face(cull: VkCullModeFlags) -> Option<pso::CullFace> {
use super::VkCullModeFlagBits::*;
if cull == VK_CULL_MODE_NONE as _ { None }
else if cull == VK_CULL_MODE_FRONT_BIT as _ { Some(pso::CullFace::Front) }
else if cull == VK_CULL_MODE_BACK_BIT as _ { Some(pso::CullFace::Back) }
else if cull == VK_CULL_MODE_FRONT_AND_BACK as _ { unimplemented!() } // TODO: can we support it?
else { panic!("Unexpected cull mode: {:?}", cull) }
}
pub fn map_front_face(face: VkFrontFace) -> pso::FrontFace {
match face {
VkFrontFace::VK_FRONT_FACE_COUNTER_CLOCKWISE => pso::FrontFace::CounterClockwise,
VkFrontFace::VK_FRONT_FACE_CLOCKWISE => pso::FrontFace::Clockwise,
_ => panic!("Unexpected front face: {:?}", face),
}
}
pub fn map_primitive_topology(topology: VkPrimitiveTopology, patch_size: PatchSize) -> hal::Primitive {
use super::VkPrimitiveTopology::*;
match topology {
VK_PRIMITIVE_TOPOLOGY_POINT_LIST => Primitive::PointList,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST => Primitive::LineList,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP => Primitive::LineStrip,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST => Primitive::TriangleList,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP => Primitive::TriangleStrip,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN =>
panic!("`VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN` not supported in portability"),
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY => Primitive::LineListAdjacency,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY => Primitive::LineStripAdjacency,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY => Primitive::TriangleListAdjacency,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY => Primitive::TriangleStripAdjacency,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST => Primitive::PatchList(patch_size),
_ => panic!("Unexpected primitive topology: {:?}", topology),
}
}
pub fn map_compare_op(op: VkCompareOp) -> pso::Comparison {
use super::VkCompareOp::*;
match op {
VK_COMPARE_OP_NEVER => pso::Comparison::Never,
VK_COMPARE_OP_LESS => pso::Comparison::Less,
VK_COMPARE_OP_EQUAL => pso::Comparison::Equal,
VK_COMPARE_OP_LESS_OR_EQUAL => pso::Comparison::LessEqual,
VK_COMPARE_OP_GREATER => pso::Comparison::Greater,
VK_COMPARE_OP_NOT_EQUAL => pso::Comparison::NotEqual,
VK_COMPARE_OP_GREATER_OR_EQUAL => pso::Comparison::GreaterEqual,
VK_COMPARE_OP_ALWAYS => pso::Comparison::Always,
_ => panic!("Unexpected compare op: {:?}", op),
}
}
pub fn map_logic_op(op: VkLogicOp) -> pso::LogicOp {
unimplemented!()
}
pub fn map_stencil_op(op: VkStencilOp) -> pso::StencilOp {
unimplemented!()
}
pub fn map_color_components(mask: VkColorComponentFlags) -> pso::ColorMask {
// Vulkan and HAL flags are equal
unsafe { mem::transmute(mask as u8) }
}
pub fn map_blend_op(
blend_op: VkBlendOp, src_factor: VkBlendFactor, dst_factor: VkBlendFactor,
) -> pso::BlendOp {
unimplemented!()
}

View file

@ -8,7 +8,7 @@ use hal::pool::RawCommandPool;
use hal::command::{ClearValueRaw, RawCommandBuffer, Rect};
use hal::queue::RawCommandQueue;
use std::ffi::CString;
use std::ffi::{CStr, CString};
use std::mem;
use std::ops::{Deref, Range};
@ -949,14 +949,344 @@ pub extern "C" fn gfxMergePipelineCaches(
}
#[inline]
pub extern "C" fn gfxCreateGraphicsPipelines(
device: VkDevice,
gpu: VkDevice,
pipelineCache: VkPipelineCache,
createInfoCount: u32,
pCreateInfos: *const VkGraphicsPipelineCreateInfo,
pAllocator: *const VkAllocationCallbacks,
_pAllocator: *const VkAllocationCallbacks,
pPipelines: *mut VkPipeline,
) -> VkResult {
unimplemented!()
assert!(pipelineCache.is_null());
let infos = unsafe {
slice::from_raw_parts(pCreateInfos, createInfoCount as _)
};
const NUM_SHADER_STAGES: usize = 5;
let mut shader_stages = Vec::with_capacity(infos.len() * NUM_SHADER_STAGES);
// Collect all information which we will borrow later. Need to work around
// the borrow checker here.
// TODO: try to refactor it once we have a more generic API
for info in infos {
let stages = unsafe {
slice::from_raw_parts(info.pStages, info.stageCount as _)
};
for stage in stages {
let name = unsafe { CStr::from_ptr(stage.pName).to_owned() };
let specialization = unsafe { stage
.pSpecializationInfo
.as_ref()
.map(|specialization| {
let data = slice::from_raw_parts(
specialization.pData,
specialization.dataSize as _,
);
let entries = slice::from_raw_parts(
specialization.pMapEntries,
specialization.mapEntryCount as _,
);
entries.
into_iter()
.map(|entry| {
// Currently blocked due to lack of specialization type knowledge
unimplemented!()
})
.collect::<Vec<pso::Specialization>>()
})
.unwrap_or(vec![])
};
shader_stages.push((
name.into_string().unwrap(),
specialization,
));
}
}
let mut cur_shader_stage = 0;
let descs = infos.into_iter().map(|info| {
// TODO: handle dynamic states and viewports
let shaders = {
let mut set: pso::GraphicsShaderSet<_> = unsafe { mem::zeroed() };
let stages = unsafe {
slice::from_raw_parts(info.pStages, info.stageCount as _)
};
for stage in stages {
use super::VkShaderStageFlagBits::*;
let (ref name, ref specialization) = shader_stages[cur_shader_stage];
cur_shader_stage += 1;
let entry_point = pso::EntryPoint {
entry: &name,
module: stage.module.deref(),
specialization: &specialization,
};
match stage.stage {
VK_SHADER_STAGE_VERTEX_BIT => { set.vertex = entry_point; }
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT => { set.hull = Some(entry_point); }
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT => { set.domain = Some(entry_point); }
VK_SHADER_STAGE_GEOMETRY_BIT => { set.geometry = Some(entry_point); }
VK_SHADER_STAGE_FRAGMENT_BIT => { set.fragment = Some(entry_point); }
stage => panic!("Unexpected shader stage: {:?}", stage),
}
}
set
};
let rasterizer = {
let state = unsafe { &*info.pRasterizationState };
assert_eq!(state.rasterizerDiscardEnable, VK_FALSE); // TODO
assert_eq!(state.depthBiasEnable, VK_FALSE); // TODO: ready for work
pso::Rasterizer {
polygon_mode: conv::map_polygon_mode(state.polygonMode, state.lineWidth),
cull_face: conv::map_cull_face(state.cullMode),
front_face: conv::map_front_face(state.frontFace),
depth_clamping: state.depthClampEnable == VK_TRUE,
depth_bias: None, // TODO
conservative: false,
}
};
let (vertex_buffers, attributes) = {
let input_state = unsafe { &*info.pVertexInputState };
let bindings = unsafe {
slice::from_raw_parts(
input_state.pVertexBindingDescriptions,
input_state.vertexBindingDescriptionCount as _,
)
};
let attributes = unsafe {
slice::from_raw_parts(
input_state.pVertexAttributeDescriptions,
input_state.vertexAttributeDescriptionCount as _,
)
};
let bindings = bindings
.into_iter()
.enumerate()
.map(|(i, binding)| {
assert_eq!(i, binding.binding as _); // TODO: currently need to be in order
let rate = match binding.inputRate {
VkVertexInputRate::VK_VERTEX_INPUT_RATE_VERTEX => 0,
VkVertexInputRate::VK_VERTEX_INPUT_RATE_INSTANCE => 1,
rate => panic!("Unexpected input rate: {:?}", rate),
};
pso::VertexBufferDesc {
stride: binding.stride,
rate,
}
})
.collect::<Vec<_>>();
let attributes = attributes
.into_iter()
.map(|attrib| {
pso::AttributeDesc {
location: attrib.location,
binding: attrib.binding,
element: pso::Element {
format: conv::map_format(attrib.format).unwrap(), // TODO: undefined allowed?
offset: attrib.offset,
},
}
})
.collect::<Vec<_>>();
(bindings, attributes)
};
let input_assembler = {
let input_state = unsafe { &*info.pInputAssemblyState };
let tessellation_state = if shaders.hull.is_some() {
Some(unsafe { &*info.pTessellationState })
} else {
None
};
assert_eq!(input_state.primitiveRestartEnable, VK_FALSE); // TODO
pso::InputAssemblerDesc {
primitive: conv::map_primitive_topology(
input_state.topology,
tessellation_state
.map(|state| state.patchControlPoints as _)
.unwrap_or(0),
),
primitive_restart: pso::PrimitiveRestart::Disabled, // TODO
}
};
// TODO: `pColorBlendState` could contain garbage, but implementations
// can ignore it in some circumstances. How to handle it?
let blender = {
let mut blend_desc = pso::BlendDesc::default();
let blend_state = unsafe { info.pColorBlendState.as_ref() };
if let Some(state) = blend_state {
if state.logicOpEnable == VK_TRUE {
blend_desc.logic_op = Some(conv::map_logic_op(state.logicOp));
}
let attachments = unsafe {
slice::from_raw_parts(state.pAttachments, state.attachmentCount as _)
};
blend_desc.targets = attachments
.into_iter()
.map(|attachment| {
let color_mask = conv::map_color_components(attachment.colorWriteMask);
let blend = if attachment.blendEnable == VK_TRUE {
pso::BlendState::On {
color: conv::map_blend_op(
attachment.colorBlendOp,
attachment.srcColorBlendFactor,
attachment.dstColorBlendFactor,
),
alpha: conv::map_blend_op(
attachment.alphaBlendOp,
attachment.srcAlphaBlendFactor,
attachment.dstAlphaBlendFactor,
),
}
} else {
pso::BlendState::Off
};
pso::ColorBlendDesc(color_mask, blend)
})
.collect();
}
// TODO: multisampling
blend_desc
};
// TODO: `pDepthStencilState` could contain garbage, but implementations
// can ignore it in some circumstances. How to handle it?
let depth_stencil = unsafe { info
.pDepthStencilState
.as_ref()
.map(|state| {
let depth_test = if state.depthTestEnable == VK_TRUE {
pso::DepthTest::On {
fun: conv::map_compare_op(state.depthCompareOp),
write: state.depthWriteEnable == VK_TRUE,
}
} else {
pso::DepthTest::Off
};
fn map_stencil_state(state: VkStencilOpState) -> pso::StencilFace {
// TODO: reference value
pso::StencilFace {
fun: conv::map_compare_op(state.compareOp),
mask_read: state.compareMask,
mask_write: state.writeMask,
op_fail: conv::map_stencil_op(state.failOp),
op_depth_fail: conv::map_stencil_op(state.depthFailOp),
op_pass: conv::map_stencil_op(state.passOp),
}
}
let stencil_test = if state.stencilTestEnable == VK_TRUE {
pso::StencilTest::On {
front: map_stencil_state(state.front),
back: map_stencil_state(state.back),
}
} else {
pso::StencilTest::Off
};
// TODO: depth bounds
pso::DepthStencilDesc {
depth: depth_test,
depth_bounds: state.depthBoundsTestEnable == VK_TRUE,
stencil: stencil_test,
}
})
};
let layout = &*info.layout;
let subpass = pass::Subpass {
index: info.subpass as _,
main_pass: &*info.renderPass,
};
let flags = {
let mut flags = pso::PipelineCreationFlags::empty();
if info.flags & VkPipelineCreateFlagBits::VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT as u32 != 0 {
flags |= pso::PipelineCreationFlags::DISABLE_OPTIMIZATION;
}
if info.flags & VkPipelineCreateFlagBits::VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT as u32 != 0 {
flags |= pso::PipelineCreationFlags::ALLOW_DERIVATIVES;
}
flags
};
let parent = {
let is_derivative = info.flags & VkPipelineCreateFlagBits::VK_PIPELINE_CREATE_DERIVATIVE_BIT as u32 != 0;
if !info.basePipelineHandle.is_null() {
match *info.basePipelineHandle {
Pipeline::Graphics(ref graphics) => pso::BasePipeline::Pipeline(graphics),
Pipeline::Compute(_) => panic!("Base pipeline handle must be a graphics pipeline"),
}
} else if is_derivative && info.basePipelineIndex > 0 {
pso::BasePipeline::Index(info.basePipelineIndex as _)
} else {
pso::BasePipeline::None // TODO
}
};
pso::GraphicsPipelineDesc {
shaders,
rasterizer,
vertex_buffers,
attributes,
input_assembler,
blender,
depth_stencil,
layout,
subpass,
flags,
parent,
}
}).collect::<Vec<_>>();
let pipelines = gpu.device.create_graphics_pipelines(&descs);
unsafe {
slice::from_raw_parts_mut(pPipelines, descs.len())
.into_iter()
.zip(pipelines.into_iter())
.map(|(pipeline, raw)| {
if let Ok(raw) = raw {
*pipeline = Handle::new(Pipeline::Graphics(raw));
}
});
}
VkResult::VK_SUCCESS
}
#[inline]
pub extern "C" fn gfxCreateComputePipelines(
@ -971,11 +1301,16 @@ pub extern "C" fn gfxCreateComputePipelines(
}
#[inline]
pub extern "C" fn gfxDestroyPipeline(
device: VkDevice,
gpu: VkDevice,
pipeline: VkPipeline,
pAllocator: *const VkAllocationCallbacks,
) {
unimplemented!()
if !pipeline.is_null() {
match *pipeline.unwrap() {
Pipeline::Graphics(pipeline) => gpu.device.destroy_graphics_pipeline(pipeline),
Pipeline::Compute(pipeline) => gpu.device.destroy_compute_pipeline(pipeline),
}
}
}
#[inline]
pub extern "C" fn gfxCreatePipelineLayout(

View file

@ -46,6 +46,7 @@ pub type VkSemaphore = Handle<<B as hal::Backend>::Semaphore>;
pub type VkFence = Handle<<B as hal::Backend>::Fence>;
pub type VkRenderPass = Handle<<B as hal::Backend>::RenderPass>;
pub type VkFramebuffer = Handle<<B as hal::Backend>::Framebuffer>;
pub type VkPipeline = Handle<Pipeline<B>>;
pub type QueueFamilyIndex = u32;
@ -54,6 +55,11 @@ pub struct Gpu<B: hal::Backend> {
queues: HashMap<QueueFamilyIndex, Vec<VkQueue>>,
}
pub enum Pipeline<B: hal::Backend> {
Graphics(B::GraphicsPipeline),
Compute(B::ComputePipeline),
}
pub enum Image<B: hal::Backend> {
Image(B::Image),
Unbound(B::UnboundImage),
@ -538,12 +544,6 @@ pub struct VkPipelineCache_T {
_unused: [u8; 0],
}
pub type VkPipelineCache = *mut VkPipelineCache_T;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct VkPipeline_T {
_unused: [u8; 0],
}
pub type VkPipeline = *mut VkPipeline_T;
pub const VkPipelineCacheHeaderVersion_VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE:
VkPipelineCacheHeaderVersion =