Move shader/program creation into video_util module

This commit is contained in:
Aaron Culliney 2016-01-02 10:53:28 -08:00
parent b59672815f
commit 7ca679350d
5 changed files with 246 additions and 241 deletions

View File

@ -260,228 +260,6 @@ static GLuint _create_CRT_texture(void) {
return texName;
}
static GLuint _build_program(demoSource *vertexSource, demoSource *fragmentSource, bool hasNormal, bool hasTexcoord) {
GLuint prgName;
GLint logLength, status;
// String to pass to glShaderSource
GLchar *sourceString = NULL;
// Determine if GLSL version 140 is supported by this context.
// We'll use this info to generate a GLSL shader source string
// with the proper version preprocessor string prepended
float glLanguageVersion = 0.f;
char *shaderLangVersion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
if (shaderLangVersion == NULL) {
ERRQUIT("shader toolchain unavailable");
}
#if TARGET_OS_IPHONE
sscanf(shaderLangVersion, "OpenGL ES GLSL ES %f", &glLanguageVersion);
#else
sscanf(shaderLangVersion, "%f", &glLanguageVersion);
#endif
// GL_SHADING_LANGUAGE_VERSION returns the version standard version form
// with decimals, but the GLSL version preprocessor directive simply
// uses integers (thus 1.10 should 110 and 1.40 should be 140, etc.)
// We multiply the floating point number by 100 to get a proper
// number for the GLSL preprocessor directive
GLuint version = 100 * glLanguageVersion;
// Get the size of the version preprocessor string info so we know
// how much memory to allocate for our sourceString
const GLsizei versionStringSize = sizeof("#version 123\n");
// Create a program object
prgName = glCreateProgram();
// Indicate the attribute indicies on which vertex arrays will be
// set with glVertexAttribPointer
// See buildVAO to see where vertex arrays are actually set
glBindAttribLocation(prgName, POS_ATTRIB_IDX, "inPosition");
if (hasNormal) {
glBindAttribLocation(prgName, NORMAL_ATTRIB_IDX, "inNormal");
}
if (hasTexcoord) {
glBindAttribLocation(prgName, TEXCOORD_ATTRIB_IDX, "inTexcoord");
}
//////////////////////////////////////
// Specify and compile VertexShader //
//////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = MALLOC(vertexSource->byteSize + versionStringSize);
// Prepend our vertex shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
if (version) {
sprintf(sourceString, "#version %d\n%s", version, vertexSource->string);
} else {
RELEASE_LOG("No GLSL version specified ... so NOT adding a #version directive to shader sources =P");
sprintf(sourceString, "%s", vertexSource->string);
}
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, (const GLchar **)&(sourceString), NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)MALLOC(logLength);
glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
LOG("Vtx Shader compile log:%s\n", log);
FREE(log);
}
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if (status == 0) {
LOG("Failed to compile vtx shader:\n%s\n", sourceString);
return 0;
}
FREE(sourceString);
// Attach the vertex shader to our program
glAttachShader(prgName, vertexShader);
/////////////////////////////////////////
// Specify and compile Fragment Shader //
/////////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = MALLOC(fragmentSource->byteSize + versionStringSize);
// Prepend our fragment shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
if (version) {
sprintf(sourceString, "#version %d\n%s", version, fragmentSource->string);
} else {
sprintf(sourceString, "%s", fragmentSource->string);
}
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, (const GLchar **)&(sourceString), NULL);
glCompileShader(fragShader);
glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)MALLOC(logLength);
glGetShaderInfoLog(fragShader, logLength, &logLength, log);
LOG("Frag Shader compile log:\n%s\n", log);
FREE(log);
}
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &status);
if (status == 0) {
LOG("Failed to compile frag shader:\n%s\n", sourceString);
return 0;
}
FREE(sourceString);
// Attach the fragment shader to our program
glAttachShader(prgName, fragShader);
//////////////////////
// Link the program //
//////////////////////
glLinkProgram(prgName);
glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)MALLOC(logLength);
glGetProgramInfoLog(prgName, logLength, &logLength, log);
LOG("Program link log:\n%s\n", log);
FREE(log);
}
glGetProgramiv(prgName, GL_LINK_STATUS, &status);
if (status == 0) {
LOG("Failed to link program");
return 0;
}
glValidateProgram(prgName);
glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)MALLOC(logLength);
glGetProgramInfoLog(prgName, logLength, &logLength, log);
LOG("Program validate log:\n%s\n", log);
FREE(log);
}
glGetProgramiv(prgName, GL_VALIDATE_STATUS, &status);
if (status == 0) {
LOG("Failed to validate program");
return 0;
}
glUseProgram(prgName);
///////////////////////////////////////
// Setup common program input points //
///////////////////////////////////////
texSamplerLoc = glGetUniformLocation(prgName, "aTexture");
if (texSamplerLoc < 0) {
LOG("OOPS, no framebufferTexture shader : %d", texSamplerLoc);
} else {
glUniform1i(texSamplerLoc, TEXTURE_ID_FRAMEBUFFER);
}
GLint maxTextureUnits = -1;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < TEXTURE_ID_MAX) {
#warning FIXME TODO ... gracefully handle devices with low max texture units?
ERRLOG("OOPS ... MAX TEXTURE UNITS : %d (<%d)", maxTextureUnits, TEXTURE_ID_MAX);
} else {
LOG("GL_MAX_TEXTURE_IMAGE_UNITS : %d", maxTextureUnits);
}
uniformMVPIdx = glGetUniformLocation(prgName, "modelViewProjectionMatrix");
if (uniformMVPIdx < 0) {
LOG("OOPS, no modelViewProjectionMatrix in shader : %d", uniformMVPIdx);
}
alphaValue = glGetUniformLocation(prgName, "aValue");
if (alphaValue < 0) {
LOG("OOPS, no texture selector in shader : %d", alphaValue);
}
GL_ERRLOG("build program");
return prgName;
}
static demoSource *_create_shader_source(const char *fileName) {
demoSource *src = NULL;
#if defined(__APPLE__)
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding());
CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL);
CFRELEASE(fileString);
CFStringRef filePath = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle);
CFRELEASE(fileURL);
src = srcLoadSource(CFStringGetCStringPtr(filePath, CFStringGetSystemEncoding()));
CFRELEASE(filePath);
#else
char *filePath = NULL;
asprintf(&filePath, "%s/shaders/%s", data_dir, fileName);
if (filePath) {
src = srcLoadSource(filePath);
ASPRINTF_FREE(filePath);
} else {
ERRLOG("OOPS Could not load shader from %s (%s)", filePath, fileName);
}
#endif
return src;
}
static void gldriver_render(void);
static void _gldriver_setup_hackarounds(void) {
@ -619,14 +397,52 @@ static void gldriver_init_common(void) {
// ----------------------------
// Load/setup shaders
demoSource *vtxSource = _create_shader_source("Basic.vsh");
demoSource *frgSource = _create_shader_source("Basic.fsh");
demoSource *vtxSource = glshader_createSource("Basic.vsh");
demoSource *frgSource = glshader_createSource("Basic.fsh");
assert(vtxSource && "Catastrophic failure if vertex shader did not compile");
assert(frgSource && "Catastrophic failure if fragment shader did not compile");
// Build/use Program
mainShaderProgram = _build_program(vtxSource, frgSource, /*withNormal:*/false, /*withTexcoord:*/true);
mainShaderProgram = glshader_buildProgram(vtxSource, frgSource, /*withNormal:*/false, /*withTexcoord:*/true, &vertexShader, &fragShader);
srcDestroySource(vtxSource);
srcDestroySource(frgSource);
glshader_destroySource(vtxSource);
glshader_destroySource(frgSource);
///////////////////////////////////////
// Setup common program input points //
///////////////////////////////////////
glUseProgram(mainShaderProgram);
texSamplerLoc = glGetUniformLocation(mainShaderProgram, "aTexture");
if (texSamplerLoc < 0) {
LOG("OOPS, no framebufferTexture shader : %d", texSamplerLoc);
} else {
glUniform1i(texSamplerLoc, TEXTURE_ID_FRAMEBUFFER);
}
GLint maxTextureUnits = -1;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < TEXTURE_ID_MAX) {
#warning FIXME TODO ... gracefully handle devices with low max texture units?
ERRLOG("OOPS ... MAX TEXTURE UNITS : %d (<%d)", maxTextureUnits, TEXTURE_ID_MAX);
} else {
LOG("GL_MAX_TEXTURE_IMAGE_UNITS : %d", maxTextureUnits);
}
uniformMVPIdx = glGetUniformLocation(mainShaderProgram, "modelViewProjectionMatrix");
if (uniformMVPIdx < 0) {
LOG("OOPS, no modelViewProjectionMatrix in shader : %d", uniformMVPIdx);
}
alphaValue = glGetUniformLocation(mainShaderProgram, "aValue");
if (alphaValue < 0) {
LOG("OOPS, no texture selector in shader : %d", alphaValue);
}
GL_ERRLOG("build program");
// ----------------------------
// setup static OpenGL state

View File

@ -14,6 +14,8 @@
#ifndef __GL_UTIL_H__
#define __GL_UTIL_H__
#define UNINITIALIZED_GL (-31337) // HACK FIXME TODO : is there an official OpenGL value we can use to signify an uninitialized state? (cannot depend on zero)
#if defined(__APPLE__)
# define USE_VAO 1
# import <CoreFoundation/CoreFoundation.h>
@ -42,7 +44,7 @@
#endif
#if !defined(USE_VAO)
#define USE_VAO 1
# define USE_VAO 1
#endif
// Global unified texture format constants ...
@ -112,3 +114,4 @@ static inline const char * GetGLErrorString(GLenum error) {
}
#endif // __GL_UTIL_H__

View File

@ -16,9 +16,6 @@
#include "common.h"
#define UNINITIALIZED_GL (-31337)
#warning FIXME TODO : is there an official OpenGL value we can use to signify an uninitialized state?
enum {
POS_ATTRIB_IDX,
TEXCOORD_ATTRIB_IDX,

View File

@ -12,13 +12,9 @@
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
#include "sourceUtil.h"
#include "common.h"
#include "modelUtil.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
demoSource *srcLoadSource(const char *filepathname) {
static demoSource *srcLoadSource(const char *filepathname) {
demoSource *source = (demoSource *)CALLOC(sizeof(demoSource), 1);
// Check the file name suffix to determine what type of shader this is
@ -57,8 +53,196 @@ demoSource *srcLoadSource(const char *filepathname) {
return source;
}
void srcDestroySource(demoSource *source) {
demoSource *glshader_createSource(const char *fileName) {
demoSource *src = NULL;
#if defined(__APPLE__)
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding());
CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL);
CFRELEASE(fileString);
CFStringRef filePath = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle);
CFRELEASE(fileURL);
src = srcLoadSource(CFStringGetCStringPtr(filePath, CFStringGetSystemEncoding()));
CFRELEASE(filePath);
#else
char *filePath = NULL;
asprintf(&filePath, "%s/shaders/%s", data_dir, fileName);
if (filePath) {
src = srcLoadSource(filePath);
ASPRINTF_FREE(filePath);
} else {
ERRLOG("OOPS Could not load shader from %s (%s)", filePath, fileName);
}
#endif
return src;
}
void glshader_destroySource(demoSource *source) {
FREE(source->string);
FREE(source);
}
GLuint glshader_buildProgram(demoSource *vertexSource, demoSource *fragmentSource, bool hasNormal, bool hasTexcoord, OUTPARM GLuint *vertexShader, OUTPARM GLuint *fragShader) {
GLuint prgName = UNINITIALIZED_GL;
GLint logLength = UNINITIALIZED_GL;
GLint status = UNINITIALIZED_GL;
// String to pass to glShaderSource
GLchar *sourceString = NULL;
// Determine if GLSL version 140 is supported by this context.
// We'll use this info to generate a GLSL shader source string
// with the proper version preprocessor string prepended
float glLanguageVersion = 0.f;
char *shaderLangVersion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
if (shaderLangVersion == NULL) {
ERRQUIT("shader toolchain unavailable");
}
#if TARGET_OS_IPHONE
sscanf(shaderLangVersion, "OpenGL ES GLSL ES %f", &glLanguageVersion);
#else
sscanf(shaderLangVersion, "%f", &glLanguageVersion);
#endif
// GL_SHADING_LANGUAGE_VERSION returns the version standard version form
// with decimals, but the GLSL version preprocessor directive simply
// uses integers (thus 1.10 should 110 and 1.40 should be 140, etc.)
// We multiply the floating point number by 100 to get a proper
// number for the GLSL preprocessor directive
GLuint version = 100 * glLanguageVersion;
// Get the size of the version preprocessor string info so we know
// how much memory to allocate for our sourceString
const GLsizei versionStringSize = sizeof("#version 123\n");
// Create a program object
prgName = glCreateProgram();
// Indicate the attribute indicies on which vertex arrays will be
// set with glVertexAttribPointer
// See buildVAO to see where vertex arrays are actually set
glBindAttribLocation(prgName, POS_ATTRIB_IDX, "inPosition");
if (hasNormal) {
glBindAttribLocation(prgName, NORMAL_ATTRIB_IDX, "inNormal");
}
if (hasTexcoord) {
glBindAttribLocation(prgName, TEXCOORD_ATTRIB_IDX, "inTexcoord");
}
//////////////////////////////////////
// Specify and compile VertexShader //
//////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = MALLOC(vertexSource->byteSize + versionStringSize);
// Prepend our vertex shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
if (version) {
sprintf(sourceString, "#version %d\n%s", version, vertexSource->string);
} else {
RELEASE_LOG("No GLSL version specified ... so NOT adding a #version directive to shader sources =P");
sprintf(sourceString, "%s", vertexSource->string);
}
*vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(*vertexShader, 1, (const GLchar **)&(sourceString), NULL);
glCompileShader(*vertexShader);
glGetShaderiv(*vertexShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)MALLOC(logLength);
glGetShaderInfoLog(*vertexShader, logLength, &logLength, log);
LOG("Vtx Shader compile log:%s\n", log);
FREE(log);
}
glGetShaderiv(*vertexShader, GL_COMPILE_STATUS, &status);
if (status == 0) {
LOG("Failed to compile vtx shader:\n%s\n", sourceString);
return 0;
}
FREE(sourceString);
// Attach the vertex shader to our program
glAttachShader(prgName, *vertexShader);
/////////////////////////////////////////
// Specify and compile Fragment Shader //
/////////////////////////////////////////
// Allocate memory for the source string including the version preprocessor information
sourceString = MALLOC(fragmentSource->byteSize + versionStringSize);
// Prepend our fragment shader source string with the supported GLSL version so
// the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts
if (version) {
sprintf(sourceString, "#version %d\n%s", version, fragmentSource->string);
} else {
sprintf(sourceString, "%s", fragmentSource->string);
}
*fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(*fragShader, 1, (const GLchar **)&(sourceString), NULL);
glCompileShader(*fragShader);
glGetShaderiv(*fragShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)MALLOC(logLength);
glGetShaderInfoLog(*fragShader, logLength, &logLength, log);
LOG("Frag Shader compile log:\n%s\n", log);
FREE(log);
}
glGetShaderiv(*fragShader, GL_COMPILE_STATUS, &status);
if (status == 0) {
LOG("Failed to compile frag shader:\n%s\n", sourceString);
return 0;
}
FREE(sourceString);
// Attach the fragment shader to our program
glAttachShader(prgName, *fragShader);
//////////////////////
// Link the program //
//////////////////////
glLinkProgram(prgName);
glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)MALLOC(logLength);
glGetProgramInfoLog(prgName, logLength, &logLength, log);
LOG("Program link log:\n%s\n", log);
FREE(log);
}
glGetProgramiv(prgName, GL_LINK_STATUS, &status);
if (status == 0) {
LOG("Failed to link program");
return 0;
}
glValidateProgram(prgName);
glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)MALLOC(logLength);
glGetProgramInfoLog(prgName, logLength, &logLength, log);
LOG("Program validate log:\n%s\n", log);
FREE(log);
}
glGetProgramiv(prgName, GL_VALIDATE_STATUS, &status);
if (status == 0) {
LOG("Failed to validate program");
return 0;
}
GL_ERRLOG("build program");
return prgName;
}

View File

@ -14,7 +14,7 @@
#ifndef __SOURCE_UTIL_H__
#define __SOURCE_UTIL_H__
#include "glUtil.h"
#include "common.h"
typedef struct demoSourceRec {
GLchar *string;
@ -22,8 +22,13 @@ typedef struct demoSourceRec {
GLenum shaderType; // Vertex or Fragment
} demoSource;
demoSource *srcLoadSource(const char *filepathname);
// Create a shader source object from a shader source file
extern demoSource *glshader_createSource(const char *filepathname);
void srcDestroySource(demoSource *source);
// Destroy a shader source object
extern void glshader_destroySource(demoSource *source);
// Builds a GL program from shader sources
extern GLuint glshader_buildProgram(demoSource *vertexSource, demoSource *fragmentSource, bool hasNormal, bool hasTexcoord, OUTPARM GLuint *vertexShader, OUTPARM GLuint *fragShader);
#endif // __SOURCE_UTIL_H__