Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions chunky/src/java/se/llbit/chunky/main/Chunky.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public static void main(final String[] args) {
if (cmdline.mode == CommandLineOptions.Mode.CLI_OPERATION) {
exitCode = cmdline.exitCode;
} else {
commonThreads = new ForkJoinPool(PersistentSettings.getNumThreads());
commonThreads = new ForkJoinPool(PersistentSettings.getRenderThreadCount());

Chunky chunky = new Chunky(cmdline.options);
chunky.headless = cmdline.mode == Mode.HEADLESS_RENDER || cmdline.mode == Mode.CREATE_SNAPSHOT;
Expand Down Expand Up @@ -341,7 +341,7 @@ public void update() {
*/
public static ForkJoinPool getCommonThreads() {
if (commonThreads == null) {
commonThreads = new ForkJoinPool(PersistentSettings.getNumThreads());
commonThreads = new ForkJoinPool(PersistentSettings.getRenderThreadCount());
}
return commonThreads;
}
Expand Down
25 changes: 19 additions & 6 deletions chunky/src/java/se/llbit/chunky/main/ChunkyOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
package se.llbit.chunky.main;

import se.llbit.chunky.PersistentSettings;
import se.llbit.chunky.renderer.RenderConstants;
import se.llbit.chunky.renderer.RenderOptions;
import se.llbit.chunky.renderer.ModifiableRenderOptions;
import se.llbit.chunky.renderer.scene.Scene;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
* Various options for Chunky, set via the configuration file and/or command-line flags.
Expand All @@ -37,12 +39,10 @@ public class ChunkyOptions {
public String imageOutputFile = "";

private List<File> resourcePacks = new ArrayList<>();
public int renderThreads = -1;
public File worldDir = null;
public int target = -1;

public int tileWidth = RenderConstants.TILE_WIDTH_DEFAULT;
public int sppPerPass = RenderConstants.SPP_PER_PASS_DEFAULT;
protected ModifiableRenderOptions renderOptions = new ModifiableRenderOptions();

/** Ignore scene loading errors when starting a headless render. */
public boolean force = false;
Expand All @@ -56,7 +56,7 @@ private ChunkyOptions() {
public static ChunkyOptions getDefaults() {
ChunkyOptions defaults = new ChunkyOptions();
defaults.sceneDir = PersistentSettings.getSceneDirectory();
defaults.renderThreads = PersistentSettings.getNumThreads();
defaults.renderOptions.setRenderThreadCount(PersistentSettings.getRenderThreadCount());
return defaults;
}

Expand All @@ -65,11 +65,24 @@ public static ChunkyOptions getDefaults() {
clone.sceneDir = sceneDir;
clone.sceneName = sceneName;
clone.resourcePacks = new ArrayList<>(resourcePacks);
clone.renderThreads = renderThreads;
clone.renderOptions.copyState(renderOptions);
clone.worldDir = worldDir;
return clone;
}

/**
* Returns the current state of the render options to by the renderer.
* It is not specified whether it is a copy or a view of the current options and
* does not guarantee to update on change.
* <p>Cast it to {@link ModifiableRenderOptions}, if you have to edit it.
* Edits are only safe on startup and might not propagate while a render is in progress.
*
* @return Options to use to start the render system.
*/
public RenderOptions getRenderOptions() {
return renderOptions;
}

public List<File> getResourcePacks() {
return resourcePacks;
}
Expand Down
12 changes: 8 additions & 4 deletions chunky/src/java/se/llbit/chunky/main/CommandLineOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

import se.llbit.chunky.PersistentSettings;
import se.llbit.chunky.renderer.ConsoleProgressListener;
import se.llbit.chunky.renderer.ModifiableRenderOptions;
import se.llbit.chunky.renderer.RenderContext;
import se.llbit.chunky.renderer.RenderOptions;
import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.chunky.resources.ResourcePackLoader;
import se.llbit.json.JsonNumber;
Expand Down Expand Up @@ -251,7 +253,7 @@ List<String> handle(List<String> args) throws InvalidCommandLineArgumentsExcepti
));
}
}
consumer.accept(new ArrayList<>(optionArguments)); // Create copy to avoid side effects.
consumer.accept(Collections.unmodifiableList(optionArguments));
return arguments;
}
}
Expand Down Expand Up @@ -293,14 +295,16 @@ public CommandLineOptions(String[] args) {
registerOption("-target", new Range(1),
arguments -> options.target = Math.max(1, Integer.parseInt(arguments.get(0))));

ModifiableRenderOptions renderOptions = (ModifiableRenderOptions) options.getRenderOptions();

registerOption("-threads", new Range(1),
arguments -> options.renderThreads = Math.max(1, Integer.parseInt(arguments.get(0))));
arguments -> renderOptions.setRenderThreadCount(Math.max(1, Integer.parseInt(arguments.get(0)))));

registerOption("-tile-width", new Range(1),
arguments -> options.tileWidth = Math.max(1, Integer.parseInt(arguments.get(0))));
arguments -> renderOptions.setTileWidth(Math.max(1, Integer.parseInt(arguments.get(0)))));

registerOption("-spp-per-pass", new Range(1),
arguments -> options.sppPerPass = Math.max(1, Integer.parseInt(arguments.get(0))));
arguments -> renderOptions.setSppPerPass(Math.max(1, Integer.parseInt(arguments.get(0)))));

registerOption("-version", new Range(0), arguments -> {
mode = Mode.CLI_OPERATION;
Expand Down
4 changes: 3 additions & 1 deletion chunky/src/java/se/llbit/chunky/map/WorldMapLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public WorldMapLoader(ChunkyFxController controller, MapView mapView) {
mapView.addViewListener(this);

// Start worker threads.
RegionParser[] regionParsers = new RegionParser[Integer.parseInt(System.getProperty("chunky.mapLoaderThreads", String.valueOf(PersistentSettings.getNumThreads())))];
RegionParser[] regionParsers = new RegionParser[Integer.parseInt(
System.getProperty("chunky.mapLoaderThreads", String.valueOf(PersistentSettings.getMapLoadingThreadCount()))
)];
for (int i = 0; i < regionParsers.length; ++i) {
regionParsers[i] = new RegionParser(this, regionQueue, mapView);
regionParsers[i].start();
Expand Down
18 changes: 12 additions & 6 deletions chunky/src/java/se/llbit/chunky/renderer/DefaultRenderManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ public DefaultRenderManager(RenderContext context, boolean headless) {
this.bufferedScene = context.getChunky().getSceneFactory().newScene();

// Create a new pool. Set the seed to the current time in milliseconds.
this.pool = context.renderPoolFactory.create(context.numRenderThreads(), System.currentTimeMillis());
this.pool = context.renderPoolFactory.create(
context.getRenderOptions().getRenderThreadCount(), System.currentTimeMillis()
);
this.setCPULoad(PersistentSettings.getCPULoad());

// Initialize callbacks here since java will complain `bufferedScene` is not initialized yet.
Expand Down Expand Up @@ -294,16 +296,16 @@ public void run() {
getPreviewRenderer().sceneReset(this, reason, resetCount);

// Select the correct renderer
Renderer render = mode == RenderMode.PREVIEW ? getPreviewRenderer() : getRenderer();
Renderer renderer = mode == RenderMode.PREVIEW ? getPreviewRenderer() : getRenderer();

frameStart = System.currentTimeMillis();
if (mode == RenderMode.PREVIEW) {
// Bail early if the preview is not visible
if (finalizeAllFrames) {
// Preview with no CPU limit
pool.setCpuLoad(100);
render.setPostRender(previewCallback);
render.render(this);
renderer.setPostRender(previewCallback);
startRender(renderer);
pool.setCpuLoad(cpuLoad);
}
} else {
Expand All @@ -314,8 +316,8 @@ public void run() {
updateRenderState(scene);
});
} else if (mode != RenderMode.PAUSED) {
render.setPostRender(renderCallback);
render.render(this);
renderer.setPostRender(renderCallback);
startRender(renderer);
}
}

Expand All @@ -328,6 +330,10 @@ public void run() {
}
}

protected void startRender(Renderer renderer) throws InterruptedException {
renderer.render(this);
}
Comment on lines +333 to +335
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for plugins?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I added this to be overridable by custom RenderManagers to add pre-start logic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. setting data in the new worker state / ray factories


/**
* Redraw the GUI screen. This should be run after postprocessing.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package se.llbit.chunky.renderer;

public class ModifiableRenderOptions implements RenderOptions {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. Can we improve this so that modifying the render options is safe and gets applied after the user confirms (or reset otherwise)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure that this would be the job of the UI logic or something in the render code which copies its state from this object. At the moment, the user can only set the tile size and spp per pass via CMD argument, right? And render thread count had some special handling somewhere which already required restarting the rendering or Chunky (?). Definitively a useful suggestion for a follow-up issue + PR :)

protected int renderThreadCount = -1;
protected int tileWidth = TILE_WIDTH_DEFAULT;
protected int sppPerPass = SPP_PER_PASS_DEFAULT;

public void copyState(RenderOptions other) {
renderThreadCount = other.getRenderThreadCount();
tileWidth = other.getTileWidth();
sppPerPass = other.getSppPerPass();
}

@Override
public int getRenderThreadCount() {
return renderThreadCount;
}

public void setRenderThreadCount(int renderThreadCount) {
this.renderThreadCount = renderThreadCount;
}

@Override
public int getTileWidth() {
return tileWidth;
}

public void setTileWidth(int tileWidth) {
this.tileWidth = tileWidth;
}

@Override
public int getSppPerPass() {
return sppPerPass;
}

public void setSppPerPass(int sppPerPass) {
this.sppPerPass = sppPerPass;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void render(DefaultRenderManager manager) throws InterruptedException {
int cropX = scene.getCropX();
int cropY = scene.getCropY();

int sppPerPass = manager.context.sppPerPass();
int sppPerPass = manager.context.getRenderOptions().getSppPerPass();
Camera cam = scene.camera();
double halfWidth = fullWidth / (2.0 * fullHeight);
double invHeight = 1.0 / fullHeight;
Expand Down
21 changes: 2 additions & 19 deletions chunky/src/java/se/llbit/chunky/renderer/RenderContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,8 @@ public File getSceneDirectory() {
return sceneDirectory;
}

/**
* @return The preferred number of rendering threads.
*/
public int numRenderThreads() {
return config.renderThreads;
public RenderOptions getRenderOptions() {
return config.getRenderOptions();
}

/**
Expand All @@ -84,18 +81,4 @@ public File getSceneFile(String fileName) {
}
return new File(sceneDirectory, fileName);
}

/**
* @return The tile width.
*/
public int tileWidth() {
return config.tileWidth;
}

/**
* @return The samples per pixel per pass
*/
public int sppPerPass() {
return config.sppPerPass;
}
}
25 changes: 15 additions & 10 deletions chunky/src/java/se/llbit/chunky/renderer/TileBasedRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

/**
* A tile based renderer. Simply call {@code submitTiles} to submit a frame's worth of tiles to the work queue.
Expand Down Expand Up @@ -57,6 +58,9 @@ public void setPostRender(BooleanSupplier callback) {
postRender = callback;
}

protected Supplier<WorkerState> workerStateFactory = WorkerState::new;
protected Supplier<Ray> rayFactory = Ray::new;

/**
* Create and submit tiles to the rendering pool.
* Await for these tiles to finish rendering with {@code manager.pool.awaitEmpty()}.
Expand All @@ -65,12 +69,12 @@ public void setPostRender(BooleanSupplier callback) {
* The second argument is the current pixel (x, y).
*/
protected void submitTiles(DefaultRenderManager manager, BiConsumer<WorkerState, IntIntPair> perPixel) {
initTiles(manager);
initTiles(manager.bufferedScene, manager.context.getRenderOptions());

cachedTiles.forEach(tile ->
manager.pool.submit(worker -> {
WorkerState state = new WorkerState();
state.ray = new Ray();
WorkerState state = workerStateFactory.get();
state.ray = rayFactory.get();
state.ray.setNormal(0, 0, -1);
state.random = worker.random;

Expand All @@ -86,11 +90,10 @@ protected void submitTiles(DefaultRenderManager manager, BiConsumer<WorkerState,
);
}

private void initTiles(DefaultRenderManager manager) {
Scene bufferedScene = manager.bufferedScene;
int width = bufferedScene.width;
int height = bufferedScene.height;
int tileWidth = manager.context.tileWidth();
private void initTiles(Scene scene, RenderOptions renderOptions) {
int width = scene.width;
int height = scene.height;
int tileWidth = renderOptions.getTileWidth();

if (prevWidth != width || prevHeight != height) {
prevWidth = width;
Expand All @@ -99,8 +102,10 @@ private void initTiles(DefaultRenderManager manager) {

for (int i = 0; i < width; i += tileWidth) {
for (int j = 0; j < height; j += tileWidth) {
cachedTiles.add(new RenderTile(i, FastMath.min(i + tileWidth, width),
j, FastMath.min(j + tileWidth, height)));
cachedTiles.add(new RenderTile(
i, FastMath.min(i + tileWidth, width),
j, FastMath.min(j + tileWidth, height)
));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public PictureExportFormat fromString(String string) {
renderThreads.setRange(1, 20);
renderThreads.clampMin();
renderThreads.onValueChange(value -> {
PersistentSettings.setNumRenderThreads(value);
PersistentSettings.setRenderThreadCount(value);
renderControls.showPopup("This change takes effect after restarting Chunky.", renderThreads);
});

Expand Down Expand Up @@ -309,8 +309,8 @@ public boolean shutdownAfterCompletedRender() {
public void update(Scene scene) {
outputMode.getSelectionModel().select(scene.getOutputMode());
fastFog.setSelected(scene.fog.fastFog());
renderThreads.set(PersistentSettings.getRenderThreadCount());
transmissivityCap.set(scene.getTransmissivityCap());
renderThreads.set(PersistentSettings.getNumThreads());
cpuLoad.set(PersistentSettings.getCPULoad());
rayDepth.set(scene.getRayDepth());
octreeImplementation.getSelectionModel().select(scene.getOctreeImplementation());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private static double[] render(Scene scene) throws InterruptedException {
// A single worker thread is used, with fixed PRNG seed.
// This makes the path tracing results deterministic.
ChunkyOptions options = ChunkyOptions.getDefaults();
options.renderThreads = 1;
((ModifiableRenderOptions) options.getRenderOptions()).setRenderThreadCount(1);
Chunky chunky = new Chunky(options);
RenderContext context = new RenderContext(chunky);
context.renderPoolFactory = (threads, seed) -> new RenderWorkerPool(threads, 0);
Expand Down
Loading