diff --git a/examples/shaders/shaders_rlgl_compute.c b/examples/shaders/shaders_rlgl_compute.c index af3bb6fe4..a92fbac6a 100644 --- a/examples/shaders/shaders_rlgl_compute.c +++ b/examples/shaders/shaders_rlgl_compute.c @@ -65,8 +65,8 @@ int main(void) // 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); + unsigned int golLogicShader = rlLoadShader(golLogicCode, RL_COMPUTE_SHADER); + unsigned int golLogicProgram = rlLoadShaderProgramCompute(golLogicShader); UnloadFileText(golLogicCode); // Game of Life logic render shader @@ -75,8 +75,8 @@ int main(void) // Game of Life transfert shader (CPU<->GPU download and upload) char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl"); - unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER); - unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader); + unsigned int golTransfertShader = rlLoadShader(golTransfertCode, RL_COMPUTE_SHADER); + unsigned int golTransfertProgram = rlLoadShaderProgramCompute(golTransfertShader); UnloadFileText(golTransfertCode); // Load shader storage buffer object (SSBO), id returned @@ -169,7 +169,9 @@ int main(void) rlUnloadShaderBuffer(ssboB); rlUnloadShaderBuffer(ssboTransfert); - // Unload compute shader programs + // Unload compute shader + rlUnloadShader(golLogicShader); + rlUnloadShader(golTransfertShader); rlUnloadShaderProgram(golTransfertProgram); rlUnloadShaderProgram(golLogicProgram); diff --git a/src/rcore.c b/src/rcore.c index 2e0958f35..de1bb371c 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1243,7 +1243,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) { Shader shader = { 0 }; - shader.id = rlLoadShaderCode(vsCode, fsCode); + shader.id = rlLoadShaderProgram(vsCode, fsCode); if (shader.id == 0) { diff --git a/src/rlgl.h b/src/rlgl.h index 0e73e415c..e5b7d87f4 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -762,7 +762,7 @@ RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Rea // Framebuffer management (fbo) RLAPI unsigned int rlLoadFramebuffer(void); // Load an empty framebuffer -RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer +RLAPI void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU // WARNING: Copy and resize framebuffer functionality only defined for software backend @@ -770,13 +770,14 @@ RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, vo RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer // Shaders management -RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings -RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) -RLAPI void rlUnloadShader(unsigned int id); // Unload shader, loaded with rlCompileShader() -RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program +RLAPI unsigned int rlLoadShader(const char *code, int type); // Load (compile) shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) +RLAPI unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode); // Load shader from code strings +RLAPI unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId); // Load shader program, using already loaded shader ids +RLAPI unsigned int rlLoadShaderProgramCompute(unsigned int csId); // Load compute shader program +RLAPI void rlUnloadShader(unsigned int id); // Unload shader, loaded with rlLoadShader() RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program -RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform, requires shader program id -RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute, requires shader program id +RLAPI int rlGetLocationUniform(unsigned int id, const char *uniformName); // Get shader location uniform, requires shader program id +RLAPI int rlGetLocationAttrib(unsigned int id, const char *attribName); // Get shader location attribute, requires shader program id RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices @@ -784,7 +785,6 @@ RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) // 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 pipeline) // Shader buffer storage object management (ssbo) @@ -3837,12 +3837,12 @@ unsigned int rlLoadFramebuffer(void) return fboId; } -// Attach color buffer texture to an fbo (unloads previous attachment) +// Attach color buffer texture to a framebuffer object (unloads previous attachment) // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture -void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel) +void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel) { #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) - glBindFramebuffer(GL_FRAMEBUFFER, fboId); + glBindFramebuffer(GL_FRAMEBUFFER, id); switch (attachType) { @@ -4179,93 +4179,14 @@ void rlUnloadVertexBuffer(unsigned int vboId) // Shaders management //----------------------------------------------------------------------------------------------- -// Load shader from code strings -// NOTE: If shader string is NULL, using default vertex/fragment shaders -unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) -{ - unsigned int id = 0; // Shader program id - if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId = 0; - unsigned int fragmentShaderId = 0; - - // Compile vertex shader (if provided) - // NOTE: If not vertex shader is provided, use default one - if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER); - else vertexShaderId = RLGL.State.defaultVShaderId; - - // Compile fragment shader (if provided) - // NOTE: If not vertex shader is provided, use default one - if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); - else fragmentShaderId = RLGL.State.defaultFShaderId; - - // In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id - if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; - else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) - { - // One of or both shader are new, a new shader program needs to be compiled - id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId); - - // Detaching and deleting vertex/fragment shaders (if not default ones) - // WARNING: Detach shader before deletion to make sure memory is freed - if (vertexShaderId != RLGL.State.defaultVShaderId) - { - // WARNING: Shader program linkage could fail and returned id is 0 - if (id > 0) glDetachShader(id, vertexShaderId); - glDeleteShader(vertexShaderId); - } - if (fragmentShaderId != RLGL.State.defaultFShaderId) - { - // WARNING: Shader program linkage could fail and returned id is 0 - if (id > 0) glDetachShader(id, fragmentShaderId); - glDeleteShader(fragmentShaderId); - } - - // In case shader program loading failed, assign default shader - if (id == 0) - { - // In case shader loading fails, reassigning default shader - TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); - id = RLGL.State.defaultShaderId; - } - /* - else - { - // Get available shader uniforms - // NOTE: This information is useful for debug... - int uniformCount = -1; - glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); - - for (int i = 0; i < uniformCount; i++) - { - int namelen = -1; - int num = -1; - char name[256] = { 0 }; // Assume no variable names longer than 256 - GLenum type = GL_ZERO; - - // Get the name of the uniforms - glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); - - name[namelen] = 0; - TRACELOG(RL_LOG_DEBUG, "SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); - } - } - */ - } -#endif - - return id; -} - -// Compile custom shader and return shader id -unsigned int rlCompileShader(const char *shaderCode, int type) +// Load (compile) shader and return shader id +unsigned int rlLoadShader(const char *code, int type) { unsigned int shaderId = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) shaderId = glCreateShader(type); - glShaderSource(shaderId, 1, &shaderCode, NULL); + glShaderSource(shaderId, 1, &code, NULL); GLint success = 0; glCompileShader(shaderId); @@ -4323,8 +4244,87 @@ unsigned int rlCompileShader(const char *shaderCode, int type) return shaderId; } -// Load custom shader strings and return program id -unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) +// Load shader program from code strings +// NOTE: If shader string is NULL, using default vertex/fragment shaders +unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode) +{ + unsigned int id = 0; // Shader program id + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int vertexShaderId = 0; + unsigned int fragmentShaderId = 0; + + // Compile vertex shader (if provided) + // NOTE: If not vertex shader is provided, use default one + if (vsCode != NULL) vertexShaderId = rlLoadShader(vsCode, GL_VERTEX_SHADER); + else vertexShaderId = RLGL.State.defaultVShaderId; + + // Compile fragment shader (if provided) + // NOTE: If not vertex shader is provided, use default one + if (fsCode != NULL) fragmentShaderId = rlLoadShader(fsCode, GL_FRAGMENT_SHADER); + else fragmentShaderId = RLGL.State.defaultFShaderId; + + // In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id + if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; + else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) + { + // One of or both shader are new, a new shader program needs to be compiled + id = rlLoadShaderProgramEx(vertexShaderId, fragmentShaderId); + + // Detaching and deleting vertex/fragment shaders (if not default ones) + // WARNING: Detach shader before deletion to make sure memory is freed + if (vertexShaderId != RLGL.State.defaultVShaderId) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if (id > 0) glDetachShader(id, vertexShaderId); + glDeleteShader(vertexShaderId); + } + if (fragmentShaderId != RLGL.State.defaultFShaderId) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if (id > 0) glDetachShader(id, fragmentShaderId); + glDeleteShader(fragmentShaderId); + } + + // In case shader program loading failed, assign default shader + if (id == 0) + { + // In case shader loading fails, reassigning default shader + TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); + id = RLGL.State.defaultShaderId; + } + /* + else + { + // Get available shader uniforms + // NOTE: This information is useful for debug... + int uniformCount = -1; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); + + for (int i = 0; i < uniformCount; i++) + { + int namelen = -1; + int num = -1; + char name[256] = { 0 }; // Assume no variable names longer than 256 + GLenum type = GL_ZERO; + + // Get the name of the uniforms + glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); + + name[namelen] = 0; + TRACELOG(RL_LOG_DEBUG, "SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); + } + } + */ + } +#endif + + return id; +} + +// Load shader program from already loaded shader ids +unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId) { unsigned int programId = 0; if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; } @@ -4333,8 +4333,8 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) GLint success = 0; programId = glCreateProgram(); - glAttachShader(programId, vShaderId); - glAttachShader(programId, fShaderId); + glAttachShader(programId, vsId); + glAttachShader(programId, fsId); // Default attribute shader locations must be bound before linking // NOTE: There is no problem with binding a generic attribute index to an attribute variable name @@ -4388,14 +4388,57 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) return programId; } -// Unload shader program -void rlUnloadShaderProgram(unsigned int id) +// Load compute shader program +unsigned int rlLoadShaderProgramCompute(unsigned int csId) { -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteProgram(id); + unsigned int programId = 0; - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id); +#if defined(GRAPHICS_API_OPENGL_43) + GLint success = 0; + programId = glCreateProgram(); + + glAttachShader(programId, csId); + + glLinkProgram(programId); + + // NOTE: All uniform variables are intitialised to 0 when a program links + + glGetProgramiv(programId, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId); + + int maxLength = 0; + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); + RL_FREE(log); + } + + glDeleteProgram(programId); + + programId = 0; + } + else + { + // Get the size of compiled shader program (not available on OpenGL ES 2.0) + // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero + //GLint binarySize = 0; + //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId); + } +#else + TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not supported, enable GRAPHICS_API_OPENGL_43"); #endif + + return programId; } // Delete shader @@ -4408,13 +4451,23 @@ void rlUnloadShader(unsigned int id) #endif } +// Unload shader program +void rlUnloadShaderProgram(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteProgram(id); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id); +#endif +} + // Get shader location uniform // NOTE: First parameter refers to shader program id -int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) +int rlGetLocationUniform(unsigned int id, const char *uniformName) { int location = -1; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetUniformLocation(shaderId, uniformName); + location = glGetUniformLocation(id, uniformName); //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName); //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location); @@ -4424,11 +4477,11 @@ int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) // Get shader location attribute // NOTE: First parameter refers to shader program id -int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) +int rlGetLocationAttrib(unsigned int id, const char *attribName) { int location = -1; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetAttribLocation(shaderId, attribName); + location = glGetAttribLocation(id, attribName); //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName); //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location); @@ -4538,57 +4591,6 @@ void rlSetShader(unsigned int id, int *locs) #endif } -// Load compute shader program -unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) -{ - unsigned int programId = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - GLint success = 0; - programId = glCreateProgram(); - glAttachShader(programId, shaderId); - glLinkProgram(programId); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(programId, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId); - - int maxLength = 0; - glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(programId, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); - RL_FREE(log); - } - - glDeleteProgram(programId); - - programId = 0; - } - else - { - // Get the size of compiled shader program (not available on OpenGL ES 2.0) - // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero - //GLint binarySize = 0; - //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId); - } -#else - TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif - - return programId; -} - // Dispatch compute shader (equivalent to *draw* for graphics pilepine) void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ) { @@ -5081,10 +5083,10 @@ static void rlLoadShaderDefault(void) // NOTE: Compiled vertex/fragment shaders are not deleted, // they are kept for re-use as default shaders in case some shader loading fails - RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader - RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader + RLGL.State.defaultVShaderId = rlLoadShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader + RLGL.State.defaultFShaderId = rlLoadShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader - RLGL.State.defaultShaderId = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); + RLGL.State.defaultShaderId = rlLoadShaderProgramEx(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); if (RLGL.State.defaultShaderId > 0) {