1 /*
  2  * Copyright (c) 2025, 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 hat.test;
 26 
 27 import hat.Accelerator;
 28 import hat.ComputeContext;
 29 import hat.ComputeRange;
 30 import hat.GlobalMesh1D;
 31 import hat.KernelContext;
 32 import hat.backend.Backend;
 33 import hat.buffer.S32Array;
 34 import hat.buffer.S32Array2D;
 35 import hat.ifacemapper.MappableIface.RO;
 36 import hat.ifacemapper.MappableIface.RW;
 37 import jdk.incubator.code.CodeReflection;
 38 import hat.test.annotation.HatTest;
 39 import hat.test.engine.HatAsserts;
 40 
 41 import java.lang.invoke.MethodHandles;
 42 
 43 public class TestMandel {
 44 
 45     @CodeReflection
 46     public static void mandel(@RO KernelContext kc, @RW S32Array2D s32Array2D, @RO S32Array pallette, float offsetx, float offsety, float scale) {
 47         if (kc.x < kc.maxX) {
 48             float width = s32Array2D.width();
 49             float height = s32Array2D.height();
 50             float x = ((kc.x % s32Array2D.width()) * scale - (scale / 2f * width)) / width + offsetx;
 51             float y = ((kc.x / 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.x, color);
 64         }
 65     }
 66 
 67     @CodeReflection
 68     static public void compute(final ComputeContext computeContext, S32Array pallete, S32Array2D s32Array2D, float x, float y, float scale) {
 69         ComputeRange computeRange = new ComputeRange(new GlobalMesh1D(s32Array2D.width() & s32Array2D.height()));
 70         computeContext.dispatchKernel(computeRange,
 71                 kc -> {
 72                     TestMandel.mandel(kc, s32Array2D, pallete, x, y, scale);
 73                 });
 74     }
 75 
 76     public static void mandelSeq(@RW S32Array2D s32Array2D, @RO S32Array pallette, float offsetx, float offsety, float scale) {
 77         for (int i = 0; i < pallette.length(); i++) {
 78             float width = s32Array2D.width();
 79             float height = s32Array2D.height();
 80             float x = ((i % s32Array2D.width()) * scale - (scale / 2f * width)) / width + offsetx;
 81             float y = (((float) i / s32Array2D.width()) * scale - (scale / 2f * height)) / height + offsety;
 82             float zx = x;
 83             float zy = y;
 84             float new_zx;
 85             int colorIdx = 0;
 86             while ((colorIdx < pallette.length()) && (((zx * zx) + (zy * zy)) < 4f)) {
 87                 new_zx = ((zx * zx) - (zy * zy)) + x;
 88                 zy = (2f * zx * zy) + y;
 89                 zx = new_zx;
 90                 colorIdx++;
 91             }
 92             int color = colorIdx < pallette.length() ? pallette.array(colorIdx) : 0;
 93             s32Array2D.array(i, color);
 94         }
 95 
 96     }
 97 
 98     @HatTest
 99     public void testMandel() {
100         Accelerator accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
101         final int width = 1024;
102         final int height = 1024;
103         final float defaultScale = 3f;
104         final float originX = -1f;
105         final float originY = 0;
106         final int maxIterations = 64;
107 
108         S32Array2D s32Array2D = S32Array2D.create(accelerator, width, height);
109         S32Array2D check = S32Array2D.create(accelerator, width, height);
110 
111         int[] palletteArray = new int[maxIterations];
112         for (int i = 1; i < maxIterations; i++) {
113             palletteArray[i]=(i/8+1);// 0-7?
114         }
115         palletteArray[0]=0;
116         S32Array pallette = S32Array.createFrom(accelerator, palletteArray);
117 
118         accelerator.compute(cc -> TestMandel.compute(cc, pallette, s32Array2D, originX, originY, defaultScale));
119 
120         // Check
121         TestMandel.mandelSeq(check, pallette, originX, originY, defaultScale);
122 
123         int subsample = 16;
124         for (int y = 0; y<height/subsample; y++) {
125             for (int x = 0; x<width/subsample; x++) {
126                 int palletteValue = s32Array2D.get(x * subsample, y * subsample); // so 0->8
127                 int palletteValueSeq = s32Array2D.get(x * subsample, y * subsample); // so 0->8
128                 HatAsserts.assertEquals(palletteValueSeq, palletteValue);
129             }
130         }
131     }
132 }