Cleanup: refactor Cycles OSL texture handling

This adds our own OSL texture handle, that has info for OIIO textures or our
own custom texture types. A filename to handle hash map is used for lookups.
This is efficient because it happens at OSL compile time, because the optimizer
can figure out constant strings and replace them with texture handles.
This commit is contained in:
Brecht Van Lommel 2019-05-02 12:40:24 +02:00
parent 08a44d2981
commit fadb6f3466
8 changed files with 309 additions and 202 deletions

@ -43,6 +43,7 @@
#include "render/buffers.h" #include "render/buffers.h"
#include "render/coverage.h" #include "render/coverage.h"
#include "util/util_aligned_malloc.h"
#include "util/util_debug.h" #include "util/util_debug.h"
#include "util/util_foreach.h" #include "util/util_foreach.h"
#include "util/util_function.h" #include "util/util_function.h"
@ -165,7 +166,7 @@ class CPUDevice : public Device {
bool need_texture_info; bool need_texture_info;
#ifdef WITH_OSL #ifdef WITH_OSL
OSLGlobals osl_globals; OSLGlobals *osl_globals;
#endif #endif
bool use_split_kernel; bool use_split_kernel;
@ -282,7 +283,9 @@ class CPUDevice : public Device {
} }
#ifdef WITH_OSL #ifdef WITH_OSL
kernel_globals.osl = &osl_globals; /* Must use aligned malloc due to concurrent hash map. */
osl_globals = util_aligned_new<OSLGlobals>();
kernel_globals.osl = osl_globals;
#endif #endif
use_split_kernel = DebugFlags().cpu.split_kernel; use_split_kernel = DebugFlags().cpu.split_kernel;
if (use_split_kernel) { if (use_split_kernel) {
@ -317,6 +320,9 @@ class CPUDevice : public Device {
~CPUDevice() ~CPUDevice()
{ {
#ifdef WITH_OSL
delete osl_globals;
#endif
task_pool.stop(); task_pool.stop();
texture_info.free(); texture_info.free();
} }
@ -492,7 +498,7 @@ class CPUDevice : public Device {
void *osl_memory() void *osl_memory()
{ {
#ifdef WITH_OSL #ifdef WITH_OSL
return &osl_globals; return osl_globals;
#else #else
return NULL; return NULL;
#endif #endif
@ -981,7 +987,7 @@ class CPUDevice : public Device {
KernelGlobals kg = kernel_globals; KernelGlobals kg = kernel_globals;
#ifdef WITH_OSL #ifdef WITH_OSL
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals); OSLShader::thread_init(&kg, &kernel_globals, osl_globals);
#endif #endif
for (int sample = 0; sample < task.num_samples; sample++) { for (int sample = 0; sample < task.num_samples; sample++) {
for (int x = task.shader_x; x < task.shader_x + task.shader_w; x++) for (int x = task.shader_x; x < task.shader_x + task.shader_w; x++)
@ -1053,7 +1059,7 @@ class CPUDevice : public Device {
kg.decoupled_volume_steps_index = 0; kg.decoupled_volume_steps_index = 0;
kg.coverage_asset = kg.coverage_object = kg.coverage_material = NULL; kg.coverage_asset = kg.coverage_object = kg.coverage_material = NULL;
#ifdef WITH_OSL #ifdef WITH_OSL
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals); OSLShader::thread_init(&kg, &kernel_globals, osl_globals);
#endif #endif
return kg; return kg;
} }

@ -21,10 +21,14 @@
# include <OSL/oslexec.h> # include <OSL/oslexec.h>
# include <OpenImageIO/refcnt.h>
# include <OpenImageIO/unordered_map_concurrent.h>
# include "util/util_map.h" # include "util/util_map.h"
# include "util/util_param.h" # include "util/util_param.h"
# include "util/util_thread.h" # include "util/util_thread.h"
# include "util/util_vector.h" # include "util/util_vector.h"
# include "util/util_unique_ptr.h"
# ifndef WIN32 # ifndef WIN32
using std::isfinite; using std::isfinite;
@ -34,6 +38,48 @@ CCL_NAMESPACE_BEGIN
class OSLRenderServices; class OSLRenderServices;
/* OSL Texture Handle
*
* OSL texture lookups are string based. If those strings are known at compile
* time, the OSL compiler can cache a texture handle to use instead of a string.
*
* By default it uses TextureSystem::TextureHandle. But since we want to support
* different kinds of textures and color space conversions, this is our own handle
* with additional data.
*
* These are stored in a concurrent hash map, because OSL can compile multiple
* shaders in parallel. */
struct OSLTextureHandle : public OIIO::RefCnt {
enum Type { OIIO, SVM, IES, BEVEL, AO };
OSLTextureHandle() : type(OIIO), svm_slot(-1), oiio_handle(NULL)
{
}
OSLTextureHandle(Type type) : type(type), svm_slot(-1), oiio_handle(NULL)
{
}
OSLTextureHandle(Type type, int svm_slot) : type(type), svm_slot(svm_slot), oiio_handle(NULL)
{
}
Type type;
int svm_slot;
OSL::TextureSystem::TextureHandle *oiio_handle;
};
typedef OIIO::intrusive_ptr<OSLTextureHandle> OSLTextureHandleRef;
typedef OIIO::unordered_map_concurrent<ustring, OSLTextureHandleRef, ustringHash>
OSLTextureHandleMap;
/* OSL Globals
*
* Data needed by OSL render services, that is global to a rendering session.
* This includes all OSL shaders, name to attribute mapping and texture handles.
* */
struct OSLGlobals { struct OSLGlobals {
OSLGlobals() OSLGlobals()
{ {
@ -70,6 +116,9 @@ struct OSLGlobals {
vector<AttributeMap> attribute_map; vector<AttributeMap> attribute_map;
ObjectNameMap object_name_map; ObjectNameMap object_name_map;
vector<ustring> object_names; vector<ustring> object_names;
/* textures */
OSLTextureHandleMap textures;
}; };
/* trace() call result */ /* trace() call result */

@ -124,8 +124,6 @@ ustring OSLRenderServices::u_I("I");
ustring OSLRenderServices::u_u("u"); ustring OSLRenderServices::u_u("u");
ustring OSLRenderServices::u_v("v"); ustring OSLRenderServices::u_v("v");
ustring OSLRenderServices::u_empty; ustring OSLRenderServices::u_empty;
ustring OSLRenderServices::u_at_bevel("@bevel");
ustring OSLRenderServices::u_at_ao("@ao");
OSLRenderServices::OSLRenderServices() OSLRenderServices::OSLRenderServices()
{ {
@ -154,7 +152,7 @@ void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_,
OSL::TextureSystem *osl_ts_) OSL::TextureSystem *osl_ts_)
{ {
kernel_globals = kernel_globals_; kernel_globals = kernel_globals_;
osl_globals = osl_globals; osl_globals = osl_globals_;
osl_ts = osl_ts_; osl_ts = osl_ts_;
} }
@ -956,19 +954,44 @@ bool OSLRenderServices::get_userdata(
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename) TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
{ {
if (filename.length() && filename[0] == '@') { OSLTextureHandleMap::iterator it = osl_globals->textures.find(filename);
/* Dummy, we don't use texture handles for builtin textures but need
* to tell the OSL runtime optimizer that this is a valid texture. */ /* For non-OIIO textures, just return a pointer to our own OSLTextureHandle. */
if (it != osl_globals->textures.end()) {
if (it->second->type != OSLTextureHandle::OIIO) {
return (TextureSystem::TextureHandle *)it->second.get();
}
}
/* Get handle from OpenImageIO. */
OSL::TextureSystem *ts = osl_ts;
TextureSystem::TextureHandle *handle = ts->get_texture_handle(filename);
if (handle == NULL) {
return NULL; return NULL;
} }
else {
return texturesys()->get_texture_handle(filename); /* Insert new OSLTextureHandle if needed. */
if (it == osl_globals->textures.end()) {
osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
it = osl_globals->textures.find(filename);
} }
/* Assign OIIO texture handle and return. */
it->second->oiio_handle = handle;
return (TextureSystem::TextureHandle *)it->second.get();
} }
bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle) bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle)
{ {
return texturesys()->good(texture_handle); OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
if (handle->oiio_handle) {
OSL::TextureSystem *ts = osl_ts;
return ts->good(handle->oiio_handle);
}
else {
return true;
}
} }
bool OSLRenderServices::texture(ustring filename, bool OSLRenderServices::texture(ustring filename,
@ -988,70 +1011,29 @@ bool OSLRenderServices::texture(ustring filename,
float *dresultdt, float *dresultdt,
ustring *errormessage) ustring *errormessage)
{ {
OSL::TextureSystem *ts = osl_ts; OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
ShaderData *sd = (ShaderData *)(sg->renderstate); OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
KernelGlobals *kg = kernel_globals;
if (texture_thread_info == NULL) {
OSLThreadData *tdata = kg->osl_tdata;
texture_thread_info = tdata->oiio_thread_info;
}
#ifdef WITH_PTEX
/* todo: this is just a quick hack, only works with particular files and options */
if (string_endswith(filename.string(), ".ptx")) {
float2 uv;
int faceid;
if (!primitive_ptex(kg, sd, &uv, &faceid))
return false;
float u = uv.x;
float v = uv.y;
float dudx = 0.0f;
float dvdx = 0.0f;
float dudy = 0.0f;
float dvdy = 0.0f;
Ptex::String error;
PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error));
if (!r) {
// std::cerr << error.c_str() << std::endl;
return false;
}
bool mipmaplerp = false;
float sharpness = 1.0f;
PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness);
PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts));
f->eval(result, options.firstchannel, nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy);
for (int c = r->numChannels(); c < nchannels; c++)
result[c] = result[0];
return true;
}
#endif
bool status = false; bool status = false;
if (filename.length() && filename[0] == '@') { switch (texture_type) {
if (filename == u_at_bevel) { case OSLTextureHandle::BEVEL: {
/* Bevel shader hack. */ /* Bevel shader hack. */
if (nchannels >= 3) { if (nchannels >= 3) {
ShaderData *sd = (ShaderData *)(sg->renderstate);
PathState *state = sd->osl_path_state; PathState *state = sd->osl_path_state;
int num_samples = (int)s; int num_samples = (int)s;
float radius = t; float radius = t;
float3 N = svm_bevel(kg, sd, state, radius, num_samples); float3 N = svm_bevel(kernel_globals, sd, state, radius, num_samples);
result[0] = N.x; result[0] = N.x;
result[1] = N.y; result[1] = N.y;
result[2] = N.z; result[2] = N.z;
status = true; status = true;
} }
break;
} }
else if (filename == u_at_ao) { case OSLTextureHandle::AO: {
/* AO shader hack. */ /* AO shader hack. */
ShaderData *sd = (ShaderData *)(sg->renderstate);
PathState *state = sd->osl_path_state; PathState *state = sd->osl_path_state;
int num_samples = (int)s; int num_samples = (int)s;
float radius = t; float radius = t;
@ -1066,19 +1048,13 @@ bool OSLRenderServices::texture(ustring filename,
if ((int)options.tblur) { if ((int)options.tblur) {
flags |= NODE_AO_GLOBAL_RADIUS; flags |= NODE_AO_GLOBAL_RADIUS;
} }
result[0] = svm_ao(kg, sd, N, state, radius, num_samples, flags); result[0] = svm_ao(kernel_globals, sd, N, state, radius, num_samples, flags);
status = true; status = true;
break;
} }
else if (filename[1] == 'l') { case OSLTextureHandle::SVM: {
/* IES light. */
int slot = atoi(filename.c_str() + 2);
result[0] = kernel_ies_interp(kg, slot, s, t);
status = true;
}
else {
/* Packed texture. */ /* Packed texture. */
int slot = atoi(filename.c_str() + 2); float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t);
result[0] = rgba[0]; result[0] = rgba[0];
if (nchannels > 1) if (nchannels > 1)
@ -1088,37 +1064,59 @@ bool OSLRenderServices::texture(ustring filename,
if (nchannels > 3) if (nchannels > 3)
result[3] = rgba[3]; result[3] = rgba[3];
status = true; status = true;
break;
} }
} case OSLTextureHandle::IES: {
else { /* IES light. */
if (texture_handle != NULL) { result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
status = ts->texture(texture_handle, status = true;
texture_thread_info, break;
options,
s,
t,
dsdx,
dtdx,
dsdy,
dtdy,
nchannels,
result,
dresultds,
dresultdt);
} }
else { case OSLTextureHandle::OIIO: {
status = ts->texture(filename, /* OpenImageIO texture cache. */
options, OSL::TextureSystem *ts = osl_ts;
s,
t, if (handle && handle->oiio_handle) {
dsdx, if (texture_thread_info == NULL) {
dtdx, OSLThreadData *tdata = kernel_globals->osl_tdata;
dsdy, texture_thread_info = tdata->oiio_thread_info;
dtdy, }
nchannels,
result, status = ts->texture(handle->oiio_handle,
dresultds, texture_thread_info,
dresultdt); options,
s,
t,
dsdx,
dtdx,
dsdy,
dtdy,
nchannels,
result,
dresultds,
dresultdt);
}
else {
status = ts->texture(filename,
options,
s,
t,
dsdx,
dtdx,
dsdy,
dtdy,
nchannels,
result,
dresultds,
dresultdt);
}
if (!status) {
/* This might be slow, but prevents error messages leak and
* other nasty stuff happening. */
ts->geterror();
}
break;
} }
} }
@ -1131,11 +1129,6 @@ bool OSLRenderServices::texture(ustring filename,
if (nchannels == 4) if (nchannels == 4)
result[3] = 1.0f; result[3] = 1.0f;
} }
/* This might be slow, but prevents error messages leak and
* other nasty stuff happening.
*/
string err = ts->geterror();
(void)err;
} }
return status; return status;
@ -1157,56 +1150,76 @@ bool OSLRenderServices::texture3d(ustring filename,
float *dresultdr, float *dresultdr,
ustring *errormessage) ustring *errormessage)
{ {
OSL::TextureSystem *ts = osl_ts; OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
ShaderData *sd = (ShaderData *)(sg->renderstate); OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
KernelGlobals *kg = kernel_globals; bool status = false;
if (texture_thread_info == NULL) { switch (texture_type) {
OSLThreadData *tdata = kg->osl_tdata; case OSLTextureHandle::SVM: {
texture_thread_info = tdata->oiio_thread_info; /* Packed texture. */
} int slot = handle->svm_slot;
float4 rgba = kernel_tex_image_interp_3d(
kernel_globals, slot, P.x, P.y, P.z, INTERPOLATION_NONE);
bool status; result[0] = rgba[0];
if (filename.length() && filename[0] == '@') { if (nchannels > 1)
int slot = atoi(filename.c_str() + 1); result[1] = rgba[1];
float4 rgba = kernel_tex_image_interp_3d(kg, slot, P.x, P.y, P.z, INTERPOLATION_NONE); if (nchannels > 2)
result[2] = rgba[2];
result[0] = rgba[0]; if (nchannels > 3)
if (nchannels > 1) result[3] = rgba[3];
result[1] = rgba[1]; status = true;
if (nchannels > 2) break;
result[2] = rgba[2];
if (nchannels > 3)
result[3] = rgba[3];
status = true;
}
else {
if (texture_handle != NULL) {
status = ts->texture3d(texture_handle,
texture_thread_info,
options,
P,
dPdx,
dPdy,
dPdz,
nchannels,
result,
dresultds,
dresultdt,
dresultdr);
} }
else { case OSLTextureHandle::OIIO: {
status = ts->texture3d(filename, /* OpenImageIO texture cache. */
options, OSL::TextureSystem *ts = osl_ts;
P,
dPdx, if (handle && handle->oiio_handle) {
dPdy, if (texture_thread_info == NULL) {
dPdz, OSLThreadData *tdata = kernel_globals->osl_tdata;
nchannels, texture_thread_info = tdata->oiio_thread_info;
result, }
dresultds,
dresultdt, status = ts->texture3d(handle->oiio_handle,
dresultdr); texture_thread_info,
options,
P,
dPdx,
dPdy,
dPdz,
nchannels,
result,
dresultds,
dresultdt,
dresultdr);
}
else {
status = ts->texture3d(filename,
options,
P,
dPdx,
dPdy,
dPdz,
nchannels,
result,
dresultds,
dresultdt,
dresultdr);
}
if (!status) {
/* This might be slow, but prevents error messages leak and
* other nasty stuff happening. */
ts->geterror();
}
break;
}
case OSLTextureHandle::IES:
case OSLTextureHandle::AO:
case OSLTextureHandle::BEVEL: {
status = false;
break;
} }
} }
@ -1219,18 +1232,13 @@ bool OSLRenderServices::texture3d(ustring filename,
if (nchannels == 4) if (nchannels == 4)
result[3] = 1.0f; result[3] = 1.0f;
} }
/* This might be slow, but prevents error messages leak and
* other nasty stuff happening.
*/
string err = ts->geterror();
(void)err;
} }
return status; return status;
} }
bool OSLRenderServices::environment(ustring filename, bool OSLRenderServices::environment(ustring filename,
TextureHandle *th, TextureHandle *texture_handle,
TexturePerthread *thread_info, TexturePerthread *thread_info,
TextureOpt &options, TextureOpt &options,
OSL::ShaderGlobals *sg, OSL::ShaderGlobals *sg,
@ -1243,20 +1251,32 @@ bool OSLRenderServices::environment(ustring filename,
float *dresultdt, float *dresultdt,
ustring *errormessage) ustring *errormessage)
{ {
OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
OSL::TextureSystem *ts = osl_ts; OSL::TextureSystem *ts = osl_ts;
bool status = false;
if (thread_info == NULL) { if (handle && handle->oiio_handle) {
OSLThreadData *tdata = kernel_globals->osl_tdata; if (thread_info == NULL) {
thread_info = tdata->oiio_thread_info; OSLThreadData *tdata = kernel_globals->osl_tdata;
thread_info = tdata->oiio_thread_info;
}
status = ts->environment(handle->oiio_handle,
thread_info,
options,
R,
dRdx,
dRdy,
nchannels,
result,
dresultds,
dresultdt);
} }
else {
if (th == NULL) { status = ts->environment(
th = ts->get_texture_handle(filename, thread_info); filename, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
} }
bool status = ts->environment(
th, thread_info, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
if (!status) { if (!status) {
if (nchannels == 3 || nchannels == 4) { if (nchannels == 3 || nchannels == 4) {
result[0] = 1.0f; result[0] = 1.0f;
@ -1273,20 +1293,22 @@ bool OSLRenderServices::environment(ustring filename,
bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg, bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
ustring filename, ustring filename,
TextureHandle *th, TextureHandle *texture_handle,
int subimage, int subimage,
ustring dataname, ustring dataname,
TypeDesc datatype, TypeDesc datatype,
void *data) void *data)
{ {
OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
/* No texture info for other texture types. */
if (handle && handle->type != OSLTextureHandle::OIIO) {
return NULL;
}
/* Get texture info from OpenImageIO. */
OSL::TextureSystem *ts = osl_ts; OSL::TextureSystem *ts = osl_ts;
if (filename.length() && filename[0] == '@') { return ts->get_texture_info(filename, subimage, dataname, datatype, data);
/* Special builtin textures. */
return false;
}
else {
return ts->get_texture_info(filename, subimage, dataname, datatype, data);
}
} }
int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg,

@ -21,7 +21,7 @@
shader node_ies_light(int use_mapping = 0, shader node_ies_light(int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
int slot = 0, string filename = "",
float Strength = 1.0, float Strength = 1.0,
point Vector = I, point Vector = I,
output float Fac = 0.0) output float Fac = 0.0)
@ -37,5 +37,5 @@ shader node_ies_light(int use_mapping = 0,
float v_angle = acos(-p[2]); float v_angle = acos(-p[2]);
float h_angle = atan2(p[0], p[1]) + M_PI; float h_angle = atan2(p[0], p[1]) + M_PI;
Fac = Strength * texture(format("@l%d", slot), h_angle, v_angle); Fac = Strength * texture(filename, h_angle, v_angle);
} }

@ -374,18 +374,7 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
is_linear = metadata.is_linear; is_linear = metadata.is_linear;
} }
if (slot == -1) { compiler.parameter_texture("filename", filename, slot);
compiler.parameter(this, "filename");
}
else {
/* TODO(sergey): It's not so simple to pass custom attribute
* to the texture() function in order to make builtin images
* support more clear. So we use special file name which is
* "@i<slot_number>" and check whether file name matches this
* mask in the OSLRenderServices::texture().
*/
compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
if (is_linear || color_space != NODE_COLOR_SPACE_COLOR) if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear"); compiler.parameter("color_space", "linear");
else else
@ -556,12 +545,7 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
is_linear = metadata.is_linear; is_linear = metadata.is_linear;
} }
if (slot == -1) { compiler.parameter_texture("filename", filename, slot);
compiler.parameter(this, "filename");
}
else {
compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
compiler.parameter(this, "projection"); compiler.parameter(this, "projection");
if (is_linear || color_space != NODE_COLOR_SPACE_COLOR) if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear"); compiler.parameter("color_space", "linear");
@ -1080,7 +1064,7 @@ void IESLightNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler); tex_mapping.compile(compiler);
compiler.parameter("slot", slot); compiler.parameter_texture_ies("filename", slot);
compiler.add(this, "node_ies_light"); compiler.add(this, "node_ies_light");
} }
@ -1567,9 +1551,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
if (use_density || use_color) { if (use_density || use_color) {
add_image(); add_image();
if (slot != -1) { compiler.parameter_texture("filename", ustring(), slot);
compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
if (space == NODE_TEX_VOXEL_SPACE_WORLD) { if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm); compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1); compiler.parameter("use_mapping", 1);

@ -145,6 +145,10 @@ void OSLShaderManager::device_update(Device *device,
/* set texture system */ /* set texture system */
scene->image_manager->set_osl_texture_system((void *)ts); scene->image_manager->set_osl_texture_system((void *)ts);
/* add special builtin texture types */
og->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
og->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
device_update_common(device, dscene, scene, progress); device_update_common(device, dscene, scene, progress);
{ {
@ -1201,6 +1205,30 @@ void OSLCompiler::compile(Scene *scene, Shader *shader)
osl_globals->bump_state.push_back(shader->osl_surface_bump_ref); osl_globals->bump_state.push_back(shader->osl_surface_bump_ref);
} }
void OSLCompiler::parameter_texture(const char *name, ustring filename, int svm_slot)
{
if (svm_slot != -1) {
/* It's not so simple to pass custom attribute to the texture() function
* in order to make builtin images support more clear. So we use special
* file name which is "@i<slot_number>" and use that for lookup in
* in OSLRenderServices::texture(). */
filename = string_printf("@i%d", svm_slot).c_str();
osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
}
else {
osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
}
parameter(name, filename);
}
void OSLCompiler::parameter_texture_ies(const char *name, int svm_slot)
{
ustring filename(string_printf("@l%d", svm_slot).c_str());
osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
parameter(name, filename);
}
#else #else
void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/) void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
@ -1255,6 +1283,16 @@ void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float
{ {
} }
void OSLCompiler::parameter_texture(const char * /* name */,
ustring /* filename */,
int /* svm_slot */)
{
}
void OSLCompiler::parameter_texture_ies(const char * /* name */, int /* svm_slot */)
{
}
#endif /* WITH_OSL */ #endif /* WITH_OSL */
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -153,6 +153,9 @@ class OSLCompiler {
void parameter_attribute(const char *name, ustring s); void parameter_attribute(const char *name, ustring s);
void parameter_texture(const char *name, ustring filename, int svm_slot);
void parameter_texture_ies(const char *name, int svm_slot);
ShaderType output_type() ShaderType output_type()
{ {
return current_type; return current_type;

@ -30,6 +30,13 @@ void *util_aligned_malloc(size_t size, int alignment);
/* Free memory allocated by util_aligned_malloc. */ /* Free memory allocated by util_aligned_malloc. */
void util_aligned_free(void *ptr); void util_aligned_free(void *ptr);
/* Aligned new operator. */
template<typename T> T *util_aligned_new()
{
void *mem = util_aligned_malloc(sizeof(T), alignof(T));
return new (mem) T();
}
CCL_NAMESPACE_END CCL_NAMESPACE_END
#endif /* __UTIL_ALIGNED_MALLOC_H__ */ #endif /* __UTIL_ALIGNED_MALLOC_H__ */