1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package mandel;
26
27 import hat.Accelerator;
28 import hat.Accelerator.Compute;
29 import hat.ComputeContext;
30 import hat.NDRange;
31 import hat.KernelContext;
32 import hat.backend.Backend;
33 import hat.buffer.S32Array;
34 import hat.buffer.S32Array2D;
35
36 import java.awt.Color;
37 import java.lang.invoke.MethodHandles;
38
39 import jdk.incubator.code.Reflect;
40 import optkl.ifacemapper.MappableIface.RO;
41 import optkl.ifacemapper.MappableIface.RW;
42 import optkl.ifacemapper.MappableIface.RW;
43
44 public class Main {
45 @Reflect
46 public static void mandel(KernelContext kc, S32Array2D s32Array2D, S32Array pallette, float offsetx, float offsety, float scale) {
47 if (kc.gix < kc.gsx) {
48 float width = s32Array2D.width();
49 float height = s32Array2D.height();
50 float x = ((kc.gix % s32Array2D.width()) * scale - (scale / 2f * width)) / width + offsetx;
51 float y = ((kc.gix / s32Array2D.width()) * scale - (scale / 2f * height)) / height + offsety;
52 float zx = x;
53 float zy = y;
54 float new_zx;
55 int colorIdx = 0;
56 while ((colorIdx < pallette.length()) && (((zx * zx) + (zy * zy)) < 4f)) {
57 new_zx = ((zx * zx) - (zy * zy)) + x;
58 zy = (2f * zx * zy) + y;
59 zx = new_zx;
60 colorIdx++;
61 }
62 int color = colorIdx < pallette.length() ? pallette.array(colorIdx) : 0;
63 s32Array2D.array(kc.gix, color);
64 }
65 }
66
67
68 @Reflect
69 static public void compute(final ComputeContext computeContext, S32Array pallete, S32Array2D s32Array2D, float x, float y, float scale) {
70 computeContext.dispatchKernel(
71 NDRange.of1D(s32Array2D.width()*s32Array2D.height()), //0..S32Array2D.size()
72 kc -> Main.mandel(kc, s32Array2D, pallete, x, y, scale));
73 }
74
75 public static void main(String[] args) {
76 final int width = 1024;
77 final int height = 1024;
78 final float defaultScale = 3f;
79 final float originX = -1f;
80 final float originY = 0;
81 final int maxIterations = 64;
82 final int zoomFrames = 200;
83
84 Accelerator accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
85 boolean headless = accelerator.config().headless(args.length>0?args[0]:null);
86 S32Array2D s32Array2D = S32Array2D.create(accelerator, width, height);
87
88 int[] palletteArray = new int[maxIterations];
89
90 if (accelerator.config().headless(args.length>0?args[0]:null)){
91 for (int i = 1; i < maxIterations; i++) {
92 palletteArray[i]=(i/8+1);// 0-7?
93 }
94 palletteArray[0]=0;
95 }else {
96 for (int i = 0; i < maxIterations; i++) {
97 final float h = i / (float) maxIterations;
98 final float b = 1.0f - (h * h);
99 palletteArray[i] = Color.HSBtoRGB(h, 1f, b);
100 }
101 }
102 S32Array pallette = S32Array.createFrom(accelerator, palletteArray);
103
104 accelerator.compute((@Reflect Compute)
105 cc -> Main.compute(cc, pallette, s32Array2D, originX, originY, defaultScale));
106
107 if (headless){
108 // Well take 1 in 4 samples (so 1024 -> 128 grid) of the pallette.
109 int subsample = 16;
110 char[] charPallette9 = new char []{' ', '.', ',',':', '-', '+','*', '#', '@', '%'};
111 for (int y = 0; y<height/subsample; y++) {
112 for (int x = 0; x<width/subsample; x++) {
113 int palletteValue = s32Array2D.get(x*subsample,y*subsample); // so 0->8
114 System.out.print(charPallette9[palletteValue]);
115 }
116 System.out.println();
117 }
118
119 }else {
120 Viewer viewer = new Viewer("mandel", s32Array2D);
121 viewer.imageViewer.syncWithRGB(s32Array2D);
122
123 while (viewer.imageViewer.getZoomPoint(defaultScale) instanceof Viewer.PointF32 zoomPoint) {
124 float x = originX;
125 float y = originY;
126 float scale = defaultScale;
127 final long startMillis = System.currentTimeMillis();
128
129 for (int sign : new int[]{-1, 1}) {
130 for (int i = 0; i < zoomFrames; i++) {
131 scale = scale + ((sign * defaultScale) / zoomFrames);
132 final float fscale = scale;
133 final float fx = x - sign * zoomPoint.x / zoomFrames;
134 final float fy = y - sign * zoomPoint.y / zoomFrames;
135 accelerator.compute((@Reflect Compute)
136 cc -> Main.compute(cc, pallette, s32Array2D, fx, fy, fscale));
137 viewer.imageViewer.syncWithRGB(s32Array2D);
138
139 }
140 }
141 var fps = ((zoomFrames * 2 * 1000) / (System.currentTimeMillis() - startMillis));
142 viewer.framesSecondSevenSegment.set((int)fps);
143 // System.out.println("FPS = " +fps);
144 }
145 }
146 }
147 }