瀏覽代碼

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