locked
Using Pixel Shader 3.0

    Question

  • For another project I need to use pixel shader 3.0. When I attempted to get the effect to work in pixel shader 3.0 I noticed that pixel shader 3.0 was not working anywhere. So I even tried using the code from How to: Create Custom Texture Effects. The HLSL code is written to compile it for pixel shader 2.0. When I changed it to pixel shader 3.0 it failed. It gave an InvalidOperationException on the graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,                0,                0,                cubeVertices.Length,                0,                12            );. When I switch back to pixel shader 2.0 the program works just fine. I added code to test which version of pixel shader I have, and I do have pixel shader 3.0 (my video card is 7900gt so it should have ps3.0). Any idea what is not working? Below is the full source. Thanks for the help!

    Shader:
    uniform extern float4x4 WorldViewProj : WORLDVIEWPROJECTION;
    uniform extern texture UserTexture;

    struct VS_OUTPUT
    {
        float4 position  : POSITION;
        float4 textureCoordinate : TEXCOORD0;
    };

    sampler textureSampler = sampler_state
    {
        Texture = <UserTexture>;
        mipfilter = LINEAR;
    };
     
    VS_OUTPUT Transform(
        float4 Position  : POSITION,
        float4 TextureCoordinate : TEXCOORD0 )
    {
        VS_OUTPUT Out = (VS_OUTPUT)0;

        Out.position = mul(Position, WorldViewProj);
        Out.textureCoordinate = TextureCoordinate;

        return Out;
    }

    float4 ApplyTexture(VS_OUTPUT vsout) : COLOR
    {
        return tex2D(textureSampler, vsout.textureCoordinate).rgba;
    }

    technique TransformAndTexture
    {
        pass P0
        {
            vertexShader = compile vs_2_0 Transform();
            pixelShader  = compile ps_3_0 ApplyTexture();
        }
    }

    Game File
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.Content;


    public class Game1 : Microsoft.Xna.Framework.Game
    {
        Matrix worldViewProjection;
        Effect effect;
        VertexDeclaration cubeVertexDeclaration;
        VertexPositionTexture[] cubeVertices;
        VertexBuffer vertexBuffer;
        IndexBuffer indexBuffer;
        short[] cubeIndices;

        GraphicsDeviceManager graphics;
        ContentManager content;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            InitializeTransform();

            if (loadAllContent)
            {
                InitializeEffect();
                InitializeCube();

                // check all available adapters on the system
                foreach (GraphicsAdapter adapter in GraphicsAdapter.Adapters)
                {
                    // get the capabilities of the hardware device
                    GraphicsDeviceCapabilities caps = adapter.GetCapabilities(DeviceType.Hardware);
                    if (caps.MaxPixelShaderProfile < ShaderProfile.PS_2_0)
                    {
                        // this adapter does not support Shader Model 2.0
                        System.Diagnostics.Debug.WriteLine("This adapter does not support Shader Model 2.0.");
                    }
                    Console.WriteLine(caps.MaxPixelShaderProfile);
                }

            }
        }

        private void InitializeTransform()
        {
            float tilt = (float)Math.PI / 8.0f;
            // Use the world matrix to tilt the cube along x and y axis
            Matrix world = Matrix.CreateRotationX(tilt) *
                Matrix.CreateRotationY(tilt);

            Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 5), Vector3.Zero,
                Vector3.Up);

            Matrix projection = Matrix.CreatePerspectiveFieldOfView(
                (float)Math.PI / 4.0f,  // 2 PI Radians is 360 degrees, so this is 45 degrees
                (float)graphics.GraphicsDevice.Viewport.Width /
                (float)graphics.GraphicsDevice.Viewport.Height,
                1.0f, 100.0f);

            worldViewProjection = world * view * projection;

        }

        private void InitializeEffect()
        {
            effect = content.Load<Effect>("ReallySimpleTexture");

            Texture2D texture = content.Load<Texture2D>("xna");


            effect.Parameters["WorldViewProj"].SetValue(worldViewProjection);
            effect.Parameters["UserTexture"].SetValue(texture);


            effect.CurrentTechnique = effect.Techniques["TransformAndTexture"];


        }

        public VertexPositionTexture[] InitializeCube()
        {
            //Create a vertex declaration for the VertexPositionTexture type.
            cubeVertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice, VertexPositionTexture.VertexElements);

            //Initialize the points to be used to draw each side of the cube.
            Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
            Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
            Vector3 topRightFront = new Vector3(1.0f, 1.0f, 1.0f);
            Vector3 bottomRightFront = new Vector3(1.0f, -1.0f, 1.0f);
            Vector3 topLeftBack = new Vector3(-1.0f, 1.0f, -1.0f);
            Vector3 topRightBack = new Vector3(1.0f, 1.0f, -1.0f);
            Vector3 bottomLeftBack = new Vector3(-1.0f, -1.0f, -1.0f);
            Vector3 bottomRightBack = new Vector3(1.0f, -1.0f, -1.0f);

            // Initialize the texture coordinates
            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
            Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

            //Create an array to hold the list of vertices.  This array will be used to assign data to the vertex buffer.
            cubeVertices = new VertexPositionTexture[36];

            // Vertices for the front of the cube
            cubeVertices[0] =
                new VertexPositionTexture(
                topLeftFront, textureTopLeft); // 0
            cubeVertices[1] =
                new VertexPositionTexture(
                bottomLeftFront, textureBottomLeft); // 1
            cubeVertices[2] =
                new VertexPositionTexture(
                topRightFront, textureTopRight); // 2
            cubeVertices[3] =
                new VertexPositionTexture(
                bottomRightFront, textureBottomRight); // 3

            // Vertices for the back of the cube
            cubeVertices[4] =
                new VertexPositionTexture(
                topLeftBack, textureTopRight); // 4
            cubeVertices[5] =
                new VertexPositionTexture(
                topRightBack, textureTopLeft); // 5
            cubeVerticesDevil =
                new VertexPositionTexture(
                bottomLeftBack, textureBottomRight); //6
            cubeVertices[7] =
                new VertexPositionTexture(
                bottomRightBack, textureBottomLeft); // 7

            // Vertices for the top of the cube
            cubeVerticesMusic =
                new VertexPositionTexture(
                topLeftFront, textureBottomLeft); // 8
            cubeVertices[9] =
                new VertexPositionTexture(
                topRightBack, textureTopRight); // 9
            cubeVertices[10] =
                new VertexPositionTexture(
                topLeftBack, textureTopLeft); // 10
            cubeVertices[11] =
                new VertexPositionTexture(
                topRightFront, textureBottomRight); // 11

            // Vertices for the bottom of the cube
            cubeVertices[12] =
                new VertexPositionTexture(
                bottomLeftFront, textureTopLeft); // 12
            cubeVertices[13] =
                new VertexPositionTexture(
                bottomLeftBack, textureBottomLeft); // 13
            cubeVertices[14] =
                new VertexPositionTexture(
                bottomRightBack, textureBottomRight); // 14
            cubeVertices[15] =
                new VertexPositionTexture(
                bottomRightFront, textureTopRight); // 15

            // Vertices for the left side of the cube
            cubeVertices[16] =
                new VertexPositionTexture(
                topLeftFront, textureTopRight); // 16
            cubeVertices[17] =
                new VertexPositionTexture(
                bottomLeftFront, textureBottomRight); // 17
            cubeVertices[18] =
                new VertexPositionTexture(
                topRightFront, textureTopLeft); // 18
            cubeVertices[19] =
                new VertexPositionTexture(
                bottomRightFront, textureBottomLeft); // 19

            // Create a vertex buffer to hold the vertex data
            vertexBuffer = new VertexBuffer(graphics.GraphicsDevice,
                VertexPositionTexture.SizeInBytes * cubeVertices.Length,
                ResourceUsage.None,
                ResourceManagementMode.Automatic
                );

            // Add the data to the vertex buffer
            vertexBuffer.SetData<VertexPositionTexture>(cubeVertices);

            // Create indices to index into the cubeVertices array
            cubeIndices = new short[] {  0,  1,  2,  // front face
                                         1,  3,  2,
                                         4,  5,  6,  // back face
                                         6,  5,  7,
                                         8,  9, 10,  // top face
                                         8, 11,  9,
                                        12, 13, 14,  // bottom face
                                        12, 14, 15,
                                        16, 13, 17,  // left face
                                        10, 13, 16,
                                        18, 19, 14,  // right face
                                         9, 18, 14 };

            // Create an index buffer to hold the index data
            indexBuffer = new IndexBuffer(graphics.GraphicsDevice,
                sizeof(short) * cubeIndices.Length,
                ResourceUsage.None,
                ResourceManagementMode.Automatic,
                IndexElementSize.SixteenBits
                );

            // Add the data to the index buffer
            indexBuffer.SetData<short>(cubeIndices);

            return cubeVertices;
        }

        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent == true)
            {
                content.Unload();
            }
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the default game to exit on Xbox 360 and Windows
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            graphics.GraphicsDevice.RenderState.CullMode =
                CullMode.CullClockwiseFace;

            graphics.GraphicsDevice.VertexDeclaration = cubeVertexDeclaration;

            graphics.GraphicsDevice.Indices = indexBuffer;

            graphics.GraphicsDevice.Vertices[0].SetSource(
                vertexBuffer,
                0,
                VertexPositionTexture.SizeInBytes);

            //This code would go between a device BeginScene-EndScene block.
            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();

                graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                    0,
                    0,
                    cubeVertices.Length,
                    0,
                    12
                );

                pass.End();
            }
            effect.End();



            base.Draw(gameTime);
        }
    }

    Tuesday, February 13, 2007 9:35 AM

Answers

  • Remember to also check the DirectX debug output. It will often tell you if you are doing something wrong. See various threads in this forum for more information about viewing the DirectX debug output or this article on my website.

    Cheers,
    Leaf.
    Tuesday, February 13, 2007 1:58 PM
  • Just a question but, why are you using vertex shader 2.0 with a 3.0 pixel shader? shouldn't they both be 3.0 to support the dynamic branching?
    Tuesday, February 13, 2007 7:58 PM

All replies

  • Hi,

    I'm a little confused by your code because it looks like it is checking for PS 2.0 support, not 3.0:

                    // get the capabilities of the hardware device
                    GraphicsDeviceCapabilities caps = adapter.GetCapabilities(DeviceType.Hardware);
                    if (caps.MaxPixelShaderProfile < ShaderProfile.PS_2_0)
                    {
                        // this adapter does not support Shader Model 2.0
                        System.Diagnostics.Debug.WriteLine("This adapter does not support Shader Model 2.0.");
                    }
          

    If you change the PS_2_0 to PS_3_0, what happens?

    It sure sounds like XNA doesn't think you have a PS 3.0 card, given that the shader will execute when it's marked as 2.0 but fails when it's marked as 3.0.  Do you have reasonably recent nVidia drivers installed?

    -Mike

    Tuesday, February 13, 2007 10:27 AM
  • I agree with manders... go to the web site for your GPU manufacturer and get the latest drivers if you don't have them. Also make sure you have any relevant updates from Windows Update. Beyond this, you might want to see if there is any additional information in the fields of the exception, such as the inner exception or message field, etc.
    Tuesday, February 13, 2007 11:15 AM
  • Remember to also check the DirectX debug output. It will often tell you if you are doing something wrong. See various threads in this forum for more information about viewing the DirectX debug output or this article on my website.

    Cheers,
    Leaf.
    Tuesday, February 13, 2007 1:58 PM
  • Just a question but, why are you using vertex shader 2.0 with a 3.0 pixel shader? shouldn't they both be 3.0 to support the dynamic branching?
    Tuesday, February 13, 2007 7:58 PM
  • Thanks for the help guys. I checked and my hardware does support pixel shader 3.0. Once I looked at the debug output the error was rather clear. I had to use vertex shader 3.0 to make it work with pixel shader 3.0. Thanks again.
    Wednesday, February 14, 2007 3:41 AM
  • Leaf., I've tried to subscribe to your blog's RSS feed but IE7 keeps telling me: "This feed contains code errors."

     

    Wednesday, February 14, 2007 5:50 PM
  • Ultrahead,

    That site uses tiddlywiki, a very nice wiki in a single html file, it's not really a blog and doesn't work so well as an RSS feed. I've made some changes that enable the RSS feed anyway, you will get notice of new posts but you might also get the occasional odd looking "upload log" post.

    Looking at the site, it's not really making use of the wiki nature of tiddlywiki so I should probably move to something like blogspot. I just have a soft spot for tiddlywiki, I use it to keep notes on my pc.

    Cheers,
    Leaf.

    Wednesday, February 14, 2007 8:28 PM