1
votes

I am totally lost now. Have been trying to read the backbuffer inside a vertex shader for days with no luck whatsoever.

I'm trying to read the vertexes position from the backbuffer and it's neighboring pixels. (I'm trying to count how many black pixels are around a vertex, and if there are any color that vertex red in the pixel shader). I've created a separate ID3D11Texture2D and an SRV to go with the backBuffer. I copy the backbuffer into this SRV's resource. Bind the SRV using VSSetShaderResources but just can't seem to be able to read from it inside the vertex shader.

I will share some code here from the creation of these elements as well as include some RenderDoc screenshots that keep showing that the SRV is being bound to the VS stage and has the right texture associated with it but every Load or []operator or tex2dlod or SampleLevel(i bound a SamplerState too) just keeps returning a single 1.0 value with the rest of the float4 never being returned, meaning i only get a float1 back. I will also include a renderdoc capture file if anyone wants to take a look.

This is a simple scene from tutorial 42 on the rastertek.com site, there is a ground plane with a cube and a sphere on it :

https://i.imgur.com/cbVC48E.gif

// Here is some code when creating the secondary texture and SRV that houses a //backBuffer
// Get the pointer to the back buffer.
    result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
    if(FAILED(result))
    {
        MessageBox((*(hwnd)), L"Get the pointer to the back buffer FAILED", L"Error", MB_OK);
        return false;
    }


    // Create another texture2d that we will use to make an SRV out of, and this texture2d will be used to copy the backbuffer to so we can read it in a shader
    D3D11_TEXTURE2D_DESC bbDesc;
    backBufferPtr->GetDesc(&bbDesc);
    bbDesc.MipLevels = 1;
    bbDesc.ArraySize = 1;
    bbDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    bbDesc.Usage = D3D11_USAGE_DEFAULT;
    bbDesc.MiscFlags = 0;
    bbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    result = m_device->CreateTexture2D(&bbDesc, NULL, &m_backBufferTx2D);
    if (FAILED(result))
    {
        MessageBox((*(m_hwnd)), L"Create a Tx2D for backbuffer SRV FAILED", L"Error", MB_OK);
        return false;
    }
    D3D11_SHADER_RESOURCE_VIEW_DESC descSRV;
    ZeroMemory(&descSRV, sizeof(descSRV));
    descSRV.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    descSRV.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    descSRV.Texture2D.MipLevels = 1;
    descSRV.Texture2D.MostDetailedMip = 0;
    result = GetDevice()->CreateShaderResourceView(m_backBufferTx2D, &descSRV, &m_backBufferSRV);
    if (FAILED(result))
    {
        MessageBox((*(m_hwnd)), L"Creating BackBuffer SRV FAILED.", L"Error", MB_OK);
        return false;
    }

    // Create the render target view with the back buffer pointer.
    result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);

First I render the scene in all white and then I copy that to the SRV and bind it for the next shader that's supposed to sample it. I'm expecting to get a float4(1.0, 1.0, 1.0, 1.0) value returned when i sample the backbuffer with the vertex's on screen position

https://i.imgur.com/N9CYg8c.png

as shown on the top left in the event browser, there were three drawindexed calls for rendering everything in white and then a CopyResource. I've selected the next (fourth) DrawIndexed and on the right side outlined in red are the inputs for this next shader clearly showing that the backBuffer has been successfully bound to the vertex shader.

And now for the part that's giving me trouble

https://i.imgur.com/ENuXk0n.png

I'm gonna be debugging this top-left vertex as shown on the screenshot, the vertex Shader has a Texture2D prevBackBuffer: register(t0); written at the top

https://i.imgur.com/8cihNsq.png

When trying to sample the left neighboring pixel this line of code returns newCoord = float2(158, 220) when entering these pixel values in the texture view i get this pixel

https://i.imgur.com/DT72Fl1.png

so the coordinates are ok so far, and as outlined i'm expecting to get a float4(0.0, 0.0, 0.0, 1,0) returned when i sample this pixel (I'm trying to count how many black pixels are around a vertex, and if there are any color that vertex red in the pixel shader)

AND YET, when i sample that pixel right after altering the pixel coordinates since load counts pixels from bottom left so i need newCoord = float2(158, 379), i get this

https://i.imgur.com/8SuwOzz.png

why is this, even if it's out of range, load should return all zeros, since I'm not sure about the whole load counts from bottom left thing I tried sampling using the top left coordinates (158, 220) but end up getting 0.0, ?, ?, ?

I'm completely stumped and have no idea what to try next. I've tried using a sample state :

// Create a clamp texture sampler state description.
    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 1;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    // Create the texture sampler state.
    result = device->CreateSamplerState(&samplerDesc, &m_sampleStateClamp);

but still never get a proper float4 back when reading the texture.

Any ideas, suggestions, I'll take anything at this point. Oh and here's a RenderDoc file of the frame i was examining : http://www.mediafire.com/file/1bfiqdpjkau4l0n/my_capture.rdc/file

2
So one thing that seems off is the SRV buffer format, DXGI_FORMAT_R8G8B8A8_UNORM. This specifies a 32-bit normalized integer buffer, with 8 bit components. If you loaded a value from the buffer, and D3D didn't do any magic to convert it, the value you get back would only be a float, since float is 32 bits, and your texture is 32 bits per pixel. This would kinda match what you're seeing here. You could try replacing the format with a 128 bpp format and downscaling the texture for display. Samplers will also do nothing - your HLSL code uses Load, which does not use a sampler.Alex
The sample code from the rastertek.com tutorial creates the backBuffer with the DXGI_FORMAT_R8G8B8A8_UNORM format. If I was to change that to R32G32B32A32 wouldn't that be too much data and the backBuffer would end up being huge and slow. How would I go about dowscaling for the displayStRaToX
does downscaling include rendering the backbuffer as a quad on to a renderTexture. doesn't that include me being able to read from the backbuffer in the first place. It seems that my issue is that i just can't read from a R8G8B8A8 textureStRaToX

2 Answers

0
votes

So from my experience, reading from the back buffer is not really an operation that you want to be doing in the first place. If you have to do any operation on the rendered scene, the best way to do that is to render the scene to an intermediate texture, perform the operation on that texture, then render the final scene to the back buffer. This is generally how things like dynamic shadows are done - the scene is rendered from the perspective of the light, and the resulting buffer is interpreted to get a shadow value that is then applied to the final scene (this is also why dynamic light sources are limited in commercial game engines - they're rather expensive to use).

A similar idea can be applied here. First, render the whole scene to an intermediate texture, bound as a render target view (where the pixel format is specified by you, the programmer). Next, rebind that intermediate texture as a shader resource view, and render the scene again, using the edge detection shader and the real back buffer (where the pixel format is defined by the hardware).

This, fundamentally, is what I believe the issue is - a back buffer is a device dependent resource, and its format can change depending on the hardware. Therefore, using it from a shader is not safe, as you don't always know what the format will be. A device independent resource, on the other hand, will always have the same format, and you can safely use it however you like from a shader.

0
votes

I wasn't able to get sampling an SRV in the vertex shader to work but what i was able to get working is using a backBuffer.SampleLevel inside a compute shader I also had to change the sampler to something like this :

D3D11_SAMPLER_DESC samplerDesc;

samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0.5f;
samplerDesc.BorderColor[1] = 0.5f;
samplerDesc.BorderColor[2] = 0.5f;
samplerDesc.BorderColor[3] = 0.5f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = 0;