blob: 1baf720b1e7b838e948dc4a0035fc31c8db8893e [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#include <stdlib.h>
18#include <stdint.h>
19#include <math.h>
20#include <sys/types.h>
21
22#include <utils/Errors.h>
23#include <utils/Log.h>
24#include <utils/StopWatch.h>
25
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080026#include <ui/PixelFormat.h>
Mathias Agopian69029eb2009-06-23 21:11:43 -070027#include <ui/FramebufferNativeWindow.h>
28
29#include <hardware/copybit.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080030
31#include "LayerBuffer.h"
32#include "SurfaceFlinger.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080033#include "DisplayHardware/DisplayHardware.h"
34
35
36namespace android {
37
38// ---------------------------------------------------------------------------
39
40const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
41const char* const LayerBuffer::typeID = "LayerBuffer";
42
43// ---------------------------------------------------------------------------
44
45LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
Mathias Agopianf9d93272009-06-19 17:00:27 -070046 const sp<Client>& client, int32_t i)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080047 : LayerBaseClient(flinger, display, client, i),
48 mNeedsBlending(false)
49{
50}
51
52LayerBuffer::~LayerBuffer()
53{
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080054}
55
Mathias Agopian9a112062009-04-17 19:36:26 -070056void LayerBuffer::onFirstRef()
57{
Mathias Agopian2e123242009-06-23 20:06:46 -070058 LayerBaseClient::onFirstRef();
Mathias Agopian9a112062009-04-17 19:36:26 -070059 mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
60 const_cast<LayerBuffer *>(this));
61}
62
Mathias Agopian076b1cc2009-04-10 14:24:30 -070063sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080064{
Mathias Agopian9a112062009-04-17 19:36:26 -070065 return mSurface;
66}
67
68status_t LayerBuffer::ditch()
69{
70 mSurface.clear();
71 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080072}
73
74bool LayerBuffer::needsBlending() const {
75 return mNeedsBlending;
76}
77
78void LayerBuffer::setNeedsBlending(bool blending) {
79 mNeedsBlending = blending;
80}
81
82void LayerBuffer::postBuffer(ssize_t offset)
83{
84 sp<Source> source(getSource());
85 if (source != 0)
86 source->postBuffer(offset);
87}
88
89void LayerBuffer::unregisterBuffers()
90{
91 sp<Source> source(clearSource());
92 if (source != 0)
93 source->unregisterBuffers();
94}
95
96uint32_t LayerBuffer::doTransaction(uint32_t flags)
97{
98 sp<Source> source(getSource());
99 if (source != 0)
100 source->onTransaction(flags);
101 return LayerBase::doTransaction(flags);
102}
103
104void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
105 Region& outDirtyRegion)
106{
107 // this code-path must be as tight as possible, it's called each time
108 // the screen is composited.
109 sp<Source> source(getSource());
110 if (source != 0)
111 source->onVisibilityResolved(planeTransform);
112 LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
113}
114
115void LayerBuffer::onDraw(const Region& clip) const
116{
117 sp<Source> source(getSource());
118 if (LIKELY(source != 0)) {
119 source->onDraw(clip);
120 } else {
121 clearWithOpenGL(clip);
122 }
123}
124
125bool LayerBuffer::transformed() const
126{
127 sp<Source> source(getSource());
128 if (LIKELY(source != 0))
129 return source->transformed();
130 return false;
131}
132
133/**
134 * This creates a "buffer" source for this surface
135 */
136status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
137{
138 Mutex::Autolock _l(mLock);
139 if (mSource != 0)
140 return INVALID_OPERATION;
141
142 sp<BufferSource> source = new BufferSource(*this, buffers);
143
144 status_t result = source->getStatus();
145 if (result == NO_ERROR) {
146 mSource = source;
147 }
148 return result;
149}
150
151/**
152 * This creates an "overlay" source for this surface
153 */
154sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
155{
156 sp<OverlayRef> result;
157 Mutex::Autolock _l(mLock);
158 if (mSource != 0)
159 return result;
160
161 sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f);
162 if (result != 0) {
163 mSource = source;
164 }
165 return result;
166}
167
168sp<LayerBuffer::Source> LayerBuffer::getSource() const {
169 Mutex::Autolock _l(mLock);
170 return mSource;
171}
172
173sp<LayerBuffer::Source> LayerBuffer::clearSource() {
174 sp<Source> source;
175 Mutex::Autolock _l(mLock);
176 source = mSource;
177 mSource.clear();
178 return source;
179}
180
181// ============================================================================
182// LayerBuffer::SurfaceBuffer
183// ============================================================================
184
Mathias Agopian9a112062009-04-17 19:36:26 -0700185LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
186 SurfaceID id, const sp<LayerBuffer>& owner)
187 : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800188{
189}
190
191LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
192{
193 unregisterBuffers();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800194}
195
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700196status_t LayerBuffer::SurfaceBuffer::registerBuffers(
197 const ISurface::BufferHeap& buffers)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800198{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700199 sp<LayerBuffer> owner(getOwner());
200 if (owner != 0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800201 return owner->registerBuffers(buffers);
202 return NO_INIT;
203}
204
205void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
206{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700207 sp<LayerBuffer> owner(getOwner());
208 if (owner != 0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800209 owner->postBuffer(offset);
210}
211
212void LayerBuffer::SurfaceBuffer::unregisterBuffers()
213{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700214 sp<LayerBuffer> owner(getOwner());
215 if (owner != 0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800216 owner->unregisterBuffers();
217}
218
219sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
220 uint32_t w, uint32_t h, int32_t format) {
221 sp<OverlayRef> result;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700222 sp<LayerBuffer> owner(getOwner());
223 if (owner != 0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800224 result = owner->createOverlay(w, h, format);
225 return result;
226}
227
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800228// ============================================================================
229// LayerBuffer::Buffer
230// ============================================================================
231
232LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
233 : mBufferHeap(buffers)
234{
235 NativeBuffer& src(mNativeBuffer);
236 src.crop.l = 0;
237 src.crop.t = 0;
238 src.crop.r = buffers.w;
239 src.crop.b = buffers.h;
240 src.img.w = buffers.hor_stride ?: buffers.w;
241 src.img.h = buffers.ver_stride ?: buffers.h;
242 src.img.format = buffers.format;
243 src.img.offset = offset;
244 src.img.base = buffers.heap->base();
245 src.img.fd = buffers.heap->heapID();
246}
247
248LayerBuffer::Buffer::~Buffer()
249{
250}
251
252// ============================================================================
253// LayerBuffer::Source
254// LayerBuffer::BufferSource
255// LayerBuffer::OverlaySource
256// ============================================================================
257
258LayerBuffer::Source::Source(LayerBuffer& layer)
259 : mLayer(layer)
260{
261}
262LayerBuffer::Source::~Source() {
263}
264void LayerBuffer::Source::onDraw(const Region& clip) const {
265}
266void LayerBuffer::Source::onTransaction(uint32_t flags) {
267}
268void LayerBuffer::Source::onVisibilityResolved(
269 const Transform& planeTransform) {
270}
271void LayerBuffer::Source::postBuffer(ssize_t offset) {
272}
273void LayerBuffer::Source::unregisterBuffers() {
274}
275bool LayerBuffer::Source::transformed() const {
276 return mLayer.mTransformed;
277}
278
279// ---------------------------------------------------------------------------
280
281LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
282 const ISurface::BufferHeap& buffers)
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700283 : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800284{
285 if (buffers.heap == NULL) {
286 // this is allowed, but in this case, it is illegal to receive
287 // postBuffer(). The surface just erases the framebuffer with
288 // fully transparent pixels.
289 mBufferHeap = buffers;
290 mLayer.setNeedsBlending(false);
291 return;
292 }
293
294 status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
295 if (err != NO_ERROR) {
296 LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
297 mStatus = err;
298 return;
299 }
300
301 PixelFormatInfo info;
302 err = getPixelFormatInfo(buffers.format, &info);
303 if (err != NO_ERROR) {
304 LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
305 buffers.format, strerror(err));
306 mStatus = err;
307 return;
308 }
309
310 if (buffers.hor_stride<0 || buffers.ver_stride<0) {
311 LOGE("LayerBuffer::BufferSource: invalid parameters "
312 "(w=%d, h=%d, xs=%d, ys=%d)",
313 buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
314 mStatus = BAD_VALUE;
315 return;
316 }
317
318 mBufferHeap = buffers;
319 mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
320 mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
321 mLayer.forceVisibilityTransaction();
Mathias Agopian69029eb2009-06-23 21:11:43 -0700322
323 hw_module_t const* module;
324 mBlitEngine = NULL;
325 if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
326 copybit_open(module, &mBlitEngine);
327 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800328}
329
330LayerBuffer::BufferSource::~BufferSource()
331{
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700332 if (mTexture.name != -1U) {
333 glDeleteTextures(1, &mTexture.name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800334 }
335}
336
337void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
338{
339 ISurface::BufferHeap buffers;
340 { // scope for the lock
341 Mutex::Autolock _l(mLock);
342 buffers = mBufferHeap;
343 if (buffers.heap != 0) {
344 const size_t memorySize = buffers.heap->getSize();
345 if ((size_t(offset) + mBufferSize) > memorySize) {
346 LOGE("LayerBuffer::BufferSource::postBuffer() "
347 "invalid buffer (offset=%d, size=%d, heap-size=%d",
348 int(offset), int(mBufferSize), int(memorySize));
349 return;
350 }
351 }
352 }
353
354 sp<Buffer> buffer;
355 if (buffers.heap != 0) {
356 buffer = new LayerBuffer::Buffer(buffers, offset);
357 if (buffer->getStatus() != NO_ERROR)
358 buffer.clear();
359 setBuffer(buffer);
360 mLayer.invalidate();
361 }
362}
363
364void LayerBuffer::BufferSource::unregisterBuffers()
365{
366 Mutex::Autolock _l(mLock);
367 mBufferHeap.heap.clear();
368 mBuffer.clear();
369 mLayer.invalidate();
370}
371
372sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
373{
374 Mutex::Autolock _l(mLock);
375 return mBuffer;
376}
377
378void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
379{
380 Mutex::Autolock _l(mLock);
381 mBuffer = buffer;
382}
383
384bool LayerBuffer::BufferSource::transformed() const
385{
386 return mBufferHeap.transform ? true : Source::transformed();
387}
388
389void LayerBuffer::BufferSource::onDraw(const Region& clip) const
390{
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700391 sp<Buffer> ourBuffer(getBuffer());
392 if (UNLIKELY(ourBuffer == 0)) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800393 // nothing to do, we don't have a buffer
394 mLayer.clearWithOpenGL(clip);
395 return;
396 }
397
Mathias Agopian69029eb2009-06-23 21:11:43 -0700398 status_t err = NO_ERROR;
399 NativeBuffer src(ourBuffer->getBuffer());
400 const Rect& transformedBounds = mLayer.getTransformedBounds();
401 copybit_device_t* copybit = mBlitEngine;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800402
Mathias Agopian69029eb2009-06-23 21:11:43 -0700403 if (copybit) {
404 const int src_width = src.crop.r - src.crop.l;
405 const int src_height = src.crop.b - src.crop.t;
406 int W = transformedBounds.width();
407 int H = transformedBounds.height();
408 if (mLayer.getOrientation() & Transform::ROT_90) {
409 int t(W); W=H; H=t;
410 }
411
412#if 0
413 /* With LayerBuffer, it is likely that we'll have to rescale the
414 * surface, because this is often used for video playback or
415 * camera-preview. Since we want these operation as fast as possible
416 * we make sure we can use the 2D H/W even if it doesn't support
417 * the requested scale factor, in which case we perform the scaling
418 * in several passes. */
419
420 const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
421 const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
422
423 float xscale = 1.0f;
424 if (src_width > W*min) xscale = 1.0f / min;
425 else if (src_width*mag < W) xscale = mag;
426
427 float yscale = 1.0f;
428 if (src_height > H*min) yscale = 1.0f / min;
429 else if (src_height*mag < H) yscale = mag;
430
431 if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
432 if (UNLIKELY(mTemporaryDealer == 0)) {
433 // allocate a memory-dealer for this the first time
434 mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
435 ->createHeap(ISurfaceComposer::eHardware);
436 mTempBitmap.init(mTemporaryDealer);
437 }
438
439 const int tmp_w = floorf(src_width * xscale);
440 const int tmp_h = floorf(src_height * yscale);
441 err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
442
443 if (LIKELY(err == NO_ERROR)) {
444 NativeBuffer tmp;
445 mTempBitmap.getBitmapSurface(&tmp.img);
446 tmp.crop.l = 0;
447 tmp.crop.t = 0;
448 tmp.crop.r = tmp.img.w;
449 tmp.crop.b = tmp.img.h;
450
451 region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
452 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
453 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
454 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
455 err = copybit->stretch(copybit,
456 &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
457 src = tmp;
458 }
459 }
460#endif
461
462 copybit_image_t dst;
463 const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
464 sp<FramebufferNativeWindow> fbw = hw.getFb();
465 android_native_buffer_t const* nb = fbw->getBackbuffer();
466 native_handle_t const* hnd = nb->handle;
467
468 if (hnd->data[1] != 0x3141592) {
469 LOGE("buffer not compatible with copybit");
470 err = -1;
471 } else {
472
473 dst.w = 320;
474 dst.h = 480;
475 dst.format = 4;
476 dst.offset = hnd->data[4];
477 dst.base = 0;
478 dst.fd = hnd->data[0];
479
480 const Rect& transformedBounds = mLayer.getTransformedBounds();
481 const copybit_rect_t& drect
482 = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
483 const State& s(mLayer.drawingState());
484 region_iterator it(clip);
485
486 // pick the right orientation for this buffer
487 int orientation = mLayer.getOrientation();
488 if (UNLIKELY(mBufferHeap.transform)) {
489 Transform rot90;
490 GraphicPlane::orientationToTransfrom(
491 ISurfaceComposer::eOrientation90, 0, 0, &rot90);
492 const Transform& planeTransform(mLayer.graphicPlane(0).transform());
493 const Layer::State& s(mLayer.drawingState());
494 Transform tr(planeTransform * s.transform * rot90);
495 orientation = tr.getOrientation();
496 }
497
498 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
499 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
500 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
501
502 err = copybit->stretch(copybit,
503 &dst, &src.img, &drect, &src.crop, &it);
504 if (err != NO_ERROR) {
505 LOGE("copybit failed (%s)", strerror(err));
506 }
507 }
508 }
509
510 if (!copybit || err)
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700511 {
512 // OpenGL fall-back
513 if (UNLIKELY(mTexture.name == -1LU)) {
514 mTexture.name = mLayer.createTexture();
515 }
Mathias Agopian0926f502009-05-04 14:17:04 -0700516 GLuint w = 0;
517 GLuint h = 0;
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700518 GGLSurface t;
519 t.version = sizeof(GGLSurface);
520 t.width = src.crop.r;
521 t.height = src.crop.b;
522 t.stride = src.img.w;
523 t.vstride= src.img.h;
524 t.format = src.img.format;
525 t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
526 const Region dirty(Rect(t.width, t.height));
527 mLayer.loadTexture(&mTexture, mTexture.name, dirty, t);
528 mTexture.transform = mBufferHeap.transform;
529 mLayer.drawWithOpenGL(clip, mTexture);
Mathias Agopian0926f502009-05-04 14:17:04 -0700530 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800531}
532
533
534// ---------------------------------------------------------------------------
535
536LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
537 sp<OverlayRef>* overlayRef,
538 uint32_t w, uint32_t h, int32_t format)
539 : Source(layer), mVisibilityChanged(false),
540 mOverlay(0), mOverlayHandle(0), mOverlayDevice(0)
541{
542 overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
543 if (overlay_dev == NULL) {
544 // overlays not supported
545 return;
546 }
547
548 mOverlayDevice = overlay_dev;
549 overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
550 if (overlay == NULL) {
551 // couldn't create the overlay (no memory? no more overlays?)
552 return;
553 }
554
555 // enable dithering...
556 overlay_dev->setParameter(overlay_dev, overlay,
557 OVERLAY_DITHER, OVERLAY_ENABLE);
558
559 mOverlay = overlay;
560 mWidth = overlay->w;
561 mHeight = overlay->h;
562 mFormat = overlay->format;
563 mWidthStride = overlay->w_stride;
564 mHeightStride = overlay->h_stride;
565
566 mOverlayHandle = overlay->getHandleRef(overlay);
567
568 // NOTE: here it's okay to acquire a reference to "this"m as long as
569 // the reference is not released before we leave the ctor.
570 sp<OverlayChannel> channel = new OverlayChannel(this);
571
572 *overlayRef = new OverlayRef(mOverlayHandle, channel,
573 mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
574}
575
576LayerBuffer::OverlaySource::~OverlaySource()
577{
578 if (mOverlay && mOverlayDevice) {
579 overlay_control_device_t* overlay_dev = mOverlayDevice;
580 overlay_dev->destroyOverlay(overlay_dev, mOverlay);
581 }
582}
583
584void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
585{
586 const Layer::State& front(mLayer.drawingState());
587 const Layer::State& temp(mLayer.currentState());
588 if (temp.sequence != front.sequence) {
589 mVisibilityChanged = true;
590 }
591}
592
593void LayerBuffer::OverlaySource::onVisibilityResolved(
594 const Transform& planeTransform)
595{
596 // this code-path must be as tight as possible, it's called each time
597 // the screen is composited.
598 if (UNLIKELY(mOverlay != 0)) {
599 if (mVisibilityChanged) {
600 mVisibilityChanged = false;
601 const Rect& bounds = mLayer.getTransformedBounds();
602 int x = bounds.left;
603 int y = bounds.top;
604 int w = bounds.width();
605 int h = bounds.height();
606
607 // we need a lock here to protect "destroy"
608 Mutex::Autolock _l(mLock);
609 if (mOverlay) {
610 overlay_control_device_t* overlay_dev = mOverlayDevice;
611 overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
612 overlay_dev->setParameter(overlay_dev, mOverlay,
613 OVERLAY_TRANSFORM, mLayer.getOrientation());
614 }
615 }
616 }
617}
618
619void LayerBuffer::OverlaySource::serverDestroy()
620{
621 mLayer.clearSource();
622 destroyOverlay();
623}
624
625void LayerBuffer::OverlaySource::destroyOverlay()
626{
627 // we need a lock here to protect "onVisibilityResolved"
628 Mutex::Autolock _l(mLock);
629 if (mOverlay) {
630 overlay_control_device_t* overlay_dev = mOverlayDevice;
631 overlay_dev->destroyOverlay(overlay_dev, mOverlay);
632 mOverlay = 0;
633 }
634}
635
636// ---------------------------------------------------------------------------
637}; // namespace android