Sign in to follow this  
Ivo Leitao

[SlimDX][D3D10/11] Problem setting matrix variable

Recommended Posts

Hi,

I'm working in a language that outputs to hlsl namely hlsl 2.0, 3.0, and 4.0. This language supports basic scalar types (bool, int and float), vector types (float2, float3 and float4) and matrix types (float2x2, float3x3 and float4x4). The vector and matrix types are custom defined.

I support global variables in this language and thus it allows get/set operations in them. In my D3D9 ouput I'm using the [font="consolas"]SetValue<T> and GetValue<T> [/font]without any kind of problems, namely I'm able to get and set Matrix variables correctly. In my D3D10/11 output I'm having problems setting and obtaining the values from matrix variables (float2x2, float3x3 and float4x4). The problem is, I'm not getting the expected output. Everything works just fine with the scalar variables and the vector variables. The problem is the matrix variables. With D3D10 and D3D11 I'm using the GetRawValue method (I've compiled the latest version of SlimDX since the Get/SetRawValue method was not in the last official release)

To illustrate the problem I'm providing the following code snippet which builds a Quad and obtains a matrix variable through the pixel shader. The program bellow also allows setting and getting global variables from the shader. It needs a custom compiled version of slimdx because it uses the Get/SetRawValue functions.

The problem is on the following lines:
[code]
bool test = prg.GetOutput<Float2x2>().Equals(new Float2x2(1.0f, 2.0f, 3.0f, 4.0f)); //OK
test &= prg.GetVariable<Float2x2>("a").Equals(new Float2x2(1.0f, 2.0f, 3.0f, 4.0f)); //Error, I'm getting Float2x2(1.0f, 3.0f, 0.0f, 0.0f)
[/code]

The code is here:
[code]
namespace Test
{
using global::SlimDX;
using global::SlimDX.D3DCompiler;
using global::SlimDX.DXGI;
using D3D10 = global::SlimDX.Direct3D10;
using System;
using System.Runtime.InteropServices;
using SlimDX.Windows;

public class Program2 : IDisposable
{
#region Types

[Serializable, StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct Float4 : IEquatable<Float4>
{
#region Fields

public float X;
public float Y;
public float Z;
public float W;

#endregion

#region Constructors

public Float4(float x, float y, float z, float w)
{
this.X = x;
this.Y = y;
this.Z = z;
this.W = w;
}

#endregion

#region Operators

public static bool operator ==(Float4 value1, Float4 value2)
{
return value1.X == value2.X && value1.Y == value2.Y && value1.Z == value2.Z && value1.W == value2.W;
}

public static bool operator !=(Float4 value1, Float4 value2)
{
return value1.X != value2.X || value1.Y != value2.Y || value1.Z != value2.Z || value1.W != value2.W;
}

#endregion

#region Methods

public override int GetHashCode()
{
return (int)(this.X + this.Y + this.Z + this.W);
}

public override bool Equals(object obj)
{
if (!(obj is Float4))
{
return false;
}

return (Float4)obj == this;
}

public bool Equals(Float4 other)
{
return this == other;
}

#endregion
}

[Serializable, StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct Float2x2 : IEquatable<Float2x2>
{
#region Fields

public float M00;
public float M01;
public float M10;
public float M11;

#endregion

#region Constructors

public Float2x2(float value)
{
this.M00 = this.M01 = this.M10 = this.M11 = value;
}

public Float2x2(float m00, float m01,
float m10, float m11)
{
this.M00 = m00;
this.M01 = m01;
this.M10 = m10;
this.M11 = m11;
}

#endregion

#region Operators

public static bool operator ==(Float2x2 value1, Float2x2 value2)
{
return value1.M00 == value2.M00 && value1.M01 == value2.M01
&& value1.M10 == value2.M10 && value1.M11 == value2.M11;
}

public static bool operator !=(Float2x2 value1, Float2x2 value2)
{
return value1.M00 != value2.M00 || value1.M01 != value2.M01
|| value1.M10 != value2.M10 || value1.M11 != value2.M11;
}

#endregion

#region Methods

public override int GetHashCode()
{
return (int)(this.M00 + this.M01
+ this.M10 + this.M11);
}

public override bool Equals(object obj)
{
if (!(obj is Float2x2))
{
return false;
}

return (Float2x2)obj == this;
}

public bool Equals(Float2x2 other)
{
return this == other;
}

#endregion
}

private struct VertexPosition10
{
#region Constants

public static readonly D3D10.InputElement[] Elements = new D3D10.InputElement[]
{
new D3D10.InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0)
};

#endregion

#region Fields

public Vector3 Position;

#endregion

#region Constructors

public VertexPosition10(Vector3 position)
{
this.Position = position;
}

#endregion

#region Properties

public static int SizeInBytes
{
get
{
return Marshal.SizeOf(typeof(VertexPosition10));
}
}

#endregion
}

#endregion

#region Constants

private string EffectCode =
@"struct VertexShaderInput
{
float3 pos : POSITION;
};

struct VertexShaderOutput
{
float4 pos : SV_POSITION;
float2 coord : TEXCOORD0;
};

struct PixelShaderOutput
{
float4 Output0 : SV_Target0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;

output.pos = float4(input.pos, 1);
output.coord = 0.5 * input.pos.xy + 0.5;

return output;
}

float2x2 a = float2x2(1.0, 2.0, 3.0, 4.0);

PixelShaderOutput PixelShaderFunction()
{
PixelShaderOutput output = (PixelShaderOutput)0;

output.Output0 = a._11_12_21_22;

return output;
}

technique10 Default
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VertexShaderFunction()));
SetGeometryShader(0);
SetPixelShader( CompileShader(ps_4_0, PixelShaderFunction()));
}
}";

private static VertexPosition10[] Vertices = new VertexPosition10[]
{
new VertexPosition10(new Vector3(-1.0f, -1.0f, 0.5f)),
new VertexPosition10(new Vector3(-1.0f, 1.0f, 0.5f)),
new VertexPosition10(new Vector3(1.0f, -1.0f, 0.5f)),
new VertexPosition10(new Vector3(1.0f, 1.0f, 0.5f))
};

private static short[] Indices = new short[] { 0, 1, 2, 3 };

#endregion

#region Fields

private int width = 1;
private int height = 1;

private RenderForm renderForm;

private Factory factory;
private Adapter adapter;
private SwapChainDescription swapChainDescription;
private SwapChain swapChain;

private D3D10.Device device;
private D3D10.Effect effect;
private D3D10.EffectPass pass;
private D3D10.InputLayout inputLayout;
private D3D10.Buffer vertexBuffer;
private D3D10.Buffer indexBuffer;
private D3D10.RenderTargetView backbuffer;
private D3D10.Texture2D gpuTexture;
private D3D10.Texture2D cpuTexture;
private Surface cpuSurface;
private D3D10.RenderTargetView renderTarget;

#endregion

#region Constructors

public Program2()
{
}

~Program2()
{
Dispose(false);
}

#endregion

#region Methods

public T GetVariable<T>(string name)
where T: struct
{
return this.effect.GetVariableByName(name).GetRawValue(Marshal.SizeOf(typeof(T))).Read<T>();
}

public void SetVariable<T>(string name, T value)
where T: struct
{
int sizeInBytes = Marshal.SizeOf(typeof(T));
using (DataStream ds = new DataStream(sizeInBytes, true, true))
{
ds.Write<T>(value);
ds.Position = 0;
this.effect.GetVariableByName(name).SetRawValue(ds, sizeInBytes);
}
}

private void CreateForm()
{
this.renderForm = new RenderForm();
}

private void CreateDevice()
{
this.factory = new Factory();
this.adapter = this.factory.GetAdapter(0);
this.device = new D3D10.Device(
this.adapter,
D3D10.DriverType.Hardware,
D3D10.DeviceCreationFlags.Debug);

this.swapChainDescription = new SwapChainDescription
{
BufferCount = 1,
Flags = SwapChainFlags.None,
IsWindowed = true,
ModeDescription = new ModeDescription(
this.width,
this.height,
new Rational(60, 1),
Format.R8G8B8A8_UNorm),
OutputHandle = this.renderForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};

this.swapChain = new SwapChain(this.factory, this.device, this.swapChainDescription);
this.factory.SetWindowAssociation(this.renderForm.Handle, WindowAssociationFlags.IgnoreAll | WindowAssociationFlags.IgnoreAltEnter);
}

private void CreateEffect()
{
string compilationErrors;
this.effect = D3D10.Effect.FromString(
this.device,
EffectCode,
"fx_4_0",
ShaderFlags.None,
EffectFlags.None,
null,
null,
null,
out compilationErrors);
this.pass = this.effect.GetTechniqueByName("Default").GetPassByName("P0");
}

private void LoadVariables()
{
}

private void CreateInput()
{
int sizeInBytes = Vertices.Length * VertexPosition10.SizeInBytes;
using (DataStream ds = new DataStream(sizeInBytes, true, true))
{
ds.WriteRange(Vertices);
ds.Position = 0;

this.vertexBuffer = new D3D10.Buffer(
this.device,
ds,
new D3D10.BufferDescription()
{
SizeInBytes = sizeInBytes,
Usage = D3D10.ResourceUsage.Default,
BindFlags = D3D10.BindFlags.VertexBuffer,
CpuAccessFlags = D3D10.CpuAccessFlags.None,
OptionFlags = D3D10.ResourceOptionFlags.None
}
);
}

sizeInBytes = Indices.Length * Marshal.SizeOf(typeof(short));
using (DataStream ds = new DataStream(sizeInBytes, true, true))
{
ds.WriteRange(Indices);
ds.Position = 0;

this.indexBuffer = new D3D10.Buffer(
this.device,
ds,
new D3D10.BufferDescription()
{
SizeInBytes = sizeInBytes,
Usage = D3D10.ResourceUsage.Default,
BindFlags = D3D10.BindFlags.IndexBuffer,
CpuAccessFlags = D3D10.CpuAccessFlags.None,
OptionFlags = D3D10.ResourceOptionFlags.None
}
);
}

this.inputLayout = new D3D10.InputLayout(this.device, pass.Description.Signature, VertexPosition10.Elements);
}

private void CreateOutput()
{
using (D3D10.Texture2D texture = D3D10.Texture2D.FromSwapChain<D3D10.Texture2D>(this.swapChain, 0))
{
this.backbuffer = new D3D10.RenderTargetView(this.device, texture);
}

this.gpuTexture = new D3D10.Texture2D(
this.device,
new D3D10.Texture2DDescription()
{
Width = this.width,
Height = this.height,
Format = Format.R32G32B32A32_Float,
Usage = D3D10.ResourceUsage.Default,
ArraySize = 1,
MipLevels = 1,
BindFlags = D3D10.BindFlags.RenderTarget,
SampleDescription = new SampleDescription(1, 0),
CpuAccessFlags = D3D10.CpuAccessFlags.None,
OptionFlags = D3D10.ResourceOptionFlags.None
});
this.cpuTexture = new D3D10.Texture2D(
this.device,
new D3D10.Texture2DDescription()
{
Width = this.width,
Height = this.height,
Format = Format.R32G32B32A32_Float,
Usage = D3D10.ResourceUsage.Staging,
ArraySize = 1,
MipLevels = 1,
BindFlags = D3D10.BindFlags.None,
SampleDescription = new SampleDescription(1, 0),
CpuAccessFlags = D3D10.CpuAccessFlags.Read,
OptionFlags = D3D10.ResourceOptionFlags.None
});
this.cpuSurface = this.cpuTexture.AsSurface();
this.renderTarget = new D3D10.RenderTargetView(this.device, this.gpuTexture);
}

public void Initialize()
{
CreateForm();
CreateDevice();
}

public void LoadContent()
{
CreateEffect();
LoadVariables();
CreateInput();
CreateOutput();
}

public virtual void UnloadContent()
{
Dispose(true);
}

public void DrawQuad()
{
this.device.InputAssembler.SetInputLayout(this.inputLayout);
this.device.InputAssembler.SetPrimitiveTopology(D3D10.PrimitiveTopology.TriangleStrip);
this.device.InputAssembler.SetIndexBuffer(this.indexBuffer, Format.R16_UInt, 0);
this.device.InputAssembler.SetVertexBuffers(0, new D3D10.VertexBufferBinding(this.vertexBuffer, VertexPosition10.SizeInBytes, 0));

this.pass.Apply();
this.device.DrawIndexed(Indices.Length, 0, 0);
}

public T GetOutput<T>()
where T: struct
{
this.device.OutputMerger.SetTargets(this.renderTarget);
this.device.Rasterizer.SetViewports(new D3D10.Viewport(0, 0, this.width, this.height, 0.0f, 1.0f));

DrawQuad();

this.device.CopyResource(this.gpuTexture, this.cpuTexture);
DataRectangle dr = this.cpuSurface.Map(MapFlags.Read);
this.cpuSurface.Unmap();

return dr.Data.Read<T>();
}

private static void Dispose<T>(T target)
where T : class, IDisposable
{
ComObject co = target as ComObject;
if (target != null && (co == null || !co.Disposed))
{
target.Dispose();
}
}

private static void Dispose<T>(ref T target)
where T : class, IDisposable
{
if (target != null)
{
Dispose<T>(target);
target = null;
}
}

private static void Dispose<T>(ref T[] target)
where T : class, IDisposable
{
if (target != null)
{
for (int i = 0; i < target.Length; i++)
{
Dispose(ref target[i]);
}

target = null;
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposeManagedResources)
{
if (disposeManagedResources)
{
Dispose(ref this.cpuSurface);
Dispose(ref this.cpuTexture);
Dispose(ref this.gpuTexture);
Dispose(ref this.renderTarget);
Dispose(ref this.effect);
Dispose(ref this.inputLayout);
Dispose(ref this.vertexBuffer);
Dispose(ref this.indexBuffer);
Dispose(ref this.backbuffer);
Dispose(ref this.device);
Dispose(ref this.swapChain);
Dispose(ref this.adapter);
Dispose(ref this.factory);
}
}

#endregion

static void Main(string[] args)
{
using (Program2 prg = new Program2())
{
prg.Initialize();
prg.LoadContent();
bool test = prg.GetOutput<Float2x2>().Equals(new Float2x2(1.0f, 2.0f, 3.0f, 4.0f)); //OK
test &= prg.GetVariable<Float2x2>("a").Equals(new Float2x2(1.0f, 2.0f, 3.0f, 4.0f)); //Error, I'm getting Float2x2(1.0f, 3.0f, 0.0f, 0.0f)
}

Console.ReadKey();
}
}
}
[/code]

Any help on this ?
Tnks in advance

Share this post


Link to post
Share on other sites
I've post an issue concerning this in the slimdx issues area. It's located here [url="http://code.google.com/p/slimdx/issues/detail?id=780"]http://code.google.com/p/slimdx/issues/detail?id=780[/url]. I've managed to correct the issue and I have attached some code in there to handle this case.

Tnks

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this