Original Post
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.