summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-12-03 11:39:01 +0100
committerLuboš Luňák <l.lunak@collabora.com>2019-12-06 14:25:30 +0100
commit5b667d771de65167e269bb145b888eabbc7fdedd (patch)
treee87eb59c423c19dbce1f3eddc6d0790b586811d0
parent8b94f29ee623a28c5225b904829e04c6b83a89a5 (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>
-rw-r--r--vcl/inc/opengl/win/gdiimpl.hxx3
-rw-r--r--vcl/inc/opengl/win/winlayout.hxx2
-rw-r--r--vcl/inc/skia/gdiimpl.hxx2
-rw-r--r--vcl/inc/skia/win/gdiimpl.hxx19
-rw-r--r--vcl/inc/skia/win/winlayout.hxx8
-rw-r--r--vcl/inc/win/salgdi.h8
-rw-r--r--vcl/inc/win/winlayout.hxx2
-rw-r--r--vcl/opengl/win/winlayout.cxx9
-rw-r--r--vcl/skia/gdiimpl.cxx10
-rw-r--r--vcl/skia/win/gdiimpl.cxx52
-rw-r--r--vcl/skia/win/winlayout.cxx27
-rw-r--r--vcl/win/gdi/winlayout.cxx4
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);