#ifndef video_hpp #define video_hpp #include #include extern "C" { #include "sc/sh_enums.h" #include "vid_enums.h" } #include "asset.hpp" struct App; struct Arena; struct Heap; template struct Primitive_Id { T index; Primitive_Id(): index(0) {} Primitive_Id(T i): index(i) {} bool operator==(Primitive_Id other) const { return index == other.index; } operator bool() const { return index != 0; } }; struct Texture_Id : public Primitive_Id { using Primitive_Id::Primitive_Id; }; struct Buffer_Id : public Primitive_Id { using Primitive_Id::Primitive_Id; }; struct Vertex_Format_Id : public Primitive_Id { using Primitive_Id::Primitive_Id; }; struct Shader_Id : public Primitive_Id { using Primitive_Id::Primitive_Id; }; struct Sampler_Id : public Primitive_Id { using Primitive_Id::Primitive_Id; }; #define descriptor_payload_size 8 struct Descriptor { enum class Type { texture, constant_buffer } type; int slot; uint8_t payload[descriptor_payload_size]; }; struct Texture_Descriptor { Texture_Id texture; Sampler_Id sampler; }; struct Constant_Buffer_Descriptor { Buffer_Id buffer; }; static_assert(sizeof(Texture_Descriptor) <= descriptor_payload_size); static_assert(sizeof(Constant_Buffer_Descriptor) <= descriptor_payload_size); #define pipeline_max_descriptors 16 struct Pipeline { uint64_t pipeline_hash; uint64_t descriptor_resource_hash; Vertex_Format_Id vertex_format; Shader_Id shader; Descriptor descriptors[pipeline_max_descriptors]; int descriptor_count; bool desc_layout_eq(const Pipeline& other) const { int i, c = descriptor_count; if (other.pipeline_hash != pipeline_hash) return false; if (other.descriptor_count != c) return false; for (i = 0; i < c; i++) { auto& a = descriptors[i]; auto& b = other.descriptors[i]; if (a.type != b.type) return false; if (a.slot != b.slot) return false; } return true; } bool desc_resources_eq(const Pipeline& other) const { int i, c = descriptor_count; if (other.descriptor_resource_hash != descriptor_resource_hash) return false; if (other.descriptor_count != c) return false; for (i = 0; i < c; i++) { auto& a = descriptors[i]; auto& b = other.descriptors[i]; if (a.type != b.type) return false; if (a.slot != b.slot) return false; switch (a.type) { case Descriptor::Type::texture: { Texture_Descriptor* ta = (Texture_Descriptor*)a.payload; Texture_Descriptor* tb = (Texture_Descriptor*)b.payload; if (ta->texture != tb->texture) return false; if (ta->sampler != tb->sampler) return false; } break; case Descriptor::Type::constant_buffer: { Constant_Buffer_Descriptor* ca = (Constant_Buffer_Descriptor*)a.payload; Constant_Buffer_Descriptor* cb = (Constant_Buffer_Descriptor*)b.payload; if (ca->buffer != cb->buffer) return false; } break; } } return true; } }; struct Colour { uint8_t r, g, b, a; }; struct Render_Pass { Texture_Id target; Colour clear; bool operator==(const Render_Pass& other) const { int size = sizeof *this, i; uint8_t* bba = (uint8_t*)this; uint8_t* bbb = (uint8_t*)&other; for (i = 0; i < size; i++, bba++, bbb++) if (*bba != *bbb) return false; return true; } }; struct Vertex_Buffer_Binding { Buffer_Id id; size_t offset; int target; }; struct Draw { Vertex_Buffer_Binding* verts; int vertex_count; int instance_count; int first_vertex; int first_instance; }; struct Pipeline_Builder { Arena* arena; Render_Pass* pass; Pipeline* pip; Pipeline_Builder(Arena* arena); void begin_rp(); void rp_target(Texture_Id id, Colour clear_colour); Render_Pass& build_rp(); void validate_rp(); void begin(); void shader(Shader_Id s); void vertex_format(Vertex_Format_Id vf); void texture(int binding, Texture_Id t, Sampler_Id s); void cbuffer(int binding, Buffer_Id id); Pipeline& build(); void validate(); }; enum Resource_State { undefined, copy_dst, copy_src, shader_read }; struct Texture : public Asset { Texture_Id id; int w, h; bool alias; }; namespace Buffer_Flags { enum { index_buffer = 1 << 0, vertex_buffer = 1 << 1, constant_buffer = 1 << 2, storage_buffer = 1 << 3, cpu_read = 1 << 4, cpu_readwrite = 1 << 5, copy_src = 1 << 6, copy_dst = 1 << 7 }; }; struct Buffer { Buffer_Id id; }; enum class Filter_Mode { point, linear }; enum class Address_Mode { repeat, mirror, clamp, border }; struct Sampler_State { Filter_Mode min; Filter_Mode mag; Filter_Mode mip; Address_Mode address_u; Address_Mode address_v; Address_Mode address_w; float border[4]; float mip_bias; bool aniso; }; struct Vertex_Format_Desc { struct Binding { int binding; int stride; SBinding_Rate rate; }; struct Attribute { int binding; int index; int offset; SVariable_Type type; }; Binding* bindings; Attribute* attributes; int binding_count; int attribute_count; }; struct Context; struct Shader; struct Device { Arena* arena; Heap* heap; App* app; static Device* create(Arena* a, App* ap); void init(Arena* a, App* ap); void destroy(); void on_resize(); void begin_frame(); void submit(Context& ctx); void present(); Context& acquire(); Context& get_ctx(); Texture_Id get_backbuffer(); Texture& get_texture(Texture_Id id); void destroy_texture(Texture_Id id); Buffer_Id create_buffer(size_t size, int flags); void* map_buffer(Buffer_Id id, size_t offset, size_t size); void unmap_buffer(Buffer_Id id); Buffer& get_buffer(Buffer_Id id); void destroy_buffer(Buffer_Id id); Vertex_Format_Id create_vertex_format( const Vertex_Format_Desc& desc ); void destroy_vertex_format(Vertex_Format_Id fmt); Shader& get_shader(Shader_Id id); Sampler_Id create_sampler(const Sampler_State& state); void destroy_sampler(Sampler_Id id); }; struct Context { void wait(); void submit( const Draw& draw, const Pipeline& p, const Render_Pass& rp ); void submit( const Draw* draws, int count, const Pipeline& p, const Render_Pass& rp ); void submit(const Render_Pass& rp); void copy(Buffer_Id dst, Buffer_Id src); void copy(Texture_Id dst, Buffer_Id src); void transition(Texture_Id id, Resource_State state); }; struct Shader : public Asset { Shader_Id id; Vertex_Format_Id vf; void destroy(Device* dev); /* -1 on failure */ int binding_index(const char* name); int attribute_index(const char* name); int target_index(const char* name); int descriptor_binding(const char* name); int descriptor_stage(int slot); }; #endif