Can i use raw HLSL shader bytecode directly to monogame? without compile into monogame MGFX content.
Iām no authority on this but I reason that if you use the windows template project - it uses SharpDX (I think is updated as needed for Monogame since original is no longer being upgraded) ā¦ and so it should be possible to integrate with something like this:
āā'csharp
// CUSTOM S H A D E R P A R A M E T E R S G O H E R E ------------------------
[StructLayout(LayoutKind.Explicit, Size = 16)] // 16 bytes total
public struct CBUFFER_PS // DEFAULT VERTEX SHADER VARS
{
[FieldOffset(0)] // just a reminder to watch data alignment
public float timer; // animation timer
[FieldOffset(4)]
public float waterTop; // top of water (range 0.0 - 1.0 on bitmap [reflection region])
[FieldOffset(8)]
public int justDistort; // distortion only (use int, not bool)
[FieldOffset(12)]
public float padding; // blank padding - (alignment)
};
//------------------------------------
public class MeoEffect : IDisposable {
bool disposed = false;
private d3d.Buffer constantBufferPS;
private Device dev;
private DeviceContext dvc;
public PixelShader PS; // custom pixel shader
public CBUFFER_PS vars;
// C O N S T R U C T O R
public MeoEffect(Device device, string FileName) {
if (!File.Exists(FileName)) {this.Report("Compiled pixel shader file not found: {0} ", FileName); return;}
dev = device; dvc = device.ImmediateContext;
using (var ps = ShaderBytecode.FromFile(FileName)) { PS = new PixelShader(dev, ps); } // load pre-compiled shader
if (PS==null) {this.Report("in MeoEffect - unable to create pixel shader"); return;}
int size = Marshal.SizeOf(typeof (CBUFFER_PS));
d3d.BufferDescription BuffDesc = new d3d.BufferDescription(size,ResourceUsage.Dynamic,BindFlags.ConstantBuffer,CpuAccessFlags.Write,ResourceOptionFlags.None,0);
constantBufferPS = new d3d.Buffer(dev, BuffDesc);
}
// U P D A T E V A R S
public void UpdateVars() {
if ((constantBufferPS==null)||(PS==null)) return;
DataStream mappedResource;
dvc.MapSubresource(constantBufferPS, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out mappedResource);
mappedResource.Write(vars);
dvc.UnmapSubresource(constantBufferPS, 0);
mappedResource.Dispose();
dvc.PixelShader.SetConstantBuffer(0, constantBufferPS);
}
// D I S P O S E
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (disposed) return;
if (disposing) { } // dispose managed
if (constantBufferPS != null) { constantBufferPS.Dispose(); constantBufferPS = null; }
if (PS != null) { PS.Dispose(); PS = null; }
disposed = true;
}
~MeoEffect() { Dispose(false); }
}
āāā
Iāve not yet tried it in Monogame itself, but Iād imagine as long as the shader is set in the appropriate place and parameters are updated as needed - it ā¦ hypothetically should work?
Anyone else?
What if I wan to change the effect parameters on runtime ? What should I do?
I actually tested the concept now and it works.
using SharpDX.Direct3D11 //(added with nuGet)
in init I add this:
dev = (SharpDX.Direct3D11.Device)GraphicsDevice.Handle; // Device (SharpDX)
dvc = dev.ImmediateContext; // DeviceContext (SharpDX [needed to set pixel shader])
In Load:
// * MUST COPY THIS INTO BINARY EXECUTABLEāS CONTENT FOLDER (with xnb files) *
waterPS = new HLSL_Effect(dev, āunderwaterPS.csoā);
Updating the constant buffers doesnāt work unless you set the b register for the cbuffer in the shader:
This is in the default vertex shader (which also has a default pixel shader):
cbuffer Parameters : register(b0) {
float4x4 MatrixTransform;
};
By default I think spriteBatch and other poly-batching VS stuff would use b0 first for whatever cbuffer
and in the replacement PIXEL SHADER (compiled cso / HLSL) I have this:
cbuffer WaterBuffer : register(b1) //<---- USING REGISTER (B1) ā¦ so must use slot 1 (slot 0 already used)
{
float timer; // for animating
float waterTop; // where is top of the water
int justDistort; // use int on cpu side
float padding; // blankā¦for alignment
};
So in the custom shaderUpdate - youād do something like this:
// U P D A T E V A R S
public void UpdateVars()
{
if ((constantBufferPS == null) || (PS == null)) { Console.WriteLine("ConstantBufferPS or PS are null"); return; }
DataStream mappedResource;
dvc.MapSubresource(constantBufferPS, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out mappedResource);
mappedResource.Write(vars);
dvc.UnmapSubresource(constantBufferPS, 0);
mappedResource.Dispose();
dvc.PixelShader.SetConstantBuffer( 1 , constantBufferPS); // <SLOT 1 register(b1)
}
Then in Update:
waterPS.vars.timer += 0.15f; // CHANGE CUSTOM PS VARS
waterPS.UpdateVars(); // UPDATE CUSTOM PS
If youāre using SpriteBatch, you can set the shader before End() or if using your own batcher you could do this:
quadBatch.End(dvc, waterPS);
and then in it:
dvc.PixelShader.Set(hlsl_fx.PS);
device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vert_count, indices, 0, triangle_count);
Hopefully that helps. I just note that I had some trouble initially with my shaders in Windows-only version cuz I didnāt realize right away that VS must receive SV_POSITION and PS must not but instead POSITION0
But yah - I tested out my old water shader from shader-byte code and hereās the result:
Great! thank you so much
Hopefully you can get it working - itās possible I missed explaining something right so if you have any questions - Iām happy to help.