Files
test/intern/cycles/kernel/geom/geom_patch.h
Brecht Van Lommel 0803119725 Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.

Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.

Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles

Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)

For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.

Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-21 14:55:54 +02:00

461 lines
13 KiB
C

/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2013 Pixar
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*/
#pragma once
CCL_NAMESPACE_BEGIN
typedef struct PatchHandle {
int array_index, patch_index, vert_index;
} PatchHandle;
ccl_device_inline int patch_map_resolve_quadrant(float median, float *u, float *v)
{
int quadrant = -1;
if (*u < median) {
if (*v < median) {
quadrant = 0;
}
else {
quadrant = 1;
*v -= median;
}
}
else {
if (*v < median) {
quadrant = 3;
}
else {
quadrant = 2;
*v -= median;
}
*u -= median;
}
return quadrant;
}
/* retrieve PatchHandle from patch coords */
ccl_device_inline PatchHandle
patch_map_find_patch(const KernelGlobals *kg, int object, int patch, float u, float v)
{
PatchHandle handle;
kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
int node = (object_patch_map_offset(kg, object) + patch) / 2;
float median = 0.5f;
for (int depth = 0; depth < 0xff; depth++) {
float delta = median * 0.5f;
int quadrant = patch_map_resolve_quadrant(median, &u, &v);
kernel_assert(quadrant >= 0);
uint child = kernel_tex_fetch(__patches, node + quadrant);
/* is the quadrant a hole? */
if (!(child & PATCH_MAP_NODE_IS_SET)) {
handle.array_index = -1;
return handle;
}
uint index = child & PATCH_MAP_NODE_INDEX_MASK;
if (child & PATCH_MAP_NODE_IS_LEAF) {
handle.array_index = kernel_tex_fetch(__patches, index + 0);
handle.patch_index = kernel_tex_fetch(__patches, index + 1);
handle.vert_index = kernel_tex_fetch(__patches, index + 2);
return handle;
}
else {
node = index;
}
median = delta;
}
/* no leaf found */
kernel_assert(0);
handle.array_index = -1;
return handle;
}
ccl_device_inline void patch_eval_bspline_weights(float t, float *point, float *deriv)
{
/* The four uniform cubic B-Spline basis functions evaluated at t */
float inv_6 = 1.0f / 6.0f;
float t2 = t * t;
float t3 = t * t2;
point[0] = inv_6 * (1.0f - 3.0f * (t - t2) - t3);
point[1] = inv_6 * (4.0f - 6.0f * t2 + 3.0f * t3);
point[2] = inv_6 * (1.0f + 3.0f * (t + t2 - t3));
point[3] = inv_6 * t3;
/* Derivatives of the above four basis functions at t */
deriv[0] = -0.5f * t2 + t - 0.5f;
deriv[1] = 1.5f * t2 - 2.0f * t;
deriv[2] = -1.5f * t2 + t + 0.5f;
deriv[3] = 0.5f * t2;
}
ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits, float *s, float *t)
{
int boundary = ((bits >> 8) & 0xf);
if (boundary & 1) {
t[2] -= t[0];
t[1] += 2 * t[0];
t[0] = 0;
}
if (boundary & 2) {
s[1] -= s[3];
s[2] += 2 * s[3];
s[3] = 0;
}
if (boundary & 4) {
t[1] -= t[3];
t[2] += 2 * t[3];
t[3] = 0;
}
if (boundary & 8) {
s[2] -= s[0];
s[1] += 2 * s[0];
s[0] = 0;
}
}
ccl_device_inline int patch_eval_depth(uint patch_bits)
{
return (patch_bits & 0xf);
}
ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
{
bool non_quad_root = (patch_bits >> 4) & 0x1;
int depth = patch_eval_depth(patch_bits);
if (non_quad_root) {
return 1.0f / (float)(1 << (depth - 1));
}
else {
return 1.0f / (float)(1 << depth);
}
}
ccl_device_inline void patch_eval_normalize_coords(uint patch_bits, float *u, float *v)
{
float frac = patch_eval_param_fraction(patch_bits);
int iu = (patch_bits >> 22) & 0x3ff;
int iv = (patch_bits >> 12) & 0x3ff;
/* top left corner */
float pu = (float)iu * frac;
float pv = (float)iv * frac;
/* normalize uv coordinates */
*u = (*u - pu) / frac;
*v = (*v - pv) / frac;
}
/* retrieve patch control indices */
ccl_device_inline int patch_eval_indices(const KernelGlobals *kg,
const PatchHandle *handle,
int channel,
int indices[PATCH_MAX_CONTROL_VERTS])
{
int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
/* XXX: regular patches only */
for (int i = 0; i < 16; i++) {
indices[i] = kernel_tex_fetch(__patches, index_base + i);
}
return 16;
}
/* evaluate patch basis functions */
ccl_device_inline void patch_eval_basis(const KernelGlobals *kg,
const PatchHandle *handle,
float u,
float v,
float weights[PATCH_MAX_CONTROL_VERTS],
float weights_du[PATCH_MAX_CONTROL_VERTS],
float weights_dv[PATCH_MAX_CONTROL_VERTS])
{
uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
float d_scale = 1 << patch_eval_depth(patch_bits);
bool non_quad_root = (patch_bits >> 4) & 0x1;
if (non_quad_root) {
d_scale *= 0.5f;
}
patch_eval_normalize_coords(patch_bits, &u, &v);
/* XXX: regular patches only for now. */
float s[4], t[4], ds[4], dt[4];
patch_eval_bspline_weights(u, s, ds);
patch_eval_bspline_weights(v, t, dt);
patch_eval_adjust_boundary_weights(patch_bits, s, t);
patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
for (int k = 0; k < 4; k++) {
for (int l = 0; l < 4; l++) {
weights[4 * k + l] = s[l] * t[k];
weights_du[4 * k + l] = ds[l] * t[k] * d_scale;
weights_dv[4 * k + l] = s[l] * dt[k] * d_scale;
}
}
}
/* generic function for evaluating indices and weights from patch coords */
ccl_device_inline int patch_eval_control_verts(const KernelGlobals *kg,
int object,
int patch,
float u,
float v,
int channel,
int indices[PATCH_MAX_CONTROL_VERTS],
float weights[PATCH_MAX_CONTROL_VERTS],
float weights_du[PATCH_MAX_CONTROL_VERTS],
float weights_dv[PATCH_MAX_CONTROL_VERTS])
{
PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
kernel_assert(handle.array_index >= 0);
int num_control = patch_eval_indices(kg, &handle, channel, indices);
patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
return num_control;
}
/* functions for evaluating attributes on patches */
ccl_device float patch_eval_float(const KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
float *du,
float *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
float val = 0.0f;
if (du)
*du = 0.0f;
if (dv)
*dv = 0.0f;
for (int i = 0; i < num_control; i++) {
float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
val += v * weights[i];
if (du)
*du += v * weights_du[i];
if (dv)
*dv += v * weights_dv[i];
}
return val;
}
ccl_device float2 patch_eval_float2(const KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
float2 *du,
float2 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
float2 val = make_float2(0.0f, 0.0f);
if (du)
*du = make_float2(0.0f, 0.0f);
if (dv)
*dv = make_float2(0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
float2 v = kernel_tex_fetch(__attributes_float2, offset + indices[i]);
val += v * weights[i];
if (du)
*du += v * weights_du[i];
if (dv)
*dv += v * weights_dv[i];
}
return val;
}
ccl_device float3 patch_eval_float3(const KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
float3 *du,
float3 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
float3 val = make_float3(0.0f, 0.0f, 0.0f);
if (du)
*du = make_float3(0.0f, 0.0f, 0.0f);
if (dv)
*dv = make_float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
val += v * weights[i];
if (du)
*du += v * weights_du[i];
if (dv)
*dv += v * weights_dv[i];
}
return val;
}
ccl_device float4 patch_eval_float4(const KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
float4 *du,
float4 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (du)
*du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (dv)
*dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
float4 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]);
val += v * weights[i];
if (du)
*du += v * weights_du[i];
if (dv)
*dv += v * weights_dv[i];
}
return val;
}
ccl_device float4 patch_eval_uchar4(const KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
float4 *du,
float4 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (du)
*du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (dv)
*dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
float4 v = color_srgb_to_linear_v4(
color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i])));
val += v * weights[i];
if (du)
*du += v * weights_du[i];
if (dv)
*dv += v * weights_dv[i];
}
return val;
}
CCL_NAMESPACE_END