Edits. I'm switching for HwndRenderTargets to DeviceContexts and SwapChains for Hwnd in a Direct2d + Win32 application and the render target is not rendering completely on the swap chain.
class direct2dWindow : public direct2dContext
{
private:
HWND hwnd;
// for main window
ID2D1DeviceContext* renderTarget;
IDXGISwapChain1* swapChain;
IDXGISurface* surface;
ID3D11Texture2D* texture;
ID2D1Bitmap1* bitmap;
// for children
bool childWindow;
direct2dBitmapCore* childBitmap;
void applySwapChain();
public:
direct2dWindow(HWND hwnd, adapterSet* _adapter, bool _childWindow);
virtual ~direct2dWindow();
void resize(UINT x, UINT y);
void moveWindow(UINT x, UINT y, UINT h, UINT w);
virtual ID2D1DeviceContext* getRenderTarget()
{
return childBitmap ? childBitmap->getRenderTarget() : renderTarget;
}
ID2D1Bitmap1* getBitmap() { return childBitmap ? childBitmap->getBitmap() : bitmap; }
virtual void beginDraw(bool& _adapter_blown_away);
virtual void endDraw(bool& _adapter_blown_away);
bool isChild() { return childWindow; }
HWND getWindow() { return hwnd; }
};
void direct2dWindow::resize(UINT x, UINT y)
{
HRESULT hr;
if (childWindow)
{
if (childBitmap)
delete childBitmap;
D2D1_SIZE_F size;
size.width = x;
size.height = y;
childBitmap = new direct2dBitmapCore(size, factory);
}
else
{
if (renderTarget)
{
renderTarget->SetTarget(nullptr);
}
if (bitmap)
{
bitmap->Release();
bitmap = nullptr;
}
if (surface)
{
surface->Release();
surface = nullptr;
}
hr = swapChain->ResizeBuffers(2, x, y, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
throwOnFail(hr, "Couldn't resize swapchain");
applySwapChain();
}
}
direct2dWindow::direct2dWindow(HWND _hwnd, adapterSet* _adapterSet, bool _childWindow) : direct2dContext(_adapterSet)
{
HRESULT hr;
hwnd = _hwnd;
bitmap = nullptr;
surface = nullptr;
swapChain = nullptr;
renderTarget = nullptr;
childBitmap = nullptr;
childWindow = _childWindow;
D2D1_DEVICE_CONTEXT_OPTIONS options;
options = D2D1_DEVICE_CONTEXT_OPTIONS::D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
hr = _adapterSet->getD2DDevice()->CreateDeviceContext(options, &renderTarget);
throwOnFail(hr, "Could not create device context");
RECT rect;
::GetClientRect(hwnd, &rect);
int width = abs(rect.right - rect.left);
int height = abs(rect.bottom - rect.top);
if (!childWindow) {
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2; // use double buffering to enable flip
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Flags = 0;
hr = _adapterSet->getDxFactory()->CreateSwapChainForHwnd(_adapterSet->getD3DDevice(), hwnd, &swapChainDesc, nullptr, nullptr, &swapChain);
throwOnFail(hr, "Could not create swap chain");
DXGI_RGBA color;
color.a = 1.0;
color.r = 0.0;
color.g = .80;
color.b = 1.0;
swapChain->SetBackgroundColor(&color);
applySwapChain();
}
else
{
D2D1_SIZE_F size;
size.width = width;
size.height = height;
childBitmap = new direct2dBitmapCore(size, _adapterSet);
}
}
void direct2dWindow::applySwapChain()
{
HRESULT hr;
float dpix, dpiy;
int dpiWindow;
dpiWindow = ::GetDpiForWindow(hwnd);
renderTarget->GetDpi(&dpix, &dpiy);
// Now we set up the Direct2D render target bitmap linked to the swapchain.
// Whenever we render to this bitmap, it is directly rendered to the
// swap chain associated with the window.
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
dpix,
dpiy
);
// Direct2D needs the dxgi version of the backbuffer surface pointer.
hr = swapChain->GetBuffer(0, IID_IDXGISurface, (void**)&surface);
throwOnFail(hr, "Could not get swap chain surface");
DXGI_SURFACE_DESC sdec;
surface->GetDesc(&sdec);
// Get a D2D surface from the DXGI back buffer to use as the D2D render target.
hr = renderTarget->CreateBitmapFromDxgiSurface(
surface,
&bitmapProperties,
&bitmap
);
auto pxsx = bitmap->GetPixelSize();
auto sizex = bitmap->GetSize();
throwOnFail(hr, "Could create bitmap from surface");
// Now we can set the Direct2D render target.
renderTarget->SetTarget(bitmap);
auto dipssz = renderTarget->GetSize();
}
I've read this over and over again...and I've played with the code above, the other bits about handling the sizing. HR is always S_OK. Everything works, it seems like DXGI or the Context doesn't understand the D2D context on top of the swap chain doesn't cover the whole client area. Spy++ shows the window positioned correctly ok.
In the image, the blue is the swap chain background color, so I know that it is actually presenting the entire screen (which, in an earlier edit, I was not sure of). The green consists of two rectangles drawn on the render target. As you can see, they are clipped, even though the target should be full size itself. However, I noticed that the size of the render target, given by the snippet, is the same size in dips as it should be in pixels, which would explain why the output is clipped, I think.