Skip to content

Instantly share code, notes, and snippets.

@kabergstrom
Last active January 2, 2019 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kabergstrom/51a7aed84a52c72d75e469ba014c041f to your computer and use it in GitHub Desktop.
Save kabergstrom/51a7aed84a52c72d75e469ba014c041f to your computer and use it in GitHub Desktop.
Encoder API example
trait Renderer<'a> {
/// Takes a pipeline, an ordered list of field descriptors and returns pointers into mapped GPU buffers for each field.
fn pipeline_outputs(
&mut self,
pipeline: Handle<Pipeline>,
fields: &[FieldDesc],
entity_offset: u32,
) -> &'a [EncodeTarget];
}
/// Enum of supported field types
enum FieldType {
Matrix4x4,
// etc..
}
/// Name and type of a field that can be linked to a GPU buffer struct
struct FieldDesc {
name: &'static str,
typ: FieldType,
}
/// Wrapper around a pointer that can be written to. Unsafe
struct EncodeTarget {
dst: Option<*mut u8>,
}
impl EncodeTarget {
#[inline]
unsafe fn write<T: Copy>(&self, value: &T) {
if self.dst.is_none() { return }
let ptr = self.dst.unwrap() as *mut T;
*ptr = *value;
}
}
/// Encoder is responsible for encoding `World` component data into GPU buffers.
trait Encoder<'a, T: SystemData> {
/// `pipelines` can use the `Renderer` to build pipelines dynamically or use a cached pipeline
fn pipelines(data: &T, renderer: &Renderer) -> Vec<Handle<Pipeline>>;
/// `fields` returns an ordered list of field descriptors that are used by the `Renderer` to find GPU buffer pointers
fn fields() -> &'a [FieldDesc];
/// `encode` writes data from components to the target GPU buffer pointers.
/// `outputs` is required to have the same order and size as the return value of `fields`.
fn encode(data: &T, outputs: &[EncodeTarget]);
}
// The Encoder implementation is quite verbose and I think we can use macros to derive most of it based on the component types.
static ASDF_FIELDS: &'static [FieldDesc] = &[FieldDesc {
name: "iso",
typ: FieldType::Matrix4x4,
}];
impl<'a> Encoder<'a, Self> for (Transform, Renderable) {
#[inline]
fn pipelines((_, renderable): &Self, _: &Renderer) -> Vec<Handle<Pipeline>> {
vec![renderable.pipeline]
}
#[inline]
fn fields() -> &'a [FieldDesc] {
ASDF_FIELDS
}
#[inline]
fn encode((transform, _): &Self, outputs: &[EncodeTarget]) {
unsafe {
outputs[0].write(&transform.iso);
}
}
}
#[inline]
fn run_encoder<'a, S: SystemData, T: Encoder<'a, S>>(
data: &S,
renderer: &mut Renderer,
entity_offset: u32,
) {
let pipelines = T::pipelines(data, renderer);
for pipeline in pipelines {
let fields = T::fields();
let outputs = renderer.pipeline_outputs(pipeline, fields, entity_offset);
T::encode(data, outputs);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment