Skip to content

Commit

Permalink
added multithreading
Browse files Browse the repository at this point in the history
  • Loading branch information
codex128 committed Jun 26, 2024
1 parent dbde835 commit a3eee4c
Show file tree
Hide file tree
Showing 18 changed files with 413 additions and 237 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public class RenderManager {
public RenderManager(Renderer renderer) {
this.renderer = renderer;
this.forcedOverrides.add(boundDrawBufferId);
this.renderObjects = new RenderObjectMap(this);
this.renderObjects = new RenderObjectMap(this, true);
}

/**
Expand Down
53 changes: 53 additions & 0 deletions jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.jme3.renderer.framegraph;

/**
*
* @author codex
*/
public enum Access {

/**
* Indicates that the resource is accessed for reading only.
*/
Read(true, false),

/**
* Indicates that the resource is accessed for writing only.
*/
Write(false, true),

/**
* Indicates that the resource is accessed for both reading and writing.
*/
ReadAndWrite(true, true);

private final boolean read, write;

private Access(boolean read, boolean write) {
this.read = read;
this.write = write;
}

/**
* Returns true if the access is for reading.
*
* @return
*/
public boolean isRead() {
return read;
}

/**
* Returns true if the access is for writing.
*
* @return
*/
public boolean isWrite() {
return write;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public boolean isProfilerAvailable() {
*
* @return
*/
public boolean isFrameCaptureActive() {
public boolean isGraphCaptureActive() {
return renderManager.getGraphCapture() != null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,13 @@
import com.jme3.profile.FgStep;
import com.jme3.profile.VpStep;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.RendererException;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.framegraph.client.GraphSetting;
import com.jme3.renderer.framegraph.debug.GraphEventCapture;
import com.jme3.renderer.framegraph.passes.Attribute;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

/**
* Manages render passes, dependencies, and resources in a node-based parameter system.
Expand Down Expand Up @@ -101,6 +100,7 @@ public class FrameGraph {
private final HashMap<String, Object> settings = new HashMap<>();
private String name = "FrameGraph";
private boolean rendered = false;
private Exception renderException;

/**
* Creates a new blank framegraph.
Expand All @@ -109,7 +109,7 @@ public class FrameGraph {
*/
public FrameGraph(AssetManager assetManager) {
this.assetManager = assetManager;
this.resources = new ResourceList();
this.resources = new ResourceList(this);
this.context = new FGRenderContext(this);
this.queues.add(new PassQueueExecutor(this, RENDER_THREAD));
}
Expand Down Expand Up @@ -197,9 +197,14 @@ public boolean execute() {
// execute
if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null);
context.pushRenderSettings();
renderException = null;
for (PassQueueExecutor p : queues) {
p.execute(context);
}
if (renderException != null) {
renderException.printStackTrace(System.err);
throw new RendererException("An uncaught rendering exception occured, forcing the application to shut down.");
}
context.popFrameBuffer();
// reset
if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null);
Expand Down Expand Up @@ -228,6 +233,16 @@ public void renderingComplete() {
rendered = false;
}

private PassQueueExecutor getQueue(int i) {
if (i >= queues.size()) {
PassQueueExecutor queue = new PassQueueExecutor(this, i);
queues.add(queue);
return queue;
} else {
return queues.get(i);
}
}

/**
* Adds the pass to end of the pass queue.
*
Expand All @@ -236,7 +251,18 @@ public void renderingComplete() {
* @return given pass
*/
public <T extends RenderPass> T add(T pass) {
return queues.get(RENDER_THREAD).add(pass);
return getQueue(RENDER_THREAD).add(pass);
}
/**
*
*
* @param <T>
* @param pass
* @param threadIndex
* @return
*/
public <T extends RenderPass> T add(T pass, int threadIndex) {
return getQueue(threadIndex).add(pass);
}
/**
* Adds the pass at the index in the pass queue.
Expand All @@ -247,11 +273,12 @@ public <T extends RenderPass> T add(T pass) {
*
* @param <T>
* @param pass
* @param index
* @param threadIndex
* @param queueIndex
* @return
*/
public <T extends RenderPass> T add(T pass, int index) {
return queues.get(RENDER_THREAD).add(pass, index);
public <T extends RenderPass> T add(T pass, int threadIndex, int queueIndex) {
return getQueue(threadIndex).add(pass, queueIndex);
}
/**
* Creates and adds an Attribute pass and links it to the given ticket.
Expand All @@ -263,7 +290,7 @@ public <T extends RenderPass> T add(T pass, int index) {
* @return created Attribute
*/
public <T> Attribute<T> addAttribute(ResourceTicket<T> ticket) {
return queues.get(RENDER_THREAD).addAttribute(ticket);
return getQueue(RENDER_THREAD).addAttribute(ticket);
}

/**
Expand Down Expand Up @@ -466,6 +493,19 @@ public void setCLQueue(CommandQueue clQueue) {
context.setCLQueue(clQueue);
}

/**
* Called internally when a rendering exception occurs.
*
* @param ex
*/
public void interruptRendering(Exception ex) {
assert ex != null : "Interrupting exception cannot be null.";
renderException = ex;
for (PassQueueExecutor q : queues) {
q.interrupt();
}
}

/**
*
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import com.jme3.export.SavableObject;
import com.jme3.renderer.framegraph.passes.RenderPass;
import java.io.IOException;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
Expand All @@ -54,22 +54,22 @@
public class FrameGraphData implements Savable {

private static final String DEF_NAME = "FrameGraph";
private static final RenderPass[] DEF_PASSES = new RenderPass[0];
private static final ArrayList<PassQueueExecutor> DEF_QUEUES = new ArrayList<>(0);
private static final SavablePassConnection[] DEF_CONNECTIONS = new SavablePassConnection[0];
private static final HashMap<String, Savable> DEF_SETTINGS = new HashMap<>();

private final boolean export;
private String name;
private RenderPass[] passes;
private ArrayList<PassQueueExecutor> queues;
private SavablePassConnection[] connections;
private Map<String, SavableObject> settings;

public FrameGraphData() {
export = false;
}
public FrameGraphData(FrameGraph fg, Collection<RenderPass> passes, Map<String, Object> settings) {
public FrameGraphData(FrameGraph fg, ArrayList<PassQueueExecutor> queues, Map<String, Object> settings) {
this.name = fg.getName();
this.passes = passes.toArray(new RenderPass[0]);
this.queues = queues;
this.settings = new HashMap<>();
for (String key : settings.keySet()) {
this.settings.put(key, new SavableObject(settings.get(key)));
Expand All @@ -82,36 +82,42 @@ public void write(JmeExporter ex) throws IOException {
if (!export) {
throw new IllegalStateException("Data is import only.");
}
if (passes == null) {
if (queues == null) {
throw new IllegalStateException("Data is already consumed.");
}
final HashMap<Integer, Integer> idMap = new HashMap<>();
final LinkedList<SavablePassConnection> list = new LinkedList<>();
int nextId = 0;
// remap ids
for (RenderPass p : passes) {
p.setExportId(nextId++);
idMap.put(p.getId(), p.getExportId());
for (PassQueueExecutor q : queues) {
for (RenderPass p : q) {
p.setExportId(nextId++);
idMap.put(p.getId(), p.getExportId());
}
}
// extract connections
for (RenderPass p : passes) for (ResourceTicket t : p.getInputTickets()) {
if (t.hasSource()) {
int outId = idMap.get(t.getSource().getPassId());
list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName()));
for (PassQueueExecutor q : queues) {
for (RenderPass p : q) for (ResourceTicket t : p.getInputTickets()) {
if (t.hasSource()) {
int outId = idMap.get(t.getSource().getPassId());
list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName()));
}
}
}
OutputCapsule out = ex.getCapsule(this);
out.write(name, "name", DEF_NAME);
out.write(passes, "passes", DEF_PASSES);
out.writeSavableArrayList(queues, "passes", DEF_QUEUES);
out.write(list.toArray(new SavablePassConnection[0]), "connections", DEF_CONNECTIONS);
out.writeStringSavableMap(settings, "settings", DEF_SETTINGS);
// reset export ids
for (RenderPass p : passes) {
p.setExportId(-1);
for (PassQueueExecutor q : queues) {
for (RenderPass p : q) {
p.setExportId(-1);
}
}
idMap.clear();
list.clear();
passes = null;
queues = null;
settings.clear();
}
@Override
Expand All @@ -122,13 +128,13 @@ public void read(JmeImporter im) throws IOException {
InputCapsule in = im.getCapsule(this);
name = in.readString("name", "FrameGraph");
int baseId = RenderPass.getNextId();
Savable[] array = in.readSavableArray("passes", new RenderPass[0]);
passes = new RenderPass[array.length];
for (int i = 0; i < array.length; i++) {
RenderPass p = passes[i] = (RenderPass)array[i];
p.shiftId(baseId);
queues = in.readSavableArrayList("passes", DEF_QUEUES);
for (PassQueueExecutor q : queues) {
for (RenderPass p : q) {
p.shiftId(baseId);
}
}
array = in.readSavableArray("connections", new SavablePassConnection[0]);
Savable[] array = in.readSavableArray("connections", new SavablePassConnection[0]);
connections = new SavablePassConnection[array.length];
for (int i = 0; i < array.length; i++) {
SavablePassConnection c = connections[i] = (SavablePassConnection)array[i];
Expand All @@ -148,17 +154,17 @@ public void apply(FrameGraph fg) {
if (export) {
throw new IllegalStateException("Data is export only.");
}
if (passes == null) {
if (queues == null) {
throw new IllegalStateException("Data has already been consumed.");
}
fg.setName(name);
for (RenderPass p : passes) {
fg.add(p);
}
// cache passes by id
HashMap<Integer, RenderPass> cache = new HashMap<>();
for (RenderPass p : passes) {
cache.put(p.getId(), p);
for (PassQueueExecutor q : queues) {
for (RenderPass p : q) {
fg.add(p, q.getIndex());
cache.put(p.getId(), p);
}
}
// read connections
for (SavablePassConnection c : connections) {
Expand All @@ -171,7 +177,7 @@ public void apply(FrameGraph fg) {
fg.setSetting(key, settings.get(key).getObject());
}
cache.clear();
passes = null;
queues = null;
connections = null;
}

Expand All @@ -183,13 +189,14 @@ public void apply(FrameGraph fg) {
public boolean isExportOnly() {
return export;
}

/**
* Returns true if this data has been consumed.
*
* @return
*/
public boolean isConsumed() {
return passes == null;
return queues == null;
}

}
Loading

0 comments on commit a3eee4c

Please sign in to comment.