Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles')
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/kernel_types.h17
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp41
-rw-r--r--intern/cycles/kernel/svm/svm.h7
-rw-r--r--intern/cycles/kernel/svm/svm_bump.h54
-rw-r--r--intern/cycles/kernel/svm/svm_types.h7
-rw-r--r--intern/cycles/render/graph.cpp23
-rw-r--r--intern/cycles/render/osl.cpp25
-rw-r--r--intern/cycles/render/shader.cpp2
-rw-r--r--intern/cycles/render/svm.cpp52
-rw-r--r--intern/cycles/render/svm.h1
14 files changed, 181 insertions, 52 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 9317bfbb703..3c37bc0b045 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -113,6 +113,7 @@ set(SRC_SVM_HEADERS
svm/svm.h
svm/svm_attribute.h
svm/svm_blackbody.h
+ svm/svm_bump.h
svm/svm_camera.h
svm/svm_closure.h
svm/svm_convert.h
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index deebf87c75f..0646148f6a0 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -714,20 +714,21 @@ enum ShaderDataFlag {
SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */
SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */
SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */
+ SD_HAS_DISPLACEMENT = (1 << 22), /* has true displacement */
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS|
- SD_VOLUME_CUBIC|SD_HAS_BUMP),
+ SD_VOLUME_CUBIC|SD_HAS_BUMP|SD_HAS_DISPLACEMENT),
/* object flags */
- SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */
- SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */
- SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */
- SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */
- SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */
- SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */
- SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */
+ SD_HOLDOUT_MASK = (1 << 23), /* holdout for camera rays */
+ SD_OBJECT_MOTION = (1 << 24), /* has object motion blur */
+ SD_TRANSFORM_APPLIED = (1 << 25), /* vertices have transform applied */
+ SD_NEGATIVE_SCALE_APPLIED = (1 << 26), /* vertices have negative scale applied */
+ SD_OBJECT_HAS_VOLUME = (1 << 27), /* object has a volume shader */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 28), /* object intersects AABB of an object with volume shader */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 29), /* has position for motion vertices */
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index 8353c4e434b..65cb7ecc6b4 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -54,6 +54,7 @@ struct OSLGlobals {
vector<OSL::ShaderGroupRef> surface_state;
vector<OSL::ShaderGroupRef> volume_state;
vector<OSL::ShaderGroupRef> displacement_state;
+ vector<OSL::ShaderGroupRef> bump_state;
OSL::ShaderGroupRef background_state;
/* attributes */
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 422af32ee79..f61a9ec0fb1 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -93,6 +93,7 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
+ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
#ifdef __HAIR__
ustring OSLRenderServices::u_is_curve("geom:is_curve");
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 2701abb483c..0f2e02c62b0 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -158,6 +158,7 @@ public:
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
+ static ustring u_geom_undisplaced;
static ustring u_is_smooth;
static ustring u_is_curve;
static ustring u_curve_thickness;
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 20dd167708c..681ea3c1794 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -184,6 +184,47 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
+ /* automatic bump shader */
+ if(kg->osl->bump_state[shader]) {
+ /* save state */
+ float3 P = sd->P;
+ float3 dPdx = sd->dP.dx;
+ float3 dPdy = sd->dP.dy;
+
+ /* set state as if undisplaced */
+ if(sd->flag & SD_HAS_DISPLACEMENT) {
+ float data[9];
+ bool found = kg->osl->services->get_attribute(sd, true, OSLRenderServices::u_empty, TypeDesc::TypeVector,
+ OSLRenderServices::u_geom_undisplaced, data);
+ assert(found);
+
+ memcpy(&sd->P, data, sizeof(float)*3);
+ memcpy(&sd->dP.dx, data+3, sizeof(float)*3);
+ memcpy(&sd->dP.dy, data+6, sizeof(float)*3);
+
+ object_position_transform(kg, sd, &sd->P);
+ object_dir_transform(kg, sd, &sd->dP.dx);
+ object_dir_transform(kg, sd, &sd->dP.dy);
+
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ }
+
+ /* execute bump shader */
+ ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
+
+ /* reset state */
+ sd->P = P;
+ sd->dP.dx = dPdx;
+ sd->dP.dy = dPdy;
+
+ globals->P = TO_VEC3(P);
+ globals->dPdx = TO_VEC3(dPdx);
+ globals->dPdy = TO_VEC3(dPdy);
+ }
+
+ /* surface shader */
if(kg->osl->surface_state[shader]) {
ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 502994e71f1..998a32e3181 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -181,6 +181,7 @@ CCL_NAMESPACE_END
#include "svm_brick.h"
#include "svm_vector_transform.h"
#include "svm_voxel.h"
+#include "svm_bump.h"
CCL_NAMESPACE_BEGIN
@@ -294,6 +295,12 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
case NODE_CLOSURE_SET_NORMAL:
svm_node_set_normal(kg, sd, stack, node.y, node.z);
break;
+ case NODE_ENTER_BUMP_EVAL:
+ svm_node_enter_bump_eval(kg, sd, stack, node.y);
+ break;
+ case NODE_LEAVE_BUMP_EVAL:
+ svm_node_leave_bump_eval(kg, sd, stack, node.y);
+ break;
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
case NODE_HSV:
svm_node_hsv(kg, sd, stack, node, &offset);
diff --git a/intern/cycles/kernel/svm/svm_bump.h b/intern/cycles/kernel/svm/svm_bump.h
new file mode 100644
index 00000000000..04a8c7b64e5
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_bump.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Eval Nodes */
+
+ccl_device void svm_node_enter_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* save state */
+ stack_store_float3(stack, offset+0, ccl_fetch(sd, P));
+ stack_store_float3(stack, offset+3, ccl_fetch(sd, dP).dx);
+ stack_store_float3(stack, offset+6, ccl_fetch(sd, dP).dy);
+
+ /* set state as if undisplaced */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
+
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 P, dPdx, dPdy;
+ P = primitive_attribute_float3(kg, sd, desc, &dPdx, &dPdy);
+
+ object_position_transform(kg, sd, &P);
+ object_dir_transform(kg, sd, &dPdx);
+ object_dir_transform(kg, sd, &dPdy);
+
+ ccl_fetch(sd, P) = P;
+ ccl_fetch(sd, dP).dx = dPdx;
+ ccl_fetch(sd, dP).dy = dPdy;
+ }
+}
+
+ccl_device void svm_node_leave_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* restore state */
+ ccl_fetch(sd, P) = stack_load_float3(stack, offset+0);
+ ccl_fetch(sd, dP).dx = stack_load_float3(stack, offset+3);
+ ccl_fetch(sd, dP).dy = stack_load_float3(stack, offset+6);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 51083c31708..9cfa8395b85 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -26,6 +26,8 @@ CCL_NAMESPACE_BEGIN
/* SVM stack offsets with this value indicate that it's not on the stack */
#define SVM_STACK_INVALID 255
+#define SVM_BUMP_EVAL_STATE_SIZE 9
+
/* Nodes */
/* Known frequencies of used nodes, used for selective nodes compilation
@@ -127,6 +129,8 @@ typedef enum ShaderNodeType {
NODE_HAIR_INFO,
NODE_UVMAP,
NODE_TEX_VOXEL,
+ NODE_ENTER_BUMP_EVAL,
+ NODE_LEAVE_BUMP_EVAL,
} ShaderNodeType;
typedef enum NodeAttributeType {
@@ -374,7 +378,8 @@ typedef enum NodeTexVoxelSpace {
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
- SHADER_TYPE_DISPLACEMENT
+ SHADER_TYPE_DISPLACEMENT,
+ SHADER_TYPE_BUMP,
} ShaderType;
/* Closure */
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 6e795ef896a..57256ceecd3 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -856,27 +856,8 @@ void ShaderGraph::bump_from_displacement()
/* connect the bump out to the set normal in: */
connect(bump->output("Normal"), set_normal->input("Direction"));
- /* connect bump output to normal input nodes that aren't set yet. actually
- * this will only set the normal input to the geometry node that we created
- * and connected to all other normal inputs already. */
- foreach(ShaderNode *node, nodes) {
- /* Don't connect normal to the bump node we're coming from,
- * otherwise it'll be a cycle in graph.
- */
- if(node == bump) {
- continue;
- }
- foreach(ShaderInput *input, node->inputs) {
- if(!input->link && (input->flags() & SocketType::LINK_NORMAL))
- connect(set_normal->output("Normal"), input);
- }
- }
-
- /* for displacement bump, clear the normal input in case the above loop
- * connected the setnormal out to the bump normalin */
- ShaderInput *bump_normal_in = bump->input("Normal");
- if(bump_normal_in)
- bump_normal_in->link = NULL;
+ /* connect to output node */
+ connect(set_normal->output("Normal"), output()->input("Normal"));
/* finally, add the copied nodes to the graph. we can't do this earlier
* because we would create dependency cycles in the above loop */
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 8d5e29579c2..f83aab47e84 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -609,7 +609,7 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
return true;
if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
return true;
- if(input->name() == "Normal")
+ if(input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
return true;
}
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
@@ -684,6 +684,8 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
ss->Shader("surface", name, id(node).c_str());
else if(current_type == SHADER_TYPE_DISPLACEMENT)
ss->Shader("displacement", name, id(node).c_str());
+ else if(current_type == SHADER_TYPE_BUMP)
+ ss->Shader("displacement", name, id(node).c_str());
else
assert(0);
@@ -1055,6 +1057,12 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
generate_nodes(dependencies);
output->compile(*this);
}
+ else if(type == SHADER_TYPE_BUMP) {
+ /* generate bump shader */
+ find_dependencies(dependencies, output->input("Normal"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
else if(type == SHADER_TYPE_VOLUME) {
/* generate volume shader */
find_dependencies(dependencies, output->input("Volume"));
@@ -1116,10 +1124,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
if(shader->used && graph && output->input("Surface")->link) {
shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- if(shader->graph_bump)
- shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
+ if(shader->graph_bump && shader->displacement_method != DISPLACE_TRUE)
+ shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
else
- shader->osl_surface_bump_ref = shader->osl_surface_ref;
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
shader->has_surface = true;
}
@@ -1146,15 +1154,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
}
/* push state to array for lookup */
- if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) {
- og->surface_state.push_back(shader->osl_surface_ref);
- }
- else {
- og->surface_state.push_back(shader->osl_surface_bump_ref);
- }
-
+ og->surface_state.push_back(shader->osl_surface_ref);
og->volume_state.push_back(shader->osl_volume_ref);
og->displacement_state.push_back(shader->osl_displacement_ref);
+ og->bump_state.push_back(shader->osl_surface_bump_ref);
}
#else
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 1876791c6e8..165a316ea76 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -407,6 +407,8 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_VOLUME_CUBIC;
if(shader->graph_bump)
flag |= SD_HAS_BUMP;
+ if(shader->displacement_method != DISPLACE_BUMP)
+ flag |= SD_HAS_DISPLACEMENT;
/* shader with bump mapping */
if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump)
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index be87b35dbbc..069c3e3043a 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -146,9 +146,8 @@ int SVMCompiler::stack_size(SocketType::Type type)
return size;
}
-int SVMCompiler::stack_find_offset(SocketType::Type type)
+int SVMCompiler::stack_find_offset(int size)
{
- int size = stack_size(type);
int offset = -1;
/* find free space in stack & mark as used */
@@ -175,6 +174,11 @@ int SVMCompiler::stack_find_offset(SocketType::Type type)
return 0;
}
+int SVMCompiler::stack_find_offset(SocketType::Type type)
+{
+ return stack_find_offset(stack_size(type));
+}
+
void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
{
int size = stack_size(type);
@@ -647,6 +651,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
case SHADER_TYPE_DISPLACEMENT:
clin = node->input("Displacement");
break;
+ case SHADER_TYPE_BUMP:
+ clin = node->input("Normal");
+ break;
default:
assert(0);
break;
@@ -663,6 +670,13 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
output->stack_offset = SVM_STACK_INVALID;
}
+ /* for the bump shader we need add a node to store the shader state */
+ int bump_state_offset = SVM_STACK_INVALID;
+ if(type == SHADER_TYPE_BUMP) {
+ bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
+ add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
+ }
+
if(shader->used) {
if(clin->link) {
bool generate = false;
@@ -680,6 +694,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
generate = true;
shader->has_displacement = true;
break;
+ case SHADER_TYPE_BUMP: /* generate bump shader */
+ generate = true;
+ break;
default:
break;
}
@@ -696,13 +713,21 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
node->compile(*this);
}
+ /* add node to restore state after bump shader has finished */
+ if(type == SHADER_TYPE_BUMP) {
+ add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
+ }
+
/* if compile failed, generate empty shader */
if(compile_failed) {
svm_nodes.clear();
compile_failed = false;
}
- add_node(NODE_END, 0, 0, 0);
+ /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */
+ if(type != SHADER_TYPE_BUMP) {
+ add_node(NODE_END, 0, 0, 0);
+ }
}
void SVMCompiler::compile(Scene *scene,
@@ -752,17 +777,22 @@ void SVMCompiler::compile(Scene *scene,
shader->has_object_dependency = false;
shader->has_integrator_dependency = false;
- /* generate surface shader */
- if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) {
- scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+ /* generate bump shader */
+ if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump) {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
+ compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
global_svm_nodes[index].y = global_svm_nodes.size();
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
- else {
- scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
- compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
- global_svm_nodes[index].y = global_svm_nodes.size();
+
+ /* generate surface shader */
+ {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+ /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */
+ if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) {
+ global_svm_nodes[index].y = global_svm_nodes.size();
+ }
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index e14d57d7601..99e91ca0c3e 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -99,6 +99,7 @@ public:
int stack_assign(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
+ int stack_find_offset(int size);
int stack_find_offset(SocketType::Type type);
void stack_clear_offset(SocketType::Type type, int offset);
void stack_link(ShaderInput *input, ShaderOutput *output);