소스 검색

shader: write a minimalist shader patcher for future GLSL 1.20 compatibility.

legacy
Sam Hocevar sam 13 년 전
부모
커밋
f5c4331d2e
1개의 변경된 파일108개의 추가작업 그리고 4개의 파일을 삭제
  1. +108
    -4
      src/shader.cpp

+ 108
- 4
src/shader.cpp 파일 보기

@@ -13,6 +13,8 @@
#endif

#include <cmath>
#include <cstring>
#include <cstdio>

#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
@@ -37,6 +39,10 @@ private:
GLuint prog_id, vert_id, frag_id;
uint32_t vert_crc, frag_crc;

/* Shader patcher */
static int GetVersion();
static void Patch(char *dst, char const *src);

/* Global shader cache */
static Shader *shaders[];
static int nshaders;
@@ -77,21 +83,26 @@ Shader::Shader(char const *vert, char const *frag)
: data(new ShaderData())
{
char buf[4096];
char const *shader = buf;
GLsizei len;

#if !defined __CELLOS_LV2__
data->vert_crc = Hash::Crc32(vert);

/* Compile vertex shader and fragment shader */
ShaderData::Patch(buf, vert);
data->vert_crc = Hash::Crc32(buf);
data->vert_id = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(data->vert_id, 1, &vert, NULL);
glShaderSource(data->vert_id, 1, &shader, NULL);
glCompileShader(data->vert_id);

glGetShaderInfoLog(data->vert_id, sizeof(buf), &len, buf);
if (len > 0)
Log::Error("failed to compile vertex shader: %s", buf);

data->frag_crc = Hash::Crc32(frag);
ShaderData::Patch(buf, frag);
data->frag_crc = Hash::Crc32(buf);
data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(data->frag_id, 1, &frag, NULL);
glShaderSource(data->frag_id, 1, &shader, NULL);
glCompileShader(data->frag_id);

glGetShaderInfoLog(data->frag_id, sizeof(buf), &len, buf);
@@ -148,5 +159,98 @@ Shader::~Shader()
#endif
}

/* Try to detect shader compiler features */
int ShaderData::GetVersion()
{
static int version = 0;

if (!version)
{
char buf[4096];
GLsizei len;

int id = glCreateShader(GL_VERTEX_SHADER);

/* Can we compile 1.30 shaders? */
char const *test130 =
"#version 130\n"
"void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
glShaderSource(id, 1, &test130, NULL);
glCompileShader(id);
glGetShaderInfoLog(id, sizeof(buf), &len, buf);
if (len <= 0)
version = 130;

/* If not, can we compile 1.20 shaders? */
if (!version)
{
char const *test120 =
"#version 120\n"
"void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
glShaderSource(id, 1, &test120, NULL);
glCompileShader(id);
glGetShaderInfoLog(id, sizeof(buf), &len, buf);
if (len <= 0)
version = 120;
}

/* Otherwise, assume we can compile 1.10 shaders. */
if (!version)
version = 110;

glDeleteShader(id);
}

return version;
}

/* Simple shader source patching for old GLSL versions.
* If supported version is 1.30, do nothing.
* If supported version is 1.20:
* - replace "#version 130" with "#version 120"
*/
void ShaderData::Patch(char *dst, char const *src)
{
int version = GetVersion();

if (version >= 130)
{
strcpy(dst, src);
return;
}

if (version == 120)
{
static char const * const replaces[] =
{
"#version 130", "#version 120",
"\nin vec2", "\nvec2",
"\nin vec3", "\nvec3",
"\nin vec4", "\nvec4",
"\nin mat4", "\nmat4",
NULL
};

while (*src)
{
for (char const * const *rep = replaces; rep[0]; rep += 2)
{
size_t l0 = strlen(rep[0]);
if (!strncmp(src, rep[0], l0))
{
src += l0;
dst += sprintf(dst, "%s", rep[1]);
goto next;
}
}

*dst++ = *src++;

next: continue;
}
*dst = '\0';
}
}

} /* namespace lol */


불러오는 중...
취소
저장