0
votes

This is C# WPF using SharpDX 4.0.

I'm trying to update a dynamic texture on each render loop using a color buffer generated from a library. I'm seeing an issue where the resulting texture doesn't match the expected bitmap. The texture appears to be wider than expect or the format is larger than expected.

var surfaceWidth = 200; var surfaceHeight = 200; 
var pixelBytes = surfaceWidth * surfaceHeight * 4;

//Set up the color buffer and byte array to stream to the texture
_colorBuffer = new int[surfaceWidth * surfaceHeight]; 
_textureStreamBytes = new byte[pixelBytes]; //16000 length

//Create the texture to update
_scanTexture = new Texture2D(Device, new Texture2DDescription()
        {
            Format = Format.B8G8R8A8_UNorm,
            ArraySize = 1,
            MipLevels = 1,
            Width = SurfaceWidth,
            Height = SurfaceHeight,
            SampleDescription = new SampleDescription(1, 0),
            Usage = ResourceUsage.Dynamic,
            BindFlags = BindFlags.ShaderResource,
            CpuAccessFlags = CpuAccessFlags.Write,
            OptionFlags = ResourceOptionFlags.None,
        });

_scanResourceView= new ShaderResourceView(Device, _scanTexture);
context.PixelShader.SetShaderResource(0, _scanResourceView);

And on render I populate the color buffer and write to the texture.

protected void Render()
{
    Device.ImmediateContext.ClearRenderTargetView(
        RenderTargetView, new SharpDX.Mathematics.Interop.RawColor4(0.8f,0.8f,0,1));
    Library.GenerateColorBuffer(ref _colorBuffer);
    System.Buffer.BlockCopy(_colorBuffer, 0, depthPixels, 0, depthPixels.Length);

    _parent.DrawBitmap(ref _colorBuffer);

    DataBox databox = context.MapSubresource(_scanTexture, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out DataStream stream);

    if (!databox.IsEmpty)
        stream.Write(_textureStreamBytes, 0, _textureStreamBytes.Length);
    context.UnmapSubresource(_scanTexture, 0);
    context.Draw(4, 0);
}

Sampler creation and setting before the above happens:

var sampler = new SamplerState(_device, new SamplerStateDescription()
        {
            Filter = SharpDX.Direct3D11.Filter.MinMagMipLinear,
            AddressU = TextureAddressMode.Wrap,
            AddressV = TextureAddressMode.Wrap,
            AddressW = TextureAddressMode.Wrap,
            BorderColor = SharpDX.Color.Blue,
            ComparisonFunction = Comparison.Never,
            MaximumAnisotropy = 1,
            MipLodBias = 0,
            MinimumLod = 0,
            MaximumLod = 0,
        });
context = _device.ImmediateContext;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
context.VertexShader.Set(vertexShader);
context.Rasterizer.SetViewport(new Viewport(0, 0, SurfaceWidth, SurfaceHeight, 0.0f, 1.0f));
context.PixelShader.Set(pixelShader);
context.PixelShader.SetSampler(0, sampler);
context.OutputMerger.SetTargets(depthView, _renderTargetView);

And shader (using a full screen triangle with no vertices):

SamplerState pictureSampler;
Texture2D picture;

struct PS_IN
{
    float4 pos : SV_POSITION;
    float2 tex : TEXCOORD;
};
PS_IN VS(uint vI : SV_VERTEXID)
{
    float2 texcoord = float2(vI & 1,vI >> 1); //you can use these for texture coordinates later
    PS_IN output = (PS_IN)0;
    output.pos = float4((texcoord.x - 0.5f) * 2, -(texcoord.y - 0.5f) * 2, 0, 1);
    output.tex = texcoord;
    return output;
}

float4 PS(PS_IN input) : SV_Target
{
    return picture.Sample(pictureSampler, input.tex);
}

What I'm seeing is:

_colorBuffer length 40000 (200 width *200 height)

_textureStreamBytes length 160000 (200 * 200 * 4bytes)

Stream from databox Length = 179200 difference of 19200 bytes / 4800 pixels. This translates to 24 rows of 200 pixel width. In other words the texture is 24 pixels wider than expected. But debugging shows width/height as 200.

Image showing the issue. Left is rendered view, right is bitmap

Does anyone know what I'm doing wrong here? Or things that should/could be done differently?

Thank you.

P.S. I've got this working correctly in OpenGL by using a similar process but need to get it working for directx:

gl.TexSubImage2D(OpenGL.GL_TEXTURE_2D, 0, 0, 0, (int)width, (int)height, OpenGL.GL_RGBA, OpenGL.GL_UNSIGNED_BYTE, colorBuffer);
1
Just looking at your tex coord, not sure but is your vI & 1 being evaluated as boolean. I would try the % modulus ( % 2) operator to at least remove that as a possibility. The problem does sit directly tex coord, I know the technique you are using and should work. I would honestly just hack out a if vI == 0 type scenario firstly to check your calc into texcoord is working like you expect. The rest seems solid.ErnieDingo
Thank you for the help, same result unfortunately. I think it has to do with the texutre/sharderresource/format due to the fact that the stream length is 12% larger (extra 24 pixels a row it appears). Another oddity is that while I specify the texture format as R8G8B8A8 it still draws it as B8G8R8A8. For the bitmap image example I actually flipped the red/blue bits. Otherwise the 3d render showed blue dots not red.Dan
Edit timed-out:Another oddity is that while I specify the texture format as B8G8R8A8 the bitmap generated for the example is using ARGB: _colorBuffer[i] = (int)((255 << 24 | red << 16 | green << 8 | blue) & 0xFFFFFFFFL); I would have thought blue << 24 | green << 16 | red << 8 | 255(alpha) << 0.Dan
I think I've found the root problem. Using a texture of 200 * 200 means that it is not a multiple of 256? 128? When I change the size of the view port to be a multiple of 256 the size of the stream and color buffer match.Dan
Good work! At least you got to the bottom of itErnieDingo

1 Answers

0
votes

From experimenting it appears that multiples of 32 are needed for both width and height. For example 100 * 128 even though a multiple of 32 will cause an issue. Instead I'm using:

var newHeight = (int)(initialHeight / 32) * 32;
var newWidth = (int)(initialWidth / 32) * 32;

I'm not sure if the root issue is my own mistake or a sharpDX issue or a DirectX issue. The other way I see to solve this issue is to add padding to the pixel array to account for the difference in length at the end of each row.