shader bytecode question

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

1 Like

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. :slight_smile: