Преглед на файлове

REVIEWED: example: Compute shader Game-of-life

Ray преди 3 години
родител
ревизия
1fac09d0f4

+ 41 - 0
examples/others/resources/shaders/glsl430/gol.glsl

@@ -0,0 +1,41 @@
+#version 430
+
+// Game of Life logic shader
+
+#define GOL_WIDTH 768
+
+layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+
+layout(std430, binding = 1) readonly restrict buffer golLayout {
+    uint golBuffer[];       // golBuffer[x, y] = golBuffer[x + gl_NumWorkGroups.x * y]
+};
+
+layout(std430, binding = 2) writeonly restrict buffer golLayout2 {
+    uint golBufferDest[];   // golBufferDest[x, y] = golBufferDest[x + gl_NumWorkGroups.x * y]
+};
+
+#define fetchGol(x, y) ((((x) < 0) || ((y) < 0) || ((x) > GOL_WIDTH) || ((y) > GOL_WIDTH)) \
+    ? (0) \
+    : golBuffer[(x) + GOL_WIDTH * (y)])
+
+#define setGol(x, y, value) golBufferDest[(x) + GOL_WIDTH*(y)] = value
+
+void main()
+{
+    uint neighbourCount = 0;
+    uint x = gl_GlobalInvocationID.x;
+    uint y = gl_GlobalInvocationID.y;
+
+    neighbourCount += fetchGol(x - 1, y - 1);   // Top left
+    neighbourCount += fetchGol(x, y - 1);       // Top middle
+    neighbourCount += fetchGol(x + 1, y - 1);   // Top right
+    neighbourCount += fetchGol(x - 1, y);       // Left
+    neighbourCount += fetchGol(x + 1, y);       // Right
+    neighbourCount += fetchGol(x - 1, y + 1);   // Bottom left
+    neighbourCount += fetchGol(x, y + 1);       // Bottom middle   
+    neighbourCount += fetchGol(x + 1, y + 1);   // Bottom right
+
+    if (neighbourCount == 3) setGol(x, y, 1);
+    else if (neighbourCount == 2) setGol(x, y, fetchGol(x, y));
+    else setGol(x, y, 0);
+}

+ 29 - 34
examples/shaders/resources/shaders/glsl430/gol_render.glsl → examples/others/resources/shaders/glsl430/gol_render.glsl

@@ -1,34 +1,29 @@
-// Game of Life rendering shader
-// Just renders the content of the ssbo at binding 1 to screen.
-#version 430
-
-#define GOL_WIDTH 768
-
-// Input vertex attributes (from vertex shader)
-in vec2 fragTexCoord;
-
-// Output fragment color
-out vec4 finalColor;
-
-// Input game of life grid.
-layout(std430, binding = 1) readonly buffer golLayout
-{
-    uint golBuffer[];
-};
-
-// Output resolution
-uniform vec2 res;
-
-void main()
-{
-    ivec2 coords = ivec2(fragTexCoord * res);
-
-    if (golBuffer[coords.x + coords.y * uvec2(res).x] == 1)
-    {
-        finalColor = vec4(1.0);
-    }
-    else
-    {
-        finalColor = vec4(0.0, 0.0, 0.0, 1.0);
-    }
-}
+#version 430
+
+// Game of Life rendering shader
+// Just renders the content of the ssbo at binding 1 to screen
+
+#define GOL_WIDTH 768
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+
+// Output fragment color
+out vec4 finalColor;
+
+// Input game of life grid.
+layout(std430, binding = 1) readonly buffer golLayout
+{
+    uint golBuffer[];
+};
+
+// Output resolution
+uniform vec2 resolution;
+
+void main()
+{
+    ivec2 coords = ivec2(fragTexCoord*resolution);
+
+    if ((golBuffer[coords.x + coords.y*uvec2(resolution).x]) == 1) finalColor = vec4(1.0);
+    else finalColor = vec4(0.0, 0.0, 0.0, 1.0);
+}

+ 51 - 54
examples/shaders/resources/shaders/glsl430/gol_transfert.glsl → examples/others/resources/shaders/glsl430/gol_transfert.glsl

@@ -1,54 +1,51 @@
-// Game of life transfert shader.
-#version 430
-#define GOL_WIDTH 768
-
-// Structure definitions
-struct GolUpdateCmd {
-    uint x; // x coordinate of the gol command
-    uint y; // y coordinate of the gol command
-    uint w; // width of the filled zone
-    uint enabled; // whether to enable or disable zone
-};
-
-// Local compute unit size.
-layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
-// Output game of life grid buffer.
-layout(std430, binding = 1) buffer golBufferLayout
-{
-    uint golBuffer[]; // golBuffer[x, y] = golBuffer[x + GOL_WIDTH * y]
-};
-
-// Command buffer
-layout(std430, binding = 3) readonly restrict buffer golUpdateLayout
-{
-    uint count;
-    GolUpdateCmd commands[];
-};
-
-#define isInside(x, y) (((x) >= 0) && ((y) >= 0) && ((x) < GOL_WIDTH) && ((y) < GOL_WIDTH))
-#define getBufferIndex(x, y) ((x) + GOL_WIDTH * (y))
-
-void main()
-{
-    uint cmd_index = gl_GlobalInvocationID.x;
-    GolUpdateCmd cmd = commands[cmd_index];
-
-    for (uint x = cmd.x; x < (cmd.x + cmd.w); x++)
-    {
-        for (uint y = cmd.y; y < (cmd.y + cmd.w); y++)
-        {
-            if (isInside(x, y))
-            {
-                if (cmd.enabled != 0)
-                {
-                    atomicOr(golBuffer[getBufferIndex(x, y)], 1);
-                }
-                else
-                {
-                    atomicAnd(golBuffer[getBufferIndex(x, y)], 0);
-                }
-            }
-        }
-    }
-}
+#version 430
+
+// Game of life transfert shader
+
+#define GOL_WIDTH 768
+
+// Game Of Life Update Command
+// NOTE: matches the structure defined on main program
+struct GolUpdateCmd {
+    uint x;         // x coordinate of the gol command
+    uint y;         // y coordinate of the gol command
+    uint w;         // width of the filled zone
+    uint enabled;   // whether to enable or disable zone
+};
+
+// Local compute unit size
+layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+// Output game of life grid buffer
+layout(std430, binding = 1) buffer golBufferLayout
+{
+    uint golBuffer[]; // golBuffer[x, y] = golBuffer[x + GOL_WIDTH * y]
+};
+
+// Command buffer
+layout(std430, binding = 3) readonly restrict buffer golUpdateLayout
+{
+    uint count;
+    GolUpdateCmd commands[];
+};
+
+#define isInside(x, y) (((x) >= 0) && ((y) >= 0) && ((x) < GOL_WIDTH) && ((y) < GOL_WIDTH))
+#define getBufferIndex(x, y) ((x) + GOL_WIDTH * (y))
+
+void main()
+{
+    uint cmdIndex = gl_GlobalInvocationID.x;
+    GolUpdateCmd cmd = commands[cmdIndex];
+
+    for (uint x = cmd.x; x < (cmd.x + cmd.w); x++)
+    {
+        for (uint y = cmd.y; y < (cmd.y + cmd.w); y++)
+        {
+            if (isInside(x, y))
+            {
+                if (cmd.enabled != 0) atomicOr(golBuffer[getBufferIndex(x, y)], 1);
+                else atomicAnd(golBuffer[getBufferIndex(x, y)], 0);
+            }
+        }
+    }
+}

+ 173 - 164
examples/shaders/shaders_compute_gol.c → examples/others/rlgl_compute_shader.c

@@ -1,164 +1,173 @@
-/*******************************************************************************************
-*
-*   raylib [shaders] example - Compute shaders Conway's Game of Life
-*
-*   NOTE: This example requires raylib OpenGL 4.3 versions for compute shaders support,
-*
-*   NOTE: Shaders used in this example are #version 430 (OpenGL 4.3).
-*
-*   This example has been created using raylib 4.0 (www.raylib.com)
-*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
-*
-*   Example contributed by Teddy Astie (@tsnake41)
-*
-*   Copyright (c) 2021 Teddy Astie (@tsnake41)
-*
-********************************************************************************************/
-
-#include <stdlib.h>
-
-#include "raylib.h"
-#include "rlgl.h"
-
-// IMPORTANT: This must match gol*.glsl GOL_WIDTH constant.
-//            This must be a multiple of 16 (check golLogic compute dispatch).
-#define GOL_WIDTH 768
-
-// Maximum amount of queued draw commands (squares draw from mouse down events).
-#define MAX_BUFFERED_TRANSFERTS 48
-
-struct GolUpdateCmd
-{
-    unsigned int x; // x coordinate of the gol command
-    unsigned int y; // y coordinate of the gol command
-    unsigned int w; // width of the filled zone
-    unsigned int enabled; // whether to enable or disable zone
-};
-
-struct GolUpdateSSBO
-{
-    unsigned int count;
-    struct GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
-};
-
-int main(void)
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    InitWindow(GOL_WIDTH, GOL_WIDTH, "raylib [shaders] example - compute shader gol");
-
-    const Vector2 resolution = { GOL_WIDTH, GOL_WIDTH };
-    unsigned int brushSize = 1;
-
-    // Game of Life logic compute shader
-    char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
-    unsigned int golLogicShader = rlCompileShader(golLogicCode, RL_COMPUTE_SHADER);
-    unsigned int golLogicProgram = rlLoadComputeShaderProgram(golLogicShader);
-    MemFree(golLogicCode);
-
-    // Game of Life logic compute shader
-    Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
-    int resUniformLoc = GetShaderLocation(golRenderShader, "res");
-
-    // Game of Life transfert shader
-    char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
-    unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER);
-    unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader);
-    MemFree(golTransfertCode);
-
-    // SSBOs
-    unsigned int ssboA = rlLoadShaderBuffer(sizeof(unsigned int) * GOL_WIDTH * GOL_WIDTH, NULL, RL_DYNAMIC_COPY);
-    unsigned int ssboB = rlLoadShaderBuffer(sizeof(unsigned int) * GOL_WIDTH * GOL_WIDTH, NULL, RL_DYNAMIC_COPY);
-
-    struct GolUpdateSSBO transfertBuffer;
-    transfertBuffer.count = 0;
-
-    int transfertSSBO = rlLoadShaderBuffer(sizeof(struct GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
-
-    // Create a white texture of the size of the window to update 
-    // each pixel of the window using the fragment shader.
-    Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
-    Texture whiteTex = LoadTextureFromImage(whiteImage);
-    UnloadImage(whiteImage);
-
-    while (!WindowShouldClose())
-    {
-        if (IsKeyPressed(KEY_UP))                            brushSize *= 2;
-        else if (IsKeyPressed(KEY_DOWN) && (brushSize != 1)) brushSize /= 2;
-
-        if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
-            && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
-        {
-            // Buffer a new command
-            transfertBuffer.commands[transfertBuffer.count].x = GetMouseX();
-            transfertBuffer.commands[transfertBuffer.count].y = GetMouseY();
-            transfertBuffer.commands[transfertBuffer.count].w = brushSize;
-            transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
-            transfertBuffer.count++;
-        }
-        else if (transfertBuffer.count > 0)
-        {
-            // Process transfert buffer
-
-            // Send SSBO buffer to GPU
-            rlUpdateShaderBufferElements(transfertSSBO, &transfertBuffer, sizeof(struct GolUpdateSSBO), 0);
-            // Process ssbo command
-            rlEnableShader(golTransfertProgram);
-            rlBindShaderBuffer(ssboA, 1);
-            rlBindShaderBuffer(transfertSSBO, 3);
-            rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // each GPU unit will process a command
-            rlDisableShader();
-
-            transfertBuffer.count = 0;
-        }
-        else
-        {
-            // Process game of life logic
-            rlEnableShader(golLogicProgram);
-            rlBindShaderBuffer(ssboA, 1);
-            rlBindShaderBuffer(ssboB, 2);
-            rlComputeShaderDispatch(GOL_WIDTH / 16, GOL_WIDTH / 16, 1);
-            rlDisableShader();
-
-            // ssboA <-> ssboB
-            int temp = ssboA;
-            ssboA = ssboB;
-            ssboB = temp;
-        }
-
-        rlBindShaderBuffer(ssboA, 1);
-
-        BeginDrawing();
-
-        ClearBackground(BLANK);
-        SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
-
-        BeginShaderMode(golRenderShader);
-        DrawTexture(whiteTex, 0, 0, WHITE);
-        EndShaderMode();
-
-        DrawFPS(0, 0);
-
-        EndDrawing();
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-
-    // Unload shader buffers objects.
-    rlUnloadShaderBuffer(ssboA);
-    rlUnloadShaderBuffer(ssboB);
-    rlUnloadShaderBuffer(transfertSSBO);
-
-    // Unload compute shader programs
-    rlUnloadShaderProgram(golTransfertProgram);
-    rlUnloadShaderProgram(golLogicProgram);
-
-    UnloadTexture(whiteTex);       // Unload white texture
-    UnloadShader(golRenderShader); // Unload rendering fragment shader
-
-    CloseWindow();                 // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-
-    return 0;
-}
+/*******************************************************************************************
+*
+*   raylib [rlgl] example - compute shader - Conway's Game of Life
+*
+*   NOTE: This example requires raylib OpenGL 4.3 versions for compute shaders support,
+*         shaders used in this example are #version 430 (OpenGL 4.3)
+*
+*   This example has been created using raylib 4.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Copyright (c) 2021 Teddy Astie (@tsnake41)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rlgl.h"
+
+#include <stdlib.h>
+
+// IMPORTANT: This must match gol*.glsl GOL_WIDTH constant.
+// This must be a multiple of 16 (check golLogic compute dispatch).
+#define GOL_WIDTH 768
+
+// Maximum amount of queued draw commands (squares draw from mouse down events).
+#define MAX_BUFFERED_TRANSFERTS 48
+
+// Game Of Life Update Command
+typedef struct GolUpdateCmd {
+    unsigned int x;         // x coordinate of the gol command
+    unsigned int y;         // y coordinate of the gol command
+    unsigned int w;         // width of the filled zone
+    unsigned int enabled;   // whether to enable or disable zone
+} GolUpdateCmd;
+
+// Game Of Life Update Commands SSBO
+typedef struct GolUpdateSSBO {
+    unsigned int count;
+    GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
+} GolUpdateSSBO;
+
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    InitWindow(GOL_WIDTH, GOL_WIDTH, "raylib [rlgl] example - compute shader - game of life");
+
+    const Vector2 resolution = { GOL_WIDTH, GOL_WIDTH };
+    unsigned int brushSize = 8;
+
+    // Game of Life logic compute shader
+    char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
+    unsigned int golLogicShader = rlCompileShader(golLogicCode, RL_COMPUTE_SHADER);
+    unsigned int golLogicProgram = rlLoadComputeShaderProgram(golLogicShader);
+    UnloadFileText(golLogicCode);
+
+    // Game of Life logic compute shader
+    Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
+    int resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
+
+    // Game of Life transfert shader
+    char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
+    unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER);
+    unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader);
+    UnloadFileText(golTransfertCode);
+
+    // SSBOs
+    unsigned int ssboA = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
+    unsigned int ssboB = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
+
+    struct GolUpdateSSBO transfertBuffer;
+    transfertBuffer.count = 0;
+
+    int transfertSSBO = rlLoadShaderBuffer(sizeof(struct GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
+
+    // Create a white texture of the size of the window to update 
+    // each pixel of the window using the fragment shader
+    Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
+    Texture whiteTex = LoadTextureFromImage(whiteImage);
+    UnloadImage(whiteImage);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        brushSize += (int)GetMouseWheelMove();
+
+        if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
+            && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
+        {
+            // Buffer a new command
+            transfertBuffer.commands[transfertBuffer.count].x = GetMouseX() - brushSize/2;
+            transfertBuffer.commands[transfertBuffer.count].y = GetMouseY() - brushSize/2;
+            transfertBuffer.commands[transfertBuffer.count].w = brushSize;
+            transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
+            transfertBuffer.count++;
+        }
+        else if (transfertBuffer.count > 0)
+        {
+            // Process transfert buffer
+
+            // Send SSBO buffer to GPU
+            rlUpdateShaderBufferElements(transfertSSBO, &transfertBuffer, sizeof(struct GolUpdateSSBO), 0);
+            
+            // Process ssbo command
+            rlEnableShader(golTransfertProgram);
+            rlBindShaderBuffer(ssboA, 1);
+            rlBindShaderBuffer(transfertSSBO, 3);
+            rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // each GPU unit will process a command
+            rlDisableShader();
+
+            transfertBuffer.count = 0;
+        }
+        else
+        {
+            // Process game of life logic
+            rlEnableShader(golLogicProgram);
+            rlBindShaderBuffer(ssboA, 1);
+            rlBindShaderBuffer(ssboB, 2);
+            rlComputeShaderDispatch(GOL_WIDTH/16, GOL_WIDTH/16, 1);
+            rlDisableShader();
+
+            // ssboA <-> ssboB
+            int temp = ssboA;
+            ssboA = ssboB;
+            ssboB = temp;
+        }
+
+        rlBindShaderBuffer(ssboA, 1);
+        SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(BLANK);
+
+            BeginShaderMode(golRenderShader);
+                DrawTexture(whiteTex, 0, 0, WHITE);
+            EndShaderMode();
+            
+            DrawRectangleLines(GetMouseX() - brushSize/2, GetMouseY() - brushSize/2, brushSize, brushSize, RED);
+
+            DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, WHITE);
+            DrawFPS(GetScreenWidth() - 100, 10);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    // Unload shader buffers objects.
+    rlUnloadShaderBuffer(ssboA);
+    rlUnloadShaderBuffer(ssboB);
+    rlUnloadShaderBuffer(transfertSSBO);
+
+    // Unload compute shader programs
+    rlUnloadShaderProgram(golTransfertProgram);
+    rlUnloadShaderProgram(golLogicProgram);
+
+    UnloadTexture(whiteTex);            // Unload white texture
+    UnloadShader(golRenderShader);      // Unload rendering fragment shader
+
+    CloseWindow();                      // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}

+ 0 - 64
examples/shaders/resources/shaders/glsl430/gol.glsl

@@ -1,64 +0,0 @@
-// Game of Life logic shader
-#version 430
-
-#define GOL_WIDTH 768
-
-layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(std430, binding = 1) readonly restrict buffer golLayout {
-    uint golBuffer[]; // golBuffer[x, y] = golBuffer[x + gl_NumWorkGroups.x * y]
-};
-
-layout(std430, binding = 2) writeonly restrict buffer golLayout2 {
-    uint golBufferDest[]; // golBufferDest[x, y] = golBufferDest[x + gl_NumWorkGroups.x * y]
-};
-
-#define fetchGol(x, y) ((((x) < 0) || ((y) < 0) || ((x) > GOL_WIDTH) || ((y) > GOL_WIDTH)) \
-    ? (0) \
-    : golBuffer[(x) + GOL_WIDTH * (y)])
-
-#define setGol(x, y, value) golBufferDest[(x) + GOL_WIDTH * (y)] = value
-
-void main()
-{
-    uint neighbour_count = 0;
-    uint x = gl_GlobalInvocationID.x;
-    uint y = gl_GlobalInvocationID.y;
-
-    // Top left
-    neighbour_count += fetchGol(x - 1, y - 1);
-
-    // Top middle
-    neighbour_count += fetchGol(x, y - 1);
-
-    // Top right
-    neighbour_count += fetchGol(x + 1, y - 1);
-
-    // Left
-    neighbour_count += fetchGol(x - 1, y);
-
-    // Right
-    neighbour_count += fetchGol(x + 1, y);
-
-    // Bottom left
-    neighbour_count += fetchGol(x - 1, y + 1);
-
-    // Bottom middle
-    neighbour_count += fetchGol(x, y + 1);
-
-    // Bottom right
-    neighbour_count += fetchGol(x + 1, y + 1);
-
-    if (neighbour_count == 3)
-    {
-        setGol(x, y, 1);
-    }
-    else if (neighbour_count == 2)
-    {
-        setGol(x, y, fetchGol(x, y));
-    }
-    else
-    {
-        setGol(x, y, 0);
-    }
-}

+ 22 - 6
src/rlgl.h

@@ -662,7 +662,6 @@ RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat);
 RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId);           // Set shader value sampler
 RLAPI void rlSetShader(unsigned int id, int *locs);                             // Set shader currently active (id and locations)
 
-#if defined(GRAPHICS_API_OPENGL_43)
 // Compute shader management
 RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId);           // Load compute shader program
 RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ);  // Dispatch compute shader (equivalent to *draw* for graphics pilepine)
@@ -678,7 +677,6 @@ RLAPI void rlBindShaderBuffer(unsigned int id, unsigned int index);
 // Buffer management
 RLAPI void rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned long long destOffset, unsigned long long srcOffset, unsigned long long count); // Copy SSBO buffer data
 RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly);  // Bind image texture
-#endif
 
 // Matrix state management
 RLAPI Matrix rlGetMatrixModelview(void);                                  // Get internal modelview matrix
@@ -3836,12 +3834,12 @@ void rlSetShader(unsigned int id, int *locs)
 #endif
 }
 
-#if defined(GRAPHICS_API_OPENGL_43)
 // Load compute shader program
 unsigned int rlLoadComputeShaderProgram(unsigned int shaderId)
 {
     unsigned int program = 0;
 
+#if defined(GRAPHICS_API_OPENGL_43)
     GLint success = 0;
     program = glCreateProgram();
     glAttachShader(program, shaderId);
@@ -3880,6 +3878,7 @@ unsigned int rlLoadComputeShaderProgram(unsigned int shaderId)
 
         TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", program);
     }
+#endif
 
     return program;
 }
@@ -3887,17 +3886,21 @@ unsigned int rlLoadComputeShaderProgram(unsigned int shaderId)
 // Dispatch compute shader (equivalent to *draw* for graphics pilepine)
 void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glDispatchCompute(groupX, groupY, groupZ);
+#endif
 }
 
 // Load shader storage buffer object (SSBO)
 unsigned int rlLoadShaderBuffer(unsigned long long size, const void *data, int usageHint)
 {
     unsigned int ssbo = 0;
-
+    
+#if defined(GRAPHICS_API_OPENGL_43)
     glGenBuffers(1, &ssbo);
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
     glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY);
+#endif
 
     return ssbo;
 }
@@ -3905,23 +3908,29 @@ unsigned int rlLoadShaderBuffer(unsigned long long size, const void *data, int u
 // Unload shader storage buffer object (SSBO)
 void rlUnloadShaderBuffer(unsigned int ssboId)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glDeleteBuffers(1, &ssboId);
+#endif
 }
 
 // Update SSBO buffer data
 void rlUpdateShaderBufferElements(unsigned int id, const void *data, unsigned long long dataSize, unsigned long long offset)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, id);
     glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, dataSize, data);
+#endif
 }
 
 // Get SSBO buffer size
 unsigned long long rlGetShaderBufferSize(unsigned int id)
 {
     long long size = 0;
-
+    
+#if defined(GRAPHICS_API_OPENGL_43)
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, id);
     glGetInteger64v(GL_SHADER_STORAGE_BUFFER_SIZE, &size);
+#endif
 
     return (size > 0)? size : 0;
 }
@@ -3929,33 +3938,40 @@ unsigned long long rlGetShaderBufferSize(unsigned int id)
 // Read SSBO buffer data
 void rlReadShaderBufferElements(unsigned int id, void *dest, unsigned long long count, unsigned long long offset)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, id);
     glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, count, dest);
+#endif
 }
 
 // Bind SSBO buffer
 void rlBindShaderBuffer(unsigned int id, unsigned int index)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, id);
+#endif
 }
 
 // Copy SSBO buffer data
 void rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned long long destOffset, unsigned long long srcOffset, unsigned long long count)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     glBindBuffer(GL_COPY_READ_BUFFER, srcId);
     glBindBuffer(GL_COPY_WRITE_BUFFER, destId);
     glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, destOffset, count);
+#endif
 }
 
 // Bind image texture
 void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly)
 {
+#if defined(GRAPHICS_API_OPENGL_43)
     int glInternalFormat = 0, glFormat = 0, glType = 0;
 
     rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
     glBindImageTexture(index, id, 0, 0, 0, readonly ? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat);
-}
 #endif
+}
 
 // Matrix state management
 //-----------------------------------------------------------------------------------------