blob: 357e4d0d5e5b36865aee683b83863ec7a7590af1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-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
17#define LOG_TAG "Surface"
18
19#include <stdint.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <errno.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026#include <utils/Errors.h>
27#include <utils/threads.h>
28#include <utils/IPCThreadState.h>
29#include <utils/IMemory.h>
30#include <utils/Log.h>
31
Mathias Agopian1473f462009-04-10 14:24:30 -070032#include <ui/DisplayInfo.h>
33#include <ui/BufferMapper.h>
34#include <ui/EGLNativeWindowSurface.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035#include <ui/ISurface.h>
36#include <ui/Surface.h>
37#include <ui/SurfaceComposerClient.h>
38#include <ui/Rect.h>
39
Mathias Agopian1473f462009-04-10 14:24:30 -070040#include <EGL/android_natives.h>
41
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042#include <private/ui/SharedState.h>
43#include <private/ui/LayerState.h>
44
Mathias Agopian1473f462009-04-10 14:24:30 -070045#include <pixelflinger/pixelflinger.h>
46
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047namespace android {
48
Mathias Agopian1473f462009-04-10 14:24:30 -070049// ============================================================================
50// SurfaceBuffer
51// ============================================================================
52
53SurfaceBuffer::SurfaceBuffer()
54 : BASE(), handle(0), mOwner(false)
55{
56 width =
57 height =
58 stride =
59 format =
60 usage = 0;
61 android_native_buffer_t::getHandle = getHandle;
62}
63
64SurfaceBuffer::SurfaceBuffer(const Parcel& data)
65 : BASE(), handle(0), mOwner(true)
66{
67 // we own the handle in this case
68 width = data.readInt32();
69 height = data.readInt32();
70 stride = data.readInt32();
71 format = data.readInt32();
72 usage = data.readInt32();
73 handle = data.readNativeHandle();
74 android_native_buffer_t::getHandle = getHandle;
75}
76
77SurfaceBuffer::~SurfaceBuffer()
78{
79 if (handle && mOwner) {
80 native_handle_close(handle);
81 native_handle_delete(const_cast<native_handle*>(handle));
82 }
83}
84
85int SurfaceBuffer::getHandle(android_native_buffer_t const * base,
86 buffer_handle_t* handle)
87{
88 *handle = getSelf(base)->handle;
89 return 0;
90}
91
92status_t SurfaceBuffer::writeToParcel(Parcel* reply,
93 android_native_buffer_t const* buffer)
94{
95 buffer_handle_t handle;
96 status_t err = buffer->getHandle(buffer, &handle);
97 if (err < 0) {
98 return err;
99 }
100 reply->writeInt32(buffer->width);
101 reply->writeInt32(buffer->height);
102 reply->writeInt32(buffer->stride);
103 reply->writeInt32(buffer->format);
104 reply->writeInt32(buffer->usage);
105 reply->writeNativeHandle(handle);
106 return NO_ERROR;
107}
108
109// ----------------------------------------------------------------------
110
111static void copyBlt(const android_native_buffer_t* dst,
112 const android_native_buffer_t* src, const Region& reg)
113{
114 Region::iterator iterator(reg);
115 if (iterator) {
116 // NOTE: dst and src must be the same format
117 Rect r;
118 const size_t bpp = bytesPerPixel(src->format);
119 const size_t dbpr = dst->stride * bpp;
120 const size_t sbpr = src->stride * bpp;
121 while (iterator.iterate(&r)) {
122 ssize_t h = r.bottom - r.top;
123 if (h) {
124 size_t size = (r.right - r.left) * bpp;
125 uint8_t* s = (GGLubyte*)src->bits +
126 (r.left + src->stride * r.top) * bpp;
127 uint8_t* d = (GGLubyte*)dst->bits +
128 (r.left + dst->stride * r.top) * bpp;
129 if (dbpr==sbpr && size==sbpr) {
130 size *= h;
131 h = 1;
132 }
133 do {
134 memcpy(d, s, size);
135 d += dbpr;
136 s += sbpr;
137 } while (--h > 0);
138 }
139 }
140 }
141}
142
143// ============================================================================
144// Surface
145// ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
147Surface::Surface(const sp<SurfaceComposerClient>& client,
148 const sp<ISurface>& surface,
149 const ISurfaceFlingerClient::surface_data_t& data,
150 uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
151 bool owner)
152 : mClient(client), mSurface(surface),
153 mToken(data.token), mIdentity(data.identity),
154 mFormat(format), mFlags(flags), mOwner(owner)
155{
Mathias Agopian1473f462009-04-10 14:24:30 -0700156 android_native_window_t::connect = connect;
157 android_native_window_t::disconnect = disconnect;
158 android_native_window_t::setSwapInterval = setSwapInterval;
159 android_native_window_t::setSwapRectangle = setSwapRectangle;
160 android_native_window_t::dequeueBuffer = dequeueBuffer;
161 android_native_window_t::lockBuffer = lockBuffer;
162 android_native_window_t::queueBuffer = queueBuffer;
163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 mSwapRectangle.makeInvalid();
Mathias Agopian1473f462009-04-10 14:24:30 -0700165
166 DisplayInfo dinfo;
167 SurfaceComposerClient::getDisplayInfo(0, &dinfo);
168 const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
169 const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
170 // FIXME: set real values here
171 const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
172 const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
173 const_cast<uint32_t&>(android_native_window_t::flags) = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174}
175
176Surface::Surface(Surface const* rhs)
177 : mOwner(false)
178{
Mathias Agopian1473f462009-04-10 14:24:30 -0700179 // FIXME: we really should get rid of this ctor. the memcpy below
180 //should be safe for now, but android_native_window_t is not supposed
181 // to be clonable.
182 memcpy( static_cast<android_native_window_t*>(this),
183 static_cast<android_native_window_t const *>(rhs),
184 sizeof(android_native_window_t));
185
186 mToken = rhs->mToken;
187 mIdentity = rhs->mIdentity;
188 mClient = rhs->mClient;
189 mSurface = rhs->mSurface;
190 mBuffers[0] = rhs->mBuffers[0];
191 mBuffers[1] = rhs->mBuffers[1];
192 mFormat = rhs->mFormat;
193 mFlags = rhs->mFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 mSwapRectangle.makeInvalid();
195}
196
197Surface::~Surface()
198{
199 if (mOwner && mToken>=0 && mClient!=0) {
200 mClient->destroySurface(mToken);
Mathias Agopian1473f462009-04-10 14:24:30 -0700201 if (mBuffers[0] != 0) {
202 BufferMapper::get().unmap(mBuffers[0]->getHandle());
203 }
204 if (mBuffers[1] != 0) {
205 BufferMapper::get().unmap(mBuffers[1]->getHandle());
206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
208 mClient.clear();
209 mSurface.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 IPCThreadState::self()->flushCommands();
211}
212
213sp<Surface> Surface::dup() const
214{
Mathias Agopian1473f462009-04-10 14:24:30 -0700215 // FIXME: we should get rid of Surface::dup()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 Surface const * r = this;
217 if (this && mOwner) {
218 // the only reason we need to do this is because of Java's garbage
219 // collector: because we're creating a copy of the Surface
Mathias Agopian1473f462009-04-10 14:24:30 -0700220 // instead of a reference, we can guarantee that when our last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 // reference goes away, the real surface will be deleted.
222 // Without this hack (the code is correct too), we'd have to
223 // wait for a GC for the surface to go away.
224 r = new Surface(this);
225 }
226 return const_cast<Surface*>(r);
227}
228
Mathias Agopian1473f462009-04-10 14:24:30 -0700229status_t Surface::validate(per_client_cblk_t const* cblk) const
230{
231 if (cblk == 0) {
232 LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
233 return NO_INIT;
234 }
235 status_t err = cblk->validate(mToken);
236 if (err != NO_ERROR) {
237 LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
238 mToken, mIdentity, err, strerror(-err));
239 return err;
240 }
241 if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
242 LOGE("using an invalid surface id=%d, identity=%u should be %d",
243 mToken, mIdentity, cblk->layers[mToken].identity);
244 return NO_INIT;
245 }
246 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247}
248
Mathias Agopian1473f462009-04-10 14:24:30 -0700249// ----------------------------------------------------------------------------
250
251int Surface::setSwapRectangle(android_native_window_t* window,
252 int l, int t, int w, int h)
253{
254 Surface* self = getSelf(window);
255 self->setSwapRectangle(Rect(l, t, l+w, t+h));
256 return 0;
257}
258
259void Surface::connect(android_native_window_t* window)
260{
261}
262
263void Surface::disconnect(android_native_window_t* window)
264{
265}
266
267int Surface::setSwapInterval(android_native_window_t* window, int interval)
268{
269 return 0;
270}
271
272int Surface::dequeueBuffer(android_native_window_t* window,
273 android_native_buffer_t** buffer)
274{
275 Surface* self = getSelf(window);
276 return self->dequeueBuffer(buffer);
277}
278
279int Surface::lockBuffer(android_native_window_t* window,
280 android_native_buffer_t* buffer)
281{
282 Surface* self = getSelf(window);
283 return self->lockBuffer(buffer);
284}
285
286int Surface::queueBuffer(android_native_window_t* window,
287 android_native_buffer_t* buffer)
288{
289 Surface* self = getSelf(window);
290 return self->queueBuffer(buffer);
291}
292
293// ----------------------------------------------------------------------------
294
295int Surface::dequeueBuffer(android_native_buffer_t** buffer)
296{
297 // FIXME: dequeueBuffer() needs proper implementation
298
299 Mutex::Autolock _l(mSurfaceLock);
300
301 per_client_cblk_t* const cblk = mClient->mControl;
302 status_t err = validate(cblk);
303 if (err != NO_ERROR)
304 return err;
305
306 SurfaceID index(mToken);
307
308 int32_t backIdx = cblk->lock_layer(size_t(index),
309 per_client_cblk_t::BLOCKING);
310
311 if (backIdx < 0)
312 return status_t(backIdx);
313
314 mBackbufferIndex = backIdx;
315 layer_cblk_t* const lcblk = &(cblk->layers[index]);
316
317 volatile const surface_info_t* const back = lcblk->surface + backIdx;
318 if (back->flags & surface_info_t::eNeedNewBuffer) {
319 getBufferLocked(backIdx);
320 }
321
322 const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
323 *buffer = backBuffer.get();
324
325 return NO_ERROR;
326}
327
328int Surface::lockBuffer(android_native_buffer_t* buffer)
329{
330 // FIXME: lockBuffer() needs proper implementation
331 return 0;
332}
333
334int Surface::queueBuffer(android_native_buffer_t* buffer)
335{
336 Mutex::Autolock _l(mSurfaceLock);
337
338 per_client_cblk_t* const cblk = mClient->mControl;
339 status_t err = validate(cblk);
340 if (err != NO_ERROR)
341 return err;
342
343 // transmit the dirty region
344 const Region dirty(swapRectangle());
345 SurfaceID index(mToken);
346 layer_cblk_t* const lcblk = &(cblk->layers[index]);
347 _send_dirty_region(lcblk, dirty);
348
349 uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
350 if (!(newstate & eNextFlipPending))
351 mClient->signalServer();
352
353 return NO_ERROR;
354}
355
356// ----------------------------------------------------------------------------
357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358status_t Surface::lock(SurfaceInfo* info, bool blocking) {
359 return Surface::lock(info, NULL, blocking);
360}
361
Mathias Agopian1473f462009-04-10 14:24:30 -0700362status_t Surface::lock(SurfaceInfo* other, Region* dirty, bool blocking)
363{
364 // FIXME: needs some locking here
365 android_native_buffer_t* backBuffer;
366 status_t err = dequeueBuffer(&backBuffer);
367 if (err == NO_ERROR) {
368 err = lockBuffer(backBuffer);
369 if (err == NO_ERROR) {
370 backBuffer->common.incRef(&backBuffer->common);
371 mLockedBuffer = backBuffer;
372 other->w = backBuffer->width;
373 other->h = backBuffer->height;
374 other->s = backBuffer->stride;
375 other->usage = backBuffer->usage;
376 other->format = backBuffer->format;
377 other->bits = backBuffer->bits;
378
379 // we handle copy-back here...
380
381 const Rect bounds(backBuffer->width, backBuffer->height);
382 Region newDirtyRegion;
383
384 per_client_cblk_t* const cblk = mClient->mControl;
385 layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
386 volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
387 if (back->flags & surface_info_t::eBufferDirty) {
388 // content is meaningless in this case and the whole surface
389 // needs to be redrawn.
390 newDirtyRegion.set(bounds);
391 if (dirty) {
392 *dirty = newDirtyRegion;
393 }
394 } else
395 {
396 if (dirty) {
397 dirty->andSelf(Region(bounds));
398 newDirtyRegion = *dirty;
399 } else {
400 newDirtyRegion.set(bounds);
401 }
402 Region copyback;
403 if (!(lcblk->flags & eNoCopyBack)) {
404 const Region previousDirtyRegion(dirtyRegion());
405 copyback = previousDirtyRegion.subtract(newDirtyRegion);
406 }
407 const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
408 if (!copyback.isEmpty() && frontBuffer!=0) {
409 // copy front to back
410 copyBlt(backBuffer, frontBuffer.get(), copyback);
411 }
412 }
413 setDirtyRegion(newDirtyRegion);
414
415
416 Rect lockBounds(backBuffer->width, backBuffer->height);
417 if (dirty) {
418 lockBounds = dirty->bounds();
419 }
420 buffer_handle_t handle;
421 backBuffer->getHandle(backBuffer, &handle);
422 status_t res = BufferMapper::get().lock(handle,
423 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
424 lockBounds);
425 LOGW_IF(res, "failed locking buffer %d (%p)",
426 mBackbufferIndex, handle);
427 setSwapRectangle(lockBounds);
428 }
429 }
430 return err;
431}
432
433status_t Surface::unlockAndPost()
434{
435 // FIXME: needs some locking here
436
437 if (mLockedBuffer == 0)
438 return BAD_VALUE;
439
440 buffer_handle_t handle;
441 mLockedBuffer->getHandle(mLockedBuffer, &handle);
442 status_t res = BufferMapper::get().unlock(handle);
443 LOGW_IF(res, "failed unlocking buffer %d (%p)",
444 mBackbufferIndex, handle);
445
446 const Rect dirty(dirtyRegion().bounds());
447 setSwapRectangle(dirty);
448 status_t err = queueBuffer(mLockedBuffer);
449 mLockedBuffer->common.decRef(&mLockedBuffer->common);
450 mLockedBuffer = 0;
451 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452}
453
Mathias Agopian1473f462009-04-10 14:24:30 -0700454void Surface::_send_dirty_region(
455 layer_cblk_t* lcblk, const Region& dirty)
456{
457 const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
458 flat_region_t* flat_region = lcblk->region + index;
459 status_t err = dirty.write(flat_region, sizeof(flat_region_t));
460 if (err < NO_ERROR) {
461 // region doesn't fit, use the bounds
462 const Region reg(dirty.bounds());
463 reg.write(flat_region, sizeof(flat_region_t));
464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465}
466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467
468status_t Surface::setLayer(int32_t layer) {
469 return mClient->setLayer(this, layer);
470}
471status_t Surface::setPosition(int32_t x, int32_t y) {
472 return mClient->setPosition(this, x, y);
473}
474status_t Surface::setSize(uint32_t w, uint32_t h) {
475 return mClient->setSize(this, w, h);
476}
477status_t Surface::hide() {
478 return mClient->hide(this);
479}
480status_t Surface::show(int32_t layer) {
481 return mClient->show(this, layer);
482}
483status_t Surface::freeze() {
484 return mClient->freeze(this);
485}
486status_t Surface::unfreeze() {
487 return mClient->unfreeze(this);
488}
489status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
490 return mClient->setFlags(this, flags, mask);
491}
492status_t Surface::setTransparentRegionHint(const Region& transparent) {
493 return mClient->setTransparentRegionHint(this, transparent);
494}
495status_t Surface::setAlpha(float alpha) {
496 return mClient->setAlpha(this, alpha);
497}
498status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
499 return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
500}
501status_t Surface::setFreezeTint(uint32_t tint) {
502 return mClient->setFreezeTint(this, tint);
503}
504
505Region Surface::dirtyRegion() const {
506 return mDirtyRegion;
507}
508void Surface::setDirtyRegion(const Region& region) const {
509 mDirtyRegion = region;
510}
511const Rect& Surface::swapRectangle() const {
512 return mSwapRectangle;
513}
514void Surface::setSwapRectangle(const Rect& r) {
515 mSwapRectangle = r;
516}
517
518sp<Surface> Surface::readFromParcel(Parcel* parcel)
519{
520 sp<SurfaceComposerClient> client;
521 ISurfaceFlingerClient::surface_data_t data;
522 sp<IBinder> clientBinder= parcel->readStrongBinder();
523 sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 data.token = parcel->readInt32();
525 data.identity = parcel->readInt32();
526 PixelFormat format = parcel->readInt32();
527 uint32_t flags = parcel->readInt32();
528
529 if (clientBinder != NULL)
530 client = SurfaceComposerClient::clientForConnection(clientBinder);
531
532 return new Surface(client, surface, data, 0, 0, format, flags, false);
533}
534
535status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
536{
537 uint32_t flags=0;
538 uint32_t format=0;
539 SurfaceID token = -1;
540 uint32_t identity = 0;
541 sp<SurfaceComposerClient> client;
542 sp<ISurface> sur;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 if (surface->isValid()) {
544 token = surface->mToken;
545 identity = surface->mIdentity;
546 client = surface->mClient;
547 sur = surface->mSurface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 format = surface->mFormat;
549 flags = surface->mFlags;
550 }
551 parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
552 parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 parcel->writeInt32(token);
554 parcel->writeInt32(identity);
555 parcel->writeInt32(format);
556 parcel->writeInt32(flags);
557 return NO_ERROR;
558}
559
560bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
561{
562 if (lhs == 0 || rhs == 0)
563 return false;
564 return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
565}
566
Mathias Agopian1473f462009-04-10 14:24:30 -0700567status_t Surface::getBufferLocked(int index)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568{
Mathias Agopian1473f462009-04-10 14:24:30 -0700569 status_t err = NO_MEMORY;
570 sp<SurfaceBuffer> buffer = mSurface->getBuffer();
571 LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
572 if (buffer != 0) {
573 sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
574 if (currentBuffer != 0) {
575 BufferMapper::get().unmap(currentBuffer->getHandle());
576 currentBuffer.clear();
577 }
578 err = BufferMapper::get().map(buffer->getHandle(), &buffer->bits);
579 LOGW_IF(err, "map(...) failed %d (%s)", err, strerror(-err));
580 if (err == NO_ERROR) {
581 currentBuffer = buffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700584 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585}
586
587}; // namespace android
588