diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-05-02 13:40:24 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-05-03 16:36:20 +0300 |
commit | fadb6f34662fb60e1a48c2c053c500f017206f27 (patch) | |
tree | 48c16c2215e7110e00b4255f6230aa3491d94ee0 /intern/cycles/kernel | |
parent | 08a44d29815f6b0b9b675a503829d2e2ce7f6426 (diff) |
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.
Diffstat (limited to 'intern/cycles/kernel')
-rw-r--r-- | intern/cycles/kernel/osl/osl_globals.h | 49 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/osl_services.cpp | 366 | ||||
-rw-r--r-- | intern/cycles/kernel/shaders/node_ies_light.osl | 4 |
3 files changed, 245 insertions, 174 deletions
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h index 641c9967586..414aaf891db 100644 --- a/intern/cycles/kernel/osl/osl_globals.h +++ b/intern/cycles/kernel/osl/osl_globals.h @@ -21,10 +21,14 @@ # include <OSL/oslexec.h> +# include <OpenImageIO/refcnt.h> +# include <OpenImageIO/unordered_map_concurrent.h> + # include "util/util_map.h" # include "util/util_param.h" # include "util/util_thread.h" # include "util/util_vector.h" +# include "util/util_unique_ptr.h" # ifndef WIN32 using std::isfinite; @@ -34,6 +38,48 @@ CCL_NAMESPACE_BEGIN 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 { OSLGlobals() { @@ -70,6 +116,9 @@ struct OSLGlobals { vector<AttributeMap> attribute_map; ObjectNameMap object_name_map; vector<ustring> object_names; + + /* textures */ + OSLTextureHandleMap textures; }; /* trace() call result */ diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index b4329ab0a71..7de596a2c30 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -124,8 +124,6 @@ ustring OSLRenderServices::u_I("I"); ustring OSLRenderServices::u_u("u"); ustring OSLRenderServices::u_v("v"); ustring OSLRenderServices::u_empty; -ustring OSLRenderServices::u_at_bevel("@bevel"); -ustring OSLRenderServices::u_at_ao("@ao"); OSLRenderServices::OSLRenderServices() { @@ -154,7 +152,7 @@ void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_, OSL::TextureSystem *osl_ts_) { kernel_globals = kernel_globals_; - osl_globals = osl_globals; + osl_globals = osl_globals_; osl_ts = osl_ts_; } @@ -956,19 +954,44 @@ bool OSLRenderServices::get_userdata( TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename) { - if (filename.length() && filename[0] == '@') { - /* Dummy, we don't use texture handles for builtin textures but need - * to tell the OSL runtime optimizer that this is a valid texture. */ + OSLTextureHandleMap::iterator it = osl_globals->textures.find(filename); + + /* 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; } - 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) { - 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, @@ -988,70 +1011,29 @@ bool OSLRenderServices::texture(ustring filename, float *dresultdt, ustring *errormessage) { - OSL::TextureSystem *ts = osl_ts; - ShaderData *sd = (ShaderData *)(sg->renderstate); - 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 + OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle; + OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO; bool status = false; - if (filename.length() && filename[0] == '@') { - if (filename == u_at_bevel) { + switch (texture_type) { + case OSLTextureHandle::BEVEL: { /* Bevel shader hack. */ if (nchannels >= 3) { + ShaderData *sd = (ShaderData *)(sg->renderstate); PathState *state = sd->osl_path_state; int num_samples = (int)s; 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[1] = N.y; result[2] = N.z; status = true; } + break; } - else if (filename == u_at_ao) { + case OSLTextureHandle::AO: { /* AO shader hack. */ + ShaderData *sd = (ShaderData *)(sg->renderstate); PathState *state = sd->osl_path_state; int num_samples = (int)s; float radius = t; @@ -1066,19 +1048,13 @@ bool OSLRenderServices::texture(ustring filename, if ((int)options.tblur) { 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; + break; } - else if (filename[1] == 'l') { - /* IES light. */ - int slot = atoi(filename.c_str() + 2); - result[0] = kernel_ies_interp(kg, slot, s, t); - status = true; - } - else { + case OSLTextureHandle::SVM: { /* Packed texture. */ - int slot = atoi(filename.c_str() + 2); - float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); + float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t); result[0] = rgba[0]; if (nchannels > 1) @@ -1088,37 +1064,59 @@ bool OSLRenderServices::texture(ustring filename, if (nchannels > 3) result[3] = rgba[3]; status = true; + break; } - } - else { - if (texture_handle != NULL) { - status = ts->texture(texture_handle, - texture_thread_info, - options, - s, - t, - dsdx, - dtdx, - dsdy, - dtdy, - nchannels, - result, - dresultds, - dresultdt); + case OSLTextureHandle::IES: { + /* IES light. */ + result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t); + status = true; + break; } - else { - status = ts->texture(filename, - options, - s, - t, - dsdx, - dtdx, - dsdy, - dtdy, - nchannels, - result, - dresultds, - dresultdt); + case OSLTextureHandle::OIIO: { + /* OpenImageIO texture cache. */ + OSL::TextureSystem *ts = osl_ts; + + if (handle && handle->oiio_handle) { + if (texture_thread_info == NULL) { + OSLThreadData *tdata = kernel_globals->osl_tdata; + texture_thread_info = tdata->oiio_thread_info; + } + + status = ts->texture(handle->oiio_handle, + texture_thread_info, + 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) 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; @@ -1157,56 +1150,76 @@ bool OSLRenderServices::texture3d(ustring filename, float *dresultdr, ustring *errormessage) { - OSL::TextureSystem *ts = osl_ts; - ShaderData *sd = (ShaderData *)(sg->renderstate); - KernelGlobals *kg = kernel_globals; + OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle; + OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO; + bool status = false; - if (texture_thread_info == NULL) { - OSLThreadData *tdata = kg->osl_tdata; - texture_thread_info = tdata->oiio_thread_info; - } + switch (texture_type) { + case OSLTextureHandle::SVM: { + /* 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; - if (filename.length() && filename[0] == '@') { - int slot = atoi(filename.c_str() + 1); - float4 rgba = kernel_tex_image_interp_3d(kg, slot, P.x, P.y, P.z, INTERPOLATION_NONE); + result[0] = rgba[0]; + if (nchannels > 1) + result[1] = rgba[1]; + if (nchannels > 2) + result[2] = rgba[2]; + if (nchannels > 3) + result[3] = rgba[3]; + status = true; + break; + } + case OSLTextureHandle::OIIO: { + /* OpenImageIO texture cache. */ + OSL::TextureSystem *ts = osl_ts; + + if (handle && handle->oiio_handle) { + if (texture_thread_info == NULL) { + OSLThreadData *tdata = kernel_globals->osl_tdata; + texture_thread_info = tdata->oiio_thread_info; + } - result[0] = rgba[0]; - if (nchannels > 1) - result[1] = rgba[1]; - if (nchannels > 2) - 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); + status = ts->texture3d(handle->oiio_handle, + 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; } - else { - status = ts->texture3d(filename, - options, - P, - dPdx, - dPdy, - dPdz, - nchannels, - result, - dresultds, - dresultdt, - dresultdr); + case OSLTextureHandle::IES: + case OSLTextureHandle::AO: + case OSLTextureHandle::BEVEL: { + status = false; + break; } } @@ -1219,18 +1232,13 @@ bool OSLRenderServices::texture3d(ustring filename, if (nchannels == 4) 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; } bool OSLRenderServices::environment(ustring filename, - TextureHandle *th, + TextureHandle *texture_handle, TexturePerthread *thread_info, TextureOpt &options, OSL::ShaderGlobals *sg, @@ -1243,19 +1251,31 @@ bool OSLRenderServices::environment(ustring filename, float *dresultdt, ustring *errormessage) { + OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle; OSL::TextureSystem *ts = osl_ts; + bool status = false; - if (thread_info == NULL) { - OSLThreadData *tdata = kernel_globals->osl_tdata; - thread_info = tdata->oiio_thread_info; - } + if (handle && handle->oiio_handle) { + if (thread_info == NULL) { + OSLThreadData *tdata = kernel_globals->osl_tdata; + thread_info = tdata->oiio_thread_info; + } - if (th == NULL) { - th = ts->get_texture_handle(filename, thread_info); + status = ts->environment(handle->oiio_handle, + thread_info, + options, + R, + dRdx, + dRdy, + nchannels, + result, + dresultds, + dresultdt); + } + else { + status = ts->environment( + 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 (nchannels == 3 || nchannels == 4) { @@ -1273,20 +1293,22 @@ bool OSLRenderServices::environment(ustring filename, bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg, ustring filename, - TextureHandle *th, + TextureHandle *texture_handle, int subimage, ustring dataname, TypeDesc datatype, void *data) { - OSL::TextureSystem *ts = osl_ts; - if (filename.length() && filename[0] == '@') { - /* Special builtin textures. */ - return false; - } - else { - return ts->get_texture_info(filename, subimage, dataname, datatype, 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; + return ts->get_texture_info(filename, subimage, dataname, datatype, data); } int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl index ea8c44e09de..ce0173451da 100644 --- a/intern/cycles/kernel/shaders/node_ies_light.osl +++ b/intern/cycles/kernel/shaders/node_ies_light.osl @@ -21,7 +21,7 @@ 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), - int slot = 0, + string filename = "", float Strength = 1.0, point Vector = I, output float Fac = 0.0) @@ -37,5 +37,5 @@ shader node_ies_light(int use_mapping = 0, float v_angle = acos(-p[2]); 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); } |