It is currently Tue Jun 18, 2013 5:45 pm



Reply to topic  [ 1 post ] 
 NV_STEREO_IMAGE_SIGNATURE and DX10/11 
Author Message
One Eyed Hopeful

Joined: Thu Sep 01, 2011 2:50 pm
Posts: 1
Hi there,
as some of you may be aware there is a low-level hack in which you render the left and right eye images manually, then you write a special value in the last row. Upon rendering this new scene, the nVidia driver picks the value up and activates the shutter glasses. I've been able to test it under DX9 (thanks to code found on this forum) so I know that it definitely can work but due to some methods not being available anymore in DX10/11 I've been unable to make it work.

The algorithm goes like this:
Render left eye image
Render right eye image
Create a texture able to contain them both PLUS an extra row (so the texture size would be 2 * width, height + 1)
Write this NV_STEREO_IMAGE_SIGNATURE value
Render this texture on the screen

My test code skips the first two steps, as I already have a stereo texture. It was a former .JPS file, specifically one of those included in the sample pictures coming with the nvidia 3D kit. Step number 5 uses a full screen quad and a shader to render the stereoized texture onto it through an ortho-projection matrix. The sample code I've seen for DX9 doesn't need this and simply calls the StretchRect(...) method to copy the texture back onto the backbuffer. So maybe it is for this reason that is not working? Is there a similar method to accomplish this in DX10? I thought that rendering onto the backbuffer would theoretically be the same than copying (or StretchRecting) a texture onto it, but maybe it is not?

Here follows my code (slimdx):
Stereoization procedure
Code:

static Texture2D Make3D(Texture2D stereoTexture)
{
    // stereoTexture contains a stereo image with the left eye image on the left half
    // and the right eye image on the right half
    // this staging texture will have an extra row to contain the stereo signature
    Texture2DDescription stagingDesc = new Texture2DDescription()
    {
        ArraySize = 1,
        Width = 3840,
        Height = 1081,
        BindFlags = BindFlags.None,
        CpuAccessFlags = CpuAccessFlags.Write,
        Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
        OptionFlags = ResourceOptionFlags.None,
        Usage = ResourceUsage.Staging,
        MipLevels = 1,
        SampleDescription = new SampleDescription(1, 0)
    };
    Texture2D staging = new Texture2D(device, stagingDesc);

    // Identify the source texture region to copy (all of it)
    ResourceRegion stereoSrcBox = new ResourceRegion { Front = 0, Back = 1, Top = 0, Bottom = 1080, Left = 0, Right = 3840 };
    // Copy it to the staging texture
    device.CopySubresourceRegion(stereoTexture, 0, stereoSrcBox, staging, 0, 0, 0, 0);

    // Open the staging texture for reading
    DataRectangle box = staging.Map(0, MapMode.Write, SlimDX.Direct3D10.MapFlags.None);
    // Go to the last row
    box.Data.Seek(stereoTexture.Description.Width * stereoTexture.Description.Height * 4, System.IO.SeekOrigin.Begin);
    // Write the NVSTEREO header
    box.Data.Write(data, 0, data.Length);
    staging.Unmap(0);
           
    // Create the final stereoized texture
    Texture2DDescription finalDesc = new Texture2DDescription()
    {
        ArraySize = 1,
        Width = 3840,
        Height = 1081,
        BindFlags = BindFlags.ShaderResource,
        CpuAccessFlags = CpuAccessFlags.Write,
        Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
        OptionFlags = ResourceOptionFlags.None,
        Usage = ResourceUsage.Dynamic,
        MipLevels = 1,
        SampleDescription = new SampleDescription(1, 0)
    };

    // Copy the staging texture on a new texture to be used as a shader resource
    Texture2D final = new Texture2D(device, finalDesc);
    device.CopyResource(staging, final);
    staging.Dispose();
    return final;
}

NV_STEREO_IMAGE_SIGNATURE data
Code:

        // The NVSTEREO header.
        static byte[] data = new byte[] {0x4e, 0x56, 0x33, 0x44,   //NVSTEREO_IMAGE_SIGNATURE         = 0x4433564e;
            0x00, 0x0F, 0x00, 0x00,   //Screen width * 2 = 1920*2 = 3840 = 0x00000F00;
            0x38, 0x04, 0x00, 0x00,   //Screen height = 1080             = 0x00000438;
            0x20, 0x00, 0x00, 0x00,   //dwBPP = 32                       = 0x00000020;
            0x02, 0x00, 0x00, 0x00};  //dwFlags = SIH_SCALE_TO_FIT       = 0x00000002

Main
Code:

private static Device device;

[STAThread]
static void Main()
{
    // Device creation
    var form = new RenderForm("Stereo test") {ClientSize = new Size(1920, 1080)};
    var desc = new SwapChainDescription()
                   {
                       BufferCount = 1,
                       ModeDescription = new ModeDescription(1920, 1080, new Rational(120, 1), Format.R8G8B8A8_UNorm),
                       IsWindowed = true,
                       OutputHandle = form.Handle,
                       SampleDescription = new SampleDescription(1, 0),
                       SwapEffect = SwapEffect.Discard,
                       Usage = Usage.RenderTargetOutput
                   };

    SwapChain swapChain;
    Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
    //Stops Alt+enter from causing fullscreen skrewiness.
    Factory factory = swapChain.GetParent<Factory>();
    factory.SetWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll);

    Texture2D backBuffer = Resource.FromSwapChain<Texture2D>(swapChain, 0);
    RenderTargetView renderView = new RenderTargetView(device, backBuffer);

    ImageLoadInformation info = new ImageLoadInformation()
                                    {
                                        BindFlags = BindFlags.None,
                                        CpuAccessFlags = CpuAccessFlags.Read,
                                        FilterFlags = FilterFlags.None,
                                        Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
                                        MipFilterFlags = FilterFlags.None,
                                        OptionFlags = ResourceOptionFlags.None,
                                        Usage = ResourceUsage.Staging,
                                        MipLevels = 1
                                    };

    // Make texture 3D
    Texture2D sourceTexture = Texture2D.FromFile(device, "medusa.jpg", info);
    Texture2D stereoizedTexture = Make3D(sourceTexture);
    ShaderResourceView srv = new ShaderResourceView(device, stereoizedTexture);

    // Create a quad that fills the whole screen
    ushort[] idx;
    TexturedVertex[] quad = CreateTexturedQuad(Vector3.Zero, 1920, 1080, out idx);

    // fill vertex and index buffers
    DataStream stream = new DataStream(4*24, true, true);
    stream.WriteRange(quad);
    stream.Position = 0;

    Buffer vertices = new SlimDX.Direct3D10.Buffer(device, stream, new BufferDescription()
                                                                       {
                                                                           BindFlags = BindFlags.VertexBuffer,
                                                                           CpuAccessFlags = CpuAccessFlags.None,
                                                                           OptionFlags = ResourceOptionFlags.None,
                                                                           SizeInBytes = 4*24,
                                                                           Usage = ResourceUsage.Default
                                                                       });
    stream.Close();

    stream = new DataStream(6*sizeof (ushort), true, true);
    stream.WriteRange(idx);
    stream.Position = 0;
    Buffer indices = new SlimDX.Direct3D10.Buffer(device, stream, new BufferDescription()
                                                                      {
                                                                          BindFlags = BindFlags.IndexBuffer,
                                                                          CpuAccessFlags = CpuAccessFlags.None,
                                                                          OptionFlags = ResourceOptionFlags.None,
                                                                          SizeInBytes = 6*sizeof (ushort),
                                                                          Usage = ResourceUsage.Default
                                                                      });

    // Create world view (ortho) projection matrices
    QuaternionCam qCam = new QuaternionCam();

    // Load effect from file. It is a basic effect that renders a full screen quad through
    // an ortho projectio=n matrix
    Effect effect = Effect.FromFile(device, "Texture.fx", "fx_4_0", ShaderFlags.Debug, EffectFlags.None);
    EffectTechnique technique = effect.GetTechniqueByIndex(0);
    EffectPass pass = technique.GetPassByIndex(0);
    InputLayout layout = new InputLayout(device, pass.Description.Signature, new[]
                                                                                 {
                                                                                     new InputElement("POSITION", 0,
                                                                                                      Format.
                                                                                                          R32G32B32A32_Float,
                                                                                                      0, 0),
                                                                                     new InputElement("TEXCOORD", 0,
                                                                                                      Format.
                                                                                                          R32G32_Float,
                                                                                                      16, 0)
                                                                                 });
    effect.GetVariableByName("mWorld").AsMatrix().SetMatrix(
        Matrix.Translation(Layout.OrthographicTransform(Vector2.Zero, 90, new Size(1920, 1080))));
    effect.GetVariableByName("mView").AsMatrix().SetMatrix(qCam.View);
    effect.GetVariableByName("mProjection").AsMatrix().SetMatrix(qCam.OrthoProjection);
    effect.GetVariableByName("tDiffuse").AsResource().SetResource(srv);

    // Set RT and Viewports
    device.OutputMerger.SetTargets(renderView);
    device.Rasterizer.SetViewports(new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height, 0.0f, 1.0f));

    // Create solid rasterizer state
    RasterizerStateDescription rDesc = new RasterizerStateDescription()
                                           {
                                               CullMode = CullMode.None,
                                               IsDepthClipEnabled = true,
                                               FillMode = FillMode.Solid,
                                               IsAntialiasedLineEnabled = true,
                                               IsFrontCounterclockwise = true,
                                               IsMultisampleEnabled = true
                                           };
    RasterizerState rState = RasterizerState.FromDescription(device, rDesc);
    device.Rasterizer.State = rState;

    // Main Loop
    MessagePump.Run(form, () =>
        {
            device.ClearRenderTargetView(renderView, Color.Cyan);

            device.InputAssembler.SetInputLayout(layout);
            device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology.TriangleList);
            device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, 24, 0));
            device.InputAssembler.SetIndexBuffer(indices, Format.R16_UInt, 0);

            for (int i = 0; i < technique.Description.PassCount; ++i)
            {
                // Render the full screen quad
                pass.Apply();
                device.DrawIndexed(6, 0, 0);
            }

            swapChain.Present(0, PresentFlags.None);
        });

    // Dispose resources
    vertices.Dispose();
    layout.Dispose();
    effect.Dispose();
    renderView.Dispose();
    backBuffer.Dispose();
    device.Dispose();
    swapChain.Dispose();

    rState.Dispose();
    stereoizedTexture.Dispose();
    sourceTexture.Dispose();
    indices.Dispose();
    srv.Dispose();
}


Thanks in advance!


Sun Sep 11, 2011 4:59 am
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 1 post ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by STSoftware.