Files
workinf_Blender_Wasm/blender-5.2.0/intern/cycles/kernel/osl/services.cpp
2026-08-12 04:47:48 -04:00

643 lines
25 KiB
C++

/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
/* TODO(sergey): There is a bit of headers dependency hell going on
* here, so for now we just put here. In the future it might be better
* to have dedicated file for such tweaks.
*/
#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#include "util/log.h"
#include "util/string.h"
#include "util/types_image.h"
#include "kernel/geom/shader_data.h"
#include "kernel/bvh/bvh.h"
#include "kernel/osl/globals.h"
#include "kernel/osl/services.h"
#include "kernel/osl/services_shared.h"
#include "kernel/osl/strings.h"
#include "kernel/osl/types.h"
CCL_NAMESPACE_BEGIN
/* RenderServices implementation */
ImageManager *OSLRenderServices::image_manager = nullptr;
OSLRenderServices::OSLRenderServices(const int device_type)
/* Dummy texture system pointer so OSL doesn't create its own. Such an opaque texture system
* pointer is supported and normally would be done with the OSL_NO_DEFAULT_TEXTURESYSTEM
* build option, but we want to work with OSL builds that don't have it. */
: OSL::RendererServices(reinterpret_cast<OSL::TextureSystem *>(1)), device_type_(device_type)
{
}
OSLRenderServices::~OSLRenderServices() = default;
int OSLRenderServices::supports(string_view feature) const
{
#ifdef WITH_OPTIX
if (feature == "OptiX") {
return device_type_ == DEVICE_OPTIX;
}
#else
(void)feature;
#endif
return false;
}
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSL::TransformationPtr /*xform*/,
const float time)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
if (globals == nullptr || globals->sd == nullptr) {
return false;
}
return osl_shared_get_object_matrix_motion(
globals->kg, globals->sd, reinterpret_cast<float *>(&result), time);
}
bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSL::TransformationPtr /*xform*/,
const float time)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
if (globals == nullptr || globals->sd == nullptr) {
return false;
}
return osl_shared_get_object_inverse_matrix_motion(
globals->kg, globals->sd, reinterpret_cast<float *>(&result), time);
}
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSLUStringHash from,
const float /*time*/)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_get_named_matrix(globals->kg, from, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSLUStringHash to,
const float /*time*/)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_get_named_inverse_matrix(globals->kg, to, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSL::TransformationPtr /*xform*/)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
if (globals == nullptr || globals->sd == nullptr) {
return false;
}
return osl_shared_get_object_matrix(
globals->kg, globals->sd, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSL::TransformationPtr /*xform*/)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
if (globals == nullptr || globals->sd == nullptr) {
return false;
}
return osl_shared_get_object_inverse_matrix(
globals->kg, globals->sd, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSLUStringHash from)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_get_named_matrix(globals->kg, from, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSLUStringHash to)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_get_named_inverse_matrix(globals->kg, to, reinterpret_cast<float *>(&result));
}
bool OSLRenderServices::get_array_attribute(OSL::ShaderGlobals * /*sg*/,
bool /*derivatives*/,
OSLUStringHash /*object*/,
const TypeDesc /*type*/,
OSLUStringHash /*name*/,
const int /*index*/,
void * /*val*/)
{
return false;
}
bool OSLRenderServices::get_object_standard_attribute(ShaderGlobals *globals,
ShaderData *sd,
OSLUStringHash name,
const TypeDesc type,
bool derivatives,
void *val)
{
return osl_shared_get_object_standard_attribute(
globals->kg, globals, sd, name, type, derivatives, val);
}
bool OSLRenderServices::get_background_attribute(ShaderGlobals *globals,
ShaderData *sd,
OSLUStringHash name,
const TypeDesc type,
bool derivatives,
void *val)
{
return osl_shared_get_background_attribute(
globals->kg, globals, sd, name, type, derivatives, val);
}
bool OSLRenderServices::get_camera_attribute(
ShaderGlobals *globals, OSLUStringHash name, TypeDesc type, bool derivatives, void *val)
{
return osl_shared_get_camera_attribute(globals->kg, globals, name, type, derivatives, val);
}
bool OSLRenderServices::get_attribute(OSL::ShaderGlobals *sg,
bool derivatives,
OSLUStringHash object_name,
const TypeDesc type,
OSLUStringHash name,
void *val)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
if (globals == nullptr) {
return false;
}
return get_attribute(globals, globals->sd, derivatives, object_name, type, name, val);
}
bool OSLRenderServices::get_attribute(ShaderGlobals *globals,
ShaderData *sd,
bool derivatives,
OSLUStringHash object_name,
const TypeDesc type,
OSLUStringHash name,
void *val)
{
if (globals == nullptr) {
return false;
}
const ThreadKernelGlobalsCPU *kg = globals->kg;
if (sd->shader == SHADER_NONE) {
/* Camera shader. */
return osl_shared_get_camera_attribute(kg, globals, name, type, derivatives, val);
}
/* lookup of attribute on another object */
int object;
if (object_name != DeviceStrings::u_empty) {
const OSLGlobals::ObjectNameMap::iterator it = kg->osl.globals->object_name_map.find(
object_name);
if (it == kg->osl.globals->object_name_map.end()) {
return false;
}
object = it->second;
}
else {
object = sd->object;
}
/* find attribute on object */
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, name.hash());
if (is_attribute_found(desc)) {
return osl_shared_get_object_attribute(kg, sd, desc, type, derivatives, val);
}
/* not found in attribute, check standard object info */
return osl_shared_get_object_standard_attribute(kg, globals, sd, name, type, derivatives, val);
}
bool OSLRenderServices::get_userdata(bool /*derivatives*/,
OSLUStringHash /*name*/,
const TypeDesc /*type*/,
OSL::ShaderGlobals * /*sg*/,
void * /*val*/)
{
return false; /* disabled by lockgeom */
}
OSL::TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(
OSLUStringHash filename, OSL::ShadingContext *context, const OSL::TextureOpt *opt)
{
return get_texture_handle(to_ustring(filename), context, opt);
}
OSL::TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(
OSL::ustring filename, OSL::ShadingContext * /*context*/, const OSL::TextureOpt * /*options*/)
{
/* Note the mutex lock in find_or_insert() is not so bad for performance because
* this function only gets called once per texture handle to create it, not for
* every texture access. */
auto [it, inserted] = textures.find_or_insert(filename,
OSLTextureHandle(OSLTextureHandleType::IMAGE));
if (inserted) {
/* Add new texture to image manager. */
const ImageHandle handle = image_manager->add_image(filename.string(), ImageParams());
OSLTextureHandle *texture_handle = const_cast<OSLTextureHandle *>(&it->second);
*texture_handle = OSLTextureHandle(handle);
}
/* Construct texture handle. We encode this as a packed integer cast to a pointer,
* which is also what we use on the GPU. OSL does not dereference these.
*
* Note that we must keep the OSLTextureHandle in the map alive, as it holds
* the ImageHandle that keeps the image loaded in the manager. */
return reinterpret_cast<OSL::TextureSystem::TextureHandle *>(
OSL_TEXTURE_HANDLE_ENCODE(it->second.type, it->second.id));
}
bool OSLRenderServices::good(OSL::TextureSystem::TextureHandle *texture_handle)
{
return OSL_TEXTURE_HANDLE_TYPE(texture_handle) != OSLTextureHandleType::IMAGE ||
OSL_TEXTURE_HANDLE_ID(texture_handle) != KERNEL_IMAGE_NONE;
}
bool OSLRenderServices::is_udim(OSL::TextureSystem::TextureHandle *texture_handle)
{
return OSL_TEXTURE_HANDLE_TYPE(texture_handle) == OSLTextureHandleType::IMAGE &&
OSL_TEXTURE_HANDLE_ID(texture_handle) <= -1;
}
bool OSLRenderServices::texture(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread * /*texture_thread_info*/,
OSL::TextureOpt &options,
OSL::ShaderGlobals *sg,
float s,
float t,
const float dsdx,
const float dtdx,
const float dsdy,
const float dtdy,
const int nchannels,
float *result,
float * /*dresultds*/,
float * /*dresultdt*/,
OSLUStringHash * /*errormessage*/)
{
if (texture_handle == nullptr) {
if (texture_filenames_seen_.insert(filename).second) {
LOG_WARNING << "Open Shading Language texture call can not resolve " << filename.c_str()
<< ", filename must be a compile-time constant";
}
return false;
}
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_texture(globals->kg,
globals,
texture_handle,
static_cast<void *>(&options),
s,
t,
dsdx,
dtdx,
dsdy,
dtdy,
nchannels,
result);
}
bool OSLRenderServices::texture3d(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread * /*texture_thread_info*/,
OSL::TextureOpt & /*options*/,
OSL::ShaderGlobals *sg,
const OSL::Vec3 &P,
const OSL::Vec3 &dPdx,
const OSL::Vec3 &dPdy,
const OSL::Vec3 &dPdz,
const int nchannels,
float *result,
float * /*dresultds*/,
float * /*dresultdt*/,
float * /*dresultdr*/,
OSLUStringHash * /*errormessage*/)
{
if (texture_handle == nullptr) {
if (texture_filenames_seen_.insert(filename).second) {
LOG_WARNING << "Open Shading Language texture3d call can not resolve " << filename.c_str()
<< ", filename must be a constant";
}
return false;
}
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_texture3d(globals->kg,
globals,
texture_handle,
make_float3(P.x, P.y, P.z),
make_float3(dPdx.x, dPdx.y, dPdx.z),
make_float3(dPdy.x, dPdy.y, dPdy.z),
make_float3(dPdz.x, dPdz.y, dPdz.z),
nchannels,
result);
}
bool OSLRenderServices::environment(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread * /*thread_info*/,
OSL::TextureOpt & /*options*/,
OSL::ShaderGlobals *sg,
const OSL::Vec3 &R,
const OSL::Vec3 &dRdx,
const OSL::Vec3 &dRdy,
const int nchannels,
float *result,
float * /*dresultds*/,
float * /*dresultdt*/,
OSLUStringHash * /*errormessage*/)
{
if (texture_handle == nullptr) {
if (texture_filenames_seen_.insert(filename).second) {
LOG_WARNING << "Open Shading Language environment call can not resolve " << filename.c_str()
<< ", filename must be a constant string after optimization";
}
return false;
}
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
return osl_shared_environment(globals->kg,
globals,
texture_handle,
make_float3(R.x, R.y, R.z),
make_float3(dRdx.x, dRdx.y, dRdx.z),
make_float3(dRdy.x, dRdy.y, dRdy.z),
nchannels,
result);
}
bool OSLRenderServices::get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread * /*texture_thread_info*/,
OSL::ShaderGlobals *sg,
const int /*subimage*/,
OSLUStringHash dataname,
const TypeDesc datatype,
void *data,
OSLUStringHash * /*errormessage*/)
{
if (texture_handle == nullptr) {
if (texture_filenames_seen_.insert(filename).second) {
LOG_WARNING << "Open Shading Language gettextureinfo call can not resolve "
<< filename.c_str() << ", filename must be a constant";
}
return false;
}
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
const ThreadKernelGlobalsCPU *kg = globals->kg;
return osl_shared_get_texture_info(
kg, texture_handle, make_float2(0.0f, 0.0f), false, dataname, datatype, data);
}
bool OSLRenderServices::get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
float s,
float t,
TexturePerthread * /*texture_thread_info*/,
OSL::ShaderGlobals *sg,
const int /*subimage*/,
OSLUStringHash dataname,
const TypeDesc datatype,
void *data,
OSLUStringHash * /*errormessage*/)
{
if (texture_handle == nullptr) {
if (texture_filenames_seen_.insert(filename).second) {
LOG_WARNING << "Open Shading Language gettextureinfo call can not resolve "
<< filename.c_str() << ", filename must be a constant";
}
return false;
}
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
const ThreadKernelGlobalsCPU *kg = globals->kg;
return osl_shared_get_texture_info(
kg, texture_handle, make_float2(s, t), true, dataname, datatype, data);
}
int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals * /*sg*/,
OSLUStringHash /*filename*/,
const OSL::Vec3 & /*center*/,
const float /*radius*/,
const int /*max_points*/,
bool /*sort*/,
#if OSL_LIBRARY_VERSION_CODE >= 11400
int * /*indices*/,
#else
size_t * /*out_indices*/,
#endif
float * /*out_distances*/,
const int /*derivs_offset*/)
{
return 0;
}
int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals * /*sg*/
,
OSLUStringHash /*filename*/,
#if OSL_LIBRARY_VERSION_CODE >= 11400
const int * /*indices*/,
#else
size_t * /*indices*/,
#endif
const int /*count*/,
OSLUStringHash /*attr_name*/,
const TypeDesc /*attr_type*/,
void * /*out_data*/)
{
return 0;
}
bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals * /*sg*/,
OSLUStringHash /*filename*/,
const OSL::Vec3 & /*pos*/,
const int /*nattribs*/,
const OSLUStringRep * /*names*/,
const TypeDesc * /*types*/,
const void ** /*data*/)
{
return false;
}
bool OSLRenderServices::trace(TraceOpt &options,
OSL::ShaderGlobals *sg,
const OSL::Vec3 &P,
const OSL::Vec3 &dPdx,
const OSL::Vec3 &dPdy,
const OSL::Vec3 &R,
const OSL::Vec3 &dRdx,
const OSL::Vec3 &dRdy)
{
/* todo: options.shader support, maybe options.traceset */
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
ShaderData *sd = globals->sd;
const ThreadKernelGlobalsCPU *kg = globals->kg;
if (sd == nullptr) {
return false;
}
/* setup ray */
Ray ray;
ray.P = make_float3(P.x, P.y, P.z);
ray.D = make_float3(R.x, R.y, R.z);
ray.tmin = options.mindist;
ray.tmax = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist;
ray.time = sd->time;
ray.self.object = OBJECT_NONE;
ray.self.prim = PRIM_NONE;
ray.self.light_object = OBJECT_NONE;
ray.self.light_prim = PRIM_NONE;
if (ray.tmin == 0.0f) {
/* avoid self-intersections */
if (ray.P == sd->P) {
ray.self.object = sd->object;
ray.self.prim = sd->prim;
}
}
/* ray differentials */
differential3 dP;
dP.dx = make_float3(dPdx.x, dPdx.y, dPdx.z);
dP.dy = make_float3(dPdy.x, dPdy.y, dPdy.z);
ray.dP = differential_make_compact(dP);
differential3 dD;
dD.dx = make_float3(dRdx.x, dRdx.y, dRdx.z);
dD.dy = make_float3(dRdy.x, dRdy.y, dRdy.z);
ray.dD = differential_make_compact(dD);
/* allocate trace data */
OSLTraceData *tracedata = globals->tracedata;
tracedata->ray = ray;
tracedata->setup = false;
tracedata->init = true;
tracedata->hit = false;
tracedata->self_hit = false;
/* Can't ray-trace from shaders like displacement, before BVH exists. */
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
return false;
}
if (options.traceset == DeviceStrings::u_traceset_only_local) {
LocalIntersection local_isect;
scene_intersect_local(kg, &ray, &local_isect, sd->object, nullptr, 1);
if (local_isect.num_hits > 0) {
tracedata->isect = local_isect.hits[0];
tracedata->hit = true;
tracedata->self_hit = true;
}
}
else {
/* Ray-trace, leaving out shadow opaque to avoid early exit. */
const PathRayVisibility visibility = PATH_RAY_VISIBILITY_ALL &
~PATH_RAY_VISIBILITY_SHADOW_OPAQUE;
tracedata->hit = scene_intersect(kg, &ray, visibility, &tracedata->isect);
if (tracedata->hit) {
tracedata->self_hit = tracedata->isect.object == sd->object;
}
}
return tracedata->hit;
}
bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg,
OSLUStringHash source,
OSLUStringHash name,
const TypeDesc type,
void *val,
bool derivatives)
{
ShaderGlobals *globals = reinterpret_cast<ShaderGlobals *>(sg);
const ThreadKernelGlobalsCPU *kg = globals->kg;
OSLTraceData *tracedata = globals->tracedata;
if (source == DeviceStrings::u_trace && tracedata->init) {
if (name == DeviceStrings::u_hit) {
return set_attribute<int>(tracedata->hit, type, derivatives, val);
}
if (tracedata->hit) {
if (name == DeviceStrings::u_hitdist) {
return set_attribute(tracedata->isect.t, type, derivatives, val);
}
ShaderData *sd = &tracedata->sd;
if (!tracedata->setup) {
/* lazy shader data setup */
shader_setup_from_ray(kg, sd, &tracedata->ray, &tracedata->isect);
tracedata->setup = true;
}
if (name == DeviceStrings::u_hitself) {
return set_attribute(float(tracedata->self_hit), type, derivatives, val);
}
if (name == DeviceStrings::u_N) {
return set_attribute(sd->N, type, derivatives, val);
}
if (name == DeviceStrings::u_Ng) {
return set_attribute(sd->Ng, type, derivatives, val);
}
if (name == DeviceStrings::u_P) {
const differential3 dP = differential_from_compact(sd->Ng, sd->dP);
return set_attribute(dual3(sd->P, dP.dx, dP.dy), type, derivatives, val);
}
if (name == DeviceStrings::u_I) {
const differential3 dI = differential_from_compact(sd->wi, sd->dI);
return set_attribute(dual3(sd->wi, dI.dx, dI.dy), type, derivatives, val);
}
if (name == DeviceStrings::u_u) {
return set_attribute(dual1(sd->u, sd->du.dx, sd->du.dy), type, derivatives, val);
}
if (name == DeviceStrings::u_v) {
return set_attribute(dual1(sd->v, sd->dv.dx, sd->dv.dy), type, derivatives, val);
}
return get_attribute(globals, sd, derivatives, DeviceStrings::u_empty, type, name, val);
}
}
return false;
}
CCL_NAMESPACE_END