2

I have a fairly simple DirectX 11 framework setup that I want to use for various 2D simulations. I am currently trying to implement the 2D Wave Equation on the GPU. It requires I keep the grid state of the simulation at 2 previous timesteps in order to compute the new one.

How I went about it was this - I have a class called FrameBuffer, which has the following public methods:

bool Initialize(D3DGraphicsObject* graphicsObject, int width, int height);

void BeginRender(float clearRed, float clearGreen, float clearBlue, float clearAlpha) const;
void EndRender() const;

// Return a pointer to the underlying texture resource
const ID3D11ShaderResourceView* GetTextureResource() const;

In my main draw loop I have an array of 3 of these buffers. Every loop I use the textures from the previous 2 buffers as inputs to the next frame buffer and I also draw any user input to change the simulation state. I then draw the result.

    int nextStep = simStep+1;
    if (nextStep > 2)
        nextStep = 0;

    mFrameArray[nextStep]->BeginRender(0.0f,0.0f,0.0f,1.0f);
    {
        mGraphicsObj->SetZBufferState(false);
        mQuad->GetRenderer()->RenderBuffers(d3dGraphicsObj->GetDeviceContext());
        ID3D11ShaderResourceView* texArray[2] = { mFrameArray[simStep]->GetTextureResource(),
                                                  mFrameArray[prevStep]->GetTextureResource() };
        result = mWaveShader->Render(d3dGraphicsObj, mQuad->GetRenderer()->GetIndexCount(), texArray);
        if (!result)
            return false;
        // perform any extra input
        I_InputSystem *inputSystem = ServiceProvider::Instance().GetInputSystem();
        if (inputSystem->IsMouseLeftDown()) {
            int x,y;
            inputSystem->GetMousePos(x,y);
            int width,height;
            mGraphicsObj->GetScreenDimensions(width,height);
            float xPos = MapValue((float)x,0.0f,(float)width,-1.0f,1.0f);
            float yPos = MapValue((float)y,0.0f,(float)height,-1.0f,1.0f);
            mColorQuad->mTransform.position = Vector3f(xPos,-yPos,0);
            result = mColorQuad->Render(&viewMatrix,&orthoMatrix);
            if (!result)
                return false;
        }
        mGraphicsObj->SetZBufferState(true);
    }
    mFrameArray[nextStep]->EndRender();

    prevStep = simStep;
    simStep = nextStep;

    ID3D11ShaderResourceView* currTexture = mFrameArray[nextStep]->GetTextureResource();

    // Render texture to screen
    mGraphicsObj->SetZBufferState(false);
    mQuad->SetTexture(currTexture);
    result = mQuad->Render(&viewMatrix,&orthoMatrix);
    if (!result)
        return false;
    mGraphicsObj->SetZBufferState(true);

The problem is nothing is happening. Whatever I draw appears on the screen(I draw using a small quad) but no part of the simulation is actually ran. I can provide the shader code if required, but I am certain it works since I've implemented this before on the CPU using the same algorithm. I'm just not certain how well D3D render targets work and if I'm just drawing wrong every frame.

EDIT 1: Here is the code for the begin and end render functions of the frame buffers:

void D3DFrameBuffer::BeginRender(float clearRed, float clearGreen, float clearBlue, float clearAlpha) const {

  ID3D11DeviceContext *context = pD3dGraphicsObject->GetDeviceContext();

context->OMSetRenderTargets(1, &(mRenderTargetView._Myptr), pD3dGraphicsObject->GetDepthStencilView());

float color[4];

// Setup the color to clear the buffer to.
color[0] = clearRed;
color[1] = clearGreen;
color[2] = clearBlue;
color[3] = clearAlpha;

// Clear the back buffer.
context->ClearRenderTargetView(mRenderTargetView.get(), color);

// Clear the depth buffer.
context->ClearDepthStencilView(pD3dGraphicsObject->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0);

void D3DFrameBuffer::EndRender() const {
    pD3dGraphicsObject->SetBackBufferRenderTarget();
}

Edit 2 Ok, I after I set up the DirectX debug layer I saw that I was using an SRV as a render target while it was still bound to the Pixel stage in out of the shaders. I fixed that by setting shader resources to NULL after I render with the wave shader, but the problem still persists - nothing actually gets ran or updated. I took the render target code from here and slightly modified it, if its any help: http://rastertek.com/dx11tut22.html

Valentin
  • 1,731
  • 2
  • 19
  • 29

1 Answers1

3

Okay, as I understand correct you need a multipass-rendering to texture.

Basiacally you do it like I've described here: link

  • You creating SRVs with both D3D11_BIND_SHADER_RESOURCE and D3D11_BIND_RENDER_TARGET bind flags.
  • You ctreating render targets from textures
  • You set first texture as input (*SetShaderResources()) and second texture as output (OMSetRenderTargets())
  • You Draw()*
  • then you bind second texture as input, and third as output
  • Draw()*
  • etc.

Additional advices:

  1. If your target GPU capable to write to UAVs from non-compute shaders, you can use it. It is much more simple and less error prone.
  2. If your target GPU suitable, consider using compute shader. It is a pleasure.
  3. Don't forget to enable DirectX debug layer. Sometimes we make obvious errors and debug output can point to them.
  4. Use graphics debugger to review your textures after each draw call.

Edit 1:

As I see, you call BeginRender and OMSetRenderTargets only once, so, all rendering goes into mRenderTargetView. But what you need is to interleave:

SetSRV(texture1);
SetRT(texture2);
Draw();
SetSRV(texture2);
SetRT(texture3);
Draw();
SetSRV(texture3);
SetRT(backBuffer);
Draw();

Also, we don't know what is mRenderTargetView yet.

so, before

result = mColorQuad->Render(&viewMatrix,&orthoMatrix);

somewhere must be OMSetRenderTargets .

Probably, it s better to review your Begin()/End() design, to make resource binding more clearly visible.

Happy coding! =)

Community
  • 1
  • 1
Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
  • Sorry, but isn't that what I am already doing? My FrameBuffer BeginRender function binds the resource in it for drawing and GetTextureResource retrieves it. Also yeah - I want to try out Compute Shaders, but I want to get this working first for my own knowledge. – Valentin Oct 07 '13 at 15:34
  • probably, but I don't know what your `BeginRender` function does. If you sure that your code written correctly, just use graphics debugger to see what's wrong. There is not much we can help you. – Ivan Aksamentov - Drop Oct 07 '13 at 15:49
  • BTW, I don't see where you bind render target. – Ivan Aksamentov - Drop Oct 07 '13 at 15:50
  • Hi again - instead of me linking more code, here is where I based my FrameBuffer class from: http://rastertek.com/dx11tut22.html there you can see how he creates and uses it, which is a bit different from what I want to do. – Valentin Oct 07 '13 at 16:21
  • Did you used any Graphics Debugger? – Ivan Aksamentov - Drop Oct 08 '13 at 10:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38775/discussion-between-drop-and-valentin) – Ivan Aksamentov - Drop Oct 08 '13 at 10:42