renderer.d 15 KB

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