#include "video.hpp" #include extern "C" { #include "memory.h" #include "plat.h" #include "str.h" } Pipeline_Builder::Pipeline_Builder(Arena* arena, Device* dev): arena(arena), dev(dev) {} void Pipeline_Builder::begin_rp() { pass = (Render_Pass*)arena_alloc(arena, sizeof *pass); zero(pass, sizeof *pass); } void Pipeline_Builder::rp_target(Texture_Id id, Colour clear) { int i = pass->colour_count++; Texture& texture = dev->get_texture(id); Render_Pass::Target t{ .id = id, .fmt = texture.fmt, .mode = Clear_Mode::clear, .clear = { .colour = clear } }; assert(i < max_colour_attachments); pass->colours[i] = t; } void Pipeline_Builder::rp_target(Texture_Id id, Clear_Mode clear) { int i = pass->colour_count++; Texture& texture = dev->get_texture(id); Render_Pass::Target t{ .id = id, .fmt = texture.fmt, .mode = clear, .clear = { .depth = 0.0f } }; assert(i < max_colour_attachments); assert(clear != Clear_Mode::clear); pass->colours[i] = t; } void Pipeline_Builder::rp_depth_target(Texture_Id id, float clear) { Texture& texture = dev->get_texture(id); Render_Pass::Target t{ .id = id, .fmt = texture.fmt, .mode = Clear_Mode::clear, .clear = { .depth = clear } }; pass->depth = t; } void Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mode) { Texture& texture = dev->get_texture(id); Render_Pass::Target t{ .id = id, .fmt = texture.fmt, .mode = mode, .clear = { .depth = 0.0f } }; assert(mode != Clear_Mode::clear); pass->depth = t; } void Pipeline_Builder::validate_rp() { int i, c = pass->colour_count; int w, h; assert(c || pass->depth.id); if (c) { Texture& tex = dev->get_texture(pass->colours[0].id); assert(pass->colours[0].id); assert(pass->colours[0].fmt == tex.fmt); w = tex.w; h = tex.h; assert(w && h); } for (i = 1; i < c; i++) { Texture& tex = dev->get_texture(pass->colours[i].id); assert(pass->colours[i].id); assert(pass->colours[i].fmt == tex.fmt); assert(tex.w == w); assert(tex.h == h); } if (pass->depth.id) { Texture& d = dev->get_texture(pass->depth.id); assert(d.fmt == pass->depth.fmt); assert( d.fmt == texture_format_d16 || d.fmt == texture_format_d24s8 || d.fmt == texture_format_d32 ); if (c) { assert(d.w == w); assert(d.h == h); } } } Render_Pass& Pipeline_Builder::build_rp() { int i, c = pass->colour_count; #define h(n, v) \ n = fnv1a64_2(n, (uint8_t*)&v, sizeof v) validate_rp(); h(pass->layout_hash, pass->colour_count); h(pass->layout_hash, pass->depth.fmt); h(pass->layout_hash, pass->depth.mode); h(pass->resource_hash, pass->depth.id); for (i = 0; i < c; i++) { Render_Pass::Target& ct = pass->colours[i]; h(pass->layout_hash, ct.fmt); h(pass->layout_hash, ct.mode); h(pass->resource_hash, ct.id); } return *pass; } void Pipeline_Builder::begin() { pip = (Pipeline*)arena_alloc(arena, sizeof *pip); zero(pip, sizeof *pip); if (dev) { Texture_Id backbuffer_id = dev->get_backbuffer(); Texture& backbuffer = dev->get_texture(backbuffer_id); pip->scissor[0] = 0; pip->scissor[1] = 0; pip->scissor[2] = backbuffer.w; pip->scissor[3] = backbuffer.h; pip->viewport[0] = 0; pip->viewport[1] = 0; pip->viewport[2] = backbuffer.w; pip->viewport[3] = backbuffer.h; } } void Pipeline_Builder::viewport( float x, float y, float w, float h ) { pip->viewport[0] = x; pip->viewport[1] = y; pip->viewport[2] = w; pip->viewport[3] = h; } void Pipeline_Builder::scissor( float x, float y, float w, float h ) { pip->scissor[0] = x; pip->scissor[1] = y; pip->scissor[2] = w; pip->scissor[3] = h; } void Pipeline_Builder::depth(bool test, bool write, Depth_Mode mode) { pip->depth_test = test; pip->depth_write = write; pip->depth_mode = mode; } void Pipeline_Builder::blend( Blend_Mode mode, Blend_Factor src, Blend_Factor dst ) { blend( Blend_Mode::add, Blend_Factor::src_colour, Blend_Factor::inv_src_alpha, mode, src, dst ); } void Pipeline_Builder::blend( Blend_Mode mode_col, Blend_Factor src_col, Blend_Factor dst_col, Blend_Mode mode_alpha, Blend_Factor src_alpha, Blend_Factor dst_alpha ) { pip->blend_enable = true; pip->blend_mode = mode_col; pip->blend_src = src_col; pip->blend_dst = dst_col; pip->blend_mode_alpha = mode_alpha; pip->blend_src_alpha = src_alpha; pip->blend_dst_alpha = dst_alpha; } void Pipeline_Builder::shader(Shader_Id s) { pip->shader = s; } void Pipeline_Builder::texture( int binding, Texture_Id t, Sampler_Id s ) { Descriptor* d; Texture_Descriptor* td; assert(pip->descriptor_count < pipeline_max_descriptors); d = &pip->descriptors[pip->descriptor_count++]; td = (Texture_Descriptor*)d->payload; d->slot = binding; d->type = Descriptor::Type::texture; td->sampler = s; td->texture = t; } void Pipeline_Builder::cbuffer( int binding, Buffer_Id id, int offset, int size ) { Descriptor* d; Constant_Buffer_Descriptor* cd; assert(pip->descriptor_count < pipeline_max_descriptors); d = &pip->descriptors[pip->descriptor_count++]; cd = (Constant_Buffer_Descriptor*)d->payload; d->slot = binding; d->type = Descriptor::Type::constant_buffer; cd->buffer = id; cd->offset = offset; cd->size = size; } void Pipeline_Builder::vertex_format(Vertex_Format_Id vf) { pip->vertex_format = vf; } Pipeline& Pipeline_Builder::build() { #define h(n, v) \ n = fnv1a64_2(n, (uint8_t*)&v, sizeof v) validate(); pip->pipeline_hash = fnv1a64(0, 0); h(pip->pipeline_hash, pip->vertex_format); h(pip->pipeline_hash, pip->shader); h(pip->pipeline_hash, pip->descriptor_count); h(pip->pipeline_hash, pip->viewport[0]); h(pip->pipeline_hash, pip->viewport[1]); h(pip->pipeline_hash, pip->viewport[2]); h(pip->pipeline_hash, pip->viewport[3]); h(pip->pipeline_hash, pip->scissor[0]); h(pip->pipeline_hash, pip->scissor[1]); h(pip->pipeline_hash, pip->scissor[2]); h(pip->pipeline_hash, pip->scissor[3]); h(pip->pipeline_hash, pip->depth_test); h(pip->pipeline_hash, pip->depth_write); h(pip->pipeline_hash, pip->depth_mode); h(pip->pipeline_hash, pip->blend_enable); h(pip->pipeline_hash, pip->blend_mode); h(pip->pipeline_hash, pip->blend_mode_alpha); h(pip->pipeline_hash, pip->blend_src); h(pip->pipeline_hash, pip->blend_dst); h(pip->pipeline_hash, pip->blend_src_alpha); h(pip->pipeline_hash, pip->blend_dst_alpha); { int i, e = pip->descriptor_count; pip->descriptor_resource_hash = fnv1a64(0, 0); for (i = 0; i < e; i++) { Descriptor* d = &pip->descriptors[i]; h(pip->pipeline_hash, d->type); h(pip->pipeline_hash, d->slot); h(pip->descriptor_resource_hash, d->type); h(pip->descriptor_resource_hash, d->slot); switch (d->type) { case Descriptor::Type::texture: { auto td = (Texture_Descriptor*)d->payload; h(pip->descriptor_resource_hash, td->sampler); h(pip->descriptor_resource_hash, td->texture); } break; case Descriptor::Type::constant_buffer: { auto cd = (Constant_Buffer_Descriptor*)d->payload; h(pip->descriptor_resource_hash, cd->buffer); h(pip->descriptor_resource_hash, cd->size); h(pip->descriptor_resource_hash, cd->offset); } break; } } } return *pip; #undef h } void Pipeline_Builder::validate() { assert(pip->vertex_format); assert(pip->shader); }