RenderProxy.cpp revision 119907cd2575c56b1ebf66348b52e67aaf6a88d8
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "RenderProxy.h"
18
19#include "CanvasContext.h"
20#include "RenderTask.h"
21#include "RenderThread.h"
22
23#include "../DeferredLayerUpdater.h"
24#include "../DisplayList.h"
25#include "../LayerRenderer.h"
26#include "../Rect.h"
27
28namespace android {
29namespace uirenderer {
30namespace renderthread {
31
32#define ARGS(method) method ## Args
33
34#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
35#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
36#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
37#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
38#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
39#define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,)
40#define CREATE_BRIDGE6(name, a1, a2, a3, a4, a5, a6) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,,)
41#define CREATE_BRIDGE7(name, a1, a2, a3, a4, a5, a6, a7) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,a7,)
42#define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
43    typedef struct { \
44        a1; a2; a3; a4; a5; a6; a7; a8; \
45    } ARGS(name); \
46    static void* Bridge_ ## name(ARGS(name)* args)
47
48#define SETUP_TASK(method) \
49    LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
50        "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
51                METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
52    MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
53    ARGS(method) *args = (ARGS(method) *) task->payload()
54
55CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
56        RenderNode* rootRenderNode, IContextFactory* contextFactory) {
57    return new CanvasContext(*args->thread, args->translucent,
58            args->rootRenderNode, args->contextFactory);
59}
60
61RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
62        : mRenderThread(RenderThread::getInstance())
63        , mContext(0) {
64    SETUP_TASK(createContext);
65    args->translucent = translucent;
66    args->rootRenderNode = rootRenderNode;
67    args->thread = &mRenderThread;
68    args->contextFactory = contextFactory;
69    mContext = (CanvasContext*) postAndWait(task);
70    mDrawFrameTask.setContext(&mRenderThread, mContext);
71}
72
73RenderProxy::~RenderProxy() {
74    destroyContext();
75}
76
77CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
78    delete args->context;
79    return NULL;
80}
81
82void RenderProxy::destroyContext() {
83    if (mContext) {
84        SETUP_TASK(destroyContext);
85        args->context = mContext;
86        mContext = 0;
87        mDrawFrameTask.setContext(NULL, NULL);
88        // This is also a fence as we need to be certain that there are no
89        // outstanding mDrawFrame tasks posted before it is destroyed
90        postAndWait(task);
91    }
92}
93
94CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
95    args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
96    return NULL;
97}
98
99void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
100    SETUP_TASK(setFrameInterval);
101    args->thread = &mRenderThread;
102    args->frameIntervalNanos = frameIntervalNanos;
103    post(task);
104}
105
106CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) {
107    bool needsRedraw = false;
108    if (Caches::hasInstance()) {
109        needsRedraw = Caches::getInstance().initProperties();
110    }
111    if (args->context->profiler().loadSystemProperties()) {
112        needsRedraw = true;
113    }
114    return (void*) needsRedraw;
115}
116
117bool RenderProxy::loadSystemProperties() {
118    SETUP_TASK(loadSystemProperties);
119    args->context = mContext;
120    return (bool) postAndWait(task);
121}
122
123CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
124    return (void*) args->context->initialize(args->window);
125}
126
127bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
128    SETUP_TASK(initialize);
129    args->context = mContext;
130    args->window = window.get();
131    return (bool) postAndWait(task);
132}
133
134CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
135    args->context->updateSurface(args->window);
136    return NULL;
137}
138
139void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
140    SETUP_TASK(updateSurface);
141    args->context = mContext;
142    args->window = window.get();
143    postAndWait(task);
144}
145
146CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) {
147    args->context->pauseSurface(args->window);
148    return NULL;
149}
150
151void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
152    SETUP_TASK(pauseSurface);
153    args->context = mContext;
154    args->window = window.get();
155    postAndWait(task);
156}
157
158CREATE_BRIDGE7(setup, CanvasContext* context, int width, int height,
159        Vector3 lightCenter, float lightRadius,
160        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
161    args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius,
162            args->ambientShadowAlpha, args->spotShadowAlpha);
163    return NULL;
164}
165
166void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
167        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
168    SETUP_TASK(setup);
169    args->context = mContext;
170    args->width = width;
171    args->height = height;
172    args->lightCenter = lightCenter;
173    args->lightRadius = lightRadius;
174    args->ambientShadowAlpha = ambientShadowAlpha;
175    args->spotShadowAlpha = spotShadowAlpha;
176    post(task);
177}
178
179CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
180    args->context->setOpaque(args->opaque);
181    return NULL;
182}
183
184void RenderProxy::setOpaque(bool opaque) {
185    SETUP_TASK(setOpaque);
186    args->context = mContext;
187    args->opaque = opaque;
188    post(task);
189}
190
191int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
192        float density) {
193    mDrawFrameTask.setDensity(density);
194    return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
195}
196
197CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
198    args->context->destroyCanvasAndSurface();
199    return NULL;
200}
201
202void RenderProxy::destroyCanvasAndSurface() {
203    SETUP_TASK(destroyCanvasAndSurface);
204    args->context = mContext;
205    // destroyCanvasAndSurface() needs a fence as when it returns the
206    // underlying BufferQueue is going to be released from under
207    // the render thread.
208    postAndWait(task);
209}
210
211CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
212    CanvasContext::invokeFunctor(*args->thread, args->functor);
213    return NULL;
214}
215
216void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
217    ATRACE_CALL();
218    RenderThread& thread = RenderThread::getInstance();
219    SETUP_TASK(invokeFunctor);
220    args->thread = &thread;
221    args->functor = functor;
222    if (waitForCompletion) {
223        // waitForCompletion = true is expected to be fairly rare and only
224        // happen in destruction. Thus it should be fine to temporarily
225        // create a Mutex
226        Mutex mutex;
227        Condition condition;
228        SignalingRenderTask syncTask(task, &mutex, &condition);
229        AutoMutex _lock(mutex);
230        thread.queue(&syncTask);
231        condition.wait(mutex);
232    } else {
233        thread.queue(task);
234    }
235}
236
237CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
238    args->context->runWithGlContext(args->task);
239    return NULL;
240}
241
242void RenderProxy::runWithGlContext(RenderTask* gltask) {
243    SETUP_TASK(runWithGlContext);
244    args->context = mContext;
245    args->task = gltask;
246    postAndWait(task);
247}
248
249CREATE_BRIDGE1(destroyLayer, Layer* layer) {
250    LayerRenderer::destroyLayer(args->layer);
251    return NULL;
252}
253
254void RenderProxy::enqueueDestroyLayer(Layer* layer) {
255    SETUP_TASK(destroyLayer);
256    args->layer = layer;
257    RenderThread::getInstance().queue(task);
258}
259
260CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
261    Layer* layer = args->context->createRenderLayer(args->width, args->height);
262    if (!layer) return 0;
263    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
264}
265
266DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
267    SETUP_TASK(createDisplayListLayer);
268    args->width = width;
269    args->height = height;
270    args->context = mContext;
271    void* retval = postAndWait(task);
272    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
273    return layer;
274}
275
276CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
277    Layer* layer = args->context->createTextureLayer();
278    if (!layer) return 0;
279    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
280}
281
282DeferredLayerUpdater* RenderProxy::createTextureLayer() {
283    SETUP_TASK(createTextureLayer);
284    args->context = mContext;
285    void* retval = postAndWait(task);
286    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
287    return layer;
288}
289
290CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
291    args->context->buildLayer(args->node);
292    return NULL;
293}
294
295void RenderProxy::buildLayer(RenderNode* node) {
296    SETUP_TASK(buildLayer);
297    args->context = mContext;
298    args->node = node;
299    postAndWait(task);
300}
301
302CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
303        SkBitmap* bitmap) {
304    bool success = args->context->copyLayerInto(args->layer, args->bitmap);
305    return (void*) success;
306}
307
308bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
309    SETUP_TASK(copyLayerInto);
310    args->context = mContext;
311    args->layer = layer;
312    args->bitmap = bitmap;
313    return (bool) postAndWait(task);
314}
315
316void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
317    mDrawFrameTask.pushLayerUpdate(layer);
318}
319
320void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
321    mDrawFrameTask.removeLayerUpdate(layer);
322}
323
324CREATE_BRIDGE1(detachSurfaceTexture, DeferredLayerUpdater* layer) {
325    args->layer->detachSurfaceTexture();
326    return NULL;
327}
328
329void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
330    SETUP_TASK(detachSurfaceTexture);
331    args->layer = layer;
332    postAndWait(task);
333}
334
335CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
336    args->context->destroyHardwareResources();
337    return NULL;
338}
339
340void RenderProxy::destroyHardwareResources() {
341    SETUP_TASK(destroyHardwareResources);
342    args->context = mContext;
343    post(task);
344}
345
346CREATE_BRIDGE2(timMemory, RenderThread* thread, int level) {
347    CanvasContext::trimMemory(*args->thread, args->level);
348    return NULL;
349}
350
351void RenderProxy::trimMemory(int level) {
352    // Avoid creating a RenderThread to do a trimMemory.
353    if (RenderThread::hasInstance()) {
354        RenderThread& thread = RenderThread::getInstance();
355        SETUP_TASK(timMemory);
356        args->thread = &thread;
357        args->level = level;
358        thread.queue(task);
359    }
360}
361
362CREATE_BRIDGE0(fence) {
363    // Intentionally empty
364    return NULL;
365}
366
367void RenderProxy::fence() {
368    SETUP_TASK(fence);
369    postAndWait(task);
370}
371
372CREATE_BRIDGE1(stopDrawing, CanvasContext* context) {
373    args->context->stopDrawing();
374    return NULL;
375}
376
377void RenderProxy::stopDrawing() {
378    SETUP_TASK(stopDrawing);
379    args->context = mContext;
380    postAndWait(task);
381}
382
383CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) {
384    args->context->notifyFramePending();
385    return NULL;
386}
387
388void RenderProxy::notifyFramePending() {
389    SETUP_TASK(notifyFramePending);
390    args->context = mContext;
391    mRenderThread.queueAtFront(task);
392}
393
394CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
395    args->context->profiler().dumpData(args->fd);
396    return NULL;
397}
398
399void RenderProxy::dumpProfileInfo(int fd) {
400    SETUP_TASK(dumpProfileInfo);
401    args->context = mContext;
402    args->fd = fd;
403    postAndWait(task);
404}
405
406CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
407    CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
408    args->buffer->decStrong(0);
409    return NULL;
410}
411
412void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
413    SETUP_TASK(setTextureAtlas);
414    args->thread = &mRenderThread;
415    args->buffer = buffer.get();
416    args->buffer->incStrong(0);
417    args->map = map;
418    args->size = size;
419    post(task);
420}
421
422void RenderProxy::post(RenderTask* task) {
423    mRenderThread.queue(task);
424}
425
426void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
427    void* retval;
428    task->setReturnPtr(&retval);
429    SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition);
430    AutoMutex _lock(mSyncMutex);
431    mRenderThread.queue(&syncTask);
432    mSyncCondition.wait(mSyncMutex);
433    return retval;
434}
435
436} /* namespace renderthread */
437} /* namespace uirenderer */
438} /* namespace android */
439