1
1

renderer.d 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. module three.gl.renderer;
  2. import three.scene;
  3. import three.camera;
  4. import std.string : toStringz;
  5. import std.exception : collectException;
  6. import std.conv : to;
  7. import std.experimental.logger;
  8. import three.gl.buffer;
  9. import three.gl.sync;
  10. import three.gl.util;
  11. public import three.gl.renderTarget;
  12. enum maxVertices = 3*150000;
  13. enum maxIndices = 3*150000;
  14. enum maxInstances = 3*300;
  15. enum maxIndirectCommands = 3*100;
  16. //======================================================================================================================
  17. //
  18. //======================================================================================================================
  19. struct GlDrawCommand {
  20. GLuint indexCount;
  21. GLuint instanceCount;
  22. GLuint indexBufferOffset;
  23. GLuint vertexBufferOffset;
  24. GLuint instanceBufferOffset;
  25. }
  26. //======================================================================================================================
  27. //
  28. //======================================================================================================================
  29. struct Viewport {
  30. void construct() pure @safe nothrow @nogc {
  31. }
  32. void destruct() pure @safe nothrow @nogc {
  33. }
  34. }
  35. //======================================================================================================================
  36. //
  37. //======================================================================================================================
  38. struct GBuffer {
  39. uint width;
  40. uint height;
  41. GLuint texturePosition;
  42. GLuint textureNormal;
  43. GLuint textureColor;
  44. GLuint textureDepthStencil;
  45. GLuint fbo;
  46. void construct(uint width, uint height) nothrow {
  47. this.width = width;
  48. this.height = height;
  49. glCheck!glGenTextures(1, &this.texturePosition);
  50. glCheck!glBindTexture(GL_TEXTURE_2D, this.texturePosition);
  51. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  52. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  53. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  54. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  55. // glCheck!glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
  56. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, width, height);
  57. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_FLOAT, null);
  58. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  59. glCheck!glGenTextures(1, &this.textureNormal);
  60. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureNormal);
  61. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  62. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  63. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  64. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  65. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB10_A2, width, height);
  66. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  67. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  68. glCheck!glGenTextures(1, &this.textureColor);
  69. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureColor);
  70. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
  71. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  72. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  73. glCheck!glGenTextures(1, &this.textureDepthStencil);
  74. glCheck!glBindTexture(GL_TEXTURE_2D, this.textureDepthStencil);
  75. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
  76. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
  77. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  78. glCheck!glGenFramebuffers(1, &this.fbo);
  79. glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this.fbo);
  80. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, this.texturePosition, 0);
  81. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_TEXTURE_2D, this.textureNormal, 0);
  82. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 2, GL_TEXTURE_2D, this.textureColor, 0);
  83. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, this.textureDepthStencil, 0);
  84. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  85. }
  86. void destruct() nothrow {
  87. glCheck!glDeleteFramebuffers(1, &this.fbo);
  88. glCheck!glDeleteTextures(1, &this.textureColor);
  89. glCheck!glDeleteTextures(1, &this.textureNormal);
  90. glCheck!glDeleteTextures(1, &this.texturePosition);
  91. }
  92. }
  93. //======================================================================================================================
  94. //
  95. //======================================================================================================================
  96. struct ShaderPipeline {
  97. GLuint pipeline;
  98. GLuint vertexShader;
  99. GLuint fragmentShader;
  100. void construct(string vertexShaderSource, string fragmentShaderSource) nothrow {
  101. glCheck!glGenProgramPipelines(1, &this.pipeline);
  102. auto szVertexSource = [vertexShaderSource.toStringz()];
  103. this.vertexShader = glCheck!glCreateShaderProgramv(GL_VERTEX_SHADER, 1, szVertexSource.ptr);
  104. int len;
  105. glCheck!glGetProgramiv(this.vertexShader, GL_INFO_LOG_LENGTH , &len);
  106. if (len > 1) {
  107. char[] msg = new char[len];
  108. glCheck!glGetProgramInfoLog(this.vertexShader, len, null, cast(char*) msg);
  109. log(cast(string)msg).collectException;
  110. }
  111. auto szFragmentSource = [fragmentShaderSource.toStringz()];
  112. this.fragmentShader = glCheck!glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, szFragmentSource.ptr);
  113. // int len;
  114. glCheck!glGetProgramiv(this.fragmentShader, GL_INFO_LOG_LENGTH , &len);
  115. if (len > 1) {
  116. char[] msg = new char[len];
  117. glCheck!glGetProgramInfoLog(this.fragmentShader, len, null, cast(char*) msg);
  118. log(cast(string)msg).collectException;
  119. }
  120. glCheck!glUseProgramStages(this.pipeline, GL_VERTEX_SHADER_BIT, this.vertexShader);
  121. glCheck!glUseProgramStages(this.pipeline, GL_FRAGMENT_SHADER_BIT, this.fragmentShader);
  122. glCheck!glValidateProgramPipeline(this.pipeline);
  123. GLint status;
  124. glCheck!glGetProgramPipelineiv(this.pipeline, GL_VALIDATE_STATUS, &status);
  125. //TODO: add error handling
  126. assert(status != 0);
  127. }
  128. void destruct() nothrow {
  129. glDeleteProgramPipelines(1, &this.pipeline);
  130. }
  131. }
  132. enum vertexShaderSource = "
  133. #version 420 core
  134. layout(location = 0) in vec3 in_position;
  135. layout(location = 1) in vec3 in_normal;
  136. layout(location = 2) in vec4 in_color;
  137. layout(location = 3) in vec2 in_texcoord;
  138. layout(std140, binding = 4) uniform InstanceData {
  139. mat4 transformations["~to!string(maxInstances)~"];
  140. };
  141. //==============
  142. out vec2 _normal;
  143. out vec2 _texture;
  144. out vec3 _color;
  145. //==============
  146. out gl_PerVertex {
  147. vec4 gl_Position;
  148. };
  149. vec2 encode(vec3 n) {
  150. float f = sqrt(8*n.z+8);
  151. return n.xy / f + 0.5;
  152. }
  153. void main() {
  154. // mat4 transformation = mat4(1.0);
  155. // transformation[0][0] = 0.005;
  156. // transformation[1][1] = 0.005;
  157. // transformation[2][2] = 0.005;
  158. gl_Position = transformations[0] * vec4(in_position.x, in_position.y, in_position.z, 1.0);
  159. _normal = encode(in_normal);
  160. _texture = in_texcoord;
  161. _color = in_color.xyz;
  162. };
  163. ";
  164. enum fragmentShaderSource = "
  165. #version 420 core
  166. //==============
  167. in vec2 _normal;
  168. in vec2 _texture;
  169. in vec3 _color;
  170. //==============
  171. layout(location = 0) out float depth;
  172. layout(location = 1) out vec4 normal;
  173. layout(location = 2) out vec4 color;
  174. void main() {
  175. depth = gl_FragCoord.z;
  176. normal.xy = _normal.xy;
  177. color.xyz = _color;
  178. }
  179. ";
  180. //======================================================================================================================
  181. //
  182. //======================================================================================================================
  183. struct Renderer {
  184. GBuffer gbuffer;
  185. ShaderPipeline shaderPipeline;
  186. GlArrayBuffer!VertexData vertexBuffer; // vertex data for all meshes
  187. GlElementArrayBuffer!IndexData indexBuffer; //index data for all meshes
  188. GlUniformBuffer!InstanceData instanceBuffer; // is filled with draw parameters for each instance each frame. shall be accessed as a ringbuffer
  189. GlDrawIndirectBuffer!GlDrawCommand drawCommandBuffer; // is filled with DrawElementsIndirectCommand for each mesh each frame. shall be accessed as a ringbuffer
  190. GlSyncManager vertexSyncManager;
  191. GlSyncManager indexSyncManager;
  192. GlSyncManager instanceSyncManager;
  193. GlSyncManager drawIndirectCommandSyncManager;
  194. size_t vertexRingbufferIndex = 0;
  195. size_t indexRingbufferIndex = 0;
  196. size_t instanceRingbufferIndex = 0;
  197. size_t drawCommandRingbufferIndex = 0;
  198. void construct(uint width, uint height) {
  199. GLbitfield createFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;//TODO: ?? | GL_MAP_DYNAMIC_STORAGE_BIT;
  200. GLbitfield mapFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
  201. this.gbuffer.construct(width, height);
  202. this.shaderPipeline.construct(vertexShaderSource, fragmentShaderSource);
  203. this.vertexBuffer.construct(maxVertices, createFlags, mapFlags);
  204. this.indexBuffer.construct(maxIndices, createFlags, mapFlags);
  205. this.instanceBuffer.construct(maxInstances, createFlags, mapFlags);
  206. this.drawCommandBuffer.construct(maxIndirectCommands, createFlags, mapFlags);
  207. this.vertexSyncManager.construct();
  208. this.indexSyncManager.construct();
  209. this.instanceSyncManager.construct();
  210. this.drawIndirectCommandSyncManager.construct();
  211. glCheck!glEnableVertexAttribArray(0);
  212. glCheck!glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)0 );
  213. glCheck!glEnableVertexAttribArray(1);
  214. glCheck!glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)3 );
  215. glCheck!glEnableVertexAttribArray(2);
  216. glCheck!glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)6 );
  217. glCheck!glEnableVertexAttribArray(3);
  218. glCheck!glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, VertexData.sizeof, cast(GLvoid*)10 );
  219. }
  220. void destruct() {
  221. this.drawIndirectCommandSyncManager.destruct();
  222. this.instanceSyncManager.destruct();
  223. this.indexSyncManager.destruct();
  224. this.vertexSyncManager.destruct();
  225. this.drawCommandBuffer.destruct();
  226. this.instanceBuffer.destruct();
  227. this.indexBuffer.destruct();
  228. this.vertexBuffer.destruct();
  229. this.shaderPipeline.destruct();
  230. this.gbuffer.destruct();
  231. }
  232. void renderOneFrame(ref Scene scene, ref Camera camera, ref GlRenderTarget renderTarget, ref Viewport viewport) {
  233. // Assert that we are tripple buffering
  234. assert(vertexBuffer.length >= 3 * scene.vertexCount);
  235. assert(indexBuffer.length >= 3 * scene.indexCount);
  236. assert(drawCommandBuffer.length >= 3 * scene.meshCount);
  237. // Calc if we have to wrap our buffer
  238. if(vertexRingbufferIndex + scene.vertexCount > this.vertexBuffer.length) {
  239. vertexRingbufferIndex = 0;
  240. }
  241. if(indexRingbufferIndex + scene.indexCount > this.indexBuffer.length) {
  242. indexRingbufferIndex = 0;
  243. }
  244. if(drawCommandRingbufferIndex + scene.meshCount > this.drawCommandBuffer.length) {
  245. drawCommandRingbufferIndex = 0;
  246. }
  247. // Wait until GPU has finished rendereing from our desired buffer destination
  248. // log("vertexSyncManager: ", vertexRingbufferIndex, " ", scene.vertexCount);
  249. // log("indexSyncManager: ", indexRingbufferIndex, " ", scene.indexCount);
  250. // log("drawIndirectCommandSyncManager: ", drawCommandRingbufferIndex, " ", scene.meshCount);
  251. this.vertexSyncManager.waitForLockedRange(vertexRingbufferIndex, scene.vertexCount);
  252. this.indexSyncManager.waitForLockedRange(indexRingbufferIndex, scene.indexCount);
  253. this.drawIndirectCommandSyncManager.waitForLockedRange(drawCommandRingbufferIndex, scene.meshCount);
  254. // Bind pipeline
  255. glCheck!glBindProgramPipeline(shaderPipeline.pipeline); scope(exit) glCheck!glBindProgramPipeline(0);
  256. // Bind buffers
  257. this.vertexBuffer.bind(); scope(exit) this.vertexBuffer.unbind();
  258. this.indexBuffer.bind(); scope(exit) this.indexBuffer.unbind();
  259. this.instanceBuffer.bind(); scope(exit) this.instanceBuffer.unbind();
  260. this.drawCommandBuffer.bind(); scope(exit) this.drawCommandBuffer.unbind();
  261. int idx = glGetUniformBlockIndex(shaderPipeline.vertexShader, "InstanceData");
  262. glCheck!glBindBufferBase(GL_UNIFORM_BUFFER, 4, instanceBuffer.handle);
  263. glCheck!glUniformBlockBinding(shaderPipeline.vertexShader, idx, 4);
  264. // Bind gbuffer
  265. glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gbuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  266. GLenum[] drawBuffers = [GL_COLOR_ATTACHMENT0 + 0, GL_COLOR_ATTACHMENT0 + 1, GL_COLOR_ATTACHMENT0 + 2];
  267. glCheck!glDrawBuffers(drawBuffers.length, drawBuffers.ptr); scope(exit) glCheck!glDrawBuffer(GL_NONE);
  268. // Clear scene and configure draw settings
  269. glCheck!glCullFace(GL_BACK);
  270. glCheck!glEnable(GL_DEPTH_TEST);
  271. glCheck!glDepthFunc(GL_LEQUAL);
  272. glCheck!glDisable(GL_SCISSOR_TEST);
  273. glCheck!glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  274. glCheck!glDepthMask(GL_TRUE); // enable depth mask _before_ glClear ing the depth buffer!
  275. glCheck!glStencilMask(0xFFFFFFFF);
  276. glCheck!glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  277. glCheck!glClearDepth(1.0f);
  278. glCheck!glClearColor(0, 0.3, 0, 1);
  279. glCheck!glViewport(0, 0, this.gbuffer.width, this.gbuffer.height);
  280. // Backup the indices, we'll need it for our draw command and locking
  281. auto curVertexRingbufferIndex = vertexRingbufferIndex;
  282. auto curIndexRingbufferIndex = indexRingbufferIndex;
  283. auto curInstanceRingbufferIndex = instanceRingbufferIndex;
  284. auto curDrawCommandRingbufferIndex = drawCommandRingbufferIndex;
  285. // Upload data to our buffers
  286. foreach(instanceDescriptor; scene.instanceDescriptor) {
  287. auto modelDescriptor = scene.modelDescriptors[instanceDescriptor.modelIndex];
  288. foreach(meshIndex; 0..modelDescriptor.meshDescriptorCount) {
  289. auto meshDesciptor = scene.meshDescriptors[modelDescriptor.meshDescriptorOffset + meshIndex];
  290. this.vertexBuffer.data[vertexRingbufferIndex .. vertexRingbufferIndex + meshDesciptor.vertexCount] = scene.vertexData[meshDesciptor.vertexOffset .. meshDesciptor.vertexOffset + meshDesciptor.vertexCount];
  291. this.indexBuffer.data[indexRingbufferIndex .. indexRingbufferIndex + meshDesciptor.indexCount] = scene.indexData[meshDesciptor.indexOffset .. meshDesciptor.indexOffset + meshDesciptor.indexCount];
  292. this.instanceBuffer.data[instanceRingbufferIndex .. instanceRingbufferIndex + instanceDescriptor.instanceCount] = scene.instanceData[instanceDescriptor.instanceOffset .. instanceDescriptor.instanceOffset + instanceDescriptor.instanceCount];
  293. this.drawCommandBuffer.data[drawCommandRingbufferIndex] = GlDrawCommand(meshDesciptor.indexCount, instanceDescriptor.instanceCount, indexRingbufferIndex, vertexRingbufferIndex, instanceRingbufferIndex);
  294. // log(this.drawCommandBuffer.data[drawCommandRingbufferIndex]);
  295. // Advance ringbuffers
  296. vertexRingbufferIndex += meshDesciptor.vertexCount;
  297. indexRingbufferIndex += meshDesciptor.indexCount;
  298. instanceRingbufferIndex += instanceDescriptor.instanceCount;
  299. ++drawCommandRingbufferIndex;
  300. }
  301. }
  302. // Draw
  303. glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, toGlType!(this.indexBuffer.ValueType), cast(const void*)(curDrawCommandRingbufferIndex * GlDrawCommand.sizeof), scene.meshCount, 0);
  304. // Lock ranges
  305. this.vertexSyncManager.lockRange(curVertexRingbufferIndex, scene.vertexCount);
  306. this.indexSyncManager.lockRange(curIndexRingbufferIndex, scene.indexCount);
  307. this.drawIndirectCommandSyncManager.lockRange(curDrawCommandRingbufferIndex, scene.meshCount);
  308. }
  309. debug {
  310. void blitGBufferToScreen() {
  311. glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, this.gbuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  312. GLsizei width = this.gbuffer.width;
  313. GLsizei height = this.gbuffer.height;
  314. scope(exit) glCheck!glReadBuffer(GL_NONE);
  315. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 0);
  316. glCheck!glBlitFramebuffer(0, 0, width, height, 0, height-300, 400, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  317. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 1);
  318. glCheck!glBlitFramebuffer(0, 0, width, height, 0, 0, 400, 300, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  319. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 2);
  320. glCheck!glBlitFramebuffer(0, 0, width, height, width-400, height-300, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  321. }
  322. }
  323. }