renderer.d 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. module three.renderer;
  2. import three.common;
  3. import three.scene;
  4. import three.camera;
  5. import three.renderTarget;
  6. import three.viewport;
  7. import three.mesh;
  8. import std.string : toStringz;
  9. import std.exception : collectException;
  10. import std.experimental.logger;
  11. import three.gl.buffer;
  12. import three.gl.draw;
  13. import three.gl.sync;
  14. enum maxVertices = 1024;
  15. enum maxIndices = 1024;
  16. enum maxPerInstanceParams = 1024;
  17. enum maxIndirectCommands = 1024;
  18. enum bufferCount = 3; //tripple buffering
  19. enum kOneSecondInNanoSeconds = GLuint64(1000000000);
  20. //======================================================================================================================
  21. //
  22. //======================================================================================================================
  23. struct Renderer {
  24. uint width;
  25. uint height;
  26. GlSyncManager syncManager;
  27. GlArrayBuffer!VertexData vertexBuffer; // vertex data for all meshes
  28. GlElementArrayBuffer!IndexData indexBuffer; //index data for all meshes
  29. GlShaderStorageBuffer!GlDrawParameter perInstanceParamBuffer; // is filled with draw parameters for each instance each frame. shall be accessed as a ringbuffer
  30. GlDispatchIndirectBuffer!GlDrawElementsIndirectCommand dispatchIndirectCommandBuffer; // is filled with DrawElementsIndirectCommand for each mesh each frame. shall be accessed as a ringbuffer
  31. void construct(uint width, uint height) {
  32. GLbitfield createFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;//TODO: ?? | GL_MAP_DYNAMIC_STORAGE_BIT;
  33. GLbitfield mapFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
  34. this.vertexBuffer.construct(bufferCount * maxVertices, createFlags, mapFlags);
  35. this.indexBuffer.construct(bufferCount * maxIndices, createFlags, mapFlags);
  36. this.perInstanceParamBuffer.construct(bufferCount * maxPerInstanceParams, createFlags, mapFlags);
  37. this.dispatchIndirectCommandBuffer.construct(bufferCount * maxIndirectCommands, createFlags, mapFlags);
  38. glCheck!glEnableVertexAttribArray(0);
  39. glCheck!glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)0 );
  40. glCheck!glEnableVertexAttribArray(1);
  41. glCheck!glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)3 );
  42. glCheck!glEnableVertexAttribArray(2);
  43. glCheck!glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)6 );
  44. glCheck!glEnableVertexAttribArray(3);
  45. glCheck!glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)10 );
  46. }
  47. void destruct() {
  48. this.vertexBuffer.destruct();
  49. this.indexBuffer.destruct();
  50. this.perInstanceParamBuffer.destruct();
  51. this.dispatchIndirectCommandBuffer.destruct();
  52. }
  53. void uploadModelData(GlArrayBuffer!VertexData vertexBuffer, GlElementArrayBuffer!IndexData indexBuffer, ModelData modelData) {
  54. //TODO: wait for buffer range
  55. //mBufferLockManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  56. // TODO: check if buffers are bound. they should always be bound here!
  57. // we need to store all models in one giant vbo to use glMultiDrawElementsIndirect.
  58. // TODO: implement triple buffering. -> use vertexBuffer and indexBuffer as giant ring buffers
  59. GLuint vertexBufferOffset = 0;
  60. GLuint indexBufferOffset = 0;
  61. foreach(meshData; modelData.meshData) {
  62. import std.c.string: memcpy;
  63. //upload vertex data
  64. assert(this.vertexBuffer.length >= meshData.vertexData.length);
  65. memcpy(this.vertexBuffer.data + vertexBufferOffset, meshData.vertexData.ptr, meshData.vertexData.length * VertexData.sizeof);
  66. vertexBufferOffset += meshData.vertexData.length * VertexData.sizeof;
  67. //upload index data
  68. assert(this.indexBuffer.length >= meshData.indexData.length);
  69. memcpy(this.indexBuffer.data + indexBufferOffset, meshData.indexData.ptr, meshData.indexData.length * IndexData.sizeof);
  70. indexBufferOffset += meshData.indexData.length * IndexData.sizeof;
  71. }
  72. }
  73. void renderOneFrame(ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
  74. // wait until GPU has finished rendereing from our desired buffer destination
  75. //TODO: syncManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  76. /*
  77. foreach(renderTarget) //framebuffer
  78. foreach(pass)
  79. foreach(material) //shaders
  80. foreach(materialInstance) //textures
  81. foreach(vertexFormat) //vertex buffers
  82. foreach(object) {
  83. write uniform data;
  84. glDrawElementsBaseVertex
  85. }
  86. */
  87. GLsizei meshCount = 0;
  88. glCheck!glViewport(0, 0, this.width, this.height);
  89. // enable depth mask _before_ glClear ing the depth buffer!
  90. glCheck!glDepthMask(GL_TRUE); scope(exit) glCheck!glDepthMask(GL_FALSE);
  91. glCheck!glEnable(GL_DEPTH_TEST); scope(exit) glCheck!glDisable(GL_DEPTH_TEST);
  92. glCheck!glDepthFunc(GL_LEQUAL);
  93. // write draw parameters
  94. // write draw commmands
  95. // draw //TODO: pass offset (cast to ptr) into command buffer instead of null
  96. this.vertexBuffer.bind();
  97. this.indexBuffer.bind();
  98. this.perInstanceParamBuffer.bind();
  99. this.dispatchIndirectCommandBuffer.bind();
  100. glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, toGlType!(this.indexBuffer.ValueType), null, meshCount, 0);
  101. //TODO: syncManager.LockRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  102. }
  103. debug {
  104. void blitGBufferToScreen() {
  105. }
  106. }
  107. }