DisplayListRenderer.cpp revision 5977baa1fa24125c148a72699b53e62abaf08960
17cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root/*
27cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * Copyright (C) 2010 The Android Open Source Project
37cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root *
47cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
57cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * you may not use this file except in compliance with the License.
67cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * You may obtain a copy of the License at
77cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root *
87cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
97cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root *
107cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * Unless required by applicable law or agreed to in writing, software
117cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
127cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * See the License for the specific language governing permissions and
147cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root * limitations under the License.
157cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root */
167cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
177cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root#define LOG_TAG "OpenGLRenderer"
187cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
197cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root#include "DisplayListRenderer.h"
207cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
217cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Rootnamespace android {
227cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Rootnamespace uirenderer {
237cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
247cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root///////////////////////////////////////////////////////////////////////////////
257cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root// Defines
267cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root///////////////////////////////////////////////////////////////////////////////
277cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
287cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root#define PATH_HEAP_SIZE 64
297cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
307cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root///////////////////////////////////////////////////////////////////////////////
317cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root// Helpers
327cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root///////////////////////////////////////////////////////////////////////////////
337cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
347cee34a051eb0087322c8b965e498f88b1aa52d3Kenny RootPathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) {
357cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root}
367cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
377cee34a051eb0087322c8b965e498f88b1aa52d3Kenny RootPathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) {
387cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    int count = buffer.readS32();
397cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
407cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    mPaths.setCount(count);
417cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath** ptr = mPaths.begin();
427cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath));
437cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
447cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    for (int i = 0; i < count; i++) {
457cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        new (p) SkPath;
467cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        p->unflatten(buffer);
477cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        *ptr++ = p;
487cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        p++;
497cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    }
507cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root}
517cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
527cee34a051eb0087322c8b965e498f88b1aa52d3Kenny RootPathHeap::~PathHeap() {
537cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath** iter = mPaths.begin();
547cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath** stop = mPaths.end();
557cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    while (iter < stop) {
567cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        (*iter)->~SkPath();
577cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        iter++;
587cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    }
597cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root}
607cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
617cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Rootint PathHeap::append(const SkPath& path) {
627cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath));
637cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    new (p) SkPath(path);
647cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    *mPaths.append() = p;
657cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    return mPaths.count();
667cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root}
677cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
687cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Rootvoid PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const {
697cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    int count = mPaths.count();
707cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root
717cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    buffer.write32(count);
727cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath** iter = mPaths.begin();
737cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    SkPath** stop = mPaths.end();
747cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root    while (iter < stop) {
757cee34a051eb0087322c8b965e498f88b1aa52d3Kenny Root        (*iter)->flatten(buffer);
76        iter++;
77    }
78}
79
80///////////////////////////////////////////////////////////////////////////////
81// Display list
82///////////////////////////////////////////////////////////////////////////////
83
84DisplayList::DisplayList(const DisplayListRenderer& recorder) {
85    initFromDisplayListRenderer(recorder);
86}
87
88DisplayList::~DisplayList() {
89    sk_free((void*) mReader.base());
90
91    Caches& caches = Caches::getInstance();
92
93    for (size_t i = 0; i < mBitmapResources.size(); i++) {
94        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
95    }
96    mBitmapResources.clear();
97
98    for (size_t i = 0; i < mShaderResources.size(); i++) {
99        caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
100    }
101    mShaderResources.clear();
102
103    for (size_t i = 0; i < mPaints.size(); i++) {
104        delete mPaints.itemAt(i);
105    }
106    mPaints.clear();
107
108    for (size_t i = 0; i < mMatrices.size(); i++) {
109        delete mMatrices.itemAt(i);
110    }
111    mMatrices.clear();
112
113    if (mPathHeap) {
114        for (int i = 0; i < mPathHeap->count(); i++) {
115            caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
116        }
117        mPathHeap->safeUnref();
118    }
119}
120
121void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder) {
122    const SkWriter32& writer = recorder.writeStream();
123    init();
124
125    if (writer.size() == 0) {
126        return;
127    }
128
129    size_t size = writer.size();
130    void* buffer = sk_malloc_throw(size);
131    writer.flatten(buffer);
132    mReader.setMemory(buffer, size);
133
134    mRCPlayback.reset(&recorder.mRCRecorder);
135    mRCPlayback.setupBuffer(mReader);
136
137    mTFPlayback.reset(&recorder.mTFRecorder);
138    mTFPlayback.setupBuffer(mReader);
139
140    Caches& caches = Caches::getInstance();
141
142    const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources();
143    for (size_t i = 0; i < bitmapResources.size(); i++) {
144        SkBitmap* resource = bitmapResources.itemAt(i);
145        mBitmapResources.add(resource);
146        caches.resourceCache.incrementRefcount(resource);
147    }
148
149    const Vector<SkiaShader*> &shaderResources = recorder.getShaderResources();
150    for (size_t i = 0; i < shaderResources.size(); i++) {
151        SkiaShader* resource = shaderResources.itemAt(i);
152        mShaderResources.add(resource);
153        caches.resourceCache.incrementRefcount(resource);
154    }
155
156    const Vector<SkPaint*> &paints = recorder.getPaints();
157    for (size_t i = 0; i < paints.size(); i++) {
158        mPaints.add(paints.itemAt(i));
159    }
160
161    const Vector<SkMatrix*> &matrices = recorder.getMatrices();
162    for (size_t i = 0; i < matrices.size(); i++) {
163        mMatrices.add(matrices.itemAt(i));
164    }
165
166    mPathHeap = recorder.mPathHeap;
167    if (mPathHeap) {
168        mPathHeap->safeRef();
169    }
170}
171
172void DisplayList::init() {
173    mPathHeap = NULL;
174}
175
176void DisplayList::replay(OpenGLRenderer& renderer) {
177    TextContainer text;
178    mReader.rewind();
179
180    int saveCount = renderer.getSaveCount() - 1;
181
182    while (!mReader.eof()) {
183        int op = mReader.readInt();
184        switch (op) {
185            case AcquireContext: {
186                renderer.acquireContext();
187            }
188            break;
189            case ReleaseContext: {
190                renderer.releaseContext();
191            }
192            break;
193            case Save: {
194                renderer.save(getInt());
195            }
196            break;
197            case Restore: {
198                renderer.restore();
199            }
200            break;
201            case RestoreToCount: {
202                renderer.restoreToCount(saveCount + getInt());
203            }
204            break;
205            case SaveLayer: {
206                renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(),
207                        getPaint(), getInt());
208            }
209            break;
210            case SaveLayerAlpha: {
211                renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(),
212                        getInt(), getInt());
213            }
214            break;
215            case Translate: {
216                renderer.translate(getFloat(), getFloat());
217            }
218            break;
219            case Rotate: {
220                renderer.rotate(getFloat());
221            }
222            break;
223            case Scale: {
224                renderer.scale(getFloat(), getFloat());
225            }
226            break;
227            case SetMatrix: {
228                renderer.setMatrix(getMatrix());
229            }
230            break;
231            case ConcatMatrix: {
232                renderer.concatMatrix(getMatrix());
233            }
234            break;
235            case ClipRect: {
236                renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(),
237                        (SkRegion::Op) getInt());
238            }
239            break;
240            case DrawDisplayList: {
241                renderer.drawDisplayList(getDisplayList());
242            }
243            break;
244            case DrawBitmap: {
245                renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint());
246            }
247            break;
248            case DrawBitmapMatrix: {
249                renderer.drawBitmap(getBitmap(), getMatrix(), getPaint());
250            }
251            break;
252            case DrawBitmapRect: {
253                renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(),
254                        getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
255            }
256            break;
257            case DrawPatch: {
258                int32_t* xDivs = NULL;
259                int32_t* yDivs = NULL;
260                uint32_t* colors = NULL;
261                uint32_t xDivsCount = 0;
262                uint32_t yDivsCount = 0;
263                int8_t numColors = 0;
264
265                SkBitmap* bitmap = getBitmap();
266
267                xDivs = getInts(xDivsCount);
268                yDivs = getInts(yDivsCount);
269                colors = getUInts(numColors);
270
271                renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount,
272                        numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
273            }
274            break;
275            case DrawColor: {
276                renderer.drawColor(getInt(), (SkXfermode::Mode) getInt());
277            }
278            break;
279            case DrawRect: {
280                renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
281            }
282            break;
283            case DrawPath: {
284                renderer.drawPath(getPath(), getPaint());
285            }
286            break;
287            case DrawLines: {
288                int count = 0;
289                float* points = getFloats(count);
290                renderer.drawLines(points, count, getPaint());
291            }
292            break;
293            case DrawText: {
294                getText(&text);
295                renderer.drawText(text.text(), text.length(), getInt(),
296                        getFloat(), getFloat(), getPaint());
297            }
298            break;
299            case ResetShader: {
300                renderer.resetShader();
301            }
302            break;
303            case SetupShader: {
304                renderer.setupShader(getShader());
305            }
306            break;
307            case ResetColorFilter: {
308                renderer.resetColorFilter();
309            }
310            break;
311            case SetupColorFilter: {
312                renderer.setupColorFilter(getColorFilter());
313            }
314            break;
315            case ResetShadow: {
316                renderer.resetShadow();
317            }
318            break;
319            case SetupShadow: {
320                renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt());
321            }
322            break;
323        }
324    }
325}
326
327///////////////////////////////////////////////////////////////////////////////
328// Base structure
329///////////////////////////////////////////////////////////////////////////////
330
331DisplayListRenderer::DisplayListRenderer():
332        mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) {
333    mPathHeap = NULL;
334    mDisplayList = NULL;
335}
336
337DisplayListRenderer::~DisplayListRenderer() {
338    reset();
339}
340
341void DisplayListRenderer::reset() {
342    if (mPathHeap) {
343        mPathHeap->unref();
344        mPathHeap = NULL;
345    }
346
347    mWriter.reset();
348    mHeap.reset();
349
350    mRCRecorder.reset();
351    mTFRecorder.reset();
352
353    Caches& caches = Caches::getInstance();
354    for (size_t i = 0; i < mBitmapResources.size(); i++) {
355        SkBitmap* resource = mBitmapResources.itemAt(i);
356        caches.resourceCache.decrementRefcount(resource);
357    }
358    mBitmapResources.clear();
359
360    for (size_t i = 0; i < mShaderResources.size(); i++) {
361        SkiaShader* resource = mShaderResources.itemAt(i);
362        caches.resourceCache.decrementRefcount(resource);
363    }
364    mShaderResources.clear();
365
366    mPaints.clear();
367    mPaintMap.clear();
368    mMatrices.clear();
369}
370
371///////////////////////////////////////////////////////////////////////////////
372// Operations
373///////////////////////////////////////////////////////////////////////////////
374
375DisplayList* DisplayListRenderer::getDisplayList() {
376    if (mDisplayList == NULL) {
377        mDisplayList = new DisplayList(*this);
378    } else {
379        mDisplayList->initFromDisplayListRenderer(*this);
380    }
381    return mDisplayList;
382}
383
384void DisplayListRenderer::setViewport(int width, int height) {
385    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
386
387    mWidth = width;
388    mHeight = height;
389}
390
391void DisplayListRenderer::prepare(bool opaque) {
392    mSnapshot = new Snapshot(mFirstSnapshot,
393            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
394    mSaveCount = 1;
395    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
396}
397
398void DisplayListRenderer::acquireContext() {
399    addOp(DisplayList::AcquireContext);
400    OpenGLRenderer::acquireContext();
401}
402
403void DisplayListRenderer::releaseContext() {
404    addOp(DisplayList::ReleaseContext);
405    OpenGLRenderer::releaseContext();
406}
407
408int DisplayListRenderer::save(int flags) {
409    addOp(DisplayList::Save);
410    addInt(flags);
411    return OpenGLRenderer::save(flags);
412}
413
414void DisplayListRenderer::restore() {
415    addOp(DisplayList::Restore);
416    OpenGLRenderer::restore();
417}
418
419void DisplayListRenderer::restoreToCount(int saveCount) {
420    addOp(DisplayList::RestoreToCount);
421    addInt(saveCount);
422    OpenGLRenderer::restoreToCount(saveCount);
423}
424
425int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
426        SkPaint* p, int flags) {
427    addOp(DisplayList::SaveLayer);
428    addBounds(left, top, right, bottom);
429    addPaint(p);
430    addInt(flags);
431    return OpenGLRenderer::save(flags);
432}
433
434int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
435        int alpha, int flags) {
436    addOp(DisplayList::SaveLayerAlpha);
437    addBounds(left, top, right, bottom);
438    addInt(alpha);
439    addInt(flags);
440    return OpenGLRenderer::save(flags);
441}
442
443void DisplayListRenderer::translate(float dx, float dy) {
444    addOp(DisplayList::Translate);
445    addPoint(dx, dy);
446    OpenGLRenderer::translate(dx, dy);
447}
448
449void DisplayListRenderer::rotate(float degrees) {
450    addOp(DisplayList::Rotate);
451    addFloat(degrees);
452    OpenGLRenderer::rotate(degrees);
453}
454
455void DisplayListRenderer::scale(float sx, float sy) {
456    addOp(DisplayList::Scale);
457    addPoint(sx, sy);
458    OpenGLRenderer::scale(sx, sy);
459}
460
461void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
462    addOp(DisplayList::SetMatrix);
463    addMatrix(matrix);
464    OpenGLRenderer::setMatrix(matrix);
465}
466
467void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
468    addOp(DisplayList::ConcatMatrix);
469    addMatrix(matrix);
470    OpenGLRenderer::concatMatrix(matrix);
471}
472
473bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
474        SkRegion::Op op) {
475    addOp(DisplayList::ClipRect);
476    addBounds(left, top, right, bottom);
477    addInt(op);
478    return OpenGLRenderer::clipRect(left, top, right, bottom, op);
479}
480
481void DisplayListRenderer::drawDisplayList(DisplayList* displayList) {
482    addOp(DisplayList::DrawDisplayList);
483    addDisplayList(displayList);
484}
485
486void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
487        SkPaint* paint) {
488    addOp(DisplayList::DrawBitmap);
489    addBitmap(bitmap);
490    addPoint(left, top);
491    addPaint(paint);
492}
493
494void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
495        SkPaint* paint) {
496    addOp(DisplayList::DrawBitmapMatrix);
497    addBitmap(bitmap);
498    addMatrix(matrix);
499    addPaint(paint);
500}
501
502void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
503        float srcRight, float srcBottom, float dstLeft, float dstTop,
504        float dstRight, float dstBottom, SkPaint* paint) {
505    addOp(DisplayList::DrawBitmapRect);
506    addBitmap(bitmap);
507    addBounds(srcLeft, srcTop, srcRight, srcBottom);
508    addBounds(dstLeft, dstTop, dstRight, dstBottom);
509    addPaint(paint);
510}
511
512void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
513        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
514        float left, float top, float right, float bottom, SkPaint* paint) {
515    addOp(DisplayList::DrawPatch);
516    addBitmap(bitmap);
517    addInts(xDivs, width);
518    addInts(yDivs, height);
519    addUInts(colors, numColors);
520    addBounds(left, top, right, bottom);
521    addPaint(paint);
522}
523
524void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
525    addOp(DisplayList::DrawColor);
526    addInt(color);
527    addInt(mode);
528}
529
530void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
531        SkPaint* paint) {
532    addOp(DisplayList::DrawRect);
533    addBounds(left, top, right, bottom);
534    addPaint(paint);
535}
536
537void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
538    addOp(DisplayList::DrawPath);
539    addPath(path);
540    addPaint(paint);
541}
542
543void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
544    addOp(DisplayList::DrawLines);
545    addFloats(points, count);
546    addPaint(paint);
547}
548
549void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
550        float x, float y, SkPaint* paint) {
551    addOp(DisplayList::DrawText);
552    addText(text, bytesCount);
553    addInt(count);
554    addPoint(x, y);
555    addPaint(paint);
556}
557
558void DisplayListRenderer::resetShader() {
559    addOp(DisplayList::ResetShader);
560}
561
562void DisplayListRenderer::setupShader(SkiaShader* shader) {
563    addOp(DisplayList::SetupShader);
564    addShader(shader);
565}
566
567void DisplayListRenderer::resetColorFilter() {
568    addOp(DisplayList::ResetColorFilter);
569}
570
571void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
572    addOp(DisplayList::SetupColorFilter);
573    addColorFilter(filter);
574}
575
576void DisplayListRenderer::resetShadow() {
577    addOp(DisplayList::ResetShadow);
578}
579
580void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
581    addOp(DisplayList::SetupShadow);
582    addFloat(radius);
583    addPoint(dx, dy);
584    addInt(color);
585}
586
587}; // namespace uirenderer
588}; // namespace android
589