⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 benchmark.java

📁 Sunflow是一个照片级的渲染系统
💻 JAVA
字号:
package org.sunflow;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

import org.sunflow.core.Display;
import org.sunflow.core.Tesselatable;
import org.sunflow.core.camera.PinholeLens;
import org.sunflow.core.display.FileDisplay;
import org.sunflow.core.light.TriangleMeshLight;
import org.sunflow.core.primitive.Sphere;
import org.sunflow.core.primitive.TriangleMesh;
import org.sunflow.core.shader.DiffuseShader;
import org.sunflow.core.shader.GlassShader;
import org.sunflow.core.shader.MirrorShader;
import org.sunflow.core.tesselatable.Teapot;
import org.sunflow.image.Color;
import org.sunflow.math.Matrix4;
import org.sunflow.math.Point3;
import org.sunflow.math.Vector3;
import org.sunflow.system.BenchmarkFramework;
import org.sunflow.system.BenchmarkTest;
import org.sunflow.system.UI;
import org.sunflow.system.UserInterface;
import org.sunflow.system.UI.Module;
import org.sunflow.system.UI.PrintLevel;

public class Benchmark implements BenchmarkTest, UserInterface, Display {
    private int resolution;
    private boolean showOutput;
    private boolean showBenchmarkOutput;
    private boolean saveOutput;
    private int threads;
    private int[] referenceImage;
    private int[] validationImage;
    private int errorThreshold;

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Benchmark options:");
            System.out.println("  -regen                        Regenerate reference images for a variety of sizes");
            System.out.println("  -bench [threads] [resolution] Run a single iteration of the benchmark using the specified thread count and image resolution");
            System.out.println("                                Default: threads=0 (auto-detect cpus), resolution=256");
        } else if (args[0].equals("-regen")) {
            int[] sizes = { 32, 64, 96, 128, 256, 384, 512 };
            for (int s : sizes) {
                // run a single iteration to generate the reference image
                Benchmark b = new Benchmark(s, true, false, true);
                b.kernelMain();
            }
        } else if (args[0].equals("-bench")) {
            int threads = 0, resolution = 256;
            if (args.length > 1)
                threads = Integer.parseInt(args[1]);
            if (args.length > 2)
                resolution = Integer.parseInt(args[2]);
            Benchmark benchmark = new Benchmark(resolution, false, true, false, threads);
            benchmark.kernelBegin();
            benchmark.kernelMain();
            benchmark.kernelEnd();
        }
    }

    public Benchmark() {
        this(384, false, true, false);
    }

    public Benchmark(int resolution, boolean showOutput, boolean showBenchmarkOutput, boolean saveOutput) {
        this(resolution, showOutput, showBenchmarkOutput, saveOutput, 0);
    }

    public Benchmark(int resolution, boolean showOutput, boolean showBenchmarkOutput, boolean saveOutput, int threads) {
        UI.set(this);
        this.resolution = resolution;
        this.showOutput = showOutput;
        this.showBenchmarkOutput = showBenchmarkOutput;
        this.saveOutput = saveOutput;
        this.threads = threads;
        errorThreshold = 6;
        // fetch reference image from resources (jar file or classpath)
        if (saveOutput)
            return;
        URL imageURL = Benchmark.class.getResource(String.format("/resources/golden_%04X.png", resolution));
        if (imageURL == null)
            UI.printError(Module.BENCH, "Unable to find reference frame!");
        UI.printInfo(Module.BENCH, "Loading reference image from: %s", imageURL);
        try {
            BufferedImage bi = ImageIO.read(imageURL);
            if (bi.getWidth() != resolution || bi.getHeight() != resolution)
                UI.printError(Module.BENCH, "Reference image has invalid resolution! Expected %dx%d found %dx%d", resolution, resolution, bi.getWidth(), bi.getHeight());
            referenceImage = new int[resolution * resolution];
            for (int y = 0, i = 0; y < resolution; y++)
                for (int x = 0; x < resolution; x++, i++)
                    referenceImage[i] = bi.getRGB(x, resolution - 1 - y); // flip
        } catch (IOException e) {
            UI.printError(Module.BENCH, "Unable to load reference frame!");
        }
    }

    public void execute() {
        // 10 iterations maximum - 10 minute time limit
        BenchmarkFramework framework = new BenchmarkFramework(10, 600);
        framework.execute(this);
    }

    private class BenchmarkScene extends SunflowAPI {
        public BenchmarkScene() {
            build();
            render(SunflowAPI.DEFAULT_OPTIONS, saveOutput ? new FileDisplay(String.format("resources/golden_%04X.png", resolution)) : Benchmark.this);
        }

        public void build() {
            // settings
            parameter("threads", threads);
            // spawn regular priority threads
            parameter("threads.lowPriority", false);
            parameter("resolutionX", resolution);
            parameter("resolutionY", resolution);
            parameter("aa.min", -1);
            parameter("aa.max", 1);
            parameter("filter", "triangle");
            parameter("depths.diffuse", 2);
            parameter("depths.reflection", 2);
            parameter("depths.refraction", 2);
            parameter("bucket.order", "hilbert");
            parameter("bucket.size", 32);
            // gi options
            parameter("gi.engine", "igi");
            parameter("gi.igi.samples", 90);
            parameter("gi.igi.c", 0.000008f);
            options(SunflowAPI.DEFAULT_OPTIONS);
            buildCornellBox();
        }

        private void buildCornellBox() {
            // camera
            parameter("eye", new Point3(0, 0, -600));
            parameter("target", new Point3(0, 0, 0));
            parameter("up", new Vector3(0, 1, 0));
            parameter("fov", 45.0f);
            camera("main_camera", new PinholeLens());
            parameter("camera", "main_camera");
            options(SunflowAPI.DEFAULT_OPTIONS);
            // cornell box
            Color gray = new Color(0.70f, 0.70f, 0.70f);
            Color blue = new Color(0.25f, 0.25f, 0.80f);
            Color red = new Color(0.80f, 0.25f, 0.25f);
            Color emit = new Color(15, 15, 15);

            float minX = -200;
            float maxX = 200;
            float minY = -160;
            float maxY = minY + 400;
            float minZ = -250;
            float maxZ = 200;

            float[] verts = new float[] { minX, minY, minZ, maxX, minY, minZ,
                    maxX, minY, maxZ, minX, minY, maxZ, minX, maxY, minZ, maxX,
                    maxY, minZ, maxX, maxY, maxZ, minX, maxY, maxZ, };
            int[] indices = new int[] { 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 1,
                    2, 5, 5, 6, 2, 2, 3, 6, 6, 7, 3, 0, 3, 4, 4, 7, 3 };

            parameter("diffuse", gray);
            shader("gray_shader", new DiffuseShader());
            parameter("diffuse", red);
            shader("red_shader", new DiffuseShader());
            parameter("diffuse", blue);
            shader("blue_shader", new DiffuseShader());

            // build walls
            parameter("triangles", indices);
            parameter("points", "point", "vertex", verts);
            parameter("faceshaders", new int[] { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2 });
            geometry("walls", new TriangleMesh());

            // instance walls
            parameter("shaders", new String[] { "gray_shader", "red_shader",
                    "blue_shader" });
            instance("walls.instance", "walls");

            // create mesh light
            parameter("points", "point", "vertex", new float[] { -50, maxY - 1,
                    -50, 50, maxY - 1, -50, 50, maxY - 1, 50, -50, maxY - 1, 50 });
            parameter("triangles", new int[] { 0, 1, 2, 2, 3, 0 });
            parameter("radiance", emit);
            parameter("samples", 8);
            TriangleMeshLight light = new TriangleMeshLight();
            light.init("light", this);

            // spheres
            parameter("eta", 1.6f);
            shader("Glass", new GlassShader());
            sphere("glass_sphere", "Glass", -120, minY + 55, -150, 50);
            parameter("color", new Color(0.70f, 0.70f, 0.70f));
            shader("Mirror", new MirrorShader());
            sphere("mirror_sphere", "Mirror", 100, minY + 60, -50, 50);

            // scanned model
            geometry("teapot", (Tesselatable) new Teapot());
            parameter("transform", Matrix4.translation(80, -50, 100).multiply(Matrix4.rotateX((float) -Math.PI / 6)).multiply(Matrix4.rotateY((float) Math.PI / 4)).multiply(Matrix4.rotateX((float) -Math.PI / 2).multiply(Matrix4.scale(1.2f))));
            parameter("shaders", "gray_shader");
            instance("teapot.instance1", "teapot");
            parameter("transform", Matrix4.translation(-80, -160, 50).multiply(Matrix4.rotateY((float) Math.PI / 4)).multiply(Matrix4.rotateX((float) -Math.PI / 2).multiply(Matrix4.scale(1.2f))));
            parameter("shaders", "gray_shader");
            instance("teapot.instance2", "teapot");
        }

        private void sphere(String name, String shaderName, float x, float y, float z, float radius) {
            geometry(name, new Sphere());
            parameter("transform", Matrix4.translation(x, y, z).multiply(Matrix4.scale(radius)));
            parameter("shaders", shaderName);
            instance(name + ".instance", name);
        }
    }

    public void kernelBegin() {
        // allocate a fresh validation target
        validationImage = new int[resolution * resolution];
    }

    public void kernelMain() {
        // this builds and renders the scene
        new BenchmarkScene();
    }

    public void kernelEnd() {
        // make sure the rendered image was correct
        int diff = 0;
        if (referenceImage != null && validationImage.length == referenceImage.length) {
            for (int i = 0; i < validationImage.length; i++) {
                // count absolute RGB differences
                diff += Math.abs((validationImage[i] & 0xFF) - (referenceImage[i] & 0xFF));
                diff += Math.abs(((validationImage[i] >> 8) & 0xFF) - ((referenceImage[i] >> 8) & 0xFF));
                diff += Math.abs(((validationImage[i] >> 16) & 0xFF) - ((referenceImage[i] >> 16) & 0xFF));
            }
            if (diff > errorThreshold)
                UI.printError(Module.BENCH, "Image check failed! - #errors: %d", diff);
            else
                UI.printInfo(Module.BENCH, "Image check passed!");
        } else
            UI.printError(Module.BENCH, "Image check failed! - reference is not comparable");

    }

    public void print(Module m, PrintLevel level, String s) {
        if (showOutput || (showBenchmarkOutput && m == Module.BENCH))
            System.out.println(UI.formatOutput(m, level, s));
        if (level == PrintLevel.ERROR)
            throw new RuntimeException(s);
    }

    public void taskStart(String s, int min, int max) {
        // render progress display not needed
    }

    public void taskStop() {
        // render progress display not needed
    }

    public void taskUpdate(int current) {
        // render progress display not needed
    }

    public void imageBegin(int w, int h, int bucketSize) {
        // we can assume w == h == resolution
    }

    public void imageEnd() {
        // nothing needs to be done - image verification is done externally
    }

    public void imageFill(int x, int y, int w, int h, Color c) {
        // this is not used
    }

    public void imagePrepare(int x, int y, int w, int h, int id) {
        // this is not needed
    }

    public void imageUpdate(int x, int y, int w, int h, Color[] data) {
        // copy bucket data to validation image
        for (int j = 0, index = 0; j < h; j++, y++)
            for (int i = 0, offset = x + resolution * (resolution - 1 - y); i < w; i++, index++, offset++)
                validationImage[offset] = data[index].copy().toNonLinear().toRGB();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -