#define MAX_ITERATIONS 255
struct __attribute__((packed)) Params {
// View center coordinates.
float2 view_center // View sizes.
float2 view_size // Square of the infinity distance.
float inf_distance_sq // Actual iterations restriction.
uchar max_iterations}
float2 complex_arg(float2 a) {
return (float2)(atan2(a.y, a.x), 0)}
float2 complex_sqrt(float2 a) {
float r = length(a) float im = sqrt((r - a.x) * 0.5) return (float2)(sqrt(0.5 * (r + a.x)), (a.y >= 0.0) ? im : -im)}
float2 complex_mul(float2 a, float2 b) {
return (float2)(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x)}
float2 complex_div(float2 a, float2 b) {
float denom = b.x * b.x + b.y * b.y return (float2)(a.x * b.x + a.y * b.y, a.y * b.x - a.x * b.y) / denom}
float2 complex_exp(float2 a) {
return (float2)(cos(a.y), sin(a.y)) * exp(a.x)}
float2 complex_log(float2 a) {
return (float2)(log(length(a)), atan2(a.y, a.x))}
float2 complex_pow(float2 a, float2 b) {
float arg = b.x * atan2(a.y, a.x) float magn = pow(length(a), b.x) return (float2)(cos(arg), sin(arg)) * magn}
float2 complex_sinh(float2 a) {
float e = exp(a.x) float invE = 1.0 / e return (float2)((e - invE) * cos(a.y) * 0.5, (e + invE) * sin(a.y) * 0.5)}
float2 complex_cosh(float2 a) {
float e = exp(a.x) float invE = 1.0 / e return (float2)((e + invE) * cos(a.y) * 0.5, (e - invE) * sin(a.y) * 0.5)}
float2 complex_tanh(float2 a) {
float e = exp(2.0 * a.x) float invE = 1.0 / e float denom = (e + invE) * 0.5 + cos(2.0 * a.y) return (float2)((e - invE) * 0.5, sin(2.0 * a.y)) / denom}
float _r_acosh(float x) {
return log(x) + log(1.0 + sqrt(1.0 - 1.0 / (x * x)))}
float2 complex_asinh(float2 a) {
float s = length((float2)(a.x, 1.0 + a.y)) float t = length((float2)(a.x, 1.0 - a.y)) float re = _r_acosh((s + t) * 0.5) return (float2)((a.x >= 0.0) ? re : -re, asin(2.0 * a.y / (s + t)))}
float2 complex_acosh(float2 a) {
float p = length((float2)(1.0 + a.x, a.y)) float q = length((float2)(1.0 - a.x, a.y)) float im = acos(2.0 * a.x / (p + q)) return (float2)(_r_acosh((p + q) * 0.5), (a.y >= 0.0) ? im : -im)}
float2 complex_atanh(float2 a) {
float p = (1.0 + a.x) * (1.0 + a.x) + a.y * a.y float q = (1.0 - a.x) * (1.0 - a.x) + a.y * a.y return (float2)(
0.25 * (log(p) - log(q)),
0.5 * atan2(2.0 * a.y, 1.0 - a.x * a.x - a.y * a.y)
)}
float2 compute(float2 z) {
COMPUTE(z)
}
__kernel void julia(
__global uchar *output,
struct Params params
) {
// Retrieve image dimensions and coordinates.
size_t w = get_num_groups(0) * get_local_size(0) size_t h = get_num_groups(1) * get_local_size(1) size_t pixel_x = get_global_id(0) size_t pixel_y = get_global_id(1)
// Convert pixels to the real-valued coordinates.
float2 z = (float2)(pixel_x + 0.5, pixel_y + 0.5) / (float2)(w, h) - (float2) 0.5 z *= (float2)(1, -1) z = z * params.view_size + params.view_center
uchar iter = params.max_iterations __attribute__((opencl_unroll_hint))
for (uchar i = 0 z = compute(z)
float z_sq_magnitude = z.x * z.x + z.y * z.y if (
isnan(z_sq_magnitude) ||
isinf(z_sq_magnitude) ||
z_sq_magnitude > params.inf_distance_sq ||
i >= params.max_iterations
) {
iter = i break }
}
float color = (float) iter / params.max_iterations output[pixel_y * w + pixel_x] = round(color * 255)}