module ecs_utils.gfx.renderer; import bindbc.sdl; import bubel.ecs.std; //import ecs_utils.core : Backend; import ecs_utils.gfx.buffer; import ecs_utils.gfx.texture; import ecs_utils.math.vector; import bubel.ecs.block_allocator; import bubel.ecs.vector; version(WebAssembly)import glad.gl.gles2; else import glad.gl.gl; version = ver1; /*version(ver5)version = vv2; else version(ver6)version = vv2;*/ extern(C) float sinf(float); extern(C) float cosf(float); enum RenderTechnique { simple,//1 simple_array,//2 vbo_batch,//3 instanced_attrib_divisor,//4 uniform_buffer,//5 uniform_buffer_indexed,//6 uniform_buffer_multi_draw,//7 uniform_buffer_instanced,//8 uniform_buffer_instanced_mapped_gl2,//9 uniform_buffer_instanced_mapped,//10 uniform_buffer_instanced_persistent_mapped,//11 uniform_buffer_instanced_persistent_mapped_coherent,//12 ssbo_instanced,//13 uniform_buffer_draw_indirect,//14 uniform_buffer_multi_draw_indirect,//15 uniform_buffer_multi_draw_indirect_arb_draw_parameters//16 } struct Renderer { //static SDL_Renderer* main_sdl_renderer; BlockAllocator allocator; enum MaxObjects = 1024 * 64 * 4; enum BufferUsage = GL_DYNAMIC_DRAW; //SDL_Window* sdl_window; //SDL_Renderer* sdl_renderer; ivec2 resolution; vec2 dres; vec4 sdl_transform; vec2 view_pos = vec2(-1,-1); vec2 view_size = vec2(1,1); enum block_size = 2^^16; enum batch_size = block_size/68;//963;//16_384; //uint[2] time_queries; struct VertexBlock { enum max_items = batch_size;//963; byte[] batch_vertices; ushort[] batch_indices; void* memory; uint items = 0; } Mutex* get_block_mutex; Mutex* block_stack_mutex; VertexBlock getBlock() { VertexBlock block; get_block_mutex.lock(); block.memory = allocator.getBlock(); get_block_mutex.unlock(); block.batch_vertices = (cast(byte*)block.memory)[0 .. VertexBlock.max_items * 4 * 14]; block.batch_indices = (cast(ushort*)block.memory)[VertexBlock.max_items * 4 * 7 .. VertexBlock.max_items * (4 * 7 + 6)]; return block; } Vector!VertexBlock blocks; uint current_block = 0; uint render_blocks = 0; void pushBlock(VertexBlock block) { block_stack_mutex.lock(); prepared_items += block.items; blocks.add(block); render_blocks++; block_stack_mutex.unlock(); } bool isRemainingBlocks() { if(render_blocks <= current_block)return false; return true; } VertexBlock fetchBlock() { block_stack_mutex.lock(); VertexBlock block = blocks[current_block]; current_block++; block_stack_mutex.unlock(); return block; } void freeBlocks() { block_stack_mutex.lock(); render_blocks = 0; current_block = 0; foreach(VertexBlock block; blocks) { allocator.freeBlock(block.memory); } blocks.clear; prepared_items=0; draw_list.clear(); block_stack_mutex.unlock(); } void pushData() { //if(!isRemainingBlocks())return; while(isRemainingBlocks()) { VertexBlock block = fetchBlock(); uint items = block.items; if(items + item_id >= MaxObjects)items = MaxObjects - item_id; batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); draw_list.add(DrawCall(item_id,items)); item_id += items; } } void pushThreadsBlocks() { foreach(i, ref Thread thread; threads) { pushBlock(thread.block); thread.block = getBlock(); } } struct Thread { //Vector!VertexBlock block; RenderData[] render_list; VertexBlock block; } Thread[] threads; Buffer[2] ubos; int block_alignment = 1; int block_max_size = 16384; struct IndirectDraw { uint count = 6; uint instances = 1; uint first_index = 0; uint base_vertex = 0; uint base_instance = 0; } Buffer[2] batch_vbo; Buffer[2] batch_ibo; ubyte[] batch_vertices; ushort[] batch_indices; Buffer indirect_buffer; IndirectDraw[] indirect_block; Buffer id_buffer; int data_offset = 48; int data_index; ubyte[] uniform_block; struct RenderData { Texture texture; uint material_id; uint mesh_id; } struct DrawCall { uint start; uint count; } Vector!DrawCall draw_list; RenderData[] render_list; uint item_id; uint prepared_items; uint[] multi_count; uint[] multi_offset; alias Technique = RenderTechnique; __gshared Technique technique = Technique.vbo_batch; void* data_ptr; //import ecs_utils.core : RenderTechnique; void initialize() { //this.technique = __ecs_used_technique; __initialize(this); get_block_mutex = Mallocator.make!Mutex(); block_stack_mutex = Mallocator.make!Mutex(); get_block_mutex.initialize(); block_stack_mutex.initialize(); threads = Mallocator.makeArray!Thread(32); foreach(ref Thread thread;threads) { thread.block = getBlock(); } } private static void __initialize_gl(ref Renderer this_) { with(this_) { //glGenQueries(2, time_queries.ptr); version(WebAssembly) { } else { glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &block_max_size); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &block_alignment); } //ubos[0].bufferStorage(1,64*MaxObjects,null); switch(technique) { case Technique.simple: uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects); data_ptr = uniform_block.ptr; data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); break; case Technique.simple_array: goto case(Technique.simple); case Technique.vbo_batch: batch_vbo[0].create(); batch_ibo[0].create(); batch_vbo[0].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); batch_vbo[1].create(); batch_ibo[1].create(); batch_vbo[1].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); //batch_vertices = Mallocator.makeArray!ubyte(14*4*MaxObjects); //batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); break; case Technique.instanced_attrib_divisor: goto case(Technique.uniform_buffer_indexed); case Technique.uniform_buffer: ubos[0].create(); ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); ubos[1].create(); ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); goto case(Technique.simple); case Technique.uniform_buffer_indexed: ubos[0].create(); ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); ubos[1].create(); ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects); data_ptr = uniform_block.ptr; break; /*case Technique.uniform_buffer_multi_draw: multi_count = Mallocator.makeArray!uint(992,6); multi_offset = Mallocator.makeArray!uint(992,0); { uint[] indices = Mallocator.makeArray!uint(992); scope(exit)Mallocator.dispose(indices); foreach(i;0..992)indices[i]=i; id_buffer.create(); id_buffer.bufferData(uint.sizeof,992,BufferUsage,indices.ptr); } goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);*/ case Technique.uniform_buffer_instanced: goto case(Technique.uniform_buffer_indexed); case Technique.uniform_buffer_instanced_mapped_gl2: ubos[0].create(); ubos[0].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null); ubos[0].map(Buffer.BindTarget.uniform); ubos[1].create(); ubos[1].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null); ubos[1].map(Buffer.BindTarget.uniform); data_ptr = ubos[0].mappedPointer(); break; case Technique.uniform_buffer_instanced_mapped: ubos[0].create(); ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); ubos[1].create(); ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); data_ptr = ubos[0].mappedPointer(); break; /*case Technique.uniform_buffer_instanced_persistent_mapped: ubos[0].create(); ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent); ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict); data_ptr = ubos[0].mappedPointer(); break; case Technique.uniform_buffer_instanced_persistent_mapped_coherent: ubos[0].create(); ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent); ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent); ubos[1].create(); ubos[1].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent); ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent); data_ptr = ubos[0].mappedPointer(); break; case Technique.ssbo_instanced: goto case(Technique.uniform_buffer_indexed); case Technique.uniform_buffer_draw_indirect: indirect_block = Mallocator.makeArray!IndirectDraw(1); indirect_buffer.create(); indirect_buffer.bufferData(IndirectDraw.sizeof,1,BufferUsage,indirect_block.ptr); indirect_buffer.bind(Buffer.BindTarget.indirect); goto case(Technique.uniform_buffer); case Technique.uniform_buffer_multi_draw_indirect: goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters); case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters: indirect_block = Mallocator.makeArray!IndirectDraw(992); foreach(i;0..992) { IndirectDraw* idraw = &indirect_block[i]; idraw.base_instance = i; } indirect_buffer.create(); indirect_buffer.bufferData(IndirectDraw.sizeof,992,BufferUsage,indirect_block.ptr); indirect_buffer.bind(Buffer.BindTarget.indirect); goto case(Technique.uniform_buffer_indexed);*/ default:break; }//*/ // if(batching)data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); //data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); /*version(ver4){} else version(ver5){} else version(ver6){} else data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));//*/ //data_offset = (data_offset + block_alignment - 1) - data_offset % block_alignment; render_list = Mallocator.makeArray!RenderData(MaxObjects); SDL_Log("Uniform block alignment: %u",block_alignment); SDL_Log("Uniform block max size: %u",block_max_size); SDL_Log("Data offset: %u",data_offset); allocator = BlockAllocator(block_size, 32); } } private static void __initialize_sdl(ref Renderer this_) { } void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) { if(prepared_items >= MaxObjects)return; __draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); } private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { /*with(this_) { SDL_Rect rect = SDL_Rect(cast(int)(coords.x*tex.data.size.x),cast(int)(coords.y*tex.data.size.y),cast(int)(coords.z*tex.data.size.x),cast(int)(coords.w*tex.data.size.y)); SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)), cast(int)(resolution.y - pos.y - size.y*0.5), cast(int)(size.x), cast(int)(size.y)); SDL_RenderCopyEx(sdl_renderer, tex.data.texture, &rect, &rect2, angle*360, null, SDL_FLIP_NONE); }*/ } private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { //import core.stdc.string; with(this_) { //pos += view_pos; size.x *= view_size.x; size.y *= view_size.y; pos.x = pos.x * view_size.x + view_pos.x; pos.y = pos.y * view_size.y + view_pos.y;//*/ /*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index; else void* ptr = uniform_block.ptr + data_index;*/ if(data_ptr is null)return; void* ptr = data_ptr + data_index; if(angle == 0) { *cast(float*)ptr = size.x; *cast(float*)(ptr+4) = 0; *cast(float*)(ptr+8) = 0; *cast(float*)(ptr+12) = size.y; } else { //import core.stdc.math; float sinn = sinf(angle); float coss = cosf(angle); *cast(float*)ptr = coss * size.x; *cast(float*)(ptr+4) = -sinn * size.y; *cast(float*)(ptr+8) = sinn * size.x; *cast(float*)(ptr+12) = coss * size.y; } //memcpy(ptr,); memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16); //render_list[item_id] = RenderData(tex,material_id,mesh_id); render_list[item_id].texture = tex; render_list[item_id].material_id = material_id; render_list[item_id].mesh_id = mesh_id; data_index += data_offset; item_id++; prepared_items++; } } private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) { import ecs_utils.gfx.config; short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; //import core.stdc.string; with(this_) { //if(item_id >= MaxObjects)return; //pos += view_pos; pos.x = pos.x * view_size.x + view_pos.x; pos.y = pos.y * view_size.y + view_pos.y;//*/ /*void* ptr = data_ptr + data_index; *cast(float*)ptr = size.x; *cast(float*)(ptr+4) = 0; *cast(float*)(ptr+8) = 0; *cast(float*)(ptr+12) = size.y; //memcpy(ptr,); memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16);*/ short[] verts = cast(short[])threads[thread_id].block.batch_vertices; uint item_id = threads[thread_id].block.items; if(angle == 0) { size.x *= view_size.x; size.y *= view_size.y; verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+4,mem.ptr,6); verts[item_id*28+7] = cast(short)((GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x) * 8191); verts[item_id*28+8] = cast(short)((GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y) * 8191); verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+11,mem.ptr,6); verts[item_id*28+14] = cast(short)((GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x) * 8191); verts[item_id*28+15] = cast(short)((GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y) * 8191); verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+18,mem.ptr,6); verts[item_id*28+21] = cast(short)((GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x) * 8191); verts[item_id*28+22] = cast(short)((GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y) * 8191); verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } else { //import core.stdc.math; float sinx = sinf(angle) * size.x * view_size.y; float cosx = cosf(angle) * size.x * view_size.x; float siny = sinf(angle) * size.y * view_size.x; float cosy = cosf(angle) * size.y * view_size.y; /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; batch_vertices[item_id*28+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; batch_vertices[item_id*28+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; batch_vertices[item_id*28+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; batch_vertices[item_id*28+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; batch_vertices[item_id*28+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; batch_vertices[item_id*28+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * cosx + GfxConfig.meshes[mesh_id].vertices[1] * siny) + pos.x) * 8191); verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * cosy - GfxConfig.meshes[mesh_id].vertices[0] * sinx) + pos.y) * 8191); verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+4,mem.ptr,6); verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * cosx + GfxConfig.meshes[mesh_id].vertices[5] * siny) + pos.x) * 8191); verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * cosy - GfxConfig.meshes[mesh_id].vertices[4] * sinx) + pos.y) * 8191); verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+11,mem.ptr,6); verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * cosx + GfxConfig.meshes[mesh_id].vertices[9] * siny) + pos.x) * 8191); verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * cosy - GfxConfig.meshes[mesh_id].vertices[8] * sinx) + pos.y) * 8191); verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+18,mem.ptr,6); verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * cosx + GfxConfig.meshes[mesh_id].vertices[13] * siny) + pos.x) * 8191); verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * cosy - GfxConfig.meshes[mesh_id].vertices[12] * sinx) + pos.y) * 8191); verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } /*verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);*/ /*verts[item_id*28+4] = depth; verts[item_id*28+11] = depth; verts[item_id*28+18] = depth; verts[item_id*28+25] = depth; *cast(uint*)&verts[item_id*28+5] = color; *cast(uint*)&verts[item_id*28+12] = color; *cast(uint*)&verts[item_id*28+19] = color; *cast(uint*)&verts[item_id*28+26] = color; memcpy(verts.ptr+item_id*28+4,mem.ptr,6); memcpy(verts.ptr+item_id*28+11,mem.ptr,6); memcpy(verts.ptr+item_id*28+18,mem.ptr,6); memcpy(verts.ptr+item_id*28+25,mem.ptr,6);*/ uint ind_id = (item_id % batch_size)*4; ushort[] indices = threads[thread_id].block.batch_indices; indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id); indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id); indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id); indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id); indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id); indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id); //render_list[item_id] = RenderData(tex,material_id,mesh_id); //render_list[item_id].texture = tex; //render_list[item_id].material_id = material_id; //render_list[item_id].mesh_id = mesh_id; //data_index += 1;//data_offset; threads[thread_id].block.items++; if(threads[thread_id].block.items >= VertexBlock.max_items) { pushBlock(threads[thread_id].block); threads[thread_id].block = getBlock(); } } } void clear() { __clear(this); } private static void __clear_sdl(ref Renderer this_) { //SDL_RenderClear(this_.sdl_renderer); } private static void __clear_gl(ref Renderer this_) { glClearColor(0,0,0,0); glViewport(0,0,this_.resolution.x,this_.resolution.y); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glDisable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS); version(WebAssembly) { glDepthRangef(0,1); } else { glDepthRange(0,1); } //glDepthRange(0,1); //glClearDepth(1); } void present() { __present(this); } private static void __present_sdl(ref Renderer this_) { //+SDL_RenderPresent(this_.sdl_renderer); } private static void __present_gl(ref Renderer this_) { this_.pushThreadsBlocks(); this_.pushData(); glViewport(0,0,this_.resolution.x,this_.resolution.y); //glEnable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0.01); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); import ecs_utils.gfx.config; with(this_) { bool instanced = false; bool indirect = false; bool multi_draw = false; Buffer.BindTarget buffer_target = Buffer.BindTarget.uniform; switch(technique) { case Technique.simple: break; case Technique.simple_array: break; case Technique.vbo_batch: //if(data_index){ //batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*14,0,batch_vertices.ptr); //batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); batch_vbo[0].bind(Buffer.BindTarget.array); batch_ibo[0].bind(Buffer.BindTarget.element_array); //glVertexAttribPointer(0,2,GL_SHORT,true,14,null); //glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)4);//} glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); //glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)6);//} break; case Technique.instanced_attrib_divisor: ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); ubos[0].bind(Buffer.BindTarget.uniform); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); glVertexAttribPointer(2,4,GL_FLOAT,false,48,null); glVertexAttribPointer(3,4,GL_FLOAT,false,48,cast(void*)16); glVertexAttribPointer(4,4,GL_FLOAT,false,48,cast(void*)32); glVertexAttribDivisor(2,1); glVertexAttribDivisor(3,1); glVertexAttribDivisor(4,1); //ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); break; case Technique.uniform_buffer: //ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null); /*if(data_index)*/ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); break; case Technique.uniform_buffer_indexed: ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); goto case(Technique.uniform_buffer); case Technique.uniform_buffer_multi_draw: id_buffer.bind(Buffer.BindTarget.array); glEnableVertexAttribArray(2); glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)uint.sizeof,cast(void*)0); glVertexAttribDivisor(2,1); multi_draw = true; goto case(Technique.uniform_buffer_instanced); case Technique.uniform_buffer_instanced: instanced = true; goto case(Technique.uniform_buffer); case Technique.uniform_buffer_instanced_mapped_gl2: instanced = true; ubos[0].unmap(Buffer.BindTarget.uniform); break; case Technique.uniform_buffer_instanced_mapped: instanced = true; ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); ubos[0].unmap(Buffer.BindTarget.uniform); break; /*case Technique.uniform_buffer_instanced_persistent_mapped: instanced = true; ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); break; case Technique.uniform_buffer_instanced_persistent_mapped_coherent: instanced = true; break; //ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); //goto case(Technique.uniform_buffer_instanced_mapped); case Technique.ssbo_instanced: //buffer_target = Buffer.BindTarget.shader_storage; ubos[0].bindRange(Buffer.BindTarget.shader_storage,0,0,48*MaxObjects); goto case(Technique.uniform_buffer_instanced); case Technique.uniform_buffer_draw_indirect: goto case(Technique.uniform_buffer); case Technique.uniform_buffer_multi_draw_indirect: indirect_buffer.bind(Buffer.BindTarget.array); glEnableVertexAttribArray(2); glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)IndirectDraw.sizeof,cast(void*)(4*uint.sizeof)); glVertexAttribDivisor(2,1); goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters); case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters: indirect = true; goto case(Technique.uniform_buffer_instanced);*/ default:break; } data_index = 0; int mesh_id = -1; int material_id = -1; int ubo_start = -1; Texture texture; uint item_ubo_id = 0; /*Buffer tmpb = ubos[0]; ubos[0] = ubos[1]; ubos[1] = tmpb; tmpb = batch_vbo[0]; batch_vbo[0] = batch_vbo[1]; batch_vbo[1] = tmpb; tmpb = batch_ibo[0]; batch_ibo[0] = batch_ibo[1]; batch_ibo[1] = tmpb;//*/ //glFinish(); //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]); if(technique == Technique.vbo_batch) { //uint items = item_id/batch_size+1; foreach(i; 0..draw_list.length) { if(material_id != render_list[i].material_id) { material_id = render_list[i].material_id; GfxConfig.materials[material_id].bind(); float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1]; GfxConfig.materials[material_id].pushUniforms(data.ptr); } if(texture.data != render_list[i].texture.data) { texture.data = render_list[i].texture.data; render_list[i].texture.bind(); } /*uint instance_count = batch_size; if((i+1)*batch_size > item_id) { instance_count = item_id%batch_size; }*/ // glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16)); // glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8)); glVertexAttribPointer(0,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14)); glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+4)); glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+8)); glVertexAttribPointer(3,4,GL_UNSIGNED_BYTE,true,14,cast(void*)(draw_list[i].start*4*14+10)); glDrawElements(GL_TRIANGLES,draw_list[i].count*6,GL_UNSIGNED_SHORT,cast(void*)(draw_list[i].start*6*2)); //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } } else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor) { if(mesh_id != render_list[0].mesh_id) { mesh_id = render_list[0].mesh_id; GfxConfig.meshes[mesh_id].bind(); } if(material_id != render_list[0].material_id) { material_id = render_list[0].material_id; GfxConfig.materials[material_id].bind(); } if(texture.data != render_list[0].texture.data) { texture.data = render_list[0].texture.data; render_list[0].texture.bind(); } glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,item_id); //glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,item_id); } else if(instanced) { uint items = item_id/992+1; foreach(i; 0..items) { if(mesh_id != render_list[i].mesh_id) { mesh_id = render_list[i].mesh_id; GfxConfig.meshes[mesh_id].bind(); } if(material_id != render_list[i].material_id) { material_id = render_list[i].material_id; GfxConfig.materials[material_id].bind(); } if(texture.data != render_list[i].texture.data) { texture.data = render_list[0].texture.data; render_list[i].texture.bind(); } ubos[0].bindRange(buffer_target,0,data_index,block_max_size); uint instance_count = 992; if(i*992 > item_id) { instance_count = i*992 - item_id; } /*if(indirect)glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, cast(void*)0, instance_count, 0); else if(multi_draw)glMultiDrawElements(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count); //glMultiDrawElementsBaseVertex(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count,cast(int*)multi_offset.ptr); else */glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,instance_count); //glDrawArraysInstanced(GL_TRIANGLES,0,6,instance_count); data_index += data_offset * 992; } } else foreach(item; render_list[0..item_id]) { if(mesh_id != item.mesh_id) { mesh_id = item.mesh_id; GfxConfig.meshes[mesh_id].bind(); } if(material_id != item.material_id) { material_id = item.material_id; GfxConfig.materials[material_id].bind(); GfxConfig.materials[material_id].pushBindings(); } if(texture.data != item.texture.data) { texture.data = render_list[0].texture.data; item.texture.bind(); } switch(technique) { case Technique.simple: /*glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]); glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]); glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]); */ GfxConfig.materials[material_id].pushUniforms(&uniform_block[data_index]);break; case Technique.simple_array: glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index)); break; case Technique.uniform_buffer: ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); break; /*case Technique.uniform_buffer_draw_indirect: ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); glDrawElementsIndirect(GL_TRIANGLES,GL_UNSIGNED_SHORT,null); data_index += data_offset; continue;*/ case Technique.uniform_buffer_indexed: if(item_ubo_id >= 992) { item_ubo_id = 0; ubo_start = data_index; ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size); } glUniform1i(0,item_ubo_id++); break; default:break; }//*/ /*version(ver3)ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); else version(ver1) { glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]); glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]); glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]); } else version(ver2)glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index)); else version(ver4) { if(item_ubo_id >= 992) { item_ubo_id = 0; ubo_start = data_index; ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size); } glUniform1i(0,item_ubo_id++); }//*/ glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null); //glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); data_index += data_offset; } //glEndQuery(GL_TIME_ELAPSED); //uint tmpq = time_queries[0]; //time_queries[0] = time_queries[1]; //time_queries[1] = tmpq; /*Buffer tmpb = ubos[0]; ubos[0] = ubos[1]; ubos[1] = tmpb;//*/ data_index = 0; //data_offset = 0; item_id = 0; //SDL_GL_SwapWindow(sdl_window); //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); //version(ver6)ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); //ubos[0].map(Buffer.BindTarget.uniform); switch(technique) { case Technique.uniform_buffer_instanced_mapped_gl2: ubos[0].map(Buffer.BindTarget.uniform); //data_ptr = ubos[0].mappedPointer(); break; case Technique.uniform_buffer_instanced_mapped: ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); //data_ptr = ubos[0].mappedPointer(); break; default:break; } if(ubos[0].data && ubos[0].mappedPointer) { data_ptr = ubos[0].mappedPointer; } /*switch(technique) { case Technique.simple: case Technique.simple_array: case Technique.uniform_buffer: case Technique.uniform_buffer_indexed: case Technique.uniform_buffer_instanced: case Technique.uniform_buffer_instanced_mapped: case Technique.uniform_buffer_instanced_persistent_mapped: default:break; }*/ } glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glDisableVertexAttribArray(3); this_.freeBlocks(); /*glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ //glDisable(GL_ALPHA_TEST); } void resize(ivec2 size) { resolution = size; dres = vec2(1.0/cast(float)size.x,1.0/cast(float)size.y); } void view(vec2 pos, vec2 size) { //view_pos = pos * size - 1; view_size = vec2(2/size.x,2/size.y); sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); view_pos = (pos - size * 0.5) * view_size; } __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; __gshared void function(ref Renderer this_) __present; __gshared void function(ref Renderer this_) __clear; __gshared void function(ref Renderer this_) __initialize; static void __loadBackend() { //this.technique = __ecs_used_technique; if(technique == Technique.vbo_batch)__draw = &__draw_gl_vbo_batch; else __draw = &__draw_gl; __present = &__present_gl; __clear = &__clear_gl; __initialize = &__initialize_gl; } }