blob: 7168bf244f71e1f046aa7bb98f5b3d097e2a4b8e [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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 "SurfaceFlinger"
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <stdint.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <math.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/ioctl.h>
29
30#include <cutils/log.h>
31#include <cutils/properties.h>
32
33#include <utils/IBinder.h>
34#include <utils/MemoryDealer.h>
35#include <utils/MemoryBase.h>
36#include <utils/MemoryHeapPmem.h>
37#include <utils/MemoryHeapBase.h>
38#include <utils/IPCThreadState.h>
39#include <utils/StopWatch.h>
40
41#include <ui/ISurfaceComposer.h>
42
43#include "VRamHeap.h"
44#include "GPUHardware.h"
45
46#if HAVE_ANDROID_OS
47#include <linux/android_pmem.h>
48#endif
49
50#include "GPUHardware/GPUHardware.h"
51
52
53/*
54 * Manage the GPU. This implementation is very specific to the G1.
55 * There are no abstraction here.
56 *
57 * All this code will soon go-away and be replaced by a new architecture
58 * for managing graphics accelerators.
59 *
60 * In the meantime, it is conceptually possible to instantiate a
61 * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
62 * of this file); practically... doubtful.
63 *
64 */
65
66namespace android {
67
68// ---------------------------------------------------------------------------
69
70class GPUClientHeap;
71class GPUAreaHeap;
72
73class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
74{
75public:
76 static const int GPU_RESERVED_SIZE;
77 static const int GPUR_SIZE;
78
79 GPUHardware();
80 virtual ~GPUHardware();
81
82 virtual void revoke(int pid);
83 virtual sp<MemoryDealer> request(int pid);
84 virtual status_t request(int pid,
85 const sp<IGPUCallback>& callback,
86 ISurfaceComposer::gpu_info_t* gpu);
87
88 virtual status_t friendlyRevoke();
89 virtual void unconditionalRevoke();
90
91 virtual pid_t getOwner() const { return mOwner; }
92
93 // used for debugging only...
94 virtual sp<SimpleBestFitAllocator> getAllocator() const;
95
96private:
97
98
99 enum {
100 NO_OWNER = -1,
101 };
102
103 struct GPUArea {
104 sp<GPUAreaHeap> heap;
105 sp<MemoryHeapPmem> clientHeap;
106 sp<IMemory> map();
107 };
108
109 struct Client {
110 pid_t pid;
111 GPUArea smi;
112 GPUArea ebi;
113 GPUArea reg;
114 void createClientHeaps();
115 void revokeAllHeaps();
116 };
117
118 Client& getClientLocked(pid_t pid);
119 status_t requestLocked(int pid);
120 void releaseLocked();
121 void takeBackGPULocked();
122 void registerCallbackLocked(const sp<IGPUCallback>& callback,
123 Client& client);
124
125 virtual void binderDied(const wp<IBinder>& who);
126
127 mutable Mutex mLock;
128 sp<GPUAreaHeap> mSMIHeap;
129 sp<GPUAreaHeap> mEBIHeap;
130 sp<GPUAreaHeap> mREGHeap;
131
132 KeyedVector<pid_t, Client> mClients;
133 DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
134
135 pid_t mOwner;
136
137 sp<MemoryDealer> mCurrentAllocator;
138 sp<IGPUCallback> mCallback;
139
140 sp<SimpleBestFitAllocator> mAllocator;
141
142 Condition mCondition;
143};
144
145// size reserved for GPU surfaces
146// 1200 KB fits exactly:
147// - two 320*480 16-bits double-buffered surfaces
148// - one 320*480 32-bits double-buffered surface
149// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
150const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
151const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
152
153// ---------------------------------------------------------------------------
154
155/*
156 * GPUHandle is a special IMemory given to the client. It represents their
157 * handle to the GPU. Once they give it up, they loose GPU access, or if
158 * they explicitly revoke their access through the binder code 1000.
159 * In both cases, this triggers a callback to revoke()
160 * first, and then actually powers down the chip.
161 *
162 * In the case of a misbehaving app, GPUHardware can ask for an immediate
163 * release of the GPU to the target process which should answer by calling
164 * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
165 * be revoked from under their feet.
166 *
167 * We should never hold a strong reference on GPUHandle. In practice this
168 * shouldn't be a big issue though because clients should use code 1000 and
169 * not rely on the dtor being called.
170 *
171 */
172
173class GPUClientHeap : public MemoryHeapPmem
174{
175public:
176 GPUClientHeap(const wp<GPUHardware>& gpu,
177 const sp<MemoryHeapBase>& heap)
178 : MemoryHeapPmem(heap), mGPU(gpu) { }
179protected:
180 wp<GPUHardware> mGPU;
181};
182
183class GPUAreaHeap : public MemoryHeapBase
184{
185public:
186 GPUAreaHeap(const wp<GPUHardware>& gpu,
187 const char* const vram, size_t size=0, size_t reserved=0)
188 : MemoryHeapBase(vram, size), mGPU(gpu) {
189 if (base() != MAP_FAILED) {
190 if (reserved == 0)
191 reserved = virtualSize();
192 mAllocator = new SimpleBestFitAllocator(reserved);
193 }
194 }
195 virtual sp<MemoryHeapPmem> createClientHeap() {
196 sp<MemoryHeapBase> parentHeap(this);
197 return new GPUClientHeap(mGPU, parentHeap);
198 }
199 virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
200 return mAllocator;
201 }
202private:
203 sp<SimpleBestFitAllocator> mAllocator;
204protected:
205 wp<GPUHardware> mGPU;
206};
207
208class GPURegisterHeap : public GPUAreaHeap
209{
210public:
211 GPURegisterHeap(const sp<GPUHardware>& gpu)
212 : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
213 virtual sp<MemoryHeapPmem> createClientHeap() {
214 sp<MemoryHeapBase> parentHeap(this);
215 return new MemoryHeapRegs(mGPU, parentHeap);
216 }
217private:
218 class MemoryHeapRegs : public GPUClientHeap {
219 public:
220 MemoryHeapRegs(const wp<GPUHardware>& gpu,
221 const sp<MemoryHeapBase>& heap)
222 : GPUClientHeap(gpu, heap) { }
223 sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
224 virtual void revoke();
225 private:
226 class GPUHandle : public MemoryHeapPmem::MemoryPmem {
227 public:
228 GPUHandle(const sp<GPUHardware>& gpu,
229 const sp<MemoryHeapPmem>& heap)
230 : MemoryHeapPmem::MemoryPmem(heap),
231 mGPU(gpu), mOwner(gpu->getOwner()) { }
232 virtual ~GPUHandle();
233 virtual sp<IMemoryHeap> getMemory(
234 ssize_t* offset, size_t* size) const;
235 virtual void revoke() { };
236 virtual status_t onTransact(
237 uint32_t code, const Parcel& data,
238 Parcel* reply, uint32_t flags);
239 private:
240 void revokeNotification();
241 wp<GPUHardware> mGPU;
242 pid_t mOwner;
243 };
244 };
245};
246
247GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
248 //LOGD("GPUHandle %p released, revoking GPU", this);
249 revokeNotification();
250}
251void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
252 sp<GPUHardware> hw(mGPU.promote());
253 if (hw != 0) {
254 hw->revoke(mOwner);
255 }
256}
257sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
258 ssize_t* offset, size_t* size) const
259{
260 sp<MemoryHeapPmem> heap = getHeap();
261 if (offset) *offset = 0;
262 if (size) *size = heap !=0 ? heap->virtualSize() : 0;
263 return heap;
264}
265status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
266 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
267{
268 status_t err = BnMemory::onTransact(code, data, reply, flags);
269 if (err == UNKNOWN_TRANSACTION && code == 1000) {
270 int callingPid = IPCThreadState::self()->getCallingPid();
271 //LOGD("pid %d voluntarily revoking gpu", callingPid);
272 if (callingPid == mOwner) {
273 revokeNotification();
274 // we've revoked the GPU, don't do it again later when we
275 // are destroyed.
276 mGPU.clear();
277 } else {
278 LOGW("%d revoking someone else's gpu? (owner=%d)",
279 callingPid, mOwner);
280 }
281 err = NO_ERROR;
282 }
283 return err;
284}
285
286// ---------------------------------------------------------------------------
287
288
289sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
290 size_t offset, size_t size)
291{
292 sp<GPUHandle> memory;
293 sp<GPUHardware> gpu = mGPU.promote();
294 if (heapID()>0 && gpu!=0) {
295#if HAVE_ANDROID_OS
296 /* this is where the GPU is powered on and the registers are mapped
297 * in the client */
298 //LOGD("ioctl(HW3D_GRANT_GPU)");
299 int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
300 if (err) {
301 // it can happen if the master heap has been closed already
302 // in which case the GPU already is revoked (app crash for
303 // instance).
304 LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
305 strerror(errno), heapID(), base());
306 }
307 memory = new GPUHandle(gpu, this);
308#endif
309 }
310 return memory;
311}
312
313void GPURegisterHeap::MemoryHeapRegs::revoke()
314{
315 MemoryHeapPmem::revoke();
316#if HAVE_ANDROID_OS
317 if (heapID() > 0) {
318 //LOGD("ioctl(HW3D_REVOKE_GPU)");
319 int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
320 LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
321 strerror(errno), heapID(), base());
322 }
323#endif
324}
325
326/*****************************************************************************/
327
328GPUHardware::GPUHardware()
329 : mOwner(NO_OWNER)
330{
331}
332
333GPUHardware::~GPUHardware()
334{
335}
336
337status_t GPUHardware::requestLocked(int pid)
338{
339 const int self_pid = getpid();
340 if (pid == self_pid) {
341 // can't use GPU from surfaceflinger's process
342 return PERMISSION_DENIED;
343 }
344
345 if (mOwner != pid) {
346 if (mREGHeap != 0) {
347 if (mOwner != NO_OWNER) {
348 // someone already has the gpu.
349 takeBackGPULocked();
350 releaseLocked();
351 }
352 } else {
353 // first time, initialize the stuff.
354 if (mSMIHeap == 0)
355 mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
356 if (mEBIHeap == 0)
357 mEBIHeap = new GPUAreaHeap(this,
358 "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
359 mREGHeap = new GPURegisterHeap(this);
360 mAllocator = mEBIHeap->getAllocator();
361 if (mAllocator == NULL) {
362 // something went terribly wrong.
363 mSMIHeap.clear();
364 mEBIHeap.clear();
365 mREGHeap.clear();
366 return INVALID_OPERATION;
367 }
368 }
369 Client& client = getClientLocked(pid);
370 mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
371 mOwner = pid;
372 }
373 return NO_ERROR;
374}
375
376sp<MemoryDealer> GPUHardware::request(int pid)
377{
378 sp<MemoryDealer> dealer;
379 Mutex::Autolock _l(mLock);
380 Client* client;
381 LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
382 if (requestLocked(pid) == NO_ERROR) {
383 dealer = mCurrentAllocator;
384 LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
385 }
386 return dealer;
387}
388
389status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
390 ISurfaceComposer::gpu_info_t* gpu)
391{
392 if (callback == 0)
393 return BAD_VALUE;
394
395 sp<IMemory> gpuHandle;
396 LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
397 Mutex::Autolock _l(mLock);
398 status_t err = requestLocked(pid);
399 if (err == NO_ERROR) {
400 // it's guaranteed to be there, be construction
401 Client& client = mClients.editValueFor(pid);
402 registerCallbackLocked(callback, client);
403 gpu->count = 2;
404 gpu->regions[0].region = client.smi.map();
405 gpu->regions[1].region = client.ebi.map();
406 gpu->regs = client.reg.map();
407 gpu->regions[0].reserved = 0;
408 gpu->regions[1].reserved = GPU_RESERVED_SIZE;
409 if (gpu->regs != 0) {
410 //LOGD("gpu core granted to pid %d, handle base=%p",
411 // mOwner, gpu->regs->pointer());
412 }
413 mCallback = callback;
414 } else {
415 LOGW("couldn't grant gpu core to pid %d", pid);
416 }
417 return err;
418}
419
420void GPUHardware::revoke(int pid)
421{
422 Mutex::Autolock _l(mLock);
423 if (mOwner > 0) {
424 if (pid != mOwner) {
425 LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
426 return;
427 }
428 //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
429 // mOwner could be <0 if the same process acquired the GPU
430 // several times without releasing it first.
431 mCondition.signal();
432 releaseLocked();
433 }
434}
435
436status_t GPUHardware::friendlyRevoke()
437{
438 Mutex::Autolock _l(mLock);
439 //LOGD("friendlyRevoke owner=%d", mOwner);
440 takeBackGPULocked();
441 releaseLocked();
442 return NO_ERROR;
443}
444
445void GPUHardware::takeBackGPULocked()
446{
447 sp<IGPUCallback> callback = mCallback;
448 mCallback.clear();
449 if (callback != 0) {
450 callback->gpuLost(); // one-way
451 mCondition.waitRelative(mLock, ms2ns(250));
452 }
453}
454
455void GPUHardware::releaseLocked()
456{
457 //LOGD("revoking gpu from pid %d", mOwner);
458 if (mOwner != NO_OWNER) {
459 // this may fail because the client might have died, and have
460 // been removed from the list.
461 ssize_t index = mClients.indexOfKey(mOwner);
462 if (index >= 0) {
463 Client& client(mClients.editValueAt(index));
464 client.revokeAllHeaps();
465 }
466 mOwner = NO_OWNER;
467 mCurrentAllocator.clear();
468 mCallback.clear();
469 }
470}
471
472GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
473{
474 ssize_t index = mClients.indexOfKey(pid);
475 if (index < 0) {
476 Client client;
477 client.pid = pid;
478 client.smi.heap = mSMIHeap;
479 client.ebi.heap = mEBIHeap;
480 client.reg.heap = mREGHeap;
481 index = mClients.add(pid, client);
482 }
483 Client& client(mClients.editValueAt(index));
484 client.createClientHeaps();
485 return client;
486}
487
488// ----------------------------------------------------------------------------
489// for debugging / testing ...
490
491sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
492 Mutex::Autolock _l(mLock);
493 return mAllocator;
494}
495
496void GPUHardware::unconditionalRevoke()
497{
498 Mutex::Autolock _l(mLock);
499 releaseLocked();
500}
501
502// ---------------------------------------------------------------------------
503
504sp<IMemory> GPUHardware::GPUArea::map() {
505 sp<IMemory> memory;
506 if (clientHeap != 0 && heap != 0) {
507 memory = clientHeap->mapMemory(0, heap->virtualSize());
508 }
509 return memory;
510}
511
512void GPUHardware::Client::createClientHeaps()
513{
514 if (smi.clientHeap == 0)
515 smi.clientHeap = smi.heap->createClientHeap();
516 if (ebi.clientHeap == 0)
517 ebi.clientHeap = ebi.heap->createClientHeap();
518 if (reg.clientHeap == 0)
519 reg.clientHeap = reg.heap->createClientHeap();
520}
521
522void GPUHardware::Client::revokeAllHeaps()
523{
524 if (smi.clientHeap != 0)
525 smi.clientHeap->revoke();
526 if (ebi.clientHeap != 0)
527 ebi.clientHeap->revoke();
528 if (reg.clientHeap != 0)
529 reg.clientHeap->revoke();
530}
531
532void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
533 Client& client)
534{
535 sp<IBinder> binder = callback->asBinder();
536 if (mRegisteredClients.add(binder, client.pid) >= 0) {
537 binder->linkToDeath(this);
538 }
539}
540
541void GPUHardware::binderDied(const wp<IBinder>& who)
542{
543 Mutex::Autolock _l(mLock);
544 pid_t pid = mRegisteredClients.valueFor(who);
545 if (pid != 0) {
546 ssize_t index = mClients.indexOfKey(pid);
547 if (index >= 0) {
548 //LOGD("*** removing client at %d", index);
549 Client& client(mClients.editValueAt(index));
550 client.revokeAllHeaps(); // not really needed in theory
551 mClients.removeItemsAt(index);
552 if (mClients.size() == 0) {
553 //LOGD("*** was last client closing everything");
554 mCallback.clear();
555 mAllocator.clear();
556 mCurrentAllocator.clear();
557 mSMIHeap.clear();
558 mREGHeap.clear();
559
560 // NOTE: we cannot clear the EBI heap because surfaceflinger
561 // itself may be using it, since this is where surfaces
562 // are allocated. if we're in the middle of compositing
563 // a surface (even if its process just died), we cannot
564 // rip the heap under our feet.
565
566 mOwner = NO_OWNER;
567 }
568 }
569 }
570}
571
572// ---------------------------------------------------------------------------
573
574sp<GPUHardwareInterface> GPUFactory::getGPU()
575{
Mathias Agopian2b42fa72009-04-27 18:50:06 -0700576 sp<GPUHardwareInterface> gpu;
577 if (access("/dev/hw3d", F_OK) == 0) {
578 gpu = new GPUHardware();
579 }
580 return gpu;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800581}
582
583// ---------------------------------------------------------------------------
584}; // namespace android
585