Best way to draw 10000 of text in a framw

232 views
Skip to first unread message

cccc

unread,
Sep 1, 2022, 7:05:03 AM9/1/22
to skia-discuss

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

Clark Kent

unread,
Sep 1, 2022, 8:28:20 AM9/1/22
to skia-discuss
do you cache anything?

Clark Kent

unread,
Sep 1, 2022, 8:29:21 AM9/1/22
to skia-discuss
such as caching text blobs, fonts, typefaces, images, ect
Message has been deleted
Message has been deleted

cccc

unread,
Sep 1, 2022, 11:15:07 PM9/1/22
to skia-discuss

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.

Clark Kent

unread,
Sep 2, 2022, 1:08:30 AM9/2/22
to skia-discuss
so, you have...

millions of cells
millions of fonts
millions of text blobs

?

Clark Kent

unread,
Sep 2, 2022, 3:29:38 AM9/2/22
to skia-discuss
in regards to the blanks, you could implement a lookahead buffer for scrolling, similar to how android's RecyclerView and AdapterView do

Clark Kent

unread,
Sep 2, 2022, 6:01:11 AM9/2/22
to skia-discuss
specifically

BUFFER is almost ALWAYS offscreen

OUTSIDE (not loaded) POS 1
BUFFER (load) POS 2
BUFFER (load) POS 3
BUFFER (load) POS 4
VISIBLE (load) POS 5
VISIBLE (load) POS 6
BUFFER (load) POS 7
BUFFER (load) POS 8
BUFFER (load) POS 9
OUTSIDE (not loaded) POS 10

as the user scrolls, the buffer will fill up and load/discard content as appropriate

if scrolled down by 1 item, item at POS 2 is unloaded and item at POS 10 is loaded

OUTSIDE (not loaded) POS 2
BUFFER (load) POS 3
BUFFER (load) POS 4
BUFFER (load) POS 5
VISIBLE (load) POS 6
VISIBLE (load) POS 7
BUFFER (load) POS 8
BUFFER (load) POS 9
BUFFER (load) POS 10
OUTSIDE (not loaded) POS 11

Clark Kent

unread,
Sep 2, 2022, 6:03:51 AM9/2/22
to skia-discuss
keep in mind the greater the buffer size the more pre-loading will need to be done and the more memory will need to be used

for content that takes some time to load, a large buffer may benefit at the cost of increased memory consumption

Clark Kent

unread,
Sep 2, 2022, 6:04:39 AM9/2/22
to skia-discuss
assuming loading is done in background as to not stall/freeze the render (UI) thread

cccc

unread,
Sep 6, 2022, 1:07:15 AM9/6/22
to skia-discuss
Hi, Thank You! for your reply. I am following the same idea of buffering but if I scroll fast on the mac I could see blanks as preloading is taking time. Also is there any lightweight option than skimage to store my rendering?

Clark Kent

unread,
Sep 6, 2022, 2:39:46 AM9/6/22
to skia-discuss
you could try to take advantage of GPU rendering via

SkSurface::MakeRenderTarget(canvas->getSurface()->recordingContext(), SkBudgeted::kNo, image_info, 0, kTopLeft_GrSurfaceOrigin, nullptr);
Message has been deleted

Clark Kent

unread,
Sep 6, 2022, 2:41:37 AM9/6/22
to skia-discuss
you should simply be able to store the surface and then directly draw the surface to the canvas, eliminating the need for an SkImage of the surface snapshot

On Tuesday, 6 September 2022 at 15:07:15 UTC+10 cccc wrote:
Reply all
Reply to author
Forward
0 new messages