diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2019-12-03 11:39:01 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2019-12-06 14:25:30 +0100 |
commit | 5b667d771de65167e269bb145b888eabbc7fdedd (patch) | |
tree | e87eb59c423c19dbce1f3eddc6d0790b586811d0 /vcl | |
parent | 8b94f29ee623a28c5225b904829e04c6b83a89a5 (diff) |
make Skia Windows text rendering use SkImage instead of SkBitmap
This will allow making it GPU-backed, as SkImage can be GPU-backed,
SkBitmap cannot.
Change-Id: I047eefe83741a036d372d39e5fc6a4fa400e6504
Reviewed-on: https://gerrit.libreoffice.org/84559
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/opengl/win/gdiimpl.hxx | 3 | ||||
-rw-r--r-- | vcl/inc/opengl/win/winlayout.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/skia/gdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/skia/win/gdiimpl.hxx | 19 | ||||
-rw-r--r-- | vcl/inc/skia/win/winlayout.hxx | 8 | ||||
-rw-r--r-- | vcl/inc/win/salgdi.h | 8 | ||||
-rw-r--r-- | vcl/inc/win/winlayout.hxx | 2 | ||||
-rw-r--r-- | vcl/opengl/win/winlayout.cxx | 9 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 10 | ||||
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 52 | ||||
-rw-r--r-- | vcl/skia/win/winlayout.cxx | 27 | ||||
-rw-r--r-- | vcl/win/gdi/winlayout.cxx | 4 |
12 files changed, 61 insertions, 85 deletions
diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx index c69795f70bd5..91e55a2ca28f 100644 --- a/vcl/inc/opengl/win/gdiimpl.hxx +++ b/vcl/inc/opengl/win/gdiimpl.hxx @@ -30,7 +30,8 @@ public: // caller must delete OpenGLTexture* getOpenGLTexture(); - virtual bool copyToTexture(Texture& aTexture) override; + /// Copy bitmap data to the texture. Texture must be initialized and the correct size to hold the bitmap. + bool copyToTexture(Texture& aTexture); struct Texture; }; diff --git a/vcl/inc/opengl/win/winlayout.hxx b/vcl/inc/opengl/win/winlayout.hxx index 24c2fc296b2c..cb6449fbd7bc 100644 --- a/vcl/inc/opengl/win/winlayout.hxx +++ b/vcl/inc/opengl/win/winlayout.hxx @@ -32,7 +32,7 @@ struct OpenGLGlobalWinGlyphCache : public GlobalWinGlyphCache PackedTextureAtlasManager maPackedTextureAtlas; - virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) override; + virtual bool AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) override; virtual void Prune() override; }; diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 98edc9156384..e61ee6cfb787 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -237,7 +237,7 @@ protected: // get the height of the device int GetHeight() const { return mProvider ? mProvider->GetHeight() : 1; } - void drawMask(const SalTwoRect& rPosAry, const SkBitmap& rBitmap, Color nMaskColor); + void drawMask(const SalTwoRect& rPosAry, const SkImage& rImage, Color nMaskColor); // When drawing using GPU, rounding errors may result in off-by-one errors, // see https://bugs.chromium.org/p/skia/issues/detail?id=9611 . Compensate for diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index 37c8ad374aa8..003fac2cc65b 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -29,22 +29,20 @@ public: virtual std::unique_ptr<Texture> getAsMaskTexture() override; - virtual bool copyToTexture(Texture& aTexture) override; - virtual bool wantsTextColorWhite() const override { return true; } - SkBitmap getAsBitmap(); - SkBitmap getAsMaskBitmap(); + sk_sp<SkImage> getAsImage(); + sk_sp<SkImage> getAsMaskImage(); struct Texture; }; struct SkiaCompatibleDC::Texture : public CompatibleDC::Texture { - SkBitmap bitmap; // TODO SkBitmap, SkSurface, SkImage? - virtual bool isValid() const { return !bitmap.drawsNothing(); } - virtual int GetWidth() const { return bitmap.width(); } - virtual int GetHeight() const { return bitmap.height(); } + sk_sp<SkImage> image; + virtual bool isValid() const { return image.get(); } + virtual int GetWidth() const { return image->width(); } + virtual int GetHeight() const { return image->height(); } }; class WinSkiaSalGraphicsImpl : public SkiaSalGraphicsImpl, public WinSalGraphicsImplBase @@ -81,8 +79,9 @@ protected: virtual void performFlush() override; }; -typedef std::pair<ControlCacheKey, SkBitmap> SkiaControlCachePair; -typedef o3tl::lru_map<ControlCacheKey, SkBitmap, ControlCacheHashFunction> SkiaControlCacheType; +typedef std::pair<ControlCacheKey, sk_sp<SkImage>> SkiaControlCachePair; +typedef o3tl::lru_map<ControlCacheKey, sk_sp<SkImage>, ControlCacheHashFunction> + SkiaControlCacheType; class SkiaControlsCache { diff --git a/vcl/inc/skia/win/winlayout.hxx b/vcl/inc/skia/win/winlayout.hxx index a577c357b84f..32b2aea266a5 100644 --- a/vcl/inc/skia/win/winlayout.hxx +++ b/vcl/inc/skia/win/winlayout.hxx @@ -26,17 +26,17 @@ struct SkiaGlobalWinGlyphCache : public GlobalWinGlyphCache { - virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) override; + virtual bool AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) override; virtual void NotifyElementUsed(WinGlyphDrawElement& rElement) override; virtual void Prune() override; - // The least recently used SkBitmap order, identified by SkBitmap::getPixels(). - std::vector<void*> mLRUOrder; + // The least recently used SkImage order, identified by SkImage::uniqueID(). + std::vector<uint32_t> mLRUOrder; }; class SkiaWinGlyphCache : public WinGlyphCache { public: - void RemoveTextures(const std::vector<void*>& pixels); + void RemoveTextures(const std::vector<uint32_t>& ids); private: // This class just "adds" RemoveTexture() to the base class, it's never instantiatied. diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index dced53aecfb0..eb0d428cc77f 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -128,9 +128,10 @@ public: HDC getCompatibleHDC() { return mhCompatibleDC; } - SalTwoRect getTwoRect() { return maRects; } + SalTwoRect getTwoRect() const { return maRects; } - Size getBitmapSize() { return Size(maRects.mnSrcWidth, maRects.mnSrcHeight); } + long getBitmapWidth() const { return maRects.mnSrcWidth; } + long getBitmapHeight() const { return maRects.mnSrcHeight; } /// Reset the DC with the defined color. void fill(sal_uInt32 color); @@ -141,9 +142,6 @@ public: /// Obtain the texture in format for WinSalGraphicsImplBase::DrawTextMask(). virtual std::unique_ptr<Texture> getAsMaskTexture() { abort(); }; - /// Copy bitmap data to the texture. Texture must be initialized and the correct size to hold the bitmap. - virtual bool copyToTexture(Texture& /*aTexture*/) { abort(); }; - /// Return true if text glyphs should be drawn as white instead of black. virtual bool wantsTextColorWhite() const { return false; } }; diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 244627c22b6f..d8cdd310b50f 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -65,7 +65,7 @@ struct GlobalWinGlyphCache static GlobalWinGlyphCache * get(); virtual ~GlobalWinGlyphCache() {} - virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) = 0; + virtual bool AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) = 0; virtual void NotifyElementUsed(WinGlyphDrawElement& /*rElement*/) {} virtual void Prune() {} }; diff --git a/vcl/opengl/win/winlayout.cxx b/vcl/opengl/win/winlayout.cxx index 52569682af06..59bf12c25c8c 100644 --- a/vcl/opengl/win/winlayout.cxx +++ b/vcl/opengl/win/winlayout.cxx @@ -11,15 +11,18 @@ #include <opengl/win/gdiimpl.hxx> -bool OpenGLGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, - int nHeight) +bool OpenGLGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) { assert(rElement.maTexture.get() == nullptr); + assert(dynamic_cast<OpenGLCompatibleDC*>(dc)); + OpenGLCompatibleDC* odc = static_cast<OpenGLCompatibleDC*>(dc); OpenGLCompatibleDC::Texture* texture = new OpenGLCompatibleDC::Texture; rElement.maTexture.reset(texture); - texture->texture = maPackedTextureAtlas.Reserve(nWidth, nHeight); + texture->texture = maPackedTextureAtlas.Reserve(dc->getBitmapWidth(), dc->getBitmapHeight()); if (!texture->texture) return false; + if (!odc->copyToTexture(*rElement.maTexture)) + return false; return true; } diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 928015ac5c14..9c8d7c497ba2 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -842,14 +842,16 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& r Color nMaskColor) { assert(dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap)); - drawMask(rPosAry, static_cast<const SkiaSalBitmap&>(rSalBitmap).GetAlphaSkBitmap(), nMaskColor); + sk_sp<SkImage> image + = SkImage::MakeFromBitmap(static_cast<const SkiaSalBitmap&>(rSalBitmap).GetAlphaSkBitmap()); + drawMask(rPosAry, *image, nMaskColor); } -void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SkBitmap& rBitmap, +void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SkImage& rImage, Color nMaskColor) { SkBitmap tmpBitmap; - if (!tmpBitmap.tryAllocN32Pixels(rBitmap.width(), rBitmap.height())) + if (!tmpBitmap.tryAllocN32Pixels(rImage.width(), rImage.height())) abort(); tmpBitmap.eraseColor(toSkColor(nMaskColor)); SkPaint paint; @@ -857,7 +859,7 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SkBitmap& rB // TODO figure out the right blend mode to avoid the temporary bitmap paint.setBlendMode(SkBlendMode::kDstOut); SkCanvas canvas(tmpBitmap); - canvas.drawBitmap(rBitmap, 0, 0, &paint); + canvas.drawImage(&rImage, 0, 0, &paint); drawBitmap(rPosAry, tmpBitmap); } diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index 53979f39aad4..5270a7c3af18 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -91,7 +91,7 @@ bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const& return false; preDraw(); - mSurface->getCanvas()->drawBitmap(iterator->second, nX, nY); + mSurface->getCanvas()->drawImage(iterator->second, nX, nY); postDraw(); return true; } @@ -103,16 +103,16 @@ bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, C assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite)); assert(dynamic_cast<SkiaCompatibleDC*>(&rBlack)); - SkBitmap bitmap = static_cast<SkiaCompatibleDC&>(rWhite).getAsBitmap(); + sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rWhite).getAsImage(); preDraw(); - mSurface->getCanvas()->drawBitmap(bitmap, nX, nY); + mSurface->getCanvas()->drawImage(image, nX, nY); postDraw(); // TODO what is the point of the second texture? (void)rBlack; if (!aControlCacheKey.canCacheControl()) return true; - SkiaControlCachePair pair(aControlCacheKey, std::move(bitmap)); + SkiaControlCachePair pair(aControlCacheKey, std::move(image)); SkiaControlsCache::get().insert(std::move(pair)); return true; } @@ -137,8 +137,8 @@ void WinSkiaSalGraphicsImpl::DeferredTextDraw(const CompatibleDC::Texture* pText // SkiaCompatibleDC::wantsTextColorWhite() ensures the glyph is white. // TODO maybe other black/white in WinFontInstance::CacheGlyphToAtlas() should be swapped. paint.setColorFilter(SkColorFilters::Blend(toSkColor(aMaskColor), SkBlendMode::kModulate)); - mSurface->getCanvas()->drawBitmapRect( - static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap, + mSurface->getCanvas()->drawImageRect( + static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->image, SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight), SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight), @@ -150,7 +150,7 @@ void WinSkiaSalGraphicsImpl::DrawTextMask(CompatibleDC::Texture* pTexture, Color const SalTwoRect& rPosAry) { assert(dynamic_cast<SkiaCompatibleDC::Texture*>(pTexture)); - drawMask(rPosAry, static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap, nMaskColor); + drawMask(rPosAry, *static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->image, nMaskColor); } SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height) @@ -161,11 +161,11 @@ SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int wid std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture() { auto ret = std::make_unique<SkiaCompatibleDC::Texture>(); - ret->bitmap = getAsMaskBitmap(); + ret->image = getAsMaskImage(); return ret; } -SkBitmap SkiaCompatibleDC::getAsMaskBitmap() +sk_sp<SkImage> SkiaCompatibleDC::getAsMaskImage() { // mpData is in the BGRA format, with A unused (and set to 0), and RGB are grey, // so convert it to Skia format, then to 8bit and finally use as alpha mask @@ -192,34 +192,11 @@ SkBitmap SkiaCompatibleDC::getAsMaskBitmap() alpha.setInfo(bitmap8.info().makeColorType(kAlpha_8_SkColorType), bitmap8.rowBytes()); alpha.setPixelRef(sk_ref_sp(bitmap8.pixelRef()), bitmap8.pixelRefOrigin().x(), bitmap8.pixelRefOrigin().y()); - return alpha; + // TODO GPU? + return SkImage::MakeFromBitmap(alpha); } -bool SkiaCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture) -{ - assert(mpImpl); - assert(dynamic_cast<SkiaCompatibleDC::Texture*>(&aTexture)); - SkBitmap tmpBitmap; - if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, - kBGRA_8888_SkColorType, kUnpremul_SkAlphaType), - mpData, maRects.mnSrcWidth * 4)) - abort(); - SkBitmap& bitmap = static_cast<SkiaCompatibleDC::Texture&>(aTexture).bitmap; - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha - SkCanvas canvas(bitmap); - // The data we got is upside-down. - SkMatrix matrix; - matrix.preTranslate(0, maRects.mnSrcHeight); - matrix.setConcat(matrix, SkMatrix::MakeScale(1, -1)); - canvas.concat(matrix); - canvas.drawBitmapRect(tmpBitmap, - SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), - SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), &paint); - return true; -} - -SkBitmap SkiaCompatibleDC::getAsBitmap() +sk_sp<SkImage> SkiaCompatibleDC::getAsImage() { SkBitmap tmpBitmap; if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, @@ -240,7 +217,8 @@ SkBitmap SkiaCompatibleDC::getAsBitmap() canvas.drawBitmapRect(tmpBitmap, SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), &paint); - return bitmap; + // TODO GPU + return SkImage::MakeFromBitmap(bitmap); } SkiaControlsCache::SkiaControlsCache() @@ -252,9 +230,7 @@ SkiaControlCacheType& SkiaControlsCache::get() { SalData* data = GetSalData(); if (!data->m_pSkiaControlsCache) - { data->m_pSkiaControlsCache.reset(new SkiaControlsCache); - } return data->m_pSkiaControlsCache->cache; } diff --git a/vcl/skia/win/winlayout.cxx b/vcl/skia/win/winlayout.cxx index 5b38b0e63f81..e544943b0e3f 100644 --- a/vcl/skia/win/winlayout.cxx +++ b/vcl/skia/win/winlayout.cxx @@ -11,17 +11,16 @@ #include <skia/win/gdiimpl.hxx> -bool SkiaGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, - int nHeight) +bool SkiaGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) { assert(rElement.maTexture.get() == nullptr); + assert(dynamic_cast<SkiaCompatibleDC*>(dc)); + SkiaCompatibleDC* sdc = static_cast<SkiaCompatibleDC*>(dc); SkiaCompatibleDC::Texture* texture = new SkiaCompatibleDC::Texture; rElement.maTexture.reset(texture); - // TODO use something GPU-backed? // TODO is it possible to have an atlas? - if (!texture->bitmap.tryAllocN32Pixels(nWidth, nHeight)) - return false; - mLRUOrder.push_back(texture->bitmap.getPixels()); + texture->image = sdc->getAsImage(); + mLRUOrder.push_back(texture->image->uniqueID()); return true; } @@ -31,10 +30,10 @@ void SkiaGlobalWinGlyphCache::Prune() if (mLRUOrder.size() > MAXSIZE) { size_t toRemove = mLRUOrder.size() - MAXSIZE; - std::vector<void*> pixelsToRemove(mLRUOrder.begin(), mLRUOrder.begin() + toRemove); + std::vector<uint32_t> idsToRemove(mLRUOrder.begin(), mLRUOrder.begin() + toRemove); mLRUOrder.erase(mLRUOrder.begin(), mLRUOrder.begin() + toRemove); for (auto& pWinGlyphCache : maWinGlyphCaches) - static_cast<SkiaWinGlyphCache*>(pWinGlyphCache)->RemoveTextures(pixelsToRemove); + static_cast<SkiaWinGlyphCache*>(pWinGlyphCache)->RemoveTextures(idsToRemove); } } @@ -43,21 +42,21 @@ void SkiaGlobalWinGlyphCache::NotifyElementUsed(WinGlyphDrawElement& rElement) SkiaCompatibleDC::Texture* texture = static_cast<SkiaCompatibleDC::Texture*>(rElement.maTexture.get()); // make the most recently used - auto it = find(mLRUOrder.begin(), mLRUOrder.end(), texture->bitmap.getPixels()); + auto it = find(mLRUOrder.begin(), mLRUOrder.end(), texture->image->uniqueID()); if (it != mLRUOrder.end()) mLRUOrder.erase(it); - mLRUOrder.push_back(texture->bitmap.getPixels()); + mLRUOrder.push_back(texture->image->uniqueID()); } -void SkiaWinGlyphCache::RemoveTextures(const std::vector<void*>& pixelsToRemove) +void SkiaWinGlyphCache::RemoveTextures(const std::vector<uint32_t>& idsToRemove) { auto it = maWinTextureCache.begin(); while (it != maWinTextureCache.end()) { assert(dynamic_cast<SkiaCompatibleDC::Texture*>(it->second.maTexture.get())); - void* pixels = static_cast<SkiaCompatibleDC::Texture*>(it->second.maTexture.get()) - ->bitmap.getPixels(); - if (std::find(pixelsToRemove.begin(), pixelsToRemove.end(), pixels) != pixelsToRemove.end()) + uint32_t id = static_cast<SkiaCompatibleDC::Texture*>(it->second.maTexture.get()) + ->image->uniqueID(); + if (std::find(idsToRemove.begin(), idsToRemove.end(), id) != idsToRemove.end()) it = maWinTextureCache.erase(it); else ++it; diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 842c2f51d77d..e13d6930df64 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -209,9 +209,7 @@ bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, return false; } - if (!GlobalWinGlyphCache::get()->AllocateTexture(aElement, nBitmapWidth, nBitmapHeight)) - return false; - if (!aDC->copyToTexture(*aElement.maTexture)) + if (!GlobalWinGlyphCache::get()->AllocateTexture(aElement, aDC.get())) return false; maWinGlyphCache.PutDrawElementInCache(std::move(aElement), nGlyphIndex); |