| 1 |
root |
1.1 |
#!/usr/bin/perl |
| 2 |
|
|
|
| 3 |
|
|
use OpenGL ":all"; |
| 4 |
|
|
use OpenCL; |
| 5 |
|
|
|
| 6 |
|
|
my $S = $ARGV[0] || 256; # window/texture size, smaller is faster |
| 7 |
|
|
|
| 8 |
|
|
# open a window and create a gl texture |
| 9 |
|
|
OpenGL::glpOpenWindow width => $S, height => $S; |
| 10 |
|
|
my $texid = glGenTextures_p 1; |
| 11 |
|
|
glBindTexture GL_TEXTURE_2D, $texid; |
| 12 |
|
|
glTexImage2D_c GL_TEXTURE_2D, 0, GL_RGBA8, $S, $S, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0; |
| 13 |
|
|
|
| 14 |
|
|
# find and use the first opencl device that let's us get a shared opengl context |
| 15 |
|
|
my $platform; |
| 16 |
|
|
my $dev; |
| 17 |
|
|
my $ctx; |
| 18 |
|
|
|
| 19 |
|
|
for (OpenCL::platforms) { |
| 20 |
|
|
$platform = $_; |
| 21 |
|
|
for ($platform->devices) { |
| 22 |
|
|
$dev = $_; |
| 23 |
root |
1.3 |
$ctx = $platform->context ([OpenCL::GLX_DISPLAY_KHR, undef, OpenCL::GL_CONTEXT_KHR, undef], [$dev]) |
| 24 |
root |
1.1 |
and last; |
| 25 |
|
|
} |
| 26 |
|
|
} |
| 27 |
|
|
|
| 28 |
|
|
$ctx |
| 29 |
|
|
or die "cannot find suitable OpenCL device\n"; |
| 30 |
|
|
|
| 31 |
root |
1.4 |
print "using ", $dev->name, "\n"; |
| 32 |
|
|
|
| 33 |
root |
1.1 |
my $queue = $ctx->queue ($dev); |
| 34 |
|
|
|
| 35 |
|
|
# now attach an opencl image2d object to the opengl texture |
| 36 |
|
|
my $tex = $ctx->gl_texture2d (OpenCL::MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, $texid); |
| 37 |
|
|
|
| 38 |
|
|
# now the boring opencl code |
| 39 |
|
|
my $src = <<EOF; |
| 40 |
|
|
kernel void |
| 41 |
|
|
juliatunnel (write_only image2d_t img, float time) |
| 42 |
|
|
{ |
| 43 |
|
|
int2 xy = (int2)(get_global_id (0), get_global_id (1)); |
| 44 |
|
|
float2 p = convert_float2 (xy) / $S.f * 2.f - 1.f; |
| 45 |
|
|
|
| 46 |
|
|
float2 m = (float2)(1.f, p.y) / fabs (p.x); // tunnel |
| 47 |
|
|
m.x = fabs (fmod (m.x + time * 0.05f, 4.f) - 2.f); |
| 48 |
|
|
|
| 49 |
|
|
float2 z = m; |
| 50 |
|
|
float2 c = (float2)(sin (time * 0.01133f), cos (time * 0.02521f)); |
| 51 |
|
|
|
| 52 |
|
|
for (int i = 0; i < 25 && dot (z, z) < 4.f; ++i) // standard julia |
| 53 |
|
|
z = (float2)(z.x * z.x - z.y * z.y, 2.f * z.x * z.y) + c; |
| 54 |
|
|
|
| 55 |
|
|
float3 colour = (float3)(z.x, z.y, atan2 (z.y, z.x)); |
| 56 |
|
|
write_imagef (img, xy, (float4)(colour * p.x * p.x, 1.)); |
| 57 |
|
|
} |
| 58 |
|
|
EOF |
| 59 |
|
|
|
| 60 |
|
|
my $prog = $ctx->build_program ($src); |
| 61 |
|
|
my $kernel = $prog->kernel ("juliatunnel"); |
| 62 |
|
|
|
| 63 |
|
|
# program compiled, kernel ready, now draw and loop |
| 64 |
|
|
|
| 65 |
|
|
for (my $time; ; ++$time) { |
| 66 |
|
|
# acquire objects from opengl |
| 67 |
|
|
$queue->acquire_gl_objects ([$tex]); |
| 68 |
|
|
|
| 69 |
|
|
# configure and run our kernel |
| 70 |
|
|
$kernel->setf ("mf", $tex, $time*2); # mf = memory object, float |
| 71 |
|
|
$queue->nd_range_kernel ($kernel, undef, [$S, $S], undef); |
| 72 |
|
|
|
| 73 |
|
|
# release objects to opengl again |
| 74 |
|
|
$queue->release_gl_objects ([$tex]); |
| 75 |
|
|
|
| 76 |
|
|
# wait |
| 77 |
|
|
$queue->finish; |
| 78 |
|
|
|
| 79 |
|
|
# now draw the texture, the defaults should be all right |
| 80 |
|
|
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST; |
| 81 |
|
|
|
| 82 |
|
|
glEnable GL_TEXTURE_2D; |
| 83 |
|
|
glBegin GL_QUADS; |
| 84 |
|
|
glTexCoord2f 0, 1; glVertex3i -1, -1, -1; |
| 85 |
|
|
glTexCoord2f 0, 0; glVertex3i 1, -1, -1; |
| 86 |
|
|
glTexCoord2f 1, 0; glVertex3i 1, 1, -1; |
| 87 |
|
|
glTexCoord2f 1, 1; glVertex3i -1, 1, -1; |
| 88 |
|
|
glEnd; |
| 89 |
|
|
|
| 90 |
|
|
glXSwapBuffers; |
| 91 |
|
|
|
| 92 |
|
|
select undef, undef, undef, 1/60; |
| 93 |
|
|
} |