OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / services / surfaceflinger / LayerBuffer.cpp
1 /*
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
17 #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
26 #include <ui/GraphicBuffer.h>
27 #include <ui/PixelFormat.h>
28 #include <ui/FramebufferNativeWindow.h>
29 #include <ui/Rect.h>
30 #include <ui/Region.h>
31
32 #include <hardware/copybit.h>
33
34 #include "LayerBuffer.h"
35 #include "SurfaceFlinger.h"
36 #include "DisplayHardware/DisplayHardware.h"
37
38 namespace android {
39
40 // ---------------------------------------------------------------------------
41
42 gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
43
44 // ---------------------------------------------------------------------------
45
46 LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
47         const sp<Client>& client)
48     : LayerBaseClient(flinger, display, client),
49       mNeedsBlending(false), mBlitEngine(0)
50 {
51 }
52
53 LayerBuffer::~LayerBuffer()
54 {
55     if (mBlitEngine) {
56         copybit_close(mBlitEngine);
57     }
58 }
59
60 void LayerBuffer::onFirstRef()
61 {
62     LayerBaseClient::onFirstRef();
63     mSurface = new SurfaceLayerBuffer(mFlinger, this);
64
65     hw_module_t const* module = (hw_module_t const*)sGrallocModule;
66     if (!module) {
67         // NOTE: technically there is a race here, but it shouldn't
68         // cause any problem since hw_get_module() always returns
69         // the same value.
70         if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
71             sGrallocModule = (gralloc_module_t const *)module;
72         }
73     }
74
75     if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
76         copybit_open(module, &mBlitEngine);
77     }
78 }
79
80 sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
81 {
82     return mSurface;
83 }
84
85 status_t LayerBuffer::ditch()
86 {
87     mSurface.clear();
88     return NO_ERROR;
89 }
90
91 bool LayerBuffer::needsBlending() const {
92     return mNeedsBlending;
93 }
94
95 void LayerBuffer::setNeedsBlending(bool blending) {
96     mNeedsBlending = blending;
97 }
98
99 void LayerBuffer::postBuffer(ssize_t offset)
100 {
101     sp<Source> source(getSource());
102     if (source != 0)
103         source->postBuffer(offset);
104 }
105
106 void LayerBuffer::unregisterBuffers()
107 {
108     sp<Source> source(clearSource());
109     if (source != 0)
110         source->unregisterBuffers();
111 }
112
113 uint32_t LayerBuffer::doTransaction(uint32_t flags)
114 {
115     sp<Source> source(getSource());
116     if (source != 0)
117         source->onTransaction(flags);
118     uint32_t res = LayerBase::doTransaction(flags);
119     // we always want filtering for these surfaces
120     mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
121     return res;
122 }
123
124 void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
125         Region& outDirtyRegion)
126 {
127     // this code-path must be as tight as possible, it's called each time
128     // the screen is composited.
129     sp<Source> source(getSource());
130     if (source != 0)
131         source->onVisibilityResolved(planeTransform);
132     LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);    
133 }
134
135 void LayerBuffer::validateVisibility(const Transform& globalTransform)
136 {
137     sp<Source> source(getSource());
138     if (source != 0)
139         source->onvalidateVisibility(globalTransform);
140     LayerBase::validateVisibility(globalTransform);
141 }
142
143 void LayerBuffer::drawForSreenShot() const
144 {
145     const DisplayHardware& hw(graphicPlane(0).displayHardware());
146     clearWithOpenGL( Region(hw.bounds()) );
147 }
148
149 void LayerBuffer::onDraw(const Region& clip) const
150 {
151     sp<Source> source(getSource());
152     if (LIKELY(source != 0)) {
153         source->onDraw(clip);
154     } else {
155         clearWithOpenGL(clip);
156     }
157 }
158
159 void LayerBuffer::serverDestroy()
160 {
161     sp<Source> source(clearSource());
162     if (source != 0) {
163         source->destroy();
164     }
165 }
166
167 /**
168  * This creates a "buffer" source for this surface
169  */
170 status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
171 {
172     Mutex::Autolock _l(mLock);
173     if (mSource != 0)
174         return INVALID_OPERATION;
175
176     sp<BufferSource> source = new BufferSource(*this, buffers);
177
178     status_t result = source->getStatus();
179     if (result == NO_ERROR) {
180         mSource = source;
181     }
182     return result;
183 }    
184
185 /**
186  * This creates an "overlay" source for this surface
187  */
188 sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f,
189         int32_t orientation)
190 {
191     sp<OverlayRef> result;
192     Mutex::Autolock _l(mLock);
193     if (mSource != 0)
194         return result;
195
196     sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation);
197     if (result != 0) {
198         mSource = source;
199     }
200     return result;
201 }
202
203 sp<LayerBuffer::Source> LayerBuffer::getSource() const {
204     Mutex::Autolock _l(mLock);
205     return mSource;
206 }
207
208 sp<LayerBuffer::Source> LayerBuffer::clearSource() {
209     sp<Source> source;
210     Mutex::Autolock _l(mLock);
211     source = mSource;
212     mSource.clear();
213     return source;
214 }
215
216 // ============================================================================
217 // LayerBuffer::SurfaceLayerBuffer
218 // ============================================================================
219
220 LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(
221         const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner)
222     : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner)
223 {
224 }
225
226 LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
227 {
228     unregisterBuffers();
229 }
230
231 status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
232         const ISurface::BufferHeap& buffers)
233 {
234     sp<LayerBuffer> owner(getOwner());
235     if (owner != 0)
236         return owner->registerBuffers(buffers);
237     return NO_INIT;
238 }
239
240 void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
241 {
242     sp<LayerBuffer> owner(getOwner());
243     if (owner != 0)
244         owner->postBuffer(offset);
245 }
246
247 void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
248 {
249     sp<LayerBuffer> owner(getOwner());
250     if (owner != 0)
251         owner->unregisterBuffers();
252 }
253
254 sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
255         uint32_t w, uint32_t h, int32_t format, int32_t orientation) {
256     sp<OverlayRef> result;
257     sp<LayerBuffer> owner(getOwner());
258     if (owner != 0)
259         result = owner->createOverlay(w, h, format, orientation);
260     return result;
261 }
262
263 // ============================================================================
264 // LayerBuffer::Buffer
265 // ============================================================================
266
267 LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers,
268         ssize_t offset, size_t bufferSize)
269     : mBufferHeap(buffers), mSupportsCopybit(false)
270 {
271     NativeBuffer& src(mNativeBuffer);
272     src.crop.l = 0;
273     src.crop.t = 0;
274     src.crop.r = buffers.w;
275     src.crop.b = buffers.h;
276
277     src.img.w       = buffers.hor_stride ?: buffers.w;
278     src.img.h       = buffers.ver_stride ?: buffers.h;
279     src.img.format  = buffers.format;
280     src.img.base    = (void*)(intptr_t(buffers.heap->base()) + offset);
281     src.img.handle  = 0;
282
283     gralloc_module_t const * module = LayerBuffer::getGrallocModule();
284     if (module && module->perform) {
285         int err = module->perform(module,
286                 GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
287                 buffers.heap->heapID(), bufferSize,
288                 offset, buffers.heap->base(),
289                 &src.img.handle);
290
291         // we can fail here is the passed buffer is purely software
292         mSupportsCopybit = (err == NO_ERROR);
293     }
294  }
295
296 LayerBuffer::Buffer::~Buffer()
297 {
298     NativeBuffer& src(mNativeBuffer);
299     if (src.img.handle) {
300         native_handle_delete(src.img.handle);
301     }
302 }
303
304 // ============================================================================
305 // LayerBuffer::Source
306 // LayerBuffer::BufferSource
307 // LayerBuffer::OverlaySource
308 // ============================================================================
309
310 LayerBuffer::Source::Source(LayerBuffer& layer)
311     : mLayer(layer)
312 {    
313 }
314 LayerBuffer::Source::~Source() {    
315 }
316 void LayerBuffer::Source::onDraw(const Region& clip) const {
317 }
318 void LayerBuffer::Source::onTransaction(uint32_t flags) {
319 }
320 void LayerBuffer::Source::onVisibilityResolved(
321         const Transform& planeTransform) {
322 }
323 void LayerBuffer::Source::postBuffer(ssize_t offset) {
324 }
325 void LayerBuffer::Source::unregisterBuffers() {
326 }
327
328 // ---------------------------------------------------------------------------
329
330 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
331         const ISurface::BufferHeap& buffers)
332     : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
333 {
334     if (buffers.heap == NULL) {
335         // this is allowed, but in this case, it is illegal to receive
336         // postBuffer(). The surface just erases the framebuffer with
337         // fully transparent pixels.
338         mBufferHeap = buffers;
339         mLayer.setNeedsBlending(false);
340         return;
341     }
342
343     status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
344     if (err != NO_ERROR) {
345         LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
346         mStatus = err;
347         return;
348     }
349     
350     PixelFormatInfo info;
351     err = getPixelFormatInfo(buffers.format, &info);
352     if (err != NO_ERROR) {
353         LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
354                 buffers.format, strerror(err));
355         mStatus = err;
356         return;
357     }
358
359     if (buffers.hor_stride<0 || buffers.ver_stride<0) {
360         LOGE("LayerBuffer::BufferSource: invalid parameters "
361              "(w=%d, h=%d, xs=%d, ys=%d)", 
362              buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
363         mStatus = BAD_VALUE;
364         return;
365     }
366
367     mBufferHeap = buffers;
368     mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
369     mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
370     mLayer.forceVisibilityTransaction();
371 }
372
373 LayerBuffer::BufferSource::~BufferSource()
374 {    
375     class MessageDestroyTexture : public MessageBase {
376         SurfaceFlinger* flinger;
377         GLuint name;
378     public:
379         MessageDestroyTexture(
380                 SurfaceFlinger* flinger, GLuint name)
381             : flinger(flinger), name(name) { }
382         virtual bool handler() {
383             glDeleteTextures(1, &name);
384             return true;
385         }
386     };
387
388     if (mTexture.name != -1U) {
389         // GL textures can only be destroyed from the GL thread
390         getFlinger()->mEventQueue.postMessage(
391                 new MessageDestroyTexture(getFlinger(), mTexture.name) );
392     }
393     if (mTexture.image != EGL_NO_IMAGE_KHR) {
394         EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
395         eglDestroyImageKHR(dpy, mTexture.image);
396     }
397 }
398
399 void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
400 {    
401     ISurface::BufferHeap buffers;
402     { // scope for the lock
403         Mutex::Autolock _l(mBufferSourceLock);
404         buffers = mBufferHeap;
405         if (buffers.heap != 0) {
406             const size_t memorySize = buffers.heap->getSize();
407             if ((size_t(offset) + mBufferSize) > memorySize) {
408                 LOGE("LayerBuffer::BufferSource::postBuffer() "
409                      "invalid buffer (offset=%d, size=%d, heap-size=%d",
410                      int(offset), int(mBufferSize), int(memorySize));
411                 return;
412             }
413         }
414     }
415
416     sp<Buffer> buffer;
417     if (buffers.heap != 0) {
418         buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
419         if (buffer->getStatus() != NO_ERROR)
420             buffer.clear();
421         setBuffer(buffer);
422         mLayer.invalidate();
423     }
424 }
425
426 void LayerBuffer::BufferSource::unregisterBuffers()
427 {
428     Mutex::Autolock _l(mBufferSourceLock);
429     mBufferHeap.heap.clear();
430     mBuffer.clear();
431     mLayer.invalidate();
432 }
433
434 sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
435 {
436     Mutex::Autolock _l(mBufferSourceLock);
437     return mBuffer;
438 }
439
440 void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
441 {
442     Mutex::Autolock _l(mBufferSourceLock);
443     mBuffer = buffer;
444 }
445
446 void LayerBuffer::BufferSource::onDraw(const Region& clip) const 
447 {
448     sp<Buffer> ourBuffer(getBuffer());
449     if (UNLIKELY(ourBuffer == 0))  {
450         // nothing to do, we don't have a buffer
451         mLayer.clearWithOpenGL(clip);
452         return;
453     }
454
455     status_t err = NO_ERROR;
456     NativeBuffer src(ourBuffer->getBuffer());
457     const Rect transformedBounds(mLayer.getTransformedBounds());
458
459 #if defined(EGL_ANDROID_image_native_buffer)
460     if (GLExtensions::getInstance().haveDirectTexture()) {
461         err = INVALID_OPERATION;
462         if (ourBuffer->supportsCopybit()) {
463             copybit_device_t* copybit = mLayer.mBlitEngine;
464             if (copybit && err != NO_ERROR) {
465                 // create our EGLImageKHR the first time
466                 err = initTempBuffer();
467                 if (err == NO_ERROR) {
468                     // NOTE: Assume the buffer is allocated with the proper USAGE flags
469                     const NativeBuffer& dst(mTempBuffer);
470                     region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
471                     copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
472                     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
473                     copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
474                     err = copybit->stretch(copybit, &dst.img, &src.img,
475                             &dst.crop, &src.crop, &clip);
476                     if (err != NO_ERROR) {
477                         clearTempBufferImage();
478                     }
479                 }
480             }
481         }
482     }
483 #endif
484     else {
485         err = INVALID_OPERATION;
486     }
487
488     if (err != NO_ERROR) {
489         // slower fallback
490         GGLSurface t;
491         t.version = sizeof(GGLSurface);
492         t.width  = src.crop.r;
493         t.height = src.crop.b;
494         t.stride = src.img.w;
495         t.vstride= src.img.h;
496         t.format = src.img.format;
497         t.data = (GGLubyte*)src.img.base;
498         const Region dirty(Rect(t.width, t.height));
499         mTextureManager.loadTexture(&mTexture, dirty, t);
500     }
501
502     mLayer.setBufferTransform(mBufferHeap.transform);
503     mLayer.drawWithOpenGL(clip, mTexture);
504 }
505
506 status_t LayerBuffer::BufferSource::initTempBuffer() const
507 {
508     // figure out the size we need now
509     const ISurface::BufferHeap& buffers(mBufferHeap);
510     uint32_t w = mLayer.mTransformedBounds.width();
511     uint32_t h = mLayer.mTransformedBounds.height();
512     if (buffers.w * h != buffers.h * w) {
513         int t = w; w = h; h = t;
514     }
515
516     // we're in the copybit case, so make sure we can handle this blit
517     // we don't have to keep the aspect ratio here
518     copybit_device_t* copybit = mLayer.mBlitEngine;
519     const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
520     const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
521     if (buffers.w > w*down)     w = buffers.w / down;
522     else if (w > buffers.w*up)  w = buffers.w*up;
523     if (buffers.h > h*down)     h = buffers.h / down;
524     else if (h > buffers.h*up)  h = buffers.h*up;
525
526     if (mTexture.image != EGL_NO_IMAGE_KHR) {
527         // we have an EGLImage, make sure the needed size didn't change
528         if (w!=mTexture.width || h!= mTexture.height) {
529             // delete the EGLImage and texture
530             clearTempBufferImage();
531         } else {
532             // we're good, we have an EGLImageKHR and it's (still) the
533             // right size
534             return NO_ERROR;
535         }
536     }
537
538     // figure out if we need linear filtering
539     if (buffers.w * h == buffers.h * w) {
540         // same pixel area, don't use filtering
541         mLayer.mNeedsFiltering = false;
542     }
543
544     // Allocate a temporary buffer and create the corresponding EGLImageKHR
545     // once the EGLImage has been created we don't need the
546     // graphic buffer reference anymore.
547     sp<GraphicBuffer> buffer = new GraphicBuffer(
548             w, h, HAL_PIXEL_FORMAT_RGB_565,
549             GraphicBuffer::USAGE_HW_TEXTURE |
550             GraphicBuffer::USAGE_HW_2D);
551
552     status_t err = buffer->initCheck();
553     if (err == NO_ERROR) {
554         NativeBuffer& dst(mTempBuffer);
555         dst.img.w = buffer->getStride();
556         dst.img.h = h;
557         dst.img.format = buffer->getPixelFormat();
558         dst.img.handle = (native_handle_t *)buffer->handle;
559         dst.img.base = 0;
560         dst.crop.l = 0;
561         dst.crop.t = 0;
562         dst.crop.r = w;
563         dst.crop.b = h;
564
565         EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
566         err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
567     }
568
569     return err;
570 }
571
572 void LayerBuffer::BufferSource::clearTempBufferImage() const
573 {
574     // delete the image
575     EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
576     eglDestroyImageKHR(dpy, mTexture.image);
577
578     // and the associated texture (recreate a name)
579     glDeleteTextures(1, &mTexture.name);
580     Texture defaultTexture;
581     mTexture = defaultTexture;
582 }
583
584 // ---------------------------------------------------------------------------
585
586 LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
587         sp<OverlayRef>* overlayRef, 
588         uint32_t w, uint32_t h, int32_t format, int32_t orientation)
589     : Source(layer), mVisibilityChanged(false),
590     mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
591 {
592     overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine();
593     if (overlay_dev == NULL) {
594         // overlays not supported
595         return;
596     }
597
598     mOverlayDevice = overlay_dev;
599     overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
600     if (overlay == NULL) {
601         // couldn't create the overlay (no memory? no more overlays?)
602         return;
603     }
604
605     // enable dithering...
606     overlay_dev->setParameter(overlay_dev, overlay, 
607             OVERLAY_DITHER, OVERLAY_ENABLE);
608
609     mOverlay = overlay;
610     mWidth = overlay->w;
611     mHeight = overlay->h;
612     mFormat = overlay->format; 
613     mWidthStride = overlay->w_stride;
614     mHeightStride = overlay->h_stride;
615     mInitialized = false;
616
617     mOverlayHandle = overlay->getHandleRef(overlay);
618     
619     sp<OverlayChannel> channel = new OverlayChannel( &layer );
620
621     *overlayRef = new OverlayRef(mOverlayHandle, channel,
622             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
623     getFlinger()->signalEvent();
624 }
625
626 LayerBuffer::OverlaySource::~OverlaySource()
627 {
628     if (mOverlay && mOverlayDevice) {
629         overlay_control_device_t* overlay_dev = mOverlayDevice;
630         overlay_dev->destroyOverlay(overlay_dev, mOverlay);
631     }
632 }
633
634 void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
635 {
636     // this would be where the color-key would be set, should we need it.
637     GLclampf red = 0;
638     GLclampf green = 0;
639     GLclampf blue = 0;
640     mLayer.clearWithOpenGL(clip, red, green, blue, 0);
641 }
642
643 void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
644 {
645     const Layer::State& front(mLayer.drawingState());
646     const Layer::State& temp(mLayer.currentState());
647     if (temp.sequence != front.sequence) {
648         mVisibilityChanged = true;
649     }
650 }
651
652 void LayerBuffer::OverlaySource::onvalidateVisibility(const Transform&)
653 {
654     mVisibilityChanged = true;
655 }
656
657 void LayerBuffer::OverlaySource::onVisibilityResolved(
658         const Transform& planeTransform)
659 {
660     // this code-path must be as tight as possible, it's called each time
661     // the screen is composited.
662     if (UNLIKELY(mOverlay != 0)) {
663         if (mVisibilityChanged || !mInitialized) {
664             mVisibilityChanged = false;
665             mInitialized = true;
666             const Rect bounds(mLayer.getTransformedBounds());
667             int x = bounds.left;
668             int y = bounds.top;
669             int w = bounds.width();
670             int h = bounds.height();
671             
672             // we need a lock here to protect "destroy"
673             Mutex::Autolock _l(mOverlaySourceLock);
674             if (mOverlay) {
675                 overlay_control_device_t* overlay_dev = mOverlayDevice;
676                 overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
677                 // we need to combine the layer orientation and the
678                 // user-requested orientation.
679                 Transform finalTransform(Transform(mLayer.getOrientation()) *
680                         Transform(mOrientation));
681                 overlay_dev->setParameter(overlay_dev, mOverlay,
682                         OVERLAY_TRANSFORM, finalTransform.getOrientation());
683                 overlay_dev->commit(overlay_dev, mOverlay);
684             }
685         }
686     }
687 }
688
689 void LayerBuffer::OverlaySource::destroy()
690 {
691     // we need a lock here to protect "onVisibilityResolved"
692     Mutex::Autolock _l(mOverlaySourceLock);
693     if (mOverlay && mOverlayDevice) {
694         overlay_control_device_t* overlay_dev = mOverlayDevice;
695         overlay_dev->destroyOverlay(overlay_dev, mOverlay);
696         mOverlay = 0;
697     }
698 }
699
700 // ---------------------------------------------------------------------------
701 }; // namespace android