See the question and my original answer on StackOverflow

Bitmaps (D2D1 or others in GPU context) are "just" GPU resources that can serve very different purposes.

Your error comes from the fact you're confusing the target bitmap for the device context with a bitmap you want to write on the device context.

  • The first bitmap is just here to express the target for the device context is in fact the DXGI surface.
  • The second bitmap is used to write some pixels on the device context (which in turn will land on the DXGI surface).

So you need to change your code. First, just connect the device context (=render target) to the DXGI surface, like this:

void setBackBuffer(D2d* d2d)
{
    IDXGISurface* surface;
    ID2D1Bitmap1* bitmap;
    HRESULT res = d2d->dxgi_swapchain->GetBuffer(0, __uuidof(surface), (void**)&surface);
    if (FAILED(res))
        return;

    res = d2d->d2d_device_ctx->CreateBitmapFromDxgiSurface(surface, NULL, &bitmap);
    if (FAILED(res))
        goto release_surface;

    d2d->d2d_device_ctx->SetTarget(bitmap);
    bitmap->Release();
release_surface:
    surface->Release();
}

And add that just after your call to CreateSwapChainForComposition.

After that, modify your render method like this for example:

void render(D2d* d2d)
{
    ID2D1Bitmap1* bitmap;
    D2D1_BITMAP_PROPERTIES1 properties;
    DXGI_SWAP_CHAIN_DESC1 desc;
    D2D1_COLOR_F c;
    HRESULT res;

    std::cout << "render" << std::endl;

    // get size from swapchain (for example)
    d2d->dxgi_swapchain->GetDesc1(&desc);
    D2D1_SIZE_U s = { desc.Width, desc.Height };

    unsigned int* data, * iter;
    unsigned int i, j;

    // BGRA test data
    data = (unsigned int*)malloc(s.width * s.height * sizeof(unsigned int));
    if (!data)
    {
        std::cout << "malloc fails" << std::endl;
        return;
    }
    iter = data;
    for (i = 0; i < s.height; i++)
    {
        for (j = 0; j < s.width; j++, iter++)
        {
            if (i >= 50 && j >= 50)
                *iter = 0xff0000ff;
            else
                *iter = 0xffff0000;
        }
    }

    std::cout << "render 4" << std::endl;

    // create a bitmap from properties & pixel buffer
    // hint: in general for most structures, it's much easier to use ZeroMemory or memset(0) so by default values are automatically set
    ZeroMemory(&properties, sizeof(properties));
    properties.pixelFormat.format = desc.Format;
    properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
    res = d2d->d2d_device_ctx->CreateBitmap(s, data, 4 * s.width, properties, &bitmap);
    if (FAILED(res))
    {
        std::cout << "create failed" << std::endl;
        goto data_free;
    }
    std::cout << "render 5" << std::endl;

    d2d->d2d_device_ctx->BeginDraw();

    c.r = 0.0f;
    c.g = 0.0f;
    c.b = 0.0f;
    c.a = 0.0f;
    d2d->d2d_device_ctx->Clear(&c);
    std::cout << "render 6" << std::endl;

    D2D1_RECT_F rect;
    rect.left = 0.0f;
    rect.top = 0.0f;
    rect.right = (float)s.width;
    rect.bottom = (float)s.height;
    d2d->d2d_device_ctx->DrawBitmap(bitmap, rect, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, rect);
    std::cout << "render 7" << std::endl;

    d2d->d2d_device_ctx->EndDraw(NULL, NULL);

    d2d->dxgi_swapchain->Present(1, 0);
    d2d->dcomp_visual->SetContent(d2d->dxgi_swapchain);
    d2d->dcomp_target->SetRoot(d2d->dcomp_visual);
    d2d->dcomp_device->Commit();

    bitmap->Release();
data_free:
    free(data);
}