diff --git a/.dir-locals.el b/.dir-locals.el index 3860e08..4891477 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1 +1 @@ -((nil . ((projectile-project-install-cmd . "mvn -B clean compile assembly:single && java -jar target/*.jar")))) +((nil . ((projectile-project-compilation-cmd . "mvn -B clean compile assembly:single && java -jar target/*.jar")))) diff --git a/README.md b/README.md index 293d2be..40290de 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,11 @@ DEVICE=1 # DEFAULT = 0 TARGET=31 -# How many shifts for N (e.g. if N should be 8, N_LSHIFTS should be 3) -# Targes 2X and 3X depend on this parameter +# Parameter for various tasks (e.g. if N should be shifted 3 times, MULTI_PARAM should be 3) +# Targes 2X and 3X depend on this parameter (1 << MULTI_PARAM) +# Target 4X (N to the left and right of x_0) # DEFAULT = 25 -N_LSHIFTS=3 +MULTI_PARAM=3 -mvn -B clean compile assembly:single && java -jar target/*.jar $DEVICE $TARGET $N_LSHIFTS +mvn -B clean compile assembly:single && java -jar target/*.jar $DEVICE $TARGET $MULTI_PARAM ``` \ No newline at end of file diff --git a/src/main/java/edu/thi/phga/aparapi_test/App.java b/src/main/java/edu/thi/phga/aparapi_test/App.java index 698a88b..0f519a4 100644 --- a/src/main/java/edu/thi/phga/aparapi_test/App.java +++ b/src/main/java/edu/thi/phga/aparapi_test/App.java @@ -1,12 +1,12 @@ package edu.thi.phga.aparapi_test; import com.aparapi.device.OpenCLDevice; - import javafx.application.Application; public class App { public static int choice; public static OpenCLDevice device; + public static int multiParam; private static void printHeader(final String txt) { final String spacer = "######################################################################"; @@ -25,11 +25,11 @@ public class App { if (args.length > 1) { target = Integer.parseInt(args[1]); } - int shift = 25; + App.multiParam = 25; if (args.length > 2) { - shift = Integer.parseInt(args[2]); + App.multiParam = Integer.parseInt(args[2]); } - final int[] b = new int[1 << shift]; + final int[] b; switch (target) { case 0: OpenCLGetMemoryInfo.getInfo(); @@ -47,6 +47,7 @@ public class App { break; // REDUCE case 20: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce1.start(b); java.util.Arrays.fill(b, 1); @@ -59,27 +60,33 @@ public class App { OpenCLReduce5.start(b); break; case 21: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce1.start(b); break; case 22: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce2.start(b); break; case 23: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce3.start(b); break; case 24: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce4.start(b); break; case 25: + b = new int[1 << App.multiParam]; java.util.Arrays.fill(b, 1); OpenCLReduce5.start(b); break; // PREFIX case 30: + b = new int[1 << App.multiParam]; // Up to 1 << 27 java.util.Arrays.fill(b, 1); OpenCLPrefix1.start(b); @@ -88,18 +95,27 @@ public class App { OpenCLPrefix2.start(b); break; case 31: + b = new int[1 << App.multiParam]; // Up to 1 << 27 java.util.Arrays.fill(b, 1); OpenCLPrefix1.start(b); break; case 32: + b = new int[1 << App.multiParam]; // Up to 1 << 28 java.util.Arrays.fill(b, 1); OpenCLPrefix2.start(b); break; case 40: + // multiParam defines smoothing + System.out.println("Spawning window Filter"); Application.launch(Rauschfilter.class); break; + case 50: + // multiParam defines ZOOM + System.out.println("Spawning window Mandelbrot"); + Application.launch(Mandelbrot.class); + break; } } } diff --git a/src/main/java/edu/thi/phga/aparapi_test/Mandelbrot.java b/src/main/java/edu/thi/phga/aparapi_test/Mandelbrot.java new file mode 100644 index 0000000..99c8da5 --- /dev/null +++ b/src/main/java/edu/thi/phga/aparapi_test/Mandelbrot.java @@ -0,0 +1,138 @@ +package edu.thi.phga.aparapi_test; + +import java.util.ArrayDeque; +import java.util.Deque; + +import com.aparapi.Range; + +import javafx.application.Application; +import javafx.geometry.Rectangle2D; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.image.ImageView; +import javafx.scene.image.PixelFormat; +import javafx.scene.image.PixelReader; +import javafx.scene.image.PixelWriter; +import javafx.scene.image.WritableImage; +import javafx.scene.image.WritablePixelFormat; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Color; +import javafx.stage.Screen; +import javafx.stage.Stage; + +public class Mandelbrot extends Application{ + private static Rectangle2D bounds = Screen.getPrimary().getBounds(); + private static final int BREITE = (int) (bounds.getWidth() * 0.8); + private static final int HOEHE = BREITE * 9 / 16; + + private double[] farbe = new double[BREITE * HOEHE]; + private double[] saturation = new double[BREITE * HOEHE]; + + private MandelbrotKernel k = new MandelbrotKernel(farbe, saturation); + private Range r; + + // (x1, y1) = links oben, (x2, y2) = rechts unten + private double x1 = -3.0; + private double x2 = 1.8; + private double y1 = (x2 - x1) * HOEHE / BREITE / 2; + private double y2 = -y1; + + // Wie scharf ist das Bild (Ab wann sagen wir |Z_n| <= 2 für alle Z_n) + private int maxIter = 200; + private int exponent = 0; + + private WritableImage image = new WritableImage(BREITE, HOEHE); + private WritablePixelFormat format = PixelFormat.getByteBgraPreInstance(); + + private PixelWriter pw = image.getPixelWriter(); + private PixelReader pr = image.getPixelReader(); + + private Deque imageStack = new ArrayDeque<>(); + private Deque frameStack = new ArrayDeque<>(); + + private Stage stage; + + private void zeichne() { + stage.setTitle("KAO: Computing..."); + + k.setParameters(x1, y1, x2, y2, maxIter); + k.execute(r); + + for (int i = 0; i < farbe.length; i++) { + Color c = Color.hsb(farbe[i], saturation[i], 0.5); + pw.setColor(i % BREITE, i / BREITE, c); + } + + setTitle(); + } + + private void setTitle() { + stage.setTitle(String.format("KAO: Mandelbrot (Zoom: %d^%d, n = %d)", + App.multiParam, exponent, maxIter)); + } + + private void zoomIn(MouseEvent e) { + byte[] buffer = new byte[4 * BREITE * HOEHE]; + pr.getPixels(0, 0, BREITE, HOEHE, format, buffer, 0, 4 * BREITE); + imageStack.push(buffer); + frameStack.push(new double[] { x1, y1, x2, y2 }); + + double x = x1 + (x2 - x1) * e.getX() / BREITE; + double y = y1 + (y2 - y1) * e.getY() / HOEHE; + + double dx = (x2 - x1) / App.multiParam / 2; + double dy = (y2 - y1) / App.multiParam / 2; + + x1 = x - dx; + x2 = x + dx; + y1 = y - dy; + y2 = y + dy; + + maxIter *= 2; + exponent++; + + zeichne(); + } + + private void zoomOut(KeyEvent e) { + String key = e.getText(); + System.out.println("Key: " + key); + if (key.equals("q") && !imageStack.isEmpty()) { + double[] frame = frameStack.pop(); + x1 = frame[0]; + y1 = frame[1]; + x2 = frame[2]; + y2 = frame[3]; + + maxIter /= 2; + + pw.setPixels(0, 0, BREITE, HOEHE, format, imageStack.pop(), 0, 4 * BREITE); + + setTitle(); + } + } + + @Override + public void start(Stage stage) { + // Set range + int maxWGSize = 16; + System.out.println("Using WGSize: " + maxWGSize); + + r = Range.create2D(App.device, BREITE, HOEHE, maxWGSize, maxWGSize); + + this.stage = stage; + ImageView view = new ImageView(image); + view.setFocusTraversable(true); + view.setOnMousePressed(this::zoomIn); + view.setOnKeyPressed(this::zoomOut); + + zeichne(); + + stage.setScene(new Scene(new Group(view))); + stage.setResizable(false); + stage.sizeToScene(); + stage.show(); + } +} diff --git a/src/main/java/edu/thi/phga/aparapi_test/MandelbrotKernel.java b/src/main/java/edu/thi/phga/aparapi_test/MandelbrotKernel.java new file mode 100644 index 0000000..9fc1214 --- /dev/null +++ b/src/main/java/edu/thi/phga/aparapi_test/MandelbrotKernel.java @@ -0,0 +1,147 @@ +package edu.thi.phga.aparapi_test; + +import com.aparapi.Kernel; + +public class MandelbrotKernel extends Kernel { + private double[] farbe; + private double[] saturation; + private double x1, x2, y1, y2; + private int maxIter; + + public MandelbrotKernel(double[] farbe, double[] saturation) { + this.farbe = farbe; + this.saturation = saturation; + } + + public void setParameters(double x1, double y1, double x2, double y2, int maxIter) { + this.x1 = x1; + this.y1 = y1; + + this.x2 = x2; + this.y2 = y2; + + this.maxIter = maxIter; + } + + // Formel: + // z_n = { 0, n=0 + // z_(n-1)^2 + c, n>0 + // c element von C (Complex) + // Bei uns ist c dann ein Pixel den wir einfärben + // bzw. der Punkt(x, y) (offset) für eine bestimmte Zahl der Mandelbrot Menge + // Schwarz == ist Teil der Menge (|z_k| <= 2) + // Farbe == sonst (|z_k| > 2) (Frühzeitiger Schleifenabbruch) + // Alle z_n beginnen bei 0 + // Iter 1: z = 0^2 + c + // Iter 2: z = c^2 + c + // Iter 3: z = (c^2 + c)^2 + c + // ... + // Abbruch: |z| > 2 || Iter == maxIter (200) + + // @Override public void run() { + // int b = getGlobalId(0); // horizontaler Index + // int h = getGlobalId(1); // vertikaler Index + + // double cx = x1 + (x2 - x1) * b / getGlobalSize(0); + // double cy = y1 + (y2 - y1) * h / getGlobalSize(1); + + // double x = cx , y = cy; + // double xx = x * x, yy = y * y; + + // int i; + + // for (i = 1; xx + yy < 4 && i <= maxIter; i++) { + // y = 2 * x * y + cy; + // x = xx - yy + cx; + // yy = y * y; + // xx = x * x; + // } + + // int idx = h * getGlobalSize(0) + b; + // farbe[idx] = log(i) * 360; + // helligkeit[idx] = i < maxIter ? 1 : 0; + // } + + @Override + public void run() { + int x = getGlobalId(0); + int y = getGlobalId(1); + + int sizeX = getGlobalSize(0); + int sizeY = getGlobalSize(1); + double imageSizeX = x2 - x1; + double imageSizeY = y2 - y1; + + // Skalierung + double cR = x1 + imageSizeX * x / sizeX; + double cI = y1 + imageSizeY * y / sizeY; + + double zR = cR; + double zI = cI; + double zRQ = zR * zR; + double zIQ = zI * zI; + double zAbs = zIQ + zRQ; + int i = 0; + + for (i = 1; i <= maxIter && zAbs < 4; i++) { + // WICHTIG REIHENFOLGE!!! zR wird überschrieben... + zI = 2 * zR * zI + cI; // 2 * xyi + c_imag + zR = zRQ - zIQ + cR; // x^2 - y^2 + c_real + + zIQ = zI * zI; + zRQ = zR * zR; + zAbs = zIQ + zRQ; + } + + int index = y * sizeX + x; + if (i < maxIter) { + saturation[index] = min(i * log(i) / maxIter + 0.2, 1); + farbe[index] = log(i) * 360; + } else { + saturation[index] = 0; + } + } + // z = z*z + c + // z^2 = (z_r + z_i*i) * (z_r + z_i*i) + // = (z_r * z_r) + (z_r * z_i*i + z_r * z_i * i) - (z_i * z_i) <- [i^2 = -1] + // = z_r^2 + 2*z_r*z_i*i - z_i^2 + // = z_r^2 - z_i^2 + 2*i*z_r*z_i + // = x^2 - y^2 + 2xyi + // real + imag + + // Nette Entdeckung :) #LaserShow WUBWUBWUBWUB + // @Override + // public void run() { + // int sizeX = getGlobalSize(0); + // int sizeY = getGlobalSize(1); + // double imageSizeX = (x2 - x1); + // double imageSizeY = (y2 - y1); + // int x = getGlobalId(0); + // int y = getGlobalId(1); + // double c_r = x + imageSizeX / sizeX; + // double c_i = y + imageSizeY / sizeY; + // double z_r = 0; // komplexe zahl + // double z_i = 0; + // double zb = 0; + + // for (int i = 0; i < 200 && zb <= 4; i++) { + // // z = z*z + c + // // z^2 + // z_r = z_r * z_r - z_i * z_i; + // z_i = z_r * z_i + z_r * z_i; + + // // z + c; + // z_r += c_r; + // z_i += c_i; + + // // sqrt(z_r^2 + z_i^2) + // zb = sqrt(z_r * z_r + z_i * z_i); + // } + + // if (zb <= 4) { + // helligkeit[x + x * y] = 0; + // } else { + // helligkeit[x + x * y] = 1; + // } + // } +} diff --git a/src/main/java/edu/thi/phga/aparapi_test/Rauschfilter.java b/src/main/java/edu/thi/phga/aparapi_test/Rauschfilter.java index 38348de..61290d1 100644 --- a/src/main/java/edu/thi/phga/aparapi_test/Rauschfilter.java +++ b/src/main/java/edu/thi/phga/aparapi_test/Rauschfilter.java @@ -3,6 +3,10 @@ package edu.thi.phga.aparapi_test; import java.util.Arrays; import java.util.stream.IntStream; +import com.aparapi.Kernel; +import com.aparapi.Range; + +import javafx.application.Application; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; @@ -11,34 +15,43 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; import javafx.stage.Stage; -public class Rauschfilter extends javafx.application.Application { +public class Rauschfilter extends Application { private static Rectangle2D bounds = Screen.getPrimary().getBounds(); private static final int BREITE = (int) (bounds.getWidth() * 0.8); private static final int HOEHE = BREITE * 9 / 16; private static final double OMEGA = 8 * Math.PI / BREITE; - private static final int FILTERLAENGE = 15; + // private static final int FILTERLAENGE = 15; @Override public void start(Stage stage) { float[] noisy = new float[BREITE]; - // float[] clean = new float[BREITE]; + float[] clean = new float[BREITE]; + Range r = Range.create(App.device, BREITE, Math.min(BREITE, 256)); for (int i = 0; i < BREITE; i++) { noisy[i] = (float) (5 * Math.sin(i * OMEGA) + Math.random() - 0.5); } - // Kernel k = new FilterKernel(noisy, clean) + Kernel k = new RauschfilterKernel(noisy, clean, App.multiParam); + System.out.println("Executing Kernel"); + k.execute(r); + double ct = k.getConversionTime(); + double et = k.getExecutionTime() - ct; + + System.out.printf("Took %.2f ms to smooth out the wave with N = %d\n", + et, App.multiParam); Canvas oben = getCanvas(noisy); + Canvas unten = getCanvas(clean); - VBox vbox = new VBox(oben); + VBox vbox = new VBox(oben, unten); vbox.setStyle("-fx-background-color: whitesmoke"); stage.setScene(new Scene(vbox)); - stage.setTitle("KAO: Mittelwertfilter der Ordnung " + (FILTERLAENGE - 1)); + stage.setTitle("KAO: Mittelwertfilter der Ordnung " + (App.multiParam - 1)); stage.setResizable(false); stage.sizeToScene(); stage.show(); diff --git a/src/main/java/edu/thi/phga/aparapi_test/RauschfilterKernel.java b/src/main/java/edu/thi/phga/aparapi_test/RauschfilterKernel.java new file mode 100644 index 0000000..57a8ba6 --- /dev/null +++ b/src/main/java/edu/thi/phga/aparapi_test/RauschfilterKernel.java @@ -0,0 +1,33 @@ +package edu.thi.phga.aparapi_test; + +import com.aparapi.Kernel; + +public class RauschfilterKernel extends Kernel { + private float[] noisy; + private float[] clean; + private int len; + RauschfilterKernel(float[] noisy, float[] clean, int len) { + this.noisy = noisy; + this.clean = clean; + this.len = len; + } + @Override + public void run() { + // y_i = 1/N(x_-N/2 + x_-N/2+1 + ... + x_-1 + x_0 + x_1 + ... + x_N/2-1 + x_N/2) + int i = getGlobalId(); + float sum = 0; + + for (int n = 1; n <= len; n++) { + // To the right of x + if (i + n < noisy.length) { + sum += noisy[i + n]; + } + // To the left of x + if (i - n >= 0) { + sum += noisy[i - n]; + } + } + // write into clean + clean[i] = (sum + noisy[i]) / len; + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java deleted file mode 100644 index c970546..0000000 --- a/src/main/java/module-info.java +++ /dev/null @@ -1,4 +0,0 @@ -open module edu.thi.phga.aparapi_test { - requires javafx.controls; - requires aparapi; -} \ No newline at end of file diff --git a/src/main/java/nene.module-info.java b/src/main/java/nene.module-info.java new file mode 100644 index 0000000..33aca92 --- /dev/null +++ b/src/main/java/nene.module-info.java @@ -0,0 +1,4 @@ +// open module edu.thi.phga.aparapi_test { +// requires aparapi; +// requires javafx.controls; +// } \ No newline at end of file