Original Post
(This is a long post) I am developing a program that makes heavely use of Vertex and especially the programmable fragment shader. AT the start of the project GLSL was choosed as the language for implementation, I have however run into some problem where it on a Nvidia Geforce 6800 card will render at ~15fps, while it using either Radeon 9800 pro or X800 Pro will take about 3 minutes per frame to render. I am quite bedazzled to why it that happend since I don't see any reason for it. I am hesitating to post the actuall shaders as I am unsure to weather or not I am allowed to publish them yet but this is how the system is implemented. Sending data is done through Immediate mode calls at the moment because of the layout of the data that needs to be sent recieved. [Reason I do this follows: I need to send six arrays of vec3 (float) that will remain constant for ~15 vertices only before they change value again (ammount of vertices in the stream is in order of 100k-1,000k), and everything is recalculated every frame, nothing can really be assumed to be constant, and using immediate mode calls to glMultitexCoord3fvARB sending it down through GL_TEXCOORD[0 through 5]_ARB saves me from manually copying them around in memory. Immediate calls acts like "statechanges" in OpenGL for the texcoord streams. SO what I send down (per vertex) is the following: 3float (vertex), 6x3float (texcoords). There is only 1 texture bound, is is a floatingpoint texture rendered with Render-To-Texture extension (internal format is RGBA 16 bit float ATI format, supported by both 6800 series geforce and 9800, x800 ati cards). The render target of the entire operation is a 8 bit texture using render-to-texture extension and a simple glBlendFunc(). [The render-to-texture, pbuffers and texture are working, this has been thourgly tested on both Geforce 6800 and Radeon 9800 card in a slightly different mechanism of sending data and other shaders, just wanted to inform of the situation to avoid any confusions/assumptions] A vec4 containing the view_port and a float containing 1.0/float(screen_resolution) are sent down as uniforms on shader creation. Per frame basis a lightvector is sent down using uniform also. That is how all data is sent to the shaders. The Vertex shader I can post as it dosn't contain any *sensetive* algorithm/method. The fresnel is turned on for Geforce 6800 and off for all ATI cards btw since in testing applications Radeon 9800 (atleast on my sytem) executing the "refract" function from GLSL dropped framrate in the order of magnitude 100 times. The fragmentshader used I don't want to paste incase it gets me in trouble but I can explain some properties it have. Using Nvidias shaderperf program it has been possible to see what amount of code it translates the fragment program into and here is the output on on "NVShaderPerf -a NV40 fragmenstsader.glsl" # 51 instructions, 7 R-regs, 1 H-regs -------------------- NV40 -------------------- Target: GeForce 6800 Ultra (NV40) :: Unified Compiler: v61.77 Cycles: 51.36 :: R Regs Used: 10 :: R Regs Max Index (0 based): 9 Pixel throughput (assuming 1 cycle texture lookup) 125.49 MP/s This is indeed a big shader but from what I been able to see it would be well within the resource limits (instruction count wise and register use wise) of that of a Radeon 9800 and X800. The shader only utilizes a very small set of ARB_fragment_program instructions: ADDR (Addition) MULR (Multiplication) MADR (Multiplication + Addition) MOVR (Move) (just a few) RCPR (1.0 / x) (only 3) RSQR (reciprocal square root) (only 1) DP3R (vectorwise dot) (only 1) SGER (greater than comparision) (only 2) SGTR (another greater than comparision) (only 1) TEX (normal 2D sampler with floatingpoint target) (only 1) Wich means the shader is basicly loads of additioning and multiplying. Is there anyone with the information I have given would know if anything I have mentioned above would make a ATo card (9800 or X800) go into sowftware mode for this ? It is mildly annoying as in the project NO Nvidia specific extension have been used, only ATI one (for the floatinpoint texture) and remaining ARB. The project runs like a charm on the Geforce 6800 card but not on 9800. Even ruling out Everything I posted as correctly programmed for ATI cards would be greatfull as I have now spent well over a week's work trying to figure out what went wrong. The latest ATI drivers (4.12) are being used btw Does the ATI cards have problems sending float data through texcoords? Are the ATI interpolators given to much work ? Is the ATI compiler failing to produce code for the fragmentshader that stays withing resource limits ? (I get NO errors through OpenGl or the log of any shader), it renders correctly on the ATi cards, but with 1 frame every 3-4 minutes instead of the geforce 15 frames/second. I really really would like to run this on ATI cards before I try and get it published (and after that open up all sources for public viewing ofcourse!) On a sidenote I wonder why ATI does not produce any public tools to aid developers with GLSL (shaders in generals even) on their cards like nvidia are doing (cg and nvshaderperf)... Edit: Noticed it was source and not code-tags on this forum. Edit2: The code was incorrect, a closingtag for a comment was missing. Thanks for reading this huge post, but I have gone blind from starrying on the problem for so long now. [Edited by - todderod on January 11, 2005 7:14:30 PM]
uniform sampler2D DepthTexture;
uniform vec3 lightVector;
varying float fresnel;
varying vec3 Point[3];
varying vec3 Line[3];
varying vec4 TriNorm;
void main()
{
gl_Position = ftransform();
Point[0] = gl_MultiTexCoord0.xyz;
Point[1] = gl_MultiTexCoord1.xyz;
Point[2] = gl_MultiTexCoord2.xyz;
Line[0] = normalize(gl_MultiTexCoord3.xyz-Point[0]);
Line[1] = normalize(gl_MultiTexCoord4.xyz-Point[1]);
Line[2] = normalize(gl_MultiTexCoord5.xyz-Point[2]);
TriNorm.xyz = normalize(-cross(Point[1]-Point[0],Point[2]-Point[0]));
TriNorm.w = length(cross(Point[1]-Point[0], Point[2]-Point[0]));
vec3 lightVec = normalize(lightVector);
/*float a = acos(dot(TriNorm.xyz,-lightVector));
float b = acos(dot(-TriNorm.xyz,refract(lightVector, TriNorm.xyz, 1.0/1.33)));
fresnel = ( sin(a-b)*sin(a-b) / (sin(a+b)*sin(a+b)) ) + tan(a-b)*tan(a-b)*tan(a+b)*tan(a+b); */
fresnel = 1.0; // (1.0-fresnel);
}