• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 package org.skia.androidkit.util;
9 
10 import android.util.Log;
11 import android.view.SurfaceHolder;
12 import org.skia.androidkit.Canvas;
13 import org.skia.androidkit.Surface;
14 
15 /**
16   * Utility base class facilitating the implementation of Surface-bound animations.
17   *
18   * Provides a dedicated render thread and user content callbacks.
19   */
20 public abstract class SurfaceRenderer implements SurfaceHolder.Callback, Runnable {
21     private android.view.Surface mAndroidSurface;
22     private Thread               mRenderThread;
23     private boolean              mThreadRunning;
24     private long                 mTimeBase;
25 
26     /**
27       * Initialization callback.
28       *
29       * This can be invoked multiple times if the underlying surface changes.
30       */
onSurfaceInitialized(Surface surface)31     protected abstract void onSurfaceInitialized(Surface surface);
32 
33     /**
34       * Callback for frame content.
35       *
36       * Invoked once per (vsync'ed) frame.
37       */
onRenderFrame(Canvas canvas, long ms)38     protected abstract void onRenderFrame(Canvas canvas, long ms);
39 
40     @Override
run()41     public void run() {
42         Log.d("SurfaceRenderer", "Render thread started.");
43 
44         // TODO: Vulkan support?
45         Surface surface = Surface.CreateGL(mAndroidSurface);
46         onSurfaceInitialized(surface);
47 
48         mTimeBase = java.lang.System.currentTimeMillis();
49 
50         while (mThreadRunning) {
51             long timestamp = java.lang.System.currentTimeMillis() - mTimeBase;
52             onRenderFrame(surface.getCanvas(), timestamp);
53             surface.flushAndSubmit();
54         }
55 
56         // Ensure that the backing surface is released on the same thread.
57         surface.release();
58 
59         Log.d("SurfaceRenderer", "Render thread finished.");
60     }
61 
62     @Override
surfaceCreated(SurfaceHolder holder)63     public void surfaceCreated(SurfaceHolder holder) {
64         // Initialization handled in surfaceChanged().
65     }
66 
67     @Override
surfaceChanged(SurfaceHolder holder, int format, int width, int height)68     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
69         mAndroidSurface = holder.getSurface();
70 
71         stopRenderThread();
72         startRenderThread();
73     }
74 
75     @Override
surfaceDestroyed(SurfaceHolder holder)76     public void surfaceDestroyed(SurfaceHolder holder) {
77         stopRenderThread();
78     }
79 
startRenderThread()80     private void startRenderThread() {
81         if (!mThreadRunning) {
82             mThreadRunning = true;
83             mRenderThread = new Thread(this);
84             mRenderThread.start();
85         }
86     }
87 
stopRenderThread()88     private void stopRenderThread() {
89         if (mThreadRunning) {
90             mThreadRunning = false;
91             try {
92                 mRenderThread.join();
93             } catch (InterruptedException e) {}
94         }
95     }
96 
setBaseTime(long millis)97     public void setBaseTime(long millis) {
98         mTimeBase = millis;
99     }
100 
release()101     public void release() {
102         stopRenderThread();
103     }
104 }
105