Fix T104240: OptiX OSL texture loading broken with displacement

The image manager used to handle OSL textures on the GPU by
default loads images after displacement is evaluated. This is a
problem when the displacement shader uses any textures, hence
why the geometry manager already makes the image manager
load any images used in the displacement shader graph early
(`GeometryManager::device_update_displacement_images`).
This only handled Cycles image nodes however, not OSL nodes, so
if any `texture` calls were made in OSL those would be missed and
therefore crash when accessed on the GPU. Unfortunately it is not
simple to determine which textures referenced by OSL are needed
for displacement, so the solution for now is to simply load all of
them early if true displacement is used.
This patch also fixes the result of the displacement shader not
being used properly in OptiX.

Maniphest Tasks: T104240

Differential Revision: https://developer.blender.org/D17162
This commit is contained in:
Patrick Mours 2023-01-31 16:35:47 +01:00
parent ce42906b89
commit fa9fc59b56
Notes: blender-bot 2023-05-22 12:40:41 +02:00
Referenced by issue #104240, Blender 3.5 alpha: OPTIX OSL texture loading broken
2 changed files with 34 additions and 2 deletions

View File

@ -161,7 +161,10 @@ ccl_device_inline void osl_eval_nodes(KernelGlobals kg,
/* shadeindex = */ 0);
# endif
if (globals.Ci) {
if constexpr (type == SHADER_TYPE_DISPLACEMENT) {
sd->P = globals.P;
}
else if (globals.Ci) {
flatten_closure_tree(kg, sd, path_flag, globals.Ci);
}
}

View File

@ -23,7 +23,10 @@
#include "subd/patch_table.h"
#include "subd/split.h"
#include "kernel/osl/globals.h"
#ifdef WITH_OSL
# include "kernel/osl/globals.h"
# include "kernel/osl/services.h"
#endif
#include "util/foreach.h"
#include "util/log.h"
@ -1671,6 +1674,7 @@ void GeometryManager::device_update_displacement_images(Device *device,
TaskPool pool;
ImageManager *image_manager = scene->image_manager;
set<int> bump_images;
bool has_osl_node = false;
foreach (Geometry *geom, scene->geometry) {
if (geom->is_modified()) {
/* Geometry-level check for hair shadow transparency.
@ -1690,6 +1694,9 @@ void GeometryManager::device_update_displacement_images(Device *device,
continue;
}
foreach (ShaderNode *node, shader->graph->nodes) {
if (node->special_type == SHADER_SPECIAL_TYPE_OSL) {
has_osl_node = true;
}
if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
continue;
}
@ -1705,6 +1712,28 @@ void GeometryManager::device_update_displacement_images(Device *device,
}
}
}
#ifdef WITH_OSL
/* If any OSL node is used for displacement, it may reference a texture. But it's
* unknown which ones, so have to load them all. */
if (has_osl_node) {
set<OSLRenderServices *> services_shared;
device->foreach_device([&services_shared](Device *sub_device) {
OSLGlobals *og = (OSLGlobals *)sub_device->get_cpu_osl_memory();
services_shared.insert(og->services);
});
for (OSLRenderServices *services : services_shared) {
for (auto it = services->textures.begin(); it != services->textures.end(); ++it) {
if (it->second->handle.get_manager() == image_manager) {
const int slot = it->second->handle.svm_slot();
bump_images.insert(slot);
}
}
}
}
#endif
foreach (int slot, bump_images) {
pool.push(function_bind(
&ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));