From: Not Zed Date: Wed, 8 Dec 2021 00:23:33 +0000 (+1030) Subject: Add a gui demo X-Git-Url: https://code.zedzone.au/cvs?a=commitdiff_plain;h=22c1978b18ddc7f6f7435ce8bbe9cf2e9e9bce08;p=zcl Add a gui demo --- diff --git a/Makefile b/Makefile index bcc5f51..b2ba201 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,18 @@ dist_EXTRA=README \ include config.make -java_MODULES=notzed.zcl notzed.zcl.demo +java_MODULES=notzed.zcl notzed.zcl.demo notzed.zcl.demo.fx notzed.zcl.demo_JDEPMOD=notzed.zcl +notzed.zcl.demo.fx_JDEPMOD=notzed.zcl include java.make + +mandelbrot: all + LD_LIBRARY_PATH=../nativez/bin/notzed.nativez/linux-amd64/lib:bin/notzed.zcl/linux-amd64/lib \ + $(JAVA) --module-path bin/modules:../nativez/bin/modules:$(JAVAFX_HOME)/lib \ + -m notzed.zcl.demo.fx/fxdemo.fract.Mandelbrot $(ARGS) + +clinfo: all + LD_LIBRARY_PATH=../nativez/bin/notzed.nativez/linux-amd64/lib:bin/notzed.zcl/linux-amd64/lib \ + strace -e open -o log $(JAVA) --module-path bin/modules:../nativez/bin/modules \ + -m notzed.zcl.demo/au.notzed.zcl.tools.clinfo $(ARGS) diff --git a/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Calculate.java b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Calculate.java new file mode 100644 index 0000000..b1ed8fd --- /dev/null +++ b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Calculate.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Michael Zucchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fxdemo.fract; + +import static au.notzed.zcl.CL.*; +import au.notzed.zcl.CLBuffer; +import au.notzed.zcl.CLCommandQueue; +import au.notzed.zcl.CLContext; +import au.notzed.zcl.CLDevice; +import au.notzed.zcl.CLException; +import au.notzed.zcl.CLKernel; +import au.notzed.zcl.CLPlatform; +import au.notzed.zcl.CLProgram; +import static java.lang.Math.cos; +import static java.lang.Math.sin; +import java.nio.ByteBuffer; + +public class Calculate { + + CLDevice[] devs; + CLContext cl; + CLCommandQueue q; + CLBuffer image; + CLProgram prog; + int width, height; + CLKernel mandelbrot; + CLKernel dmandelbrot; + + Calculate(int width, int height) throws CLException { + devs = new CLDevice[]{CLPlatform.getBestDevice(CL_DEVICE_TYPE_ALL)}; + cl = CLContext.createContext(null, devs); + q = cl.createCommandQueue(devs[0], 0); + + this.width = width; + this.height = height; + + image = cl.createBuffer(0, width * height * 4); + + prog = cl.createProgramWithSource(getClass().getResourceAsStream("mandelbrot.cl")); + prog.buildProgram(devs, null); + + mandelbrot = prog.createKernel("mandelbrot"); + mandelbrot.setArg(0, image); + mandelbrot.setArg(1, width, height); + + dmandelbrot = prog.createKernel("dmandelbrot"); + dmandelbrot.setArg(0, image); + dmandelbrot.setArg(1, width, height); + } + + public void run(ByteBuffer buffer, double ox, double oy, double sx, double sy, double arg, int m) { + try { + mandelbrot.setArg(2, ox, oy); + mandelbrot.setArg(3, sx, sy); + mandelbrot.setArg(4, sin(arg), cos(arg)); + mandelbrot.setArg(5, m); + System.out.println("enqueue"); + q.enqueue2DKernel(mandelbrot, 0, 0, width, height, 8, 8, null, null); + q.enqueueReadBuffer(image, true, 0, buffer.limit(), buffer, null, null); + System.out.println("finish"); + q.finish(); + } catch (CLException ex) { + ex.printStackTrace(); + } + } + + public void rund(ByteBuffer buffer, double ox, double oy, double sx, double sy, double arg, int m) { + try { + dmandelbrot.setArg(2, ox, oy); + dmandelbrot.setArg(3, sx, sy); + dmandelbrot.setArg(4, sin(arg), cos(arg)); + dmandelbrot.setArg(5, m); + + System.out.println("enqueue"); + q.enqueue2DKernel(dmandelbrot, 0, 0, width, height, 8, 8, null, null); + q.enqueueReadBuffer(image, true, 0, buffer.limit(), buffer, null, null); + System.out.println("finish"); + q.finish(); + } catch (CLException ex) { + ex.printStackTrace(); + } + + } + +} diff --git a/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Mandelbrot.java b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Mandelbrot.java new file mode 100644 index 0000000..12188a1 --- /dev/null +++ b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/Mandelbrot.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2020 Michael Zucchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fxdemo.fract; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.animation.Transition; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.scene.Scene; +import javafx.scene.image.ImageView; +import javafx.scene.image.PixelFormat; +import javafx.scene.image.WritableImage; +import javafx.scene.input.KeyCombination; +import javafx.scene.layout.AnchorPane; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import javafx.util.Duration; +import java.nio.ByteBuffer; +import au.notzed.zcl.CLMemory; + +/** + * Simple mandelbrot demo. + */ +public class Mandelbrot extends Application { + + int width = 1920 / 2; + int height = 1200 / 2; + Calculate calc; + WritableImage image; + ByteBuffer buffer; + ExecutorService queue = Executors.newSingleThreadExecutor((r) -> { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + }); + float scale = 0.001f; + //double cx = -0.235125, cy = 0.827215; + //double cx = -0.74529, cy = 0.11307; + // double cx = -0.761574, cy =-0.0847596; + double cx = -0.7746806106269039, cy = -0.1374168856037867; + + long nframes; + long lframes; + boolean goin = true; + double vscale = 0.01; + + @Override + public void start(Stage stage) throws Exception { + + calc = new Calculate(width, height); + image = new WritableImage(width, height); + + ImageView iv = new ImageView(image); + Text fps = new Text("FPS?"); + fps.setStyle("-fx-font: 24 monospace; -fx-fill: orange; -fx-effect: dropshadow(two-pass-box, orangered, 6, 0.5, 0, 0);"); + + Scene scene = new Scene(new AnchorPane(iv, fps)); + + scene.getAccelerators().put(KeyCombination.valueOf("ESC"), stage::close); + + // stage.setFullScreen(true); + AnchorPane.setLeftAnchor(fps, 24.0); + AnchorPane.setTopAnchor(fps, 24.0); + + stage.setScene(scene); + stage.show(); + + buffer = CLMemory.alloc(width * height * 4); + + Timeline tofps = new Timeline(new KeyFrame(Duration.seconds(1), (ActionEvent event) -> { + fps.setText(String.valueOf((nframes - lframes))); + lframes = nframes; + })); + tofps.setCycleCount(Timeline.INDEFINITE); + tofps.play(); + + Transition zoom = new Transition(60) { + { + setCycleDuration(Duration.seconds(15)); + } + + @Override + protected void interpolate(double frac) { + //double scale = frac * (0.001 - 0.000001) + 0.000001; + if (true) { + double scale = 0.005 / Math.exp(frac * 30); + recalcd(scale, (int) (-Math.log(scale) * 80)); + } else { + double scale = 0.005 / Math.exp(frac * 12); + recalc(scale, (int) (-Math.log(scale) * 160)); + } + + //System.out.printf("scale %e iter %f\n", scale, -Math.log(scale) * 100); + //recalc((float) scale); + //recalc(scale); + //recalc(vscale); + //vscale *= 0.95; + } + }; + zoom.setInterpolator(Interpolator.EASE_BOTH); + zoom.setAutoReverse(true); + zoom.setCycleCount(Timeline.INDEFINITE); + zoom.play(); + + //recalc(); + } + + boolean busy; + double arg = 0; + + void recalcd(double scale, int m) { + arg -= 0.05; + if (true) { + if (busy) + return; + busy = true; + //System.out.println(scale); + queue.submit(() -> { + double x = cx - width * scale * 0.5; + double y = cy - height * scale * 0.5; + + calc.rund(buffer, x, y, scale, scale, arg, m); + Platform.runLater(() -> { + nframes++; + image.getPixelWriter() + .setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, width * 4); + busy = false; + }); + }); + } else { + double x = cx - width * scale * 0.5; + double y = cy - height * scale * 0.5; + + calc.rund(buffer, x, y, scale, scale, arg, m); + nframes++; + image.getPixelWriter() + .setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, width * 4); + } + } + + void recalc(double scale, int m) { + arg += 0.05; + if (true) { + if (busy) + return; + busy = true; + queue.submit(() -> { + double x = cx - width * scale * 0.5; + double y = cy - height * scale * 0.5; + + calc.run(buffer, x, y, scale, scale, arg, m); + + Platform.runLater(() -> { + nframes++; + image.getPixelWriter() + .setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, width * 4); + busy = false; + }); + }); + } else { + double x = cx - width * scale * 0.5; + double y = cy - height * scale * 0.5; + + calc.run(buffer, x, y, scale, scale, arg, m); + nframes++; + image.getPixelWriter() + .setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, width * 4); + } + + } + +} diff --git a/src/notzed.zcl.demo.fx/classes/fxdemo/fract/mandelbrot.cl b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/mandelbrot.cl new file mode 100644 index 0000000..bb7009c --- /dev/null +++ b/src/notzed.zcl.demo.fx/classes/fxdemo/fract/mandelbrot.cl @@ -0,0 +1,97 @@ + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable + +#define LWS_X 8 +#define LWS_Y 8 + +kernel void +__attribute__((reqd_work_group_size(LWS_X, LWS_Y, 1))) +mandelbrot(global uchar4 *image, int2 size, double2 origin, double2 scale, double2 sincos, int m) { + int dx = get_global_id(0); + int dy = get_global_id(1); + + if (dx < size.x && dy < size.y) { +#if 0 + float2 c = (float2)(dx, dy) * scale + origin; +#else + double2 s = convert_double2(size); + double2 v; + + v = (double2)(dx, dy) - s * 0.5; + v = (double2)(v.x * sincos.x + v.y * sincos.y, + v.x * sincos.y - v.y * sincos.x); + v += s * 0.5; + + v *= scale; + v += origin; + + float2 c = convert_float2(v); +#endif + int n = 0; + float2 z = 0; + + do { + z = (float2)(z.x * z.x - z.y * z.y, 2.0f * z.x * z.y) + c; + n++; + } while (dot(z, z) < 4 && n < m); + + // we use a simple cosine palette to determine color: + // http://iquilezles.org/www/articles/palettes/palettes.htm + float t = n * 10.0f / m; + float3 d = (float3)(0.5f, 0.5f, 0.5f); + float3 e = (float3)(0.5f, 0.5f, 0.5f); + float3 f = (float3)(1.0f, 1.0f, 1.0f); + float3 g = (float3)(0.00f, 0.33f, 0.67f); + float4 colour = (float4)( d + e * cos(6.28318f * (f * t + g)), 1.0f); + + if (convert_int(n) == m) + colour = (float4)(0, 0, 0, 1); + + // store the rendered mandelbrot set into a storage buffer: + image[dx + dy * size.x] = convert_uchar4(colour * 255.0f); + } +} + +// rot-zoomer +kernel void +__attribute__((reqd_work_group_size(LWS_X, LWS_Y, 1))) +dmandelbrot(global uchar4 *image, int2 size, double2 origin, double2 scale, double2 sincos, int m) { + int dx = get_global_id(0); + int dy = get_global_id(1); + + if (dx < size.x && dy < size.y) { + double2 s = convert_double2(size); + double2 c; + + c = (double2)(dx, dy) - s * 0.5; + c = (double2)(c.x * sincos.x + c.y * sincos.y, + c.x * sincos.y - c.y * sincos.x); + c += s * 0.5; + + c *= scale; + c += origin; + + int n = 0; + double2 z = 0; + + do { + z = (double2)(z.x * z.x - z.y * z.y, 2.0f * z.x * z.y) + c; + n++; + } while (dot(z, z) < 4 && n < m); + + // we use a simple cosine palette to determine color: + // http://iquilezles.org/www/articles/palettes/palettes.htm + float t = n * 10.0f / m; + float3 d = (float3)(0.5f, 0.5f, 0.5f); + float3 e = (float3)(0.5f, 0.5f, 0.5f); + float3 f = (float3)(1.0f, 1.0f, 1.0f); + float3 g = (float3)(0.00f, 0.33f, 0.67f); + float4 colour = (float4)( d + e * cos(6.28318f * (f * t + g)), 1.0f); + + if (convert_int(n) == m) + colour = (float4)(0, 0, 0, 1); + + // store the rendered mandelbrot set into a storage buffer: + image[dx + dy * size.x] = convert_uchar4(colour * 255.0f); + } +} diff --git a/src/notzed.zcl.demo.fx/classes/module-info.java b/src/notzed.zcl.demo.fx/classes/module-info.java new file mode 100644 index 0000000..f9f8e8b --- /dev/null +++ b/src/notzed.zcl.demo.fx/classes/module-info.java @@ -0,0 +1,15 @@ + +/** + * OpenCL demos that use JavaFX. + */ +module notzed.zcl.demo.fx { + requires javafx.base; + requires javafx.controls; + requires javafx.graphics; + requires javafx.swing; + + requires notzed.zcl; + + exports fxdemo.fract to javafx.graphics; + +}