瀏覽代碼

Start render graph. RenderGraphDriver is based on former LogDriver.

clementlandrin 2 月之前
父節點
當前提交
d86342292e
共有 3 個文件被更改,包括 541 次插入0 次删除
  1. 331 0
      h3d/impl/RenderGraph.hx
  2. 187 0
      h3d/impl/RenderGraphDriver.hx
  3. 23 0
      h3d/scene/pbr/Renderer.hx

+ 331 - 0
h3d/impl/RenderGraph.hx

@@ -0,0 +1,331 @@
+package h3d.impl;
+
+#if render_graph
+import h3d.Engine.DepthBinding;
+
+class RenderGraph {
+	static var enable = false;
+	public static var frame : Frame;
+
+	public static function start() {
+		enable = true;
+		frame = new Frame();
+		var e = h3d.Engine.getCurrent();
+		e.setDriver(new h3d.impl.RenderGraphDriver(e.driver));
+	}
+
+	public static function mark(step : String) {
+		if ( !enable ) return;
+		frame.mark(step);
+	}
+
+	public static function setTargets(targets : Array<h3d.mat.Texture>, depthBinding : DepthBinding ) {
+		if ( !enable ) return;
+		frame.setTargetSection(new TargetsSection(targets, depthBinding));
+	}
+
+	public static function setTarget(target : h3d.mat.Texture, layer : Int, mipLevel : Int, depthBinding : DepthBinding) {
+		if ( !enable ) return;
+		frame.setTargetSection(new TargetSection(target, layer, mipLevel, depthBinding));
+	}
+
+	public static function setDepth(target : h3d.mat.Texture) {
+		if ( !enable ) return;
+		frame.setTargetSection(new DepthSection(target));
+	}
+
+	public static function clearTarget() {
+		if ( !enable ) return;
+		frame.clearTarget();
+	}
+
+	public static function sampleTexture(t : h3d.mat.Texture) {
+		if ( !enable ) return;
+		if ( t == null || !t.flags.has(Target) ) return;
+		frame.sampleTexture(t);
+	}
+
+	public static function save(outFile: String) {
+		if ( !enable ) return;
+		var content = frame.dump();
+		sys.io.File.saveContent(outFile, haxe.Json.stringify(content, "\t"));
+	}
+
+	public static function end() {
+		if ( !enable ) return;
+		enable = false;
+		var e = h3d.Engine.getCurrent();
+		var logDriver = cast(e.driver, h3d.impl.RenderGraphDriver);
+		e.setDriver(@:privateAccess logDriver.d);
+	}
+
+	public static function dispose() {
+		frame = null;
+	}
+
+}
+
+class Frame {
+	var curStep : String;
+	public var sections : Array<RenderSection>;
+	public var textures : Map<h3d.mat.Texture, TexData>;
+
+	public function new() {
+		sections = [];
+		textures = [];
+	}
+
+	public function useTexture(t : h3d.mat.Texture) {
+		if ( t != null && textures.get(t) == null )
+			textures.set(t, @:privateAccess new TexData(t));
+	}
+
+	public function getTextureData(t : h3d.mat.Texture) {
+		if ( t == null )
+			return null;
+		useTexture(t);
+		return textures.get(t);
+	}
+
+	public function getTextureId(t : h3d.mat.Texture) {
+		if ( t == null )
+			return -1;
+		return getTextureData(t).id;
+	}
+
+	public function getTextureDataById(id:Int):TexData {
+		for (t in textures)
+			if (t.id == id)
+				return t;
+		return null;
+	}
+
+	public function mark(step : String) {
+		if ( curStep != step ) {
+			curStep =  step;
+			sections.push(new RenderSection(step));
+		}
+	}
+
+	public function getCurSection() {
+		if ( sections.length == 0 ) {
+			var curSection = new RenderSection("begin");
+			sections.push(curSection);
+			return curSection;
+		}
+		return sections[sections.length - 1];
+	}
+
+	public function getCurTargetSection() {
+		var curSection = getCurSection();
+		var curTargetSection = curSection.getCurSection();
+		if ( curTargetSection == null ) {
+			// fallback if mark occurs without setRenderTarget
+			return sections[sections.length - 2 ].getCurSection();
+		}
+		return curSection.getCurSection();
+	}
+
+	public function setTargetSection(targetSection : TargetSectionBase) {
+		var curSection = getCurSection();
+		curSection.setTargetSection(targetSection);
+	}
+
+	public function clearTarget() {
+		getCurTargetSection().clearTarget();
+	}
+
+	public function sampleTexture(t : h3d.mat.Texture) {
+		getCurTargetSection().sampleTexture(t);
+	}
+
+	public function dump() {
+		var tex = [for ( t in textures) t];
+		tex.sort((t1,t2) -> return t1.id > t2.id ? 1 : -1);
+		return {
+			renderSections : [for ( s in sections ) s.dump()],
+			textures : tex
+		}
+	}
+}
+
+class RenderSection {
+	public var step : String;
+	public var targetSections : Array<TargetSectionBase>;
+
+	public function new(step : String) {
+		this.step = step;
+		targetSections = [];
+	}
+
+	public function getCurSection() {
+		return targetSections[targetSections.length - 1];
+	}
+
+	public function setTargetSection(targetSection : TargetSectionBase) {
+		targetSections.push(targetSection);
+	}
+
+	public function dump() {
+		return {
+			step : step,
+			sections : [for ( ts in targetSections ) ts.dump()],
+		}
+	}
+}
+
+class TargetSectionBase {
+	public var depthBinding : DepthBinding;
+	public var events : Array<Event>;
+
+	public function new(depthBinding : DepthBinding) {
+		this.depthBinding = depthBinding;
+		events = [];
+	}
+
+	public function clearTarget() {
+		events.push(new ClearEvent());
+	}
+
+	public function sampleTexture(t : h3d.mat.Texture) {
+		events.push(new SampleTextureEvent(t));
+	}
+
+	public function getTextureIds() : Array<Int> {
+		return [];
+	}
+
+	public function dump() : Dynamic {
+		return {
+			events : [for ( e in events ) e.dump()],
+		};
+	}
+
+}
+
+class TargetSection extends TargetSectionBase {
+	public var textureId : Int;
+	public var layer : Int;
+	public var mipLevel : Int;
+
+	public function new(target : h3d.mat.Texture, layer : Int, mipLevel : Int, depthBinding : DepthBinding) {
+		super(depthBinding);
+		this.textureId = RenderGraph.frame.getTextureId(target);
+		this.layer = layer;
+		this.mipLevel = mipLevel;
+	}
+
+	override function getTextureIds() {
+		return [textureId];
+	}
+
+	override function dump() {
+		var res = super.dump();
+		res.texture = textureId;
+		res.layer = layer;
+		res.mipLevel = mipLevel;
+		return res;
+	}
+}
+
+class TargetsSection extends TargetSectionBase {
+	public var textureIds : Array<Int>;
+
+	public function new(targets : Array<h3d.mat.Texture>, depthBinding : DepthBinding) {
+		super(depthBinding);
+		this.textureIds = [];
+		for ( t in targets )
+			textureIds.push(RenderGraph.frame.getTextureId(t));
+	}
+
+	override function getTextureIds() {
+		return textureIds;
+	}
+
+	override function dump() {
+		var res = super.dump();
+		res.textures = textureIds;
+		return res;
+	}
+}
+
+class DepthSection extends TargetSectionBase {
+	public var depthId : Int;
+
+	public function new(depth : h3d.mat.Texture) {
+		super(DepthOnly);
+		this.depthId = RenderGraph.frame.getTextureId(depth);
+	}
+
+	override function dump() {
+		var res = super.dump();
+		res.depth = depthId;
+		return res;
+	}
+}
+
+class TexData {
+	static var CUR_ID : Int = 0;
+	public var name : String;
+	public var width : Int;
+	public var height : Int;
+	public var fmt : hxd.PixelFormat;
+	public var id(default, null) : Int;
+
+	function new(t : h3d.mat.Texture) {
+		name = t.name;
+		width = t.width;
+		height = t.height;
+		fmt = t.format;
+		id = CUR_ID;
+		CUR_ID++;
+	}
+
+	public function dump() {
+		return {
+			name : name,
+			width : width,
+			height : height,
+			fmt : fmt.getName(),
+			id : id,
+		}
+	}
+}
+
+class Event {
+	public function new() {
+
+	}
+
+	public function dump() : Dynamic {
+		return {};
+	}
+}
+
+class ClearEvent extends Event {
+	public function new() {
+		super();
+	}
+
+	override function dump() {
+		var res = super.dump();
+		res.event = "clear event";
+		return res;
+	}
+}
+
+class SampleTextureEvent extends Event {
+	public var textureId : Int;
+	public function new(t : h3d.mat.Texture) {
+		super();
+		textureId = RenderGraph.frame.getTextureId(t);
+	}
+
+	override function dump() {
+		var res = super.dump();
+		res.event = "sample texture";
+		res.texture = textureId;
+		return res;
+	}
+}
+#end

+ 187 - 0
h3d/impl/RenderGraphDriver.hx

@@ -0,0 +1,187 @@
+package h3d.impl;
+import h3d.impl.Driver;
+
+#if render_graph
+class RenderGraphDriver extends Driver {
+
+	var d : Driver;
+	var loggedShaders = new Map<Int,Bool>();
+	var currentShader : hxsl.RuntimeShader;
+	public var logLines : Array<String> = null;
+
+	public function new( driver : Driver ) {
+		this.d = driver;
+		logEnable = true;
+		driver.logEnable = true;
+	}
+
+	override function hasFeature( f : Feature ) {
+		return d.hasFeature(f);
+	}
+
+	override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
+		return d.isSupportedFormat(fmt);
+	}
+
+	override function isDisposed() {
+		return d.isDisposed();
+	}
+
+	override function dispose() {
+		d.dispose();
+	}
+
+	override function begin( frame : Int ) {
+		d.begin(frame);
+	}
+
+	override function clear( ?color : h3d.Vector4, ?depth : Float, ?stencil : Int ) {
+		h3d.impl.RenderGraph.clearTarget();
+		d.clear(color, depth, stencil);
+	}
+
+	override function captureRenderBuffer( pixels : hxd.Pixels ) {
+		// TODO
+		d.captureRenderBuffer(pixels);
+	}
+
+	override function getDriverName( details : Bool ) {
+		return d.getDriverName(details);
+	}
+
+	override function init( onCreate : Bool -> Void, forceSoftware = false ) {
+		d.init(function(b) {
+			log('OnCreate $b');
+			onCreate(b);
+		},forceSoftware);
+	}
+
+	override function resize( width : Int, height : Int ) {
+		// TODO
+		d.resize(width, height);
+	}
+
+	override function selectShader( shader : hxsl.RuntimeShader ) {
+		currentShader = shader;
+		return d.selectShader(shader);
+	}
+
+	override function getNativeShaderCode( shader ) {
+		return d.getNativeShaderCode(shader);
+	}
+
+	override function selectMaterial( pass : h3d.mat.Pass ) {
+		// TODO
+		d.selectMaterial(pass);
+	}
+
+	override function uploadShaderBuffers( buffers : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
+		uploadBuffer(buffers, currentShader.vertex, buffers.vertex, which);
+		if ( currentShader.fragment != null )
+			uploadBuffer(buffers, currentShader.fragment, buffers.fragment, which);
+		d.uploadShaderBuffers(buffers, which);
+	}
+
+	function uploadBuffer( buffer : h3d.shader.Buffers, s : hxsl.RuntimeShader.RuntimeShaderData, buf : h3d.shader.Buffers.ShaderBuffers, which : h3d.shader.Buffers.BufferKind ) {
+		switch( which ) {
+		case Globals:
+		case Params:
+		case Buffers:
+			// TODO
+		case Textures:
+			inline function logVars( s : hxsl.RuntimeShader.RuntimeShaderData, buf : h3d.shader.Buffers.ShaderBuffers ) {
+				var t = s.textures;
+				while( t != null ) {
+					RenderGraph.sampleTexture(buf.tex[t.pos]);
+					log('Set ${s.kind.getName()} Texture@${t.pos} ' + t.name);
+					t = t.next;
+				}
+			}
+			logVars(s, buf);
+		}
+	}
+
+	override function selectBuffer( buffer : Buffer ) {
+		d.selectBuffer(buffer);
+	}
+
+	override function selectMultiBuffers( formats : hxd.BufferFormat.MultiFormat, buffers : Array<Buffer> ) {
+		d.selectMultiBuffers(formats,buffers);
+	}
+
+	override function draw( ibuf : h3d.Buffer, startIndex : Int, ntriangles : Int ) {
+		// TODO
+		d.draw(ibuf, startIndex, ntriangles);
+	}
+
+	override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
+		d.setRenderZone(x, y, width, height);
+	}
+
+	override function setRenderTarget( tex : Null<h3d.mat.Texture>, face = 0, mipMap = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
+		h3d.impl.RenderGraph.setTarget(tex, face, mipMap, depthBinding);
+		d.setRenderTarget(tex, face);
+	}
+
+	override function setRenderTargets( textures : Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
+		h3d.impl.RenderGraph.setTargets(textures, depthBinding);
+		d.setRenderTargets(textures);
+	}
+
+	override function setDepth( depthBuffer : h3d.mat.Texture ) {
+		h3d.impl.RenderGraph.setDepth(depthBuffer);
+		d.setDepth(depthBuffer);
+	}
+
+	override function end() {
+		// TODO
+		d.end();
+	}
+
+	override function present() {
+		// TODO
+		d.present();
+	}
+
+	override function setDebug( b : Bool ) {
+		d.setDebug(b);
+	}
+
+	override function allocTexture( t : h3d.mat.Texture ) : Texture {
+		// TODO
+		return d.allocTexture(t);
+	}
+
+	override function allocBuffer( b : Buffer ) : GPUBuffer {
+		// TODO
+		return d.allocBuffer(b);
+	}
+
+	override function disposeTexture( t : h3d.mat.Texture ) {
+		// TODO
+		d.disposeTexture(t);
+	}
+
+	override function disposeBuffer( b : h3d.Buffer ) {
+		// TODO
+		d.disposeBuffer(b);
+	}
+
+	override function uploadBufferData( b : h3d.Buffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
+		d.uploadBufferData(b, startVertex, vertexCount, buf, bufPos);
+	}
+
+	override function uploadBufferBytes( b : h3d.Buffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+		d.uploadBufferBytes(b, startVertex, vertexCount, buf, bufPos);
+	}
+
+	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
+		d.uploadTextureBitmap(t, bmp, mipLevel, side);
+	}
+
+	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
+		// TODO
+		d.uploadTexturePixels(t, pixels, mipLevel, side);
+	}
+}
+#end

+ 23 - 0
h3d/scene/pbr/Renderer.hx

@@ -480,6 +480,13 @@ class Renderer extends h3d.scene.Renderer {
 	}
 
 	function beginPbr() {
+		#if render_graph
+		if ( dumpFrame == hxd.Timer.frameCount ) {
+			h3d.impl.RenderGraph.start();
+			dumpFrame = -1;
+		}
+		#end
+
 		var props : RenderProps = props;
 		// reset tonemap shaders
 		var s = @:privateAccess tonemap.pass.shaders;
@@ -742,6 +749,15 @@ class Renderer extends h3d.scene.Renderer {
 		}
 		mark("vsync");
 		removeVolumetricEffects();
+		#if render_graph
+		h3d.impl.RenderGraph.end();
+		#end
+	}
+
+	override function mark(step : String) {
+		#if render_graph
+		h3d.impl.RenderGraph.mark(step);
+		#end
 	}
 
 	var debugPushPos : { x : Float, y : Float }
@@ -811,6 +827,13 @@ class Renderer extends h3d.scene.Renderer {
 		exposure = props.exposure;
 	}
 
+	#if render_graph
+	var dumpFrame = -1;
+	public function dump() {
+		dumpFrame = hxd.Timer.frameCount+1;
+	}
+	#end
+
 	#if editor
 	override function editProps() {
 		var props : RenderProps = props;