0

我正在寻找编写一个 perona malik 各向异性过滤器,看起来出于性能原因我需要使用 gpu。长话短说,我想知道如何在 xna 中使用 HLSL 来执行 GPGPU 任务。

我正在寻找一些代码片段来将一些数据移动到 GPU,逐帧处理它,然后返回它,以便我可以用它做其他事情。

根据我的阅读,我需要使用“乒乓球

编辑

这是我到目前为止所拥有的

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace HotplateTest
{
    public class XNAClass : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        RenderTarget2D Target;
        RenderTarget2D Output;
        Effect physicsEffect;

        Vector4[] positions;

        public XNAClass()
        {
            graphics = new GraphicsDeviceManager(this);
        }

        protected override void Initialize()
        {
            Target = new RenderTarget2D(graphics.GraphicsDevice, 10, 10, false, SurfaceFormat.Vector4, DepthFormat.None);
            Output = new RenderTarget2D(graphics.GraphicsDevice, 10, 10, false, SurfaceFormat.Vector4, DepthFormat.None);

            positions = new Vector4[100];
            for (int i = 0; i < positions.Length; i++)
            {
                positions[i] = new Vector4(i);
            }

            Target.SetData<Vector4>(positions);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            base.LoadContent();
            physicsEffect = Content.Load<Effect>("shader");
        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {

            GraphicsDevice.SetRenderTarget(Target); 
            GraphicsDevice.Clear(Color.Black);
            physicsEffect.Techniques[0].Passes[0].Apply();
            physicsEffect.Parameters["oldPositionTexture"].SetValue(Output); 
            physicsEffect.CurrentTechnique.Passes[0].Apply();

            GraphicsDevice.SetRenderTarget(null);
            Target.GetData<Vector4>(positions);


            base.Draw(gameTime);
        }
    }
}

HLSL

texture oldPositionTexture;

sampler oldPositionSampler = sampler_state
{
    Texture = < oldPositionTexture >;

    MipFilter = POINT;
    MinFilter = POINT;
    MagFilter = POINT;
    ADDRESSU = CLAMP;
    ADDRESSV = CLAMP;
};

struct VertexShaderInput
{
    float4 Position : POSITION;
    float2 Tex  : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION;
    float2 Tex  : TEXCOORD0;
};

// input texture dimensions
static const float w = 10;
static const float h = 10;

static const float2 pixel = float2(1.0 / w, 1.0 / h);
static const float2 halfPixel = float2(pixel.x / 2, pixel.y / 2);

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

    output.Tex = input.Tex; 

    return output;
}

float4 PS1(VertexShaderOutput input) : COLOR0
{
    float2 myV = input.Tex;
    float myPosAndMass = tex2D(oldPositionSampler, myV);

    return float4(myPosAndMass, myPosAndMass, myPosAndMass, myPosAndMass);
}

technique Technique1
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS1();
    }
}

我收到一条错误消息

Microsoft.Xna.Framework.Graphics.dll 中出现“System.ArgumentException”类型的未处理异常

附加信息:您在此方法中用于 T 的类型是此资源的无效大小。

有趣的是,当我在 C# 代码中使用 Single 而不是 Vector4 时,不会出现错误消息。当然,这意味着在位置变量中计算的结果现在是无用的,因为当它们真的是 vector4 时,它们被解释为单个。

4

1 回答 1

0

C#

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Emgu.Util;
using Emgu.CV;
using Emgu.CV.Structure;

namespace HLSLTest
{
    public delegate void Disp();

    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        Capture cap = new Capture("output.avi");
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        RenderTarget2D renOutput;

        Vector4[] gpuStore = new Vector4[1920 * 1080];

        Effect effect;
        QuadRender quad;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            quad = new QuadRender(GraphicsDevice);

            renOutput = new RenderTarget2D(GraphicsDevice, 1920, 1080, false, SurfaceFormat.Vector4, DepthFormat.Depth24);

            effect = Content.Load<Effect>("Shader");

            base.LoadContent();

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            Image<Bgr, Byte> video = cap.QueryFrame();
            using (Image<Bgra, float> vid2 = video.Convert<Bgra, float>())
            {

                Texture2D t = new Texture2D(GraphicsDevice, video.Width, video.Height, false, SurfaceFormat.Vector4);
                t.SetData<byte>(vid2.Bytes);

                GraphicsDevice.SetRenderTarget(renOutput);
                effect.Parameters["Input0"].SetValue(t);
                quad.RenderFullScreenQuad(effect);
                for (int i = 0; i < effect.Techniques.Count; i++)
                {
                    for (int j = 0; j < effect.Techniques[i].Passes.Count; j++)
                    {
                        effect.Techniques[i].Passes[j].Apply();
                    }
                }

                GraphicsDevice.SetRenderTarget(null);
                renOutput.GetData<Vector4>(gpuStore);
            }

            base.Draw(gameTime);
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace HLSLTest
{
    internal sealed class QuadRender
    {
        private VertexPositionTexture[] verts;
        private GraphicsDevice myDevice;
        private short[] ib = null;

        ///
        /// Loads the quad.
        ///
        ///
        public QuadRender(GraphicsDevice device)
        {
            myDevice = device;         
            verts = new VertexPositionTexture[]
            {
                new VertexPositionTexture
                (
                    new Vector3(0,0,0),
                    new Vector2(1,1)
                ),
                new VertexPositionTexture
                (
                    new Vector3(0,0,0),
                    new Vector2(0,1)
                ),
                new VertexPositionTexture
                (
                    new Vector3(0,0,0),
                    new Vector2(0,0)
                ),
                new VertexPositionTexture
                (
                    new Vector3(0,0,0),
                    new Vector2(1,0)
                )
            };

            ib = new short[] { 0, 1, 2, 2, 3, 0 };
        }             

        ///
        /// Draws the fullscreen quad.
        ///
        ///
        public void RenderFullScreenQuad(Effect effect)
        {
            effect.CurrentTechnique.Passes[0].Apply();
            RenderQuad(Vector2.One * -1, Vector2.One);
        }

        public void RenderQuad(Vector2 v1, Vector2 v2)
        {          

            verts[0].Position.X = v2.X;
            verts[0].Position.Y = v1.Y;

            verts[1].Position.X = v1.X;
            verts[1].Position.Y = v1.Y;

            verts[2].Position.X = v1.X;
            verts[2].Position.Y = v2.Y;

            verts[3].Position.X = v2.X;
            verts[3].Position.Y = v2.Y;

            myDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, verts, 0, 4, ib, 0, 2);
        }
    }
}

HLSL

texture2D Input0;
sampler2D Input0Sampler = sampler_state
{
    Texture = <Input0>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

texture2D Input1;
sampler2D Input1Sampler = sampler_state
{
    Texture = <Input1>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

texture2D Input2;
sampler2D Input2Sampler = sampler_state
{
    Texture = <Input2>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

texture2D Input3;
sampler2D Input3Sampler = sampler_state
{
    Texture = <Input3>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};


struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 TextureCoordinate : TEXCOORD0;
};

struct PixelShaderOutput
{
    // TODO: Optionally add/remove output indices to match GPUProcessor.numOutputs
    float4 Index0 : COLOR0;
};

// input texture dimensions
static const float w = 1920;
static const float h = 1080;

static const float2 pixel = float2(1.0 / w, 1.0 / h);
static const float2 halfPixel = float2(pixel.x / 2, pixel.y / 2);


VertexShaderOutput VertexShaderFunction(VertexShaderInput vsInput)
{
    //VertexShaderOutput output;

    //output.Position = vsInput.Position;
    //output.TextureCoordinate = vsInput.TextureCoordinate;

    VertexShaderOutput output;
    vsInput.Position.x =  vsInput.Position.x - 2*halfPixel.x;
    vsInput.Position.y =  vsInput.Position.y + 2*halfPixel.y;
    output.Position = vsInput.Position;
    output.TextureCoordinate = vsInput.TextureCoordinate ;
    return output;


    //return output;
}

PixelShaderOutput PixelShaderFunction(VertexShaderOutput psInput)
{
    PixelShaderOutput output;
    // TODO: Optionally add/remove samples to match GPUProcessor.numInputs
    float4 input0 = tex2D(Input0Sampler, psInput.TextureCoordinate);
    //float4 input1 = tex2D(Input0Sampler, psInput.TextureCoordinate);
    //float4 input2 = tex2D(Input0Sampler, psInput.TextureCoordinate);
    //float4 input3 = tex2D(Input0Sampler, psInput.TextureCoordinate);

    // your calculations go here

    // TODO: Optionally add/remove outputs to match GPUProcessor.numOutputs
    output.Index0 = input0;//float4(100,200,13,24);//input0;

    return output;
}

technique Verlet
{
    pass Go
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
于 2013-07-24T05:26:15.937 回答