Merge branch 'master' into blender2.8
[blender.git] / source / blender / gpu / intern / gpu_codegen.c
index 9e4d0d5f82303bc97af77ea9c760371c0caa49be..9f41253b176e34ff08ab3a772cd9787cb067ce5e 100644 (file)
@@ -31,8 +31,6 @@
  * Convert material node-trees to GLSL.
  */
 
-#include "GPU_glew.h"
-
 #include "MEM_guardedalloc.h"
 
 #include "DNA_customdata_types.h"
 #include "BLI_dynstr.h"
 #include "BLI_ghash.h"
 
-#include "GPU_material.h"
 #include "GPU_extensions.h"
+#include "GPU_glew.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
 
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" /* for intptr_t support */
 
 #include "gpu_codegen.h"
 
@@ -57,7 +58,7 @@
 extern char datatoc_gpu_shader_material_glsl[];
 extern char datatoc_gpu_shader_vertex_glsl[];
 extern char datatoc_gpu_shader_vertex_world_glsl[];
-
+extern char datatoc_gpu_shader_geometry_glsl[];
 
 static char *glsl_material_library = NULL;
 
@@ -91,9 +92,11 @@ static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
 /* GLSL code parsing for finding function definitions.
  * These are stored in a hash for lookup when creating a material. */
 
-static GHash *FUNCTION_HASH= NULL;
-/* static char *FUNCTION_PROTOTYPES= NULL;
- * static GPUShader *FUNCTION_LIB= NULL;*/
+static GHash *FUNCTION_HASH = NULL;
+#if 0
+static char *FUNCTION_PROTOTYPES = NULL;
+static GPUShader *FUNCTION_LIB = NULL;
+#endif
 
 static int gpu_str_prefix(const char *str, const char *prefix)
 {
@@ -117,8 +120,8 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
                if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
                        break;
                else {
-                       if (token && len < max-1) {
-                               *token= *str;
+                       if (token && len < max - 1) {
+                               *token = *str;
                                token++;
                                len++;
                        }
@@ -127,7 +130,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
        }
 
        if (token)
-               *token= '\0';
+               *token = '\0';
 
        /* skip the next special characters:
         * note the missing ')' */
@@ -166,25 +169,30 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
                                code = gpu_str_skip_token(code, NULL, 0);
 
                        /* test for type */
-                       type= GPU_NONE;
-                       for (i=1; i<=16; i++) {
+                       type = GPU_NONE;
+                       for (i = 1; i <= 16; i++) {
                                if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
-                                       type= i;
+                                       type = i;
                                        break;
                                }
                        }
 
-                       if (!type && gpu_str_prefix(code, "sampler2DShadow"))
-                               type= GPU_SHADOW2D;
-                       if (!type && gpu_str_prefix(code, "sampler2D"))
-                               type= GPU_TEX2D;
+                       if (!type && gpu_str_prefix(code, "samplerCube")) {
+                               type = GPU_TEXCUBE;
+                       }
+                       if (!type && gpu_str_prefix(code, "sampler2DShadow")) {
+                               type = GPU_SHADOW2D;
+                       }
+                       if (!type && gpu_str_prefix(code, "sampler2D")) {
+                               type = GPU_TEX2D;
+                       }
 
                        if (type) {
                                /* add parameter */
                                code = gpu_str_skip_token(code, NULL, 0);
                                code = gpu_str_skip_token(code, NULL, 0);
-                               function->paramqual[function->totparam]= qual;
-                               function->paramtype[function->totparam]= type;
+                               function->paramqual[function->totparam] = qual;
+                               function->paramtype[function->totparam] = type;
                                function->totparam++;
                        }
                        else {
@@ -221,7 +229,7 @@ static char *gpu_generate_function_prototyps(GHash *hash)
                function = BLI_ghashIterator_getValue(ghi);
 
                BLI_dynstr_appendf(ds, "void %s(", name);
-               for (a=0; a<function->totparam; a++) {
+               for (a = 0; a < function->totparam; a++) {
                        if (function->paramqual[a] == FUNCTION_QUAL_OUT)
                                BLI_dynstr_append(ds, "out ");
                        else if (function->paramqual[a] == FUNCTION_QUAL_INOUT)
@@ -233,10 +241,11 @@ static char *gpu_generate_function_prototyps(GHash *hash)
                                BLI_dynstr_append(ds, "sampler2DShadow");
                        else
                                BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]);
-                               
-                       //BLI_dynstr_appendf(ds, " param%d", a);
-                       
-                       if (a != function->totparam-1)
+#  if 0
+                       BLI_dynstr_appendf(ds, " param%d", a);
+#  endif
+
+                       if (a != function->totparam - 1)
                                BLI_dynstr_append(ds, ", ");
                }
                BLI_dynstr_append(ds, ");\n");
@@ -268,7 +277,7 @@ void gpu_codegen_init(void)
 
 void gpu_codegen_exit(void)
 {
-       extern Material defmaterial;    // render module abuse...
+       extern Material defmaterial; /* render module abuse... */
 
        if (defmaterial.gpumaterial.first)
                GPU_material_free(&defmaterial.gpumaterial);
@@ -285,14 +294,16 @@ void gpu_codegen_exit(void)
                glsl_material_library = NULL;
        }
 
-       /*if (FUNCTION_PROTOTYPES) {
+#if 0
+       if (FUNCTION_PROTOTYPES) {
                MEM_freeN(FUNCTION_PROTOTYPES);
                FUNCTION_PROTOTYPES = NULL;
-       }*/
-       /*if (FUNCTION_LIB) {
+       }
+       if (FUNCTION_LIB) {
                GPU_shader_free(FUNCTION_LIB);
                FUNCTION_LIB = NULL;
-       }*/
+       }
+#endif
 }
 
 /* GLSL code generation */
@@ -308,17 +319,17 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
        }
        else if (to == GPU_FLOAT) {
                if (from == GPU_VEC4)
-                       BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name);
+                       BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name);
                else if (from == GPU_VEC3)
-                       BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name);
+                       BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
                else if (from == GPU_VEC2)
                        BLI_dynstr_appendf(ds, "%s.r", name);
        }
        else if (to == GPU_VEC2) {
                if (from == GPU_VEC4)
-                       BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name);
+                       BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name);
                else if (from == GPU_VEC3)
-                       BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name);
+                       BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name);
                else if (from == GPU_FLOAT)
                        BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
        }
@@ -346,9 +357,9 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
 
        BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
 
-       for (i=0; i<type; i++) {
+       for (i = 0; i < type; i++) {
                BLI_dynstr_appendf(ds, "%f", data[i]);
-               if (i == type-1)
+               if (i == type - 1)
                        BLI_dynstr_append(ds, ")");
                else
                        BLI_dynstr_append(ds, ", ");
@@ -375,6 +386,10 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
                return "unfinvviewmat";
        else if (builtin == GPU_INVERSE_OBJECT_MATRIX)
                return "unfinvobmat";
+       else if (builtin == GPU_LOC_TO_VIEW_MATRIX)
+               return "unflocaltoviewmat";
+       else if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX)
+               return "unfinvlocaltoviewmat";
        else if (builtin == GPU_VIEW_POSITION)
                return "varposition";
        else if (builtin == GPU_VIEW_NORMAL)
@@ -413,11 +428,11 @@ static void codegen_set_unique_ids(ListBase *nodes)
        GPUOutput *output;
        int id = 1, texid = 0;
 
-       bindhash= BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
-       definehash= BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
+       bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
+       definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
 
-       for (node=nodes->first; node; node=node->next) {
-               for (input=node->inputs.first; input; input=input->next) {
+       for (node = nodes->first; node; node = node->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        /* set id for unique names of uniform variables */
                        input->id = id++;
                        input->bindtex = false;
@@ -464,7 +479,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
                        }
                }
 
-               for (output=node->outputs.first; output; output=output->next)
+               for (output = node->outputs.first; output; output = output->next)
                        /* set id for unique names of tmp variables storing output */
                        output->id = id++;
        }
@@ -481,17 +496,19 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
        int builtins = 0;
 
        /* print uniforms */
-       for (node=nodes->first; node; node=node->next) {
-               for (input=node->inputs.first; input; input=input->next) {
+       for (node = nodes->first; node; node = node->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
                                /* create exactly one sampler for each texture */
-                               if (codegen_input_has_texture(input) && input->bindtex)
+                               if (codegen_input_has_texture(input) && input->bindtex) {
                                        BLI_dynstr_appendf(ds, "uniform %s samp%d;\n",
-                                               (input->textype == GPU_TEX2D) ? "sampler2D" : "sampler2DShadow",
+                                               (input->textype == GPU_TEX2D) ? "sampler2D" :
+                                               (input->textype == GPU_TEXCUBE) ? "samplerCube" : "sampler2DShadow",
                                                input->texid);
+                               }
                        }
                        else if (input->source == GPU_SOURCE_BUILTIN) {
-                               /* only define each builting uniform/varying once */
+                               /* only define each builtin uniform/varying once */
                                if (!(builtins & input->builtin)) {
                                        builtins |= input->builtin;
                                        name = GPU_builtin_name(input->builtin);
@@ -501,7 +518,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
                                                        GPU_DATATYPE_STR[input->type], name);
                                        }
                                        else {
-                                               BLI_dynstr_appendf(ds, "varying %s %s;\n",
+                                               BLI_dynstr_appendf(ds, "%s %s %s;\n",
+                                                       GLEW_VERSION_3_0 ? "in" : "varying",
                                                        GPU_DATATYPE_STR[input->type], name);
                                        }
                                }
@@ -521,8 +539,20 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
                                }
                        }
                        else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
-                               BLI_dynstr_appendf(ds, "varying %s var%d;\n",
+#ifdef WITH_OPENSUBDIV
+                               bool skip_opensubdiv = input->attribtype == CD_TANGENT;
+                               if (skip_opensubdiv) {
+                                       BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
+                               }
+#endif
+                               BLI_dynstr_appendf(ds, "%s %s var%d;\n",
+                                       GLEW_VERSION_3_0 ? "in" : "varying",
                                        GPU_DATATYPE_STR[input->type], input->attribid);
+#ifdef WITH_OPENSUBDIV
+                               if (skip_opensubdiv) {
+                                       BLI_dynstr_appendf(ds, "#endif\n");
+                               }
+#endif
                        }
                }
        }
@@ -538,22 +568,23 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
        GPUInput *input;
        GPUOutput *output;
 
-       for (node=nodes->first; node; node=node->next) {
+       for (node = nodes->first; node; node = node->next) {
                /* load pixels from textures */
-               for (input=node->inputs.first; input; input=input->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        if (input->source == GPU_SOURCE_TEX_PIXEL) {
                                if (codegen_input_has_texture(input) && input->definetex) {
                                        BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
                                        BLI_dynstr_appendf(ds, "samp%d, gl_TexCoord[%d].st);\n",
-                                               input->texid, input->texid);
+                                                          input->texid, input->texid);
                                }
                        }
                }
 
                /* declare temporary variables for node output storage */
-               for (output=node->outputs.first; output; output=output->next)
+               for (output = node->outputs.first; output; output = output->next) {
                        BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
-                               GPU_DATATYPE_STR[output->type], output->id);
+                                          GPU_DATATYPE_STR[output->type], output->id);
+               }
        }
 
        BLI_dynstr_append(ds, "\n");
@@ -565,10 +596,10 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
        GPUInput *input;
        GPUOutput *output;
 
-       for (node=nodes->first; node; node=node->next) {
+       for (node = nodes->first; node; node = node->next) {
                BLI_dynstr_appendf(ds, "\t%s(", node->name);
                
-               for (input=node->inputs.first; input; input=input->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        if (input->source == GPU_SOURCE_TEX) {
                                BLI_dynstr_appendf(ds, "samp%d", input->texid);
                                if (input->link)
@@ -603,7 +634,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
                        BLI_dynstr_append(ds, ", ");
                }
 
-               for (output=node->outputs.first; output; output=output->next) {
+               for (output = node->outputs.first; output; output = output->next) {
                        BLI_dynstr_appendf(ds, "tmp%d", output->id);
                        if (output->next)
                                BLI_dynstr_append(ds, ", ");
@@ -623,20 +654,57 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
        char *code;
        int builtins;
 
-       /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/
+#ifdef WITH_OPENSUBDIV
+       GPUNode *node;
+       GPUInput *input;
+#endif
+
+
+#if 0
+       BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
+#endif
 
        codegen_set_unique_ids(nodes);
        builtins = codegen_print_uniforms_functions(ds, nodes);
 
-       //if (G.debug & G_DEBUG)
-       //      BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#if 0
+       if (G.debug & G_DEBUG)
+               BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#endif
 
-       BLI_dynstr_append(ds, "void main(void)\n");
-       BLI_dynstr_append(ds, "{\n");
+       BLI_dynstr_append(ds, "void main()\n{\n");
 
        if (builtins & GPU_VIEW_NORMAL)
-               BLI_dynstr_append(ds, "\tvec3 facingnormal = (gl_FrontFacing)? varnormal: -varnormal;\n");
-       
+               BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n");
+
+       /* Calculate tangent space. */
+#ifdef WITH_OPENSUBDIV
+       {
+               bool has_tangent = false;
+               for (node = nodes->first; node; node = node->next) {
+                       for (input = node->inputs.first; input; input = input->next) {
+                               if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+                                       if (input->attribtype == CD_TANGENT) {
+                                               BLI_dynstr_appendf(ds, "#ifdef USE_OPENSUBDIV\n");
+                                               BLI_dynstr_appendf(ds, "\t%s var%d;\n",
+                                                                  GPU_DATATYPE_STR[input->type],
+                                                                  input->attribid);
+                                               if (has_tangent == false) {
+                                                       BLI_dynstr_appendf(ds, "\tvec3 Q1 = dFdx(inpt.v.position.xyz);\n");
+                                                       BLI_dynstr_appendf(ds, "\tvec3 Q2 = dFdy(inpt.v.position.xyz);\n");
+                                                       BLI_dynstr_appendf(ds, "\tvec2 st1 = dFdx(inpt.v.uv);\n");
+                                                       BLI_dynstr_appendf(ds, "\tvec2 st2 = dFdy(inpt.v.uv);\n");
+                                                       BLI_dynstr_appendf(ds, "\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n");
+                                               }
+                                               BLI_dynstr_appendf(ds, "\tvar%d = vec4(T, 1.0);\n", input->attribid);
+                                               BLI_dynstr_appendf(ds, "#endif\n");
+                                       }
+                               }
+                       }
+               }
+       }
+#endif
+
        codegen_declare_tmps(ds, nodes);
        codegen_call_functions(ds, nodes, output);
 
@@ -646,7 +714,9 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
        code = BLI_dynstr_get_cstring(ds);
        BLI_dynstr_free(ds);
 
-       //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+       if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
 
        return code;
 }
@@ -657,15 +727,29 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
        GPUNode *node;
        GPUInput *input;
        char *code;
-       char *vertcode;
+       char *vertcode = NULL;
        
-       for (node=nodes->first; node; node=node->next) {
-               for (input=node->inputs.first; input; input=input->next) {
+       for (node = nodes->first; node; node = node->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
-                               BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
+#ifdef WITH_OPENSUBDIV
+                               bool skip_opensubdiv = ELEM(input->attribtype, CD_MTFACE, CD_TANGENT);
+                               if (skip_opensubdiv) {
+                                       BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
+                               }
+#endif
+                               BLI_dynstr_appendf(ds, "%s %s att%d;\n",
+                                       GLEW_VERSION_3_0 ? "in" : "attribute",
                                        GPU_DATATYPE_STR[input->type], input->attribid);
-                               BLI_dynstr_appendf(ds, "varying %s var%d;\n",
+                               BLI_dynstr_appendf(ds, "uniform int att%d_info;\n",  input->attribid);
+                               BLI_dynstr_appendf(ds, "%s %s var%d;\n",
+                                       GLEW_VERSION_3_0 ? "out" : "varying",
                                        GPU_DATATYPE_STR[input->type], input->attribid);
+#ifdef WITH_OPENSUBDIV
+                               if (skip_opensubdiv) {
+                                       BLI_dynstr_appendf(ds, "#endif\n");
+                               }
+#endif
                        }
                }
        }
@@ -686,22 +770,45 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
 
        BLI_dynstr_append(ds, vertcode);
        
-       for (node=nodes->first; node; node=node->next)
-               for (input=node->inputs.first; input; input=input->next)
+       for (node = nodes->first; node; node = node->next)
+               for (input = node->inputs.first; input; input = input->next)
                        if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
                                if (input->attribtype == CD_TANGENT) { /* silly exception */
-                                       BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
-                                       BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid);
+#ifdef WITH_OPENSUBDIV
+                                       BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
+#endif
+                                       BLI_dynstr_appendf(
+                                               ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n",
+                                               input->attribid, input->attribid);
+                                       BLI_dynstr_appendf(
+                                               ds, "\tvar%d.w = att%d.w;\n",
+                                               input->attribid, input->attribid);
+#ifdef WITH_OPENSUBDIV
+                                       BLI_dynstr_appendf(ds, "#endif\n");
+#endif
+                               }
+                               else {
+#ifdef WITH_OPENSUBDIV
+                                       bool is_mtface = input->attribtype == CD_MTFACE;
+                                       if (is_mtface) {
+                                               BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
+                                       }
+#endif
+                                       BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
+                                                          input->attribid, input->attribid, input->attribid);
+#ifdef WITH_OPENSUBDIV
+                                       if (is_mtface) {
+                                               BLI_dynstr_appendf(ds, "#endif\n");
+                                       }
+#endif
                                }
-                               else
-                                       BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
                        }
                        /* unfortunately special handling is needed here because we abuse gl_Color/gl_SecondaryColor flat shading */
                        else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) {
                                if (input->oglbuiltin == GPU_MATCAP_NORMAL) {
                                        /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
                                         * between shader stages and we want the full range of the normal */
-                                       BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5, 0.5, 0.5) * varnormal + vec3(0.5, 0.5, 0.5);\n");
+                                       BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5) * varnormal + vec3(0.5);\n");
                                        BLI_dynstr_appendf(ds, "\tgl_FrontSecondaryColor = vec4(matcapcol, 1.0);\n");
                                }
                                else if (input->oglbuiltin == GPU_COLOR) {
@@ -709,20 +816,77 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
                                }
                        }
 
-       BLI_dynstr_append(ds, "}\n\n");
+       BLI_dynstr_append(ds, "}\n");
 
        code = BLI_dynstr_get_cstring(ds);
 
        BLI_dynstr_free(ds);
 
-       //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+       if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
 
        return code;
 }
 
-int GPU_bicubic_bump_support(void)
+static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
 {
-       return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
+#ifdef WITH_OPENSUBDIV
+       if (use_opensubdiv) {
+               DynStr *ds = BLI_dynstr_new();
+               GPUNode *node;
+               GPUInput *input;
+               char *code;
+
+               /* Generate varying declarations. */
+               for (node = nodes->first; node; node = node->next) {
+                       for (input = node->inputs.first; input; input = input->next) {
+                               if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+                                       if (input->attribtype == CD_MTFACE) {
+                                               BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
+                                                                  GLEW_VERSION_3_0 ? "in" : "varying",
+                                                                  GPU_DATATYPE_STR[input->type],
+                                                                  input->attribid,
+                                                                  GLEW_VERSION_3_0 ? "[]" : "");
+                                               BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
+                                                                  input->attribid);
+                                       }
+                               }
+                       }
+               }
+
+               BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
+
+               /* Generate varying assignments. */
+               /* TODO(sergey): Disabled for now, needs revisit. */
+#if 0
+               for (node = nodes->first; node; node = node->next) {
+                       for (input = node->inputs.first; input; input = input->next) {
+                               if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+                                       if (input->attribtype == CD_MTFACE) {
+                                               BLI_dynstr_appendf(ds,
+                                                                  "\tINTERP_FACE_VARYING_2(var%d, "
+                                                                      "fvar%d_offset, st);\n",
+                                                                  input->attribid,
+                                                                  input->attribid);
+                                       }
+                               }
+                       }
+               }
+#endif
+
+               BLI_dynstr_append(ds, "}\n");
+               code = BLI_dynstr_get_cstring(ds);
+               BLI_dynstr_free(ds);
+
+               //if (G.debug & G_DEBUG) printf("%s\n", code);
+
+               return code;
+       }
+#else
+       UNUSED_VARS(nodes, use_opensubdiv);
+#endif
+       return NULL;
 }
 
 void GPU_code_generate_glsl_lib(void)
@@ -766,15 +930,35 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
 
        GPU_shader_bind(shader);
 
-       for (node=nodes->first; node; node=node->next) {
+       for (node = nodes->first; node; node = node->next) {
                z = 0;
-               for (input=node->inputs.first; input; input=next, z++) {
+               for (input = node->inputs.first; input; input = next, z++) {
                        next = input->next;
 
                        /* attributes don't need to be bound, they already have
                         * an id that the drawing functions will use */
-                       if (input->source == GPU_SOURCE_ATTRIB ||
-                           input->source == GPU_SOURCE_BUILTIN ||
+                       if (input->source == GPU_SOURCE_ATTRIB) {
+#ifdef WITH_OPENSUBDIV
+                               /* We do need mtface attributes for later, so we can
+                                * update face-varuing variables offset in the texture
+                                * buffer for proper sampling from the shader.
+                                *
+                                * We don't do anything about attribute itself, we
+                                * only use it to learn which uniform name is to be
+                                * updated.
+                                *
+                                * TODO(sergey): We can add ad extra uniform input
+                                * for the offset, which will be purely internal and
+                                * which would avoid having such an exceptions.
+                                */
+                               if (input->attribtype != CD_MTFACE) {
+                                       continue;
+                               }
+#else
+                               continue;
+#endif
+                       }
+                       if (input->source == GPU_SOURCE_BUILTIN ||
                            input->source == GPU_SOURCE_OPENGL_BUILTIN)
                        {
                                continue;
@@ -798,6 +982,14 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
                        if (extract)
                                input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
 
+#ifdef WITH_OPENSUBDIV
+                       if (input->source == GPU_SOURCE_ATTRIB &&
+                           input->attribtype == CD_MTFACE)
+                       {
+                               extract = 1;
+                       }
+#endif
+
                        /* extract nodes */
                        if (extract) {
                                BLI_remlink(&node->inputs, input);
@@ -820,18 +1012,21 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
 
        GPU_shader_bind(shader);
 
-       /* now bind the textures */
-       for (input=inputs->first; input; input=input->next) {
+       /* create the textures */
+       for (input = inputs->first; input; input = input->next) {
                if (input->ima)
-                       input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap);
+                       input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->textarget, input->image_isdata, time, mipmap);
                else if (input->prv)
                        input->tex = GPU_texture_from_preview(input->prv, mipmap);
+       }
 
+       /* bind the textures, in second loop so texture binding during
+        * create doesn't overwrite already bound textures */
+       for (input = inputs->first; input; input = input->next) {
                if (input->tex && input->bindtex) {
                        GPU_texture_bind(input->tex, input->texid);
                        GPU_shader_uniform_texture(shader, input->shaderloc, input->tex);
                }
-                       
        }
 }
 
@@ -845,10 +1040,19 @@ void GPU_pass_update_uniforms(GPUPass *pass)
                return;
 
        /* pass dynamic inputs to opengl, others were removed */
-       for (input=inputs->first; input; input=input->next)
-               if (!(input->ima || input->tex || input->prv))
-                       GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
-                               input->dynamicvec);
+       for (input = inputs->first; input; input = input->next) {
+               if (!(input->ima || input->tex || input->prv)) {
+                       if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) {
+                               // The hardness is actually a short pointer, so we convert it here
+                               float val = (float)(*(short *)input->dynamicvec);
+                               GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val);
+                       }
+                       else {
+                               GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
+                                       input->dynamicvec);
+                       }
+               }
+       }
 }
 
 void GPU_pass_unbind(GPUPass *pass)
@@ -860,7 +1064,7 @@ void GPU_pass_unbind(GPUPass *pass)
        if (!shader)
                return;
 
-       for (input=inputs->first; input; input=input->next) {
+       for (input = inputs->first; input; input = input->next) {
                if (input->tex && input->bindtex)
                        GPU_texture_unbind(input->tex);
 
@@ -902,7 +1106,7 @@ static GPUNode *GPU_node_begin(const char *name)
 {
        GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode");
 
-       node->name= name;
+       node->name = name;
 
        return node;
 }
@@ -916,8 +1120,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
        if (link->output) {
                outnode = link->output->node;
                name = outnode->name;
+               input = outnode->inputs.first;
 
-               if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
+               if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) &&
+                   (input->type == type))
+               {
                        input = MEM_dupallocN(outnode->inputs.first);
                        input->type = type;
                        if (input->link)
@@ -971,7 +1178,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
                input->source = GPU_SOURCE_TEX;
                input->textype = type;
 
-               //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#if 0
+               input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#endif
                input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
                input->textarget = GL_TEXTURE_2D;
 
@@ -983,15 +1192,25 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
                input->type = GPU_VEC4;
                input->source = GPU_SOURCE_TEX;
 
-               if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW)
+               if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW) {
                        input->prv = link->ptr1;
-               else {
+                       input->textarget = GL_TEXTURE_2D;
+                       input->textype = GPU_TEX2D;
+               }
+               else if (link->image == GPU_NODE_LINK_IMAGE_BLENDER) {
                        input->ima = link->ptr1;
                        input->iuser = link->ptr2;
                        input->image_isdata = link->image_isdata;
+                       input->textarget = GL_TEXTURE_2D;
+                       input->textype = GPU_TEX2D;
+               }
+               else if (link->image == GPU_NODE_LINK_IMAGE_CUBE_MAP) {
+                       input->ima = link->ptr1;
+                       input->iuser = link->ptr2;
+                       input->image_isdata = link->image_isdata;
+                       input->textarget = GL_TEXTURE_CUBE_MAP;
+                       input->textype = GPU_TEXCUBE;
                }
-               input->textarget = GL_TEXTURE_2D;
-               input->textype = GPU_TEX2D;
                MEM_freeN(link);
        }
        else if (link->attribtype) {
@@ -1008,11 +1227,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
                input->type = type;
                input->source = GPU_SOURCE_VEC_UNIFORM;
 
-               memcpy(input->vec, link->ptr1, type*sizeof(float));
+               memcpy(input->vec, link->ptr1, type * sizeof(float));
                if (link->dynamic) {
-                       input->dynamicvec= link->ptr1;
-                       input->dynamictype= link->dynamictype;
-                       input->dynamicdata= link->ptr2;
+                       input->dynamicvec = link->ptr1;
+                       input->dynamictype = link->dynamictype;
+                       input->dynamicdata = link->ptr2;
                }
                MEM_freeN(link);
        }
@@ -1046,7 +1265,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
                output->link->type = type;
                output->link->output = output;
 
-               /* note: the caller owns the reference to the linkfer, GPUOutput
+               /* note: the caller owns the reference to the link, GPUOutput
                 * merely points to it, and if the node is destroyed it will
                 * set that pointer to NULL */
        }
@@ -1058,7 +1277,7 @@ static void gpu_inputs_free(ListBase *inputs)
 {
        GPUInput *input;
 
-       for (input=inputs->first; input; input=input->next) {
+       for (input = inputs->first; input; input = input->next) {
                if (input->link)
                        gpu_node_link_free(input->link);
                else if (input->tex && !input->dynamictex)
@@ -1074,7 +1293,7 @@ static void gpu_node_free(GPUNode *node)
 
        gpu_inputs_free(&node->inputs);
 
-       for (output=node->outputs.first; output; output=output->next)
+       for (output = node->outputs.first; output; output = output->next)
                if (output->link) {
                        output->link->output = NULL;
                        gpu_node_link_free(output->link);
@@ -1106,10 +1325,10 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
 
        memset(attribs, 0, sizeof(*attribs));
 
-       for (node=nodes->first; node; node=node->next) {
-               for (input=node->inputs.first; input; input=input->next) {
+       for (node = nodes->first; node; node = node->next) {
+               for (input = node->inputs.first; input; input = input->next) {
                        if (input->source == GPU_SOURCE_ATTRIB) {
-                               for (a=0; a<attribs->totlayer; a++) {
+                               for (a = 0; a < attribs->totlayer; a++) {
                                        if (attribs->layer[a].type == input->attribtype &&
                                            STREQ(attribs->layer[a].name, input->attribname))
                                        {
@@ -1141,10 +1360,10 @@ static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
        GPUNode *node;
        GPUInput *input;
        
-       *builtin= 0;
+       *builtin = 0;
 
-       for (node=nodes->first; node; node=node->next)
-               for (input=node->inputs.first; input; input=input->next)
+       for (node = nodes->first; node; node = node->next)
+               for (input = node->inputs.first; input; input = input->next)
                        if (input->source == GPU_SOURCE_BUILTIN)
                                *builtin |= input->builtin;
 }
@@ -1155,8 +1374,8 @@ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
 {
        GPUNodeLink *link = GPU_node_link_create();
 
-       link->attribtype= type;
-       link->attribname= name;
+       link->attribtype = type;
+       link->attribname = name;
 
        return link;
 }
@@ -1165,8 +1384,8 @@ GPUNodeLink *GPU_uniform(float *num)
 {
        GPUNodeLink *link = GPU_node_link_create();
 
-       link->ptr1= num;
-       link->ptr2= NULL;
+       link->ptr1 = num;
+       link->ptr2 = NULL;
 
        return link;
 }
@@ -1175,9 +1394,9 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d
 {
        GPUNodeLink *link = GPU_node_link_create();
 
-       link->ptr1= num;
-       link->ptr2= data;
-       link->dynamic= true;
+       link->ptr1 = num;
+       link->ptr2 = data;
+       link->dynamic = true;
        link->dynamictype = dynamictype;
 
 
@@ -1196,12 +1415,24 @@ GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
        return link;
 }
 
+GPUNodeLink *GPU_cube_map(Image *ima, ImageUser *iuser, bool is_data)
+{
+       GPUNodeLink *link = GPU_node_link_create();
+
+       link->image = GPU_NODE_LINK_IMAGE_CUBE_MAP;
+       link->ptr1 = ima;
+       link->ptr2 = iuser;
+       link->image_isdata = is_data;
+
+       return link;
+}
+
 GPUNodeLink *GPU_image_preview(PreviewImage *prv)
 {
        GPUNodeLink *link = GPU_node_link_create();
        
-       link->image= GPU_NODE_LINK_IMAGE_PREVIEW;
-       link->ptr1= prv;
+       link->image = GPU_NODE_LINK_IMAGE_PREVIEW;
+       link->ptr1 = prv;
        
        return link;
 }
@@ -1213,7 +1444,7 @@ GPUNodeLink *GPU_texture(int size, float *pixels)
 
        link->texture = true;
        link->texturesize = size;
-       link->ptr1= pixels;
+       link->ptr1 = pixels;
 
        return link;
 }
@@ -1234,7 +1465,7 @@ GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
 {
        GPUNodeLink *link = GPU_node_link_create();
 
-       link->builtin= builtin;
+       link->builtin = builtin;
 
        return link;
 }
@@ -1259,19 +1490,19 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
        function = gpu_lookup_function(name);
        if (!function) {
                fprintf(stderr, "GPU failed to find function %s\n", name);
-               return 0;
+               return false;
        }
 
        node = GPU_node_begin(name);
 
        va_start(params, name);
-       for (i=0; i<function->totparam; i++) {
+       for (i = 0; i < function->totparam; i++) {
                if (function->paramqual[i] != FUNCTION_QUAL_IN) {
-                       linkptr= va_arg(params, GPUNodeLink**);
+                       linkptr = va_arg(params, GPUNodeLink **);
                        gpu_node_output(node, function->paramtype[i], linkptr);
                }
                else {
-                       link= va_arg(params, GPUNodeLink*);
+                       link = va_arg(params, GPUNodeLink *);
                        gpu_node_input_link(node, link, function->paramtype[i]);
                }
        }
@@ -1279,7 +1510,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
 
        gpu_material_add_node(mat, node);
 
-       return 1;
+       return true;
 }
 
 bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...)
@@ -1293,7 +1524,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
        function = gpu_lookup_function(name);
        if (!function) {
                fprintf(stderr, "GPU failed to find function %s\n", name);
-               return 0;
+               return false;
        }
 
        node = GPU_node_begin(name);
@@ -1315,10 +1546,10 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
        }
 
        va_start(params, out);
-       for (i=0; i<function->totparam; i++) {
+       for (i = 0; i < function->totparam; i++) {
                if (function->paramqual[i] != FUNCTION_QUAL_IN) {
                        if (totout == 0) {
-                               linkptr= va_arg(params, GPUNodeLink**);
+                               linkptr = va_arg(params, GPUNodeLink **);
                                gpu_node_output(node, function->paramtype[i], linkptr);
                        }
                        else
@@ -1326,7 +1557,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
                }
                else {
                        if (totin == 0) {
-                               link= va_arg(params, GPUNodeLink*);
+                               link = va_arg(params, GPUNodeLink *);
                                if (link->socket)
                                        gpu_node_input_socket(node, link->socket);
                                else
@@ -1340,7 +1571,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
 
        gpu_material_add_node(mat, node);
        
-       return 1;
+       return true;
 }
 
 int GPU_link_changed(GPUNodeLink *link)
@@ -1379,7 +1610,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
                return;
        
        node->tag = true;
-       for (input=node->inputs.first; input; input=input->next)
+       for (input = node->inputs.first; input; input = input->next)
                if (input->link)
                        gpu_nodes_tag(input->link);
 }
@@ -1388,12 +1619,12 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
 {
        GPUNode *node, *next;
 
-       for (node=nodes->first; node; node=node->next)
+       for (node = nodes->first; node; node = node->next)
                node->tag = false;
 
        gpu_nodes_tag(outlink);
 
-       for (node=nodes->first; node; node=next) {
+       for (node = nodes->first; node; node = next) {
                next = node->next;
 
                if (!node->tag) {
@@ -1403,18 +1634,23 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
        }
 }
 
-GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
-                                                  GPUVertexAttribs *attribs, int *builtins,
-                                                  const GPUMatType type, const char *UNUSED(name))
+GPUPass *GPU_generate_pass(
+        ListBase *nodes, GPUNodeLink *outlink,
+        GPUVertexAttribs *attribs, int *builtins,
+        const GPUMatType type, const char *UNUSED(name),
+        const bool use_opensubdiv,
+        const bool use_new_shading)
 {
        GPUShader *shader;
        GPUPass *pass;
-       char *vertexcode, *fragmentcode;
+       char *vertexcode, *geometrycode, *fragmentcode;
 
-       /*if (!FUNCTION_LIB) {
+#if 0
+       if (!FUNCTION_LIB) {
                GPU_nodes_free(nodes);
                return NULL;
-       }*/
+       }
+#endif
 
        /* prune unused nodes */
        gpu_nodes_prune(nodes, outlink);
@@ -1425,7 +1661,24 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
        /* generate code and compile with opengl */
        fragmentcode = code_generate_fragment(nodes, outlink->output);
        vertexcode = code_generate_vertex(nodes, type);
-       shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
+       geometrycode = code_generate_geometry(nodes, use_opensubdiv);
+
+       int flags = GPU_SHADER_FLAGS_NONE;
+       if (use_opensubdiv) {
+               flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV;
+       }
+       if (use_new_shading) {
+               flags |= GPU_SHADER_FLAGS_NEW_SHADING;
+       }
+       shader = GPU_shader_create_ex(vertexcode,
+                                     fragmentcode,
+                                     geometrycode,
+                                     glsl_material_library,
+                                     NULL,
+                                     0,
+                                     0,
+                                     0,
+                                     flags);
 
        /* failed? */
        if (!shader) {
@@ -1445,6 +1698,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
        pass->output = outlink->output;
        pass->shader = shader;
        pass->fragmentcode = fragmentcode;
+       pass->geometrycode = geometrycode;
        pass->vertexcode = vertexcode;
        pass->libcode = glsl_material_library;
 
@@ -1461,8 +1715,9 @@ void GPU_pass_free(GPUPass *pass)
        gpu_inputs_free(&pass->inputs);
        if (pass->fragmentcode)
                MEM_freeN(pass->fragmentcode);
+       if (pass->geometrycode)
+               MEM_freeN(pass->geometrycode);
        if (pass->vertexcode)
                MEM_freeN(pass->vertexcode);
        MEM_freeN(pass);
 }
-