[Bf-blender-cvs] [fadb6f34662] master: Cleanup: refactor Cycles OSL texture handling

Brecht Van Lommel noreply at git.blender.org
Fri May 3 15:43:30 CEST 2019


Commit: fadb6f34662fb60e1a48c2c053c500f017206f27
Author: Brecht Van Lommel
Date:   Thu May 2 12:40:24 2019 +0200
Branches: master
https://developer.blender.org/rBfadb6f34662fb60e1a48c2c053c500f017206f27

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.

===================================================================

M	intern/cycles/device/device_cpu.cpp
M	intern/cycles/kernel/osl/osl_globals.h
M	intern/cycles/kernel/osl/osl_services.cpp
M	intern/cycles/kernel/shaders/node_ies_light.osl
M	intern/cycles/render/nodes.cpp
M	intern/cycles/render/osl.cpp
M	intern/cycles/render/osl.h
M	intern/cycles/util/util_aligned_malloc.h

===================================================================

diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 837a8186064..32911e054fe 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -43,6 +43,7 @@
 #include "render/buffers.h"
 #include "render/coverage.h"
 
+#include "util/util_aligned_malloc.h"
 #include "util/util_debug.h"
 #include "util/util_foreach.h"
 #include "util/util_function.h"
@@ -165,7 +166,7 @@ class CPUDevice : public Device {
   bool need_texture_info;
 
 #ifdef WITH_OSL
-  OSLGlobals osl_globals;
+  OSLGlobals *osl_globals;
 #endif
 
   bool use_split_kernel;
@@ -282,7 +283,9 @@ class CPUDevice : public Device {
     }
 
 #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
     use_split_kernel = DebugFlags().cpu.split_kernel;
     if (use_split_kernel) {
@@ -317,6 +320,9 @@ class CPUDevice : public Device {
 
   ~CPUDevice()
   {
+#ifdef WITH_OSL
+    delete osl_globals;
+#endif
     task_pool.stop();
     texture_info.free();
   }
@@ -492,7 +498,7 @@ class CPUDevice : public Device {
   void *osl_memory()
   {
 #ifdef WITH_OSL
-    return &osl_globals;
+    return osl_globals;
 #else
     return NULL;
 #endif
@@ -981,7 +987,7 @@ class CPUDevice : public Device {
     KernelGlobals kg = kernel_globals;
 
 #ifdef WITH_OSL
-    OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
+    OSLShader::thread_init(&kg, &kernel_globals, osl_globals);
 #endif
     for (int sample = 0; sample < task.num_samples; sample++) {
       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.coverage_asset = kg.coverage_object = kg.coverage_material = NULL;
 #ifdef WITH_OSL
-    OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
+    OSLShader::thread_init(&kg, &kernel_globals, osl_globals);
 #endif
     return kg;
   }
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_glo

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list