renderer.d 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. import three.gl.util;
  15. enum maxVertices = 1024;
  16. enum maxIndices = 1024;
  17. enum maxPerInstanceParams = 1024;
  18. enum maxIndirectCommands = 1024;
  19. enum bufferCount = 3; //tripple buffering
  20. enum kOneSecondInNanoSeconds = GLuint64(1000000000);
  21. //======================================================================================================================
  22. //
  23. //======================================================================================================================
  24. struct GBuffer {
  25. uint width;
  26. uint height;
  27. GLuint texturePosition;
  28. GLuint textureNormal;
  29. GLuint textureColor;
  30. GLuint textureDepthStencil;
  31. GLuint fbo;
  32. void construct(uint width, uint height) nothrow {
  33. this.width = width;
  34. this.height = height;
  35. glCheck!glGenTextures(1, &this.texturePosition);
  36. glCheck!glBindTexture(GL_TEXTURE_2D, this.texturePosition);
  37. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, width, height);
  38. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_FLOAT, null);
  39. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  40. glCheck!glGenTextures(1, &this.textureNormal);
  41. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureNormal);
  42. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB10_A2, width, height);
  43. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  44. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  45. glCheck!glGenTextures(1, &this.textureColor);
  46. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureColor);
  47. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
  48. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  49. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  50. glCheck!glGenTextures(1, &this.textureDepthStencil);
  51. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureDepthStencil);
  52. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
  53. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
  54. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  55. glCheck!glGenFramebuffers(1, &this.fbo);
  56. glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this.fbo);
  57. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, this.texturePosition, 0);
  58. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_TEXTURE_2D, this.textureNormal, 0);
  59. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 2, GL_TEXTURE_2D, this.textureColor, 0);
  60. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, this.textureDepthStencil, 0);
  61. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  62. }
  63. void destruct() nothrow {
  64. glCheck!glDeleteFramebuffers(1, &this.fbo);
  65. glCheck!glDeleteTextures(1, &this.textureColor);
  66. glCheck!glDeleteTextures(1, &this.textureNormal);
  67. glCheck!glDeleteTextures(1, &this.texturePosition);
  68. }
  69. }
  70. //======================================================================================================================
  71. //
  72. //======================================================================================================================
  73. struct ShaderPipeline {
  74. GLuint pipeline;
  75. GLuint vertexShaderGeometryPass;
  76. GLuint fragmentShaderGeometryPass;
  77. void construct(string vertexShaderSource, string fragmentShaderSource) nothrow {
  78. glCheck!glGenProgramPipelines(1, &this.pipeline);
  79. auto szVertexSource = [vertexShaderSource.toStringz()];
  80. this.vertexShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_VERTEX_SHADER, 1, szVertexSource.ptr);
  81. int len;
  82. glCheck!glGetProgramiv(this.vertexShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
  83. if (len > 1) {
  84. char[] msg = new char[len];
  85. glCheck!glGetProgramInfoLog(this.vertexShaderGeometryPass, len, null, cast(char*) msg);
  86. log(cast(string)msg).collectException;
  87. }
  88. auto szFragmentSource = [fragmentShaderSource.toStringz()];
  89. this.fragmentShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, szFragmentSource.ptr);
  90. // int len;
  91. glCheck!glGetProgramiv(this.fragmentShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
  92. if (len > 1) {
  93. char[] msg = new char[len];
  94. glCheck!glGetProgramInfoLog(this.fragmentShaderGeometryPass, len, null, cast(char*) msg);
  95. log(cast(string)msg).collectException;
  96. }
  97. glCheck!glUseProgramStages(this.pipeline, GL_VERTEX_SHADER_BIT, this.vertexShaderGeometryPass);
  98. glCheck!glUseProgramStages(this.pipeline, GL_FRAGMENT_SHADER_BIT, this.fragmentShaderGeometryPass);
  99. glCheck!glValidateProgramPipeline(this.pipeline);
  100. GLint status;
  101. glCheck!glGetProgramPipelineiv(this.pipeline, GL_VALIDATE_STATUS, &status);
  102. //TODO: add error handling
  103. assert(status != 0);
  104. }
  105. void destruct() nothrow {
  106. glDeleteProgramPipelines(1, &this.pipeline);
  107. }
  108. }
  109. enum vertexShaderSource = "
  110. #version 420 core
  111. layout(location = 0) in vec3 in_position;
  112. layout(location = 1) in vec3 in_normal;
  113. layout(location = 2) in vec2 in_texcoord;
  114. layout(location = 3) in vec4 in_color;
  115. //==============
  116. out vec2 _normal;
  117. out vec2 _texture;
  118. out vec3 _color;
  119. //==============
  120. out gl_PerVertex
  121. {
  122. vec4 gl_Position;
  123. };
  124. vec2 encode(vec3 n)
  125. {
  126. float f = sqrt(8*n.z+8);
  127. return n.xy / f + 0.5;
  128. }
  129. void main()
  130. {
  131. gl_Position = vec4(0.005 * in_position.x, 0.005 * in_position.y, 0.005* in_position.z, 1.0);
  132. _normal = encode(in_normal);
  133. _texture = in_texcoord;
  134. _color = in_color.xyz;
  135. };
  136. ";
  137. enum fragmentShaderSource = "
  138. #version 420 core
  139. //==============
  140. in vec2 _normal;
  141. in vec2 _texture;
  142. in vec3 _color;
  143. //==============
  144. layout(location = 0) out float depth;
  145. layout(location = 1) out vec4 normal;
  146. layout(location = 2) out vec4 color;
  147. void main()
  148. {
  149. depth = gl_FragCoord.z;
  150. normal.xy = _normal.xy;
  151. color.xyz = _color;
  152. }
  153. ";
  154. //======================================================================================================================
  155. //
  156. //======================================================================================================================
  157. struct Renderer {
  158. GBuffer gbuffer;
  159. ShaderPipeline shaderPipeline;
  160. GlArrayBuffer!VertexData vertexBuffer; // vertex data for all meshes
  161. GlElementArrayBuffer!IndexData indexBuffer; //index data for all meshes
  162. GlShaderStorageBuffer!GlDrawParameter perInstanceParamBuffer; // is filled with draw parameters for each instance each frame. shall be accessed as a ringbuffer
  163. GlDispatchIndirectBuffer!GlDrawElementsIndirectCommand dispatchIndirectCommandBuffer; // is filled with DrawElementsIndirectCommand for each mesh each frame. shall be accessed as a ringbuffer
  164. GlSyncManager syncManager;
  165. void construct(uint width, uint height) {
  166. GLbitfield createFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;//TODO: ?? | GL_MAP_DYNAMIC_STORAGE_BIT;
  167. GLbitfield mapFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
  168. this.gbuffer.construct(width, height);
  169. this.shaderPipeline.construct(vertexShaderSource, fragmentShaderSource);
  170. this.vertexBuffer.construct(bufferCount * maxVertices, createFlags, mapFlags);
  171. this.indexBuffer.construct(bufferCount * maxIndices, createFlags, mapFlags);
  172. this.perInstanceParamBuffer.construct(bufferCount * maxPerInstanceParams, createFlags, mapFlags);
  173. this.dispatchIndirectCommandBuffer.construct(bufferCount * maxIndirectCommands, createFlags, mapFlags);
  174. this.syncManager.construct();
  175. glCheck!glEnableVertexAttribArray(0);
  176. glCheck!glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)0 );
  177. glCheck!glEnableVertexAttribArray(1);
  178. glCheck!glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)3 );
  179. glCheck!glEnableVertexAttribArray(2);
  180. glCheck!glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)6 );
  181. glCheck!glEnableVertexAttribArray(3);
  182. glCheck!glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)10 );
  183. }
  184. void destruct() {
  185. this.syncManager.destruct();
  186. this.dispatchIndirectCommandBuffer.destruct();
  187. this.perInstanceParamBuffer.destruct();
  188. this.indexBuffer.destruct();
  189. this.vertexBuffer.destruct();
  190. this.shaderPipeline.destruct();
  191. this.gbuffer.destruct();
  192. }
  193. // void uploadModelData(GlArrayBuffer!VertexData vertexBuffer, GlElementArrayBuffer!IndexData indexBuffer, ModelData modelData) {
  194. // //TODO: wait for buffer range
  195. // //mBufferLockManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  196. //
  197. // // TODO: check if buffers are bound. they should always be bound here!
  198. //
  199. // // we need to store all models in one giant vbo to use glMultiDrawElementsIndirect.
  200. // // TODO: implement triple buffering. -> use vertexBuffer and indexBuffer as giant ring buffers
  201. // GLuint vertexBufferOffset = 0;
  202. // GLuint indexBufferOffset = 0;
  203. //
  204. // foreach(meshData; modelData.meshData) {
  205. // import std.c.string: memcpy;
  206. // //upload vertex data
  207. // assert(this.vertexBuffer.length >= meshData.vertexData.length);
  208. // memcpy(this.vertexBuffer.data + vertexBufferOffset, meshData.vertexData.ptr, meshData.vertexData.length * VertexData.sizeof);
  209. // vertexBufferOffset += meshData.vertexData.length * VertexData.sizeof;
  210. // //upload index data
  211. // assert(this.indexBuffer.length >= meshData.indexData.length);
  212. // memcpy(this.indexBuffer.data + indexBufferOffset, meshData.indexData.ptr, meshData.indexData.length * IndexData.sizeof);
  213. // indexBufferOffset += meshData.indexData.length * IndexData.sizeof;
  214. // }
  215. // }
  216. void renderOneFrame(ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
  217. // wait until GPU has finished rendereing from our desired buffer destination
  218. //TODO: this.syncManager.WaitForLockedRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  219. /*
  220. foreach(renderTarget) //framebuffer
  221. foreach(pass)
  222. foreach(material) //shaders
  223. foreach(materialInstance) //textures
  224. foreach(vertexFormat) //vertex buffers
  225. foreach(object) {
  226. write uniform data;
  227. glDrawElementsBaseVertex
  228. }
  229. */
  230. GLsizei meshCount = 0;
  231. glCheck!glViewport(0, 0, this.gbuffer.width, this.gbuffer.height);
  232. // enable depth mask _before_ glClear ing the depth buffer!
  233. glCheck!glDepthMask(GL_TRUE); scope(exit) glCheck!glDepthMask(GL_FALSE);
  234. glCheck!glEnable(GL_DEPTH_TEST); scope(exit) glCheck!glDisable(GL_DEPTH_TEST);
  235. glCheck!glDepthFunc(GL_LEQUAL);
  236. // write draw parameters
  237. // write draw commmands
  238. // draw //TODO: pass offset (cast to ptr) into command buffer instead of null
  239. this.vertexBuffer.bind();
  240. this.indexBuffer.bind();
  241. this.perInstanceParamBuffer.bind();
  242. this.dispatchIndirectCommandBuffer.bind();
  243. glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, toGlType!(this.indexBuffer.ValueType), null, meshCount, 0);
  244. //TODO: this.syncManager.LockRange(mStartDestOffset, _vertices.size() * sizeof(Vec2));
  245. }
  246. debug {
  247. void blitGBufferToScreen() {
  248. }
  249. }
  250. }