Browse Source

Can sample depth buffer. Get rid of depth texture on pbr renderer (at least if not js).

clementlandrin 2 years ago
parent
commit
d922827ce3

+ 27 - 9
h3d/Engine.hx

@@ -7,14 +7,23 @@ private class TargetTmp {
 	public var next : TargetTmp;
 	public var layer : Int;
 	public var mipLevel : Int;
-	public function new(t, n, l, m) {
+	public var depthBinding : DepthBinding;
+	public function new(t, n, l, m, db) {
 		this.t = t;
 		this.next = n;
 		this.layer = l;
 		this.mipLevel = m;
+		this.depthBinding = db;
 	}
 }
 
+enum DepthBinding {
+	ReadWrite;
+	ReadOnly;
+	DepthOnly;
+	NotBound;
+}
+
 class Engine {
 
 	public var driver(default,null) : h3d.impl.Driver;
@@ -47,6 +56,7 @@ class Engine {
 	var currentTargetTex : h3d.mat.Texture;
 	var currentTargetLayer : Int;
 	var currentTargetMip : Int;
+	var currentDepthBinding : DepthBinding;
 	var needFlushTarget : Bool;
 	var nullTexture : h3d.mat.Texture;
 	var textureColorCache = new Map<Int,h3d.mat.Texture>();
@@ -301,16 +311,17 @@ class Engine {
 		return targetStack == null ? null : targetStack.t == nullTexture ? targetStack.textures[0] : targetStack.t;
 	}
 
-	public function pushTarget( tex : h3d.mat.Texture, layer = 0, mipLevel = 0 ) {
+	public function pushTarget( tex : h3d.mat.Texture, layer = 0, mipLevel = 0, depthBinding = ReadWrite ) {
 		var c = targetTmp;
 		if( c == null )
-			c = new TargetTmp(tex, targetStack, layer, mipLevel);
+			c = new TargetTmp(tex, targetStack, layer, mipLevel, depthBinding);
 		else {
 			targetTmp = c.next;
 			c.t = tex;
 			c.next = targetStack;
 			c.mipLevel = mipLevel;
 			c.layer = layer;
+			c.depthBinding = depthBinding;
 		}
 		targetStack = c;
 		updateNeedFlush();
@@ -321,15 +332,19 @@ class Engine {
 		if( t == null )
 			needFlushTarget = currentTargetTex != null;
 		else
-			needFlushTarget = currentTargetTex != t.t || currentTargetLayer != t.layer || currentTargetMip != t.mipLevel || t.textures != null;
+			needFlushTarget = currentTargetTex != t.t || currentTargetLayer != t.layer || currentTargetMip != t.mipLevel || t.textures != null || currentDepthBinding != t.depthBinding;
 	}
 
-	public function pushTargets( textures : Array<h3d.mat.Texture> ) {
-		pushTarget(nullTexture);
+	public function pushTargets( textures : Array<h3d.mat.Texture>, depthBinding = ReadWrite ) {
+		pushTarget(nullTexture, depthBinding);
 		targetStack.textures = textures;
 		needFlushTarget = true;
 	}
 
+	public function pushDepth( depthBuffer : h3d.mat.Texture ) {
+		pushTarget(depthBuffer, DepthOnly);
+	}
+
 	public function popTarget() {
 		var c = targetStack;
 		if( c == null )
@@ -353,13 +368,16 @@ class Engine {
 			driver.setRenderTarget(null);
 			currentTargetTex = null;
 		} else {
-			if( t.textures != null )
-				driver.setRenderTargets(t.textures);
+			if ( t.depthBinding == DepthOnly )
+				driver.setDepth(t.t);
+			else if( t.textures != null )
+				driver.setRenderTargets(t.textures, t.depthBinding);
 			else
-				driver.setRenderTarget(t.t, t.layer, t.mipLevel);
+				driver.setRenderTarget(t.t, t.layer, t.mipLevel, t.depthBinding);
 			currentTargetTex = t.t;
 			currentTargetLayer = t.layer;
 			currentTargetMip = t.mipLevel;
+			currentDepthBinding = t.depthBinding;
 		}
 		needFlushTarget = false;
 	}

+ 77 - 12
h3d/impl/DX12Driver.hx

@@ -384,6 +384,9 @@ class DX12Driver extends h3d.impl.Driver {
 		renderTargetViews.onFree = function(prev) frame.toRelease.push(prev);
 		depthStenciViews.onFree = function(prev) frame.toRelease.push(prev);
 		defaultDepth = new h3d.mat.Texture(0,0, Depth24Stencil8);
+		defaultDepth.t = new TextureData();
+		defaultDepth.t.state = DEPTH_WRITE;
+		defaultDepth.name = "defaultDepth";
 
 		var desc = new CommandSignatureDesc();
 		desc.byteStride = 5 * 4;
@@ -402,6 +405,7 @@ class DX12Driver extends h3d.impl.Driver {
 		frameCount = hxd.Timer.frameCount;
 		currentFrame = Driver.getCurrentBackBufferIndex();
 		frame = frames[currentFrame];
+		defaultDepth.t.res = frame.depthBuffer;
 		frame.allocator.reset();
 		frame.commandList.reset(frame.allocator, null);
 		while( frame.toRelease.length > 0 )
@@ -461,7 +465,6 @@ class DX12Driver extends h3d.impl.Driver {
 			clear.b = color.b;
 			clear.a = color.a;
 			var count = currentRenderTargets.length;
-			if( count == 0 ) count = 1;
 			for( i in 0...count ) {
 				var tex = currentRenderTargets[i];
 				if( tex != null && tex.t.setClearColor(color) ) {
@@ -595,22 +598,39 @@ class DX12Driver extends h3d.impl.Driver {
 		}
 	}
 
-	function getDepthView( tex : h3d.mat.Texture ) {
-		if( tex != null && tex.depthBuffer == null ) {
+	function getDepthViewFromTexture( tex : h3d.mat.Texture, readOnly : Bool ) {
+		if ( tex != null && tex.depthBuffer == null ) {
 			depthEnabled = false;
 			return null;
 		}
-		if( tex != null ) {
+		if ( tex != null ) {
 			var w = tex.depthBuffer.width;
 			var h = tex.depthBuffer.height;
 			if( w != tex.width || h != tex.height )
 				throw "Depth size mismatch";
 		}
+		return getDepthView(tex == null ? null : tex.depthBuffer, readOnly);
+	}
+
+	function getDepthView( depthBuffer : h3d.mat.Texture, readOnly : Bool ) {
+		var res = depthBuffer == null ? frame.depthBuffer : depthBuffer.t.res;
 		var depthView = depthStenciViews.alloc(1);
-		Driver.createDepthStencilView(tex == null || tex.depthBuffer == defaultDepth ? frame.depthBuffer : @:privateAccess tex.depthBuffer.t.res, null, depthView);
+		var viewDesc = new DepthStencilViewDesc();
+		viewDesc.arraySize = 1;
+		viewDesc.mipSlice = 0;
+		viewDesc.firstArraySlice = 0;
+		viewDesc.format = D24_UNORM_S8_UINT;
+		viewDesc.viewDimension = TEXTURE2D;
+		if ( readOnly ) {
+			viewDesc.flags.set(READ_ONLY_DEPTH);
+			viewDesc.flags.set(READ_ONLY_STENCIL);
+		}
+		Driver.createDepthStencilView(res, viewDesc, depthView);
 		var depths = tmp.depthStencils;
 		depths[0] = depthView;
 		depthEnabled = true;
+		if ( depthBuffer != null )
+			transition(depthBuffer.t, readOnly ? DEPTH_READ : DEPTH_WRITE);
 		return depths;
 	}
 
@@ -632,13 +652,15 @@ class DX12Driver extends h3d.impl.Driver {
 		frame.commandList.rsSetViewports(1, tmp.viewport);
 	}
 
-	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer:Int = 0, mipLevel:Int = 0) {
+	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer:Int = 0, mipLevel:Int = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite) {
 
 		if( tex != null ) {
 			if( tex.t == null ) tex.alloc();
 			transition(tex.t, RENDER_TARGET);
 		}
 
+		depthEnabled = depthBinding != NotBound;
+
 		var texView = renderTargetViews.alloc(1);
 		var isArr = tex != null && (tex.flags.has(IsArray) || tex.flags.has(Cube));
 		var desc = null;
@@ -659,7 +681,16 @@ class DX12Driver extends h3d.impl.Driver {
 		}
 		Driver.createRenderTargetView(tex == null ? frame.backBuffer.res : tex.t.res, desc, texView);
 		tmp.renderTargets[0] = texView;
-		frame.commandList.omSetRenderTargets(1, tmp.renderTargets, true, getDepthView(tex));
+		if ( tex != null && !tex.flags.has(WasCleared) ) {
+			tex.flags.set(WasCleared);
+			var clear = tmp.clearColor;
+			clear.r = 0;
+			clear.g = 0;
+			clear.b = 0;
+			clear.a = 0;
+			frame.commandList.clearRenderTargetView(tmp.renderTargets[0], clear);
+		}
+		frame.commandList.omSetRenderTargets(1, tmp.renderTargets, true, depthEnabled ? getDepthViewFromTexture(tex, depthBinding == ReadOnly ) : null);
 
 		while( currentRenderTargets.length > 0 ) currentRenderTargets.pop();
 		if( tex != null ) currentRenderTargets.push(tex);
@@ -673,10 +704,12 @@ class DX12Driver extends h3d.impl.Driver {
 		needPipelineFlush = true;
 	}
 
-	override function setRenderTargets(textures:Array<h3d.mat.Texture>) {
+	override function setRenderTargets(textures:Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite) {
 		while( currentRenderTargets.length > textures.length )
 			currentRenderTargets.pop();
 
+		depthEnabled = depthBinding != NotBound;
+
 		var t0 = textures[0];
 		var texViews = renderTargetViews.alloc(textures.length);
 		var bits = 0;
@@ -686,16 +719,38 @@ class DX12Driver extends h3d.impl.Driver {
 			tmp.renderTargets[i] = view;
 			currentRenderTargets[i] = t;
 			bits |= getRTBits(t) << (i << 2);
+			if ( !t.flags.has(WasCleared) ) {
+				t.flags.set(WasCleared);
+				var clear = tmp.clearColor;
+				clear.r = 0;
+				clear.g = 0;
+				clear.b = 0;
+				clear.a = 0;
+				frame.commandList.clearRenderTargetView(tmp.renderTargets[i], clear);
+			}
 			transition(t.t, RENDER_TARGET);
 		}
 
-		frame.commandList.omSetRenderTargets(textures.length, tmp.renderTargets, true, getDepthView(textures[0]));
+		frame.commandList.omSetRenderTargets(textures.length, tmp.renderTargets, true, depthEnabled ? getDepthViewFromTexture(t0, depthBinding == ReadOnly) : null);
 		initViewport(t0.width, t0.height);
 
 		pipelineSignature.setI32(PSIGN_RENDER_TARGETS, bits | (depthEnabled ? 0x80000000 : 0));
 		needPipelineFlush = true;
 	}
 
+	override function setDepth(depthBuffer : h3d.mat.Texture) {
+		var view = getDepthView(depthBuffer, false);
+		depthEnabled = true;
+		frame.commandList.omSetRenderTargets(0, null, true, view);
+
+		while( currentRenderTargets.length > 0 ) currentRenderTargets.pop();
+
+		initViewport(depthBuffer.width, depthBuffer.height);
+
+		pipelineSignature.setI32(PSIGN_RENDER_TARGETS, 0x80000000);
+		needPipelineFlush = true;
+	}
+
 	override function setRenderZone(x:Int, y:Int, width:Int, height:Int) {
 		if( width < 0 && height < 0 && x == 0 && y == 0 ) {
 			tmp.rect.left = 0;
@@ -1240,11 +1295,11 @@ class DX12Driver extends h3d.impl.Driver {
 		desc.depthOrArraySize = 1;
 		desc.mipLevels = 1;
 		desc.sampleDesc.count = 1;
-		desc.format = D24_UNORM_S8_UINT;
+		desc.format = R24G8_TYPELESS;
 		desc.flags.set(ALLOW_DEPTH_STENCIL);
 		tmp.heap.type = DEFAULT;
 
-		tmp.clearValue.format = desc.format;
+		tmp.clearValue.format = D24_UNORM_S8_UINT;
 		tmp.clearValue.depth = 1;
 		tmp.clearValue.stencil= 0;
 		td.state = DEPTH_WRITE;
@@ -1441,13 +1496,23 @@ class DX12Driver extends h3d.impl.Driver {
 						desc.format = t.t.format;
 						desc.arraySize = t.layerCount;
 						tdesc = desc;
+					} else if ( t.isDepth() ) {
+						var desc = tmp.tex2DSRV;
+						desc.format = R24_UNORM_X8_TYPELESS;
+						tdesc = desc;
 					} else {
 						var desc = tmp.tex2DSRV;
 						desc.format = t.t.format;
 						tdesc = desc;
 					}
 					t.lastFrame = frameCount;
-					transition(t.t, shader.vertex ? NON_PIXEL_SHADER_RESOURCE : PIXEL_SHADER_RESOURCE);
+					var state = if ( t.isDepth() )
+						DEPTH_READ;
+					else if ( shader.vertex )
+						NON_PIXEL_SHADER_RESOURCE;
+					else
+						PIXEL_SHADER_RESOURCE;
+					transition(t.t, state);
 					Driver.createShaderResourceView(t.t.res, tdesc, srv.offset(i * frame.shaderResourceViews.stride));
 
 					var desc = tmp.samplerDesc;

+ 52 - 15
h3d/impl/DirectXDriver.hx

@@ -232,8 +232,8 @@ class DirectXDriver extends h3d.impl.Driver {
 		depthDesc.bind = DepthStencil | ShaderResource;
 		var depth = Driver.createTexture2d(depthDesc);
 		if( depth == null ) throw "Failed to create depthBuffer";
-		var depthView = Driver.createDepthStencilView(depth,D24_UNORM_S8_UINT);
-		var readOnlyDepthView = Driver.createDepthStencilView(depth, D24_UNORM_S8_UINT);
+		var depthView = Driver.createDepthStencilView(depth,D24_UNORM_S8_UINT, false);
+		var readOnlyDepthView = Driver.createDepthStencilView(depth, D24_UNORM_S8_UINT, true);
 
 		var vdesc = new ShaderResourceViewDesc();
 		vdesc.format = R24_UNORM_X8_TYPELESS;
@@ -243,7 +243,7 @@ class DirectXDriver extends h3d.impl.Driver {
 		vdesc.count = -1;
 		var shaderView = Driver.createShaderResourceView(depth, vdesc);
 
-		defaultDepth = { res : depth, view : shaderView, depthView : depthView, rt : null, mips : 0 };
+		defaultDepth = { res : depth, view : shaderView, depthView : depthView, readOnlyDepthView : readOnlyDepthView, rt : null, mips : 0 };
 		@:privateAccess {
 			defaultDepthInst.t = defaultDepth;
 			defaultDepthInst.width = width;
@@ -366,9 +366,9 @@ class DirectXDriver extends h3d.impl.Driver {
 		vdesc.start = 0;
 		vdesc.count = -1;
 		var srv = Driver.createShaderResourceView(depth,vdesc);
-		var depthView = Driver.createDepthStencilView(depth,D24_UNORM_S8_UINT);
-		var readOnlyDepthView = Driver.createDepthStencilView(depth, D24_UNORM_S8_UINT);
-		return { res : depth, view : srv, depthView : depthView, rt : null, mips : 0 };
+		var depthView = Driver.createDepthStencilView(depth,D24_UNORM_S8_UINT, false);
+		var readOnlyDepthView = Driver.createDepthStencilView(depth, D24_UNORM_S8_UINT, true);
+		return { res : depth, view : srv, depthView : depthView, readOnlyDepthView : readOnlyDepthView, rt : null, mips : 0 };
 	}
 
 	override function disposeDepthBuffer(b:h3d.mat.Texture) @:privateAccess {
@@ -952,14 +952,22 @@ class DirectXDriver extends h3d.impl.Driver {
 	}
 
 	var tmpTextures = new Array<h3d.mat.Texture>();
-	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer = 0, mipLevel = 0) {
+	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer = 0, mipLevel = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite) {
 		if( tex == null ) {
 			curTexture = null;
 			currentDepth = defaultDepth;
 			currentTargets[0] = defaultTarget;
 			currentTargetResources[0] = null;
 			targetsCount = 1;
-			Driver.omSetRenderTargets(1, currentTargets, currentDepth.depthView);
+			var depthView = switch (depthBinding) {
+			case NotBound:
+				null;
+			case ReadOnly:
+				currentDepth.readOnlyDepthView;
+			default:
+				currentDepth.depthView;
+			}
+			Driver.omSetRenderTargets(1, currentTargets, depthView);
 			viewport[2] = outputWidth;
 			viewport[3] = outputHeight;
 			viewport[5] = 1.;
@@ -967,7 +975,7 @@ class DirectXDriver extends h3d.impl.Driver {
 			return;
 		}
 		tmpTextures[0] = tex;
-		_setRenderTargets(tmpTextures, layer, mipLevel);
+		_setRenderTargets(tmpTextures, layer, mipLevel, depthBinding);
 	}
 
 	function unbind( res ) {
@@ -983,13 +991,13 @@ class DirectXDriver extends h3d.impl.Driver {
 		}
 	}
 
-	override function setRenderTargets(textures:Array<h3d.mat.Texture>) {
-		_setRenderTargets(textures, 0, 0);
+	override function setRenderTargets(textures:Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite) {
+		_setRenderTargets(textures, 0, 0, depthBinding);
 	}
 
-	function _setRenderTargets( textures:Array<h3d.mat.Texture>, layer : Int, mipLevel : Int ) {
+	function _setRenderTargets( textures:Array<h3d.mat.Texture>, layer : Int, mipLevel : Int, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		if( textures.length == 0 ) {
-			setRenderTarget(null);
+			setRenderTarget(null, depthBinding);
 			return;
 		}
 		if( hasDeviceError )
@@ -1028,7 +1036,19 @@ class DirectXDriver extends h3d.impl.Driver {
 				Driver.clearColor(rt, 0, 0, 0, 0);
 			}
 		}
-		Driver.omSetRenderTargets(textures.length, currentTargets, currentDepth == null ? null : currentDepth.depthView);
+		var depthView = if ( currentDepth == null )
+			null;
+		else {
+			switch ( depthBinding ) {
+			case NotBound:
+				null;
+			case ReadOnly:
+				currentDepth.readOnlyDepthView;
+			default:
+				currentDepth.depthView;
+			}
+		}
+		Driver.omSetRenderTargets(textures.length, currentTargets, depthView);
 		targetsCount = textures.length;
 
 		var w = tex.width >> mipLevel; if( w == 0 ) w = 1;
@@ -1039,6 +1059,23 @@ class DirectXDriver extends h3d.impl.Driver {
 		Driver.rsSetViewports(1, viewport);
 	}
 
+	override function setDepth( depthBuffer : h3d.mat.Texture ) {
+		if( hasDeviceError )
+			return;
+		currentDepth = @:privateAccess (depthBuffer == null ? null : depthBuffer.t);
+		depthBuffer.lastFrame = frame;
+		unbind(currentDepth.view);
+		Driver.omSetRenderTargets(0, null, currentDepth.depthView);
+		targetsCount = 0;
+
+		var w = depthBuffer.width; if( w == 0 ) w = 1;
+		var h = depthBuffer.height; if( h == 0 ) h = 1;
+		viewport[2] = w;
+		viewport[3] = h;
+		viewport[5] = 1.;
+		Driver.rsSetViewports(1, viewport);
+	}
+
 	override function setRenderZone(x:Int, y:Int, width:Int, height:Int) {
 		if( x == 0 && y == 0 && width < 0 && height < 0 ) {
 			hasScissor = false;
@@ -1298,7 +1335,7 @@ class DirectXDriver extends h3d.impl.Driver {
 				t.lastFrame = frame;
 
 				var view = t.t.view;
-				if( view != state.resources[i] ) {
+				if( view != state.resources[i] || t.t.depthView != null ) {
 					state.resources[i] = view;
 					max = i;
 					if( start < 0 ) start = i;

+ 6 - 3
h3d/impl/Driver.hx

@@ -28,7 +28,7 @@ typedef Query = h3d.impl.DX12Driver.QueryData;
 #elseif hldx
 typedef IndexBuffer = { res : dx.Resource, count : Int, bits : Int };
 typedef GPUBuffer = dx.Resource;
-typedef Texture = { res : dx.Resource, view : dx.Driver.ShaderResourceView, ?depthView : dx.Driver.DepthStencilView, rt : Array<dx.Driver.RenderTargetView>, mips : Int };
+typedef Texture = { res : dx.Resource, view : dx.Driver.ShaderResourceView, ?depthView : dx.Driver.DepthStencilView, ?readOnlyDepthView : dx.Driver.DepthStencilView, rt : Array<dx.Driver.RenderTargetView>, mips : Int };
 typedef Query = {};
 #elseif usesys
 typedef IndexBuffer = haxe.GraphicsDriver.IndexBuffer;
@@ -205,10 +205,13 @@ class Driver {
 	public function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
 	}
 
-	public function setRenderTarget( tex : Null<h3d.mat.Texture>, layer = 0, mipLevel = 0 ) {
+	public function setRenderTarget( tex : Null<h3d.mat.Texture>, layer = 0, mipLevel = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 	}
 
-	public function setRenderTargets( textures : Array<h3d.mat.Texture> ) {
+	public function setRenderTargets( textures : Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
+	}
+
+	public function setDepth( tex : Null<h3d.mat.Texture> ) {
 	}
 
 	public function allocDepthBuffer( b : h3d.mat.Texture ) : Texture {

+ 62 - 4
h3d/impl/GlDriver.hx

@@ -606,6 +606,21 @@ class GlDriver extends Driver {
 		if( curColorMask != pass.colorMask ) {
 			var m = pass.colorMask;
 			gl.colorMask(m & 1 != 0, m & 2 != 0, m & 4 != 0, m & 8 != 0);
+			var mi = m >> 4;
+			if ( mi > 0 ) {
+				#if (hl_ver >= version("1.14.0"))
+				var i = 1;
+				do {
+					if ( mi & 15 > 0 ) {
+						gl.colorMaski(i, mi & 1 != 0, mi & 2 != 0, mi & 4 != 0, mi & 8 != 0);
+					}
+					mi = mi >> 4;
+					i++;
+				} while ( mi > 0 );
+				#else
+				throw "GL ColorMaski support requires hlsdl 1.14+";
+				#end
+			}
 			curColorMask = m;
 		}
 
@@ -1515,7 +1530,7 @@ class GlDriver extends Driver {
 		return pixels;
 	}
 
-	override function setRenderTarget( tex : h3d.mat.Texture, layer = 0, mipLevel = 0 ) {
+	override function setRenderTarget( tex : h3d.mat.Texture, layer = 0, mipLevel = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		unbindTargets();
 		curTarget = tex;
 		if( tex == null ) {
@@ -1553,7 +1568,7 @@ class GlDriver extends Driver {
 		else
 			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cube) ? CUBE_FACES[layer] : GL.TEXTURE_2D, tex.t.t, mipLevel);
 
-		if( tex.depthBuffer != null ) {
+		if( tex.depthBuffer != null && depthBinding != NotBound ) {
 			// Depthbuffer and stencilbuffer are combined in one buffer, created with GL.DEPTH_STENCIL
 			if(tex.depthBuffer.hasStencil() && tex.depthBuffer.format == Depth24Stencil8) {
 				gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,@:privateAccess tex.depthBuffer.t.t, 0);
@@ -1588,9 +1603,9 @@ class GlDriver extends Driver {
 		#end
 	}
 
-	override function setRenderTargets( textures : Array<h3d.mat.Texture> ) {
+	override function setRenderTargets( textures : Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		unbindTargets();
-		setRenderTarget(textures[0]);
+		setRenderTarget(textures[0], depthBinding);
 		if( textures.length < 2 )
 			return;
 		numTargets = textures.length;
@@ -1615,6 +1630,49 @@ class GlDriver extends Driver {
 		if( needClear ) clear(BLACK);
 	}
 
+	override function setDepth( depthBuffer : h3d.mat.Texture ) {
+		unbindTargets();
+		curTarget = depthBuffer;
+
+		depthBuffer.lastFrame = frame;
+		curTargetLayer = 0;
+		curTargetMip = 0;
+		#if multidriver
+		if( depthBuffer.t.driver != this )
+			throw "Invalid texture context";
+		#end
+		gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
+
+		gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, null, 0);
+
+		if(depthBuffer.hasStencil() && depthBuffer.format == Depth24Stencil8) {
+			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,@:privateAccess depthBuffer.t.t, 0);
+		} else {
+			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,null,0);
+			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_2D, @:privateAccess depthBuffer.t.t,0);
+			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.STENCIL_ATTACHMENT, GL.TEXTURE_2D,depthBuffer.hasStencil() ? @:privateAccess depthBuffer.t.t : null,0);
+		}
+
+		var w = depthBuffer.width; if( w == 0 ) w = 1;
+		var h = depthBuffer.height; if( h == 0 ) h = 1;
+		gl.viewport(0, 0, w, h);
+		for( i in 0...boundTextures.length )
+			boundTextures[i] = null;
+
+		// if( !tex.flags.has(WasCleared) ) {
+		// 	tex.flags.set(WasCleared); // once we draw to, do not clear again
+		// 	clear(BLACK);
+		// }
+
+		#if js
+		if( glDebug ) {
+			var code = gl.checkFramebufferStatus(GL.FRAMEBUFFER);
+			if( code != GL.FRAMEBUFFER_COMPLETE )
+				throw "Invalid frame buffer: "+code;
+		}
+		#end
+	}
+
 	override function init( onCreate : Bool -> Void, forceSoftware = false ) {
 		#if js
 		// wait until all assets have properly load

+ 11 - 0
h3d/mat/Pass.hx

@@ -19,6 +19,7 @@ class Pass {
 	var shaders : hxsl.ShaderList;
 	var nextPass : Pass;
 	var culled : Bool = false;
+	var rendererFlags : Int = 0;
 
 	@:bits(flags) public var enableLights : Bool;
 	/**
@@ -167,10 +168,15 @@ class Pass {
 		this.colorMask = this.colorMask | mask;
 	}
 
+	function resetRendererFlags() {
+		rendererFlags = 0;
+	}
+
 	public function addShader<T:hxsl.Shader>(s:T) : T {
 		// throwing an exception will require NG GameServer review
 		if( s == null ) return null;
 		shaders = hxsl.ShaderList.addSort(s, shaders);
+		resetRendererFlags();
 		return s;
 	}
 
@@ -178,6 +184,7 @@ class Pass {
 		if ( s == null ) return null;
 		selfShadersChanged = true;
 		selfShaders = hxsl.ShaderList.addSort(s, selfShaders);
+		resetRendererFlags();
 		return s;
 	}
 
@@ -214,6 +221,7 @@ class Pass {
 		var sl = shaders, prev = null;
 		while( sl != null ) {
 			if( sl.s == s ) {
+				resetRendererFlags();
 				if ( selfShadersCache == sl )
 					selfShadersCache = selfShadersCache.next;
 				if( prev == null )
@@ -229,6 +237,7 @@ class Pass {
 		prev = null;
 		while ( sl != null ) {
 			if ( sl.s == s ) {
+				resetRendererFlags();
 				if ( selfShadersCache == sl )
 					selfShadersCache = selfShadersCache.next;
 				if ( prev == null )
@@ -248,6 +257,7 @@ class Pass {
 		var prev = null;
 		while( sl != null ) {
 			if( hxd.impl.Api.isOfType(sl.s, t) ) {
+				resetRendererFlags();
 				if ( selfShadersCache == sl )
 					selfShadersCache = selfShadersCache.next;
 				if( prev == null )
@@ -263,6 +273,7 @@ class Pass {
 		prev = null;
 		while( sl != null ) {
 			if( hxd.impl.Api.isOfType(sl.s, t) ) {
+				resetRendererFlags();
 				if ( selfShadersCache == sl )
 					selfShadersCache = selfShadersCache.next;
 				if( prev == null )

+ 3 - 8
h3d/pass/CascadeShadowMap.hx

@@ -173,18 +173,13 @@ class CascadeShadowMap extends DirShadowMap {
 
 		var textures = [];
 		for (i in 0...cascade) {
-			var texture = ctx.textures.allocTarget("cascadeShadowMap", size, size, false, format);
-			if( customDepth && (depth == null || depth.width != size || depth.height != size || depth.isDisposed()) ) {
-				if( depth != null ) depth.dispose();
-				depth = new h3d.mat.Texture(size, size, Depth24Stencil8);
-			}
-			texture.depthBuffer = depth;
-			textures.push(texture);
+			var texture = ctx.textures.allocTarget("cascadeShadowMap", size, size, false, Depth24Stencil8);
 
 			currentCascadeIndex = i;
 			var p = passes.save();
 			cullPasses(passes,function(col) return col.inFrustum(lightCameras[i].frustum));
-			processShadowMap( passes, texture, sort);
+			texture = processShadowMap( passes, texture, sort);
+			textures.push(texture);
 			passes.load(p);
 
 		}

+ 19 - 8
h3d/pass/DirShadowMap.hx

@@ -2,7 +2,6 @@ package h3d.pass;
 
 class DirShadowMap extends Shadows {
 
-	var customDepth : Bool;
 	var depth : h3d.mat.Texture;
 	var dshader : h3d.shader.DirShadow;
 	var border : Border;
@@ -32,8 +31,6 @@ class DirShadowMap extends Shadows {
 		lightCamera.orthoBounds = new h3d.col.Bounds();
 		shader = dshader = new h3d.shader.DirShadow();
 		border = new Border(size, size);
-		customDepth = h3d.Engine.getCurrent().driver.hasFeature(AllocDepthBuffer);
-		if( !customDepth ) depth = h3d.mat.Texture.getDefaultDepth();
 	}
 
 	override function set_mode(m:Shadows.RenderMode) {
@@ -56,7 +53,7 @@ class DirShadowMap extends Shadows {
 
 	override function dispose() {
 		super.dispose();
-		if( customDepth && depth != null ) depth.dispose();
+		if( depth != null ) depth.dispose();
 		if ( border != null ) border.dispose();
 	}
 
@@ -269,8 +266,11 @@ class DirShadowMap extends Shadows {
 	}
 
 	function processShadowMap( passes, tex, ?sort) {
-		ctx.engine.pushTarget(tex);
-		ctx.engine.clear(0xFFFFFF, 1);
+		if ( tex.isDepth() )
+			ctx.engine.pushDepth(tex);
+		else
+			ctx.engine.pushTarget(tex);
+		ctx.engine.clear(0xFFFFFF, 1.0);
 		super.draw(passes, sort);
 
 		var doBlur = blur.radius > 0 && (mode != Mixed || !ctx.computingStatic);
@@ -291,6 +291,11 @@ class DirShadowMap extends Shadows {
 		}
 
 		if( doBlur ) {
+			if ( tex.isDepth() ) {
+				var tmp = ctx.textures.allocTarget("dirShadowMapFloat", size, size, false, format);
+				h3d.pass.Copy.run(tex, tmp);
+				tex = tmp;
+			}
 			blur.apply(ctx, tex);
 			if( border != null ) {
 				ctx.engine.pushTarget(tex);
@@ -298,6 +303,7 @@ class DirShadowMap extends Shadows {
 				ctx.engine.popTarget();
 			}
 		}
+		return tex;
 	}
 
 	var g : h3d.scene.Graphics;
@@ -332,15 +338,20 @@ class DirShadowMap extends Shadows {
 
 		cullPasses(passes,function(col) return col.inFrustum(lightCamera.frustum));
 
+		#if js
 		var texture = ctx.textures.allocTarget("dirShadowMap", size, size, false, format);
-		if( customDepth && (depth == null || depth.width != size || depth.height != size || depth.isDisposed()) ) {
+		if( depth == null || depth.width != size || depth.height != size || depth.isDisposed() ) {
 			if( depth != null ) depth.dispose();
 			depth = new h3d.mat.Texture(size, size, Depth24Stencil8);
 			depth.name = "dirShadowMapDepth";
 		}
 		texture.depthBuffer = depth;
+		#else
+		depth = ctx.textures.allocTarget("dirShadowMap", size, size, false, Depth24Stencil8);
+		var texture = depth;
+		#end
 
-		processShadowMap(passes, texture, sort);
+		texture = processShadowMap(passes, texture, sort);
 
 		syncShader(texture);
 

+ 2 - 4
h3d/pass/PointShadowMap.hx

@@ -11,7 +11,6 @@ enum CubeFaceFlag {
 
 class PointShadowMap extends Shadows {
 
-	var customDepth : Bool;
 	var depth : h3d.mat.Texture;
 	var pshader : h3d.shader.PointShadow;
 	var mergePass = new h3d.pass.ScreenFx(new h3d.shader.MinMaxShader.CubeMinMaxShader());
@@ -30,8 +29,7 @@ class PointShadowMap extends Shadows {
 		lightCamera.screenRatio = 1.0;
 		lightCamera.fovY = 90;
 		shader = pshader = new h3d.shader.PointShadow();
-		customDepth = h3d.Engine.getCurrent().driver.hasFeature(AllocDepthBuffer);
-		if( !customDepth ) depth = h3d.mat.Texture.getDefaultDepth();
+		depth = h3d.mat.Texture.getDefaultDepth();
 
 		faceMask.set(Front);
 		faceMask.set(Back);
@@ -57,7 +55,7 @@ class PointShadowMap extends Shadows {
 
 	override function dispose() {
 		super.dispose();
-		if( customDepth && depth != null ) depth.dispose();
+		if( depth != null ) depth.dispose();
 		if( tmpTex != null) tmpTex.dispose();
 	}
 

+ 2 - 5
h3d/pass/SpotShadowMap.hx

@@ -2,7 +2,6 @@ package h3d.pass;
 
 class SpotShadowMap extends Shadows {
 
-	var customDepth : Bool;
 	var depth : h3d.mat.Texture;
 	var sshader : h3d.shader.SpotShadow;
 	var border : Border;
@@ -16,8 +15,6 @@ class SpotShadowMap extends Shadows {
 		lightCamera.zNear = 0.01;
 		shader = sshader = new h3d.shader.SpotShadow();
 		border = new Border(size, size);
-		customDepth = h3d.Engine.getCurrent().driver.hasFeature(AllocDepthBuffer);
-		if( !customDepth ) depth = h3d.mat.Texture.getDefaultDepth();
 	}
 
 	override function set_mode(m:Shadows.RenderMode) {
@@ -44,7 +41,7 @@ class SpotShadowMap extends Shadows {
 
 	override function dispose() {
 		super.dispose();
-		if( customDepth && depth != null ) depth.dispose();
+		if( depth != null ) depth.dispose();
 		border.dispose();
 	}
 
@@ -133,7 +130,7 @@ class SpotShadowMap extends Shadows {
 		cullPasses(passes, function(col) return col.inFrustum(lightCamera.frustum));
 
 		var texture = ctx.computingStatic ? createStaticTexture() : ctx.textures.allocTarget("spotShadowMap", size, size, false, format);
-		if( customDepth && (depth == null || depth.width != texture.width || depth.height != texture.height || depth.isDisposed()) ) {
+		if( depth == null || depth.width != texture.width || depth.height != texture.height || depth.isDisposed() ) {
 			if( depth != null ) depth.dispose();
 			depth = new h3d.mat.Texture(texture.width, texture.height, Depth24Stencil8);
 		}

+ 2 - 0
h3d/scene/RenderContext.hx

@@ -90,6 +90,8 @@ class RenderContext extends h3d.impl.RenderContext {
 	}
 
 	public function emitPass( pass : h3d.mat.Pass, obj : h3d.scene.Object ) @:privateAccess {
+		if ( pass.rendererFlags & 1 == 0 )
+			@:privateAccess scene.renderer.setPassFlags(pass);
 		var o = allocPool;
 		if( o == null ) {
 			o = new h3d.pass.PassObject();

+ 16 - 4
h3d/scene/Renderer.hx

@@ -126,15 +126,21 @@ class Renderer extends hxd.impl.AnyProps {
 		h3d.pass.Copy.run(from, to, blend);
 	}
 
-	function setTarget( tex ) {
+	function setTarget( tex, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		if( hasSetTarget ) ctx.engine.popTarget();
-		ctx.engine.pushTarget(tex);
+		ctx.engine.pushTarget(tex, depthBinding);
 		hasSetTarget = true;
 	}
 
-	function setTargets<T:h3d.mat.Texture>( textures : Array<T> ) {
+	function setTargets<T:h3d.mat.Texture>( textures : Array<T>, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		if( hasSetTarget ) ctx.engine.popTarget();
-		ctx.engine.pushTargets(cast textures);
+		ctx.engine.pushTargets(cast textures, depthBinding);
+		hasSetTarget = true;
+	}
+
+	function setDepth( depthBuffer : h3d.mat.Texture ) {
+		if( hasSetTarget ) ctx.engine.popTarget();
+		ctx.engine.pushDepth(depthBuffer);
 		hasSetTarget = true;
 	}
 
@@ -149,6 +155,12 @@ class Renderer extends hxd.impl.AnyProps {
 		return passObjects.get(name) != null;
 	}
 
+	@:access(h3d.mat.Pass)
+	function setPassFlags( pass : h3d.mat.Pass ) {
+		pass.rendererFlags |= 1;
+	}
+
+	@:access(h3d.pass.PassList)
 	function get( name : String ) {
 		var p = passObjects.get(name);
 		if( p == null ) return emptyPasses;

+ 55 - 15
h3d/scene/pbr/Renderer.hx

@@ -83,7 +83,9 @@ class Renderer extends h3d.scene.Renderer {
 		#if !MRT_low
 		other : (null:h3d.mat.Texture),
 		#end
+		#if js
 		depth : (null:h3d.mat.Texture),
+		#end
 		hdr : (null:h3d.mat.Texture),
 		ldr : (null:h3d.mat.Texture),
 	};
@@ -101,11 +103,13 @@ class Renderer extends h3d.scene.Renderer {
 		Vec4([Value("output.normal",3),ALPHA]),
 		#if !MRT_low
 		Vec4([Value("output.metalness"), Value("output.roughness"), Value("output.occlusion"), ALPHA]),
-		Vec4([Value("output.emissive"), Value("output.custom1"), Value("output.custom2"), ALPHA]),
+		Vec4([Value("output.emissive"), Value("output.custom1"), Value("output.custom2"), ALPHA])
 		#else
-		Vec4([Value("output.metalness"), Value("output.roughness"), Value("output.emissive"), ALPHA]),
+		Vec4([Value("output.metalness"), Value("output.roughness"), Value("output.emissive"), ALPHA])
+		#end
+		#if js
+		,Vec4([Value("output.depth"),Const(0), Const(0), ALPHA /* ? */])
 		#end
-		Vec4([Value("output.depth"),Const(0), Const(0), ALPHA /* ? */])
 	]);
 	var decalsOutput = new h3d.pass.Output("decals",[
 		Vec4([Swiz(Value("output.color"),[X,Y,Z]), Value("output.albedoStrength",1)]),
@@ -127,8 +131,10 @@ class Renderer extends h3d.scene.Renderer {
 		#end
 	]);
 	var colorDepthOutput = new h3d.pass.Output("colorDepth",[
-		Value("output.color"),
-		Vec4([Value("output.depth"),Const(0),Const(0),h3d.scene.pbr.Renderer.ALPHA])
+		Value("output.color")
+		#if js
+		,Vec4([Value("output.depth"),Const(0),Const(0),h3d.scene.pbr.Renderer.ALPHA])
+		#end
 	]);
 
 	public function new(?env) {
@@ -305,7 +311,7 @@ class Renderer extends h3d.scene.Renderer {
 
 		// Probe Rendering & Blending
 		var probeOutput = allocTarget("probeOutput", true, 1.0, #if MRT_low RGB10A2 #else RGBA16F #end);
-		ctx.engine.pushTarget(probeOutput);
+		ctx.engine.pushTarget(probeOutput, ReadOnly);
 		clear(0);
 
 		// Default Env & SkyBox
@@ -393,14 +399,24 @@ class Renderer extends h3d.scene.Renderer {
 		#if !MRT_low
 		textures.other = allocTarget("other", true, 1.);
 		#end
+		#if js
 		textures.depth = allocTarget("depth", true, 1., R32F);
+		#end
 		textures.hdr = allocTarget("hdrOutput", true, 1, #if MRT_low RGB10A2 #else RGBA16F #end);
 		textures.ldr = allocTarget("ldrOutput");
 	}
 
+	public function getPbrDepth() {
+		#if js
+		return textures.depth;
+		#else
+		return textures.albedo.depthBuffer;
+		#end
+	}
+
 	function initGlobals() {
 		ctx.setGlobal("albedoMap", { texture : textures.albedo, channel : hxsl.Channel.R });
-		ctx.setGlobal("depthMap", { texture : textures.depth, channel : hxsl.Channel.R });
+		ctx.setGlobal("depthMap", { texture : getPbrDepth(), channel : hxsl.Channel.R });
 		ctx.setGlobal("normalMap", { texture : textures.normal, channel : hxsl.Channel.R });
 		ctx.setGlobal("occlusionMap", { texture : textures.pbr, channel : hxsl.Channel.B });
 		ctx.setGlobal("hdrMap", textures.hdr);
@@ -425,7 +441,7 @@ class Renderer extends h3d.scene.Renderer {
 		pbrProps.albedoTex = textures.albedo;
 		pbrProps.normalTex = textures.normal;
 		pbrProps.pbrTex = textures.pbr;
-		pbrProps.depthTex = textures.depth;
+		pbrProps.depthTex = getPbrDepth();
 		#if !MRT_low
 		pbrProps.otherTex = textures.other;
 		#end
@@ -512,7 +528,7 @@ class Renderer extends h3d.scene.Renderer {
 	function drawPbrDecals( passName : String ) {
 		var passes = get(passName);
 		if( passes.isEmpty() ) return;
-		ctx.engine.pushTargets([textures.albedo,textures.normal,textures.pbr]);
+		ctx.engine.pushTargets([textures.albedo,textures.normal,textures.pbr], ReadOnly);
 		renderPass(decalsOutput, passes);
 		ctx.engine.popTarget();
 	}
@@ -520,20 +536,32 @@ class Renderer extends h3d.scene.Renderer {
 	function drawEmissiveDecals( passName : String ) {
 		var passes = get(passName);
 		if( passes.isEmpty() ) return;
-		ctx.engine.pushTargets([textures.albedo,textures.normal,textures.pbr#if !MRT_low ,textures.other #end]);
+		ctx.engine.pushTargets([textures.albedo,textures.normal,textures.pbr#if !MRT_low ,textures.other #end], ReadOnly);
 		renderPass(emissiveDecalsOutput, passes);
 		ctx.engine.popTarget();
 	}
 
+	function getPbrRenderTargets( depth : Bool ) {
+		#if js
+		if ( depth )
+			return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end #if js , getPbrDepth() #end];
+		#end
+		return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end];
+	}
+
 	override function render() {
 		beginPbr();
+		#if js
 		setTarget(textures.depth);
 		ctx.engine.clearF(new h3d.Vector(1));
+		#end
 
-		setTargets([textures.albedo,textures.normal,textures.pbr#if !MRT_low ,textures.other #end]);
+		setTargets(getPbrRenderTargets(false));
 		clear(0, 1, 0);
 
-		setTargets([textures.albedo,textures.normal,textures.pbr#if !MRT_low ,textures.other #end,textures.depth]);
+		#if js
+		setTargets(getPbrRenderTargets(true));
+		#end
 
 		begin(MainDraw);
 		renderPass(output, get("terrain"));
@@ -548,14 +576,18 @@ class Renderer extends h3d.scene.Renderer {
 		drawEmissiveDecals("emissiveDecal");
 		end();
 
-		setTarget(textures.hdr);
+		setTarget(textures.hdr, ReadOnly);
 		clear(0);
 		lighting();
 
+		setTarget(textures.hdr);
 		begin(Forward);
+		setTarget(textures.hdr);
 		var ls = hxd.impl.Api.downcast(getLightSystem(), h3d.scene.pbr.LightSystem);
 		ls.forwardMode = true;
-		setTargets([textures.hdr, textures.depth]);
+		#if js
+		setTargets([textures.hdr, getPbrDepth()]);
+		#end
 		renderPass(colorDepthOutput, get("forward"));
 		setTarget(textures.hdr);
 		renderPass(defaultPass, get("forwardAlpha"), backToFront);
@@ -570,19 +602,27 @@ class Renderer extends h3d.scene.Renderer {
 			return;
 		}
 
+		setTarget(textures.hdr, ReadOnly);
 		begin(BeforeTonemapping);
+		setTarget(textures.hdr, ReadOnly);
 		draw("beforeTonemappingDecal");
+		setTarget(textures.hdr);
 		draw("beforeTonemapping");
+		setTarget(textures.hdr, ReadOnly);
 		end();
 
-		setTarget(textures.ldr);
+		setTarget(textures.ldr, ReadOnly);
 		tonemap.render();
 
 		begin(AfterTonemapping);
+		setTarget(textures.ldr, ReadOnly);
 		draw("afterTonemappingDecal");
+		setTarget(textures.ldr);
 		draw("afterTonemapping");
+		setTarget(textures.ldr, ReadOnly);
 		end();
 
+		setTarget(textures.ldr);
 		begin(Overlay);
 		draw("overlay");
 		end();