rlgl_compute_shader.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*******************************************************************************************
  2. *
  3. * raylib [rlgl] example - compute shader - Conway's Game of Life
  4. *
  5. * NOTE: This example requires raylib OpenGL 4.3 versions for compute shaders support,
  6. * shaders used in this example are #version 430 (OpenGL 4.3)
  7. *
  8. * This example has been created using raylib 4.0 (www.raylib.com)
  9. * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
  10. *
  11. * Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
  12. *
  13. * Copyright (c) 2021 Teddy Astie (@tsnake41)
  14. *
  15. ********************************************************************************************/
  16. #include "raylib.h"
  17. #include "rlgl.h"
  18. #include <stdlib.h>
  19. // IMPORTANT: This must match gol*.glsl GOL_WIDTH constant.
  20. // This must be a multiple of 16 (check golLogic compute dispatch).
  21. #define GOL_WIDTH 768
  22. // Maximum amount of queued draw commands (squares draw from mouse down events).
  23. #define MAX_BUFFERED_TRANSFERTS 48
  24. // Game Of Life Update Command
  25. typedef struct GolUpdateCmd {
  26. unsigned int x; // x coordinate of the gol command
  27. unsigned int y; // y coordinate of the gol command
  28. unsigned int w; // width of the filled zone
  29. unsigned int enabled; // whether to enable or disable zone
  30. } GolUpdateCmd;
  31. // Game Of Life Update Commands SSBO
  32. typedef struct GolUpdateSSBO {
  33. unsigned int count;
  34. GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
  35. } GolUpdateSSBO;
  36. int main(void)
  37. {
  38. // Initialization
  39. //--------------------------------------------------------------------------------------
  40. InitWindow(GOL_WIDTH, GOL_WIDTH, "raylib [rlgl] example - compute shader - game of life");
  41. const Vector2 resolution = { GOL_WIDTH, GOL_WIDTH };
  42. unsigned int brushSize = 8;
  43. // Game of Life logic compute shader
  44. char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
  45. unsigned int golLogicShader = rlCompileShader(golLogicCode, RL_COMPUTE_SHADER);
  46. unsigned int golLogicProgram = rlLoadComputeShaderProgram(golLogicShader);
  47. UnloadFileText(golLogicCode);
  48. // Game of Life logic compute shader
  49. Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
  50. int resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
  51. // Game of Life transfert shader
  52. char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
  53. unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER);
  54. unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader);
  55. UnloadFileText(golTransfertCode);
  56. // SSBOs
  57. unsigned int ssboA = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
  58. unsigned int ssboB = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
  59. struct GolUpdateSSBO transfertBuffer;
  60. transfertBuffer.count = 0;
  61. int transfertSSBO = rlLoadShaderBuffer(sizeof(struct GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
  62. // Create a white texture of the size of the window to update
  63. // each pixel of the window using the fragment shader
  64. Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
  65. Texture whiteTex = LoadTextureFromImage(whiteImage);
  66. UnloadImage(whiteImage);
  67. //--------------------------------------------------------------------------------------
  68. // Main game loop
  69. while (!WindowShouldClose())
  70. {
  71. // Update
  72. //----------------------------------------------------------------------------------
  73. brushSize += (int)GetMouseWheelMove();
  74. if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
  75. && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
  76. {
  77. // Buffer a new command
  78. transfertBuffer.commands[transfertBuffer.count].x = GetMouseX() - brushSize/2;
  79. transfertBuffer.commands[transfertBuffer.count].y = GetMouseY() - brushSize/2;
  80. transfertBuffer.commands[transfertBuffer.count].w = brushSize;
  81. transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
  82. transfertBuffer.count++;
  83. }
  84. else if (transfertBuffer.count > 0)
  85. {
  86. // Process transfert buffer
  87. // Send SSBO buffer to GPU
  88. rlUpdateShaderBufferElements(transfertSSBO, &transfertBuffer, sizeof(struct GolUpdateSSBO), 0);
  89. // Process ssbo command
  90. rlEnableShader(golTransfertProgram);
  91. rlBindShaderBuffer(ssboA, 1);
  92. rlBindShaderBuffer(transfertSSBO, 3);
  93. rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // each GPU unit will process a command
  94. rlDisableShader();
  95. transfertBuffer.count = 0;
  96. }
  97. else
  98. {
  99. // Process game of life logic
  100. rlEnableShader(golLogicProgram);
  101. rlBindShaderBuffer(ssboA, 1);
  102. rlBindShaderBuffer(ssboB, 2);
  103. rlComputeShaderDispatch(GOL_WIDTH/16, GOL_WIDTH/16, 1);
  104. rlDisableShader();
  105. // ssboA <-> ssboB
  106. int temp = ssboA;
  107. ssboA = ssboB;
  108. ssboB = temp;
  109. }
  110. rlBindShaderBuffer(ssboA, 1);
  111. SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
  112. //----------------------------------------------------------------------------------
  113. // Draw
  114. //----------------------------------------------------------------------------------
  115. BeginDrawing();
  116. ClearBackground(BLANK);
  117. BeginShaderMode(golRenderShader);
  118. DrawTexture(whiteTex, 0, 0, WHITE);
  119. EndShaderMode();
  120. DrawRectangleLines(GetMouseX() - brushSize/2, GetMouseY() - brushSize/2, brushSize, brushSize, RED);
  121. DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, WHITE);
  122. DrawFPS(GetScreenWidth() - 100, 10);
  123. EndDrawing();
  124. //----------------------------------------------------------------------------------
  125. }
  126. // De-Initialization
  127. //--------------------------------------------------------------------------------------
  128. // Unload shader buffers objects.
  129. rlUnloadShaderBuffer(ssboA);
  130. rlUnloadShaderBuffer(ssboB);
  131. rlUnloadShaderBuffer(transfertSSBO);
  132. // Unload compute shader programs
  133. rlUnloadShaderProgram(golTransfertProgram);
  134. rlUnloadShaderProgram(golLogicProgram);
  135. UnloadTexture(whiteTex); // Unload white texture
  136. UnloadShader(golRenderShader); // Unload rendering fragment shader
  137. CloseWindow(); // Close window and OpenGL context
  138. //--------------------------------------------------------------------------------------
  139. return 0;
  140. }