REVIEWED: example: Compute shader Game-of-life

This commit is contained in:
Ray 2021-10-31 12:28:04 +01:00
parent f090f5444c
commit 1fac09d0f4
6 changed files with 316 additions and 322 deletions

View file

@ -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);
}

View file

@ -1,7 +1,8 @@
// Game of Life rendering shader
// Just renders the content of the ssbo at binding 1 to screen.
#version 430 #version 430
// Game of Life rendering shader
// Just renders the content of the ssbo at binding 1 to screen
#define GOL_WIDTH 768 #define GOL_WIDTH 768
// Input vertex attributes (from vertex shader) // Input vertex attributes (from vertex shader)
@ -17,18 +18,12 @@ layout(std430, binding = 1) readonly buffer golLayout
}; };
// Output resolution // Output resolution
uniform vec2 res; uniform vec2 resolution;
void main() void main()
{ {
ivec2 coords = ivec2(fragTexCoord * res); ivec2 coords = ivec2(fragTexCoord*resolution);
if (golBuffer[coords.x + coords.y * uvec2(res).x] == 1) 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);
finalColor = vec4(1.0);
}
else
{
finalColor = vec4(0.0, 0.0, 0.0, 1.0);
}
} }

View file

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

View file

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

View file

@ -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);
}
}

View file

@ -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,7 +3886,9 @@ 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)
@ -3895,9 +3896,11 @@ unsigned int rlLoadShaderBuffer(unsigned long long size, const void *data, int u
{ {
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,14 +3908,18 @@ 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
@ -3920,8 +3927,10 @@ 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
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------