Skip to main content
GameDev.net gamedev.net
Using GameDev.net for your class this semester?
Learn more →
🔒 Locked

[DX11] Compute shader "race condition" error when using optimization level 2 or 3

Started by n3Xus Jan 28, 2011 at 2:13 AM 17 replies 14.7k views
Original Post
n3Xus
n3Xus
Hello,

I'm playing around with compute shaders, so for my first more serious CS I decided to implement a simple blur shader.

Right now I finished the horizontal blur pass and it worked, until I switch on optimization levels 2 or 3 (D3D10_SHADER_OPTIMIZATION_LEVEL2, _3).
It works for D3D10_SHADER_SKIP_OPTIMIZATION and D3D10_SHADER_OPTIMIZATION_LEVEL1 flags.

Here is the error:
"race condition writing to shared memory detected, consider making this write conditional"



My blur looks "ok" for the horizontal pass, there aren't any artifacts that you get if you screw up your thread/group index calculations


I'm confused about this error, as if the blur algorith incorrectly indexes the shared variable only in the release version with optimizations enabled.

Here is a rough outline of how I do the blur:


groupshared float4 gsPixels[32*2*2]; // The error points to this line

[numthreads(32,2,1)]
void CSMAIN(...)
{
// Compute some indexes and texcoords based on the CSMAIN thread/group id input parameters
// Nothing is read/written from any resource at this point

....


// Now I read some colors from the fullscreen texture and I store
// them into the gsPixels variable.

// Now I wait for all threads to finish writing to the group shared variable
GroupMemoryBarrierWithGroupSync();

// And now I read the values from the gsPixels variable and do the
// actual blur and write the result to the UAV


}




Any suggestion what could be causing this error on the higher optimization levels??
MJP
MJP
I got the same warning recently on one of my compute shaders when I kicked it up to optimization level 3. I couldn't figure out...it seemed to happen whenever I had a shared memory write even if there was a conditional making sure only the first thread did the write. On level 1 it compiles fine and works fine, so I suspect there may be a compiler bug.
n3Xus
n3Xus


Seems so, I'll try submitting a bug report to MS.

I get that error even if I don't write to the groupshared variable at all
DieterVW
DieterVW
Can you post the real shader here so that we can help better.

Do you use and SV_Group* index when writing to group shared memory? That should normally be all the protection you need to convince the compiler that the writes are safe.
n3Xus
n3Xus
Hey,

Even if I don't write to the groupshared variable, just declare it, it gives me the error on optimization levels 2 and 3.

I compile the shader with these flags:

UINT shaderCompileFlags=
D3D10_SHADER_OPTIMIZATION_LEVEL1|
D3D10_SHADER_PACK_MATRIX_ROW_MAJOR|
D3D10_SHADER_PREFER_FLOW_CONTROL|
D3D10_SHADER_ENABLE_STRICTNESS;

Change D3D10_SHADER_OPTIMIZATION_LEVEL1 to 2/3 to get the error.

Here is the code:



// Packs float4 in [0,1] range into [0-255] uint
uint PackFloat4(float4 val)
{
return (uint(val.x*255.0f)<<24)|(uint(val.y*255.0f)<<16)|(uint(val.z*255.0f)<<8)|(uint(val.w*255.0f)<<0);
}

// Unpacks values and returns float4 in [0,1] range
float4 UnpackFloat4(uint value)
{

// Note: 1/255=0.003921568
return float4(
((value>>24)&0xFF)*0.003921568,
((value>>16)&0xFF)*0.003921568,
((value>>8)&0xFF)*0.003921568,
((value>>0)&0xFF)*0.003921568);

}

Texture2D texColor: register(t0);

RWTexture2D<uint> uav: register(u0);


// THE ERROR POINTS TO THIS LINE:
groupshared uint gsPixels[32*2*2];



[numthreads(32,2,1)]
void CSMAIN( uint3 threadID:SV_GroupThreadID,
uint3 groupID:SV_GroupID)
{


int tx=groupID.x*32+threadID.x;
int ty=groupID.y*2+threadID.y;

int tid=threadID.x+threadID.y*32;


// Line (in pixels)
int currentLineInPixels=threadID.y*64;


// Blur side
int blurSideTimes16=blurSideTimes16=((uint)tid*(1.0f/16.0f)-2*threadID.y);

blurSideTimes16=(blurSideTimes16*2-1)*16;


int2 texcoords=int2(tx,ty);
int2 texcoordsWithOffset=texcoords+int2(blurSideTimes16,0);


// Pixel at current texcoords
int index=16+threadID.x+threadID.y*64;


gsPixels[index]=PackFloat4(saturate(texColor[texcoords.xy]));

// Its offset pixel
gsPixels[index+blurSideTimes16]=PackFloat4(saturate(texColor[texcoordsWithOffset.xy]));

// Wait until all pixels are stored in shared memory
GroupMemoryBarrierWithGroupSync();

// Read pixels on the left/right from the current pixel
float4 sum=float4(0,0,0,0);
int temp=threadID.x+currentLineInPixels;

[unroll]for(float f=0;f<32;f+=1.0f)
{
// Perform intensity based on gradient here, reduces instruction count
sum+=UnpackFloat4(gsPixels[temp+f]) * (1-abs( (16 - f)*(1.0f/16.0f)) ); // 16==halfSamples, 0.0625=1/halfSamples
}

sum/=32;


uav[texcoords]=PackFloat4(sum);

}
coordz
coordz
What DX runtime and SDK are you using? I tried this shader as you described with June 2010 but get no error or warning.

OT why do you want to prefer flow control? especially as you seem to want to optimize


Hey,

Even if I don't write to the groupshared variable, just declare it, it gives me the error on optimization levels 2 and 3.

I compile the shader with these flags:

UINT shaderCompileFlags=
D3D10_SHADER_OPTIMIZATION_LEVEL1|
D3D10_SHADER_PACK_MATRIX_ROW_MAJOR|
D3D10_SHADER_PREFER_FLOW_CONTROL|
D3D10_SHADER_ENABLE_STRICTNESS;

Change D3D10_SHADER_OPTIMIZATION_LEVEL1 to 2/3 to get the error.

Here is the code:



// Packs float4 in [0,1] range into [0-255] uint
uint PackFloat4(float4 val)
{
return (uint(val.x*255.0f)<<24)|(uint(val.y*255.0f)<<16)|(uint(val.z*255.0f)<<8)|(uint(val.w*255.0f)<<0);
}

// Unpacks values and returns float4 in [0,1] range
float4 UnpackFloat4(uint value)
{

// Note: 1/255=0.003921568
return float4(
((value>>24)&0xFF)*0.003921568,
((value>>16)&0xFF)*0.003921568,
((value>>8)&0xFF)*0.003921568,
((value>>0)&0xFF)*0.003921568);

}

Texture2D texColor: register(t0);

RWTexture2D<uint> uav: register(u0);


// THE ERROR POINTS TO THIS LINE:
groupshared uint gsPixels[32*2*2];



[numthreads(32,2,1)]
void CSMAIN( uint3 threadID:SV_GroupThreadID,
uint3 groupID:SV_GroupID)
{


int tx=groupID.x*32+threadID.x;
int ty=groupID.y*2+threadID.y;

int tid=threadID.x+threadID.y*32;


// Line (in pixels)
int currentLineInPixels=threadID.y*64;


// Blur side
int blurSideTimes16=blurSideTimes16=((uint)tid*(1.0f/16.0f)-2*threadID.y);

blurSideTimes16=(blurSideTimes16*2-1)*16;


int2 texcoords=int2(tx,ty);
int2 texcoordsWithOffset=texcoords+int2(blurSideTimes16,0);


// Pixel at current texcoords
int index=16+threadID.x+threadID.y*64;


gsPixels[index]=PackFloat4(saturate(texColor[texcoords.xy]));

// Its offset pixel
gsPixels[index+blurSideTimes16]=PackFloat4(saturate(texColor[texcoordsWithOffset.xy]));

// Wait until all pixels are stored in shared memory
GroupMemoryBarrierWithGroupSync();

// Read pixels on the left/right from the current pixel
float4 sum=float4(0,0,0,0);
int temp=threadID.x+currentLineInPixels;

[unroll]for(float f=0;f<32;f+=1.0f)
{
// Perform intensity based on gradient here, reduces instruction count
sum+=UnpackFloat4(gsPixels[temp+f]) * (1-abs( (16 - f)*(1.0f/16.0f)) ); // 16==halfSamples, 0.0625=1/halfSamples
}

sum/=32;


uav[texcoords]=PackFloat4(sum);

}

n3Xus
n3Xus

What DX runtime and SDK are you using? I tried this shader as you described with June 2010 but get no error or warning.


I'm using the June2010 SDK and the latest runtime (I just redownloaded the runtime to be sure).




OT why do you want to prefer flow control? especially as you seem to want to optimize


This is the first time that I actually went in-depth in shader optimizations, thanks for the tip!

Does the assembly code generated by the directX shader compiler in any way differ if you use a radeon/gefore gpu?
Which gpu do you have coordz? I have a Radeon 6950.

coordz
coordz
The DX shader compiler will generate the same DX asm regardless of the hardware. It is this DX asm that is then consumed by the driver (AMD/NVIDIA) to compile for the particular hardware in your machine.

I'm using an Radeon 5870 and envious of your newer card

There's a very useful tool by AMD

http://developer.amd...es/default.aspx

which will allow you to compile DX shader *independently* of the GPU in your machine. It's actually meant for profiling but in your case I'd be interested to know what happens when you try compiling your shader in this tool and if you get the same errors.



Does the assembly code generated by the directX shader compiler in any way differ if you use a radeon/gefore gpu?
Which gpu do you have coordz? I have a Radeon 6950.


DieterVW
DieterVW
I believe that those tools by AMD/NVIDIA use hte MS compiler as the first step and then show the results of their asm compiler (per hardware) as the second step. That means he'll still get the same errors using their tools.
n3Xus
n3Xus
Huh, it compiles perfectly in the ShaderAnalyzer.

Could it be the ID3D11Device then (some state about it?)? coordz could you please post your code snippet for device creation (flags etc..)?




The DX shader compiler will generate the same DX asm regardless of the hardware. It is this DX asm that is then consumed by the driver (AMD/NVIDIA) to compile for the particular hardware in your machine.


Thanks for explaining that, makes sense.


I'm using an Radeon 5870 and envious of your newer card


I know the feeling laugh.gif It's a nice and quiet little thing (compare to the double fanned loud monster I had before).
MJP
MJP
Shader compilation is completely independent of a D3D device, so that shouldn't matter. You can try compiling your shader with fxc.exe using the same settings, to see if it works without running your app, although AFAIK there should be no difference between invoking fxc or callinf D3DCompile.
Matias Goldberg
Matias Goldberg
I never did a CS but I'm used to parallel programming, and I spot something dangerous (which is probably why DX is complaining, even if it is a false warning):

gsPixels[index]=PackFloat4(saturate(texColor[texcoords.xy]));

// Its offset pixel
gsPixels[index+blurSideTimes16]=PackFloat4(saturate(texColor[texcoordsWithOffset.xy]));

// Wait until all pixels are stored in shared memory
GroupMemoryBarrierWithGroupSync();



See the problem? You're writing to gsPixels[index+blurSideTimes16].

I don't know how many threads you're running, nor how you're running them. However, if in (i.e.) one of your threads index+blurSideTimes16 = 32 and in another thread index = 32; you'll get a race condition.

Even if you took care that none of the writes "+blurSideTimes16" overlaps with other threads, I'm pretty sure DX isn't realizing that, or it may even not be possible to accurately detect this situation for D3D11 runtimes.
Cheers

Dark Sylinc

DieterVW
DieterVW
I tried this on the June 2010 SDK as well and found that it compiles fine at all optimization levels. Either you change something in this shader from the original or else y our application is linking to the wrong version of the compiler DLL, probably a previous SDK release.
n3Xus
n3Xus
@Matias Goldberg: Thanks for pointing that out, the problem is that even if I don't write to that variable at all I still get that error.




@DieterVW: Yeah, I think I could be linking the wrong compiler lib - I tried compiling it with fxc and it works, but here is the problem:


I staticaly link d3dcompiler.lib, but I don't link any DLLs, I'm very unexperienced as far as proper deployment release versions go.
The dll whose name sounds usable is D3D11SDKLayers.dll, I tried linking it via the Linker tab but it failed while it was loading it:

error LNK1107: invalid or corrupt file: cannot read at 0x288


I'm not even sure if this is the proper way to link dlls. Are there any other DLLs that I should be linking?

EDIT: I now found D3DCompiler_43.dll and I'm loading it using LoadLibrary, but it still doesn't work. Are there any extra steps needed?
(note that my renderer is in a separate DLL from my aplication, I tried calling LoadLibrary in both of them but it doesn't work, is there
anything special needed in this case?)




DieterVW
DieterVW
If you type the word 'set' on a cmd prompt you'll get a list of environment variables. One of those variables should look like the following:
DXSDK_DIR='C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\

You can then use this inside visual studio when settings the libs/includes/executable directories for including DX. Make sure that this var is pointing to the dx install you're expecing it too.

The values in VS should looks something like:
$(DXSDK_DIR)\include
$(DXSDK_DIR)\lib\x86
$(DXSDK_DIR)\Utilities\bin\x86

Then just make sure you link to d3dcompiler.lib as you were. When debugging you should see the latest compiler dll get loaded which would be d3dcompiler_43.dll. The dll can be found in you system32 and wow64 system paths if the installation worked correctly.
n3Xus
n3Xus
It says in the Output window:
Application.exe': Loaded 'C:\Windows\SysWOW64\D3DCompiler_43.dll', Cannot find or open the PDB file
I noticed there is another D3DCompiler_43.dll in system32. Does this has anyhing to do with it?

So it gets loaded, but it still doesn't work. I think I'll just use a custom compile step on the .hlsl files and make it execute fxc.exe.
DieterVW
DieterVW
The wow64 version is compiled for 32bit applications while the system32 version is compiled for the native am64 architecture. Depending on how your application is compiled the OS will make sure you get the right version of the dll. In this case you're loading up the correct one. It's really odd that this isn't working for you. If you compile on the command line using fxc do you get the same error?
n3Xus
n3Xus
Thanks for explaining that DieterVW smile.gif


I compiled it successfully with fxc manually, but I'm not sure about the command line parameters, in the documentation
it says that /O1 is the default and that /O2 and /O3 are the same as /O1 and reserved for future use - is "future use"
optimization level 2/3 in DX11?

If /Ox are not for optimization levels, which command line parameters are?


I compiled it with this flags and it compiled successfully:



fxc /T cs_5_0 /E main /O3 /Fo outputShader.bin myInputShader.hlsl
Black-Panther
Black-Panther
Hi there!


I have now a very similar problem, which I couldn't solve till now. Did you find any solution to yours?
Team leader of stillalive|studios
our current project: Son of Nor (facebook, [twitter]sasGames[/twitter], website)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.