Jump to content
  • Advertisement
Sign in to follow this  
Dave Eberly

OpenGL Problem with cgc version 2.2.0006

This topic is 3342 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 am using cgc (version 2.2.0006) to compile a pixel shader using the ps_3_0 profile (the only other parameters are the entry point and the FX input file). The compiler produces the output without complaint. When I pass the program string to D3DXAssemblerShader, the call fails with an HRESULT of D3DXERR_INVALIDDATA. I also used cgc to compile the shader using the OpenGL arbfp1 profile. The shader works just fine. I am using DX9 March 2009. The shader has a few nested if-then-else statements. I am wondering whether other folks have had similar problems with cgc and this type of shader. The skeleton of the code is
void MyPixelShader (in float2 tc : TEXCOORD0, out float4 result : COLOR)
{
    if (0.0f < tc.x)
    {
        if (tc.x < 1.0f)
        {
            if (0.0f < tc.y)
            {
                if (tc.y < 1.0f)
                {
                    result = Interior(tc);
                }
                else
                {
                    result = EdgeInteriorY1(tc);
                }
            }
            else
            {
                result = EdgeInteriorY0(tc);
            }
        }
        else
        {
            if (0.0f < tc.y)
            {
                if (tc.y < 1.0f)
                {
                    result = EdgeInteriorX1(tc);
                }
                else
                {
                    result = CornerX1Y1(tc);
                }
            }
            else
            {
                 result = CornerX1Y0(tc);
            }
        }
    }
    else
    {
        if (0.0f < tc.y)
        {
            if (tc.y < 1.0f)
            {
                result = EdgeInteriorX0(tc);
            }
            else
            {
                 result = CornerX0Y1(tc);
            }
        }
        else
        {
            result = CornerX0Y0(tc);
        }
    }
}


Share this post


Link to post
Share on other sites
Advertisement
Are you sure cgc outputs shader assembly? I've never used it, but I would think would just output a stream of DWORD tokens that could you could feed to IDirect3DDevice9::CreatePixelShader.

Share this post


Link to post
Share on other sites
For years I have been using successfully the following approach:

IDirect3DDevice9* device = ***;
IDirect3DPixelShader9* shader = ***;

const char* programText = ***;
int programLength = (int)strlen(programText);
LPD3DXBUFFER compiledShader = 0;
LPD3DXBUFFER errors = 0;
HRESULT hr = D3DXAssembleShader(programText, programLength, 0, 0, 0,
&compiledShader, &errors);
assertion(hr == D3D_OK && compiledShader,
"Failed to assemble pixel shader: %s\n", DXGetErrorString9(hr));

hr = device->CreatePixelShader(
(DWORD*)(compiledShader->GetBufferPointer()), &shader);
assertion(hr == D3D_OK, "Failed to create pixel shader\n");

if (compiledShader)
{
compiledShader->Release();
}
if (errors)
{
errors->Release();
}


The first few lines of the cgc output is

ps_3_0
dcl_2d s0
dcl_2d s1
def c5, 0.00000000, 1.00000000, 0.50000000, 2.00000000
dcl t0.xy
mov r0.x, c1
mad r1.x, c5.z, r0, t0
mov r0.y, c1
:


"programText" in my code segment is a single string that concatenates all these instructions (with a newline as separator between instructions).

Share this post


Link to post
Share on other sites
Have you tried to get more information about what is wrong? The hresult D3DXERR_INVALIDDATA alone is not very usefull. Maybe look into the "errors" result returned from D3DXAssembleShader or on the debug output when running Direct3D in debug mode.

With cg it can happen that you produce code that does not respect all the limitations you have in Direct3D itself. So it might pass the cg compiler and get translated into the target profile (correctly) but it does not fit in the limits put on the target profile by Direct3D. Common problems are: Too many instructions, too many registers used, texture sampling in a context or with an argument that does not perfectly fit into the profile.

PS: You should try with the latest Cg 2.2.0010 as well, released a few days ago.

Share this post


Link to post
Share on other sites
Thanks for the hint :) I had not considered looking at the "errors" variable. In fact, it has quite a few strings, each for a specific line of ASM code. They are all: "error X6077: texld/texldb/texldp/dsx/dsy instructions with r# as source cannot be used inside dynamic conditional 'if' blocks, dynamic conditional subroutine calls, or loop/rep with break*."

Sure enough, each of my nested calls (such as "Interior") have tex2D calls that lead to texld ASM with a r# as source. Now I will need to determine how to rewrite the code to avoid this. The actual shader is part of a GPU-based fluid solver (for Navier-Stokes), and the nesting is to handle the boundary conditions in the same manner I do on the CPU.

Share this post


Link to post
Share on other sites
For this type of error you can do one of the following.

- You remove the dynamic branching by compiling to a ps_2_x profile or by forcing cg to produce ps_3_0 code without dynamic branching. But depending on how your code is written this might produce very inefficient code, where you sample texture at all possible locations (when you really need just one sample at the right location).

- You can just calculate the coordinates you want to sample textures at inside the "if" statements, but do the actual sampling outside the "if" statement. A few examples (I hope I remember things right):


// this should be ok, because you sample directly at tc
if (tc.x < 0)
result = tex2D(..., tc);
else
result = 2 * tex2D(..., tc);

// this should give you the error "X6077", because the location you sample at gets calculated (so resides in r#)
if (tc.x < 0)
result = tex2D(..., 2 * tc);
else
result = tex2D(..., 2 * tc + 1);

// this should do the same as the error example above, but should run without error

float2 coord;
if (tc.x < 0)
coord = 2 * tc;
else
coord = 2 * tc + 1;
result = tex2D(..., coord);



- I think there is a third possible solution to the problem by sampling a texture at a predetermined mipmap level (or something like that).

Share this post


Link to post
Share on other sites
Quote:
Original post by Moeller
For this type of error you can do one of the following.

- You remove the dynamic branching by compiling to a ps_2_x profile or by forcing cg to produce ps_3_0 code without dynamic branching. But depending on how your code is written this might produce very inefficient code, where you sample texture at all possible locations (when you really need just one sample at the right location).

- You can just calculate the coordinates you want to sample textures at inside the "if" statements, but do the actual sampling outside the "if" statement. A few examples (I hope I remember things right):

*** Source Snippet Removed ***
- I think there is a third possible solution to the problem by sampling a texture at a predetermined mipmap level (or something like that).


Thanks for the ideas. I did try a ps_2_0 profile, but exceeded the maximum number of instructions. I will try the tcoord calculations as you mentioned. For my application, it is important to obtain the correct boundary behavior. I can just do the sampling outside the dynamic branching. Sometimes there will be more samples than I need, but the extra cost is irrelevant in my app.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!