Sign in to follow this  

Array in constant buffer

This topic is 670 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm using SharpDX (compatible with SlimDX) and trying to put arrays into a constant buffer.

 

I made a struct and gave it a StructLayout with LayoutKind.Explicit and I manually set Size also.

 

Inside the struct, I make arrays with attributes FieldOffset and MarshalAs in which I set UnmanagedType.ByValArray and I manually set SizeConst.

 

When I instantiate the struct, I create the arrays to the size I specified.  Then I populate them with the values I want.

 

Then I update the constant buffer with my struct data, and the size is divisible by 16.

 

In the shader, I have the arrays of corresponding data types set to the sizes to match the ones in C#.  It's all inside a tbuffer.

 

But then when I run the pixel shader, all the values it reads from the arrays seem to be 0, regardless of what values I set in it.

 

I know the constant buffer in general is working, because it was working before I added the arrays to the structure.

 

So what could be wrong?

Share this post


Link to post
Share on other sites

I tried some more stuff but it still doesn't work:

 

I tried to make the tbuffer a cbuffer because it didn't seem to be compatible with tbuffers (but the reason I made it a tbuffer in the first place was that I got an error that the cbuffer was bigger than it was allowed to be).

 

But then I separated it into to structs, and kept that part without arrays as a cbuffer and put all arrays into a tbuffer.

 

I also made two ConstantBuffer objects - one for each structure type, and I set them to slot 0 and slot 1 and I update them both just before trying to draw anything.

 

Also, I tried setting the cbuffer to : register (b0) and the tbuffer to : register (t1) - is that right?

 

Now it's only drawing an image if I give it hard-coded numbers in the pixel shader, so I know it's able to draw, but it still gets 0 (looks black) whenever it reads any number as a color from an array in the tbuffer.

Share this post


Link to post
Share on other sites

I can't.  I don't have it with me and I'm not at liberty to divulge.  I'm not sure why everyone always wants to see the code every single time though, no matter how detailed my explanation is.

 

Really all I need is any possible explanation of how to use constant or texture buffers with arrays in them and get the data into the array so that it actually gets into the pixel shader.

 

I wouldn't think it should be this insufferably difficult to do.

Share this post


Link to post
Share on other sites


What I really need is any source code or a link so it that has a complete example (even a simple one) of just how to put arrays into a buffer and get them to be used by the pixel shader.  That's all.

 

In that case, You can google search for tutorials and sample codes on the subject. Unbird's post-link could be a starting place

Share this post


Link to post
Share on other sites

Well I tried it but it didn't work.

 

By the way, I did it slightly differently, because I'm not using an array, I'm using a structure that contains several arrays of different types.  And I'm putting it in a texture buffer rather than a constant buffer (the constant buffers don't provide enough memory).

 

So the way I did it was to use Write<> rather than WriteRange.  But I set up the buffer description the same but with the size in bytes that I need.

 

Other than that, I did it how you said, but I still got a black screen.

 

Also, when I update my constant buffer resource (I do that for the constant buffer, and the texture buffer, because I couldn't find a different function for that), I tried setting it with only the first 2 parameters but was afraid it may be overwriting it so I also tried setting the third (optional) parameter (it's an int called subresource or something) and I set it to 0 for the constant buffer and 1 for the texture buffer (that corresponds to the registers they use although they're called b0 and t1 respectively).  I don't know if this is correct but I tried it with and without it.

 

Anyway, whatever I do, it's always a black screen.

Share this post


Link to post
Share on other sites


I have searched for them and the ones I used didn't work.  That's why I came here.

Well I tried it but it didn't work. By the way, I did it slightly differently

Anyway, whatever I do, it's always a black screen.


This is why people keep asking for source. All anyone can do without it is blindly guess and point you to working implementations. If you still can't make it work, then you're obviously doing something wrong. If you want some actual, constructive help, post the code!

Share this post


Link to post
Share on other sites

Well it's a real mess.  I've made a simplified example - about as simple as I think it could even be.  As it turns out, I'm not even sure my constant buffer data is getting through at all!  (Except that I'm pretty sure the transformation matrix is going through, otherwise how would the multiplication work?  And it usually does, but right now I can't tell because the screen is black anyway.)

This is some test code I've written to draw a single triangle using a constant buffer.  Don't worry about the texture coordinates, because it's ignoring them, but they never interfered with anything anyway.  All I'm trying to do is put a test color into the constant buffer and make the pixel shader always output that color, so that it just draws one triangle that is that color:
 

 

using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using SharpDX.D3DCompiler;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace test_namespace
{
    class Test
    {
        [StructLayout(LayoutKind.Explicit, Size = 80, Pack = 16)]
        public struct Data
        {
            [FieldOffset(0)]
            public Matrix mat;
            [FieldOffset(64)]
            public Vector4 testColor;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct Point
        {
            [FieldOffset(0)]
            public Vector4 pos;
            [FieldOffset(16)]
            public Vector2 tex;
        }

        int width = 1000;
        int height = 1000;
        const int vertSize = 6 * sizeof(float);
        RenderForm form;
        PictureBox pic;
        SharpDX.Direct3D11.Device dev;
        DeviceContext dc;
        SwapChainDescription scd;
        SwapChain sc;
        RasterizerStateDescription rsd;
        RasterizerState rs;
        Viewport vp;
        Texture2DDescription depthDesc;
        DepthStencilView dsv;
        RenderTargetView rtv;
        SharpDX.Direct3D11.Buffer buffer;
        InputLayout il;
        VertexShader vs;
        ShaderBytecode vsCode;
        PixelShader ps;
        ShaderBytecode psCode;
        Matrix view;
        Matrix proj;
        Matrix mat;
        Data data;
        DataStream pointStream;
        SharpDX.Direct3D11.Buffer pointBuffer;

        public Test()
        {
            init();
            initMat();

            data.testColor = new Vector4(1.0f, 0.5f, 0.25f, 0.0f);

            string code = "struct vert { float4 pos : POSITION; float2 tex : TEXCOORD; };\n"
              + "struct pix { float4 pos : SV_POSITION; float2 tex : TEXCOORD; };\n"
              + "cbuffer buf1 : register(b0) { float4x4 mat; float4 testColor; }\n"
              + "pix VS(vert vertIn) { pix pixOut = (pix)0; pixOut.pos = mul(vertIn.pos, mat); pixOut.tex = vertIn.tex; return pixOut; }\n"
              + "float4 PS(pix pixIn) : SV_Target { return testColor; }";

            vsCode = ShaderBytecode.Compile(code, "VS", "vs_5_0");
            vs = new VertexShader(dev, vsCode);
            psCode = ShaderBytecode.Compile(code, "PS", "ps_5_0");
            ps = new PixelShader(dev, psCode);

            dc.VertexShader.Set(vs);
            dc.PixelShader.Set(ps);

            il = new InputLayout(dev, ShaderSignature.GetInputSignature(vsCode),
              new InputElement[] {new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0),
              new InputElement("TEXCOORD", 0, Format.R32G32_Float, 16, 0)});

            dc.InputAssembler.InputLayout = il;
            dc.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;

            updateBuffer();

            RenderLoop.Run(form, () =>
            {
                dc.ClearDepthStencilView(dsv, DepthStencilClearFlags.Depth, 1.0f, 0);
                dc.ClearRenderTargetView(rtv, Color4.Black);
                float dist = 10.0f;
                draw(new Vector3(-dist, -dist, dist), Vector2.Zero, new Vector3(-dist, dist, dist), Vector2.UnitY,
                  new Vector3(dist, dist, dist), Vector2.One);
            });
        }

        void init()
        {
            form = new RenderForm();
            form.ClientSize = new System.Drawing.Size(width, height);
            form.BackColor = System.Drawing.Color.Black;
            form.FormClosed += form_FormClosed;
            pic = new PictureBox();
            pic.Location = new System.Drawing.Point(0, 0);
            pic.Size = new Size(width, height);
            pic.Show();
            form.Controls.Add(pic);

            scd = new SwapChainDescription();
            scd.BufferCount = 1;
            scd.Flags = SwapChainFlags.AllowModeSwitch;
            scd.IsWindowed = true;
            scd.ModeDescription = new ModeDescription(width, height, new Rational(60, 1), Format.R8G8B8A8_UNorm);
            scd.OutputHandle = pic.Handle;
            scd.SampleDescription = new SampleDescription(1, 0);
            scd.SwapEffect = SwapEffect.Discard;
            scd.Usage = Usage.RenderTargetOutput;

            rsd = new RasterizerStateDescription();
            rsd.CullMode = CullMode.None;
            rsd.DepthBias = 0;
            rsd.DepthBiasClamp = 0;
            rsd.FillMode = FillMode.Solid;
            rsd.IsAntialiasedLineEnabled = true;
            rsd.IsDepthClipEnabled = true;
            rsd.IsFrontCounterClockwise = false;
            rsd.IsMultisampleEnabled = true;
            rsd.IsScissorEnabled = false;
            rsd.SlopeScaledDepthBias = 0;

            SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, scd, out dev, out sc);
            rs = new RasterizerState(dev, rsd);
            vp = new Viewport(0, 0, width, height, 0.0f, 1.0f);
            dc = dev.ImmediateContext;
            dc.Rasterizer.State = rs;
            dc.Rasterizer.SetViewports(vp);

            depthDesc = new Texture2DDescription();
            depthDesc.ArraySize = 1;
            depthDesc.BindFlags = BindFlags.DepthStencil;
            depthDesc.CpuAccessFlags = CpuAccessFlags.None;
            depthDesc.Format = Format.D32_Float_S8X24_UInt;
            depthDesc.Height = height;
            depthDesc.MipLevels = 1;
            depthDesc.OptionFlags = ResourceOptionFlags.None;
            depthDesc.SampleDescription = new SampleDescription(1, 0);
            depthDesc.Usage = ResourceUsage.Default;
            depthDesc.Width = width;

            dsv = new DepthStencilView(dev, new Texture2D(dev, depthDesc));
            rtv = new RenderTargetView(dev, (SharpDX.Direct3D11.Resource)SharpDX.Direct3D11.Resource.FromSwapChain<Texture2D>(sc, 0));
            dc.OutputMerger.SetTargets(dsv, rtv);

            buffer = new SharpDX.Direct3D11.Buffer(dev, Marshal.SizeOf(typeof(Data)),
              ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
            dc.VertexShader.SetConstantBuffer(0, buffer);
        }

        void initMat()
        {
            view = Matrix.LookAtLH(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
            proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)width / (float)height, 0.001f, 10000.0f);
            mat = view * proj;
            mat.Transpose();
            data.mat = mat;
        }

        void updateBuffer()
        {
            dc.UpdateSubresource<Data>(ref data, buffer);
        }

        public void draw(Vector3 p1, Vector2 t1, Vector3 p2, Vector2 t2, Vector3 p3, Vector2 t3)
        {
            Vector3[] p = new Vector3[3] {p1, p2, p3};
            Vector2[] t = new Vector2[3] {t1, t2, t3};
            Point[] points = new Point[3];
            for(int i = 0; i < 3; i++)
            {
                points[i] = new Point();
                points[i].pos = new Vector4(p[i].X, p[i].Y, p[i].Z, 1.0f);
                points[i].tex = new Vector2(t[i].X, t[i].Y);
            }
            using(pointStream = new DataStream(vertSize * 3, true, true))
            {
                pointStream.WriteRange<Point>(points);
                using(pointBuffer = new SharpDX.Direct3D11.Buffer(dev, pointStream, vertSize * 3,
                  ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0))
                {
                    dc.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
                    dc.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(pointBuffer, vertSize, 0));
                    dc.Draw(3, 0);
                }
            }
        }

        void form_FormClosed(object sender, FormClosedEventArgs e)
        {
            buffer.Dispose();
            il.Dispose();
            ps.Dispose();
            psCode.Dispose();
            vs.Dispose();
            vsCode.Dispose();
            rtv.Dispose();
            dsv.Dispose();
            dc.ClearState();
            dc.Flush();
            dc.Dispose();
            dev.Dispose();
            sc.Dispose();
        }
    }
}
 

 

 

 

 

 

Also, here is the shader code formatted in a more readable way:

 

 

 

 

 

 

struct vert
{
    float4 pos : POSITION;
    float2 tex : TEXCOORD;
};

struct pix
{
    float4 pos : SV_POSITION;
    float2 tex : TEXCOORD;
};

cbuffer buf1 : register(b0)
{
    float4x4 mat;
    float4 testColor;
}

pix VS(vert vertIn)
{
    pix pixOut = (pix)0;
    pixOut.pos = mul(vertIn.pos, mat);
    pixOut.tex = vertIn.tex;
    return out;
}

float4 PS(pix pixIn) : SV_Target
{
    return testColor;
}

 

 

 

 

Right now it's just black.  I've tried replacing the line in the pixel shader that returns the color by making it return a hard-coded constant color instead.  That doesn't work, so I guess something is wrong with it's ability to draw anything at all.  I didn't have time to mess with it as much as I'd like, but there's no way around that.  I also tried pulling the stuff out of the render loop to see if it would just run once, and calling form.Show(), but that didn't work either.

Anyway, I'm sure getting it to display a triangle is easy and I overlooked something simple, but I don't know what.

 

Then the next step would be to get it to actually use the testColor variable in the constant buffer to display the color I specify.

 

Once that works, I need to be able to get an arbitrary number of possibly large arrays into the constant buffer (and make it multiple constant buffers or texture buffers if necessary), and make sure it's still able to read all that data.

 

If you want to test it, you should be able to just copy all the code into one file, then make another main file that calls the constructor to make the window.  It's that simple.

 

I can't seem to get any of it working though.  Does anyone have any ideas?

Edited by myvraccount

Share this post


Link to post
Share on other sites

Well you wanted a code sample.  I've made one.  It's complete and should compile.

 

Does anyone have any ideas how to fix it?

 

Not to rush, but I really would like it soon if possible, because I only have time to work on this on Saturdays, so if I can't fix it by then, it's delayed another week!

Share this post


Link to post
Share on other sites
I hear you, this is really weird. I put together a working version (minor changes, seems I used a different SharpDX version), including both the approach I showed and your fixed array variant. Had to fix a couple of other bugs which naturally crawled in with your effort.

I can guide you through the how-to if you wish (it's usually better to learn the debugging techniques than just be given the solution wink.png).

For the future: You seem to be under a restrictive NDA, so I'd advertise that more clearly (e.g. in your signature). Otherwise your threads will continue to look this way.

Share this post


Link to post
Share on other sites

God, everyone says post source code, then when I spend hours putting something together that I can post and actually do, I hear no more responses.  What happened?

That was just standard advice to make it more likely that someone would be able to help you, not a guarantee. Always keep in mind that there are a number of people coming here from different timezones around the world, with varying skill sets. It sometimes may take a while before someone with the ability to recognize your problem comes along, if at all. Some problems are easier to solve than others, but posting source is a minimal first step.

Share this post


Link to post
Share on other sites

I know, Aldacron.  It's just that I was getting frustrated and perhaps a bit impatient and it had been a few days, and I really wanted a solution by tomorrow.

 

Thanks, unbird, I'll look at your example.  Also, it has occurred to me after looking at another example (a little different because it's C++ and using a buffer description object instead of putting all those parameters directly into the buffer constructor) that maybe part of the problem is that I don't have the cpu access flags set to write, and the usage is not set to dynamic.

 

Might this be part of the problem and did you change that in the example?  (I'll look at your example tomorrow when I have more time).

Share this post


Link to post
Share on other sites

unbird, thanks a lot!  I had a chance to look at your code (I haven't been able to try it out yet, but I'll do that tomorrow).

 

It looks like you fixed a lot of problems.  Would this also work with a tbuffer?  Because I was making such big arrays that it was telling me that the cbuffer ran out of memory but then I changed to a tbuffer and stopped getting that error.

 

Anyway, I can't wait to try it out!

Share this post


Link to post
Share on other sites
tbuffers work similarily. Upload is done the same way. And indeed the limit is higher (at least 128 Mb).
They come in different flavors :
  • generic (e.g. [tt]Buffer<float4>[/tt] in HLSL). Allows what DXGI_FORMAT can cover, not every format is allowed though.
  • structured (e.g. [tt]StructuredBuffer<matrix>[/tt]). Allows self-defined structs, though only (u)ints and floats work directly as basic types.
  • raw ([tt]ByteAddressBuffer[/tt]). Here you basically manage the memory yourself.
They are a bit more complicated to set up since they're now bound indirectly through views (like textures): shader resource view for reading or unordered access view for reading and writing ([tt]RW[/tt] prefix in HLSL, registers u#). It needs a bit fiddling with the flags but the D3D debug layer (which you already have enabled) will help you there.

Here an example of a structured buffer ([tt][RW]StructuredBuffer<float3>[/tt]):

var arraySize = 12;
structuredBuffer = new SharpDX.Direct3D11.Buffer(device, new BufferDescription()
{
    BindFlags = BindFlags.ShaderResource | BindFlags.UnorderedAccess,
    CpuAccessFlags = CpuAccessFlags.None,
    OptionFlags = ResourceOptionFlags.BufferStructured,
    SizeInBytes = arraySize * Marshal.SizeOf(typeof(Vector3)),
    StructureByteStride = Marshal.SizeOf(typeof(Vector3)),
    Usage = ResourceUsage.Default,
});
structureBufferSRV = new ShaderResourceView(device, structuredBuffer, new ShaderResourceViewDescription()
{
    BufferEx = new ShaderResourceViewDescription.ExtendedBufferResource()
    {
        ElementCount = arraySize,
        FirstElement = 0,
        Flags = ShaderResourceViewExtendedBufferFlags.None,
    },
    Format = Format.Unknown,
    Dimension = ShaderResourceViewDimension.ExtendedBuffer,
});
structureBufferUAV = new UnorderedAccessView(device, structuredBuffer, new UnorderedAccessViewDescription()
{
    Buffer = new UnorderedAccessViewDescription.BufferResource()
    {
        ElementCount = arraySize,
        FirstElement = 0,
        Flags = UnorderedAccessViewBufferFlags.None,
    },
    Format = Format.Unknown,
    Dimension = UnorderedAccessViewDimension.Buffer,
});

Share this post


Link to post
Share on other sites

This topic is 670 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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