Kaydet (Commit) 80d0b291 authored tarafından Tomaž Vajngerl's avatar Tomaž Vajngerl

opengl: use packed texture atlas for glyph cache in win. backend

Change-Id: I6a627699d49bad47213788877fa3947ad2ef83f4
üst 40e9ed91
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#ifndef INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H #ifndef INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
#define INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H #define INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
#include <vcl/opengl/OpenGLHelper.hxx>
#include <o3tl/make_unique.hxx> #include <o3tl/make_unique.hxx>
#include "opengl/texture.hxx" #include "opengl/texture.hxx"
#include <memory> #include <memory>
...@@ -34,10 +36,10 @@ struct AccumulatedTexturesEntry ...@@ -34,10 +36,10 @@ struct AccumulatedTexturesEntry
: maTexture(rTexture) : maTexture(rTexture)
{} {}
void insert(const SalColor& aColor, const SalTwoRect& r2Rect) void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
{ {
TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor]; TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor];
maTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false); rTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false);
GLfloat nX1 = r2Rect.mnDestX; GLfloat nX1 = r2Rect.mnDestX;
GLfloat nY1 = r2Rect.mnDestY; GLfloat nY1 = r2Rect.mnDestY;
...@@ -86,19 +88,18 @@ public: ...@@ -86,19 +88,18 @@ public:
maEntries.clear(); maEntries.clear();
} }
void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect) void insert(OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
{ {
GLuint nTextureId = rTexture.Id(); GLuint nTextureId = rTexture.Id();
auto iterator = maEntries.find(nTextureId); if (maEntries.find(nTextureId) == maEntries.end())
if (iterator == maEntries.end())
{ {
maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(rTexture); OpenGLTexture aWholeTexture(rTexture.GetWholeTexture());
maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(aWholeTexture);
} }
std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId]; std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId];
rEntry->insert(aColor, r2Rect); rEntry->insert(rTexture, aColor, r2Rect);
} }
AccumulatedTexturesMap& getAccumulatedTexturesMap() AccumulatedTexturesMap& getAccumulatedTexturesMap()
......
...@@ -96,7 +96,7 @@ private: ...@@ -96,7 +96,7 @@ private:
public: public:
OpenGLTexture(); OpenGLTexture();
OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber = 0); OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber);
OpenGLTexture( int nWidth, int nHeight, bool bAllocate = true ); OpenGLTexture( int nWidth, int nHeight, bool bAllocate = true );
OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ); OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData );
...@@ -113,13 +113,15 @@ public: ...@@ -113,13 +113,15 @@ public:
void GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const; void GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const;
void GetWholeCoord( GLfloat* pCoord ) const; void GetWholeCoord( GLfloat* pCoord ) const;
OpenGLTexture GetWholeTexture();
void Bind(); void Bind();
void Unbind(); void Unbind();
void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ); void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData );
GLuint AddStencil(); GLuint AddStencil();
GLuint StencilId() const; GLuint StencilId() const;
bool CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
void SaveToFile(const OUString& rFileName); void SaveToFile(const OUString& rFileName);
GLenum GetFilter() const; GLenum GetFilter() const;
......
...@@ -147,7 +147,7 @@ public: ...@@ -147,7 +147,7 @@ public:
void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect ); void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect );
void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect ); void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect );
void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect ); void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect );
void DeferredTextDraw(const OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry); void DeferredTextDraw(OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
void FlushDeferredDrawing(bool bInDraw = false); void FlushDeferredDrawing(bool bInDraw = false);
public: public:
......
...@@ -172,11 +172,16 @@ public: ...@@ -172,11 +172,16 @@ public:
SalTwoRect getTwoRect() { return maRects; } SalTwoRect getTwoRect() { return maRects; }
Size getBitmapSize() { return Size(maRects.mnSrcWidth, maRects.mnSrcHeight); }
/// Reset the DC with the defined color. /// Reset the DC with the defined color.
void fill(sal_uInt32 color); void fill(sal_uInt32 color);
/// Obtain the texture; the caller must delete it after use. /// Obtain the texture; the caller must delete it after use.
OpenGLTexture* getTexture(); OpenGLTexture* getTexture();
/// Copy bitmap data to the texture. Texutre must be initialized and the correct size to hold the bitmap.
bool copyToTexture(OpenGLTexture& aTexture);
}; };
class WinSalGraphics : public SalGraphics class WinSalGraphics : public SalGraphics
......
...@@ -1669,7 +1669,7 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor, ...@@ -1669,7 +1669,7 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor,
mpProgram->Clean(); mpProgram->Clean();
} }
void OpenGLSalGraphicsImpl::DeferredTextDraw(const OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry) void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
{ {
mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry); mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry);
} }
...@@ -1682,6 +1682,8 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw) ...@@ -1682,6 +1682,8 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
if (!bIsInDraw) if (!bIsInDraw)
PreDraw(); PreDraw();
VCL_GL_INFO("FlushDeferredDrawing");
OpenGLZone aZone; OpenGLZone aZone;
#if 0 // Draw a background rect under text for debugging - same color shows text from the same texture #if 0 // Draw a background rect under text for debugging - same color shows text from the same texture
......
...@@ -373,26 +373,31 @@ template <> ...@@ -373,26 +373,31 @@ template <>
void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted) const void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted) const
{ {
VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
VCL_GL_INFO(" With 2Rect Src [" << rPosAry.mnSrcX << ", " << rPosAry.mnSrcY << "] wh (" << rPosAry.mnSrcWidth << ", " << rPosAry.mnSrcHeight << ")");
VCL_GL_INFO(" With 2Rect Dest [" << rPosAry.mnDestX << ", " << rPosAry.mnDestY << "] wh (" << rPosAry.mnDestWidth << ", " << rPosAry.mnDestHeight << ")");
GLfloat x1 = 0.0f; GLfloat x1 = 0.0f;
GLfloat x2 = 0.0f; GLfloat x2 = 0.0f;
GLfloat y1 = 0.0f; GLfloat y1 = 0.0f;
GLfloat y2 = 0.0f; GLfloat y2 = 0.0f;
double fTextureWidth(mpImpl->mnWidth);
double fTextureHeight(mpImpl->mnHeight);
if (mpImpl) if (mpImpl)
{ {
x1 = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth; x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth;
x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth; x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth;
if (bInverted) if (bInverted)
{ {
y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
} }
else else
{ {
y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
} }
} }
...@@ -433,6 +438,11 @@ void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const ...@@ -433,6 +438,11 @@ void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
} }
} }
OpenGLTexture OpenGLTexture::GetWholeTexture()
{
return OpenGLTexture(mpImpl, Rectangle(Point(0, 0), Size(mpImpl->mnWidth, mpImpl->mnHeight)), -1);
}
GLenum OpenGLTexture::GetFilter() const GLenum OpenGLTexture::GetFilter() const
{ {
if( mpImpl ) if( mpImpl )
...@@ -440,6 +450,17 @@ GLenum OpenGLTexture::GetFilter() const ...@@ -440,6 +450,17 @@ GLenum OpenGLTexture::GetFilter() const
return GL_NEAREST; return GL_NEAREST;
} }
bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
{
if (!pData || mpImpl == nullptr)
return false;
int nX = maRect.Left();
int nY = maRect.Top();
return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData);
}
void OpenGLTexture::SetFilter( GLenum nFilter ) void OpenGLTexture::SetFilter( GLenum nFilter )
{ {
if( mpImpl ) if( mpImpl )
......
...@@ -591,6 +591,14 @@ OpenGLTexture* OpenGLCompatibleDC::getTexture() ...@@ -591,6 +591,14 @@ OpenGLTexture* OpenGLCompatibleDC::getTexture()
return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData)); return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
} }
bool OpenGLCompatibleDC::copyToTexture(OpenGLTexture& aTexture)
{
if (!mpImpl)
return false;
return aTexture.CopyData(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
}
WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider): WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
mhLocalDC(0), mhLocalDC(0),
mbPrinter(eType == WinSalGraphics::PRINTER), mbPrinter(eType == WinSalGraphics::PRINTER),
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <opengl/texture.hxx> #include <opengl/texture.hxx>
#include <opengl/win/gdiimpl.hxx> #include <opengl/win/gdiimpl.hxx>
#include "opengl/PackedTextureAtlas.hxx"
#include <vcl/opengl/OpenGLHelper.hxx> #include <vcl/opengl/OpenGLHelper.hxx>
#include <win/salgdi.h> #include <win/salgdi.h>
#include <win/saldata.hxx> #include <win/saldata.hxx>
...@@ -74,13 +76,11 @@ const int GLYPH_SPACE_RATIO = 8; ...@@ -74,13 +76,11 @@ const int GLYPH_SPACE_RATIO = 8;
const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2; const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2;
} }
struct OpenGLGlyphCacheChunk struct OpenGLGlyphDrawElement
{ {
int mnFirstGlyph; // Must be int to handle non-BMP code points when mbRealGlyphIndices is false Rectangle maLocation;
int mnGlyphCount; int maLeftOverhangs;
std::vector<Rectangle> maLocation; OpenGLTexture maTexture;
std::vector<int> maLeftOverhangs;
std::shared_ptr<OpenGLTexture> mpTexture;
int mnBaselineOffset; int mnBaselineOffset;
int mnHeight; int mnHeight;
bool mbVertical; bool mbVertical;
...@@ -97,6 +97,41 @@ struct OpenGLGlyphCacheChunk ...@@ -97,6 +97,41 @@ struct OpenGLGlyphCacheChunk
} }
}; };
class GlyphCache
{
private:
static PackedTextureAtlasManager sPackedTextureAtlas;
std::unordered_map<int, OpenGLGlyphDrawElement> maOpenGLTextureCache;
public:
GlyphCache()
{}
void ReserveTextureSpace(OpenGLGlyphDrawElement& rElement, int nWidth, int nHeight)
{
rElement.maTexture = sPackedTextureAtlas.Reserve(nWidth, nHeight);
}
void PutDrawElementInCache(const OpenGLGlyphDrawElement& rElement, int nGlyphIndex)
{
assert(!IsGlyphCached(nGlyphIndex));
maOpenGLTextureCache[nGlyphIndex] = OpenGLGlyphDrawElement(rElement);
}
OpenGLGlyphDrawElement& GetDrawElement(int nGlyphIndex)
{
assert(IsGlyphCached(nGlyphIndex));
return maOpenGLTextureCache[nGlyphIndex];
}
bool IsGlyphCached(int nGlyphIndex)
{
return maOpenGLTextureCache.find(nGlyphIndex) != maOpenGLTextureCache.end();
}
};
PackedTextureAtlasManager GlyphCache::sPackedTextureAtlas(2048, 2048);
// win32 specific physical font instance // win32 specific physical font instance
class WinFontInstance : public LogicalFontInstance class WinFontInstance : public LogicalFontInstance
{ {
...@@ -122,7 +157,6 @@ public: ...@@ -122,7 +157,6 @@ public:
{ return maScriptCache; } { return maScriptCache; }
private: private:
mutable SCRIPT_CACHE maScriptCache; mutable SCRIPT_CACHE maScriptCache;
std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache;
public: public:
int GetCachedGlyphWidth( int nCharCode ) const; int GetCachedGlyphWidth( int nCharCode ) const;
...@@ -136,9 +170,15 @@ public: ...@@ -136,9 +170,15 @@ public:
demo_atlas_t* mpGLyphyAtlas; demo_atlas_t* mpGLyphyAtlas;
demo_font_t* mpGLyphyFont; demo_font_t* mpGLyphyFont;
bool GlyphIsCached(int nGlyphIndex) const; private:
bool AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics); GlyphCache maGlyphCache;
const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const; public:
bool CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
GlyphCache& GetGlyphCache()
{
return maGlyphCache;
}
private: private:
IntMap maWidthMap; IntMap maWidthMap;
...@@ -246,96 +286,6 @@ private: ...@@ -246,96 +286,6 @@ private:
HDC mhDC; HDC mhDC;
}; };
#ifdef SAL_LOG_INFO
namespace {
char ColorFor(COLORREF aColor)
{
if (aColor == RGB(0xFF, 0xFF, 0xFF))
return ' ';
else if (aColor == RGB(0x00, 0x00, 0x00))
return 'X';
return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3);
}
void DumpGlyphBitmap(HDC hDC, const OpenGLGlyphCacheChunk& rChunk)
{
HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP));
if (hBitmap == NULL)
{
SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError()));
return;
}
BITMAP aBitmap;
if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap))
{
SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError()));
return;
}
SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":");
std::ostringstream sLine("\n", std::ios_base::ate);
std::ostringstream sScale;
long nPrintWidth = std::min(125l, aBitmap.bmWidth);
for (long y = 0; y < aBitmap.bmHeight; y++)
{
if (y == rChunk.mnBaselineOffset + rChunk.getExtraOffset())
sLine << "--------------------------\n";
long n = 0;
for (long x = 0; x < nPrintWidth; x++)
{
// delimit.
for (size_t i = 0; i < rChunk.maLocation.size(); ++i)
{
if (x == rChunk.maLocation[i].Right())
{
n = 0;
sLine << '|';
if (y == 0)
sScale << ' ';
break;
}
}
sLine << ColorFor(GetPixel(hDC, x, y));
if (y == 0)
sScale << (n++ % 10);
}
sLine << "\n";
}
sLine << sScale.str();
SAL_INFO("vcl.gdi.opengl", sLine.str());
}
} // anonymous namespace
#endif // SAL_LOG_INFO
template< typename charT, typename traits >
inline std::basic_ostream<charT, traits> & operator <<(
std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache )
{
stream << "{";
for (auto i = rCache.cbegin(); i != rCache.cend(); ++i)
{
stream << "[" << i->mnFirstGlyph;
if (i->mnGlyphCount > 1)
stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1);
stream << "]";
if (i+1 != rCache.cend())
{
stream << ",";
assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph);
}
}
return stream << "}";
}
inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth ) inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth )
{ {
maWidthMap[ nCharCode ] = nCharWidth; maWidthMap[ nCharCode ] = nCharWidth;
...@@ -349,60 +299,16 @@ inline int WinFontInstance::GetCachedGlyphWidth( int nCharCode ) const ...@@ -349,60 +299,16 @@ inline int WinFontInstance::GetCachedGlyphWidth( int nCharCode ) const
return it->second; return it->second;
} }
bool WinFontInstance::GlyphIsCached(int nGlyphIndex) const bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
{ {
if (nGlyphIndex == DROPPED_OUTGLYPH) if (nGlyphIndex == DROPPED_OUTGLYPH)
return true; return true;
for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++) OpenGLGlyphDrawElement aElement;
if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph && aElement.mbRealGlyphIndices = bRealGlyphIndices;
nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount)
return true;
return false;
}
bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
{
const int DEFAULT_CHUNK_SIZE = 40;
if (nGlyphIndex == DROPPED_OUTGLYPH)
return true;
SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); std::vector<uint32_t> aCodePointsOrGlyphIndices(1);
aCodePointsOrGlyphIndices[0] = nGlyphIndex;
auto n = maOpenGLGlyphCache.begin();
while (n != maOpenGLGlyphCache.end() &&
nGlyphIndex > n->mnFirstGlyph)
++n;
assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph);
int nCount = DEFAULT_CHUNK_SIZE;
if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph)
nCount = n->mnFirstGlyph - nGlyphIndex;
if (nCount < DEFAULT_CHUNK_SIZE)
{
if (n == maOpenGLGlyphCache.begin())
{
nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
}
else
{
nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount,
n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
}
nCount = n->mnFirstGlyph - nGlyphIndex;
}
OpenGLGlyphCacheChunk aChunk;
aChunk.mnFirstGlyph = nGlyphIndex;
aChunk.mnGlyphCount = nCount;
aChunk.mbRealGlyphIndices = bRealGlyphIndices;
std::vector<uint32_t> aCodePointsOrGlyphIndices(nCount);
for (int i = 0; i < nCount; i++)
aCodePointsOrGlyphIndices[i] = nGlyphIndex + i;
HDC hDC = CreateCompatibleDC(rLayout.mhDC); HDC hDC = CreateCompatibleDC(rLayout.mhDC);
if (hDC == NULL) if (hDC == NULL)
...@@ -441,7 +347,7 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, ...@@ -441,7 +347,7 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
return false; return false;
} }
} }
std::vector<WORD> aGlyphIndices(nCount); std::vector<WORD> aGlyphIndices(1);
// Fetch the ink boxes and calculate the size of the atlas. // Fetch the ink boxes and calculate the size of the atlas.
if (!bRealGlyphIndices) if (!bRealGlyphIndices)
{ {
...@@ -453,69 +359,60 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, ...@@ -453,69 +359,60 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
} }
else else
{ {
for (int i = 0; i < nCount; i++) aGlyphIndices[0] = aCodePointsOrGlyphIndices[0];
aGlyphIndices[i] = aCodePointsOrGlyphIndices[i];
} }
Rectangle bounds(0, 0, 0, 0); Rectangle bounds(0, 0, 0, 0);
auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + nCount); auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + 1);
for (auto &box : aInkBoxes) for (auto &box : aInkBoxes)
bounds.Union(box + Point(bounds.Right(), 0)); bounds.Union(box + Point(bounds.Right(), 0));
// bounds.Top() is the offset from the baseline at (0,0) to the top of the // bounds.Top() is the offset from the baseline at (0,0) to the top of the
// inkbox. // inkbox.
aChunk.mnBaselineOffset = -bounds.Top(); aElement.mnBaselineOffset = -bounds.Top();
aChunk.mnHeight = bounds.getHeight(); aElement.mnHeight = bounds.getHeight();
aChunk.mbVertical = false; aElement.mbVertical = false;
aChunk.maLeftOverhangs.resize(nCount);
aChunk.maLocation.resize(nCount);
// Try hard to avoid overlap as we want to be able to use // Try hard to avoid overlap as we want to be able to use
// individual rectangles for each glyph. The ABC widths don't // individual rectangles for each glyph. The ABC widths don't
// take anti-aliasing into consideration. Let's hope that leaving // take anti-aliasing into consideration. Let's hope that leaving
// "extra" space between glyphs will help. // "extra" space between glyphs will help.
std::vector<float> aGlyphAdv(nCount); // offsets between glyphs std::vector<float> aGlyphAdv(1); // offsets between glyphs
std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(nCount, DWRITE_GLYPH_OFFSET{0.0f,0.0f}); std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(1, DWRITE_GLYPH_OFFSET{0.0f, 0.0f});
std::vector<int> aEnds(nCount); // end of each glyph box std::vector<int> aEnds(1); // end of each glyph box
float totWidth = 0; float totWidth = 0;
for (int i = 0; i < nCount; ++i)
{ {
int overhang = aInkBoxes[i].Left(); int overhang = aInkBoxes[0].Left();
int blackWidth = aInkBoxes[i].getWidth(); // width of non-AA pixels int blackWidth = aInkBoxes[0].getWidth(); // width of non-AA pixels
aChunk.maLeftOverhangs[i] = overhang; aElement.maLeftOverhangs = overhang;
aGlyphAdv[i] = blackWidth + aChunk.getExtraSpace(); aGlyphAdv[0] = blackWidth + aElement.getExtraSpace();
aGlyphOffset[i].advanceOffset = -overhang; aGlyphOffset[0].advanceOffset = -overhang;
totWidth += aGlyphAdv[i]; totWidth += aGlyphAdv[0];
aEnds[i] = totWidth; aEnds[0] = totWidth;
} }
// Leave extra space also at top and bottom // Leave extra space also at top and bottom
int nBitmapWidth = totWidth, int nBitmapWidth = totWidth;
nBitmapHeight = bounds.getHeight() + aChunk.getExtraSpace(); int nBitmapHeight = bounds.getHeight() + aElement.getExtraSpace();
aChunk.maLocation.resize(nCount);
UINT nPos = 0; UINT nPos = 0;
for (int i = 0; i < nCount; i++)
// FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
if (aElement.mbVertical)
{ {
// FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !? aElement.maLocation.Left() = 0;
if (aChunk.mbVertical) aElement.maLocation.Right() = nBitmapWidth;
{ aElement.maLocation.Top() = nPos;
aChunk.maLocation[i].Left() = 0; aElement.maLocation.Bottom() = nPos + aGlyphAdv[0] + aElement.maLeftOverhangs;
aChunk.maLocation[i].Right() = nBitmapWidth; }
aChunk.maLocation[i].Top() = nPos; else
aChunk.maLocation[i].Bottom() = nPos + aGlyphAdv[i] + aChunk.maLeftOverhangs[i]; {
} aElement.maLocation.Left() = nPos;
else aElement.maLocation.Right() = aEnds[0];
{ aElement.maLocation.Top() = 0;
aChunk.maLocation[i].Left() = nPos; aElement.maLocation.Bottom() = bounds.getHeight() + aElement.getExtraSpace();
aChunk.maLocation[i].Right() = aEnds[i];
aChunk.maLocation[i].Top() = 0;
aChunk.maLocation[i].Bottom() = bounds.getHeight() + aChunk.getExtraSpace();
}
nPos = aEnds[i];
} }
nPos = aEnds[0];
OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight); OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
...@@ -536,11 +433,15 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, ...@@ -536,11 +433,15 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
return false; return false;
} }
D2D1_POINT_2F baseline = { aChunk.getExtraOffset(), aChunk.getExtraOffset() + aChunk.mnBaselineOffset }; D2D1_POINT_2F baseline = {
aElement.getExtraOffset(),
aElement.getExtraOffset() + aElement.mnBaselineOffset
};
DWRITE_GLYPH_RUN glyphs = { DWRITE_GLYPH_RUN glyphs = {
pTxt->GetFontFace(), pTxt->GetFontFace(),
pTxt->GetEmHeight(), pTxt->GetEmHeight(),
nCount, 1,
aGlyphIndices.data(), aGlyphIndices.data(),
aGlyphAdv.data(), aGlyphAdv.data(),
aGlyphOffset.data(), aGlyphOffset.data(),
...@@ -550,11 +451,11 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, ...@@ -550,11 +451,11 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
pRT->BeginDraw(); pRT->BeginDraw();
pRT->DrawGlyphRun(baseline, &glyphs, pBrush); pRT->DrawGlyphRun(baseline, &glyphs, pBrush);
HRESULT hr = pRT->EndDraw(); HRESULT hResult = pRT->EndDraw();
pBrush->Release(); pBrush->Release();
switch (hr) switch (hResult)
{ {
case S_OK: case S_OK:
break; break;
...@@ -571,25 +472,14 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, ...@@ -571,25 +472,14 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
pTxt->ReleaseFont(); pTxt->ReleaseFont();
aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture()); maGlyphCache.ReserveTextureSpace(aElement, nBitmapWidth, nBitmapHeight);
aDC.copyToTexture(aElement.maTexture);
maOpenGLGlyphCache.insert(n, aChunk); maGlyphCache.PutDrawElementInCache(aElement, nGlyphIndex);
SelectFont(aDC.getCompatibleHDC(), hOrigFont); SelectFont(aDC.getCompatibleHDC(), hOrigFont);
if (hNonAntialiasedFont != NULL) if (hNonAntialiasedFont != NULL)
DeleteObject(hNonAntialiasedFont); DeleteObject(hNonAntialiasedFont);
#ifdef SAL_LOG_INFO
SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache);
DumpGlyphBitmap(aDC.getCompatibleHDC(), aChunk);
{
std::ostringstream sLine;
for (int i = 0; i < nCount; i++)
sLine << aGlyphAdv[i] << ":" << aChunk.maLeftOverhangs[i] << " ";
SAL_INFO("vcl.gdi.opengl", "DX:offset : " << sLine.str());
}
#endif
return true; return true;
} }
...@@ -1288,16 +1178,6 @@ void SimpleWinLayout::Simplify( bool /*bIsBase*/ ) ...@@ -1288,16 +1178,6 @@ void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
mnWidth = mnBaseAdv = 0; mnWidth = mnBaseAdv = 0;
} }
const OpenGLGlyphCacheChunk& WinFontInstance::GetCachedGlyphChunkFor(int nGlyphIndex) const
{
auto i = maOpenGLGlyphCache.cbegin();
while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount)
++i;
assert(i != maOpenGLGlyphCache.cend());
assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount);
return *i;
}
void WinFontInstance::setupGLyphy(HDC hDC) void WinFontInstance::setupGLyphy(HDC hDC)
{ {
if (mbGLyphySetupCalled) if (mbGLyphySetupCalled)
...@@ -1531,11 +1411,9 @@ bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const ...@@ -1531,11 +1411,9 @@ bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const
nCodePoint = mpOutGlyphs[i]; nCodePoint = mpOutGlyphs[i];
} }
if (mrWinFontEntry.GlyphIsCached(nCodePoint)) if (!mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
continue; assert(mrWinFontEntry.CacheGlyphToAtlas(false, nCodePoint, *this, rGraphics));
if (!mrWinFontEntry.AddChunkOfGlyphs(false, nCodePoint, *this, rGraphics))
return false;
} }
return true; return true;
...@@ -1577,18 +1455,16 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const ...@@ -1577,18 +1455,16 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
nCodePoint = mpOutGlyphs[i]; nCodePoint = mpOutGlyphs[i];
} }
assert(mrWinFontEntry.GlyphIsCached(nCodePoint)); OpenGLGlyphDrawElement& rElement(mrWinFontEntry.GetGlyphCache().GetDrawElement(nCodePoint));
OpenGLTexture& rTexture = rElement.maTexture;
const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(nCodePoint); SalTwoRect a2Rects(0, 0,
const int n = nCodePoint - rChunk.mnFirstGlyph; rTexture.GetWidth(), rTexture.GetHeight(),
nAdvance + aPos.X() - rElement.getExtraOffset() + rElement.maLeftOverhangs,
aPos.Y() - rElement.mnBaselineOffset - rElement.getExtraOffset(),
rTexture.GetWidth(), rTexture.GetHeight());
SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
nAdvance + aPos.X() - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n],
aPos.Y() - rChunk.mnBaselineOffset - rChunk.getExtraOffset(),
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
nAdvance += mpGlyphAdvances[i]; nAdvance += mpGlyphAdvances[i];
} }
...@@ -2801,11 +2677,9 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const ...@@ -2801,11 +2677,9 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
{ {
for (int i = 0; i < mnGlyphCount; i++) for (int i = 0; i < mnGlyphCount; i++)
{ {
if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])) int nCodePoint = mpOutGlyphs[i];
continue; if (!mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
assert(mrWinFontEntry.CacheGlyphToAtlas(true, nCodePoint, *this, rGraphics));
if (!mrWinFontEntry.AddChunkOfGlyphs(true, mpOutGlyphs[i], *this, rGraphics))
return false;
} }
} }
...@@ -3093,28 +2967,30 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons ...@@ -3093,28 +2967,30 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
continue; continue;
assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])); OpenGLGlyphDrawElement& rElement = mrWinFontEntry.GetGlyphCache().GetDrawElement(mpOutGlyphs[i]);
OpenGLTexture& rTexture = rElement.maTexture;
const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]);
const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph;
if (rChunk.mbVertical) if (rElement.mbVertical)
{ {
SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), SalTwoRect a2Rects(0, 0,
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), rTexture.GetWidth(), rTexture.GetHeight(),
aPos.X() + rChunk.maLeftOverhangs[n], nAdvance + aPos.Y(), aPos.X() + rElement.maLeftOverhangs,
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? nAdvance + aPos.Y(),
pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects); rTexture.GetWidth(), rTexture.GetHeight());
pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
} }
else else
{ {
SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), SalTwoRect a2Rects(0, 0,
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), rTexture.GetWidth(), rTexture.GetHeight(),
nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n], nAdvance + aPos.X() + mpGlyphOffsets[i].du - rElement.getExtraOffset() + rElement.maLeftOverhangs,
aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnBaselineOffset - rChunk.getExtraOffset(), aPos.Y() + mpGlyphOffsets[i].dv - rElement.mnBaselineOffset - rElement.getExtraOffset(),
rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? rTexture.GetWidth(), rTexture.GetHeight());
pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
} }
nAdvance += pGlyphWidths[i]; nAdvance += pGlyphWidths[i];
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment