Skip to main content
GameDev.net gamedev.net
🔒 Locked

fragment shader headache

Started by fanaticlatic Apr 14, 2008 at 1:30 PM 2 replies 1.7k views
Original Post
fanaticlatic
fanaticlatic
Hi all, I am trying to convert the article "Fast Fluid Dynamics Simulation on the GPU" in GPU Gems chapter 38 from an opengl cg implementation to a DirectX 9 HLSL implementation. So far the advection pass is working fine which for those of you unfamiliar with the aforementioned article is the pass that pushes the 2D fluid around. My current problem involves the jacobi poisson solver used for the viscous diffusion pass and pressure pass. The jacobi function in my shader is this: //--------------------------------------------------------------// // Jacobi Poisson Solver //--------------------------------------------------------------// shared texture initVelocity_Tex : r_Velocity : register(s1); sampler2D velocity = sampler_state { Texture = ; ADDRESSU = WRAP; ADDRESSV = WRAP; ADDRESSW = WRAP; }; float alpha : register(c2); float rBeta : register(c3); float4 jacobi(float2 coords : TEXCOORD0) : COLOR0 { // left, right, bottom and top velocity samples float4 texL = tex2D(velocity, coords - float2(1,0)); float4 texR = tex2D(velocity, coords + float2(1,0)); float4 texB = tex2D(velocity, coords - float2(0,1)); float4 texT = tex2D(velocity, coords + float2(0,1)); // velocity sample, from center float4 texC = tex2D(velocity, coords); // evaluate jacobi iteration return (texL + texR + texB + texT + alpha * texC) * rBeta; //+ float4(0.1f,0.0f,0.0f,0.0f); } pixelfragment jacobiFragment = compile_fragment ps_2_0 jacobi(); Please note how i have attempted to place the texture object into the register (s1). I did this to ensure the GPU would not overwrite the dye texture used by the advection pass. Yet when i check the shader using NVidia perfHUD the assembly output appears to suggest the texture is placed in register(s0) regardless. Here is the assembly output saved from the PerfHUD test: // // Generated by Microsoft (R) D3DX9 Fragment Linker 9.19.949.1104 // // Parameters: // // float alpha; // float rBeta; // sampler2D velocity; // // // Registers: // // Name Reg Size // ------------ ----- ---- // alpha c2 1 // rBeta c3 1 // velocity s0 1 // ps_2_0 dcl t0.xy dcl_2d s0 def c4, -1, 0, 0, 0 def c5, 0.100000001, 0, 0, 0 def c6, 0, -1, 0, 0 add r3.xy, t0, c4 add r2.xy, t0, -c4 add r1.xy, t0, c6 add r0.xy, t0, -c6 texld r3, r3, s0 texld r4, r2, s0 texld r2, r1, s0 texld r1, r0, s0 texld r0, t0, s0 add r3, r3, r4 add r2, r2, r3 add r1, r1, r2 mad r0, c2.x, r0, r1 mov r1.w, c3.x mad r0, r0, r1.w, c5 mov oC0, r0 // approximately 16 instruction slots used (5 texture, 11 arithmetic) I beleive this overwriting of register values between calls to the advection and jacobi passes to be the current problem with my application. I have tried all sorts from rewriting the app using an ID3DXEffect object rather than explicit calls to the graphics device to implementing user defined semantics as seen in the first code snippet above (see r_Velocity). all to no avail. If anyone has any thoughts about were i am going wrong please let me know. here is the render code i am using for the program. // Number of iterations Jacobi solver should do. const UINT JACOBI_ITR = 20; // Save a pointer to the initial Render Target. IDirect3DSurface9 *pTargSurface = NULL; // GetRenderTarget increases the surface's reference count // so remember to call release when it has been finished with. m_pDevice->GetRenderTarget(0,&pTargSurface); // Set the device to point to the new render target. m_pDevice->SetRenderTarget(0,m_pRTSurface); // Convert milliseconds into seconds and add to current time currentTime += ((float)elapsedTime)/100.0f; // Uncomment to see a static image useful when checking output // between builds. //currentTime = 500; ///////////////ADVECTION//////////// // Pass in variable values to the effect m_pAdvectionConstTable->SetFloat(m_pDevice,"fTime", (float)currentTime); // Get the surface description of the dye texture. D3DSURFACE_DESC surfDesc; m_pTexture->GetLevelDesc(0,&surfDesc); // Use surface description to set rdx value m_pAdvectionConstTable->SetFloat(m_pDevice,"rdx",1.0f/surfDesc.Width); /////////////////////////////////// ///////////////ADVECTION RENDER/////////////// // Set Dye texture to device m_pDevice->SetTexture(0,m_pTexture); // Set Velocity texture to device m_pDevice->SetTexture(1,pScratchTexture); // Associate this vertex/pixel shader with the device m_pDevice->SetVertexShader(m_pVertexShader); m_pDevice->SetPixelShader(m_pAdvectionPixelShader); // Render screen aligned quad Plane::Render(elapsedTime); // Store the new render target data in the OffScreenSurfaces. m_pDevice->GetRenderTargetData(m_pRTSurface,m_pOffScreenSurface); // Store the advection data into the second off screen surface m_pDevice->GetRenderTargetData(m_pRTSurface,m_pOffScreenSurface2); // Copy advection to original render target POINT pt; pt.x = 0; pt.y = 100; m_pDevice->UpdateSurface(m_pOffScreenSurface,NULL,pTargSurface,&pt); //////////////JACOBI/////////////// // max = 0.005f // min = 0.0001f float kinematicViscosity = 0.0001f; float alpha = ((float)(surfDesc.Width*surfDesc.Width)) / (kinematicViscosity*(elapsedTime/100.0f)); float rBeta = 1.0f/(4.0f+alpha); m_pJacobiConstTable->SetFloat(m_pDevice,"alpha", alpha); m_pJacobiConstTable->SetFloat(m_pDevice,"rBeta", rBeta); // Set the device to point to the new render target. m_pDevice->SetRenderTarget(0,m_pRTSurface2); ////////////////JACOBI RENDER//////////////// // Set new pixel shader to the graphics device // the vertex shader is set before advection pass. m_pDevice->SetPixelShader(m_pJacobiPixelShader); // Jacobi iterator for(UINT iJacobi = 0; iJacobi < JACOBI_ITR; iJacobi++) { // Set Velocity texture m_pDevice->SetTexture(1,pScratchTexture); // Render screen aligned quad Plane::Render(elapsedTime); // Store the new render target data in the OffScreenSurface2. m_pDevice->GetRenderTargetData(m_pRTSurface2,m_pOffScreenSurface2); // Update velocity texture surface m_pDevice->UpdateSurfac(m_pOffScreenSurface2,NULL,pScratchSurface,NULL); } // Set position for data to be copied to original render target. POINT pt2; pt2.x = 520; pt2.y = 100; // Copy the OffScreenSurface2 to the original render target surface. m_pDevice->UpdateSurface(m_pOffScreenSurface2,NULL,pTargSurface,&pt2); ////////////////REVERT TO ORIGINAL RT//////////////// // Restore the original render target. m_pDevice->SetRenderTarget(0,pTargSurface); // GetRenderTarget increases the surfaces reference count // so release the pointer to the surface to avoid memory leaks. // NOTE: The reference counter for the render target should not // be 0 at this point. SafeRelease(pTargSurface); Just to make clear i am doing this as my dissertation project and any help on this will be referenced and documented in my final report. Thanks in advance, mark.
"I have more fingers in more pies than a leper at a bakery!"
MJP
MJP
There may be a way to bind a texture to a sampler register, but I've always bound a sampler to a register if I want to explicitly specify a texture stage. Like this:

sampler2D velocity : register(s1);


Or of course, you can just use ID3DXEffect::SetTexture if you want to bind a texture to right texture stage.
browny
browny
Quote:

// left, right, bottom and top velocity samples
float4 texL = tex2D(velocity, coords - float2(1,0));
float4 texR = tex2D(velocity, coords + float2(1,0));
float4 texB = tex2D(velocity, coords - float2(0,1));
float4 texT = tex2D(velocity, coords + float2(0,1));


I didn't go through the whole code, nor that I would understand all fancy maths that are involved.But the above code looks kind of weird to me because it seems ou are trying to sample four neighbouring pixels of a texture ( is that right ). In that case , you will need to multiply a scale with float2(1,0) and etc, because "1" means the end of your texure (not the next pixel)!. So if you texture X-Size is 512, the scale would be 1/512.
Z
fanaticlatic
fanaticlatic
Thanks for the quick response guys.


Quote:

There may be a way to bind a texture to a sampler register, but I've always bound a sampler to a register if I want to explicitly specify a texture stage. Like this:

sampler2D velocity : register(s1);

Or of course, you can just use ID3DXEffect::SetTexture if you want to bind a texture to right texture stage.


I tried both of those methods MJP though i have changed alot since i tried using ID3DXEffect but neither seemed to help the problem. That being said i think will try setting the register on the sampler with the sampler as a parameter to the advection and jacobi functions, hopefully that might help.

Quote:

I didn't go through the whole code, nor that I would understand all fancy maths that are involved.But the above code looks kind of weird to me because it seems ou are trying to sample four neighbouring pixels of a texture ( is that right ). In that case , you will need to multiply a scale with float2(1,0) and etc, because "1" means the end of your texure (not the next pixel)!. So if you texture X-Size is 512, the scale would be 1/512.


Thats precisely what i am going for. I have not tried scaling this value so i'll give that a whirl and let you know how i get on.

Thanks for taking the time to trawl through my initial post guys.
"I have more fingers in more pies than a leper at a bakery!"

Topic Locked

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

Sign in to reply to this topic.