| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- module three.renderer;
- import three.common;
- import three.scene;
- import three.camera;
- import three.renderTarget;
- import three.viewport;
- import three.mesh;
- import std.string : toStringz;
- import std.exception : collectException;
- import std.experimental.logger;
- import three.gl.buffer;
- import three.gl.draw;
- import three.gl.sync;
- enum maxVertices = 1024;
- enum maxIndices = 1024;
- enum maxPerInstanceParams = 1024;
- enum maxIndirectCommands = 1024;
- enum bufferCount = 3; //tripple buffering
- enum kOneSecondInNanoSeconds = GLuint64(1000000000);
- //======================================================================================================================
- //
- //======================================================================================================================
- struct Renderer {
- uint width;
- uint height;
- GlSyncManager syncManager;
- GlArrayBuffer!VertexData vertexBuffer; // vertex data for all meshes
- GlElementArrayBuffer!IndexData indexBuffer; //index data for all meshes
- GlShaderStorageBuffer!GlDrawParameter perInstanceParamBuffer; // is filled with draw parameters for each instance each frame. shall be accessed as a ringbuffer
- GlDispatchIndirectBuffer!GlDrawElementsIndirectCommand dispatchIndirectCommandBuffer; // is filled with DrawElementsIndirectCommand for each mesh each frame. shall be accessed as a ringbuffer
- void construct(uint width, uint height) {
- GLbitfield createFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;//TODO: ?? | GL_MAP_DYNAMIC_STORAGE_BIT;
- GLbitfield mapFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
-
- this.vertexBuffer.construct(bufferCount * maxVertices, createFlags, mapFlags);
- this.indexBuffer.construct(bufferCount * maxIndices, createFlags, mapFlags);
- this.perInstanceParamBuffer.construct(bufferCount * maxPerInstanceParams, createFlags, mapFlags);
- this.dispatchIndirectCommandBuffer.construct(bufferCount * maxIndirectCommands, createFlags, mapFlags);
- glCheck!glEnableVertexAttribArray(0);
- glCheck!glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)0 );
- glCheck!glEnableVertexAttribArray(1);
- glCheck!glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)3 );
- glCheck!glEnableVertexAttribArray(2);
- glCheck!glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)6 );
- glCheck!glEnableVertexAttribArray(3);
- glCheck!glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)10 );
- }
- void destruct() {
- this.vertexBuffer.destruct();
- this.indexBuffer.destruct();
- this.perInstanceParamBuffer.destruct();
- this.dispatchIndirectCommandBuffer.destruct();
- }
- void uploadModelData(GlArrayBuffer!VertexData vertexBuffer, GlElementArrayBuffer!IndexData indexBuffer, ModelData modelData) {
- //TODO: wait for buffer range
- //mBufferLockManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
- // TODO: check if buffers are bound. they should always be bound here!
- // we need to store all models in one giant vbo to use glMultiDrawElementsIndirect.
- // TODO: implement triple buffering. -> use vertexBuffer and indexBuffer as giant ring buffers
- GLuint vertexBufferOffset = 0;
- GLuint indexBufferOffset = 0;
-
- foreach(meshData; modelData.meshData) {
- import std.c.string: memcpy;
- //upload vertex data
- assert(this.vertexBuffer.length >= meshData.vertexData.length);
- memcpy(this.vertexBuffer.data + vertexBufferOffset, meshData.vertexData.ptr, meshData.vertexData.length * VertexData.sizeof);
- vertexBufferOffset += meshData.vertexData.length * VertexData.sizeof;
- //upload index data
- assert(this.indexBuffer.length >= meshData.indexData.length);
- memcpy(this.indexBuffer.data + indexBufferOffset, meshData.indexData.ptr, meshData.indexData.length * IndexData.sizeof);
- indexBufferOffset += meshData.indexData.length * IndexData.sizeof;
- }
- }
- void renderOneFrame(ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
- // wait until GPU has finished rendereing from our desired buffer destination
- //TODO: syncManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
- /*
- foreach(renderTarget) //framebuffer
- foreach(pass)
- foreach(material) //shaders
- foreach(materialInstance) //textures
- foreach(vertexFormat) //vertex buffers
- foreach(object) {
- write uniform data;
- glDrawElementsBaseVertex
- }
- */
-
- GLsizei meshCount = 0;
-
- glCheck!glViewport(0, 0, this.width, this.height);
-
- // enable depth mask _before_ glClear ing the depth buffer!
- glCheck!glDepthMask(GL_TRUE); scope(exit) glCheck!glDepthMask(GL_FALSE);
- glCheck!glEnable(GL_DEPTH_TEST); scope(exit) glCheck!glDisable(GL_DEPTH_TEST);
- glCheck!glDepthFunc(GL_LEQUAL);
-
- // write draw parameters
-
- // write draw commmands
-
- // draw //TODO: pass offset (cast to ptr) into command buffer instead of null
-
- this.vertexBuffer.bind();
- this.indexBuffer.bind();
- this.perInstanceParamBuffer.bind();
- this.dispatchIndirectCommandBuffer.bind();
-
- glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, toGlType!(this.indexBuffer.ValueType), null, meshCount, 0);
- //TODO: syncManager.LockRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
- }
-
- debug {
- void blitGBufferToScreen() {
- }
- }
- }
|