Add Chromium-only Blender WebEngine parity work
This commit is contained in:
54
blender-5.2.0/intern/cycles/kernel/util/colorspace.h
Normal file
54
blender-5.2.0/intern/cycles/kernel/util/colorspace.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "util/types_spectrum.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device float3 xyz_to_rgb(KernelGlobals kg, const float3 xyz)
|
||||
{
|
||||
return make_float3(dot(make_float3(kernel_data.film.xyz_to_r), xyz),
|
||||
dot(make_float3(kernel_data.film.xyz_to_g), xyz),
|
||||
dot(make_float3(kernel_data.film.xyz_to_b), xyz));
|
||||
}
|
||||
|
||||
ccl_device float3 xyz_to_rgb_clamped(KernelGlobals kg, const float3 xyz)
|
||||
{
|
||||
return max(xyz_to_rgb(kg, xyz), zero_float3());
|
||||
}
|
||||
|
||||
ccl_device float3 rec709_to_rgb(KernelGlobals kg, const float3 rec709)
|
||||
{
|
||||
return (kernel_data.film.is_rec709) ?
|
||||
rec709 :
|
||||
make_float3(dot(make_float3(kernel_data.film.rec709_to_r), rec709),
|
||||
dot(make_float3(kernel_data.film.rec709_to_g), rec709),
|
||||
dot(make_float3(kernel_data.film.rec709_to_b), rec709));
|
||||
}
|
||||
|
||||
template<class T> ccl_device auto linear_rgb_to_gray(KernelGlobals kg, const T c)
|
||||
{
|
||||
return dot(c, make_float3(kernel_data.film.rgb_to_y));
|
||||
}
|
||||
|
||||
ccl_device_inline Spectrum rgb_to_spectrum(const float3 rgb)
|
||||
{
|
||||
return rgb;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 spectrum_to_rgb(Spectrum s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
ccl_device float spectrum_to_gray(KernelGlobals kg, Spectrum c)
|
||||
{
|
||||
return linear_rgb_to_gray(kg, spectrum_to_rgb(c));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
169
blender-5.2.0/intern/cycles/kernel/util/differential.h
Normal file
169
blender-5.2.0/intern/cycles/kernel/util/differential.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
|
||||
|
||||
ccl_device void differential_transfer(ccl_private differential3 *surface_dP,
|
||||
const differential3 ray_dP,
|
||||
const float3 ray_D,
|
||||
const differential3 ray_dD,
|
||||
const float3 surface_Ng,
|
||||
const float ray_t)
|
||||
{
|
||||
/* ray differential transfer through homogeneous medium, to
|
||||
* compute dPdx/dy at a shading point from the incoming ray */
|
||||
|
||||
const float3 tmp = ray_D / dot(ray_D, surface_Ng);
|
||||
const float3 tmpx = ray_dP.dx + ray_t * ray_dD.dx;
|
||||
const float3 tmpy = ray_dP.dy + ray_t * ray_dD.dy;
|
||||
|
||||
surface_dP->dx = tmpx - dot(tmpx, surface_Ng) * tmp;
|
||||
surface_dP->dy = tmpy - dot(tmpy, surface_Ng) * tmp;
|
||||
}
|
||||
|
||||
ccl_device void differential_incoming(ccl_private differential3 *dI, const differential3 dD)
|
||||
{
|
||||
/* compute dIdx/dy at a shading point, we just need to negate the
|
||||
* differential of the ray direction */
|
||||
|
||||
dI->dx = -dD.dx;
|
||||
dI->dy = -dD.dy;
|
||||
}
|
||||
|
||||
ccl_device void differential_dudv(ccl_private differential *du,
|
||||
ccl_private differential *dv,
|
||||
float3 dPdu,
|
||||
float3 dPdv,
|
||||
differential3 dP,
|
||||
const float3 Ng)
|
||||
{
|
||||
/* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
|
||||
* from the primitive, we can compute dudx/dy and dvdx/dy. these are
|
||||
* mainly used for differentials of arbitrary mesh attributes. */
|
||||
|
||||
/* find most stable axis to project to 2D */
|
||||
const float xn = fabsf(Ng.x);
|
||||
const float yn = fabsf(Ng.y);
|
||||
const float zn = fabsf(Ng.z);
|
||||
|
||||
if (zn < xn || zn < yn) {
|
||||
if (yn < xn || yn < zn) {
|
||||
dPdu.x = dPdu.y;
|
||||
dPdv.x = dPdv.y;
|
||||
dP.dx.x = dP.dx.y;
|
||||
dP.dy.x = dP.dy.y;
|
||||
}
|
||||
|
||||
dPdu.y = dPdu.z;
|
||||
dPdv.y = dPdv.z;
|
||||
dP.dx.y = dP.dx.z;
|
||||
dP.dy.y = dP.dy.z;
|
||||
}
|
||||
|
||||
/* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
|
||||
* and the same for dudy and dvdy. the denominator is the same for both
|
||||
* solutions, so we compute it only once.
|
||||
*
|
||||
* `dP.dx = dPdu * dudx + dPdv * dvdx;`
|
||||
* `dP.dy = dPdu * dudy + dPdv * dvdy;` */
|
||||
|
||||
float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y);
|
||||
|
||||
if (det != 0.0f) {
|
||||
det = 1.0f / det;
|
||||
}
|
||||
|
||||
du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det;
|
||||
dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det;
|
||||
|
||||
du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det;
|
||||
dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det;
|
||||
}
|
||||
|
||||
ccl_device differential differential_zero()
|
||||
{
|
||||
differential d;
|
||||
d.dx = 0.0f;
|
||||
d.dy = 0.0f;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
ccl_device differential3 differential3_zero()
|
||||
{
|
||||
differential3 d;
|
||||
d.dx = zero_float3();
|
||||
d.dy = zero_float3();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Compact ray differentials that are just a radius to reduce memory usage and access cost
|
||||
* on GPUs, basically cone tracing.
|
||||
*
|
||||
* See above for more accurate reference implementations of ray differentials. */
|
||||
|
||||
ccl_device_forceinline float differential_zero_compact()
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float differential_make_compact(const float dD)
|
||||
{
|
||||
return dD;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float differential_make_compact(const differential3 dD)
|
||||
{
|
||||
return 0.5f * (len(dD.dx) + len(dD.dy));
|
||||
}
|
||||
|
||||
ccl_device_forceinline float differential_make_compact(const dual3 D)
|
||||
{
|
||||
return 0.5f * (len(D.dx) + len(D.dy));
|
||||
}
|
||||
|
||||
ccl_device_forceinline float differential_incoming_compact(const float dD)
|
||||
{
|
||||
return dD;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float differential_transfer_compact(const float ray_dP,
|
||||
const float3 /* ray_D */,
|
||||
const float ray_dD,
|
||||
const float ray_t)
|
||||
{
|
||||
return ray_dP + ray_t * ray_dD;
|
||||
}
|
||||
|
||||
ccl_device_forceinline differential3 differential_from_compact(const float3 D, const float dD)
|
||||
{
|
||||
float3 dx;
|
||||
float3 dy;
|
||||
make_orthonormals(D, &dx, &dy);
|
||||
|
||||
differential3 d;
|
||||
d.dx = dD * dx;
|
||||
d.dy = dD * dy;
|
||||
return d;
|
||||
}
|
||||
|
||||
ccl_device void differential_dudv_compact(ccl_private differential *du,
|
||||
ccl_private differential *dv,
|
||||
const float3 dPdu,
|
||||
const float3 dPdv,
|
||||
const float dP,
|
||||
const float3 Ng)
|
||||
{
|
||||
/* TODO: can we speed this up? */
|
||||
differential_dudv(du, dv, dPdu, dPdv, differential_from_compact(Ng, dP), Ng);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
145
blender-5.2.0/intern/cycles/kernel/util/ies.h
Normal file
145
blender-5.2.0/intern/cycles/kernel/util/ies.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* IES Light */
|
||||
|
||||
ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg,
|
||||
const int ofs,
|
||||
const bool wrap_vlow,
|
||||
const bool wrap_vhigh,
|
||||
const int v,
|
||||
const int v_num,
|
||||
const float v_frac,
|
||||
const int h)
|
||||
{
|
||||
/* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
|
||||
* of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
|
||||
* with this would be to lookup the corresponding value on the other side of the pole, but since
|
||||
* the horizontal coordinates might be nonuniform, this would require yet another interpolation.
|
||||
* Therefore, the assumption is made that the light is going to be symmetrical, which means that
|
||||
* we can just take the corresponding value at the current horizontal coordinate. */
|
||||
|
||||
#define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v))
|
||||
|
||||
/* Look up the inner two points directly. */
|
||||
const float c = IES_LOOKUP(v + 1);
|
||||
const float b = IES_LOOKUP(v);
|
||||
|
||||
/* Look up first point, or fall back to second point if not available. */
|
||||
float a = b;
|
||||
if (v > 0) {
|
||||
a = IES_LOOKUP(v - 1);
|
||||
}
|
||||
else if (wrap_vlow) {
|
||||
a = IES_LOOKUP(1);
|
||||
}
|
||||
|
||||
/* Look up last point, or fall back to third point if not available. */
|
||||
float d = c;
|
||||
if (v + 2 < v_num) {
|
||||
d = IES_LOOKUP(v + 2);
|
||||
}
|
||||
else if (wrap_vhigh) {
|
||||
d = IES_LOOKUP(v_num - 2);
|
||||
}
|
||||
|
||||
#undef IES_LOOKUP
|
||||
|
||||
return cubic_interp(a, b, c, d, v_frac);
|
||||
}
|
||||
|
||||
ccl_device_inline float kernel_ies_interp(KernelGlobals kg,
|
||||
const int slot,
|
||||
const float h_angle,
|
||||
const float v_angle)
|
||||
{
|
||||
/* Find offset of the IES data in the table. */
|
||||
int ofs = __float_as_int(kernel_data_fetch(ies, slot));
|
||||
if (ofs == -1) {
|
||||
return 100.0f;
|
||||
}
|
||||
|
||||
const int h_num = __float_as_int(kernel_data_fetch(ies, ofs++));
|
||||
const int v_num = __float_as_int(kernel_data_fetch(ies, ofs++));
|
||||
|
||||
#define IES_LOOKUP_ANGLE_H(h) kernel_data_fetch(ies, ofs + (h))
|
||||
#define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
|
||||
|
||||
/* Check whether the angle is within the bounds of the IES texture. */
|
||||
const float v_low = IES_LOOKUP_ANGLE_V(0);
|
||||
const float v_high = IES_LOOKUP_ANGLE_V(v_num - 1);
|
||||
const float h_low = IES_LOOKUP_ANGLE_H(0);
|
||||
const float h_high = IES_LOOKUP_ANGLE_H(h_num - 1);
|
||||
if (v_angle < v_low || v_angle >= v_high) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (h_angle < h_low || h_angle >= h_high) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* If the texture covers the full 360° range horizontally, wrap around the lookup
|
||||
* to get proper cubic interpolation. Otherwise, just set the out-of-range values to zero.
|
||||
* Similar logic for V, but there we check the lower and upper wrap separately. */
|
||||
const bool wrap_h = (h_low < 1e-7f && h_high > M_2PI_F - 1e-7f);
|
||||
const bool wrap_vlow = (v_low < 1e-7f);
|
||||
const bool wrap_vhigh = (v_high > M_PI_F - 1e-7f);
|
||||
|
||||
/* Lookup the angles to find the table position. */
|
||||
int h_i;
|
||||
int v_i;
|
||||
/* TODO(lukas): Consider using bisection.
|
||||
* Probably not worth it for the vast majority of IES files. */
|
||||
for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++) {
|
||||
;
|
||||
}
|
||||
for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++) {
|
||||
;
|
||||
}
|
||||
|
||||
const float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
|
||||
const float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
|
||||
|
||||
#undef IES_LOOKUP_ANGLE_H
|
||||
#undef IES_LOOKUP_ANGLE_V
|
||||
|
||||
/* Skip forward to the actual intensity data. */
|
||||
ofs += h_num + v_num;
|
||||
|
||||
/* Interpolate the inner two points directly. */
|
||||
const float b = interpolate_ies_vertical(
|
||||
kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i);
|
||||
const float c = interpolate_ies_vertical(
|
||||
kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1);
|
||||
|
||||
/* Interpolate first point, or fall back to second point if not available. */
|
||||
float a = b;
|
||||
if (h_i > 0) {
|
||||
a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i - 1);
|
||||
}
|
||||
else if (wrap_h) {
|
||||
/* The last entry (360°) equals the first one, so we need to wrap around to the one before. */
|
||||
a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_num - 2);
|
||||
}
|
||||
|
||||
/* Interpolate last point, or fall back to second point if not available. */
|
||||
float d = b;
|
||||
if (h_i + 2 < h_num) {
|
||||
d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 2);
|
||||
}
|
||||
else if (wrap_h) {
|
||||
/* Same logic here, wrap around to the second element if necessary. */
|
||||
d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, 1);
|
||||
}
|
||||
|
||||
/* Cubic interpolation can result in negative values, so get rid of them. */
|
||||
return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
192
blender-5.2.0/intern/cycles/kernel/util/image_2d.h
Normal file
192
blender-5.2.0/intern/cycles/kernel/util/image_2d.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/sample/lcg.h"
|
||||
|
||||
#include "util/atomic.h"
|
||||
#include "util/defines.h"
|
||||
#include "util/math_fast.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_forceinline int kernel_image_udim_map(KernelGlobals kg,
|
||||
const int id,
|
||||
ccl_private float2 &uv)
|
||||
{
|
||||
if (id >= 0) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const int tx = (int)uv.x;
|
||||
const int ty = (int)uv.y;
|
||||
if (tx < 0 || ty < 0 || tx >= 10) {
|
||||
return KERNEL_IMAGE_NONE;
|
||||
}
|
||||
|
||||
int udim_id = -id - 1;
|
||||
const int num_udims = kernel_data_fetch(image_texture_udims, udim_id++).tile;
|
||||
const int tile = 1001 + 10 * ty + tx;
|
||||
|
||||
for (int i = 0; i < num_udims; i++) {
|
||||
const KernelImageUDIM udim = kernel_data_fetch(image_texture_udims, udim_id++);
|
||||
if (udim.tile == tile) {
|
||||
/* If we found the tile, offset the UVs to be relative to it. */
|
||||
uv.x -= tx;
|
||||
uv.y -= ty;
|
||||
return udim.image_texture_id;
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_IMAGE_NONE;
|
||||
}
|
||||
|
||||
ccl_device_forceinline bool kernel_image_tile_wrap(const ExtensionType extension,
|
||||
ccl_private float2 &uv)
|
||||
{
|
||||
/* Wrapping. */
|
||||
switch (extension) {
|
||||
case EXTENSION_REPEAT:
|
||||
uv = uv - floor(uv);
|
||||
return true;
|
||||
case EXTENSION_CLIP:
|
||||
return (uv.x >= 0.0f && uv.x <= 1.0f && uv.y >= 0.0f && uv.y <= 1.0f);
|
||||
case EXTENSION_EXTEND:
|
||||
uv = clamp(uv, zero_float2(), one_float2());
|
||||
return true;
|
||||
case EXTENSION_MIRROR: {
|
||||
const float2 t = uv * 0.5f;
|
||||
uv = 2.0f * (t - floor(t));
|
||||
uv = select(uv >= one_float2(), 2.0f * one_float2() - uv, uv);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* From UV coordinates in 0..1 range, compute tile and pixel coordinates. */
|
||||
ccl_device_forceinline KernelTileDescriptor
|
||||
kernel_image_tile_map(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const ccl_global KernelImageTexture &tex,
|
||||
const uint image_texture_id,
|
||||
const dual2 uv,
|
||||
ccl_private float2 &xy)
|
||||
{
|
||||
/* Find mipmap level. Use squared lengths to avoid two sqrt operations,
|
||||
* compensating with 0.5 factor on the log2. */
|
||||
const float dudxy_sq = len_squared(make_float2(uv.dx.x, uv.dy.x)) * float(tex.width * tex.width);
|
||||
const float dvdxy_sq = len_squared(make_float2(uv.dx.y, uv.dy.y)) *
|
||||
float(tex.height * tex.height);
|
||||
|
||||
/* Limit max anisotropy ratio, to avoid loading too high mip resolutions
|
||||
* for stretched UV coordinates, which don't really benefit from it anyway. */
|
||||
const float maxdxy_sq = max(dudxy_sq, dvdxy_sq);
|
||||
const float mindxy_sq = min(dudxy_sq, dvdxy_sq);
|
||||
const float inv_aniso_ratio_sq = 1.0f / (16.0f * 16.0f);
|
||||
/* Native log2 is faster on GPU. */
|
||||
#ifdef __KERNEL_GPU__
|
||||
float flevel = 0.5f * log2(max(mindxy_sq, maxdxy_sq * inv_aniso_ratio_sq));
|
||||
#else
|
||||
float flevel = 0.5f * fast_log2f(max(mindxy_sq, maxdxy_sq * inv_aniso_ratio_sq));
|
||||
#endif
|
||||
|
||||
/* Select mipmap level. */
|
||||
if (sd->lcg_state != 0) {
|
||||
/* For rounding instead of flooring. */
|
||||
flevel += 0.5f;
|
||||
/* Randomize mip level, except for some cases like displacement or importance map. */
|
||||
const float transition = 0.5f;
|
||||
flevel += (lcg_step_float(&sd->lcg_state) - 0.5f) * transition;
|
||||
}
|
||||
else {
|
||||
/* When not using stochastic interpolation, round to higher level. */
|
||||
}
|
||||
flevel += kernel_data.image.mip_bias;
|
||||
const int level = clamp(int(flevel), 0, tex.tile_levels - 1);
|
||||
|
||||
/* Compute width of this mipmap level. */
|
||||
const int width = max(1, tex.width >> level);
|
||||
const int height = max(1, tex.height >> level);
|
||||
|
||||
/* Convert coordinates to pixel space.
|
||||
* Flip Y convention for tiles to match tx files. */
|
||||
xy = make_float2(uv.val.x * width, (1.0f - uv.val.y) * height);
|
||||
|
||||
/* Tile mapping */
|
||||
const int ix = clamp((int)xy.x, 0, width - 1);
|
||||
const int iy = clamp((int)xy.y, 0, height - 1);
|
||||
const int tile_size_shift = tex.tile_size_shift;
|
||||
const int tile_size_padded = (1 << tile_size_shift) + KERNEL_IMAGE_TEX_PADDING * 2;
|
||||
|
||||
const int tile_x = ix >> tile_size_shift;
|
||||
const int tile_y = iy >> tile_size_shift;
|
||||
const int tile_offset = kernel_data_fetch(image_texture_tile_descriptors,
|
||||
tex.tile_descriptor_offset + level) +
|
||||
tile_x + tile_y * divide_up_by_shift(width, tile_size_shift);
|
||||
|
||||
KernelTileDescriptor tile_descriptor = kernel_data_fetch(
|
||||
image_texture_tile_descriptors, tex.tile_descriptor_offset + tile_offset);
|
||||
|
||||
const uint access_index = tex.tile_descriptor_offset + tile_offset;
|
||||
|
||||
if (!kernel_tile_descriptor_loaded(tile_descriptor)) {
|
||||
#ifdef __KERNEL_GPU__
|
||||
/* For GPU, mark load requested and cancel shader execution. */
|
||||
if (tile_descriptor == KERNEL_TILE_LOAD_NONE) {
|
||||
tile_descriptor = KERNEL_TILE_LOAD_REQUEST;
|
||||
/* Write load request for quick rejection of subsequent reads. */
|
||||
kernel_data_write(image_texture_tile_descriptors,
|
||||
tex.tile_descriptor_offset + tile_offset,
|
||||
tile_descriptor);
|
||||
/* Set access state that will be read back to host. Using a byte
|
||||
* instead of a bitmask avoids the need for atomics. */
|
||||
kernel_data_array(
|
||||
image_texture_tile_access_state)[access_index] = KERNEL_TILE_ACCESS_REQUESTED;
|
||||
}
|
||||
if (tile_descriptor == KERNEL_TILE_LOAD_REQUEST) {
|
||||
sd->flag |= SD_CACHE_MISS;
|
||||
}
|
||||
return tile_descriptor;
|
||||
#else
|
||||
/* For CPU, load tile immediately. */
|
||||
if (tile_descriptor != KERNEL_TILE_LOAD_FAILED) {
|
||||
KernelTileDescriptor &p_tile_descriptor =
|
||||
kg->image_texture_tile_descriptors.data[access_index];
|
||||
kg->image_load_requested_cpu(image_texture_id,
|
||||
level,
|
||||
tile_x << tile_size_shift,
|
||||
tile_y << tile_size_shift,
|
||||
p_tile_descriptor);
|
||||
tile_descriptor = p_tile_descriptor;
|
||||
}
|
||||
if (!kernel_tile_descriptor_loaded(tile_descriptor)) {
|
||||
return tile_descriptor;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Mark tile as used for cache eviction tracking. Read before writing as we
|
||||
* expect most of the time this was already written. */
|
||||
if (kernel_data_array(image_texture_tile_access_state)[access_index] != KERNEL_TILE_ACCESS_USED)
|
||||
{
|
||||
kernel_data_array(image_texture_tile_access_state)[access_index] = KERNEL_TILE_ACCESS_USED;
|
||||
}
|
||||
|
||||
/* Remap coordinates into tiled image space. */
|
||||
const int offset = kernel_tile_descriptor_offset(tile_descriptor);
|
||||
xy += make_float2(KERNEL_IMAGE_TEX_PADDING - (tile_x << tile_size_shift) +
|
||||
offset * tile_size_padded,
|
||||
KERNEL_IMAGE_TEX_PADDING - (tile_y << tile_size_shift));
|
||||
|
||||
return tile_descriptor;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
266
blender-5.2.0/intern/cycles/kernel/util/image_3d.h
Normal file
266
blender-5.2.0/intern/cycles/kernel/util/image_3d.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/sample/lcg.h"
|
||||
|
||||
#include "util/types_image.h"
|
||||
|
||||
#if !defined(__KERNEL_METAL__) && !defined(__KERNEL_ONEAPI__)
|
||||
# ifdef WITH_NANOVDB
|
||||
# include "kernel/util/nanovdb.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
/* Make template functions private so symbols don't conflict between kernels with different
|
||||
* instruction sets. */
|
||||
namespace {
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
|
||||
/* Cubic interpolation weights. */
|
||||
ccl_device_forceinline void fill_cubic_weights(float3 w[4], float3 t)
|
||||
{
|
||||
w[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f);
|
||||
w[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f);
|
||||
w[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f);
|
||||
w[3] = (1.0f / 6.0f) * t * t * t;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** Return the sample position for stochastical one-tap sampling.
|
||||
* From "Stochastic Texture Filtering": https://arxiv.org/abs/2305.05810
|
||||
* \{ */
|
||||
ccl_device_inline float3 interp_tricubic_stochastic(const float3 P, ccl_private float3 &rand)
|
||||
{
|
||||
const float3 p = floor(P);
|
||||
const float3 t = P - p;
|
||||
|
||||
float3 w[4];
|
||||
fill_cubic_weights(w, t);
|
||||
|
||||
/* For reservoir sampling, always accept the first in the stream. */
|
||||
float3 total_weight = w[0];
|
||||
float3 offset = make_float3(-1.0f);
|
||||
|
||||
for (int j = 1; j < 4; j++) {
|
||||
total_weight += w[j];
|
||||
const float3 thresh = w[j] / total_weight;
|
||||
const auto mask = rand < thresh;
|
||||
offset = select(mask, make_float3(float(j) - 1.0f), offset);
|
||||
rand = select(mask, safe_divide(rand, thresh), safe_divide(rand - thresh, 1.0f - thresh));
|
||||
}
|
||||
|
||||
return p + offset;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 interp_trilinear_stochastic(const float3 P, const float3 rand)
|
||||
{
|
||||
const float3 p = floor(P);
|
||||
const float3 t = P - p;
|
||||
return select(rand < t, p + 1.0f, p);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 interp_stochastic(const float3 P,
|
||||
ccl_private InterpolationType &interpolation,
|
||||
ccl_private float3 &rand)
|
||||
{
|
||||
float3 P_new = P;
|
||||
if (interpolation == INTERPOLATION_CUBIC) {
|
||||
P_new = interp_tricubic_stochastic(P, rand);
|
||||
}
|
||||
else if (interpolation == INTERPOLATION_LINEAR) {
|
||||
P_new = interp_trilinear_stochastic(P, rand);
|
||||
}
|
||||
else {
|
||||
kernel_assert(interpolation == INTERPOLATION_CLOSEST);
|
||||
}
|
||||
interpolation = INTERPOLATION_CLOSEST;
|
||||
return P_new;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
template<typename OutT, typename Acc>
|
||||
ccl_device OutT kernel_image_interp_trilinear_nanovdb(ccl_private Acc &acc, const float3 P)
|
||||
{
|
||||
const float3 floor_P = floor(P);
|
||||
const float3 t = P - floor_P;
|
||||
const int3 index = make_int3(floor_P);
|
||||
|
||||
const int ix = index.x;
|
||||
const int iy = index.y;
|
||||
const int iz = index.z;
|
||||
|
||||
return mix(mix(mix(OutT(acc.getValue(make_int3(ix, iy, iz))),
|
||||
OutT(acc.getValue(make_int3(ix, iy, iz + 1))),
|
||||
t.z),
|
||||
mix(OutT(acc.getValue(make_int3(ix, iy + 1, iz + 1))),
|
||||
OutT(acc.getValue(make_int3(ix, iy + 1, iz))),
|
||||
1.0f - t.z),
|
||||
t.y),
|
||||
mix(mix(OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz))),
|
||||
OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz + 1))),
|
||||
t.z),
|
||||
mix(OutT(acc.getValue(make_int3(ix + 1, iy, iz + 1))),
|
||||
OutT(acc.getValue(make_int3(ix + 1, iy, iz))),
|
||||
1.0f - t.z),
|
||||
1.0f - t.y),
|
||||
t.x);
|
||||
}
|
||||
|
||||
template<typename OutT, typename Acc>
|
||||
ccl_device OutT kernel_image_interp_tricubic_nanovdb(ccl_private Acc &acc, const float3 P)
|
||||
{
|
||||
# if defined(__KERNEL_HIP__)
|
||||
/* Explicitly unroll for HIP compiler to unroll the loop. Without this the render result is wrong
|
||||
* on a specific platform/compiler combinations. ALso don't rely on the `unroll` hint as it has
|
||||
* a performance impact. See #152126 and discussion/benchmark in !152321. */
|
||||
|
||||
const float3 floor_P = floor(P);
|
||||
const float3 t = P - floor_P;
|
||||
const int3 index = make_int3(floor_P);
|
||||
|
||||
const int xc[4] = {index.x - 1, index.x, index.x + 1, index.x + 2};
|
||||
const int yc[4] = {index.y - 1, index.y, index.y + 1, index.y + 2};
|
||||
const int zc[4] = {index.z - 1, index.z, index.z + 1, index.z + 2};
|
||||
|
||||
float3 weight[4];
|
||||
fill_cubic_weights(weight, t);
|
||||
|
||||
# define DATA(x, y, z) (OutT(acc.getValue(make_int3(xc[x], yc[y], zc[z]))))
|
||||
# define COL_TERM(col, row) \
|
||||
(weight[col].y * (weight[0].x * DATA(0, col, row) + weight[1].x * DATA(1, col, row) + \
|
||||
weight[2].x * DATA(2, col, row) + weight[3].x * DATA(3, col, row)))
|
||||
# define ROW_TERM(row) \
|
||||
(weight[row].z * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
|
||||
|
||||
/* Actual interpolation. */
|
||||
return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
|
||||
|
||||
# undef COL_TERM
|
||||
# undef ROW_TERM
|
||||
# undef DATA
|
||||
|
||||
# else
|
||||
|
||||
const float3 floor_P = floor(P);
|
||||
const float3 t = P - floor_P;
|
||||
const int3 index = make_int3(floor_P) - make_int3(1);
|
||||
|
||||
float3 w[4];
|
||||
fill_cubic_weights(w, t);
|
||||
|
||||
OutT result = make_zero<OutT>();
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
OutT col_term_acc = make_zero<OutT>();
|
||||
for (int j = 0; j < 4; j++) {
|
||||
col_term_acc += w[j].y * (w[0].x * (OutT(acc.getValue(index + make_int3(0, j, k)))) +
|
||||
w[1].x * (OutT(acc.getValue(index + make_int3(1, j, k)))) +
|
||||
w[2].x * (OutT(acc.getValue(index + make_int3(2, j, k)))) +
|
||||
w[3].x * (OutT(acc.getValue(index + make_int3(3, j, k)))));
|
||||
}
|
||||
result += w[k].z * col_term_acc;
|
||||
}
|
||||
|
||||
return result;
|
||||
# endif
|
||||
}
|
||||
|
||||
template<typename OutT, typename T>
|
||||
# if defined(__KERNEL_METAL__)
|
||||
__attribute__((noinline))
|
||||
# else
|
||||
ccl_device_noinline
|
||||
# endif
|
||||
OutT kernel_image_interp_nanovdb(const ccl_global KernelImageInfo &info,
|
||||
float3 P,
|
||||
const InterpolationType interp)
|
||||
{
|
||||
ccl_global nanovdb::NanoGrid<T> *const grid = (ccl_global nanovdb::NanoGrid<T> *)info.data;
|
||||
|
||||
if (interp == INTERPOLATION_CLOSEST) {
|
||||
nanovdb::ReadAccessor<T> acc(grid->tree().root());
|
||||
return OutT(acc.getValue(make_int3(floor(P))));
|
||||
}
|
||||
|
||||
nanovdb::CachedReadAccessor<T> acc(grid->tree().root());
|
||||
if (interp == INTERPOLATION_LINEAR) {
|
||||
return kernel_image_interp_trilinear_nanovdb<OutT>(acc, P);
|
||||
}
|
||||
|
||||
return kernel_image_interp_tricubic_nanovdb<OutT>(acc, P);
|
||||
}
|
||||
#endif /* WITH_NANOVDB */
|
||||
|
||||
ccl_device float4 kernel_image_interp_3d(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const int image_texture_id,
|
||||
float3 P,
|
||||
InterpolationType interp,
|
||||
const bool stochastic)
|
||||
{
|
||||
#ifdef WITH_NANOVDB
|
||||
const ccl_global KernelImageTexture &tex = kernel_data_fetch(image_textures, image_texture_id);
|
||||
const ccl_global KernelImageInfo &info = kernel_data_fetch(image_info, tex.image_info_id);
|
||||
|
||||
if (tex.use_transform_3d) {
|
||||
P = transform_point(&tex.transform_3d, P);
|
||||
}
|
||||
|
||||
InterpolationType interpolation = (interp == INTERPOLATION_NONE) ?
|
||||
(InterpolationType)info.interpolation :
|
||||
interp;
|
||||
|
||||
if (stochastic) {
|
||||
float3 rand = lcg_step_float3(&sd->lcg_state);
|
||||
P = interp_stochastic(P, interpolation, rand);
|
||||
}
|
||||
|
||||
const ImageDataType data_type = (ImageDataType)info.data_type;
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
|
||||
const float f = kernel_image_interp_nanovdb<float, float>(info, P, interpolation);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
|
||||
const float3 f = kernel_image_interp_nanovdb<float3, packed_float3>(info, P, interpolation);
|
||||
return make_float4(f, 1.0f);
|
||||
}
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT4) {
|
||||
return kernel_image_interp_nanovdb<float4, float4>(info, P, interpolation);
|
||||
}
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
|
||||
const float f = kernel_image_interp_nanovdb<float, nanovdb::FpN>(info, P, interpolation);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
|
||||
const float f = kernel_image_interp_nanovdb<float, nanovdb::Fp16>(info, P, interpolation);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
if (data_type == IMAGE_DATA_TYPE_NANOVDB_EMPTY) {
|
||||
return zero_float4();
|
||||
}
|
||||
#else
|
||||
(void)kg;
|
||||
(void)sd;
|
||||
(void)image_texture_id;
|
||||
(void)P;
|
||||
(void)interp;
|
||||
(void)stochastic;
|
||||
#endif
|
||||
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
} /* Namespace. */
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
74
blender-5.2.0/intern/cycles/kernel/util/lookup_table.h
Normal file
74
blender-5.2.0/intern/cycles/kernel/util/lookup_table.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Interpolated lookup table access */
|
||||
|
||||
ccl_device float lookup_table_read(KernelGlobals kg, float x, const int offset, const int size)
|
||||
{
|
||||
x = saturatef(x) * (size - 1);
|
||||
|
||||
const int index = min(float_to_int(x), size - 1);
|
||||
const int nindex = min(index + 1, size - 1);
|
||||
const float t = x - index;
|
||||
|
||||
const float data0 = kernel_data_fetch(lookup_table, index + offset);
|
||||
if (t == 0.0f) {
|
||||
return data0;
|
||||
}
|
||||
|
||||
const float data1 = kernel_data_fetch(lookup_table, nindex + offset);
|
||||
return (1.0f - t) * data0 + t * data1;
|
||||
}
|
||||
|
||||
ccl_device float lookup_table_read_2D(
|
||||
KernelGlobals kg, const float x, float y, const int offset, const int xsize, const int ysize)
|
||||
{
|
||||
y = saturatef(y) * (ysize - 1);
|
||||
|
||||
const int index = min(float_to_int(y), ysize - 1);
|
||||
const int nindex = min(index + 1, ysize - 1);
|
||||
const float t = y - index;
|
||||
|
||||
const float data0 = lookup_table_read(kg, x, offset + xsize * index, xsize);
|
||||
if (t == 0.0f) {
|
||||
return data0;
|
||||
}
|
||||
|
||||
const float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize);
|
||||
return (1.0f - t) * data0 + t * data1;
|
||||
}
|
||||
|
||||
ccl_device float lookup_table_read_3D(KernelGlobals kg,
|
||||
const float x,
|
||||
float y,
|
||||
float z,
|
||||
const int offset,
|
||||
const int xsize,
|
||||
const int ysize,
|
||||
const int zsize)
|
||||
{
|
||||
z = saturatef(z) * (zsize - 1);
|
||||
|
||||
const int index = min(float_to_int(z), zsize - 1);
|
||||
const int nindex = min(index + 1, zsize - 1);
|
||||
const float t = z - index;
|
||||
|
||||
const float data0 = lookup_table_read_2D(kg, x, y, offset + xsize * ysize * index, xsize, ysize);
|
||||
if (t == 0.0f) {
|
||||
return data0;
|
||||
}
|
||||
|
||||
const float data1 = lookup_table_read_2D(
|
||||
kg, x, y, offset + xsize * ysize * nindex, xsize, ysize);
|
||||
return (1.0f - t) * data0 + t * data1;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
436
blender-5.2.0/intern/cycles/kernel/util/nanovdb.h
Normal file
436
blender-5.2.0/intern/cycles/kernel/util/nanovdb.h
Normal file
@@ -0,0 +1,436 @@
|
||||
/* SPDX-FileCopyrightText: 2020-2021 Contributors to the OpenVDB Project
|
||||
* SPDX-FileCopyrightText: 2023-2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This is an extract from NanoVDB.h, with minimal code needed for kernel side access to grids. The
|
||||
* original headers are not compatible with Metal due to missing address space qualifiers. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/defines.h"
|
||||
#include "util/math_int3.h"
|
||||
#include "util/types_base.h"
|
||||
#include "util/types_int3.h"
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
# include <climits>
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define NANOVDB_USE_SINGLE_ROOT_KEY
|
||||
#define NANOVDB_DATA_ALIGNMENT 32 // NOLINT
|
||||
|
||||
namespace nanovdb {
|
||||
|
||||
/* Utilities */
|
||||
|
||||
template<typename DstT, typename SrcT>
|
||||
const ccl_device ccl_global DstT *PtrAdd(const ccl_global SrcT *p, int64_t offset)
|
||||
{
|
||||
return reinterpret_cast<const ccl_global DstT *>(reinterpret_cast<const ccl_global char *>(p) +
|
||||
offset);
|
||||
}
|
||||
|
||||
/* Coord */
|
||||
|
||||
using Coord = int3;
|
||||
using PackedCoord = packed_int3;
|
||||
|
||||
/* Mask */
|
||||
|
||||
template<uint32_t LOG2DIM> struct Mask {
|
||||
ccl_static_constexpr uint32_t SIZE = 1U << (3 * LOG2DIM);
|
||||
ccl_static_constexpr uint32_t WORD_COUNT = SIZE >> 6;
|
||||
uint64_t mWords[WORD_COUNT];
|
||||
|
||||
ccl_device_inline_method bool isOff(const uint32_t n) const ccl_global
|
||||
{
|
||||
return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63)));
|
||||
}
|
||||
};
|
||||
|
||||
/* Grid */
|
||||
|
||||
template<typename TreeT> struct alignas(NANOVDB_DATA_ALIGNMENT) Grid {
|
||||
ccl_static_constexpr int MaxNameSize = 256;
|
||||
uint64_t mMagic;
|
||||
uint64_t mChecksum;
|
||||
uint32_t mVersion;
|
||||
uint32_t mFlags;
|
||||
uint32_t mGridIndex;
|
||||
uint32_t mGridCount;
|
||||
uint64_t mGridSize;
|
||||
char mGridName[MaxNameSize];
|
||||
uint8_t mMap[264];
|
||||
uint8_t mWorldBBox[48]; // double[6], but no doubles in Metal
|
||||
uint8_t mVoxelSize[24]; // double[3], but no doubles in Metal
|
||||
uint32_t mGridClass;
|
||||
uint32_t mGridType;
|
||||
uint32_t mData0;
|
||||
uint64_t mData1, mData2;
|
||||
|
||||
using BuildType = typename TreeT::BuildType;
|
||||
|
||||
const ccl_device_inline_method ccl_global TreeT &tree() const ccl_global
|
||||
{
|
||||
return *reinterpret_cast<const ccl_global TreeT *>(this + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/* Tree */
|
||||
|
||||
template<typename RootT> struct alignas(NANOVDB_DATA_ALIGNMENT) Tree {
|
||||
int64_t mNodeOffset[4];
|
||||
uint32_t mNodeCount[3];
|
||||
uint32_t mTileCount[3];
|
||||
uint64_t mVoxelCount;
|
||||
|
||||
using ValueType = typename RootT::ValueType;
|
||||
using BuildType = typename RootT::BuildType;
|
||||
|
||||
const ccl_device_inline_method ccl_global RootT &root() const ccl_global
|
||||
{
|
||||
return *reinterpret_cast<const ccl_global RootT *>(
|
||||
mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
/* RootNode */
|
||||
|
||||
template<typename ChildT> struct alignas(NANOVDB_DATA_ALIGNMENT) RootNode {
|
||||
using ValueType = typename ChildT::ValueType;
|
||||
using BuildType = typename ChildT::BuildType;
|
||||
|
||||
#ifdef NANOVDB_USE_SINGLE_ROOT_KEY
|
||||
using KeyT = uint64_t;
|
||||
static ccl_device_inline_method uint64_t CoordToKey(const Coord ijk)
|
||||
{
|
||||
return (uint64_t(uint32_t(ijk.z) >> ChildT::TOTAL)) |
|
||||
(uint64_t(uint32_t(ijk.y) >> ChildT::TOTAL) << 21) |
|
||||
(uint64_t(uint32_t(ijk.x) >> ChildT::TOTAL) << 42);
|
||||
}
|
||||
#else
|
||||
using KeyT = Coord;
|
||||
static ccl_device_inline_method Coord CoordToKey(const CoordT ijk)
|
||||
{
|
||||
return ijk & ~ChildT::MASK;
|
||||
}
|
||||
#endif
|
||||
PackedCoord mBBox[2];
|
||||
uint32_t mTableSize;
|
||||
|
||||
ValueType mBackground;
|
||||
ValueType mMinimum;
|
||||
ValueType mMaximum;
|
||||
float mAverage;
|
||||
float mStdDevi;
|
||||
|
||||
struct alignas(NANOVDB_DATA_ALIGNMENT) Tile {
|
||||
KeyT key;
|
||||
int64_t child;
|
||||
uint32_t state;
|
||||
ValueType value;
|
||||
};
|
||||
|
||||
const ccl_device_inline_method ccl_global Tile *probeTile(const Coord ijk) const ccl_global
|
||||
{
|
||||
const auto key = CoordToKey(ijk);
|
||||
const ccl_global Tile *p = reinterpret_cast<const ccl_global Tile *>(this + 1);
|
||||
const ccl_global Tile *q = p + mTableSize;
|
||||
for (; p < q; ++p) {
|
||||
if (p->key == key) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ccl_device_inline_method ccl_global ChildT *getChild(const ccl_global Tile *tile) const
|
||||
ccl_global
|
||||
{
|
||||
return PtrAdd<ChildT>(this, tile->child);
|
||||
}
|
||||
|
||||
ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
|
||||
};
|
||||
|
||||
/* InternalNode */
|
||||
|
||||
template<typename ChildT, const uint32_t Log2Dim = ChildT::LOG2DIM + 1>
|
||||
struct alignas(NANOVDB_DATA_ALIGNMENT) InternalNode {
|
||||
using ValueType = typename ChildT::ValueType;
|
||||
using BuildType = typename ChildT::BuildType;
|
||||
|
||||
union Tile {
|
||||
ValueType value;
|
||||
int64_t child;
|
||||
};
|
||||
|
||||
PackedCoord mBBox[2];
|
||||
uint64_t mFlags;
|
||||
Mask<Log2Dim> mValueMask;
|
||||
Mask<Log2Dim> mChildMask;
|
||||
|
||||
ValueType mMinimum;
|
||||
ValueType mMaximum;
|
||||
float mAverage;
|
||||
float mStdDevi;
|
||||
|
||||
alignas(32) Tile mTable[1u << (3 * Log2Dim)];
|
||||
|
||||
const ccl_device_inline_method ccl_global ChildT *getChild(const uint32_t n) const ccl_global
|
||||
{
|
||||
return PtrAdd<ChildT>(this, mTable[n].child);
|
||||
}
|
||||
|
||||
ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
|
||||
ccl_static_constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL;
|
||||
ccl_static_constexpr uint32_t DIM = 1u << TOTAL;
|
||||
ccl_static_constexpr uint32_t SIZE = 1u << (3 * LOG2DIM);
|
||||
ccl_static_constexpr uint32_t MASK = (1u << TOTAL) - 1u;
|
||||
ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
|
||||
|
||||
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
|
||||
{
|
||||
return (((ijk.x & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) |
|
||||
(((ijk.y & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ((ijk.z & MASK) >> ChildT::TOTAL);
|
||||
}
|
||||
};
|
||||
|
||||
/* LeafData */
|
||||
|
||||
template<typename ValueT, const uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData {
|
||||
using ValueType = ValueT;
|
||||
using BuildType = ValueT;
|
||||
|
||||
PackedCoord mBBoxMin;
|
||||
uint8_t mBBoxDif[3];
|
||||
uint8_t mFlags;
|
||||
Mask<LOG2DIM> mValueMask;
|
||||
|
||||
ValueType mMinimum;
|
||||
ValueType mMaximum;
|
||||
float mAverage;
|
||||
float mStdDevi;
|
||||
alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
|
||||
|
||||
ccl_device_inline_method ValueType getValue(const uint32_t i) const ccl_global
|
||||
{
|
||||
return mValues[i];
|
||||
}
|
||||
};
|
||||
|
||||
/* LeafFnBase */
|
||||
|
||||
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafFnBase {
|
||||
PackedCoord mBBoxMin;
|
||||
uint8_t mBBoxDif[3];
|
||||
uint8_t mFlags;
|
||||
Mask<LOG2DIM> mValueMask;
|
||||
|
||||
float mMinimum;
|
||||
float mQuantum;
|
||||
uint16_t mMin, mMax, mAvg, mDev;
|
||||
};
|
||||
|
||||
/* LeafData<Fp16> */
|
||||
|
||||
class Fp16 {};
|
||||
|
||||
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, LOG2DIM> {
|
||||
using ValueType = float;
|
||||
using BuildType = Fp16;
|
||||
|
||||
LeafFnBase<LOG2DIM> base;
|
||||
alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
|
||||
|
||||
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
|
||||
{
|
||||
return mCode[i] * base.mQuantum + base.mMinimum;
|
||||
}
|
||||
};
|
||||
|
||||
/* LeafData<FpN> */
|
||||
|
||||
class FpN {};
|
||||
|
||||
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, LOG2DIM> {
|
||||
using ValueType = float;
|
||||
using BuildType = FpN;
|
||||
|
||||
LeafFnBase<LOG2DIM> base;
|
||||
|
||||
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
|
||||
{
|
||||
const int b = base.mFlags >> 5;
|
||||
uint32_t code = reinterpret_cast<const ccl_global uint32_t *>(this + 1)[i >> (5 - b)];
|
||||
code >>= (i & ((32 >> b) - 1)) << b;
|
||||
code &= (1 << (1 << b)) - 1;
|
||||
return float(code) * base.mQuantum + base.mMinimum;
|
||||
}
|
||||
};
|
||||
|
||||
/* LeafNode */
|
||||
|
||||
template<typename BuildT, const uint32_t Log2Dim = 3>
|
||||
struct alignas(NANOVDB_DATA_ALIGNMENT) LeafNode {
|
||||
using DataType = LeafData<BuildT, Log2Dim>;
|
||||
using ValueType = typename DataType::ValueType;
|
||||
using BuildType = typename DataType::BuildType;
|
||||
|
||||
DataType data;
|
||||
|
||||
ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
|
||||
ccl_static_constexpr uint32_t TOTAL = LOG2DIM;
|
||||
ccl_static_constexpr uint32_t DIM = 1u << TOTAL;
|
||||
ccl_static_constexpr uint32_t SIZE = 1u << 3 * LOG2DIM;
|
||||
ccl_static_constexpr uint32_t MASK = (1u << LOG2DIM) - 1u;
|
||||
ccl_static_constexpr uint32_t LEVEL = 0;
|
||||
|
||||
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
|
||||
{
|
||||
return ((ijk.x & MASK) << (2 * LOG2DIM)) | ((ijk.y & MASK) << LOG2DIM) | (ijk.z & MASK);
|
||||
}
|
||||
|
||||
ccl_device_inline_method ValueType getValue(const uint32_t offset) const ccl_global
|
||||
{
|
||||
return data.getValue(offset);
|
||||
}
|
||||
|
||||
ccl_device_inline_method ValueType getValue(const Coord ijk) const ccl_global
|
||||
{
|
||||
return getValue(CoordToOffset(ijk));
|
||||
}
|
||||
};
|
||||
|
||||
/* Template Specializations */
|
||||
|
||||
template<typename BuildT> using NanoLeaf = LeafNode<BuildT, 3>;
|
||||
template<typename BuildT> using NanoLower = InternalNode<NanoLeaf<BuildT>, 4>;
|
||||
template<typename BuildT> using NanoUpper = InternalNode<NanoLower<BuildT>, 5>;
|
||||
template<typename BuildT> using NanoRoot = RootNode<NanoUpper<BuildT>>;
|
||||
template<typename BuildT> using NanoTree = Tree<NanoRoot<BuildT>>;
|
||||
template<typename BuildT> using NanoGrid = Grid<NanoTree<BuildT>>;
|
||||
|
||||
/* ReadAccessor */
|
||||
|
||||
template<typename BuildT> class ReadAccessor {
|
||||
using RootT = NanoRoot<BuildT>;
|
||||
using LeafT = NanoLeaf<BuildT>;
|
||||
|
||||
mutable const ccl_global RootT *mRoot;
|
||||
|
||||
public:
|
||||
using ValueType = typename RootT::ValueType;
|
||||
|
||||
ccl_device_inline_method ReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
|
||||
|
||||
ccl_device_inline_method ValueType getValue(const Coord ijk) const
|
||||
{
|
||||
const ccl_global auto *tile = mRoot->probeTile(ijk);
|
||||
if (tile == nullptr) {
|
||||
return mRoot->mBackground;
|
||||
}
|
||||
if (tile->child == 0) {
|
||||
return tile->value;
|
||||
}
|
||||
|
||||
const ccl_global auto *upper = mRoot->getChild(tile);
|
||||
const uint32_t upper_n = upper->CoordToOffset(ijk);
|
||||
if (upper->mChildMask.isOff(upper_n)) {
|
||||
return upper->mTable[upper_n].value;
|
||||
}
|
||||
|
||||
const ccl_global auto *lower = upper->getChild(upper_n);
|
||||
const uint32_t lower_n = lower->CoordToOffset(ijk);
|
||||
if (lower->mChildMask.isOff(lower_n)) {
|
||||
return lower->mTable[lower_n].value;
|
||||
}
|
||||
|
||||
const ccl_global LeafT *leaf = lower->getChild(lower_n);
|
||||
return leaf->getValue(ijk);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename BuildT> class CachedReadAccessor {
|
||||
using RootT = NanoRoot<BuildT>;
|
||||
using UpperT = NanoUpper<BuildT>;
|
||||
using LowerT = NanoLower<BuildT>;
|
||||
using LeafT = NanoLeaf<BuildT>;
|
||||
|
||||
mutable Coord mKeys[3] = {make_int3(INT_MAX), make_int3(INT_MAX), make_int3(INT_MAX)};
|
||||
mutable const ccl_global RootT *mRoot = nullptr;
|
||||
mutable const ccl_global void *mNode[3] = {nullptr, nullptr, nullptr};
|
||||
|
||||
public:
|
||||
using ValueType = typename RootT::ValueType;
|
||||
|
||||
ccl_device_inline_method CachedReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
|
||||
|
||||
template<typename NodeT> ccl_device_inline_method bool isCached(const Coord ijk) const
|
||||
{
|
||||
return (ijk.x & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].x &&
|
||||
(ijk.y & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].y &&
|
||||
(ijk.z & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].z;
|
||||
}
|
||||
|
||||
ccl_device_inline_method ValueType getValueAndCache(const ccl_global RootT &node,
|
||||
const Coord ijk) const
|
||||
{
|
||||
if (const ccl_global auto *tile = node.probeTile(ijk)) {
|
||||
if (tile->child != 0) {
|
||||
const ccl_global auto *child = node.getChild(tile);
|
||||
insert(ijk, child);
|
||||
return getValueAndCache(*child, ijk);
|
||||
}
|
||||
return tile->value;
|
||||
}
|
||||
return node.mBackground;
|
||||
}
|
||||
|
||||
ccl_device_inline_method ValueType getValueAndCache(const ccl_global LeafT &node,
|
||||
const Coord ijk) const
|
||||
{
|
||||
return node.getValue(ijk);
|
||||
}
|
||||
|
||||
template<typename NodeT>
|
||||
ccl_device_inline_method ValueType getValueAndCache(const ccl_global NodeT &node,
|
||||
const Coord ijk) const
|
||||
{
|
||||
const uint32_t n = node.CoordToOffset(ijk);
|
||||
if (node.mChildMask.isOff(n)) {
|
||||
return node.mTable[n].value;
|
||||
}
|
||||
const ccl_global auto *child = node.getChild(n);
|
||||
insert(ijk, child);
|
||||
return getValueAndCache(*child, ijk);
|
||||
}
|
||||
|
||||
ccl_device_inline_method ValueType getValue(const Coord ijk) const
|
||||
{
|
||||
if (isCached<LeafT>(ijk)) {
|
||||
return getValueAndCache(*((const ccl_global LeafT *)mNode[0]), ijk);
|
||||
}
|
||||
if (isCached<LowerT>(ijk)) {
|
||||
return getValueAndCache(*((const ccl_global LowerT *)mNode[1]), ijk);
|
||||
}
|
||||
if (isCached<UpperT>(ijk)) {
|
||||
return getValueAndCache(*((const ccl_global UpperT *)mNode[2]), ijk);
|
||||
}
|
||||
return getValueAndCache(*mRoot, ijk);
|
||||
}
|
||||
|
||||
template<typename NodeT>
|
||||
ccl_device_inline_method void insert(const Coord ijk, const ccl_global NodeT *node) const
|
||||
{
|
||||
mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
|
||||
mNode[NodeT::LEVEL] = node;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nanovdb
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
28
blender-5.2.0/intern/cycles/kernel/util/profiler.h
Normal file
28
blender-5.2.0/intern/cycles/kernel/util/profiler.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
# include "util/profiling.h" // IWYU pragma: export
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
# define PROFILING_INIT(kg, event) \
|
||||
ProfilingHelper profiling_helper((ProfilingState *)&kg->profiler, event)
|
||||
# define PROFILING_EVENT(event) profiling_helper.set_event(event)
|
||||
# define PROFILING_INIT_FOR_SHADER(kg, event) \
|
||||
ProfilingWithShaderHelper profiling_helper((ProfilingState *)&kg->profiler, event)
|
||||
# define PROFILING_SHADER(object, shader) \
|
||||
profiling_helper.set_shader(object, (shader) & SHADER_MASK);
|
||||
#else
|
||||
# define PROFILING_INIT(kg, event)
|
||||
# define PROFILING_EVENT(event)
|
||||
# define PROFILING_INIT_FOR_SHADER(kg, event)
|
||||
# define PROFILING_SHADER(object, shader)
|
||||
#endif /* !__KERNEL_GPU__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
Reference in New Issue
Block a user