This project has moved and is read-only. For the latest updates, please go here.

How to save & restore device state when using SpriteBatch & SpriteFont?

Jul 24, 2015 at 2:52 AM
Edited Jul 24, 2015 at 2:53 AM
I want to display cube and string but when I call Begin() and End() of SpriteBatch, cube disappears.

Image
This is DirectX 10 example which is using ID3DX10Sprite & ID3DX10Font, and the following is code fragment.
void DrawString()
{
    RECT rect;
    SetRectEmpty(&rect);
    rect.left = 0;
    rect.right = vars->clientWidth;
    rect.top = 0;
    rect.bottom = vars->clientHeight;

    vars->pSprite->Begin(D3DX10_SPRITE_SAVE_STATE); 
    if (!vars->pFont->DrawTextW(nullptr, L"Si hoc legere scis nimium eruditionis habes.", -1, &rect, DT_CENTER | DT_TOP, D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)))
    {
        MessageBoxW(nullptr, L"Failed calling DrawTextW", nullptr, 0);
    }
    vars->pSprite->End();
}
And the following is DirectX 11.1 example using DirectX Tool Kit.
Image
void DrawString()
{
    vars->spriteBatch->Begin();
    vars->spriteFont->DrawString(vars->spriteBatch.get(), L"Si hoc legere scis nimium eruditionis habes.", DirectX::XMFLOAT2(0.0f, 0.0f));
    vars->spriteBatch->End();
}
As you can see I can save the state of my device by passing "D3DX10_SPRITE_SAVE_STATE" at DirectX 10, but I don't know how to save the state at DXTK. Can anyone help my situation?
Following is the declaration of DirectX::SpriteBatch.Begin().
void XM_CALLCONV Begin(SpriteSortMode sortMode = SpriteSortMode_Deferred, _In_opt_ ID3D11BlendState* blendState = nullptr, _In_opt_ ID3D11SamplerState* samplerState = nullptr, _In_opt_ ID3D11DepthStencilState* depthStencilState = nullptr, _In_opt_ ID3D11RasterizerState* rasterizerState = nullptr, _In_opt_ std::function<void DIRECTX_STD_CALLCONV()> setCustomShaders = nullptr, FXMMATRIX transformMatrix = MatrixIdentity);
Jul 24, 2015 at 6:40 AM
Direct3D 11 does not have support for this style of state capture as it's extremely inefficient.

Instead, your cube draw should explicitly set the state it needs. I cant' tell from your snippets what the exact problem is here, but it's likely something quite simple.
Jul 24, 2015 at 8:09 AM
auto vars = DX11StaticVariables::GetInstance();

void InitResources()
{
    VERTEX OurVertices[] =
    {
        { -1.0f, -1.0f, 1.0f, D3DXVECTOR3(0.0f, 0.0f, 1.0f) }, // side 1
        { 1.0f, -1.0f, 1.0f, D3DXVECTOR3(0.0f, 0.0f, 1.0f) },
        { -1.0f, 1.0f, 1.0f, D3DXVECTOR3(0.0f, 0.0f, 1.0f) },
        { 1.0f, 1.0f, 1.0f, D3DXVECTOR3(0.0f, 0.0f, 1.0f) },

        { -1.0f, -1.0f, -1.0f, D3DXVECTOR3(0.0f, 0.0f, -1.0f) }, // side 2
        { -1.0f, 1.0f, -1.0f, D3DXVECTOR3(0.0f, 0.0f, -1.0f) },
        { 1.0f, -1.0f, -1.0f, D3DXVECTOR3(0.0f, 0.0f, -1.0f) },
        { 1.0f, 1.0f, -1.0f, D3DXVECTOR3(0.0f, 0.0f, -1.0f) },

        { -1.0f, 1.0f, -1.0f, D3DXVECTOR3(0.0f, 1.0f, 0.0f) }, // side 3
        { -1.0f, 1.0f, 1.0f, D3DXVECTOR3(0.0f, 1.0f, 0.0f) },
        { 1.0f, 1.0f, -1.0f, D3DXVECTOR3(0.0f, 1.0f, 0.0f) },
        { 1.0f, 1.0f, 1.0f, D3DXVECTOR3(0.0f, 1.0f, 0.0f) },

        { -1.0f, -1.0f, -1.0f, D3DXVECTOR3(0.0f, -1.0f, 0.0f) }, // side 4
        { 1.0f, -1.0f, -1.0f, D3DXVECTOR3(0.0f, -1.0f, 0.0f) },
        { -1.0f, -1.0f, 1.0f, D3DXVECTOR3(0.0f, -1.0f, 0.0f) },
        { 1.0f, -1.0f, 1.0f, D3DXVECTOR3(0.0f, -1.0f, 0.0f) },

        { 1.0f, -1.0f, -1.0f, D3DXVECTOR3(1.0f, 0.0f, 0.0f) }, // side 5
        { 1.0f, 1.0f, -1.0f, D3DXVECTOR3(1.0f, 0.0f, 0.0f) },
        { 1.0f, -1.0f, 1.0f, D3DXVECTOR3(1.0f, 0.0f, 0.0f) },
        { 1.0f, 1.0f, 1.0f, D3DXVECTOR3(1.0f, 0.0f, 0.0f) },

        { -1.0f, -1.0f, -1.0f, D3DXVECTOR3(-1.0f, 0.0f, 0.0f) }, // side 6
        { -1.0f, -1.0f, 1.0f, D3DXVECTOR3(-1.0f, 0.0f, 0.0f) },
        { -1.0f, 1.0f, -1.0f, D3DXVECTOR3(-1.0f, 0.0f, 0.0f) },
        { -1.0f, 1.0f, 1.0f, D3DXVECTOR3(-1.0f, 0.0f, 0.0f) },
    };

    // create the vertex buffer
    D3D11_BUFFER_DESC bd;
    RtlZeroMemory(&bd, sizeof(bd));

    bd.Usage = D3D11_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof(VERTEX) * 24;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    vars->d3dDevice->CreateBuffer(&bd, nullptr, &vars->vertexBuffer);

    // copy the vertices into the buffer
    D3D11_MAPPED_SUBRESOURCE ms;
    vars->d3dImmediateContext->Map(vars->vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
    memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
    vars->d3dImmediateContext->Unmap(vars->vertexBuffer, NULL);


    // create the index buffer out of DWORDs
    DWORD OurIndices[] =
    {
        0, 1, 2, // side 1
        2, 1, 3,
        4, 5, 6, // side 2
        6, 5, 7,
        8, 9, 10, // side 3
        10, 9, 11,
        12, 13, 14, // side 4
        14, 13, 15,
        16, 17, 18, // side 5
        18, 17, 19,
        20, 21, 22, // side 6
        22, 21, 23,
    };

    // create the index buffer
    bd.Usage = D3D11_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof(DWORD) * 36;
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    bd.MiscFlags = 0;

    vars->d3dDevice->CreateBuffer(&bd, nullptr, &vars->indexBuffer);

    vars->d3dImmediateContext->Map(vars->indexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
    memcpy(ms.pData, OurIndices, sizeof(OurIndices)); // copy the data
    vars->d3dImmediateContext->Unmap(vars->indexBuffer, NULL);
}

void RenderFrame()
{
    UpdateEnvironment();

    vars->d3dImmediateContext->ClearRenderTargetView(vars->renderTargetView, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
    vars->d3dImmediateContext->ClearDepthStencilView(vars->depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    UINT stride = sizeof(VERTEX);
    UINT offset = 0;
    vars->d3dImmediateContext->IASetVertexBuffers(0, 1, &vars->vertexBuffer, &stride, &offset);
    vars->d3dImmediateContext->IASetIndexBuffer(vars->indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    vars->d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    /* Draw cube */
    vars->d3dImmediateContext->UpdateSubresource(vars->constantBuffer, 0, nullptr, &vars->envBuffer, 0, 0);
    vars->d3dImmediateContext->DrawIndexed(36, 0, 0);

    DrawString();

    vars->swapChain->Present(0, 0);
}
As you can see, I prepare my cube data at InitResources() and render it at RenderFrame(). RenderFrame is in the loop of WinMain. Can you tell me how to set the state at cube drawing step?
If you have hard time understanding my code structure, I can upload entire project.

Thank you.