hal/gles: pipeline creation

This commit is contained in:
Dzmitry Malyshau 2021-06-23 01:40:02 -04:00 committed by Dzmitry Malyshau
parent d29c450ec3
commit d3d2ed5a9e
10 changed files with 539 additions and 206 deletions

View File

@ -169,6 +169,14 @@ impl super::Adapter {
let extensions = gl.supported_extensions();
log::info!("Extensions: {:?}", extensions);
let shading_language_version = {
let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION);
log::info!("SL version: {}", sl_version);
let (sl_major, sl_minor) = Self::parse_version(&version).ok()?;
let value = (sl_major * 100 + sl_minor * 10) as u16;
naga::back::glsl::Version::Embedded(value)
};
let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE;
features.set(
wgt::Features::DEPTH_CLAMPING,
@ -240,6 +248,7 @@ impl super::Adapter {
shared: Arc::new(super::AdapterShared {
context: gl,
private_caps,
shading_language_version,
}),
},
info: Self::make_info(vendor, renderer),

View File

@ -1,5 +1,5 @@
use super::Command as C;
use super::Resource; //TEMP
use super::{conv, Command as C};
use std::{mem, ops::Range};
impl super::CommandBuffer {
@ -113,7 +113,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
dst: dst_raw,
dst_target,
dst_info: super::TextureCopyInfo {
external_format: dst.format_desc.tex_external,
external_format: dst.format_desc.external,
data_type: dst.format_desc.data_type,
texel_size: dst.format_info.block_size,
},
@ -142,7 +142,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
src: src_raw,
src_target,
src_info: super::TextureCopyInfo {
external_format: src.format_desc.tex_external,
external_format: src.format_desc.external,
data_type: src.format_desc.data_type,
texel_size: src.format_info.block_size,
},
@ -200,7 +200,9 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.cmd_buffer.commands.push(C::PopDebugGroup);
}
unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology);
}
unsafe fn set_index_buffer<'a>(
&mut self,
@ -233,7 +235,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
) {
debug_assert_eq!(start_instance, 0);
self.cmd_buffer.commands.push(C::Draw {
primitive: self.state.primitive,
topology: self.state.topology,
start_vertex,
vertex_count,
instance_count,
@ -254,7 +256,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
};
let index_offset = self.state.index_offset + index_size * start_index as wgt::BufferAddress;
self.cmd_buffer.commands.push(C::DrawIndexed {
primitive: self.state.primitive,
topology: self.state.topology,
index_type,
index_offset,
index_count,
@ -272,7 +274,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
let indirect_offset =
offset + draw * mem::size_of::<wgt::DrawIndirectArgs>() as wgt::BufferAddress;
self.cmd_buffer.commands.push(C::DrawIndirect {
primitive: self.state.primitive,
topology: self.state.topology,
indirect_buf: buffer.raw,
indirect_offset,
});
@ -292,7 +294,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
let indirect_offset = offset
+ draw * mem::size_of::<wgt::DrawIndexedIndirectArgs>() as wgt::BufferAddress;
self.cmd_buffer.commands.push(C::DrawIndexedIndirect {
primitive: self.state.primitive,
topology: self.state.topology,
index_type,
indirect_buf: buffer.raw,
indirect_offset,
@ -325,7 +327,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {}
unsafe fn end_compute_pass(&mut self) {}
unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {}
unsafe fn dispatch(&mut self, count: [u32; 3]) {
self.cmd_buffer.commands.push(C::Dispatch(count));

View File

@ -1,163 +1,64 @@
impl super::AdapterShared {
pub(super) fn describe_texture_format(
&self,
format: wgt::TextureFormat,
) -> super::FormatDescription {
use super::VertexAttribKind as Vak;
texture_format: wgt::TextureFormat,
) -> super::TextureFormatDesc {
use wgt::TextureFormat as Tf;
let (tex_internal, tex_external, data_type, num_components, va_kind) = match format {
Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE, 1, Vak::Float),
Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE, 1, Vak::Float),
Tf::R8Uint => (
glow::R8UI,
glow::RED_INTEGER,
glow::UNSIGNED_BYTE,
1,
Vak::Integer,
),
Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE, 1, Vak::Integer),
Tf::R16Uint => (
glow::R16UI,
glow::RED_INTEGER,
glow::UNSIGNED_SHORT,
1,
Vak::Integer,
),
Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT, 1, Vak::Integer),
Tf::R16Float => (glow::R16F, glow::RED, glow::UNSIGNED_SHORT, 1, Vak::Float),
Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE, 2, Vak::Float),
Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE, 2, Vak::Float),
Tf::Rg8Uint => (
glow::RG8UI,
glow::RG_INTEGER,
glow::UNSIGNED_BYTE,
2,
Vak::Integer,
),
Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE, 2, Vak::Integer),
Tf::R32Uint => (
glow::R32UI,
glow::RED_INTEGER,
glow::UNSIGNED_INT,
1,
Vak::Integer,
),
Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT, 1, Vak::Integer),
Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT, 1, Vak::Float),
Tf::Rg16Uint => (
glow::RG16UI,
glow::RG_INTEGER,
glow::UNSIGNED_SHORT,
2,
Vak::Integer,
),
Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT, 2, Vak::Integer),
Tf::Rg16Float => (glow::RG16F, glow::RG, glow::UNSIGNED_SHORT, 2, Vak::Float),
Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE, 4, Vak::Float),
Tf::Rgba8UnormSrgb => (
glow::SRGB8_ALPHA8,
glow::RGBA,
glow::UNSIGNED_BYTE,
4,
Vak::Float,
),
Tf::Bgra8UnormSrgb => (
glow::SRGB8_ALPHA8,
glow::RGBA,
glow::UNSIGNED_BYTE,
4,
Vak::Float,
), //TODO?
Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE, 4, Vak::Float),
Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE, 4, Vak::Float),
Tf::Rgba8Uint => (
glow::RGBA8UI,
glow::RGBA_INTEGER,
glow::UNSIGNED_BYTE,
4,
Vak::Integer,
),
Tf::Rgba8Sint => (
glow::RGBA8I,
glow::RGBA_INTEGER,
glow::BYTE,
4,
Vak::Integer,
),
let (internal, external, data_type) = match texture_format {
Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE),
Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE),
Tf::R8Uint => (glow::R8UI, glow::RED_INTEGER, glow::UNSIGNED_BYTE),
Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE),
Tf::R16Uint => (glow::R16UI, glow::RED_INTEGER, glow::UNSIGNED_SHORT),
Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT),
Tf::R16Float => (glow::R16F, glow::RED, glow::HALF_FLOAT),
Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE),
Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE),
Tf::Rg8Uint => (glow::RG8UI, glow::RG_INTEGER, glow::UNSIGNED_BYTE),
Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE),
Tf::R32Uint => (glow::R32UI, glow::RED_INTEGER, glow::UNSIGNED_INT),
Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT),
Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT),
Tf::Rg16Uint => (glow::RG16UI, glow::RG_INTEGER, glow::UNSIGNED_SHORT),
Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT),
Tf::Rg16Float => (glow::RG16F, glow::RG, glow::HALF_FLOAT),
Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE),
Tf::Rgba8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE),
Tf::Bgra8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE), //TODO?
Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE),
Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE),
Tf::Rgba8Uint => (glow::RGBA8UI, glow::RGBA_INTEGER, glow::UNSIGNED_BYTE),
Tf::Rgba8Sint => (glow::RGBA8I, glow::RGBA_INTEGER, glow::BYTE),
Tf::Rgb10a2Unorm => (
glow::RGB10_A2,
glow::RGBA,
glow::UNSIGNED_INT_2_10_10_10_REV,
1,
Vak::Integer,
),
Tf::Rg11b10Float => (
glow::R11F_G11F_B10F,
glow::RGB,
glow::UNSIGNED_INT_10F_11F_11F_REV,
1,
Vak::Integer,
),
Tf::Rg32Uint => (
glow::RG32UI,
glow::RG_INTEGER,
glow::UNSIGNED_INT,
2,
Vak::Integer,
),
Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT, 2, Vak::Integer),
Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT, 2, Vak::Float),
Tf::Rgba16Uint => (
glow::RGBA16UI,
glow::RGBA_INTEGER,
glow::UNSIGNED_SHORT,
4,
Vak::Integer,
),
Tf::Rgba16Sint => (
glow::RGBA16I,
glow::RGBA_INTEGER,
glow::SHORT,
4,
Vak::Integer,
),
Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::UNSIGNED_SHORT, 4, Vak::Float),
Tf::Rgba32Uint => (
glow::RGBA32UI,
glow::RGBA_INTEGER,
glow::UNSIGNED_INT,
4,
Vak::Integer,
),
Tf::Rgba32Sint => (
glow::RGBA32I,
glow::RGBA_INTEGER,
glow::INT,
4,
Vak::Integer,
),
Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT, 4, Vak::Float),
Tf::Depth32Float => (
glow::DEPTH_COMPONENT32F,
glow::DEPTH_COMPONENT,
glow::FLOAT,
1,
Vak::Float,
),
Tf::Rg32Uint => (glow::RG32UI, glow::RG_INTEGER, glow::UNSIGNED_INT),
Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT),
Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT),
Tf::Rgba16Uint => (glow::RGBA16UI, glow::RGBA_INTEGER, glow::UNSIGNED_SHORT),
Tf::Rgba16Sint => (glow::RGBA16I, glow::RGBA_INTEGER, glow::SHORT),
Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::HALF_FLOAT),
Tf::Rgba32Uint => (glow::RGBA32UI, glow::RGBA_INTEGER, glow::UNSIGNED_INT),
Tf::Rgba32Sint => (glow::RGBA32I, glow::RGBA_INTEGER, glow::INT),
Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT),
Tf::Depth32Float => (glow::DEPTH_COMPONENT32F, glow::DEPTH_COMPONENT, glow::FLOAT),
Tf::Depth24Plus => (
glow::DEPTH_COMPONENT24,
glow::DEPTH_COMPONENT,
glow::UNSIGNED_NORMALIZED,
2,
Vak::Float,
),
Tf::Depth24PlusStencil8 => (
glow::DEPTH24_STENCIL8,
glow::DEPTH_COMPONENT,
glow::UNSIGNED_INT,
2,
Vak::Float,
),
Tf::Bc1RgbaUnorm
| Tf::Bc1RgbaUnormSrgb
@ -211,16 +112,59 @@ impl super::AdapterShared {
| Tf::Astc12x12RgbaUnormSrgb => unimplemented!(),
};
super::FormatDescription {
tex_internal,
tex_external,
super::TextureFormatDesc {
internal,
external,
data_type,
num_components,
va_kind,
}
}
}
pub(super) fn describe_vertex_format(vertex_format: wgt::VertexFormat) -> super::VertexFormatDesc {
use super::VertexAttribKind as Vak;
use wgt::VertexFormat as Vf;
let (element_count, element_format, attrib_kind) = match vertex_format {
Vf::Unorm8x2 => (2, glow::UNSIGNED_BYTE, Vak::Float),
Vf::Snorm8x2 => (2, glow::BYTE, Vak::Float),
Vf::Uint8x2 => (2, glow::UNSIGNED_BYTE, Vak::Integer),
Vf::Sint8x2 => (2, glow::BYTE, Vak::Integer),
Vf::Unorm8x4 => (4, glow::UNSIGNED_BYTE, Vak::Float),
Vf::Snorm8x4 => (4, glow::BYTE, Vak::Float),
Vf::Uint8x4 => (4, glow::UNSIGNED_BYTE, Vak::Integer),
Vf::Sint8x4 => (4, glow::BYTE, Vak::Integer),
Vf::Unorm16x2 => (2, glow::UNSIGNED_SHORT, Vak::Float),
Vf::Snorm16x2 => (2, glow::SHORT, Vak::Float),
Vf::Uint16x2 => (2, glow::UNSIGNED_SHORT, Vak::Integer),
Vf::Sint16x2 => (2, glow::SHORT, Vak::Integer),
Vf::Float16x2 => (2, glow::HALF_FLOAT, Vak::Float),
Vf::Unorm16x4 => (4, glow::UNSIGNED_SHORT, Vak::Float),
Vf::Snorm16x4 => (4, glow::SHORT, Vak::Float),
Vf::Uint16x4 => (4, glow::UNSIGNED_SHORT, Vak::Integer),
Vf::Sint16x4 => (4, glow::SHORT, Vak::Integer),
Vf::Float16x4 => (4, glow::HALF_FLOAT, Vak::Float),
Vf::Uint32 => (1, glow::UNSIGNED_INT, Vak::Integer),
Vf::Sint32 => (1, glow::INT, Vak::Integer),
Vf::Float32 => (1, glow::FLOAT, Vak::Float),
Vf::Uint32x2 => (2, glow::UNSIGNED_INT, Vak::Integer),
Vf::Sint32x2 => (2, glow::INT, Vak::Integer),
Vf::Float32x2 => (2, glow::FLOAT, Vak::Float),
Vf::Uint32x3 => (3, glow::UNSIGNED_INT, Vak::Integer),
Vf::Sint32x3 => (3, glow::INT, Vak::Integer),
Vf::Float32x3 => (3, glow::FLOAT, Vak::Float),
Vf::Uint32x4 => (4, glow::UNSIGNED_INT, Vak::Integer),
Vf::Sint32x4 => (4, glow::INT, Vak::Integer),
Vf::Float32x4 => (4, glow::FLOAT, Vak::Float),
Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(),
};
super::VertexFormatDesc {
element_count,
element_format,
attrib_kind,
}
}
pub fn map_filter_modes(
min: wgt::FilterMode,
mag: wgt::FilterMode,
@ -266,3 +210,14 @@ pub fn map_compare_func(fun: wgt::CompareFunction) -> u32 {
Cf::Always => glow::ALWAYS,
}
}
pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 {
use wgt::PrimitiveTopology as Pt;
match topology {
Pt::PointList => glow::POINTS,
Pt::LineList => glow::LINES,
Pt::LineStrip => glow::LINE_STRIP,
Pt::TriangleList => glow::TRIANGLES,
Pt::TriangleStrip => glow::TRIANGLE_STRIP,
}
}

View File

@ -1,6 +1,259 @@
use super::{DeviceResult, Resource}; //TEMP
use super::conv;
use super::Resource; //TEMP
use crate::util::map_naga_stage;
use glow::HasContext;
use std::{convert::TryInto, ptr::NonNull, sync::Arc};
use std::{convert::TryInto, iter, ptr::NonNull, sync::Arc};
type ShaderStage<'a> = (
naga::ShaderStage,
&'a crate::ProgrammableStage<'a, super::Api>,
);
type NameBindingMap = fxhash::FxHashMap<String, (super::BindingRegister, u8)>;
struct CompilationContext<'a> {
layout: &'a super::PipelineLayout,
sampler_map: &'a mut super::SamplerBindMap,
name_binding_map: &'a mut NameBindingMap,
}
impl CompilationContext<'_> {
fn consume_reflection(
self,
module: &naga::Module,
ep_info: &naga::valid::FunctionInfo,
reflection_info: naga::back::glsl::ReflectionInfo,
) {
for (handle, var) in module.global_variables.iter() {
if ep_info[handle].is_empty() {
continue;
}
let register = match var.class {
naga::StorageClass::Uniform => super::BindingRegister::UniformBuffers,
naga::StorageClass::Storage => super::BindingRegister::StorageBuffers,
_ => continue,
};
//TODO: make Naga reflect all the names, not just textures
let br = var.binding.as_ref().unwrap();
let slot = self.layout.get_slot(br);
let name = reflection_info.uniforms[&handle].clone();
log::debug!("Rebind buffer: {:?} -> {}", var.name.as_ref(), &name);
self.name_binding_map.insert(name, (register, slot));
}
for (name, mapping) in reflection_info.texture_mapping {
let tex_br = module.global_variables[mapping.texture]
.binding
.as_ref()
.unwrap();
let texture_linear_index = self.layout.get_slot(tex_br);
self.name_binding_map.insert(
name,
(super::BindingRegister::Textures, texture_linear_index),
);
if let Some(sampler_handle) = mapping.sampler {
let sam_br = module.global_variables[sampler_handle]
.binding
.as_ref()
.unwrap();
let sampler_linear_index = self.layout.get_slot(sam_br);
self.sampler_map[texture_linear_index as usize] = Some(sampler_linear_index);
}
}
}
}
impl super::Device {
unsafe fn compile_shader(
&self,
shader: &str,
naga_stage: naga::ShaderStage,
) -> Result<glow::Shader, crate::PipelineError> {
let gl = &self.shared.context;
let target = match naga_stage {
naga::ShaderStage::Vertex => glow::VERTEX_SHADER,
naga::ShaderStage::Fragment => glow::FRAGMENT_SHADER,
naga::ShaderStage::Compute => glow::COMPUTE_SHADER,
};
let raw = gl.create_shader(target).unwrap();
gl.shader_source(raw, shader);
gl.compile_shader(raw);
log::info!("\tCompiled shader {:?}", raw);
let compiled_ok = gl.get_shader_compile_status(raw);
let msg = gl.get_shader_info_log(raw);
if compiled_ok {
if !msg.is_empty() {
log::warn!("\tCompile: {}", msg);
}
Ok(raw)
} else {
Err(crate::PipelineError::Linkage(
map_naga_stage(naga_stage),
msg,
))
}
}
fn create_shader(
&self,
naga_stage: naga::ShaderStage,
stage: &crate::ProgrammableStage<super::Api>,
context: CompilationContext,
) -> Result<glow::Shader, crate::PipelineError> {
use naga::back::glsl;
let options = glsl::Options {
version: self.shared.shading_language_version,
shader_stage: naga_stage,
entry_point: stage.entry_point.to_string(),
};
let shader = &stage.module.naga;
let entry_point_index = (&shader.module.entry_points)
.into_iter()
.position(|ep| ep.name.as_str() == stage.entry_point)
.ok_or(crate::PipelineError::EntryPoint(naga_stage))?;
let mut output = String::new();
let mut writer = glsl::Writer::new(&mut output, &shader.module, &shader.info, &options)
.map_err(|e| {
let msg = format!("{}", e);
crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg)
})?;
let reflection_info = writer.write().map_err(|e| {
let msg = format!("{}", e);
crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg)
})?;
log::debug!("Naga generated shader:\n{}", output);
context.consume_reflection(
&shader.module,
shader.info.get_entry_point(entry_point_index),
reflection_info,
);
unsafe { self.compile_shader(&output, naga_stage) }
}
unsafe fn create_pipeline<'a, I: Iterator<Item = ShaderStage<'a>>>(
&self,
shaders: I,
layout: &super::PipelineLayout,
) -> Result<super::PipelineInner, crate::PipelineError> {
let gl = &self.shared.context;
let program = gl.create_program().unwrap();
let mut name_binding_map = NameBindingMap::default();
let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS];
let mut has_stages = wgt::ShaderStage::empty();
let mut shaders_to_delete = arrayvec::ArrayVec::<[_; 3]>::new();
for (naga_stage, stage) in shaders {
has_stages |= map_naga_stage(naga_stage);
let context = CompilationContext {
layout,
sampler_map: &mut sampler_map,
name_binding_map: &mut name_binding_map,
};
let shader = self.create_shader(naga_stage, stage, context)?;
shaders_to_delete.push(shader);
}
// Create empty fragment shader if only vertex shader is present
if has_stages == wgt::ShaderStage::VERTEX {
let version = match self.shared.shading_language_version {
naga::back::glsl::Version::Embedded(v) => v,
naga::back::glsl::Version::Desktop(_) => unreachable!(),
};
let shader_src = format!("#version {} es \n void main(void) {{}}", version,);
log::info!("Only vertex shader is present. Creating an empty fragment shader",);
let shader = self.compile_shader(&shader_src, naga::ShaderStage::Fragment)?;
shaders_to_delete.push(shader);
}
for &shader in shaders_to_delete.iter() {
gl.attach_shader(program, shader);
}
gl.link_program(program);
for shader in shaders_to_delete {
gl.delete_shader(shader);
}
log::info!("\tLinked program {:?}", program);
let linked_ok = gl.get_program_link_status(program);
let msg = gl.get_program_info_log(program);
if !linked_ok {
return Err(crate::PipelineError::Linkage(has_stages, msg));
}
if !msg.is_empty() {
log::warn!("\tLink: {}", msg);
}
if !self
.shared
.private_caps
.contains(super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER)
{
gl.use_program(Some(program));
for (ref name, (register, slot)) in name_binding_map {
log::trace!("Get binding {:?} from program {:?}", name, program);
match register {
super::BindingRegister::Textures => {
let loc = gl.get_uniform_location(program, name).unwrap();
gl.uniform_1_i32(Some(&loc), slot as _);
}
super::BindingRegister::UniformBuffers => {
let index = gl.get_uniform_block_index(program, name).unwrap();
gl.uniform_block_binding(program, index, slot as _);
}
super::BindingRegister::StorageBuffers => {
let index = gl.get_shader_storage_block_index(program, name).unwrap();
gl.shader_storage_block_binding(program, index, slot as _);
}
}
}
}
let uniforms = {
let count = gl.get_active_uniforms(program);
let mut offset = 0;
let mut uniforms = Vec::new();
for uniform in 0..count {
let glow::ActiveUniform { size, utype, name } =
gl.get_active_uniform(program, uniform).unwrap();
if let Some(location) = gl.get_uniform_location(program, &name) {
// Sampler2D won't show up in UniformLocation and the only other uniforms
// should be push constants
uniforms.push(super::UniformDesc {
location,
offset,
utype,
});
offset += size as u32;
}
}
uniforms.into_boxed_slice()
};
Ok(super::PipelineInner {
program,
sampler_map,
uniforms,
})
}
}
impl crate::Device<super::Api> for super::Device {
unsafe fn exit(self) {
@ -76,7 +329,7 @@ impl crate::Device<super::Api> for super::Device {
is_coherent: buffer.map_flags & glow::MAP_COHERENT_BIT != 0,
})
}
unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> DeviceResult<()> {
unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> {
let gl = &self.shared.context;
gl.bind_buffer(buffer.target, Some(buffer.raw));
gl.unmap_buffer(buffer.target);
@ -131,14 +384,14 @@ impl crate::Device<super::Api> for super::Device {
gl.renderbuffer_storage_multisample(
glow::RENDERBUFFER,
desc.sample_count as i32,
format_desc.tex_internal,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
);
} else {
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.tex_internal,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
);
@ -164,7 +417,7 @@ impl crate::Device<super::Api> for super::Device {
gl.tex_storage_3d(
target,
desc.mip_level_count as i32,
format_desc.tex_internal,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
desc.size.depth_or_array_layers as i32,
@ -176,7 +429,7 @@ impl crate::Device<super::Api> for super::Device {
gl.tex_storage_2d(
target,
desc.mip_level_count as i32,
format_desc.tex_internal,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
);
@ -189,7 +442,7 @@ impl crate::Device<super::Api> for super::Device {
gl.tex_storage_3d(
target,
desc.mip_level_count as i32,
format_desc.tex_internal,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
desc.size.depth_or_array_layers as i32,
@ -391,37 +644,87 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &crate::ShaderModuleDescriptor,
shader: crate::ShaderInput,
) -> Result<Resource, crate::ShaderError> {
Ok(Resource)
) -> Result<super::ShaderModule, crate::ShaderError> {
Ok(super::ShaderModule {
naga: match shader {
crate::ShaderInput::SpirV(_) => panic!("Unable to pass-through SPIR-V"),
crate::ShaderInput::Naga(naga) => naga,
},
})
}
unsafe fn destroy_shader_module(&self, module: Resource) {}
unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) {}
unsafe fn create_render_pipeline(
&self,
desc: &crate::RenderPipelineDescriptor<super::Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
) -> Result<super::RenderPipeline, crate::PipelineError> {
let shaders = iter::once((naga::ShaderStage::Vertex, &desc.vertex_stage)).chain(
desc.fragment_stage
.as_ref()
.map(|fs| (naga::ShaderStage::Fragment, fs)),
);
let inner = self.create_pipeline(shaders, desc.layout)?;
let attributes = {
let gl = &self.shared.context;
let mut attributes = Vec::new();
for (index, vb_layout) in desc.vertex_buffers.iter().enumerate() {
for vat in vb_layout.attributes.iter() {
let format_desc = conv::describe_vertex_format(vat.format);
attributes.push(super::AttributeDesc {
location: vat.shader_location,
offset: vat.offset as u32,
buffer_index: index as u32,
format_desc,
});
}
}
attributes.into_boxed_slice()
};
Ok(super::RenderPipeline {
inner,
primitive: desc.primitive.clone(),
attributes,
depth: desc.depth_stencil.clone(),
})
}
unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
let gl = &self.shared.context;
gl.delete_program(pipeline.inner.program);
}
unsafe fn create_compute_pipeline(
&self,
desc: &crate::ComputePipelineDescriptor<super::Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
) -> Result<super::ComputePipeline, crate::PipelineError> {
let shaders = iter::once((naga::ShaderStage::Compute, &desc.stage));
let inner = self.create_pipeline(shaders, desc.layout)?;
Ok(super::ComputePipeline { inner })
}
unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
let gl = &self.shared.context;
gl.delete_program(pipeline.inner.program);
}
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> DeviceResult<Resource> {
) -> Result<Resource, crate::DeviceError> {
Ok(Resource)
}
unsafe fn destroy_query_set(&self, set: Resource) {}
unsafe fn create_fence(&self) -> DeviceResult<Resource> {
unsafe fn create_fence(&self) -> Result<Resource, crate::DeviceError> {
Ok(Resource)
}
unsafe fn destroy_fence(&self, fence: Resource) {}
unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult<crate::FenceValue> {
unsafe fn get_fence_value(
&self,
fence: &Resource,
) -> Result<crate::FenceValue, crate::DeviceError> {
Ok(0)
}
unsafe fn wait(
@ -429,7 +732,7 @@ impl crate::Device<super::Api> for super::Device {
fence: &Resource,
value: crate::FenceValue,
timeout_ms: u32,
) -> DeviceResult<bool> {
) -> Result<bool, crate::DeviceError> {
Ok(true)
}

View File

@ -587,7 +587,7 @@ impl crate::Surface<super::Api> for Surface {
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.tex_internal,
format_desc.internal,
config.extent.width as _,
config.extent.height as _,
);
@ -606,7 +606,7 @@ impl crate::Surface<super::Api> for Surface {
renderbuffer,
framebuffer,
extent: config.extent,
format: format_desc.tex_internal,
format: format_desc.internal,
sample_type: wgt::TextureSampleType::Float { filterable: false },
});

View File

@ -21,7 +21,10 @@ pub struct Api;
#[derive(Debug)]
pub struct Resource;
type DeviceResult<T> = Result<T, crate::DeviceError>;
//Note: we can support more samplers if not every one of them is used at a time,
// but it probably doesn't worth it.
const MAX_SAMPLER_SLOTS: usize = 16;
const MAX_TEXTURE_SLOTS: usize = 16;
impl crate::Api for Api {
type Instance = Instance;
@ -44,9 +47,9 @@ impl crate::Api for Api {
type BindGroupLayout = BindGroupLayout;
type BindGroup = BindGroup;
type PipelineLayout = PipelineLayout;
type ShaderModule = Resource;
type RenderPipeline = Resource;
type ComputePipeline = Resource;
type ShaderModule = ShaderModule;
type RenderPipeline = RenderPipeline;
type ComputePipeline = ComputePipeline;
}
bitflags::bitflags! {
@ -152,23 +155,22 @@ impl Sampled for SampledTextureBinding {
#[derive(Debug, Clone, Copy)]
enum VertexAttribKind {
Float, // glVertexAttribPointer
Float, // glVertexAttribPointer
Integer, // glVertexAttribIPointer
Double, // glVertexAttribLPointer
//Double, // glVertexAttribLPointer
}
#[derive(Debug)]
struct FormatDescription {
tex_internal: u32,
tex_external: u32,
struct TextureFormatDesc {
internal: u32,
external: u32,
data_type: u32,
num_components: u8,
va_kind: VertexAttribKind,
}
struct AdapterShared {
context: glow::Context,
private_caps: PrivateCapability,
shading_language_version: naga::back::glsl::Version,
}
pub struct Adapter {
@ -218,7 +220,7 @@ impl TextureInner {
#[derive(Debug)]
pub struct Texture {
inner: TextureInner,
format_desc: FormatDescription,
format_desc: TextureFormatDesc,
format_info: wgt::TextureFormatInfo,
}
@ -258,6 +260,13 @@ pub struct PipelineLayout {
group_infos: Box<[BindGroupLayoutInfo]>,
}
impl PipelineLayout {
fn get_slot(&self, br: &naga::ResourceBinding) -> u8 {
let group_info = &self.group_infos[br.group as usize];
group_info.binding_to_slot[br.binding as usize]
}
}
#[derive(Debug)]
enum BindingRegister {
Textures,
@ -287,6 +296,54 @@ pub struct BindGroup {
contents: Box<[RawBinding]>,
}
#[derive(Debug)]
pub struct ShaderModule {
naga: crate::NagaShader,
}
struct VertexFormatDesc {
element_count: i32,
element_format: u32,
attrib_kind: VertexAttribKind,
}
struct AttributeDesc {
location: u32,
offset: u32,
buffer_index: u32,
format_desc: VertexFormatDesc,
}
#[derive(Clone)]
struct UniformDesc {
location: glow::UniformLocation,
offset: u32,
utype: u32,
}
/// For each texture in the pipeline layout, store the index of the only
/// sampler (in this layout) that the texture is used with.
type SamplerBindMap = [Option<u8>; MAX_TEXTURE_SLOTS];
struct PipelineInner {
program: glow::Program,
sampler_map: SamplerBindMap,
uniforms: Box<[UniformDesc]>,
}
pub struct RenderPipeline {
inner: PipelineInner,
//blend_targets: Vec<pso::ColorBlendDesc>,
attributes: Box<[AttributeDesc]>,
//vertex_buffers: Box<[wgt::VertexBufferLayout]>,
primitive: wgt::PrimitiveState,
depth: Option<wgt::DepthStencilState>,
}
pub struct ComputePipeline {
inner: PipelineInner,
}
#[derive(Debug)]
struct TextureCopyInfo {
external_format: u32,
@ -297,13 +354,13 @@ struct TextureCopyInfo {
#[derive(Debug)]
enum Command {
Draw {
primitive: u32,
topology: u32,
start_vertex: u32,
vertex_count: u32,
instance_count: u32,
},
DrawIndexed {
primitive: u32,
topology: u32,
index_type: u32,
index_count: u32,
index_offset: wgt::BufferAddress,
@ -311,12 +368,12 @@ enum Command {
instance_count: u32,
},
DrawIndirect {
primitive: u32,
topology: u32,
indirect_buf: glow::Buffer,
indirect_offset: wgt::BufferAddress,
},
DrawIndexedIndirect {
primitive: u32,
topology: u32,
index_type: u32,
indirect_buf: glow::Buffer,
indirect_offset: wgt::BufferAddress,
@ -376,7 +433,7 @@ pub struct CommandBuffer {
#[derive(Default)]
struct CommandState {
primitive: u32,
topology: u32,
index_format: wgt::IndexFormat,
index_offset: wgt::BufferAddress,
}

View File

@ -20,16 +20,16 @@ impl super::Queue {
let gl = &self.shared.context;
match *command {
C::Draw {
primitive,
topology,
start_vertex,
vertex_count,
instance_count,
} => {
if instance_count == 1 {
gl.draw_arrays(primitive, start_vertex as i32, vertex_count as i32);
gl.draw_arrays(topology, start_vertex as i32, vertex_count as i32);
} else {
gl.draw_arrays_instanced(
primitive,
topology,
start_vertex as i32,
vertex_count as i32,
instance_count as i32,
@ -37,7 +37,7 @@ impl super::Queue {
}
}
C::DrawIndexed {
primitive,
topology,
index_type,
index_count,
index_offset,
@ -45,27 +45,27 @@ impl super::Queue {
instance_count,
} => match (base_vertex, instance_count) {
(0, 1) => gl.draw_elements(
primitive,
topology,
index_count as i32,
index_type,
index_offset as i32,
),
(0, _) => gl.draw_elements_instanced(
primitive,
topology,
index_count as i32,
index_type,
index_offset as i32,
instance_count as i32,
),
(_, 1) => gl.draw_elements_base_vertex(
primitive,
topology,
index_count as i32,
index_type,
index_offset as i32,
base_vertex,
),
(_, _) => gl.draw_elements_instanced_base_vertex(
primitive,
topology,
index_count as _,
index_type,
index_offset as i32,
@ -74,16 +74,16 @@ impl super::Queue {
),
},
C::DrawIndirect {
primitive: _,
topology: _,
indirect_buf,
indirect_offset: _,
} => {
gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf));
//TODO: https://github.com/grovesNL/glow/issues/172
//gl.draw_arrays_indirect(primitive, indirect_offset);
//gl.draw_arrays_indirect(topology, indirect_offset);
}
C::DrawIndexedIndirect {
primitive: _,
topology: _,
index_type: _,
indirect_buf,
indirect_offset: _,

View File

@ -837,7 +837,6 @@ pub struct CommandEncoderDescriptor<'a, A: Api> {
}
/// Naga shader module.
#[derive(Debug)]
pub struct NagaShader {
/// Shader module IR.
pub module: naga::Module,
@ -845,6 +844,14 @@ pub struct NagaShader {
pub info: naga::valid::ModuleInfo,
}
// Custom implementation avoids the need to generate Debug impl code
// for the whole Naga module and info.
impl fmt::Debug for NagaShader {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Naga shader")
}
}
/// Shader input.
pub enum ShaderInput<'a> {
Naga(NagaShader),

View File

@ -61,10 +61,10 @@ impl super::Device {
},
};
let module = &stage.module.raw.module;
let module = &stage.module.naga.module;
let (source, info) = naga::back::msl::write_string(
module,
&stage.module.raw.info,
&stage.module.naga.info,
&layout.naga_options,
&pipeline_options,
)
@ -644,7 +644,7 @@ impl crate::Device<super::Api> for super::Device {
shader: crate::ShaderInput,
) -> Result<super::ShaderModule, crate::ShaderError> {
match shader {
crate::ShaderInput::Naga(raw) => Ok(super::ShaderModule { raw }),
crate::ShaderInput::Naga(naga) => Ok(super::ShaderModule { naga }),
crate::ShaderInput::SpirV(_) => {
unreachable!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend")
}

View File

@ -555,7 +555,7 @@ unsafe impl Sync for BindGroup {}
#[derive(Debug)]
pub struct ShaderModule {
raw: crate::NagaShader,
naga: crate::NagaShader,
}
#[derive(Debug, Default)]