GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number, const int flags) { #ifdef WITH_OPENSUBDIV /* TODO(sergey): used to add #version 150 to the geometry shader. * Could safely be renamed to "use_geometry_code" since it's very * likely any of geometry code will want to use GLSL 1.5. */ bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; #else UNUSED_VARS(flags); bool use_opensubdiv = false; #endif GLint status; GLchar log[5000]; GLsizei length = 0; GPUShader *shader; char standard_defines[MAX_DEFINE_LENGTH] = ""; char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; if (geocode && !GPU_geometry_shader_support()) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE); if (vertexcode) shader->vertex = glCreateShader(GL_VERTEX_SHADER); if (fragcode) shader->fragment = glCreateShader(GL_FRAGMENT_SHADER); if (geocode) shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT); shader->program = glCreateProgram(); if (!shader->program || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment) || (geocode && !shader->geometry)) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); return NULL; } gpu_shader_standard_defines(standard_defines, use_opensubdiv, (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0); gpu_shader_standard_extensions(standard_extensions, geocode != NULL); if (vertexcode) { const char *source[5]; /* custom limit, may be too small, beware */ int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; source[num_source++] = vertexcode; gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX); glAttachShader(shader->program, shader->vertex); glShaderSource(shader->vertex, num_source, source, NULL); glCompileShader(shader->vertex); glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status); if (!status) { glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log); shader_print_errors("compile", log, source, num_source); GPU_shader_free(shader); return NULL; } } if (fragcode) { const char *source[7]; int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; #ifdef WITH_OPENSUBDIV /* TODO(sergey): Move to fragment shader source code generation. */ if (use_opensubdiv) { source[num_source++] = "#ifdef USE_OPENSUBDIV\n" "in block {\n" " VertexData v;\n" "} inpt;\n" "#endif\n"; } #endif if (defines) source[num_source++] = defines; if (libcode) source[num_source++] = libcode; source[num_source++] = fragcode; gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT); glAttachShader(shader->program, shader->fragment); glShaderSource(shader->fragment, num_source, source, NULL); glCompileShader(shader->fragment); glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status); if (!status) { glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log); shader_print_errors("compile", log, source, num_source); GPU_shader_free(shader); return NULL; } } if (geocode) { const char *source[6]; int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; source[num_source++] = geocode; gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY); glAttachShader(shader->program, shader->geometry); glShaderSource(shader->geometry, num_source, source, NULL); glCompileShader(shader->geometry); glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status); if (!status) { glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log); shader_print_errors("compile", log, source, num_source); GPU_shader_free(shader); return NULL; } if (!use_opensubdiv) { GPU_shader_geometry_stage_primitive_io(shader, input, output, number); } } #ifdef WITH_OPENSUBDIV if (use_opensubdiv) { glBindAttribLocation(shader->program, 0, "position"); glBindAttribLocation(shader->program, 1, "normal"); GPU_shader_geometry_stage_primitive_io(shader, GL_LINES_ADJACENCY_EXT, GL_TRIANGLE_STRIP, 4); } #endif glLinkProgram(shader->program); glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { glGetProgramInfoLog(shader->program, sizeof(log), &length, log); /* print attached shaders in pipeline order */ if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); if (geocode) shader_print_errors("linking", log, &geocode, 1); if (libcode) shader_print_errors("linking", log, &libcode, 1); if (fragcode) shader_print_errors("linking", log, &fragcode, 1); GPU_shader_free(shader); return NULL; } #ifdef WITH_OPENSUBDIV /* TODO(sergey): Find a better place for this. */ if (use_opensubdiv && GLEW_VERSION_4_1) { glProgramUniform1i(shader->program, glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"), 30); /* GL_TEXTURE30 */ glProgramUniform1i(shader->program, glGetUniformLocation(shader->program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ } #endif return shader; }
GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines) { GLint status; GLcharARB log[5000]; GLsizei length = 0; GPUShader *shader; char standard_defines[MAX_DEFINE_LENGTH] = ""; if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); if (vertexcode) shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if (fragcode) shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); shader->object = glCreateProgramObjectARB(); if (!shader->object || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment)) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); return NULL; } gpu_shader_standard_defines(standard_defines); if (vertexcode) { const char *source[5]; /* custom limit, may be too small, beware */ int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = gpu_shader_standard_extensions(); source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; if (vertexcode) source[num_source++] = vertexcode; glAttachObjectARB(shader->object, shader->vertex); glShaderSourceARB(shader->vertex, num_source, source, NULL); glCompileShaderARB(shader->vertex); glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->vertex, sizeof(log), &length, log); shader_print_errors("compile", log, vertexcode); GPU_shader_free(shader); return NULL; } } if (fragcode) { const char *source[6]; int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = gpu_shader_standard_extensions(); source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; if (libcode) source[num_source++] = libcode; if (fragcode) source[num_source++] = fragcode; glAttachObjectARB(shader->object, shader->fragment); glShaderSourceARB(shader->fragment, num_source, source, NULL); glCompileShaderARB(shader->fragment); glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->fragment, sizeof(log), &length, log); shader_print_errors("compile", log, fragcode); GPU_shader_free(shader); return NULL; } } #if 0 if (lib && lib->lib) glAttachObjectARB(shader->object, lib->lib); #endif glLinkProgramARB(shader->object); glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->object, sizeof(log), &length, log); if (fragcode) shader_print_errors("linking", log, fragcode); else if (vertexcode) shader_print_errors("linking", log, vertexcode); else if (libcode) shader_print_errors("linking", log, libcode); GPU_shader_free(shader); return NULL; } return shader; }