Alright, been working on setting up my first deferred rendering attempt using a light prepass technique in Direct3D 11.

Anywho, I've been having problems understanding and using render targets. Never really had to do much of anything with them in my previous forward rendering approaches. I'm pretty sure I'm correctly initializing them and binding them to the output merger stage however I'm not getting any results from my first geometry pass.

Now, what I'm doing to test my Geometry buffer pass could be the problem itself and the source of my confusion. I've been unclear as to how to choose which render target is presented with the swap chain. I've been working under the assumption that I just need to make sure I have a render target view that was initialized using the swap chain's backbuffer address and that this render target is what gets presented each frame. So based on that I've been binding my "Presentation" render target to the pipeline instead of what I would be using for my Position and/or Normal render buffers. However, I get nothing but an empty black frame so I assume the buffer isn't getting written to properly. (I'm actually overriding the values written to the buffer with a hard coded color in the pixel shader so I don't think it's related to the shader logic doing something funky, however sending the same "presentation" render target through my forward pass shader works fine...)

So my questions essentially are: am I missing a critical concept or failing to properly set up the Texture2D and Render Target View resources? And is my approach in choosing which render target to present correct, or can I directly bind a specific render target to the swap chain? Also my swap chain has a DXGI_FORMAT_R8G8B8A8_UNORM format for the backbuffer, do the other render target views and textures have to match this?

Edit: With Nathan's clarification and debugging tips I was able to solve my buffer issue. It was actually getting written to however, I had a transposed matrix that was mucking up the vertex transformations. The code below works fine if someone reads this that is interested in it.

Providing the relevant code from my project.

Prepare pipeline for the geometry pass. (Pretty sure I've got this correct)

void GeometryBufferPass::StartRendering(RenderTargetView* _positionRT, RenderTargetView* _normalRT,
DepthBuffer* _depthBuffer, RasterizerState* _rasterizerState) {
static ID3D11RenderTargetView* _renderTargets[2];

static float _ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // RGBA
pDeviceManager->GetDeviceContext()->ClearRenderTargetView(_positionRT->GetRenderTargetView(), _ClearColor);
pDeviceManager->GetDeviceContext()->ClearRenderTargetView(_normalRT->GetRenderTargetView(), _ClearColor);
pDeviceManager->GetDeviceContext()->ClearDepthStencilView(_depthBuffer->GetDepthBufferView(), D3D11_CLEAR_DEPTH, 1.0f, 1);

pDeviceManager->GetDeviceContext()->VSSetShader(vShader.GetShaderPtr(), 0, 0);
pDeviceManager->GetDeviceContext()->PSSetShader(pShader.GetShaderPtr(), 0, 0);

_renderTargets[0] = _positionRT->GetRenderTargetView();
_renderTargets[1] = _normalRT->GetRenderTargetView();
pDeviceManager->GetDeviceContext()->OMSetRenderTargets(2, _renderTargets, _depthBuffer->GetDepthBufferView());



pDeviceManager->GetDeviceContext()->VSSetConstantBuffers(0, 1, transformBuffer.GetConstantBuffer());
pDeviceManager->GetDeviceContext()->PSSetConstantBuffers(1, 1, materialBuffer.GetConstantBuffer());

Render each object through the geometry pass.

void GeometryBufferPass::Render(Entity &_entity) {
static XMMATRIX _matrix;
static GeometryBufferPass_TransformBuffer _transformBuffer;
static GeometryBufferPass_MaterialBuffer _materialBuffer;
static unsigned int _offset = 0;

_matrix = XMMatrixMultiply(*_entity.GetInstanceObject()->GetScaleMatrix(), *_entity.GetInstanceObject()->GetRotationMatrix());
_matrix = XMMatrixMultiply(_matrix, *_entity.GetInstanceObject()->GetTranslationMatrix());
_transformBuffer.world = XMMatrixTranspose(_matrix);

_matrix = XMMatrixMultiply(_matrix, viewProjectionMatrix);
_transformBuffer.worldViewProjection = XMMatrixTranspose(_matrix);


_materialBuffer.specularExponent = _entity.GetRenderObject()->GetMaterial()->GetSpecularExponent();

pDeviceManager->GetDeviceContext()->IASetVertexBuffers(0, 1, _entity.GetRenderObject()->GetVertexBuffer()->GetVertexBuffer(), _entity.GetRenderObject()->GetVertexBuffer()->GetVertexStridePtr(), &_offset);    
if (_entity.GetRenderObject()->GetVertexBuffer()->GetIndexBuffer() != 0) {
    pDeviceManager->GetDeviceContext()->IASetIndexBuffer(_entity.GetRenderObject()->GetVertexBuffer()->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, 0); 
} else pDeviceManager->GetDeviceContext()->Draw(_entity.GetRenderObject()->GetVertexBuffer()->GetVertexBufferSize(), 0);    

Here is how I create Texture2D and Render Target View objects.

bool Texture2D::InitializeTexture(const unsigned int _width, const unsigned int _height, const bool _isShaderResourceView, const bool _isRenderTargetView) {
if (!StartUp())
    return false;

_desc.Width = _width;
_desc.Height = _height;
_desc.MipLevels = 0;
_desc.ArraySize = 1;
_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; // or DXGI_FORMAT_R8G8B8A8_UNORM? Even though I am writing 4 floats to it...
_desc.Usage = D3D11_USAGE_DEFAULT;
_desc.CPUAccessFlags = 0;
_desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS; // Not sure if I need to generate a mip map chain for my purposes.

unsigned int _bindFlag = 0;
if (_isShaderResourceView)
    _bindFlag |= D3D11_BIND_SHADER_RESOURCE;

if (_isRenderTargetView)
    _bindFlag |= D3D11_BIND_RENDER_TARGET;

_desc.BindFlags = _bindFlag;

_sampleDesc.Count = 1;
_sampleDesc.Quality = 0;
_desc.SampleDesc = _sampleDesc;

if (FAILED(pDeviceManager->GetDevice()->CreateTexture2D(&_desc, 0, &pTexture)))
    return false;

if (_isRenderTargetView)
    if (!renderTarget.StartUp(pTexture, _desc.Format))
        return false;

return true;

Render Target View initialization

bool RenderTargetView::StartUp(ID3D11Resource* _resource, const DXGI_FORMAT _format, const D3D11_RTV_DIMENSION _viewType) {
pDeviceManager = D11DeviceManager::GetSingleton();

_desc.Format = _format;
_desc.ViewDimension = _viewType;

// Class only handles Texture2D at the moment.
D3D11_TEX2D_RTV _rtv;
_rtv.MipSlice = 1;
_desc.Texture2D = _rtv;

return !FAILED(pDeviceManager->GetDevice()->CreateRenderTargetView(_resource, &_desc, &pRenderTargetView));

And figured I might as well post the shader code just in case.

cbuffer TransformBuffer : register(b0) {
float4x4 worldMatrix,

// Pretty sure constant buffers have to be atleast 16 bytes
// but shader compiler has yet to throw a warning or error.
cbuffer MaterialBuffer : register(b1) {
float  materialSpecularExponent;

struct vsInput {
float3 positionLS : POSITION;
float3 textureLS  : TEXTURE;
float3 normalLS   : NORMAL;

struct vsOutput {
float4 positionCS : SV_POSITION;
float2 textureLS  : TEXTURE;
float3 normalWS   : NORMAL;
float3 positionWS : POSITION;

struct psOutput {
float4 normalWS   : SV_TARGET0;
float4 positionWS : SV_TARGET1;

vsOutput VS( in const vsInput _in ) {
vsOutput _out;

_out.positionCS = float4(mul(_in.positionLS, (float3x3) worldViewProjectionMatrix), 1.0f);
_out.positionWS = mul(_in.positionLS, (float3x3) worldMatrix);
_out.normalWS   = mul(_in.normalLS,   (float3x3) worldMatrix);
_out.textureLS  = (float2)_in.textureLS;

return _out;

psOutput PS( in const vsOutput _in ) {
psOutput _out;

// Overwriting the pixel shader return values just so I can see if the render
// target is getting written to.
_out.normalWS   = float4(0.5f, 1.0f, 0.0f, 1.0f);//float4(normalize(_in.normalWS), materialSpecularExponent);
_out.positionWS = float4(0.5f, 1.0f, 0.0f, 1.0f);//float4(_in.positionWS, 1.0f);

return _out;

1 Answer 1


You don't choose which render target to present. The IDXGISwapChain object owns the back buffer (the render target that gets presented); it's automatically created when the swap chain is set up. To draw to the back buffer, you first get a reference to it as a texture by calling IDXGISwapChain::GetBuffer; then you set up a RenderTargetView from that.

In order to display another render target on the screen, you can use ID3D11DeviceContext::CopyResource to copy from the other render target to the back buffer. That only works if they're exactly the same size and format; in other cases, I believe you have to copy the image by drawing a full-screen quad with a simple pixel shader that samples your image and returns it.

Other render targets and textures do not need to have the same format as the back buffer; they can have any supported format you want.

  • \$\begingroup\$ Excellent. Thank you for clarifying this! However, I'm still not getting any output to my presentation render target when I send it in as one of the normal or position render targets. I"m completely stumped. \$\endgroup\$ Jan 9, 2012 at 18:31
  • 1
    \$\begingroup\$ @KlashnikovKid Try clearing your buffers to a known color and see if that color shows up on screen. Also double check your render states and make sure there aren't unintended culling, blending, or depth-testing states that might screw things up. Also, you might try using Pix (shader debugger tool in the DirectX SDK); might be able to get something useful out of that. \$\endgroup\$ Jan 9, 2012 at 19:12
  • \$\begingroup\$ Thanks, clearing my buffer to a known color was a good idea. Turned out my render targets were getting written to, I just forgot that my camera class automatically transposed the view and projection matrices which was the problem! Doh! \$\endgroup\$ Jan 9, 2012 at 22:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .