Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71c8fa17 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "RenderThread work"

parents 1eb87f2c cec24ae1
Loading
Loading
Loading
Loading
+62 −8
Original line number Diff line number Diff line
@@ -635,11 +635,11 @@ public class GLRenderer extends HardwareRenderer {
    GLRenderer(boolean translucent) {
        mTranslucent = translucent;

        loadSystemProperties(null);
        loadSystemProperties();
    }

    @Override
    boolean loadSystemProperties(Surface surface) {
    boolean loadSystemProperties() {
        boolean value;
        boolean changed = false;

@@ -1101,11 +1101,6 @@ public class GLRenderer extends HardwareRenderer {
        return mHeight;
    }

    @Override
    HardwareCanvas getCanvas() {
        return mCanvas;
    }

    @Override
    void setName(String name) {
        mName = name;
@@ -1128,6 +1123,66 @@ public class GLRenderer extends HardwareRenderer {
        }
    }

    @Override
    void drawDisplayList(DisplayList displayList, View.AttachInfo attachInfo,
            HardwareDrawCallbacks callbacks, Rect dirty) {
        if (canDraw()) {
            if (!hasDirtyRegions()) {
                dirty = null;
            }

            // We are already on the correct thread
            final int surfaceState = checkRenderContextUnsafe();
            if (surfaceState != SURFACE_STATE_ERROR) {
                HardwareCanvas canvas = mCanvas;

                if (mProfileEnabled) {
                    mProfileLock.lock();
                }

                dirty = beginFrame(canvas, dirty, surfaceState);

                int saveCount = 0;
                int status = DisplayList.STATUS_DONE;

                long start = getSystemTime();
                try {
                    status = prepareFrame(dirty);

                    saveCount = canvas.save();
                    callbacks.onHardwarePreDraw(canvas);

                    status |= drawDisplayList(attachInfo, canvas, displayList, status);
                } catch (Exception e) {
                    Log.e(LOG_TAG, "An error has occurred while drawing:", e);
                } finally {
                    callbacks.onHardwarePostDraw(canvas);
                    canvas.restoreToCount(saveCount);

                    mDrawDelta = getSystemTime() - start;

                    if (mDrawDelta > 0) {
                        mFrameCount++;

                        debugOverdraw(attachInfo, dirty, canvas, displayList);
                        debugDirtyRegions(dirty, canvas);
                        drawProfileData(attachInfo);
                    }
                }

                onPostDraw();

                swapBuffers(status);

                if (mProfileEnabled) {
                    mProfileLock.unlock();
                }

                attachInfo.mIgnoreDirtyState = false;
            }
        }
    }

    @Override
    void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
            Rect dirty) {
@@ -1144,7 +1199,6 @@ public class GLRenderer extends HardwareRenderer {
            final int surfaceState = checkRenderContextUnsafe();
            if (surfaceState != SURFACE_STATE_ERROR) {
                HardwareCanvas canvas = mCanvas;
                attachInfo.mHardwareCanvas = canvas;

                if (mProfileEnabled) {
                    mProfileLock.lock();
+22 −10
Original line number Diff line number Diff line
@@ -188,6 +188,9 @@ public abstract class HardwareRenderer {
     */
    public static boolean sSystemRendererDisabled = false;

    /** @hide */
    public static boolean sUseRenderThread = false;

    private boolean mEnabled;
    private boolean mRequested = true;

@@ -305,13 +308,6 @@ public abstract class HardwareRenderer {
     */
    abstract int getHeight();

    /**
     * Gets the current canvas associated with this HardwareRenderer.
     *
     * @return the current HardwareCanvas
     */
    abstract HardwareCanvas getCanvas();

    /**
     * Outputs extra debugging information in the specified file descriptor.
     * @param pw
@@ -335,7 +331,7 @@ public abstract class HardwareRenderer {
     *
     * @return True if a property has changed.
     */
    abstract boolean loadSystemProperties(Surface surface);
    abstract boolean loadSystemProperties();

    /**
     * Sets the directory to use as a persistent storage for hardware rendering
@@ -411,6 +407,18 @@ public abstract class HardwareRenderer {
    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
            Rect dirty);

    /**
     * Temporary hook to draw a display list directly, only used if sUseRenderThread
     * is true.
     *
     * @param displayList The display list to draw
     * @param attachInfo AttachInfo tied to the specified view.
     * @param callbacks Callbacks invoked when drawing happens.
     * @param dirty The dirty rectangle to update, can be null.
     */
    abstract void drawDisplayList(DisplayList displayList, View.AttachInfo attachInfo,
            HardwareDrawCallbacks callbacks, Rect dirty);

    /**
     * Creates a new hardware layer. A hardware layer built by calling this
     * method will be treated as a texture layer, instead of as a render target.
@@ -517,10 +525,14 @@ public abstract class HardwareRenderer {
     * @return A hardware renderer backed by OpenGL.
     */
    static HardwareRenderer create(boolean translucent) {
        HardwareRenderer renderer = null;
        if (GLES20Canvas.isAvailable()) {
            return new GLRenderer(translucent);
            renderer = new GLRenderer(translucent);
        }
        if (renderer != null && sUseRenderThread) {
            renderer = new ThreadedRenderer((GLRenderer)renderer);
        }
        return null;
        return renderer;
    }

    /**
+317 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Looper;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;

import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * Hardware renderer that proxies the rendering to a render thread. Most calls
 * are synchronous, however a few such as draw() are posted async. The display list
 * is shared between the two threads and is guarded by a top level lock.
 *
 * The UI thread can block on the RenderThread, but RenderThread must never
 * block on the UI thread.
 *
 * Note that although currently the EGL context & surfaces are created & managed
 * by the render thread, the goal is to move that into a shared structure that can
 * be managed by both threads. EGLSurface creation & deletion should ideally be
 * done on the UI thread and not the RenderThread to avoid stalling the
 * RenderThread with surface buffer allocation.
 *
 * @hide
 */
public class ThreadedRenderer extends HardwareRenderer {
    private static final String LOGTAG = "ThreadedRenderer";

    @SuppressWarnings("serial")
    static HashMap<String, Method> sMethodLut = new HashMap<String, Method>() {{
        Method[] methods = HardwareRenderer.class.getDeclaredMethods();
        for (Method m : methods) {
            put(m.getName(), m);
        }
    }};
    static boolean sNeedsInit = true;

    private HardwareRenderer mRemoteRenderer;
    private int mWidth, mHeight;
    private RTJob mPreviousDraw;

    ThreadedRenderer(GLRenderer backingRenderer) {
        mRemoteRenderer = backingRenderer;
        setEnabled(true);
        if (sNeedsInit) {
            sNeedsInit = false;
            postToRenderThread(new Runnable() {
                @Override
                public void run() {
                    // Hack to allow GLRenderer to create a handler to post the EGL
                    // destruction to, although it'll never run
                    Looper.prepare();
                }
            });
        }
    }

    @Override
    void destroy(boolean full) {
        run("destroy", full);
    }

    @Override
    boolean initialize(Surface surface) throws OutOfResourcesException {
        return (Boolean) run("initialize", surface);
    }

    @Override
    void updateSurface(Surface surface) throws OutOfResourcesException {
        post("updateSurface", surface);
    }

    @Override
    void destroyLayers(View view) {
        throw new NoSuchMethodError();
    }

    @Override
    void destroyHardwareResources(View view) {
        run("destroyHardwareResources", view);
    }

    @Override
    void invalidate(Surface surface) {
        post("invalidate", surface);
    }

    @Override
    boolean validate() {
        // TODO Remove users of this API
        return false;
    }

    @Override
    boolean safelyRun(Runnable action) {
        return (Boolean) run("safelyRun", action);
    }

    @Override
    void setup(int width, int height) {
        mWidth = width;
        mHeight = height;
        post("setup", width, height);
    }

    @Override
    int getWidth() {
        return mWidth;
    }

    @Override
    int getHeight() {
        return mHeight;
    }

    @Override
    void dumpGfxInfo(PrintWriter pw) {
        // TODO Auto-generated method stub
    }

    @Override
    long getFrameCount() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    boolean loadSystemProperties() {
        return (Boolean) run("loadSystemProperties");
    }

    @Override
    void pushLayerUpdate(HardwareLayer layer) {
        throw new NoSuchMethodError();
    }

    @Override
    void cancelLayerUpdate(HardwareLayer layer) {
        throw new NoSuchMethodError();
    }

    @Override
    void flushLayerUpdates() {
        throw new NoSuchMethodError();
    }

    @Override
    void drawDisplayList(DisplayList displayList, AttachInfo attachInfo,
            HardwareDrawCallbacks callbacks, Rect dirty) {
        throw new NoSuchMethodError();
    }

    /**
     * TODO: Remove
     * Temporary hack to allow RenderThreadTest prototype app to trigger
     * replaying a DisplayList after modifying the displaylist properties
     *
     *  @hide */
    public void repeatLastDraw() {
        if (mPreviousDraw == null) {
            throw new IllegalStateException("There isn't a previous draw");
        }
        synchronized (mPreviousDraw) {
            mPreviousDraw.completed = false;
        }
        mPreviousDraw.args[3] = null;
        postToRenderThread(mPreviousDraw);
    }

    @Override
    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
        requireCompletion(mPreviousDraw);

        attachInfo.mIgnoreDirtyState = true;
        attachInfo.mDrawingTime = SystemClock.uptimeMillis();
        view.mPrivateFlags |= View.PFLAG_DRAWN;

        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                == View.PFLAG_INVALIDATED;
        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;

        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
        DisplayList displayList = view.getDisplayList();
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);

        view.mRecreateDisplayList = false;

        mPreviousDraw = post("drawDisplayList", displayList, attachInfo,
                callbacks, dirty);
    }

    @Override
    HardwareLayer createHardwareLayer(boolean isOpaque) {
        throw new NoSuchMethodError();
    }

    @Override
    HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
        throw new NoSuchMethodError();
    }

    @Override
    SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
        throw new NoSuchMethodError();
    }

    @Override
    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
        throw new NoSuchMethodError();
    }

    @Override
    void detachFunctor(int functor) {
        throw new NoSuchMethodError();
    }

    @Override
    boolean attachFunctor(AttachInfo attachInfo, int functor) {
        throw new NoSuchMethodError();
    }

    @Override
    void setName(String name) {
        post("setName", name);
    }

    private static void requireCompletion(RTJob job) {
        if (job != null) {
            synchronized (job) {
                if (!job.completed) {
                    try {
                        job.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    private RTJob post(String method, Object... args) {
        RTJob job = new RTJob();
        job.method = sMethodLut.get(method);
        job.args = args;
        job.target = mRemoteRenderer;
        if (job.method == null) {
            throw new NullPointerException("Couldn't find method: " + method);
        }
        postToRenderThread(job);
        return job;
    }

    private Object run(String method, Object... args) {
        RTJob job = new RTJob();
        job.method = sMethodLut.get(method);
        job.args = args;
        job.target = mRemoteRenderer;
        if (job.method == null) {
            throw new NullPointerException("Couldn't find method: " + method);
        }
        synchronized (job) {
            postToRenderThread(job);
            try {
                job.wait();
                return job.ret;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    static class RTJob implements Runnable {
        Method method;
        Object[] args;
        Object target;
        Object ret;
        boolean completed = false;

        @Override
        public void run() {
            try {
                ret = method.invoke(target, args);
                synchronized (this) {
                    completed = true;
                    notify();
                }
            } catch (Exception e) {
                Log.e(LOGTAG, "Failed to invoke: " + method.getName(), e);
            }
        }
    }

    /** @hide */
    public static native void postToRenderThread(Runnable runnable);
}
+7 −2
Original line number Diff line number Diff line
@@ -11234,6 +11234,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return null;
    }
    /**
     * @hide
     */
    public HardwareRenderer getHardwareRenderer() {
        return mAttachInfo != null ? mAttachInfo.mHardwareRenderer : null;
    }
    /**
     * <p>Causes the Runnable to be added to the message queue.
     * The runnable will be run on the user interface thread.</p>
@@ -18869,8 +18876,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        final Callbacks mRootCallbacks;
        HardwareCanvas mHardwareCanvas;
        IWindowId mIWindowId;
        WindowId mWindowId;
+115 −109

File changed.

Preview size limit exceeded, changes collapsed.

Loading