blob: 25badacc32221497188ae05247b72211a4a854aa [file] [log] [blame]
John Reck4f02bf42014-01-03 18:09:17 -08001/*
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#define LOG_TAG "RenderProxy"
18
19#include "RenderProxy.h"
20
21#include "CanvasContext.h"
22#include "RenderTask.h"
23#include "RenderThread.h"
24
25#include "../DisplayList.h"
26#include "../Rect.h"
27
28namespace android {
29namespace uirenderer {
30namespace renderthread {
31
32#define ARGS(method) method ## Args
33
34#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
35#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
36#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
37#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
38#define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
39 typedef struct { \
40 a1; a2; a3; a4; a5; a6; a7; a8; \
41 } ARGS(name); \
42 static void* Bridge_ ## name(ARGS(name)* args)
43
44#define SETUP_TASK(method) \
45 LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
46 "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
47 METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
48 MethodInvokeRenderTask* task = createTask((RunnableMethod) Bridge_ ## method); \
49 ARGS(method) *args = (ARGS(method) *) task->payload()
50
51CREATE_BRIDGE1(createContext, bool translucent) {
52 return new CanvasContext(args->translucent);
53}
54
55RenderProxy::RenderProxy(bool translucent)
56 : mRenderThread(RenderThread::getInstance())
57 , mContext(0) {
58 SETUP_TASK(createContext);
59 args->translucent = translucent;
60 mContext = (CanvasContext*) postAndWait(task);
61}
62
63RenderProxy::~RenderProxy() {
64 destroyContext();
65}
66
67CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
68 delete args->context;
69 return NULL;
70}
71
72void RenderProxy::destroyContext() {
73 if (mContext) {
74 SETUP_TASK(destroyContext);
75 args->context = mContext;
76 mContext = 0;
77 post(task);
78 }
79}
80
81CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
82 return (void*) args->context->initialize(args->window);
83}
84
85bool RenderProxy::initialize(EGLNativeWindowType window) {
86 SETUP_TASK(initialize);
87 args->context = mContext;
88 args->window = window;
89 return (bool) postAndWait(task);
90}
91
92CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window) {
93 args->context->updateSurface(args->window);
94 return NULL;
95}
96
97void RenderProxy::updateSurface(EGLNativeWindowType window) {
98 SETUP_TASK(updateSurface);
99 args->context = mContext;
100 args->window = window;
101 post(task);
102}
103
104CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
105 args->context->setup(args->width, args->height);
106 return NULL;
107}
108
109void RenderProxy::setup(int width, int height) {
110 SETUP_TASK(setup);
111 args->context = mContext;
112 args->width = width;
113 args->height = height;
114 post(task);
115}
116
117CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
118 Rect dirty) {
119 Rect* dirty = &args->dirty;
120 if (dirty->bottom == -1 && dirty->left == -1 &&
121 dirty->top == -1 && dirty->right == -1) {
122 dirty = 0;
123 }
124 args->context->drawDisplayList(args->displayList, dirty);
125 return NULL;
126}
127
128void RenderProxy::drawDisplayList(DisplayList* displayList,
129 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
130 SETUP_TASK(drawDisplayList);
131 args->context = mContext;
132 args->displayList = displayList;
133 args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
134 // TODO: Switch to post() once some form of thread safety strategy is in place
135 postAndWait(task);
136}
137
138CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) {
139 args->context->destroyCanvas();
140 return NULL;
141}
142
143void RenderProxy::destroyCanvas() {
144 SETUP_TASK(destroyCanvas);
145 args->context = mContext;
146 post(task);
147}
148
149CREATE_BRIDGE2(attachFunctor, CanvasContext* context, Functor* functor) {
150 args->context->attachFunctor(args->functor);
151 return NULL;
152}
153
154void RenderProxy::attachFunctor(Functor* functor) {
155 SETUP_TASK(attachFunctor);
156 args->context = mContext;
157 args->functor = functor;
158 post(task);
159}
160
161CREATE_BRIDGE2(detachFunctor, CanvasContext* context, Functor* functor) {
162 args->context->detachFunctor(args->functor);
163 return NULL;
164}
165
166void RenderProxy::detachFunctor(Functor* functor) {
167 SETUP_TASK(detachFunctor);
168 args->context = mContext;
169 args->functor = functor;
170 post(task);
171}
172
173MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
174 // TODO: Consider having a small pool of these to avoid alloc churn
175 return new MethodInvokeRenderTask(method);
176}
177
178void RenderProxy::post(RenderTask* task) {
179 mRenderThread.queue(task);
180}
181
182void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
183 void* retval;
184 task->setReturnPtr(&retval);
185 SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition);
186 AutoMutex _lock(mSyncMutex);
187 mRenderThread.queue(&syncTask);
188 mSyncCondition.wait(mSyncMutex);
189 return retval;
190}
191
192} /* namespace renderthread */
193} /* namespace uirenderer */
194} /* namespace android */