Search code examples
direct2dhdpi

D2D1 has obvious aliasing under high DPI


  • Write a simple demo to verify the issue, the higher the DPI, the more obvious the alias, the text is the same, try to use SetAntialiasMode and SetTextAntialiasMode no improvement, my system is win10 Professional version.
  • Is there some way to achieve anti-aliasing under high DPI? dpi: 384 and capture screen

    static ID2D1Factory * g_factory;
    static IDWriteFactory*  g_dwrite_factory;
    static ID2D1HwndRenderTarget * g_render_target;
    static INT32 _dpi_x = 96;
    static INT32 _dpi_y = 96;
    
    #define DIP_TEST
    
    void OnSize(LPARAM lparam)
    {    
    UINT32 width = LOWORD(lparam);
    UINT32 height = HIWORD(lparam);
    
    UINT32 pixel_width = (UINT32)(width * _dpi_x / 96.0f);
    UINT32 pixel_height = (UINT32)(height * _dpi_x / 96.0f);
    
    if (g_render_target)
    g_render_target->Resize(D2D1::SizeU(pixel_width, pixel_height));
    }
    
    bool AppInit()
    {
    #ifdef DIP_TEST
    SetProcessDPIAware();
    _dpi_x = 384;
    _dpi_y = 384; 
    #endif
    
    D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_factory);
    DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&g_dwrite_factory));
    
    RECT rc;
    GetClientRect(g_hwnd, &rc);
    
    UINT32 logic_width = rc.right - rc.left;
    UINT32 logic_height = rc.bottom - rc.top;
    UINT32 w = (UINT32)(logic_width * _dpi_x / 96.0f);
    UINT32 h = (UINT32)(logic_height * _dpi_x / 96.0f);
    
    D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, pixelFormat);//D2D1_RENDER_TARGET_TYPE_SOFTWARE为了截图
    #ifdef DIP_TEST
    props.dpiX = (float)_dpi_x;
    props.dpiY = (float)_dpi_y;
    #endif
    
    g_factory->CreateHwndRenderTarget(props,
    D2D1::HwndRenderTargetProperties(g_hwnd, D2D1::SizeU(w, h)),
    &g_render_target);
    
    return true;
    }
    
    void OnPaint()
    {
    if (!g_render_target)
        return;
    
    ...
    g_render_target->BeginDraw();
    g_render_target->Clear(D2D1::ColorF(0.f, 0.f, 0.0f));
    //g_render_target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
    stroke_brush->SetColor(D2D1::ColorF(1.0f, 0.0f, 0.0f, 1.0f));
    D2D1_RECT_F textLayoutRect = D2D1::RectF(100.0f, 150.0f, 600.0f, 600.0f);
    g_render_target->DrawTextW(sz, text_len, dwrite_text_format, textLayoutRect, stroke_brush, D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE_NATURAL);     
    g_render_target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(300.5, 200.5), 250, 150), stroke_brush, 2);
    g_render_target->EndDraw(); 
    ...
    }
    

Solution

  • It seems that you enable DPI awareness after creating window. You should declare dpi awareness in application manifest instead. Also there is no need to perform manual dimension scaling like (logic_width * _dpi_x / 96.0f); because window size will be already in physical pixels, not in logical_pixels.