Can not render to a render target that is also used as a texture

Started by
6 comments, last by XNA Coder 14 years, 7 months ago
Hi, I have a problem where I could only find solutions for fixed function pipeline programs. I try to render to a renderTarget texture with a HLSL shader that actually does not read from the renderTarget texture it renders into, but always get this DirectX error message:
Direct3D9: (WARN) :Can not render to a render target that is also used as a texture.
A render target was detected as bound, but couldn't detect if texture was actually used in rendering.
As the message and the forums already hint: Maybe I just need to unbind some textures, so I unbound the textures in the shader, but that didn't help. I'm still getting that failure constantly. Maybe I unbound them wrong? I did it with: pEffect->SetTexture(hTexture, NULL). OK? I'm really confused, the code looks perfect and I can find no answer, only for fixed function solutions in DX8: Device->SetTexture(x, NULL) - which of course isn't used anymore in DX9 shader based rendering. I even splitted the 2 passes into 2 different techniques - but no change. Here is my pseudo-code:

pEffect->SetTechnique(g_hTechnique);
  UINT passes;
  pEffect->Begin( &passes, D3DXFX_DONOTSAVESTATE );
  {
    ..SetVertexDeclaration...StreamSource
    pEffect->BeginPass(0);
    {
      SetRenderTarget(temp)
      rendering: temp = render(tex0 | tex1);
    }
    pEffect->EndPass();
  }
  pEffect->End();

  // Doesn't change _anything_ !!!!!!!!!!!
  pEffect->SetTexture( hTex0, NULL );
  pEffect->SetTexture( hTex1, NULL );
  pEffect->CommitChanges();

  pEffect->SetTechnique(g_hTechnique2);
  pEffect->Begin( &passes, D3DXFX_DONOTSAVESTATE);
  {
    pEffect->BeginPass(0);
    {
      SetRenderTarget(tex1);
      // Here happens the DX9 warning:
      rendering: tex1 = render(temp);
    }
    pEffect->EndPass();
  }
  pEffect->End();
(PS: I already tried to declare my vertex and pixel shaders as 3.0 - no difference :( ) Please, can anyone help? I'm absolutely lost here.
Advertisement
Quote:Original post by XNA Coder
  UINT passes;  pEffect->Begin( &passes, D3DXFX_DONOTSAVESTATE );  {    ..SetVertexDeclaration...StreamSource    pEffect->BeginPass(0);    {      SetRenderTarget(temp)      rendering: temp = render(tex0 | tex1);    }    pEffect->EndPass();  }  pEffect->End();
I'm no expert, but I don't think you can set the render target in the middle of rendering an effect. You should set the render target at the beginning.

I also think you can't render to a render target that was used as a texture inside a single BeginScene/EndScene. You've got to do two separate BeginScene/EndScene calls (but you only call Present the one time, of course). At least, that's how I do it, someone more knowledgeable than me can correct me if I'm wrong of course...
Quote:Original post by Codeka
I'm no expert, but I don't think you can set the render target in the middle of rendering an effect. You should set the render target at the beginning.

Well, I'm doing this all the time, successful. Nevertheless, this is a special case, so I tried and moved it out, but that didn't change anything :-(

Quote:Original post by Codeka
I also think you can't render to a render target that was used as a texture inside a single BeginScene/EndScene. You've got to do two separate BeginScene/EndScene calls (but you only call Present the one time, of course).

I tried different combinations of BeginScene/EndScene and Present, but it didn't change a thing.
:-(

I've run out of ideas.
Please, has anyone some ideas?
I've never worked with FX files, so I can't tell exactly how to do this. But with the plain render pipeline, you *have* to unbind a texture specifically before using it as a rendertarget. That means IDirect3DDevice9::SetTexture( ThatStageToWhichTheTextureWasBound, NULL); Most probably there's an effect equivalent of that call to bind a NULL texture to that specific sampler.
----------
Gonna try that "Indie" stuff I keep hearing about. Let's start with Splatter.
Quote:Original post by Schrompf
I've never worked with FX files, so I can't tell exactly how to do this. But with the plain render pipeline, you *have* to unbind a texture specifically before using it as a rendertarget. That means IDirect3DDevice9::SetTexture( ThatStageToWhichTheTextureWasBound, NULL); Most probably there's an effect equivalent of that call to bind a NULL texture to that specific sampler.


You have to be careful with this, because Effect's will keep a cached value of all parameters (including textures). They will then re-apply the values onto the device when you call Begin or BeginPass. So you may need to set the effect parameter values to NULL as well.


Quote:Original post by SchrompfThat means IDirect3DDevice9::SetTexture( ThatStageToWhichTheTextureWasBound, NULL); Most probably there's an effect equivalent of that call to bind a NULL texture to that specific sampler.

That's what I already said: I found that answer already for fixed function pipelines, but there is no equivalent in the HLSL pipeline. I can only set pEffect->SetTexture(handleTexture, NULL), but that didn't help a bit. We programmable pipeline guys know the Device->SetTexture() only from the tales of our ancestors ;-)
(Although it has its special meaning for programmable piepline, etc., read below.)

But anyway out of desperation I tried the fixed pipeline way again, although it didn't help earlier, combined with the other suggestions I got...
And it actually helped! I don't know what I made different that time, but this time it helped. I set blindly: Device->SetTexture(0..2, NULL) in a loop. But that's total guessing, because I never set the textures that way in the first time. I even guess the nr. of textures (3), because there a 3 different textures involved in my rendering process.
After that I set the texture I want to render from again in the effect, although this shouldn't be needed, and it works without it, I do it anyway.
Because: this use of Device->SetTexture(...) is mysteriously and actually not correct for the programmable pipeline. Although it is documented and has its use for the programmable pipeline, DirectX sets it itself (in this case) and I interfere blindly without exactly knowing why and how DirectX set and bound the texture sampler stages to the textures.

Does anyone know more how DirectX sets and binds the textures internally with SetTexture in the programmable shader pipeline?
Quote:Original post by XNA Coder
Does anyone know more how DirectX sets and binds the textures internally with SetTexture in the programmable shader pipeline?


Sure. Here is how you set textures with the progammable shader pipeline: you call IDirect3DDevice9::SetTexture. [smile]

You're confusing "programmable pipeline" with "Effects framework". The effects framework is just a layer on top of standard D3D...it doesn't do anything you couldn't do yourself with code by calling the core (non-D3DX) API methods. In the case of textures, when you call ID3DXEffect:SetTexture it internally caches the texture interface pointer. Then when you call BeginPass for a technique and pass that uses that texture, the effect will call IDirect3DDevice9::SetTexture with the the texture stage contained in its internal constant table that it uses to map your effects global variables to shader registers.

Have you used PIX before? I would really suggest you run PIX, and have it run your app in "single-frame capture" mode. Capture a single frame by pressing F12, close your app, and then have a look through the Events view on the left side to see all of the D3D calls made in a single frame. If you expand the ID3DXEffect calls, you can see all of the core D3D calls made behind the scenes. You can also have a look at exactly when you're setting render targets and textures, and be able to work out where you problem area is.

Quote:Original post by MJP
Sure. Here is how you set textures with the progammable shader pipeline: you call IDirect3DDevice9::SetTexture. [smile]

You're confusing "programmable pipeline" with "Effects framework". The effects framework is just a layer on top of standard D3D...it doesn't do anything you couldn't do yourself with code by calling the core (non-D3DX) API methods. In the case of textures, when you call ID3DXEffect:SetTexture it internally caches the texture interface pointer. Then when you call BeginPass for a technique and pass that uses that texture, the effect will call IDirect3DDevice9::SetTexture with the the texture stage contained in its internal constant table that it uses to map your effects global variables to shader registers.
Have you used PIX before? I would really suggest you run PIX, and...

OMG! You are so right! I actually knew pix before.
I should've used pix right from the beginning! It tells you so much more... if you know what you're searching for ;-)
You're exactly right: If you use DirectX9 on a modern GPU all the standard draw methods, like standard lighting, specular highlighting, etc., are automatically translated into Flexible Shader code. Direct3D even tells you that in the dbg info. But! What Effect does, is actually only encapsulating the standard D3D state calls, which can be seen in pix.
The way fixed function shaders are automatically translated in (pre-)programmed flexible shader functions is actually misleading and not parallel to the way the Effect class works.

Thanks! I understand know. [smile]

This topic is closed to new replies.

Advertisement