Jump to content
  • Advertisement

3D Solved - D3D9 - Use Pixel Shader to copy texture to texture

Recommended Posts

// SOLVED: code working properly now

Hey guys,

having read a lot here in the forums before, I decided to sign up and ask for help with my problem. And I would really appreciate any help!

I need to copy the contents of a D3D9 texture (1024 x 1024) of format INTZ to system memory to be able to use it in a different application. By the way, I am stuck with D3D9, the INTZ texture is part of a closed application and I get its handle via intercepting the D3D calls (proxy dll).

As far as I know (at least my attempts trying to do so failed) it is not possible to just use GetRenderDataTarget. The texture resides in the default pool and its usage is set to Depth/Stencil (2), thus the other methods like StretchRect, UpdateTexture, etc. also cannot be used.

Now I would like to use a pixel shader to sample this texture and write/copy the contents to a texture of a different format like R32F. I suppose, I can then use GetRenderTargetData to copy the contents to a third texture in system memory and lock this texture afterwards (probably with a delay so that the GPU has enough time to copy the data from video to system memory).

What I have so far is the following:

------ Vertex shader -----

struct VS_IN
    float4 pos : POSITION;
    float2 texcoord : TEXCOORD0;    

struct VS_OUT
    float4 pos : POSITION;
    float2 texcoord : TEXCOORD0;        

VS_OUT main(VS_IN input)
    VS_OUT output;
    output.pos = input.pos;
    output.texcoord = input.texcoord;
    return output;

------ Pixel shader: ------

sampler2D s2d : register(s0);

struct PS_IN

    float2 pos : VPOS; //screen position
    float2 texcoord : TEXCOORD0;    

float4 main(PS_IN input)
    float depth = tex2D(s2d,input.texcoord).r;
    return float4(depth, depth, depth, 1.0);


Application code:


struct CPYVTX_t {
    float x, y, z, rhw;
    float tu, tv;

#define D3D9CHECKANDTHROW(cmd,msg)        \
if (FAILED(cmd))                        \
{                                        \
    throw std::runtime_error(msg);        \


void Init()

D3D9CHECKANDTHROW(apDev->CreateOffscreenPlainSurface(gcR32Width, gcR32Height, D3DFMT_R32F, D3DPOOL_SYSTEMMEM, &gpSysMemSurface, 0),
        "Failed to create offscreen plain surface in system memory.")    

    D3D9CHECKANDTHROW(apDev->CreateRenderTarget(gcR32Width, gcR32Height, D3DFMT_R32F, D3DMULTISAMPLE_NONE, 0, false, &gpCopyRenderTarget, 0),
        "Failed to create render target as destination for copy pass.")

    D3D9CHECKANDTHROW(apDev->CreateDepthStencilSurface(gcR32Width, gcR32Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, true, &gpCopyDepthStencil, 0),
        "Failed to create depth stencil surface.")

    D3D9CHECKANDTHROW(apDev->CreateVertexDeclaration(CPYVTX_DECL, &gpVertexDeclaration),
        "Failed to create vertex declaration")

    // initialize vertices to be used for texture access    
    D3D9CHECKANDTHROW(apDev->CreateVertexBuffer(sizeof(CPYVTX_t) * 4, NULL, 0, D3DPOOL_DEFAULT, &gpVtxBuf, NULL),
        "Failed to create vertex buffer required for copy pass.")


        CPYVTX_t* lpVertices;
        gpVtxBuf->Lock(0, 0, (void**)&lpVertices, NULL);
        //Coordinates system, in general:   https://msdn.microsoft.com/en-us/library/windows/desktop/bb204853(v=vs.85).aspx
        //D3D9 vs D3D10 / NDC:                  https://msdn.microsoft.com/en-us/library/windows/desktop/cc308049(v=vs.85).aspx  
        //Triangle strips example:                https://msdn.microsoft.com/de-de/library/windows/desktop/bb206274(v=vs.85).aspx
        lpVertices[0].tu = 0.0f;
        lpVertices[0].tv = 0.0f;
        lpVertices[0].x = -1.0f;
        lpVertices[0].y = 1.0f;
        lpVertices[0].z = 0.0f;
        lpVertices[0].rhw = 1.0f;

        lpVertices[1].tu = 1.0f;
        lpVertices[1].tv = 0.0f;
        lpVertices[1].x = 1.0f;
        lpVertices[1].y = 1.0f;
        lpVertices[1].z = 0.0f;
        lpVertices[1].rhw = 1.0f;

        lpVertices[2].tu = 0.0f;
        lpVertices[2].tv = 1.0f;
        lpVertices[2].x = -1.0f;
        lpVertices[2].y = -1.0f;
        lpVertices[2].z = 0.0f;
        lpVertices[2].rhw = 1.0f;

        lpVertices[3].tu = 1.0f;
        lpVertices[3].tv = 1.0f;
        lpVertices[3].x = 1.0f;
        lpVertices[3].y = -1.0f;
        lpVertices[3].z = 0.0f;
        lpVertices[3].rhw = 1.0f;


LPD3DXBUFFER lpCPSO = nullptr, lpCVSO = nullptr, lpErrBuf = nullptr;
        NULL, NULL, "main", "vs_3_0", 0, &lpCVSO, &lpErrBuf, NULL),
        "Failed to compile vertex shader file.")

            NULL, NULL, "main", "ps_3_0", 0, &lpCPSO, &lpErrBuf, NULL),
            "Failed to compile pixel shader file.")

        if (gpCopyPixelShader)
        if (gpCopyVertexShader)
        D3D9CHECKANDTHROW(apDev->CreatePixelShader((DWORD*)lpCPSO->GetBufferPointer(), &gpCopyPixelShader),
            "Failed to create pixel shader from compiled object.")

        D3D9CHECKANDTHROW(apDev->CreateVertexShader((DWORD*)lpCVSO->GetBufferPointer(), &gpCopyVertexShader),
            "Failed to create vertex shader from compiled object.")


void RunCopy(){
    IDirect3DVertexDeclaration9 *lpDecl = nullptr;
    IDirect3DSurface9 *lpRenderTargetSfc = nullptr, *lpDepthStencilSfc = nullptr;
    IDirect3DVertexBuffer9 *lpVtxBuf = nullptr;
    IDirect3DVertexShader9 *lpVSShader = nullptr;
    IDirect3DPixelShader9 *lpPSShader = nullptr;
    IDirect3DBaseTexture9 *lpCurrentTex = nullptr;
    UINT lVtxBufOffset = 0, lVtxBufStride = 0;
    DWORD lFVF = 0;
// --- get current state

D3D9CHECKANDTHROW(apDev->GetVertexDeclaration(&lpDecl), "GetVertexDeclaration failed")
D3D9CHECKANDTHROW(apDev->GetStreamSource(0, &lpVtxBuf, &lVtxBufOffset, &lVtxBufStride), "")
D3D9CHECKANDTHROW(apDev->GetRenderTarget(0, &lpRenderTargetSfc), "GetRenderTarget failed.")
D3D9CHECKANDTHROW(apDev->GetDepthStencilSurface(&lpDepthStencilSfc), "GetDepthStencil failed.")
D3D9CHECKANDTHROW(apDev->GetVertexShader(&lpVSShader), "GetVertexShader")
D3D9CHECKANDTHROW(apDev->GetPixelShader(&lpPSShader), "GetPixelShader")
D3D9CHECKANDTHROW(apDev->GetTexture(0, &lpCurrentTex), "GetTexture failed")

// --- set new states required for copy pass

D3D9CHECKANDTHROW(apDev->SetVertexDeclaration(gpVertexDeclaration), "SetVertexDeclaration failed.")
D3D9CHECKANDTHROW(apDev->SetStreamSource(0, gpVtxBuf, 0, sizeof(CPYVTX_t)), "SetStreamSource failed.")
D3D9CHECKANDTHROW(apDev->SetRenderTarget(0, gpCopyRenderTarget), "SetRenderTarget failed.")
D3D9CHECKANDTHROW(apDev->SetDepthStencilSurface(gpCopyDepthStencil), "SetDepthStencilSurface failed.")
D3D9CHECKANDTHROW(apDev->SetVertexShader(gpCopyVertexShader), "SetVertexShader failed.")
D3D9CHECKANDTHROW(apDev->SetPixelShader(gpCopyPixelShader), "SetPixelShader failed.")

D3D9CHECKANDTHROW(apDev->SetTexture(0, gpR32Tex), "SetTexture failed")
D3D9CHECKANDTHROW(apDev->SetPixelShaderConstantF(0, &lFrustum.far_plane, 1), "SetPixelShaderConstantF failed.")
D3D9CHECKANDTHROW(apDev->SetPixelShaderConstantF(1, &lFrustum.near_plane, 1), "SetPixelShaderConstantF failed.")
D3D9CHECKANDTHROW(apDev->SetPixelShaderConstantF(2, lInvProjMat, 4), "SetPixelShaderConstantF failed.")

D3D9CHECKANDTHROW(apDev->BeginScene(), "BeginScene failed.")
D3D9CHECKANDTHROW(apDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2), "DrawPrimitive failed.")
D3D9CHECKANDTHROW(apDev->EndScene(), "EndScene failed.")

// --- reset previous state
D3D9CHECKANDTHROW(apDev->SetVertexDeclaration(lpDecl), "SetVertexDeclaration failed.")
D3D9CHECKANDTHROW(apDev->SetStreamSource(0, lpVtxBuf, lVtxBufOffset, lVtxBufStride), "SetStreamSource failed.")
D3D9CHECKANDTHROW(apDev->SetRenderTarget(0, lpRenderTargetSfc), "SetRenderTarget failed.")
D3D9CHECKANDTHROW(apDev->SetDepthStencilSurface(lpDepthStencilSfc), "SetDepthStencilSurface failed.")
D3D9CHECKANDTHROW(apDev->SetVertexShader(lpVSShader), "SetVertexShader failed.")
D3D9CHECKANDTHROW(apDev->SetPixelShader(lpPSShader), "SetPixelShader failed.")
D3D9CHECKANDTHROW(apDev->SetTexture(0, lpCurrentTex), "SetTexture failed.")



I believe the vertex definition (CPYVTX) needs to be extended to contain D3DFVF_XYZRHW and the float members respectively, otherwise the pixel shader does not know of which pixel it should set the value. But to be honest, I don't know what the  XYZRHW variables should contain. X and Y equal to the dimensions in pixels?(0|0), (0|1023), (1023|0),(1023|1023)?

How do I access an INTZ texture (which internally should be equal to D24S8) in the pixel shader and write its output to a R32F texture - is my shader syntax correct?

As I said initially, I am really grateful for every answer.

Edited by Apollo13
// SOLVED: new code working properly now

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!