Hi, I have a huge table of text with millions of rows and thousands of columns. I am trying to use skia to render the table.
My approach - I do listen to the change in the content offset of NSScrollview and redraw my metal view with the current content offset.
As it takes more time to render those text, I did draw them into tiles of 256*256 pixels in the raster surface in multithread and stored the images in the surfaceList, and stitched them together in the GPU context.
void SkiaRenderer::drawInOffScreenSurfaceAndAddInBuffer(std::string key, int width, int height) {
SkImageInfo imgInfo = SkImageInfo::Make(width, height, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);
imgInfo.computeByteSize(imgInfo.minRowBytes());
sk_sp<SkSurface> newSurface = SkSurface::MakeRaster(imgInfo);
SkCanvas* canvas = newSurface->getCanvas();
int starX = surfaceList[key]->startX;
int starY = surfaceList[key]->startY;
drawInCanvas(canvas, starX, starY, width, height, 1);
mtx->lock();
if (surfaceList[key] != nullptr) {
surfaceList[key]->count++;
surfaceList[key]->image = newSurface->makeImageSnapshot();
surfaceList[key]->isAvailable = false;
}
mtx->unlock();
}
static void drawInCanvas(SkCanvas* canvas, int xOffset, int yOffset, int width, int height, float scale) {
SkPaint paint = SkPaint();
paint.setColor(SkColorSetRGB(0, 0, 25));
paint.setStyle(SkPaint::kFill_Style);
SkFontStyle fontstyle = SkFontStyle::BoldItalic();
sk_sp<SkTypeface> typeface = SkTypeface::MakeFromName("Arial", fontstyle);
SkFont font = SkFont();
font.setSize(15*scale);
font.setTypeface(typeface);
float y = 0, colWidth = 80, rowHt = 18;
int startRow = yOffset/rowHt, startCol = xOffset/colWidth, endRow = (yOffset+height)/rowHt+1, endCol = (xOffset+width)/colWidth+1;
y = ((startRow*rowHt)-yOffset)*scale;
colWidth *= scale;
rowHt *= scale;
for(int i=startRow; i<=endRow; i++) {
float x = (((colWidth/scale)*startCol)-xOffset)*scale;
for(int j=startCol; j<=endCol; j++) {
std::string str = "R"+std::to_string(i)+"C"+std::to_string(j);
sk_sp<SkTextBlob> textBlob = SkTextBlob::MakeFromText(str.c_str(), str.size(), font);
canvas->drawTextBlob(textBlob, x, y, paint);
canvas->drawLine(x, y, x+colWidth, y, paint);
canvas->drawLine(x+colWidth, y, x+colWidth, y+rowHt, paint);
x += colWidth;
}
y += rowHt;
}
}
Stitching the tiles together here
bool SkiaRenderer::drawActiveViewport(GrRecordingContext* context, sk_sp<SkSurface> surface, int xoffSet, int yoffSet, int width, int height, int scale, bool isEnd) {
SkCanvas* canvas = surface->getCanvas();
canvas->drawColor(SK_ColorCYAN);
canvas->scale(scale, scale);
canvas->clipRect(SkRect::Make(SkISize::Make(width, height)));
int startX = xoffSet/maxSize;
int endX = (xoffSet+width)/maxSize+1;
int startY = int(yoffSet/maxSize);
int endY = ((yoffSet+(height))/maxSize)+1;
bool complete = true;
for(int i=startX; i<=endX; i++) {
for(int j=startY; j<=endY; j++) {
std::string key = "R"+std::to_string(i)+"C"+std::to_string(j);
bool isAvailable = surfaceList[key] != nullptr && !surfaceList[key]->isAvailable;
if(isAvailable) {
canvas->drawImage(surfaceList[key]->image, i*maxSize-xoffSet, j*maxSize-yoffSet);
}
complete &= isAvailable;
}
}
return complete;
}
But still, I could see blanks as the user scrolls fast(rendering text takes much time and tiles are not created)
Plz do point me in the right direction to render text fastly
Yes, I cache the images drawn on the raster surface, Once the images are cached I don't see the blanks. As there are millions of rows I couldn't cache all the images. I am using an LRU cache to store the images. If the images are not available on request I see blanks.
Also, I couldn't cache the text blobs or fonts, as there will be different text with a different font in each cell of the table.