Blender V5.0
cycles/kernel/device/cpu/image.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
9
10#include "util/half.h"
11
13
14/* Make template functions private so symbols don't conflict between kernels with different
15 * instruction sets. */
16namespace {
17
18#define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
19 { \
20 u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
21 u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
22 u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
23 u[3] = (1.0f / 6.0f) * t * t * t; \
24 } \
25 (void)0
26
27ccl_device_inline float frac(const float x, int *ix)
28{
29 int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
30 *ix = i;
31 return x - (float)i;
32}
33
34template<typename TexT, typename OutT = float4> struct TextureInterpolator {
35
36 static ccl_always_inline OutT zero()
37 {
38 if constexpr (std::is_same_v<OutT, float4>) {
39 return zero_float4();
40 }
41 else {
42 return 0.0f;
43 }
44 }
45
47 {
48 return r;
49 }
50
52 {
53 const float f = 1.0f / 255.0f;
54 return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
55 }
56
57 static ccl_always_inline float read(const uchar r)
58 {
59 return r * (1.0f / 255.0f);
60 }
61
62 static ccl_always_inline float read(const float r)
63 {
64 return r;
65 }
66
68 {
69 return half4_to_float4_image(r);
70 }
71
72 static ccl_always_inline float read(half r)
73 {
74 return half_to_float_image(r);
75 }
76
77 static ccl_always_inline float read(const uint16_t r)
78 {
79 return r * (1.0f / 65535.0f);
80 }
81
83 {
84 const float f = 1.0f / 65535.0f;
85 return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
86 }
87
88 /* Read 2D Texture Data
89 * Does not check if data request is in bounds. */
90 static ccl_always_inline OutT
91 read(const TexT *data, const int x, int y, const int width, const int /*height*/)
92 {
93 return read(data[y * width + x]);
94 }
95
96 /* Read 2D Texture Data Clip
97 * Returns transparent black if data request is out of bounds. */
98 static ccl_always_inline OutT
99 read_clip(const TexT *data, const int x, int y, const int width, const int height)
100 {
101 if (x < 0 || x >= width || y < 0 || y >= height) {
102 return zero();
103 }
104 return read(data[y * width + x]);
105 }
106
107 static ccl_always_inline int wrap_periodic(int x, const int width)
108 {
109 x %= width;
110 if (x < 0) {
111 x += width;
112 }
113 return x;
114 }
115
116 static ccl_always_inline int wrap_clamp(const int x, const int width)
117 {
118 return clamp(x, 0, width - 1);
119 }
120
121 static ccl_always_inline int wrap_mirror(const int x, const int width)
122 {
123 const int m = abs(x + (x < 0)) % (2 * width);
124 if (m >= width) {
125 return 2 * width - m - 1;
126 }
127 return m;
128 }
129
130 /* ******** 2D interpolation ******** */
131
132 static ccl_always_inline OutT interp_closest(const TextureInfo &info, const float x, float y)
133 {
134 const int width = info.width;
135 const int height = info.height;
136 int ix, iy;
137 frac(x * (float)width, &ix);
138 frac(y * (float)height, &iy);
139 switch (info.extension) {
140 case EXTENSION_REPEAT:
141 ix = wrap_periodic(ix, width);
142 iy = wrap_periodic(iy, height);
143 break;
144 case EXTENSION_CLIP:
145 /* No samples are inside the clip region. */
146 if (ix < 0 || ix >= width || iy < 0 || iy >= height) {
147 return zero();
148 }
149 break;
150 case EXTENSION_EXTEND:
151 ix = wrap_clamp(ix, width);
152 iy = wrap_clamp(iy, height);
153 break;
154 case EXTENSION_MIRROR:
155 ix = wrap_mirror(ix, width);
156 iy = wrap_mirror(iy, height);
157 break;
158 default:
159 kernel_assert(0);
160 return zero();
161 }
162
163 const TexT *data = (const TexT *)info.data;
164 return read(data, ix, iy, width, height);
165 }
166
167 static ccl_always_inline OutT interp_linear(const TextureInfo &info, const float x, float y)
168 {
169 const int width = info.width;
170 const int height = info.height;
171
172 /* A -0.5 offset is used to center the linear samples around the sample point. */
173 int ix, iy;
174 int nix, niy;
175 const float tx = frac(x * (float)width - 0.5f, &ix);
176 const float ty = frac(y * (float)height - 0.5f, &iy);
177 const TexT *data = (const TexT *)info.data;
178
179 switch (info.extension) {
180 case EXTENSION_REPEAT:
181 ix = wrap_periodic(ix, width);
182 nix = wrap_periodic(ix + 1, width);
183
184 iy = wrap_periodic(iy, height);
185 niy = wrap_periodic(iy + 1, height);
186 break;
187 case EXTENSION_CLIP:
188 /* No linear samples are inside the clip region. */
189 if (ix < -1 || ix >= width || iy < -1 || iy >= height) {
190 return zero();
191 }
192 nix = ix + 1;
193 niy = iy + 1;
194 return (1.0f - ty) * (1.0f - tx) * read_clip(data, ix, iy, width, height) +
195 (1.0f - ty) * tx * read_clip(data, nix, iy, width, height) +
196 ty * (1.0f - tx) * read_clip(data, ix, niy, width, height) +
197 ty * tx * read_clip(data, nix, niy, width, height);
198 case EXTENSION_EXTEND:
199 nix = wrap_clamp(ix + 1, width);
200 ix = wrap_clamp(ix, width);
201 niy = wrap_clamp(iy + 1, height);
202 iy = wrap_clamp(iy, height);
203 break;
204 case EXTENSION_MIRROR:
205 nix = wrap_mirror(ix + 1, width);
206 ix = wrap_mirror(ix, width);
207 niy = wrap_mirror(iy + 1, height);
208 iy = wrap_mirror(iy, height);
209 break;
210 default:
211 kernel_assert(0);
212 return zero();
213 }
214
215 return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) +
216 (1.0f - ty) * tx * read(data, nix, iy, width, height) +
217 ty * (1.0f - tx) * read(data, ix, niy, width, height) +
218 ty * tx * read(data, nix, niy, width, height);
219 }
220
221 static ccl_always_inline OutT interp_cubic(const TextureInfo &info, const float x, float y)
222 {
223 const int width = info.width;
224 const int height = info.height;
225
226 /* A -0.5 offset is used to center the cubic samples around the sample point. */
227 int ix, iy;
228 const float tx = frac(x * (float)width - 0.5f, &ix);
229 const float ty = frac(y * (float)height - 0.5f, &iy);
230
231 int pix, piy;
232 int nix, niy;
233 int nnix, nniy;
234
235 switch (info.extension) {
236 case EXTENSION_REPEAT:
237 ix = wrap_periodic(ix, width);
238 pix = wrap_periodic(ix - 1, width);
239 nix = wrap_periodic(ix + 1, width);
240 nnix = wrap_periodic(ix + 2, width);
241
242 iy = wrap_periodic(iy, height);
243 piy = wrap_periodic(iy - 1, height);
244 niy = wrap_periodic(iy + 1, height);
245 nniy = wrap_periodic(iy + 2, height);
246 break;
247 case EXTENSION_CLIP:
248 /* No cubic samples are inside the clip region. */
249 if (ix < -2 || ix > width || iy < -2 || iy > height) {
250 return zero();
251 }
252
253 pix = ix - 1;
254 nix = ix + 1;
255 nnix = ix + 2;
256
257 piy = iy - 1;
258 niy = iy + 1;
259 nniy = iy + 2;
260 break;
261 case EXTENSION_EXTEND:
262 pix = wrap_clamp(ix - 1, width);
263 nix = wrap_clamp(ix + 1, width);
264 nnix = wrap_clamp(ix + 2, width);
265 ix = wrap_clamp(ix, width);
266
267 piy = wrap_clamp(iy - 1, height);
268 niy = wrap_clamp(iy + 1, height);
269 nniy = wrap_clamp(iy + 2, height);
270 iy = wrap_clamp(iy, height);
271 break;
272 case EXTENSION_MIRROR:
273 pix = wrap_mirror(ix - 1, width);
274 nix = wrap_mirror(ix + 1, width);
275 nnix = wrap_mirror(ix + 2, width);
276 ix = wrap_mirror(ix, width);
277
278 piy = wrap_mirror(iy - 1, height);
279 niy = wrap_mirror(iy + 1, height);
280 nniy = wrap_mirror(iy + 2, height);
281 iy = wrap_mirror(iy, height);
282 break;
283 default:
284 kernel_assert(0);
285 return zero();
286 }
287
288 const TexT *data = (const TexT *)info.data;
289 const int xc[4] = {pix, ix, nix, nnix};
290 const int yc[4] = {piy, iy, niy, nniy};
291 float u[4], v[4];
292
293 /* Some helper macros to keep code size reasonable.
294 * Lets the compiler inline all the matrix multiplications.
295 */
296#define DATA(x, y) (read_clip(data, xc[x], yc[y], width, height))
297#define TERM(col) \
298 (v[col] * \
299 (u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col)))
300
303
304 /* Actual interpolation. */
305 return TERM(0) + TERM(1) + TERM(2) + TERM(3);
306#undef TERM
307#undef DATA
308 }
309
310 static ccl_always_inline OutT interp(const TextureInfo &info, const float x, float y)
311 {
312 switch (info.interpolation) {
314 return interp_closest(info, x, y);
316 return interp_linear(info, x, y);
317 default:
318 return interp_cubic(info, x, y);
319 }
320 }
321};
322
323#undef SET_CUBIC_SPLINE_WEIGHTS
324
325ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, const int id, const float x, float y)
326{
327 const TextureInfo &info = kernel_data_fetch(texture_info, id);
328
329 if (UNLIKELY(!info.data)) {
330 return zero_float4();
331 }
332
333 switch (info.data_type) {
335 const float f = TextureInterpolator<half, float>::interp(info, x, y);
336 return make_float4(f, f, f, 1.0f);
337 }
339 const float f = TextureInterpolator<uchar, float>::interp(info, x, y);
340 return make_float4(f, f, f, 1.0f);
341 }
343 const float f = TextureInterpolator<uint16_t, float>::interp(info, x, y);
344 return make_float4(f, f, f, 1.0f);
345 }
347 const float f = TextureInterpolator<float, float>::interp(info, x, y);
348 return make_float4(f, f, f, 1.0f);
349 }
358 default:
359 assert(0);
360 return make_float4(
362 }
363}
364
365} /* Namespace. */
366
unsigned char uchar
#define UNLIKELY(x)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
Definition half.h:41
nullptr float
#define TERM(col)
#define SET_CUBIC_SPLINE_WEIGHTS(u, t)
CCL_NAMESPACE_BEGIN ccl_device_inline float frac(const float x, ccl_private int *ix)
ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, const int id, const float x, float y)
#define kernel_assert(cond)
#define kernel_data_fetch(name, index)
#define ccl_always_inline
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
#define assert(assertion)
#define abs
constexpr T clamp(T, U, U) RET
ccl_device_inline float4 half4_to_float4_image(const half4 h)
Definition half.h:112
ccl_device_inline float half_to_float_image(half h)
Definition half.h:98
ccl_device_inline int float_to_int(const float f)
Definition math_base.h:407
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:13
#define ccl_device
#define make_float4
static ccl_always_inline OutT interp(const TextureInfo &info, const float x, float y)
static ccl_always_inline OutT read(const TexT *data, const int x, int y, const int width, const int)
static ccl_always_inline float read(const uint16_t r)
static ccl_always_inline int wrap_mirror(const int x, const int width)
static ccl_always_inline float4 read(const uchar4 r)
static ccl_always_inline float read(const uchar r)
static ccl_always_inline OutT interp_linear(const TextureInfo &info, const float x, float y)
static ccl_always_inline OutT interp_cubic(const TextureInfo &info, const float x, float y)
static ccl_always_inline OutT interp_closest(const TextureInfo &info, const float x, float y)
static ccl_always_inline int wrap_periodic(int x, const int width)
static ccl_always_inline float4 read(const float4 r)
static ccl_always_inline float4 read(ushort4 r)
static ccl_always_inline OutT read_clip(const TexT *data, const int x, int y, const int width, const int height)
static ccl_always_inline float4 read(half4 r)
static ccl_always_inline int wrap_clamp(const int x, const int width)
static ccl_always_inline float read(const float r)
static ccl_always_inline float read(half r)
uint64_t data
Definition texture.h:86
uint data_type
Definition texture.h:88
uint width
Definition texture.h:93
uint extension
Definition texture.h:91
uint height
Definition texture.h:94
uint interpolation
Definition texture.h:90
Definition half.h:60
uchar z
uchar w
uchar x
uchar y
uint16_t w
uint16_t y
uint16_t z
uint16_t x
i
Definition text_draw.cc:230
@ IMAGE_DATA_TYPE_BYTE
Definition texture.h:37
@ IMAGE_DATA_TYPE_FLOAT
Definition texture.h:36
@ IMAGE_DATA_TYPE_FLOAT4
Definition texture.h:33
@ IMAGE_DATA_TYPE_USHORT4
Definition texture.h:39
@ IMAGE_DATA_TYPE_USHORT
Definition texture.h:40
@ IMAGE_DATA_TYPE_HALF
Definition texture.h:38
@ IMAGE_DATA_TYPE_BYTE4
Definition texture.h:34
@ IMAGE_DATA_TYPE_HALF4
Definition texture.h:35
@ INTERPOLATION_LINEAR
Definition texture.h:24
@ INTERPOLATION_CLOSEST
Definition texture.h:25
@ EXTENSION_REPEAT
Definition texture.h:73
@ EXTENSION_CLIP
Definition texture.h:77
@ EXTENSION_EXTEND
Definition texture.h:75
@ EXTENSION_MIRROR
Definition texture.h:79
@ TEX_IMAGE_MISSING_G
Definition texture.h:15
@ TEX_IMAGE_MISSING_A
Definition texture.h:17
@ TEX_IMAGE_MISSING_R
Definition texture.h:14
@ TEX_IMAGE_MISSING_B
Definition texture.h:16