Windows 上的 SKIA 渲染(HDC 的 SkCanvas)

Posted

技术标签:

【中文标题】Windows 上的 SKIA 渲染(HDC 的 SkCanvas)【英文标题】:SKIA Rendering on Windows(SkCanvas from HDC) 【发布时间】:2015-06-17 16:30:49 【问题描述】:

我正在尝试使用 SKIA 在 Windows 上绘图。

是否有从 HDC 启动 SkCanvas 的方法?

【问题讨论】:

【参考方案1】:

有几种方法可以在 Windows 上“使用”skia。这些方法在您 skia 文件夹中 skia\src\views\win 的 SkOSWindow_win.cpp 中进行了描述。

例如:

    您可以像在函数 SkOSWindow::attachGL

    中那样将 OpenGL 视口附加到您的窗口
    HDC dc = GetDC((HWND)fHWND);
    if (NULL == fHGLRC) 
        fHGLRC = SkCreateWGLContext(dc, msaaSampleCount,
            kGLPreferCompatibilityProfile_SkWGLContextRequest);
        if (NULL == fHGLRC) 
            return false;
        
        glClearStencil(0);
        glClearColor(0, 0, 0, 0);
        glStencilMask(0xffffffff);
        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    
    if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) 
        // use DescribePixelFormat to get the stencil bit depth.
        int pixelFormat = GetPixelFormat(dc);
        PIXELFORMATDESCRIPTOR pfd;
        DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
        info->fStencilBits = pfd.cStencilBits;
    
        // Get sample count if the MSAA WGL extension is present
        SkWGLExtensions extensions;
        if (extensions.hasExtension(dc, "WGL_ARB_multisample")) 
            static const int kSampleCountAttr = SK_WGL_SAMPLES;
            extensions.getPixelFormatAttribiv(dc,
                pixelFormat,
                0,
                1,
                &kSampleCountAttr,
                &info->fSampleCount);
        
        else 
            info->fSampleCount = 0;
        
    
        glViewport(0, 0,
            SkScalarRoundToInt(this->width()),
            SkScalarRoundToInt(this->height()));
        return true;
    
    

    您可以像 SkOSWindow::doPaint 中所做的那样,通过 BitBlt 操作将 SkCanvas 的内容复制到 HDC

    HDC hdc = (HDC)ctx;
    const SkBitmap& bitmap = this->getBitmap();
    
    BITMAPINFO bmi;
    memset(&bmi, 0, sizeof(bmi));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = bitmap.width();
    bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = 0;
    
    //
    // Do the SetDIBitsToDevice.
    //
    // TODO(wjmaclean):
    //       Fix this call to handle SkBitmaps that have rowBytes != width,
    //       i.e. may have padding at the end of lines. The SkASSERT below
    //       may be ignored by builds, and the only obviously safe option
    //       seems to be to copy the bitmap to a temporary (contiguous)
    //       buffer before passing to SetDIBitsToDevice().
    SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
    bitmap.lockPixels();
    int ret = SetDIBitsToDevice(hdc,
        0, 0,
        bitmap.width(), bitmap.height(),
        0, 0,
        0, bitmap.height(),
        bitmap.getPixels(),
        &bmi,
        DIB_RGB_COLORS);
    (void)ret; // we're ignoring potential failures for now.
    bitmap.unlockPixels();
    

【讨论】:

我认为解决方案 2 是最好的方法。 这取决于你想要得到什么。 #2 产生可预测的渲染结果并且更健壮,但不使用 OpenGL,因此速度显着变慢。

以上是关于Windows 上的 SKIA 渲染(HDC 的 SkCanvas)的主要内容,如果未能解决你的问题,请参考以下文章

为啥窗户上的skia效率低下

Skia 或 Direct2D 如何使用 GPU 渲染线条或多边形?

Skia GPU加速能使Android系统的Webkit渲染获得多少收益

Skia深入分析

Skia深入分析

三星 Galaxy S3 上的原生窗口渲染问题