1/*
2 * Copyright 2021 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "modules/androidkit/src/SurfaceThread.h"
8
9#include "tools/sk_app/WindowContext.h"
10#include "tools/sk_app/android/WindowContextFactory_android.h"
11
12#include "include/core/SkCanvas.h"
13#include "include/core/SkTypes.h"
14
15SurfaceThread::SurfaceThread() {
16    pipe(fPipe);
17    fRunning = true;
18    pthread_create(&fThread, nullptr, pthread_main, this);
19}
20
21void SurfaceThread::postMessage(const Message& message) const {
22    write(fPipe[1], &message, sizeof(message));
23}
24
25void SurfaceThread::readMessage(Message* message) const {
26    read(fPipe[0], message, sizeof(Message));
27}
28
29void SurfaceThread::release() {
30    pthread_join(fThread, nullptr);
31}
32
33int SurfaceThread::message_callback(int /* fd */, int /* events */, void* data) {
34    auto surfaceThread = (SurfaceThread*)data;
35    Message message;
36    surfaceThread->readMessage(&message);
37    // get target surface from Message
38
39    switch (message.fType) {
40        case kInitialize: {
41            sk_app::DisplayParams params;
42            auto winctx = sk_app::window_context_factory::MakeGLForAndroid(message.fNativeWindow, params);
43            if (!winctx) {
44                break;
45            }
46            *message.fWindowSurface = new WindowSurface(message.fNativeWindow, std::move(winctx));
47            break;
48        }
49        case kDestroy: {
50            SkDebugf("surface destroyed, shutting down thread");
51            surfaceThread->fRunning = false;
52            if(auto* windowSurface = reinterpret_cast<Surface*>(*message.fWindowSurface)){
53                windowSurface->release(nullptr);
54                delete windowSurface;
55            }
56            return 0;
57            break;
58        }
59        case kRenderPicture: {
60            sk_sp<SkPicture> picture(message.fPicture);
61            if(auto* windowSurface = reinterpret_cast<Surface*>(*message.fWindowSurface)){
62                windowSurface->getCanvas()->drawPicture(picture);
63                windowSurface->flushAndSubmit();
64            }
65            break;
66        }
67        default: {
68            // do nothing
69        }
70    }
71
72    return 1;  // continue receiving callbacks
73}
74
75void* SurfaceThread::pthread_main(void* arg) {
76    auto surfaceThread = (SurfaceThread*)arg;
77    // Looper setup
78    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
79    ALooper_addFd(looper, surfaceThread->fPipe[0], 1, ALOOPER_EVENT_INPUT,
80               surfaceThread->message_callback, surfaceThread);
81
82    while (surfaceThread->fRunning) {
83        const int ident = ALooper_pollAll(0, nullptr, nullptr, nullptr);
84
85        if (ident >= 0) {
86            SkDebugf("Unhandled ALooper_pollAll ident=%d !", ident);
87        }
88    }
89    return nullptr;
90}
91