-- --------------------------------------------------------------------------------------------------- -- bins -- All geometry ends up in a binding, pipeline, uniforms and draw calls. -- So to make this more efficient, geometry buffers (vert, uv, index, normals and others) are -- organized in two main bin categories. -- Main category: Priority - this is the main ordering of rendering. -- The higher the priority id the further down the list of rendering. -- Thus bins with priority 1 are highest, and are rendered first. -- Secondary category: Shader order id - this is the ordering within a bin. -- The higher the shader order id, also the further down the list of rendering within a bin -- Thus geometry can be ordered within a priority bin -- This is most often happening when the render engine does specifc types of sorting -- -- Notes: Initially the shader order id, will not be managed or used. To be implemented later if -- needed (which is expected) -- -- -- bin default priority ranges. -- bins will have ranges for specific types of shaders and geometry. -- If a material is tagged with transparent, or opaque then the geometry will be -- added to the transparent or opaque bins respectively. -- -- The default bin priority ranges are fixed. And _shall_ _not_ change for the duration of the -- development of the rendering engine. READ THIS: THEY ARE FIXED. DO NOT CHANGE! -- -- pass -- A pass is a collection of bin ids to render together. -- Thus while you might have an ordered set of geom in bins, they can be associated -- with a specific pass if needed - even multiple passes eg: -- when rendering to texture then rendering the same geometry to the display, or; -- rendering one geometry as transparent, and one in the gui. -- -- geometry -- The geometry object is specifically: -- 1. A set of buffers (vert, index, etc) -- 2. An associated material id -- 3. Unifrom data - for vs, and fs uniforms when preparing the shaders before draw. -- 4. The offset and length of the draw call. This allows for the same buffers to be -- used with different materials or uniform data. -- When the bin is created, it will do so for the buffers, and assign them an id. If the same -- buffers are submitted again, it will lookup these and use them. Minimizing duplication. -- --------------------------------------------------------------------------------------------------- local sapp = require("sokol_app") local slib = require("sokol_libs") -- Warn - always after gfx!! local hmm = require("hmm") local hutils = require("hmm_utils") local utils = require("lua.utils") local ffi = require("ffi") -- --------------------------------------------------------------------------------------------------- local tinsert = table.insert local tcount = table.getn -- --------------------------------------------------------------------------------------------------- local bintype = { BTYPE_CUSTOM_BG = 0x1000, BTYPE_BACKGROUND = 0x2000, BTYPE_TRANSPARENT = 0x4000, BTYPE_CUT_OUT = 0x6000, BTYPE_OPAQUE = 0x8000, BTYPE_GUI = 0xA000, BTYPE_CUSTOM_GUI = 0xC000, BTYPE_CUSTOM_OVERLAY = 0xD000, } -- bins can be inserted (use the management methods to do so!!) local default_bins = { [bintype.BTYPE_CUSTOM_BG] = {}, [bintype.BTYPE_BACKGROUND] = {}, [bintype.BTYPE_TRANSPARENT] = {}, [bintype.BTYPE_CUT_OUT] = {}, [bintype.BTYPE_OPAQUE] = {}, [bintype.BTYPE_GUI] = {}, [bintype.BTYPE_CUSTOM_GUI] = {}, [bintype.BTYPE_CUSTOM_OVERLAY] = {}, } -- -------------------------------------------------------------------------------------- -- A ultra base bin_state object - this is what is stored in the bins -- -- Note: params may move from here. TBA. ffi.cdef[[ typedef struct bin_state { sg_range *vs_params; int vs_block_index; sg_range *fs_params; int fs_block_index; sg_pipeline pip; sg_bindings* bind; int offset; int count; int instances; } bin_state; ]] -- --------------------------------------------------------------------------------------------------- -- A table (like a class) to handle the main singleton of bins. -- Note: This could be extended to have multiple bins if needed. local bin_mgr = {} -- --------------------------------------------------------------------------------------------------- bin_mgr.init = function() bin_mgr.bins = utils.deepcopy(default_bins) bin_mgr.passes = { } for k,v in pairs(bintype) do bin_mgr[k] = v end end -- --------------------------------------------------------------------------------------------------- -- TODO: Need to deal with this. Will become a fast lookup for numerous items local cache = {} bin_mgr.bin_add = function(geom) local vs_range = nil if(geom.vs_params) then vs_range = ffi.new("sg_range[1]") vs_range[0].ptr = geom.vs_params vs_range[0].size = ffi.sizeof(ffi.typeof(geom.vs_params[0])) tinsert(cache, vs_range) end local fs_range = nil if(geom.fs_params) then fs_range = ffi.new("sg_range[1]") fs_range[0].ptr = geom.fs_params fs_range[0].size = ffi.sizeof(geom.fs_params[0]) tinsert(cache, fs_range) end local dstate = ffi.new("bin_state[1]",{}) dstate[0].vs_params = vs_range dstate[0].vs_block_index = 0 -- Need to fix dstate[0].fs_params = fs_range dstate[0].fs_block_index = 0 -- Need to fix dstate[0].pip = geom.pip dstate[0].bind = geom.bind dstate[0].offset = geom.offset or 0 -- Assert will prob be temporary. Will capture this upstream. assert(geom.count ~= nil or geom.count ~= 0, "[render bin_add] Invalid geometry count for mesh.") dstate[0].count = geom.count dstate[0].instances = geom.instances or 1 local bin_slot = bintype.BTYPE_OPAQUE if(geom.bintype) then bin_slot = geom.bintype end -- Insert into known bin slot local thebin = bin_mgr.bins[bin_slot] if(thebin) then tinsert(bin_mgr.bins[bin_slot], dstate) -- Insert into newly created bin slot else bin_mgr.bins[bin_slot] = { dstate } end return bin_slot end -- --------------------------------------------------------------------------------------------------- -- Need a way to order passes on submission bin_mgr.pass_add = function(pdata, index, front) local thispass = ffi.new("sg_pass[1]") thispass[0].action.colors[0].load_action = pdata.action thispass[0].action.colors[0].clear_value = pdata.clear thispass[0].swapchain = pdata.swapchain local binpass = { pass = thispass, binlist = { bintype.BTYPE_OPAQUE }, } if(index) then binpass.binlist = { index } end local passid = 1 if(not front) then passid = tcount(bin_mgr.passes) end tinsert(bin_mgr.passes, passid, binpass) return passid end -- --------------------------------------------------------------------------------------------------- -- Need a way to order passes on submission bin_mgr.bin_add_func = function(bid, func, index) if(index) then tinsert(bin_mgr.bins[bid], index, func) else tinsert(bin_mgr.bins[bid], func) end end -- --------------------------------------------------------------------------------------------------- bin_mgr.bin_remove = function(bid) end -- --------------------------------------------------------------------------------------------------- bin_mgr.bin_clear = function(bid) end -- --------------------------------------------------------------------------------------------------- bin_mgr.update = function(dt) end -- --------------------------------------------------------------------------------------------------- bin_mgr.render = function() -- Not initialized? if(bin_mgr.bins == nil) then return end -- iterate passes and render bins with pass setup for pi, pass in ipairs(bin_mgr.passes) do pass.pass[0].swapchain = slib.sglue_swapchain() if(pass.binlist) then sg.sg_begin_pass(pass.pass) -- Go through the bins for this pass! for bi, binid in ipairs(pass.binlist) do -- Fetch the bin from the pool local binlist = bin_mgr.bins[binid] for bli, bin in ipairs(binlist) do if(type(bin) == "function") then bin(sapp.sapp_width(), sapp.sapp_height()) else sg.sg_apply_pipeline(bin[0].pip) sg.sg_apply_bindings(bin[0].bind) if(bin[0].vs_params ~= nil) then sg.sg_apply_uniforms(sg.SG_SHADERSTAGE_VS, bin[0].vs_params) end if(bin[0].fs_params ~= nil) then sg.sg_apply_uniforms(sg.SG_SHADERSTAGE_FS, bin[0].fs_params) end sg.sg_draw(bin[0].offset, bin[0].count, bin[0].instances) end end end sg.sg_end_pass() end end sg.sg_commit() end -- --------------------------------------------------------------------------------------------------- return bin_mgr -- ---------------------------------------------------------------------------------------------------