diff options
Diffstat (limited to 'libs')
42 files changed, 2706 insertions, 1778 deletions
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp index a018b4c..6c11114 100644 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ b/libs/audioflinger/AudioDumpInterface.cpp @@ -32,7 +32,7 @@ namespace android { // ---------------------------------------------------------------------------- AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) - : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8("")) + : mPolicyCommands(String8("")), mFileName(String8("")) { if(hw == 0) { LOGE("Dump construct hw = 0"); @@ -47,6 +47,11 @@ AudioDumpInterface::~AudioDumpInterface() for (size_t i = 0; i < mOutputs.size(); i++) { closeOutputStream((AudioStreamOut *)mOutputs[i]); } + + for (size_t i = 0; i < mInputs.size(); i++) { + closeInputStream((AudioStreamIn *)mInputs[i]); + } + if(mFinalInterface) delete mFinalInterface; } @@ -60,31 +65,32 @@ AudioStreamOut* AudioDumpInterface::openOutputStream( uint32_t lRate = 44100; - if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) { - outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); - if (outFinal != 0) { - lFormat = outFinal->format(); - lChannels = outFinal->channels(); - lRate = outFinal->sampleRate(); - if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) { - mFirstHwOutput = false; - } - } + outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); + if (outFinal != 0) { + lFormat = outFinal->format(); + lChannels = outFinal->channels(); + lRate = outFinal->sampleRate(); } else { - if (format != 0 && *format != 0) { - lFormat = *format; - } else { - lFormat = AudioSystem::PCM_16_BIT; + if (format != 0) { + if (*format != 0) { + lFormat = *format; + } else { + *format = lFormat; + } } - if (channels != 0 && *channels != 0) { - lChannels = *channels; - } else { - lChannels = AudioSystem::CHANNEL_OUT_STEREO; + if (channels != 0) { + if (*channels != 0) { + lChannels = *channels; + } else { + *channels = lChannels; + } } - if (sampleRate != 0 && *sampleRate != 0) { - lRate = *sampleRate; - } else { - lRate = 44100; + if (sampleRate != 0) { + if (*sampleRate != 0) { + lRate = *sampleRate; + } else { + *sampleRate = lRate; + } } if (status) *status = NO_ERROR; } @@ -111,7 +117,6 @@ void AudioDumpInterface::closeOutputStream(AudioStreamOut* out) dumpOut->standby(); if (dumpOut->finalStream() != NULL) { mFinalInterface->closeOutputStream(dumpOut->finalStream()); - mFirstHwOutput = true; } mOutputs.remove(dumpOut); @@ -126,18 +131,33 @@ AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO; uint32_t lRate = 8000; - - if (mInputs.size() == 0) { - inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); - if (inFinal == 0) return 0; - + inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); + if (inFinal != 0) { lFormat = inFinal->format(); lChannels = inFinal->channels(); lRate = inFinal->sampleRate(); } else { - if (format != 0 && *format != 0) lFormat = *format; - if (channels != 0 && *channels != 0) lChannels = *channels; - if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate; + if (format != 0) { + if (*format != 0) { + lFormat = *format; + } else { + *format = lFormat; + } + } + if (channels != 0) { + if (*channels != 0) { + lChannels = *channels; + } else { + *channels = lChannels; + } + } + if (sampleRate != 0) { + if (*sampleRate != 0) { + lRate = *sampleRate; + } else { + *sampleRate = lRate; + } + } if (status) *status = NO_ERROR; } LOGV("openInputStream(), inFinal %p", inFinal); @@ -223,6 +243,15 @@ String8 AudioDumpInterface::getParameters(const String8& keys) return keyValuePairs; } +status_t AudioDumpInterface::setMode(int mode) +{ + return mFinalInterface->setMode(mode); +} + +size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount); +} // ---------------------------------------------------------------------------- @@ -235,7 +264,7 @@ AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface, uint32_t sampleRate) : mInterface(interface), mId(id), mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices), - mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0) + mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) { LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); } @@ -254,26 +283,26 @@ ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes) if (mFinalStream) { ret = mFinalStream->write(buffer, bytes); } else { - usleep((bytes * 1000000) / frameSize() / sampleRate()); + usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); ret = bytes; } - if(!mOutFile) { + if(!mFile) { if (mInterface->fileName() != "") { char name[255]; - sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); - mOutFile = fopen(name, "wb"); - LOGV("Opening dump file %s, fh %p", name, mOutFile); + sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); + mFile = fopen(name, "wb"); + LOGV("Opening dump file %s, fh %p", name, mFile); } } - if (mOutFile) { - fwrite(buffer, bytes, 1, mOutFile); + if (mFile) { + fwrite(buffer, bytes, 1, mFile); } return ret; } status_t AudioStreamOutDump::standby() { - LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream); + LOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); Close(); if (mFinalStream != 0 ) return mFinalStream->standby(); @@ -330,7 +359,7 @@ status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs) } if (param.getInt(String8("format"), valueInt) == NO_ERROR) { - if (mOutFile == 0) { + if (mFile == 0) { mFormat = valueInt; } else { status = INVALID_OPERATION; @@ -345,7 +374,7 @@ status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs) } if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) { if (valueInt > 0 && valueInt <= 48000) { - if (mOutFile == 0) { + if (mFile == 0) { mSampleRate = valueInt; } else { status = INVALID_OPERATION; @@ -373,9 +402,9 @@ status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args) void AudioStreamOutDump::Close() { - if(mOutFile) { - fclose(mOutFile); - mOutFile = 0; + if(mFile) { + fclose(mFile); + mFile = 0; } } @@ -396,7 +425,7 @@ AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface, uint32_t sampleRate) : mInterface(interface), mId(id), mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices), - mBufferSize(1024), mFinalStream(finalStream), mInFile(0) + mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) { LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); } @@ -409,55 +438,68 @@ AudioStreamInDump::~AudioStreamInDump() ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) { - if (mFinalStream) { - return mFinalStream->read(buffer, bytes); - } - - usleep((bytes * 1000000) / frameSize() / sampleRate()); + ssize_t ret; - if(!mInFile) { - char name[255]; - strcpy(name, "/sdcard/music/sine440"); - if (channels() == AudioSystem::CHANNEL_IN_MONO) { - strcat(name, "_mo"); - } else { - strcat(name, "_st"); + if (mFinalStream) { + ret = mFinalStream->read(buffer, bytes); + if(!mFile) { + if (mInterface->fileName() != "") { + char name[255]; + sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); + mFile = fopen(name, "wb"); + LOGV("Opening input dump file %s, fh %p", name, mFile); + } } - if (format() == AudioSystem::PCM_16_BIT) { - strcat(name, "_16b"); - } else { - strcat(name, "_8b"); + if (mFile) { + fwrite(buffer, bytes, 1, mFile); } - if (sampleRate() < 16000) { - strcat(name, "_8k"); - } else if (sampleRate() < 32000) { - strcat(name, "_22k"); - } else if (sampleRate() < 48000) { - strcat(name, "_44k"); - } else { - strcat(name, "_48k"); - } - strcat(name, ".wav"); - mInFile = fopen(name, "rb"); - LOGV("Opening dump file %s, fh %p", name, mInFile); - if (mInFile) { - fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); + } else { + usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); + ret = bytes; + if(!mFile) { + char name[255]; + strcpy(name, "/sdcard/music/sine440"); + if (channels() == AudioSystem::CHANNEL_IN_MONO) { + strcat(name, "_mo"); + } else { + strcat(name, "_st"); + } + if (format() == AudioSystem::PCM_16_BIT) { + strcat(name, "_16b"); + } else { + strcat(name, "_8b"); + } + if (sampleRate() < 16000) { + strcat(name, "_8k"); + } else if (sampleRate() < 32000) { + strcat(name, "_22k"); + } else if (sampleRate() < 48000) { + strcat(name, "_44k"); + } else { + strcat(name, "_48k"); + } + strcat(name, ".wav"); + mFile = fopen(name, "rb"); + LOGV("Opening input read file %s, fh %p", name, mFile); + if (mFile) { + fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); + } } - - } - if (mInFile) { - ssize_t bytesRead = fread(buffer, bytes, 1, mInFile); - if (bytesRead != bytes) { - fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); - fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile); + if (mFile) { + ssize_t bytesRead = fread(buffer, bytes, 1, mFile); + if (bytesRead >=0 && bytesRead < bytes) { + fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); + fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile); + } } } - return bytes; + + return ret; } status_t AudioStreamInDump::standby() { - LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream); + LOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); Close(); if (mFinalStream != 0 ) return mFinalStream->standby(); @@ -523,9 +565,9 @@ status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args) void AudioStreamInDump::Close() { - if(mInFile) { - fclose(mInFile); - mInFile = 0; + if(mFile) { + fclose(mFile); + mFile = 0; } } }; // namespace android diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h index 4c62b3e..814ce5f 100644 --- a/libs/audioflinger/AudioDumpInterface.h +++ b/libs/audioflinger/AudioDumpInterface.h @@ -69,7 +69,7 @@ private: uint32_t mDevice; // current device this output is routed to size_t mBufferSize; AudioStreamOut *mFinalStream; - FILE *mOutFile; // output file + FILE *mFile; // output file int mFileCount; }; @@ -109,7 +109,8 @@ private: uint32_t mDevice; // current device this output is routed to size_t mBufferSize; AudioStreamIn *mFinalStream; - FILE *mInFile; // output file + FILE *mFile; // output file + int mFileCount; }; class AudioDumpInterface : public AudioHardwareBase @@ -134,6 +135,8 @@ public: virtual status_t setMasterVolume(float volume) {return mFinalInterface->setMasterVolume(volume);} + virtual status_t setMode(int mode); + // mic mute virtual status_t setMicMute(bool state) {return mFinalInterface->setMicMute(state);} @@ -143,6 +146,8 @@ public: virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics); virtual void closeInputStream(AudioStreamIn* in); @@ -153,8 +158,7 @@ public: protected: AudioHardwareInterface *mFinalInterface; - SortedVector<AudioStreamOutDump *> mOutputs; - bool mFirstHwOutput; + SortedVector<AudioStreamOutDump *> mOutputs; SortedVector<AudioStreamInDump *> mInputs; Mutex mLock; String8 mPolicyCommands; diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 2414e8d..3b38d83 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -142,6 +142,7 @@ AudioFlinger::AudioFlinger() } #ifdef LVMX LifeVibes::init(); + mLifeVibesClientPid = -1; #endif } @@ -596,8 +597,10 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) int musicEnabled = -1; if (NO_ERROR == param.get(key, value)) { if (value == LifevibesEnable) { + mLifeVibesClientPid = IPCThreadState::self()->getCallingPid(); musicEnabled = 1; } else if (value == LifevibesDisable) { + mLifeVibesClientPid = -1; musicEnabled = 0; } } @@ -609,7 +612,7 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) mHardwareStatus = AUDIO_SET_PARAMETER; result = mAudioHardware->setParameters(keyValuePairs); #ifdef LVMX - if ((NO_ERROR == result) && (musicEnabled != -1)) { + if (musicEnabled != -1) { LifeVibes::enableMusic((bool) musicEnabled); } #endif @@ -713,51 +716,57 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) { - LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); Mutex::Autolock _l(mLock); - sp<IBinder> binder = client->asBinder(); - if (mNotificationClients.indexOf(binder) < 0) { - LOGV("Adding notification client %p", binder.get()); - binder->linkToDeath(this); - mNotificationClients.add(binder); - } + int pid = IPCThreadState::self()->getCallingPid(); + if (mNotificationClients.indexOfKey(pid) < 0) { + sp<NotificationClient> notificationClient = new NotificationClient(this, + client, + pid); + LOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); - // the config change is always sent from playback or record threads to avoid deadlock - // with AudioSystem::gLock - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); - } + mNotificationClients.add(pid, notificationClient); + + sp<IBinder> binder = client->asBinder(); + binder->linkToDeath(notificationClient); + + // the config change is always sent from playback or record threads to avoid deadlock + // with AudioSystem::gLock + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); + } - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); + for (size_t i = 0; i < mRecordThreads.size(); i++) { + mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); + } } } -void AudioFlinger::binderDied(const wp<IBinder>& who) { - - LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); +void AudioFlinger::removeNotificationClient(pid_t pid) +{ Mutex::Autolock _l(mLock); - IBinder *binder = who.unsafe_get(); - - if (binder != NULL) { - int index = mNotificationClients.indexOf(binder); - if (index >= 0) { - LOGV("Removing notification client %p", binder); - mNotificationClients.removeAt(index); + int index = mNotificationClients.indexOfKey(pid); + if (index >= 0) { + sp <NotificationClient> client = mNotificationClients.valueFor(pid); + LOGV("removeNotificationClient() %p, pid %d", client.get(), pid); +#ifdef LVMX + if (pid == mLifeVibesClientPid) { + LOGV("Disabling lifevibes"); + LifeVibes::enableMusic(false); + mLifeVibesClientPid = -1; } +#endif + mNotificationClients.removeItem(pid); } } // audioConfigChanged_l() must be called with AudioFlinger::mLock held -void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) { +void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) +{ size_t size = mNotificationClients.size(); for (size_t i = 0; i < size; i++) { - sp<IBinder> binder = mNotificationClients.itemAt(i); - LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get()); - sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); - client->ioConfigChanged(event, ioHandle, param2); + mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2); } } @@ -768,12 +777,13 @@ void AudioFlinger::removeClient_l(pid_t pid) mClients.removeItem(pid); } + // ---------------------------------------------------------------------------- AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id) : Thread(false), mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), - mFormat(0), mFrameSize(1), mStandby(false), mId(id), mExiting(false) + mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false) { } @@ -806,7 +816,7 @@ uint32_t AudioFlinger::ThreadBase::sampleRate() const int AudioFlinger::ThreadBase::channelCount() const { - return mChannelCount; + return (int)mChannelCount; } int AudioFlinger::ThreadBase::format() const @@ -863,11 +873,12 @@ void AudioFlinger::ThreadBase::processConfigEvents() LOGV("processConfigEvents() remaining events %d", mConfigEvents.size()); ConfigEvent *configEvent = mConfigEvents[0]; mConfigEvents.removeAt(0); - // release mLock because audioConfigChanged() will lock AudioFlinger mLock - // before calling Audioflinger::audioConfigChanged_l() thus creating - // potential cross deadlock between AudioFlinger::mLock and mLock + // release mLock before locking AudioFlinger mLock: lock order is always + // AudioFlinger then ThreadBase to avoid cross deadlock mLock.unlock(); - audioConfigChanged(configEvent->mEvent, configEvent->mParam); + mAudioFlinger->mLock.lock(); + audioConfigChanged_l(configEvent->mEvent, configEvent->mParam); + mAudioFlinger->mLock.unlock(); delete configEvent; mLock.lock(); } @@ -943,8 +954,6 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); } - // notify client processes that a new input has been opened - sendConfigEvent(AudioSystem::OUTPUT_OPENED); } AudioFlinger::PlaybackThread::~PlaybackThread() @@ -1054,7 +1063,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra status_t lStatus; if (mType == DIRECT) { - if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) { + if (sampleRate != mSampleRate || format != mFormat || channelCount != (int)mChannelCount) { LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p", sampleRate, format, channelCount, mOutput); lStatus = BAD_VALUE; @@ -1224,16 +1233,17 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys) return mOutput->getParameters(keys); } -void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) { +// destroyTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) { AudioSystem::OutputDescriptor desc; void *param2 = 0; - LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param); + LOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event, param); switch (event) { case AudioSystem::OUTPUT_OPENED: case AudioSystem::OUTPUT_CONFIG_CHANGED: - desc.channels = mChannelCount; + desc.channels = mChannels; desc.samplingRate = mSampleRate; desc.format = mFormat; desc.frameCount = mFrameCount; @@ -1247,17 +1257,16 @@ void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) { default: break; } - Mutex::Autolock _l(mAudioFlinger->mLock); mAudioFlinger->audioConfigChanged_l(event, mId, param2); } void AudioFlinger::PlaybackThread::readOutputParameters() { mSampleRate = mOutput->sampleRate(); - mChannelCount = AudioSystem::popCount(mOutput->channels()); - + mChannels = mOutput->channels(); + mChannelCount = (uint16_t)AudioSystem::popCount(mChannels); mFormat = mOutput->format(); - mFrameSize = mOutput->frameSize(); + mFrameSize = (uint16_t)mOutput->frameSize(); mFrameCount = mOutput->bufferSize() / mFrameSize; // FIXME - Current mixer implementation only supports stereo output: Always @@ -1604,66 +1613,22 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track return mixerStatus; } -void AudioFlinger::MixerThread::getTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks, - int streamType) +void AudioFlinger::MixerThread::invalidateTracks(int streamType) { - LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.size()); + LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size()); Mutex::Autolock _l(mLock); size_t size = mTracks.size(); for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; if (t->type() == streamType) { - tracks.add(t); - int j = mActiveTracks.indexOf(t); - if (j >= 0) { - t = mActiveTracks[j].promote(); - if (t != NULL) { - activeTracks.add(t); + t->mCblk->lock.lock(); + t->mCblk->flags |= CBLK_INVALID_ON; + t->mCblk->cv.signal(); + t->mCblk->lock.unlock(); } } } - } - - size = activeTracks.size(); - for (size_t i = 0; i < size; i++) { - mActiveTracks.remove(activeTracks[i]); - } - - size = tracks.size(); - for (size_t i = 0; i < size; i++) { - sp<Track> t = tracks[i]; - mTracks.remove(t); - deleteTrackName_l(t->name()); - } -} - -void AudioFlinger::MixerThread::putTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks) -{ - LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this, tracks.size(), activeTracks.size()); - Mutex::Autolock _l(mLock); - size_t size = tracks.size(); - for (size_t i = 0; i < size ; i++) { - sp<Track> t = tracks[i]; - int name = getTrackName_l(); - - if (name < 0) return; - - t->mName = name; - t->mThread = this; - mTracks.add(t); - int j = activeTracks.indexOf(t); - if (j >= 0) { - mActiveTracks.add(t); - // force buffer refilling and no ramp volume when the track is mixed for the first time - t->mFillingUpStatus = Track::FS_FILLING; - } - } -} // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::MixerThread::getTrackName_l() @@ -2332,13 +2297,13 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( // clear all buffers mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; - mCblk->channels = (uint8_t)channelCount; + mCblk->channelCount = (uint8_t)channelCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); // Force underrun condition to avoid false underrun callback until first data is // written to buffer - mCblk->flowControlFlag = 1; + mCblk->flags = CBLK_UNDERRUN_ON; } else { mBuffer = sharedBuffer->pointer(); } @@ -2356,12 +2321,12 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( // clear all buffers mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; - mCblk->channels = (uint8_t)channelCount; + mCblk->channelCount = (uint8_t)channelCount; mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); // Force underrun condition to avoid false underrun callback until first data is // written to buffer - mCblk->flowControlFlag = 1; + mCblk->flags = CBLK_UNDERRUN_ON; mBufferEnd = (uint8_t *)mBuffer + bufferSize; } } @@ -2423,7 +2388,7 @@ int AudioFlinger::ThreadBase::TrackBase::sampleRate() const { } int AudioFlinger::ThreadBase::TrackBase::channelCount() const { - return (int)mCblk->channels; + return (int)mCblk->channelCount; } void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { @@ -2435,9 +2400,9 @@ void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t f if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) { LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ - server %d, serverBase %d, user %d, userBase %d, channels %d", + server %d, serverBase %d, user %d, userBase %d, channelCount %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, - cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); + cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channelCount); return 0; } @@ -2522,7 +2487,7 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) (mClient == NULL) ? getpid() : mClient->pid(), mStreamType, mFormat, - mCblk->channels, + mCblk->channelCount, mFrameCount, mState, mMute, @@ -2579,9 +2544,9 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { if (mFillingUpStatus != FS_FILLING) return true; if (mCblk->framesReady() >= mCblk->frameCount || - mCblk->forceReady) { + (mCblk->flags & CBLK_FORCEREADY_MSK)) { mFillingUpStatus = FS_FILLED; - mCblk->forceReady = 0; + mCblk->flags &= ~CBLK_FORCEREADY_MSK; return true; } return false; @@ -2696,8 +2661,8 @@ void AudioFlinger::PlaybackThread::Track::reset() TrackBase::reset(); // Force underrun condition to avoid false underrun callback until first data is // written to buffer - mCblk->flowControlFlag = 1; - mCblk->forceReady = 0; + mCblk->flags |= CBLK_UNDERRUN_ON; + mCblk->flags &= ~CBLK_FORCEREADY_MSK; mFillingUpStatus = FS_FILLING; mResetDone = true; } @@ -2808,7 +2773,7 @@ void AudioFlinger::RecordThread::RecordTrack::stop() TrackBase::reset(); // Force overerrun condition to avoid false overrun callback until first data is // read from buffer - mCblk->flowControlFlag = 1; + mCblk->flags |= CBLK_UNDERRUN_ON; } } @@ -2817,7 +2782,7 @@ void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) snprintf(buffer, size, " %05d %03u %03u %04u %01d %05u %08x %08x\n", (mClient == NULL) ? getpid() : mClient->pid(), mFormat, - mCblk->channels, + mCblk->channelCount, mFrameCount, mState, mCblk->sampleRate, @@ -2841,13 +2806,13 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get(); if (mCblk != NULL) { - mCblk->out = 1; + mCblk->flags |= CBLK_DIRECTION_OUT; mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); mCblk->volume[0] = mCblk->volume[1] = 0x1000; mOutBuffer.frameCount = 0; playbackThread->mTracks.add(this); - LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", - mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd); + LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channelCount %d mBufferEnd %p", + mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channelCount, mBufferEnd); } else { LOGW("Error creating output track on thread %p", playbackThread); } @@ -2882,7 +2847,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr { Buffer *pInBuffer; Buffer inBuffer; - uint32_t channels = mCblk->channels; + uint32_t channelCount = mCblk->channelCount; bool outputBufferFull = false; inBuffer.frameCount = frames; inBuffer.i16 = data; @@ -2898,10 +2863,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (mBufferQueue.size() < kMaxOverFlowBuffers) { uint32_t startFrames = (mCblk->frameCount - frames); pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[startFrames * channels]; + pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; pInBuffer->frameCount = startFrames; pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t)); + memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); mBufferQueue.add(pInBuffer); } else { LOGW ("OutputTrack::write() %p no more buffers in queue", this); @@ -2939,12 +2904,12 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr } uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; - memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t)); + memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); mCblk->stepUser(outFrames); pInBuffer->frameCount -= outFrames; - pInBuffer->i16 += outFrames * channels; + pInBuffer->i16 += outFrames * channelCount; mOutBuffer.frameCount -= outFrames; - mOutBuffer.i16 += outFrames * channels; + mOutBuffer.i16 += outFrames * channelCount; if (pInBuffer->frameCount == 0) { if (mBufferQueue.size()) { @@ -2964,10 +2929,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0 && !thread->standby()) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels]; + pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; pInBuffer->frameCount = inBuffer.frameCount; pInBuffer->i16 = pInBuffer->mBuffer; - memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t)); + memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t)); mBufferQueue.add(pInBuffer); LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); } else { @@ -2983,10 +2948,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (mCblk->user < mCblk->frameCount) { frames = mCblk->frameCount - mCblk->user; pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[frames * channels]; + pInBuffer->mBuffer = new int16_t[frames * channelCount]; pInBuffer->frameCount = frames; pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t)); + memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); mBufferQueue.add(pInBuffer); } else if (mActive) { stop(); @@ -3086,6 +3051,28 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const // ---------------------------------------------------------------------------- +AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, + const sp<IAudioFlingerClient>& client, + pid_t pid) + : mAudioFlinger(audioFlinger), mPid(pid), mClient(client) +{ +} + +AudioFlinger::NotificationClient::~NotificationClient() +{ + mClient.clear(); +} + +void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) +{ + sp<NotificationClient> keep(this); + { + mAudioFlinger->removeNotificationClient(mPid); + } +} + +// ---------------------------------------------------------------------------- + AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) : BnAudioTrack(), mTrack(track) @@ -3242,7 +3229,6 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, A mReqChannelCount = AudioSystem::popCount(channels); mReqSampleRate = sampleRate; readInputParameters(); - sendConfigEvent(AudioSystem::INPUT_OPENED); } @@ -3339,7 +3325,7 @@ bool AudioFlinger::RecordThread::threadLoop() framesIn = framesOut; mRsmpInIndex += framesIn; framesOut -= framesIn; - if (mChannelCount == mReqChannelCount || + if ((int)mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT) { memcpy(dst, src, framesIn * mFrameSize); } else { @@ -3360,7 +3346,7 @@ bool AudioFlinger::RecordThread::threadLoop() } if (framesOut && mFrameCount == mRsmpInIndex) { if (framesOut == mFrameCount && - (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) { + ((int)mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) { mBytesRead = mInput->read(buffer.raw, mInputBytes); framesOut = 0; } else { @@ -3657,14 +3643,14 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys) return mInput->getParameters(keys); } -void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) { +void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) { AudioSystem::OutputDescriptor desc; void *param2 = 0; switch (event) { case AudioSystem::INPUT_OPENED: case AudioSystem::INPUT_CONFIG_CHANGED: - desc.channels = mChannelCount; + desc.channels = mChannels; desc.samplingRate = mSampleRate; desc.format = mFormat; desc.frameCount = mFrameCount; @@ -3676,7 +3662,6 @@ void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) { default: break; } - Mutex::Autolock _l(mAudioFlinger->mLock); mAudioFlinger->audioConfigChanged_l(event, mId, param2); } @@ -3688,9 +3673,10 @@ void AudioFlinger::RecordThread::readInputParameters() mResampler = 0; mSampleRate = mInput->sampleRate(); - mChannelCount = AudioSystem::popCount(mInput->channels()); + mChannels = mInput->channels(); + mChannelCount = (uint16_t)AudioSystem::popCount(mChannels); mFormat = mInput->format(); - mFrameSize = mInput->frameSize(); + mFrameSize = (uint16_t)mInput->frameSize(); mInputBytes = mInput->bufferSize(); mFrameCount = mInputBytes / mFrameSize; mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount]; @@ -3795,6 +3781,8 @@ int AudioFlinger::openOutput(uint32_t *pDevices, if (pChannels) *pChannels = channels; if (pLatencyMs) *pLatencyMs = thread->latency(); + // notify client processes of the new output creation + thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); return mNextThreadId; } @@ -3816,6 +3804,8 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2) DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId); thread->addOutputTrack(thread2); mPlaybackThreads.add(mNextThreadId, thread); + // notify client processes of the new output creation + thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); return mNextThreadId; } @@ -3945,6 +3935,8 @@ int AudioFlinger::openInput(uint32_t *pDevices, input->standby(); + // notify client processes of the new input creation + thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED); return mNextThreadId; } @@ -3985,22 +3977,16 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) } LOGV("setStreamOutput() stream %d to output %d", stream, output); + audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream); for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); if (thread != dstThread && thread->type() != PlaybackThread::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; - SortedVector < sp<MixerThread::Track> > tracks; - SortedVector < wp<MixerThread::Track> > activeTracks; - srcThread->getTracks(tracks, activeTracks, stream); - if (tracks.size()) { - dstThread->putTracks(tracks, activeTracks); + srcThread->invalidateTracks(stream); } } - } - - dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream); return NO_ERROR; } diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 739ec33..f35f38b 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -57,7 +57,7 @@ class AudioResampler; static const nsecs_t kStandbyTimeInNsecs = seconds(3); -class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient +class AudioFlinger : public BnAudioFlinger { public: static void instantiate(); @@ -139,9 +139,6 @@ public: virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output); - // IBinder::DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - enum hardware_call_state { AUDIO_HW_IDLE = 0, AUDIO_HW_INIT, @@ -205,6 +202,27 @@ private: pid_t mPid; }; + // --- Notification Client --- + class NotificationClient : public IBinder::DeathRecipient { + public: + NotificationClient(const sp<AudioFlinger>& audioFlinger, + const sp<IAudioFlingerClient>& client, + pid_t pid); + virtual ~NotificationClient(); + + sp<IAudioFlingerClient> client() { return mClient; } + + // IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + + private: + NotificationClient(const NotificationClient&); + NotificationClient& operator = (const NotificationClient&); + + sp<AudioFlinger> mAudioFlinger; + pid_t mPid; + sp<IAudioFlingerClient> mClient; + }; class TrackHandle; class RecordHandle; @@ -324,7 +342,7 @@ private: virtual bool checkForNewParameters_l() = 0; virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys) = 0; - virtual void audioConfigChanged(int event, int param = 0) = 0; + virtual void audioConfigChanged_l(int event, int param = 0) = 0; void sendConfigEvent(int event, int param = 0); void sendConfigEvent_l(int event, int param = 0); void processConfigEvents(); @@ -348,9 +366,10 @@ private: sp<AudioFlinger> mAudioFlinger; uint32_t mSampleRate; size_t mFrameCount; - int mChannelCount; + uint32_t mChannels; + uint16_t mChannelCount; + uint16_t mFrameSize; int mFormat; - uint32_t mFrameSize; Condition mParamCond; Vector<String8> mNewParameters; status_t mParamStatus; @@ -528,7 +547,7 @@ private: void restore() { if (mSuspended) mSuspended--; } bool isSuspended() { return (mSuspended != 0); } virtual String8 getParameters(const String8& keys); - virtual void audioConfigChanged(int event, int param = 0); + virtual void audioConfigChanged_l(int event, int param = 0); virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); struct stream_type_t { @@ -594,11 +613,7 @@ private: // Thread virtuals virtual bool threadLoop(); - void getTracks(SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks, - int streamType); - void putTracks(SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks); + void invalidateTracks(int streamType); virtual bool checkForNewParameters_l(); virtual status_t dumpInternals(int fd, const Vector<String16>& args); @@ -685,6 +700,7 @@ private: void removeClient_l(pid_t pid); + void removeNotificationClient(pid_t pid); // record thread @@ -744,7 +760,7 @@ private: virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); virtual bool checkForNewParameters_l(); virtual String8 getParameters(const String8& keys); - virtual void audioConfigChanged(int event, int param = 0); + virtual void audioConfigChanged_l(int event, int param = 0); void readInputParameters(); virtual unsigned int getInputFramesLost(); @@ -796,8 +812,11 @@ private: DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads; - SortedVector< sp<IBinder> > mNotificationClients; + DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; int mNextThreadId; +#ifdef LVMX + int mLifeVibesClientPid; +#endif }; // ---------------------------------------------------------------------------- diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp index c8b3f48..381a958 100644 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ b/libs/audioflinger/AudioPolicyManagerBase.cpp @@ -1249,6 +1249,17 @@ void AudioPolicyManagerBase::closeA2dpOutputs() LOGV("setDeviceConnectionState() closing A2DP and duplicated output!"); if (mDuplicatedOutput != 0) { + AudioOutputDescriptor *dupOutputDesc = mOutputs.valueFor(mDuplicatedOutput); + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); + // As all active tracks on duplicated output will be deleted, + // and as they were also referenced on hardware output, the reference + // count for their stream type must be adjusted accordingly on + // hardware output. + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + int refCount = dupOutputDesc->mRefCount[i]; + hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); + } + mpClientInterface->closeOutput(mDuplicatedOutput); delete mOutputs.valueFor(mDuplicatedOutput); mOutputs.removeItem(mDuplicatedOutput); @@ -1288,11 +1299,6 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); - int refCount = a2dpOutputDesc->mRefCount[i]; - // in the case of duplicated output, the ref count is first incremented - // and then decremented on hardware output tus keeping its value - hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); - a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); } } // do not change newDevice if it was already set before this call by a previous call to @@ -1318,11 +1324,6 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); - int refCount = hwOutputDesc->mRefCount[i]; - // in the case of duplicated output, the ref count is first incremented - // and then decremented on hardware output tus keeping its value - a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); - hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); } } } diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index 86eb78d..b8a0630 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -13,6 +13,7 @@ LOCAL_SRC_FILES:= \ LayerDim.cpp \ MessageQueue.cpp \ SurfaceFlinger.cpp \ + TextureManager.cpp \ Tokenizer.cpp \ Transform.cpp diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h index e2bcf6a..6f8507e 100644 --- a/libs/surfaceflinger/Barrier.h +++ b/libs/surfaceflinger/Barrier.h @@ -29,10 +29,6 @@ public: inline Barrier() : state(CLOSED) { } inline ~Barrier() { } void open() { - // gcc memory barrier, this makes sure all memory writes - // have been issued by gcc. On an SMP system we'd need a real - // h/w barrier. - asm volatile ("":::"memory"); Mutex::Autolock _l(lock); state = OPENED; cv.broadcast(); diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index ea68352..51de1da 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -73,7 +73,7 @@ void checkEGLErrors(const char* token) DisplayHardware::DisplayHardware( const sp<SurfaceFlinger>& flinger, uint32_t dpy) - : DisplayHardwareBase(flinger, dpy) + : DisplayHardwareBase(flinger, dpy), mFlags(0) { init(dpy); } @@ -125,7 +125,6 @@ void DisplayHardware::init(uint32_t dpy) EGLint numConfigs=0; EGLSurface surface; EGLContext context; - mFlags = CACHED_BUFFERS; // TODO: all the extensions below should be queried through // eglGetProcAddress(). @@ -253,22 +252,10 @@ void DisplayHardware::init(uint32_t dpy) LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); -#if 0 - // for drivers that don't have proper support for flushing cached buffers - // on gralloc unlock, uncomment this block and test for the specific - // renderer substring - if (strstr(gl_renderer, "<some vendor string>")) { - LOGD("Assuming uncached graphics buffers."); - mFlags &= ~CACHED_BUFFERS; - } -#endif if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) { mFlags |= NPOT_EXTENSION; } - if (strstr(gl_extensions, "GL_OES_draw_texture")) { - mFlags |= DRAW_TEXTURE_EXTENSION; - } #ifdef EGL_ANDROID_image_native_buffer if (strstr( gl_extensions, "GL_OES_EGL_image") && (strstr(egl_extensions, "EGL_KHR_image_base") || diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h index df046af..ebd7c42 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -46,12 +46,10 @@ public: DIRECT_TEXTURE = 0x00000002, COPY_BITS_EXTENSION = 0x00000008, NPOT_EXTENSION = 0x00000100, - DRAW_TEXTURE_EXTENSION = 0x00000200, BUFFER_PRESERVED = 0x00010000, PARTIAL_UPDATES = 0x00020000, // video driver feature SLOW_CONFIG = 0x00040000, // software SWAP_RECTANGLE = 0x00080000, - CACHED_BUFFERS = 0x00100000 }; DisplayHardware( diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index ce7e9aa..3fbb4d3 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -47,47 +47,42 @@ template <typename T> inline T min(T a, T b) { // --------------------------------------------------------------------------- -const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4; -const char* const Layer::typeID = "Layer"; - -// --------------------------------------------------------------------------- - Layer::Layer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& c, int32_t i) - : LayerBaseClient(flinger, display, c, i), + const sp<Client>& client, int32_t i) + : LayerBaseClient(flinger, display, client, i), + lcblk(NULL), mSecure(false), - mNoEGLImageForSwBuffers(false), mNeedsBlending(true), - mNeedsDithering(false) + mNeedsDithering(false), + mTextureManager(mFlags), + mBufferManager(mTextureManager), + mWidth(0), mHeight(0), mFixedSize(false) { // no OpenGL operation is possible here, since we might not be // in the OpenGL thread. - mFrontBufferIndex = lcblk->getFrontBuffer(); + lcblk = new SharedBufferServer( + client->ctrlblk, i, mBufferManager.getDefaultBufferCount(), + getIdentity()); + + mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() ); } Layer::~Layer() { - destroy(); + // FIXME: must be called from the main UI thread + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + mBufferManager.destroy(dpy); + // the actual buffers will be destroyed here + delete lcblk; } -void Layer::destroy() +// called with SurfaceFlinger::mStateLock as soon as the layer is entered +// in the purgatory list +void Layer::onRemoved() { - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - if (mTextures[i].name != -1U) { - glDeleteTextures(1, &mTextures[i].name); - mTextures[i].name = -1U; - } - if (mTextures[i].image != EGL_NO_IMAGE_KHR) { - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTextures[i].image); - mTextures[i].image = EGL_NO_IMAGE_KHR; - } - Mutex::Autolock _l(mLock); - mBuffers[i].clear(); - mWidth = mHeight = 0; - } - mSurface.clear(); + // wake up the condition + lcblk->setStatus(NO_INIT); } sp<LayerBaseClient::Surface> Layer::createSurface() const @@ -97,9 +92,17 @@ sp<LayerBaseClient::Surface> Layer::createSurface() const status_t Layer::ditch() { + // NOTE: Called from the main UI thread + // the layer is not on screen anymore. free as much resources as possible mFreezeLock.clear(); - destroy(); + + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + mBufferManager.destroy(dpy); + mSurface.clear(); + + Mutex::Autolock _l(mLock); + mWidth = mHeight = 0; return NO_ERROR; } @@ -131,24 +134,19 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mHeight = h; mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; - mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS); // we use the red index int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); mNeedsDithering = layerRedsize > displayRedSize; - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - mBuffers[i] = new GraphicBuffer(); - } mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); return NO_ERROR; } void Layer::reloadTexture(const Region& dirty) { - Mutex::Autolock _l(mLock); - sp<GraphicBuffer> buffer(getFrontBufferLocked()); + sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); if (buffer == NULL) { // this situation can happen if we ran out of memory for instance. // not much we can do. continue to use whatever texture was bound @@ -156,118 +154,24 @@ void Layer::reloadTexture(const Region& dirty) return; } - const int index = mFrontBufferIndex; - - // create the new texture name if needed - if (UNLIKELY(mTextures[index].name == -1U)) { - mTextures[index].name = createTexture(); - mTextures[index].width = 0; - mTextures[index].height = 0; - } - #ifdef EGL_ANDROID_image_native_buffer if (mFlags & DisplayHardware::DIRECT_TEXTURE) { - if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) { - if (mTextures[index].dirty) { - if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) { - // not sure what we can do here... - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; - goto slowpath; - } - } - } else { - if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width || - mHybridBuffer->height != buffer->height)) { - mHybridBuffer.clear(); - mHybridBuffer = new GraphicBuffer( - buffer->width, buffer->height, buffer->format, - GraphicBuffer::USAGE_SW_WRITE_OFTEN | - GraphicBuffer::USAGE_HW_TEXTURE); - if (initializeEglImage( - mHybridBuffer, &mTextures[0]) != NO_ERROR) { - // not sure what we can do here... - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; - mHybridBuffer.clear(); - goto slowpath; - } - } - - GGLSurface t; - status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); - LOGE_IF(res, "error %d (%s) locking buffer %p", - res, strerror(res), buffer.get()); - if (res == NO_ERROR) { - Texture* const texture(&mTextures[0]); - - glBindTexture(GL_TEXTURE_2D, texture->name); - - sp<GraphicBuffer> buf(mHybridBuffer); - void* vaddr; - res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr); - if (res == NO_ERROR) { - int bpp = 0; - switch (t.format) { - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_RGBA_4444: - bpp = 2; - break; - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - bpp = 4; - break; - default: - if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - bpp = 1; - break; - } - // oops, we don't handle this format! - LOGE("layer %p, texture=%d, using format %d, which is not " - "supported by the GL", this, texture->name, t.format); - } - if (bpp) { - const Rect bounds(dirty.getBounds()); - size_t src_stride = t.stride; - size_t dst_stride = buf->stride; - if (src_stride == dst_stride && - bounds.width() == t.width && - bounds.height() == t.height) - { - memcpy(vaddr, t.data, t.height * t.stride * bpp); - } else { - GLubyte const * src = t.data + - (bounds.left + bounds.top * src_stride) * bpp; - GLubyte * dst = (GLubyte *)vaddr + - (bounds.left + bounds.top * dst_stride) * bpp; - const size_t length = bounds.width() * bpp; - size_t h = bounds.height(); - src_stride *= bpp; - dst_stride *= bpp; - while (h--) { - memcpy(dst, src, length); - dst += dst_stride; - src += src_stride; - } - } - } - buf->unlock(); - } - buffer->unlock(); - } + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) { + // not sure what we can do here... + mFlags &= ~DisplayHardware::DIRECT_TEXTURE; + goto slowpath; } } else #endif { slowpath: - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - mTextures[i].image = EGL_NO_IMAGE_KHR; - } GGLSurface t; status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); LOGE_IF(res, "error %d (%s) locking buffer %p", res, strerror(res), buffer.get()); if (res == NO_ERROR) { - loadTexture(&mTextures[0], dirty, t); + mBufferManager.loadTexture(dirty, t); buffer->unlock(); } } @@ -275,11 +179,8 @@ slowpath: void Layer::onDraw(const Region& clip) const { - int index = mFrontBufferIndex; - if (mTextures[index].image == EGL_NO_IMAGE_KHR) - index = 0; - GLuint textureName = mTextures[index].name; - if (UNLIKELY(textureName == -1LU)) { + Texture tex(mBufferManager.getActiveTexture()); + if (tex.name == -1LU) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with // SurfaceView because the WindowManager can't know when the client @@ -305,13 +206,53 @@ void Layer::onDraw(const Region& clip) const } return; } - drawWithOpenGL(clip, mTextures[index]); + drawWithOpenGL(clip, tex); +} + +bool Layer::needsFiltering() const +{ + if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { + // NOTE: there is a race here, because mFixedSize is updated in a + // binder transaction. however, it doesn't really matter since it is + // evaluated each time we draw. To be perfectly correct, this flag + // would have to be associated with a buffer. + if (mFixedSize) + return true; + } + return LayerBase::needsFiltering(); +} + + +status_t Layer::setBufferCount(int bufferCount) +{ + // Ensures our client doesn't go away while we're accessing + // the shared area. + sp<Client> ourClient(client.promote()); + if (ourClient == 0) { + // oops, the client is already gone + return DEAD_OBJECT; + } + + // NOTE: lcblk->resize() is protected by an internal lock + status_t err = lcblk->resize(bufferCount); + if (err == NO_ERROR) + mBufferManager.resize(bufferCount); + + return err; } -sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) +sp<GraphicBuffer> Layer::requestBuffer(int index, + uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat, + uint32_t usage) { sp<GraphicBuffer> buffer; + if ((reqWidth | reqHeight | reqFormat) < 0) + return buffer; + + if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight)) + return buffer; + // this ensures our client doesn't go away while we're accessing // the shared area. sp<Client> ourClient(client.promote()); @@ -324,7 +265,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) * This is called from the client's Surface::dequeue(). This can happen * at any time, especially while we're in the middle of using the * buffer 'index' as our front buffer. - * + * * Make sure the buffer we're resizing is not the front buffer and has been * dequeued. Once this condition is asserted, we are guaranteed that this * buffer cannot become the front buffer under our feet, since we're called @@ -337,31 +278,33 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) return buffer; } - uint32_t w, h; + uint32_t w, h, f; { // scope for the lock Mutex::Autolock _l(mLock); - w = mWidth; - h = mHeight; - buffer = mBuffers[index]; - - // destroy() could have been called before we get here, we log it - // because it's uncommon, and the code below should handle it - LOGW_IF(buffer==0, - "mBuffers[%d] is null (mWidth=%d, mHeight=%d)", - index, w, h); - - mBuffers[index].clear(); + const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight); + const bool formatChanged = mReqFormat != reqFormat; + mReqWidth = reqWidth; + mReqHeight = reqHeight; + mReqFormat = reqFormat; + mFixedSize = reqWidth && reqHeight; + w = reqWidth ? reqWidth : mWidth; + h = reqHeight ? reqHeight : mHeight; + f = reqFormat ? reqFormat : mFormat; + buffer = mBufferManager.detachBuffer(index); + if (fixedSizeChanged || formatChanged) { + lcblk->reallocateAllExcept(index); + } } const uint32_t effectiveUsage = getEffectiveUsage(usage); if (buffer!=0 && buffer->getStrongCount() == 1) { - err = buffer->reallocate(w, h, mFormat, effectiveUsage); + err = buffer->reallocate(w, h, f, effectiveUsage); } else { // here we have to reallocate a new buffer because we could have a // client in our process with a reference to it (eg: status bar), // and we can't release the handle under its feet. buffer.clear(); - buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage); + buffer = new GraphicBuffer(w, h, f, effectiveUsage); err = buffer->initCheck(); } @@ -377,15 +320,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) if (err == NO_ERROR && buffer->handle != 0) { Mutex::Autolock _l(mLock); - if (mWidth && mHeight) { - // and we have new buffer - mBuffers[index] = buffer; - // texture is now dirty... - mTextures[index].dirty = true; - } else { - // oops we got killed while we were allocating the buffer - buffer.clear(); - } + mBufferManager.attachBuffer(index, buffer); } return buffer; } @@ -411,15 +346,8 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const } else { // it's allowed to modify the usage flags here, but generally // the requested flags should be honored. - if (mNoEGLImageForSwBuffers) { - if (usage & GraphicBuffer::USAGE_HW_MASK) { - // request EGLImage for h/w buffers only - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - } - } else { - // request EGLImage for all buffers - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - } + // request EGLImage for all buffers + usage |= GraphicBuffer::USAGE_HW_TEXTURE; } return usage; } @@ -429,42 +357,46 @@ uint32_t Layer::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - if ((front.requested_w != temp.requested_w) || - (front.requested_h != temp.requested_h)) { + const bool sizeChanged = (front.requested_w != temp.requested_w) || + (front.requested_h != temp.requested_h); + + if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), " - "drawing (%d,%d), (%dx%d), (%dx%d)", - this, - int(temp.requested_w), int(temp.requested_h), - int(front.requested_w), int(front.requested_h), - int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()), - int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight())); - - // we're being resized and there is a freeze display request, - // acquire a freeze lock, so that the screen stays put - // until we've redrawn at the new size; this is to avoid - // glitches upon orientation changes. - if (mFlinger->hasFreezeRequest()) { - // if the surface is hidden, don't try to acquire the - // freeze lock, since hidden surfaces may never redraw - if (!(front.flags & ISurfaceComposer::eLayerHidden)) { - mFreezeLock = mFlinger->getFreezeLock(); + "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", + this, + int(temp.requested_w), int(temp.requested_h), + int(front.requested_w), int(front.requested_h)); + + if (!isFixedSize()) { + // we're being resized and there is a freeze display request, + // acquire a freeze lock, so that the screen stays put + // until we've redrawn at the new size; this is to avoid + // glitches upon orientation changes. + if (mFlinger->hasFreezeRequest()) { + // if the surface is hidden, don't try to acquire the + // freeze lock, since hidden surfaces may never redraw + if (!(front.flags & ISurfaceComposer::eLayerHidden)) { + mFreezeLock = mFlinger->getFreezeLock(); + } } - } - // this will make sure LayerBase::doTransaction doesn't update - // the drawing state's size - Layer::State& editDraw(mDrawingState); - editDraw.requested_w = temp.requested_w; - editDraw.requested_h = temp.requested_h; + // this will make sure LayerBase::doTransaction doesn't update + // the drawing state's size + Layer::State& editDraw(mDrawingState); + editDraw.requested_w = temp.requested_w; + editDraw.requested_h = temp.requested_h; - // record the new size, form this point on, when the client request a - // buffer, it'll get the new size. - setDrawingSize(temp.requested_w, temp.requested_h); + // record the new size, form this point on, when the client request + // a buffer, it'll get the new size. + setBufferSize(temp.requested_w, temp.requested_h); - // all buffers need reallocation - lcblk->reallocate(); + // all buffers need reallocation + lcblk->reallocateAll(); + } else { + // record the new size + setBufferSize(temp.requested_w, temp.requested_h); + } } if (temp.sequence != front.sequence) { @@ -478,12 +410,17 @@ uint32_t Layer::doTransaction(uint32_t flags) return LayerBase::doTransaction(flags); } -void Layer::setDrawingSize(uint32_t w, uint32_t h) { +void Layer::setBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock _l(mLock); mWidth = w; mHeight = h; } +bool Layer::isFixedSize() const { + Mutex::Autolock _l(mLock); + return mFixedSize; +} + // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- @@ -491,22 +428,25 @@ void Layer::setDrawingSize(uint32_t w, uint32_t h) { void Layer::lockPageFlip(bool& recomputeVisibleRegions) { ssize_t buf = lcblk->retireAndLock(); - if (buf < NO_ERROR) { - //LOGW("nothing to retire (%s)", strerror(-buf)); - // NOTE: here the buffer is locked because we will used + if (buf == NOT_ENOUGH_DATA) { + // NOTE: This is not an error, it simply means there is nothing to + // retire. The buffer is locked because we will use it // for composition later in the loop return; } - // ouch, this really should never happen - if (uint32_t(buf)>=NUM_BUFFERS) { + if (buf < NO_ERROR) { LOGE("retireAndLock() buffer index (%d) out of range", buf); mPostedDirtyRegion.clear(); return; } // we retired a buffer, which becomes the new front buffer - mFrontBufferIndex = buf; + if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { + LOGE("retireAndLock() buffer index (%d) out of range", buf); + mPostedDirtyRegion.clear(); + return; + } // get the dirty region sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); @@ -559,9 +499,15 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mFlinger->signalEvent(); } - if (!mPostedDirtyRegion.isEmpty()) { - reloadTexture( mPostedDirtyRegion ); - } + /* a buffer was posted, so we need to call reloadTexture(), which + * will update our internal data structures (eg: EGLImageKHR or + * texture names). we need to do this even if mPostedDirtyRegion is + * empty -- it's orthogonal to the fact that a new buffer was posted, + * for instance, a degenerate case could be that the user did an empty + * update but repainted the buffer with appropriate content (after a + * resize for instance). + */ + reloadTexture( mPostedDirtyRegion ); } void Layer::unlockPageFlip( @@ -585,17 +531,177 @@ void Layer::unlockPageFlip( } if (visibleRegionScreen.isEmpty()) { // an invisible layer should not hold a freeze-lock - // (because it may never be updated and thereore never release it) + // (because it may never be updated and therefore never release it) mFreezeLock.clear(); } } void Layer::finishPageFlip() { - status_t err = lcblk->unlock( mFrontBufferIndex ); - LOGE_IF(err!=NO_ERROR, - "layer %p, buffer=%d wasn't locked!", - this, mFrontBufferIndex); + int buf = mBufferManager.getActiveBufferIndex(); + status_t err = lcblk->unlock( buf ); + LOGE_IF(err!=NO_ERROR, "layer %p, buffer=%d wasn't locked!", this, buf); +} + + +void Layer::dump(String8& result, char* buffer, size_t SIZE) const +{ + LayerBaseClient::dump(result, buffer, SIZE); + + SharedBufferStack::Statistics stats = lcblk->getStats(); + result.append( lcblk->dump(" ") ); + sp<const GraphicBuffer> buf0(getBuffer(0)); + sp<const GraphicBuffer> buf1(getBuffer(1)); + uint32_t w0=0, h0=0, s0=0; + uint32_t w1=0, h1=0, s1=0; + if (buf0 != 0) { + w0 = buf0->getWidth(); + h0 = buf0->getHeight(); + s0 = buf0->getStride(); + } + if (buf1 != 0) { + w1 = buf1->getWidth(); + h1 = buf1->getHeight(); + s1 = buf1->getStride(); + } + snprintf(buffer, SIZE, + " " + "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," + " freezeLock=%p, dq-q-time=%u us\n", + pixelFormat(), + w0, h0, s0, w1, h1, s1, + getFreezeLock().get(), stats.totalTime); + + result.append(buffer); +} + +// --------------------------------------------------------------------------- + +Layer::BufferManager::BufferManager(TextureManager& tm) + : mNumBuffers(NUM_BUFFERS), mTextureManager(tm), + mActiveBuffer(0), mFailover(false) +{ +} + +Layer::BufferManager::~BufferManager() +{ +} + +status_t Layer::BufferManager::resize(size_t size) +{ + Mutex::Autolock _l(mLock); + mNumBuffers = size; + return NO_ERROR; +} + +// only for debugging +sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const { + return mBufferData[index].buffer; +} + +status_t Layer::BufferManager::setActiveBufferIndex(size_t index) { + // TODO: need to validate 'index' + mActiveBuffer = index; + return NO_ERROR; +} + +size_t Layer::BufferManager::getActiveBufferIndex() const { + return mActiveBuffer; +} + +Texture Layer::BufferManager::getActiveTexture() const { + Texture res; + if (mFailover) { + res = mFailoverTexture; + } else { + static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture; + } + return res; +} + +sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const { + const size_t activeBuffer = mActiveBuffer; + BufferData const * const buffers = mBufferData; + Mutex::Autolock _l(mLock); + return buffers[activeBuffer].buffer; +} + +sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index) +{ + BufferData* const buffers = mBufferData; + sp<GraphicBuffer> buffer; + Mutex::Autolock _l(mLock); + buffer = buffers[index].buffer; + buffers[index].buffer = 0; + return buffer; +} + +status_t Layer::BufferManager::attachBuffer(size_t index, + const sp<GraphicBuffer>& buffer) +{ + BufferData* const buffers = mBufferData; + Mutex::Autolock _l(mLock); + buffers[index].buffer = buffer; + buffers[index].texture.dirty = true; + return NO_ERROR; +} + +status_t Layer::BufferManager::destroy(EGLDisplay dpy) +{ + BufferData* const buffers = mBufferData; + size_t num; + { // scope for the lock + Mutex::Autolock _l(mLock); + num = mNumBuffers; + for (size_t i=0 ; i<num ; i++) { + buffers[i].buffer = 0; + } + } + for (size_t i=0 ; i<num ; i++) { + destroyTexture(&buffers[i].texture, dpy); + } + destroyTexture(&mFailoverTexture, dpy); + return NO_ERROR; +} + +status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, + const sp<GraphicBuffer>& buffer) +{ + size_t index = mActiveBuffer; + Image& texture(mBufferData[index].texture); + status_t err = mTextureManager.initEglImage(&texture, dpy, buffer); + // if EGLImage fails, we switch to regular texture mode, and we + // free all resources associated with using EGLImages. + if (err == NO_ERROR) { + mFailover = false; + destroyTexture(&mFailoverTexture, dpy); + } else { + mFailover = true; + const size_t num = mNumBuffers; + for (size_t i=0 ; i<num ; i++) { + destroyTexture(&mBufferData[i].texture, dpy); + } + } + return err; +} + +status_t Layer::BufferManager::loadTexture( + const Region& dirty, const GGLSurface& t) +{ + return mTextureManager.loadTexture(&mFailoverTexture, dirty, t); +} + +status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy) +{ + if (tex->name != -1U) { + glDeleteTextures(1, &tex->name); + tex->name = -1U; + } + if (tex->image != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(dpy, tex->image); + tex->image = EGL_NO_IMAGE_KHR; + } + return NO_ERROR; } // --------------------------------------------------------------------------- @@ -610,20 +716,37 @@ Layer::SurfaceLayer::~SurfaceLayer() { } -sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) +sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { sp<GraphicBuffer> buffer; sp<Layer> owner(getOwner()); if (owner != 0) { - LOGE_IF(uint32_t(index)>=NUM_BUFFERS, - "getBuffer() index (%d) out of range", index); - if (uint32_t(index) < NUM_BUFFERS) { - buffer = owner->requestBuffer(index, usage); - } + /* + * requestBuffer() cannot be called from the main thread + * as it could cause a dead-lock, since it may have to wait + * on conditions updated my the main thread. + */ + buffer = owner->requestBuffer(index, w, h, format, usage); } return buffer; } +status_t Layer::SurfaceLayer::setBufferCount(int bufferCount) +{ + status_t err = DEAD_OBJECT; + sp<Layer> owner(getOwner()); + if (owner != 0) { + /* + * setBufferCount() cannot be called from the main thread + * as it could cause a dead-lock, since it may have to wait + * on conditions updated my the main thread. + */ + err = owner->setBufferCount(bufferCount); + } + return err; +} + // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 743afb4..59603a5 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -31,6 +31,7 @@ #include "LayerBase.h" #include "Transform.h" +#include "TextureManager.h" namespace android { @@ -41,16 +42,13 @@ class FreezeLock; // --------------------------------------------------------------------------- -const size_t NUM_BUFFERS = 2; - class Layer : public LayerBaseClient { -public: - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - +public: + // lcblk is (almost) only accessed from the main SF thread, in the places + // where it's not, a reference to Client must be held + SharedBufferServer* lcblk; + Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); @@ -59,7 +57,8 @@ public: status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags=0); - void setDrawingSize(uint32_t w, uint32_t h); + void setBufferSize(uint32_t w, uint32_t h); + bool isFixedSize() const; virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); @@ -68,30 +67,32 @@ public: virtual void finishPageFlip(); virtual bool needsBlending() const { return mNeedsBlending; } virtual bool needsDithering() const { return mNeedsDithering; } + virtual bool needsFiltering() const; virtual bool isSecure() const { return mSecure; } virtual sp<Surface> createSurface() const; virtual status_t ditch(); + virtual void onRemoved(); // only for debugging - inline sp<GraphicBuffer> getBuffer(int i) { return mBuffers[i]; } + inline sp<GraphicBuffer> getBuffer(int i) const { return mBufferManager.getBuffer(i); } // only for debugging inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; } // only for debugging inline PixelFormat pixelFormat() const { return mFormat; } - // only for debugging - inline int getFrontBufferIndex() const { return mFrontBufferIndex; } + + virtual const char* getTypeId() const { return "Layer"; } + +protected: + virtual void dump(String8& result, char* scratch, size_t size) const; private: - inline sp<GraphicBuffer> getFrontBufferLocked() { - return mBuffers[mFrontBufferIndex]; - } - void reloadTexture(const Region& dirty); uint32_t getEffectiveUsage(uint32_t usage) const; - sp<GraphicBuffer> requestBuffer(int index, int usage); - void destroy(); + sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + status_t setBufferCount(int bufferCount); class SurfaceLayer : public LayerBaseClient::Surface { public: @@ -99,7 +100,9 @@ private: SurfaceID id, const sp<Layer>& owner); ~SurfaceLayer(); private: - virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + virtual status_t setBufferCount(int bufferCount); sp<Layer> getOwner() const { return static_cast<Layer*>(Surface::getOwner().get()); } @@ -109,22 +112,83 @@ private: sp<Surface> mSurface; bool mSecure; - bool mNoEGLImageForSwBuffers; int32_t mFrontBufferIndex; bool mNeedsBlending; bool mNeedsDithering; Region mPostedDirtyRegion; sp<FreezeLock> mFreezeLock; PixelFormat mFormat; - - // protected by mLock - sp<GraphicBuffer> mBuffers[NUM_BUFFERS]; - Texture mTextures[NUM_BUFFERS]; - sp<GraphicBuffer> mHybridBuffer; - uint32_t mWidth; - uint32_t mHeight; - - mutable Mutex mLock; + + class BufferManager { + static const size_t NUM_BUFFERS = 2; + struct BufferData { + sp<GraphicBuffer> buffer; + Image texture; + }; + // this lock protect mBufferData[].buffer but since there + // is very little contention, we have only one like for + // the whole array, we also use it to protect mNumBuffers. + mutable Mutex mLock; + BufferData mBufferData[SharedBufferStack::NUM_BUFFER_MAX]; + size_t mNumBuffers; + Texture mFailoverTexture; + TextureManager& mTextureManager; + ssize_t mActiveBuffer; + bool mFailover; + static status_t destroyTexture(Image* tex, EGLDisplay dpy); + + public: + static size_t getDefaultBufferCount() { return NUM_BUFFERS; } + BufferManager(TextureManager& tm); + ~BufferManager(); + + // detach/attach buffer from/to given index + sp<GraphicBuffer> detachBuffer(size_t index); + status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer); + + // resize the number of active buffers + status_t resize(size_t size); + + // ---------------------------------------------- + // must be called from GL thread + + // set/get active buffer index + status_t setActiveBufferIndex(size_t index); + size_t getActiveBufferIndex() const; + + // return the active buffer + sp<GraphicBuffer> getActiveBuffer() const; + + // return the active texture (or fail-over) + Texture getActiveTexture() const; + + // frees resources associated with all buffers + status_t destroy(EGLDisplay dpy); + + // load bitmap data into the active buffer + status_t loadTexture(const Region& dirty, const GGLSurface& t); + + // make active buffer an EGLImage if needed + status_t initEglImage(EGLDisplay dpy, + const sp<GraphicBuffer>& buffer); + + // ---------------------------------------------- + // only for debugging + sp<GraphicBuffer> getBuffer(size_t index) const; + }; + + TextureManager mTextureManager; + BufferManager mBufferManager; + + // this lock protects mWidth and mHeight which are accessed from + // the main thread and requestBuffer's binder transaction thread. + mutable Mutex mLock; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mReqWidth; + uint32_t mReqHeight; + uint32_t mReqFormat; + bool mFixedSize; }; // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index a8b735e..76733a9 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -32,29 +32,21 @@ #include "LayerBase.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "TextureManager.h" namespace android { // --------------------------------------------------------------------------- -const uint32_t LayerBase::typeInfo = 1; -const char* const LayerBase::typeID = "LayerBase"; - -const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2; -const char* const LayerBaseClient::typeID = "LayerBaseClient"; - -// --------------------------------------------------------------------------- - LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) : dpy(display), contentDirty(false), mFlinger(flinger), - mTransformed(false), - mUseLinearFiltering(false), + mNeedsFiltering(false), mOrientation(0), mLeft(0), mTop(0), mTransactionFlags(0), - mPremultipliedAlpha(true), mDebug(false), + mPremultipliedAlpha(true), mName("unnamed"), mDebug(false), mInvalidate(0) { const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); @@ -221,13 +213,12 @@ uint32_t LayerBase::doTransaction(uint32_t flags) flags |= eVisibleRegion; this->contentDirty = true; - const bool linearFiltering = mUseLinearFiltering; - mUseLinearFiltering = false; + mNeedsFiltering = false; if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { // we may use linear filtering, if the matrix scales us const uint8_t type = temp.transform.getType(); if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) { - mUseLinearFiltering = true; + mNeedsFiltering = true; } } } @@ -267,7 +258,6 @@ void LayerBase::validateVisibility(const Transform& planeTransform) // cache a few things... mOrientation = tr.getOrientation(); mTransformedBounds = tr.makeBounds(w, h); - mTransformed = transformed; mLeft = tr.tx(); mTop = tr.ty(); } @@ -348,25 +338,13 @@ void LayerBase::draw(const Region& inClip) const */ } -GLuint LayerBase::createTexture() const -{ - GLuint textureName = -1; - glGenTextures(1, &textureName); - glBindTexture(GL_TEXTURE_2D, textureName); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - return textureName; -} - -void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red, - GLclampx green, GLclampx blue, - GLclampx alpha) const +void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, + GLclampf green, GLclampf blue, + GLclampf alpha) const { const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t fbHeight = hw.getHeight(); - glColor4x(red,green,blue,alpha); + glColor4f(red,green,blue,alpha); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glDisable(GL_DITHER); @@ -374,7 +352,7 @@ void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red, Region::const_iterator it = clip.begin(); Region::const_iterator const end = clip.end(); glEnable(GL_SCISSOR_TEST); - glVertexPointer(2, GL_FIXED, 0, mVertices); + glVertexPointer(2, GL_FLOAT, 0, mVertices); while (it != end) { const Rect& r = *it++; const GLint sy = fbHeight - (r.top + r.height()); @@ -418,14 +396,14 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const env = GL_REPLACE; src = GL_SRC_ALPHA; } - const GGLfixed alpha = (s.alpha << 16)/255; - glColor4x(alpha, alpha, alpha, alpha); + const GLfloat alpha = s.alpha * (1.0f/255.0f); + glColor4f(alpha, alpha, alpha, alpha); glEnable(GL_BLEND); glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env); } else { glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glColor4x(0x10000, 0x10000, 0x10000, 0x10000); + glColor4f(1, 1, 1, 1); if (needsBlending()) { GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; glEnable(GL_BLEND); @@ -437,13 +415,11 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const Region::const_iterator it = clip.begin(); Region::const_iterator const end = clip.end(); - - //StopWatch watch("GL transformed"); - const GLfixed texCoords[4][2] = { - { 0, 0 }, - { 0, 0x10000 }, - { 0x10000, 0x10000 }, - { 0x10000, 0 } + const GLfloat texCoords[4][2] = { + { 0, 0 }, + { 0, 1 }, + { 1, 1 }, + { 1, 0 } }; glMatrixMode(GL_TEXTURE); @@ -470,8 +446,8 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const } glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FIXED, 0, mVertices); - glTexCoordPointer(2, GL_FIXED, 0, texCoords); + glVertexPointer(2, GL_FLOAT, 0, mVertices); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); while (it != end) { const Rect& r = *it++; @@ -487,7 +463,7 @@ void LayerBase::validateTexture(GLint textureName) const glBindTexture(GL_TEXTURE_2D, textureName); // TODO: reload the texture if needed // this is currently done in loadTexture() below - if (mUseLinearFiltering) { + if (needsFiltering()) { glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { @@ -502,200 +478,32 @@ void LayerBase::validateTexture(GLint textureName) const } } -bool LayerBase::isSupportedYuvFormat(int format) const +void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const { - switch (format) { - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_P: - case HAL_PIXEL_FORMAT_YCbCr_420_P: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - case HAL_PIXEL_FORMAT_YCbCr_420_I: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - return true; - } - return false; -} - -void LayerBase::loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t) const -{ - if (texture->name == -1U) { - // uh? - return; - } - - glBindTexture(GL_TEXTURE_2D, texture->name); - - /* - * In OpenGL ES we can't specify a stride with glTexImage2D (however, - * GL_UNPACK_ALIGNMENT is a limited form of stride). - * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we - * need to do something reasonable (here creating a bigger texture). - * - * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); - * - * This situation doesn't happen often, but some h/w have a limitation - * for their framebuffer (eg: must be multiple of 8 pixels), and - * we need to take that into account when using these buffers as - * textures. - * - * This should never be a problem with POT textures - */ - - int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); - unpack = 1 << ((unpack > 3) ? 3 : unpack); - glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); - - /* - * round to POT if needed - */ - if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) { - texture->NPOTAdjust = true; - } - - if (texture->NPOTAdjust) { - // find the smallest power-of-two that will accommodate our surface - texture->potWidth = 1 << (31 - clz(t.width)); - texture->potHeight = 1 << (31 - clz(t.height)); - if (texture->potWidth < t.width) texture->potWidth <<= 1; - if (texture->potHeight < t.height) texture->potHeight <<= 1; - texture->wScale = float(t.width) / texture->potWidth; - texture->hScale = float(t.height) / texture->potHeight; - } else { - texture->potWidth = t.width; - texture->potHeight = t.height; - } - - Rect bounds(dirty.bounds()); - GLvoid* data = 0; - if (texture->width != t.width || texture->height != t.height) { - texture->width = t.width; - texture->height = t.height; - - // texture size changed, we need to create a new one - bounds.set(Rect(t.width, t.height)); - if (t.width == texture->potWidth && - t.height == texture->potHeight) { - // we can do it one pass - data = t.data; - } - - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGB, texture->potWidth, texture->potHeight, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexImage2D(GL_TEXTURE_2D, 0, - GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, - GL_LUMINANCE, GL_UNSIGNED_BYTE, data); - } else { - // oops, we don't handle this format! - LOGE("layer %p, texture=%d, using format %d, which is not " - "supported by the GL", this, texture->name, t.format); - } - } - if (!data) { - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride*4); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_LUMINANCE, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride); - } - } -} - -status_t LayerBase::initializeEglImage( - const sp<GraphicBuffer>& buffer, Texture* texture) -{ - status_t err = NO_ERROR; - - // we need to recreate the texture - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - - // free the previous image - if (texture->image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, texture->image); - texture->image = EGL_NO_IMAGE_KHR; - } - - // construct an EGL_NATIVE_BUFFER_ANDROID - android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); - - // create the new EGLImageKHR - const EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, EGL_NONE - }; - texture->image = eglCreateImageKHR( - dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer)clientBuf, attrs); - - if (texture->image != EGL_NO_IMAGE_KHR) { - glBindTexture(GL_TEXTURE_2D, texture->name); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - (GLeglImageOES)texture->image); - GLint error = glGetError(); - if (UNLIKELY(error != GL_NO_ERROR)) { - LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) " - "failed err=0x%04x", - this, texture->image, error); - err = INVALID_OPERATION; - } else { - // Everything went okay! - texture->NPOTAdjust = false; - texture->dirty = false; - texture->width = clientBuf->width; - texture->height = clientBuf->height; - } - } else { - LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x", - this, eglGetError()); - err = INVALID_OPERATION; - } - return err; + const Layer::State& s(drawingState()); + snprintf(buffer, SIZE, + "+ %s %p\n" + " " + "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " + "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " + "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", + getTypeId(), this, s.z, tx(), ty(), s.w, s.h, + needsBlending(), needsDithering(), contentDirty, + s.alpha, s.flags, + s.transform[0][0], s.transform[0][1], + s.transform[1][0], s.transform[1][1]); + result.append(buffer); } - // --------------------------------------------------------------------------- -int32_t LayerBaseClient::sIdentity = 0; +int32_t LayerBaseClient::sIdentity = 1; LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i) - : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i), + : LayerBase(flinger, display), client(client), mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity))) { - lcblk = new SharedBufferServer( - client->ctrlblk, i, NUM_BUFFERS, - mIdentity); } void LayerBaseClient::onFirstRef() @@ -712,16 +520,15 @@ LayerBaseClient::~LayerBaseClient() if (client != 0) { client->free(mIndex); } - delete lcblk; } -int32_t LayerBaseClient::serverIndex() const +ssize_t LayerBaseClient::serverIndex() const { sp<Client> client(this->client.promote()); if (client != 0) { return (client->cid<<16)|mIndex; } - return 0xFFFF0000 | mIndex; + return ssize_t(0xFFFF0000 | mIndex); } sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() @@ -742,12 +549,19 @@ sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const const_cast<LayerBaseClient *>(this)); } -// called with SurfaceFlinger::mStateLock as soon as the layer is entered -// in the purgatory list -void LayerBaseClient::onRemoved() +void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const { - // wake up the condition - lcblk->setStatus(NO_INIT); + LayerBase::dump(result, buffer, SIZE); + + sp<Client> client(this->client.promote()); + snprintf(buffer, SIZE, + " name=%s\n" + " id=0x%08x, client=0x%08x, identity=%u\n", + getName().string(), + clientIndex(), client.get() ? client->cid : 0, + getIdentity()); + + result.append(buffer); } // --------------------------------------------------------------------------- @@ -799,11 +613,17 @@ status_t LayerBaseClient::Surface::onTransact( return BnSurface::onTransact(code, data, reply, flags); } -sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) +sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { return NULL; } +status_t LayerBaseClient::Surface::setBufferCount(int bufferCount) +{ + return INVALID_OPERATION; +} + status_t LayerBaseClient::Surface::registerBuffers( const ISurface::BufferHeap& buffers) { diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index 62ec839..2e2f2df 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -29,7 +29,7 @@ #include <ui/Region.h> #include <ui/Overlay.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <private/surfaceflinger/SharedBufferStack.h> #include <private/surfaceflinger/LayerState.h> @@ -46,40 +46,15 @@ class Client; class GraphicBuffer; class GraphicPlane; class SurfaceFlinger; +class Texture; // --------------------------------------------------------------------------- class LayerBase : public RefBase { - // poor man's dynamic_cast below - template<typename T> - struct getTypeInfoOfAnyType { - static uint32_t get() { return T::typeInfo; } - }; - - template<typename T> - struct getTypeInfoOfAnyType<T*> { - static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); } - }; - public: - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - - template<typename T> - static T dynamicCast(LayerBase* base) { - uint32_t mostDerivedInfo = base->getTypeInfo(); - uint32_t castToInfo = getTypeInfoOfAnyType<T>::get(); - if ((mostDerivedInfo & castToInfo) == castToInfo) - return static_cast<T>(base); - return 0; - } + LayerBase(SurfaceFlinger* flinger, DisplayID display); - - LayerBase(SurfaceFlinger* flinger, DisplayID display); - DisplayID dpy; mutable bool contentDirty; Region visibleRegionScreen; @@ -125,6 +100,9 @@ public: void invalidate(); + virtual const char* getTypeId() const { return "LayerBase"; } + virtual ssize_t serverIndex() const { return -1; } + /** * draw - performs some global clipping optimizations * and calls onDraw(). @@ -199,9 +177,9 @@ public: virtual bool needsDithering() const { return false; } /** - * transformed -- true is this surface needs a to be transformed + * needsLinearFiltering - true if this surface needs filtering */ - virtual bool transformed() const { return mTransformed; } + virtual bool needsFiltering() const { return mNeedsFiltering; } /** * isSecure - true if this surface is secure, that is if it prevents @@ -217,7 +195,10 @@ public: * current list */ virtual void onRemoved() { }; - + /** always call base class first */ + virtual void dump(String8& result, char* scratch, size_t size) const; + + enum { // flags for doTransaction() eVisibleRegion = 0x00000002, }; @@ -241,44 +222,18 @@ protected: const GraphicPlane& graphicPlane(int dpy) const; GraphicPlane& graphicPlane(int dpy); - GLuint createTexture() const; - - struct Texture { - Texture() : name(-1U), width(0), height(0), - image(EGL_NO_IMAGE_KHR), transform(0), - NPOTAdjust(false), dirty(true) { } - GLuint name; - GLuint width; - GLuint height; - GLuint potWidth; - GLuint potHeight; - GLfloat wScale; - GLfloat hScale; - EGLImageKHR image; - uint32_t transform; - bool NPOTAdjust; - bool dirty; - }; - - void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g, - GLclampx b, GLclampx alpha) const; + void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g, + GLclampf b, GLclampf alpha) const; void clearWithOpenGL(const Region& clip) const; void drawWithOpenGL(const Region& clip, const Texture& texture) const; - void loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t) const; - status_t initializeEglImage( - const sp<GraphicBuffer>& buffer, Texture* texture); - - bool isSupportedYuvFormat(int format) const; sp<SurfaceFlinger> mFlinger; uint32_t mFlags; // cached during validateVisibility() - bool mTransformed; - bool mUseLinearFiltering; + bool mNeedsFiltering; int32_t mOrientation; - GLfixed mVertices[4][2]; + GLfloat mVertices[4][2]; Rect mTransformedBounds; int mLeft; int mTop; @@ -313,14 +268,6 @@ class LayerBaseClient : public LayerBase { public: class Surface; - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - - // lcblk is (almost) only accessed from the main SF thread, in the places - // where it's not, a reference to Client must be held - SharedBufferServer* lcblk; LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); @@ -331,14 +278,11 @@ public: inline uint32_t getIdentity() const { return mIdentity; } inline int32_t clientIndex() const { return mIndex; } - int32_t serverIndex() const; - sp<Surface> getSurface(); virtual sp<Surface> createSurface() const; - - virtual void onRemoved(); - + virtual ssize_t serverIndex() const; + virtual const char* getTypeId() const { return "LayerBaseClient"; } class Surface : public BnSurface { @@ -356,7 +300,10 @@ public: sp<LayerBaseClient> getOwner() const; private: - virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + virtual status_t setBufferCount(int bufferCount); + virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); @@ -373,8 +320,11 @@ public: friend class Surface; +protected: + virtual void dump(String8& result, char* scratch, size_t size) const; + private: - int32_t mIndex; + int32_t mIndex; mutable Mutex mLock; mutable wp<Surface> mClientSurface; // only read diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp index 5fd7904..09c90e8 100644 --- a/libs/surfaceflinger/LayerBlur.cpp +++ b/libs/surfaceflinger/LayerBlur.cpp @@ -33,11 +33,6 @@ namespace android { // --------------------------------------------------------------------------- -const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8; -const char* const LayerBlur::typeID = "LayerBlur"; - -// --------------------------------------------------------------------------- - LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i) : LayerBaseClient(flinger, display, client, i), mCacheDirty(true), @@ -100,7 +95,9 @@ void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirty mCacheDirty = false; } else { if (!mAutoRefreshPending) { - mFlinger->signalDelayedEvent(ms2ns(500)); + mFlinger->postMessageAsync( + new MessageBase(MessageQueue::INVALIDATE), + ms2ns(500)); mAutoRefreshPending = true; } } @@ -206,8 +203,8 @@ void LayerBlur::onDraw(const Region& clip) const const State& s = drawingState(); if (UNLIKELY(s.alpha < 0xFF)) { - const GGLfixed alpha = (s.alpha << 16)/255; - glColor4x(0, 0, 0, alpha); + const GLfloat alpha = s.alpha * (1.0f/255.0f); + glColor4f(0, 0, 0, alpha); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); @@ -225,38 +222,20 @@ void LayerBlur::onDraw(const Region& clip) const glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (UNLIKELY(transformed() - || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) { - // This is a very rare scenario. - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(mWidthScale, mHeightScale, 1); - glTranslatef(-x, mYOffset - y, 0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FIXED, 0, mVertices); - glTexCoordPointer(2, GL_FIXED, 0, mVertices); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } else { - // NOTE: this is marginally faster with the software gl, because - // glReadPixels() reads the fb bottom-to-top, however we'll - // skip all the jaccobian computations. - Rect r; - GLint crop[4] = { 0, 0, w, h }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - y = fbHeight - (y + h); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawTexiOES(x, y, 0, w, h); - } + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glScalef(mWidthScale, mHeightScale, 1); + glTranslatef(-x, mYOffset - y, 0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, mVertices); + glTexCoordPointer(2, GL_FLOAT, 0, mVertices); + while (it != end) { + const Rect& r = *it++; + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } + glDisableClientState(GL_TEXTURE_COORD_ARRAY); } } diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h index 5b63dec..380f587 100644 --- a/libs/surfaceflinger/LayerBlur.h +++ b/libs/surfaceflinger/LayerBlur.h @@ -31,11 +31,6 @@ namespace android { class LayerBlur : public LayerBaseClient { public: - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - LayerBlur(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); virtual ~LayerBlur(); @@ -43,6 +38,7 @@ public: virtual void onDraw(const Region& clip) const; virtual bool needsBlending() const { return true; } virtual bool isSecure() const { return false; } + virtual const char* getTypeId() const { return "LayerBlur"; } virtual uint32_t doTransaction(uint32_t flags); virtual void setVisibleRegion(const Region& visibleRegion); diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index 5c21593..8a582da 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -39,8 +39,6 @@ namespace android { // --------------------------------------------------------------------------- -const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20; -const char* const LayerBuffer::typeID = "LayerBuffer"; gralloc_module_t const* LayerBuffer::sGrallocModule = 0; // --------------------------------------------------------------------------- @@ -120,7 +118,7 @@ uint32_t LayerBuffer::doTransaction(uint32_t flags) source->onTransaction(flags); uint32_t res = LayerBase::doTransaction(flags); // we always want filtering for these surfaces - mUseLinearFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG); + mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG); return res; } @@ -145,14 +143,6 @@ void LayerBuffer::onDraw(const Region& clip) const } } -bool LayerBuffer::transformed() const -{ - sp<Source> source(getSource()); - if (LIKELY(source != 0)) - return source->transformed(); - return false; -} - void LayerBuffer::serverDestroy() { sp<Source> source(clearSource()); @@ -321,16 +311,13 @@ void LayerBuffer::Source::postBuffer(ssize_t offset) { } void LayerBuffer::Source::unregisterBuffers() { } -bool LayerBuffer::Source::transformed() const { - return mLayer.mTransformed; -} // --------------------------------------------------------------------------- LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers) : Source(layer), mStatus(NO_ERROR), mBufferSize(0), - mUseEGLImageDirectly(true) + mTextureManager(layer.mFlags) { if (buffers.heap == NULL) { // this is allowed, but in this case, it is illegal to receive @@ -444,11 +431,6 @@ void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer) mBuffer = buffer; } -bool LayerBuffer::BufferSource::transformed() const -{ - return mBufferHeap.transform ? true : Source::transformed(); -} - void LayerBuffer::BufferSource::onDraw(const Region& clip) const { sp<Buffer> ourBuffer(getBuffer()); @@ -462,35 +444,10 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const NativeBuffer src(ourBuffer->getBuffer()); const Rect transformedBounds(mLayer.getTransformedBounds()); - if (UNLIKELY(mTexture.name == -1LU)) { - mTexture.name = mLayer.createTexture(); - } - #if defined(EGL_ANDROID_image_native_buffer) if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) { err = INVALID_OPERATION; if (ourBuffer->supportsCopybit()) { - - // there are constraints on buffers used by the GPU and these may not - // be honored here. We need to change the API so the buffers - // are allocated with gralloc. For now disable this code-path -#if 0 - // First, try to use the buffer as an EGLImage directly - if (mUseEGLImageDirectly) { - // NOTE: Assume the buffer is allocated with the proper USAGE flags - - sp<GraphicBuffer> buffer = new GraphicBuffer( - src.img.w, src.img.h, src.img.format, - GraphicBuffer::USAGE_HW_TEXTURE, - src.img.w, src.img.handle, false); - - err = mLayer.initializeEglImage(buffer, &mTexture); - if (err != NO_ERROR) { - mUseEGLImageDirectly = false; - } - } -#endif - copybit_device_t* copybit = mLayer.mBlitEngine; if (copybit && err != NO_ERROR) { // create our EGLImageKHR the first time @@ -527,7 +484,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const t.format = src.img.format; t.data = (GGLubyte*)src.img.base; const Region dirty(Rect(t.width, t.height)); - mLayer.loadTexture(&mTexture, dirty, t); + mTextureManager.loadTexture(&mTexture, dirty, t); } mTexture.transform = mBufferHeap.transform; @@ -569,7 +526,7 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const // figure out if we need linear filtering if (buffers.w * h == buffers.h * w) { // same pixel area, don't use filtering - mLayer.mUseLinearFiltering = false; + mLayer.mNeedsFiltering = false; } // Allocate a temporary buffer and create the corresponding EGLImageKHR @@ -593,7 +550,8 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const dst.crop.r = w; dst.crop.b = h; - err = mLayer.initializeEglImage(buffer, &mTexture); + EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); + err = mTextureManager.initEglImage(&mTexture, dpy, buffer); } return err; @@ -609,7 +567,6 @@ void LayerBuffer::BufferSource::clearTempBufferImage() const glDeleteTextures(1, &mTexture.name); Texture defaultTexture; mTexture = defaultTexture; - mTexture.name = mLayer.createTexture(); } // --------------------------------------------------------------------------- @@ -665,9 +622,9 @@ LayerBuffer::OverlaySource::~OverlaySource() void LayerBuffer::OverlaySource::onDraw(const Region& clip) const { // this would be where the color-key would be set, should we need it. - GLclampx red = 0; - GLclampx green = 0; - GLclampx blue = 0; + GLclampf red = 0; + GLclampf green = 0; + GLclampf blue = 0; mLayer.clearWithOpenGL(clip, red, green, blue, 0); } diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index b176623..d38dde2 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include "LayerBase.h" +#include "TextureManager.h" struct copybit_device_t; @@ -45,31 +46,25 @@ class LayerBuffer : public LayerBaseClient virtual void onVisibilityResolved(const Transform& planeTransform); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); - virtual bool transformed() const; virtual void destroy() { } protected: LayerBuffer& mLayer; }; public: - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - LayerBuffer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); virtual ~LayerBuffer(); virtual void onFirstRef(); virtual bool needsBlending() const; + virtual const char* getTypeId() const { return "LayerBuffer"; } virtual sp<LayerBaseClient::Surface> createSurface() const; virtual status_t ditch(); virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t flags); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - virtual bool transformed() const; status_t registerBuffers(const ISurface::BufferHeap& buffers); void postBuffer(ssize_t offset); @@ -133,7 +128,6 @@ private: virtual void onDraw(const Region& clip) const; virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); - virtual bool transformed() const; virtual void destroy() { } private: status_t initTempBuffer() const; @@ -143,9 +137,9 @@ private: status_t mStatus; ISurface::BufferHeap mBufferHeap; size_t mBufferSize; - mutable LayerBase::Texture mTexture; + mutable Texture mTexture; mutable NativeBuffer mTempBuffer; - mutable bool mUseEGLImageDirectly; + mutable TextureManager mTextureManager; }; class OverlaySource : public Source { diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp index fd61e30..568fedb 100644 --- a/libs/surfaceflinger/LayerDim.cpp +++ b/libs/surfaceflinger/LayerDim.cpp @@ -30,9 +30,6 @@ namespace android { // --------------------------------------------------------------------------- -const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10; -const char* const LayerDim::typeID = "LayerDim"; - bool LayerDim::sUseTexture; GLuint LayerDim::sTexId; EGLImageKHR LayerDim::sImage; diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h index d4672a1..19a9990 100644 --- a/libs/surfaceflinger/LayerDim.h +++ b/libs/surfaceflinger/LayerDim.h @@ -37,11 +37,6 @@ class LayerDim : public LayerBaseClient static int32_t sWidth; static int32_t sHeight; public: - static const uint32_t typeInfo; - static const char* const typeID; - virtual char const* getTypeID() const { return typeID; } - virtual uint32_t getTypeInfo() const { return typeInfo; } - LayerDim(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); virtual ~LayerDim(); @@ -49,6 +44,7 @@ public: virtual void onDraw(const Region& clip) const; virtual bool needsBlending() const { return true; } virtual bool isSecure() const { return false; } + virtual const char* getTypeId() const { return "LayerDim"; } static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h); }; diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp index b43d801..d668e88 100644 --- a/libs/surfaceflinger/MessageQueue.cpp +++ b/libs/surfaceflinger/MessageQueue.cpp @@ -60,9 +60,9 @@ MessageQueue::~MessageQueue() { } -MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout) +sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout) { - MessageList::value_type result; + sp<MessageBase> result; bool again; do { @@ -132,6 +132,7 @@ MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout) if (again) { // the message has been processed. release our reference to it // without holding the lock. + result->notify(); result = 0; } @@ -141,7 +142,7 @@ MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout) } status_t MessageQueue::postMessage( - const MessageList::value_type& message, nsecs_t relTime, uint32_t flags) + const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) { return queueMessage(message, relTime, flags); } @@ -154,7 +155,7 @@ status_t MessageQueue::invalidate() { } status_t MessageQueue::queueMessage( - const MessageList::value_type& message, nsecs_t relTime, uint32_t flags) + const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) { Mutex::Autolock _l(mLock); message->when = systemTime() + relTime; @@ -167,13 +168,13 @@ status_t MessageQueue::queueMessage( return NO_ERROR; } -void MessageQueue::dump(const MessageList::value_type& message) +void MessageQueue::dump(const sp<MessageBase>& message) { Mutex::Autolock _l(mLock); dumpLocked(message); } -void MessageQueue::dumpLocked(const MessageList::value_type& message) +void MessageQueue::dumpLocked(const sp<MessageBase>& message) { LIST::const_iterator cur(mMessages.begin()); LIST::const_iterator end(mMessages.end()); diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h index dc8138d..890f809 100644 --- a/libs/surfaceflinger/MessageQueue.h +++ b/libs/surfaceflinger/MessageQueue.h @@ -25,6 +25,7 @@ #include <utils/Timers.h> #include <utils/List.h> +#include "Barrier.h" namespace android { @@ -37,7 +38,6 @@ class MessageList List< sp<MessageBase> > mList; typedef List< sp<MessageBase> > LIST; public: - typedef sp<MessageBase> value_type; inline LIST::iterator begin() { return mList.begin(); } inline LIST::const_iterator begin() const { return mList.begin(); } inline LIST::iterator end() { return mList.end(); } @@ -63,11 +63,19 @@ public: // return true if message has a handler virtual bool handler() { return false; } + + // waits for the handler to be processed + void wait() const { barrier.wait(); } + // releases all waiters. this is done automatically if + // handler returns true + void notify() const { barrier.open(); } + protected: virtual ~MessageBase() { } private: + mutable Barrier barrier; friend class LightRefBase<MessageBase>; }; @@ -82,42 +90,33 @@ class MessageQueue typedef List< sp<MessageBase> > LIST; public: - // this is a work-around the multichar constant warning. A macro would - // work too, but would pollute the namespace. - template <int a, int b, int c, int d> - struct WHAT { - static const uint32_t Value = - (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)| - (uint32_t(c&0xff)<<8)|uint32_t(d&0xff); - }; - MessageQueue(); ~MessageQueue(); // pre-defined messages enum { - INVALIDATE = WHAT<'_','p','d','t'>::Value + INVALIDATE = '_upd' }; - MessageList::value_type waitMessage(nsecs_t timeout = -1); + sp<MessageBase> waitMessage(nsecs_t timeout = -1); - status_t postMessage(const MessageList::value_type& message, + status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0, uint32_t flags = 0); - + status_t invalidate(); - void dump(const MessageList::value_type& message); + void dump(const sp<MessageBase>& message); private: - status_t queueMessage(const MessageList::value_type& message, + status_t queueMessage(const sp<MessageBase>& message, nsecs_t reltime, uint32_t flags); - void dumpLocked(const MessageList::value_type& message); + void dumpLocked(const sp<MessageBase>& message); Mutex mLock; Condition mCondition; MessageList mMessages; bool mInvalidate; - MessageList::value_type mInvalidateMessage; + sp<MessageBase> mInvalidateMessage; }; // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 0722fda..fff0853 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -206,8 +206,8 @@ void SurfaceFlinger::init() property_get("debug.sf.showbackground", value, "0"); mDebugBackground = atoi(value); - LOGI_IF(mDebugRegion, "showupdates enabled"); - LOGI_IF(mDebugBackground, "showbackground enabled"); + LOGI_IF(mDebugRegion, "showupdates enabled"); + LOGI_IF(mDebugBackground, "showbackground enabled"); } SurfaceFlinger::~SurfaceFlinger() @@ -225,7 +225,7 @@ sp<IMemoryHeap> SurfaceFlinger::getCblk() const return mServerHeap; } -sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection() +sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { Mutex::Autolock _l(mStateLock); uint32_t token = mTokens.acquire(); @@ -357,7 +357,6 @@ status_t SurfaceFlinger::readyToRun() dcblk->ydpi = hw.getDpiY(); dcblk->fps = hw.getRefreshRate(); dcblk->density = hw.getDensity(); - asm volatile ("":::"memory"); // Initialize OpenGL|ES glActiveTexture(GL_TEXTURE0); @@ -427,7 +426,7 @@ void SurfaceFlinger::waitForEvent() timeout = waitTime>0 ? waitTime : 0; } - MessageList::value_type msg = mEventQueue.waitMessage(timeout); + sp<MessageBase> msg = mEventQueue.waitMessage(timeout); // see if we timed out if (isFrozen()) { @@ -462,9 +461,20 @@ void SurfaceFlinger::signal() const { const_cast<SurfaceFlinger*>(this)->signalEvent(); } -void SurfaceFlinger::signalDelayedEvent(nsecs_t delay) +status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t flags) { - mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay); + return mEventQueue.postMessage(msg, reltime, flags); +} + +status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t flags) +{ + status_t res = mEventQueue.postMessage(msg, reltime, flags); + if (res == NO_ERROR) { + msg->wait(); + } + return res; } // ---------------------------------------------------------------------------- @@ -1079,15 +1089,15 @@ status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) { - if (layer == 0) - return BAD_VALUE; ssize_t i = mCurrentState.layersSortedByZ.add( layer, &LayerBase::compareCurrentStateZ); - sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get()); - if (lbc != 0) { - mLayerMap.add(lbc->serverIndex(), lbc); - } - return NO_ERROR; + return (i < 0) ? status_t(i) : status_t(NO_ERROR); +} + +status_t SurfaceFlinger::addClientLayer_l(const sp<LayerBaseClient>& lbc) +{ + ssize_t serverIndex = lbc->serverIndex(); + return mLayerMap.add(serverIndex, lbc); } status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) @@ -1095,10 +1105,9 @@ status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); if (index >= 0) { mLayersRemoved = true; - sp<LayerBaseClient> layer = - LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get()); - if (layer != 0) { - mLayerMap.removeItem(layer->serverIndex()); + ssize_t serverIndex = layerBase->serverIndex(); + if (serverIndex >= 0) { + mLayerMap.removeItem(serverIndex); } return NO_ERROR; } @@ -1137,15 +1146,11 @@ uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) return android_atomic_and(~flags, &mTransactionFlags) & flags; } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay) +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { uint32_t old = android_atomic_or(flags, &mTransactionFlags); if ((old & flags)==0) { // wake the server up - if (delay > 0) { - signalDelayedEvent(delay); - } else { - signalEvent(); - } + signalEvent(); } return old; } @@ -1225,7 +1230,7 @@ int SurfaceFlinger::setOrientation(DisplayID dpy, } sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, - const String8& name, ISurfaceFlingerClient::surface_data_t* params, + const String8& name, ISurfaceComposerClient::surface_data_t* params, DisplayID d, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { @@ -1247,7 +1252,7 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, //LOGD("createSurface for pid %d (%d x %d)", pid, w, h); int32_t id = client->generateId(pid); - if (uint32_t(id) >= NUM_LAYERS_MAX) { + if (uint32_t(id) >= SharedBufferStack::NUM_LAYERS_MAX) { LOGE("createSurface() failed, generateId = %d", id); return surfaceHandle; } @@ -1298,7 +1303,7 @@ sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked( format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: - format = PIXEL_FORMAT_RGB_565; + format = PIXEL_FORMAT_RGBX_8888; break; } @@ -1307,6 +1312,7 @@ sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked( if (LIKELY(err == NO_ERROR)) { layer->initStates(w, h, flags); addLayer_l(layer); + addClientLayer_l(layer); } else { LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err)); layer.clear(); @@ -1321,6 +1327,7 @@ sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked( sp<LayerBlur> layer = new LayerBlur(this, display, client, id); layer->initStates(w, h, flags); addLayer_l(layer); + addClientLayer_l(layer); return layer; } @@ -1331,6 +1338,7 @@ sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked( sp<LayerDim> layer = new LayerDim(this, display, client, id); layer->initStates(w, h, flags); addLayer_l(layer); + addClientLayer_l(layer); return layer; } @@ -1341,6 +1349,7 @@ sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked( sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id); layer->initStates(w, h, flags); addLayer_l(layer); + addClientLayer_l(layer); return layer; } @@ -1397,7 +1406,7 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) } }; - mEventQueue.postMessage( new MessageDestroySurface(this, layer) ); + postMessageAsync( new MessageDestroySurface(this, layer) ); return NO_ERROR; } @@ -1512,83 +1521,17 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } - size_t s = mClientsMap.size(); - char name[64]; - for (size_t i=0 ; i<s ; i++) { - sp<Client> client = mClientsMap.valueAt(i); - sprintf(name, " Client (id=0x%08x)", client->cid); - client->dump(name); - } const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { - /*** LayerBase ***/ - const sp<LayerBase>& layer = currentLayers[i]; - const Layer::State& s = layer->drawingState(); - snprintf(buffer, SIZE, - "+ %s %p\n" - " " - "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " - "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", - layer->getTypeID(), layer.get(), - s.z, layer->tx(), layer->ty(), s.w, s.h, - layer->needsBlending(), layer->needsDithering(), - layer->contentDirty, - s.alpha, s.flags, - s.transform[0][0], s.transform[0][1], - s.transform[1][0], s.transform[1][1]); - result.append(buffer); - buffer[0] = 0; - /*** LayerBaseClient ***/ - sp<LayerBaseClient> lbc = - LayerBase::dynamicCast< LayerBaseClient* >(layer.get()); - if (lbc != 0) { - sp<Client> client(lbc->client.promote()); - snprintf(buffer, SIZE, - " name=%s\n", lbc->getName().string()); - result.append(buffer); - snprintf(buffer, SIZE, - " id=0x%08x, client=0x%08x, identity=%u\n", - lbc->clientIndex(), client.get() ? client->cid : 0, - lbc->getIdentity()); - - result.append(buffer); - buffer[0] = 0; - } - /*** Layer ***/ - sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get()); - if (l != 0) { - SharedBufferStack::Statistics stats = l->lcblk->getStats(); - result.append( l->lcblk->dump(" ") ); - sp<const GraphicBuffer> buf0(l->getBuffer(0)); - sp<const GraphicBuffer> buf1(l->getBuffer(1)); - uint32_t w0=0, h0=0, s0=0; - uint32_t w1=0, h1=0, s1=0; - if (buf0 != 0) { - w0 = buf0->getWidth(); - h0 = buf0->getHeight(); - s0 = buf0->getStride(); - } - if (buf1 != 0) { - w1 = buf1->getWidth(); - h1 = buf1->getHeight(); - s1 = buf1->getStride(); - } - snprintf(buffer, SIZE, - " " - "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," - " freezeLock=%p, dq-q-time=%u us\n", - l->pixelFormat(), - w0, h0, s0, w1, h1, s1, - l->getFreezeLock().get(), stats.totalTime); - result.append(buffer); - buffer[0] = 0; - } + const sp<LayerBase>& layer(currentLayers[i]); + layer->dump(result, buffer, SIZE); + const Layer::State& s(layer->drawingState()); s.transparentRegion.dump(result, "transparentRegion"); layer->transparentRegionScreen.dump(result, "transparentRegionScreen"); layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); } + mWormholeRegion.dump(result, "WormholeRegion"); const DisplayHardware& hw(graphicPlane(0).displayHardware()); snprintf(buffer, SIZE, @@ -1601,16 +1544,19 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) " last transaction time : %f us\n", mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0); result.append(buffer); + if (inSwapBuffersDuration || !locked) { snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", inSwapBuffersDuration/1000.0); result.append(buffer); } + if (inTransactionDuration || !locked) { snprintf(buffer, SIZE, " transaction time: %f us\n", inTransactionDuration/1000.0); result.append(buffer); } + snprintf(buffer, SIZE, " client count: %d\n", mClientsMap.size()); result.append(buffer); const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); @@ -1733,7 +1679,7 @@ Client::~Client() { int32_t Client::generateId(int pid) { const uint32_t i = clz( ~mBitmap ); - if (i >= NUM_LAYERS_MAX) { + if (i >= SharedBufferStack::NUM_LAYERS_MAX) { return NO_MEMORY; } mPid = pid; @@ -1760,7 +1706,8 @@ void Client::free(int32_t id) } bool Client::isValid(int32_t i) const { - return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i))); + return (uint32_t(i)<SharedBufferStack::NUM_LAYERS_MAX) && + (mBitmap & (1<<(31-i))); } sp<LayerBaseClient> Client::getLayerUser(int32_t i) const { @@ -1773,10 +1720,6 @@ sp<LayerBaseClient> Client::getLayerUser(int32_t i) const { return lbc; } -void Client::dump(const char* what) -{ -} - // --------------------------------------------------------------------------- #if 0 #pragma mark - @@ -1797,7 +1740,7 @@ sp<IMemoryHeap> BClient::getControlBlock() const { } sp<ISurface> BClient::createSurface( - ISurfaceFlingerClient::surface_data_t* params, int pid, + ISurfaceComposerClient::surface_data_t* params, int pid, const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index d75dc15..d8fe98c 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -32,7 +32,7 @@ #include <ui/PixelFormat.h> #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include "Barrier.h" #include "Layer.h" @@ -73,7 +73,6 @@ public: inline bool isValid(int32_t i) const; sp<LayerBaseClient> getLayerUser(int32_t i) const; - void dump(const char* what); const Vector< wp<LayerBaseClient> >& getLayers() const { return mLayers; @@ -159,7 +158,7 @@ public: virtual status_t dump(int fd, const Vector<String16>& args); // ISurfaceComposer interface - virtual sp<ISurfaceFlingerClient> createConnection(); + virtual sp<ISurfaceComposerClient> createConnection(); virtual sp<IMemoryHeap> getCblk() const; virtual void bootFinished(); virtual void openGlobalTransaction(); @@ -190,7 +189,7 @@ private: friend class LayerDim; sp<ISurface> createSurface(ClientID client, int pid, const String8& name, - ISurfaceFlingerClient::surface_data_t* params, + ISurfaceComposerClient::surface_data_t* params, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); @@ -256,8 +255,6 @@ private: public: // hack to work around gcc 4.0.3 bug void signalEvent(); private: - void signalDelayedEvent(nsecs_t delay); - void handleConsoleEvents(); void handleTransaction(uint32_t transactionFlags); void handleTransactionLocked( @@ -281,12 +278,13 @@ private: void destroyConnection(ClientID cid); sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const; status_t addLayer_l(const sp<LayerBase>& layer); + status_t addClientLayer_l(const sp<LayerBaseClient>& lbc); status_t removeLayer_l(const sp<LayerBase>& layer); status_t purgatorizeLayer_l(const sp<LayerBase>& layer); void free_resources_l(); uint32_t getTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags, nsecs_t delay = 0); + uint32_t setTransactionFlags(uint32_t flags); void commitTransaction(); @@ -310,7 +308,12 @@ private: mutable MessageQueue mEventQueue; - + + status_t postMessageAsync(const sp<MessageBase>& msg, + nsecs_t reltime=0, uint32_t flags = 0); + + status_t postMessageSync(const sp<MessageBase>& msg, + nsecs_t reltime=0, uint32_t flags = 0); // access must be protected by mStateLock @@ -390,14 +393,14 @@ public: // --------------------------------------------------------------------------- -class BClient : public BnSurfaceFlingerClient +class BClient : public BnSurfaceComposerClient { public: BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk); ~BClient(); - // ISurfaceFlingerClient interface + // ISurfaceComposerClient interface virtual sp<IMemoryHeap> getControlBlock() const; virtual sp<ISurface> createSurface( diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp new file mode 100644 index 0000000..ee2159b --- /dev/null +++ b/libs/surfaceflinger/TextureManager.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <ui/GraphicBuffer.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <hardware/hardware.h> + +#include "clz.h" +#include "DisplayHardware/DisplayHardware.h" +#include "TextureManager.h" + +namespace android { + +// --------------------------------------------------------------------------- + +TextureManager::TextureManager(uint32_t flags) + : mFlags(flags) +{ +} + +GLuint TextureManager::createTexture() +{ + GLuint textureName = -1; + glGenTextures(1, &textureName); + glBindTexture(GL_TEXTURE_2D, textureName); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + return textureName; +} + +bool TextureManager::isSupportedYuvFormat(int format) +{ + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_P: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_I: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return true; + } + return false; +} + +status_t TextureManager::initEglImage(Image* texture, + EGLDisplay dpy, const sp<GraphicBuffer>& buffer) +{ + status_t err = NO_ERROR; + if (!texture->dirty) return err; + + // free the previous image + if (texture->image != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(dpy, texture->image); + texture->image = EGL_NO_IMAGE_KHR; + } + + // construct an EGL_NATIVE_BUFFER_ANDROID + android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); + + // create the new EGLImageKHR + const EGLint attrs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE, EGL_NONE + }; + texture->image = eglCreateImageKHR( + dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + (EGLClientBuffer)clientBuf, attrs); + + if (texture->image != EGL_NO_IMAGE_KHR) { + if (texture->name == -1UL) { + texture->name = createTexture(); + texture->width = 0; + texture->height = 0; + } + glBindTexture(GL_TEXTURE_2D, texture->name); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, + (GLeglImageOES)texture->image); + GLint error = glGetError(); + if (error != GL_NO_ERROR) { + LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x", + texture->image, error); + err = INVALID_OPERATION; + } else { + // Everything went okay! + texture->dirty = false; + texture->width = clientBuf->width; + texture->height = clientBuf->height; + } + } else { + LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError()); + err = INVALID_OPERATION; + } + return err; +} + +status_t TextureManager::loadTexture(Texture* texture, + const Region& dirty, const GGLSurface& t) +{ + if (texture->name == -1UL) { + texture->name = createTexture(); + texture->width = 0; + texture->height = 0; + } + + glBindTexture(GL_TEXTURE_2D, texture->name); + + /* + * In OpenGL ES we can't specify a stride with glTexImage2D (however, + * GL_UNPACK_ALIGNMENT is a limited form of stride). + * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we + * need to do something reasonable (here creating a bigger texture). + * + * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); + * + * This situation doesn't happen often, but some h/w have a limitation + * for their framebuffer (eg: must be multiple of 8 pixels), and + * we need to take that into account when using these buffers as + * textures. + * + * This should never be a problem with POT textures + */ + + int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); + unpack = 1 << ((unpack > 3) ? 3 : unpack); + glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); + + /* + * round to POT if needed + */ + if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) { + texture->NPOTAdjust = true; + } + + if (texture->NPOTAdjust) { + // find the smallest power-of-two that will accommodate our surface + texture->potWidth = 1 << (31 - clz(t.width)); + texture->potHeight = 1 << (31 - clz(t.height)); + if (texture->potWidth < t.width) texture->potWidth <<= 1; + if (texture->potHeight < t.height) texture->potHeight <<= 1; + texture->wScale = float(t.width) / texture->potWidth; + texture->hScale = float(t.height) / texture->potHeight; + } else { + texture->potWidth = t.width; + texture->potHeight = t.height; + } + + Rect bounds(dirty.bounds()); + GLvoid* data = 0; + if (texture->width != t.width || texture->height != t.height) { + texture->width = t.width; + texture->height = t.height; + + // texture size changed, we need to create a new one + bounds.set(Rect(t.width, t.height)); + if (t.width == texture->potWidth && + t.height == texture->potHeight) { + // we can do it one pass + data = t.data; + } + + if (t.format == HAL_PIXEL_FORMAT_RGB_565) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGB, texture->potWidth, texture->potHeight, 0, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, texture->potWidth, texture->potHeight, 0, + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || + t.format == HAL_PIXEL_FORMAT_RGBX_8888) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, texture->potWidth, texture->potHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + } else if (isSupportedYuvFormat(t.format)) { + // just show the Y plane of YUV buffers + glTexImage2D(GL_TEXTURE_2D, 0, + GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, data); + } else { + // oops, we don't handle this format! + LOGE("texture=%d, using format %d, which is not " + "supported by the GL", texture->name, t.format); + } + } + if (!data) { + if (t.format == HAL_PIXEL_FORMAT_RGB_565) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + t.data + bounds.top*t.stride*2); + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, + t.data + bounds.top*t.stride*2); + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || + t.format == HAL_PIXEL_FORMAT_RGBX_8888) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGBA, GL_UNSIGNED_BYTE, + t.data + bounds.top*t.stride*4); + } else if (isSupportedYuvFormat(t.format)) { + // just show the Y plane of YUV buffers + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_LUMINANCE, GL_UNSIGNED_BYTE, + t.data + bounds.top*t.stride); + } + } + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h new file mode 100644 index 0000000..d0acfe9 --- /dev/null +++ b/libs/surfaceflinger/TextureManager.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_TEXTURE_MANAGER_H +#define ANDROID_TEXTURE_MANAGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES/gl.h> + +#include <ui/Region.h> + +#include <pixelflinger/pixelflinger.h> + +namespace android { + +// --------------------------------------------------------------------------- + +class GraphicBuffer; + +// --------------------------------------------------------------------------- + +struct Image { + Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0), + transform(0), dirty(true) { } + GLuint name; + EGLImageKHR image; + GLuint width; + GLuint height; + uint32_t transform; + bool dirty; +}; + +struct Texture : public Image { + Texture() : Image(), NPOTAdjust(false) { } + GLuint potWidth; + GLuint potHeight; + GLfloat wScale; + GLfloat hScale; + bool NPOTAdjust; +}; + +// --------------------------------------------------------------------------- + +class TextureManager { + uint32_t mFlags; + GLuint createTexture(); + static bool isSupportedYuvFormat(int format); +public: + + TextureManager(uint32_t flags); + + // load bitmap data into the active buffer + status_t loadTexture(Texture* texture, + const Region& dirty, const GGLSurface& t); + + // make active buffer an EGLImage if needed + status_t initEglImage(Image* texture, + EGLDisplay dpy, const sp<GraphicBuffer>& buffer); +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_TEXTURE_MANAGER_H diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp index 175f989..5e27cc9 100644 --- a/libs/surfaceflinger/Transform.cpp +++ b/libs/surfaceflinger/Transform.cpp @@ -229,14 +229,13 @@ Transform::vec3 Transform::transform(const vec3& v) const { return r; } -void Transform::transform(fixed1616* point, int x, int y) const +void Transform::transform(float* point, int x, int y) const { - const float toFixed = 65536.0f; const mat33& M(mMatrix); vec2 v(x, y); v = transform(v); - point[0] = v[0] * toFixed; - point[1] = v[1] * toFixed; + point[0] = v[0]; + point[1] = v[1]; } Rect Transform::makeBounds(int w, int h) const diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h index 2e5b893..20fa11a 100644 --- a/libs/surfaceflinger/Transform.h +++ b/libs/surfaceflinger/Transform.h @@ -37,8 +37,6 @@ public: explicit Transform(uint32_t orientation); ~Transform(); - typedef int32_t fixed1616; - // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h enum orientation_flags { ROT_0 = 0x00000000, @@ -76,7 +74,7 @@ public: // transform data Rect makeBounds(int w, int h) const; - void transform(fixed1616* point, int x, int y) const; + void transform(float* point, int x, int y) const; Region transform(const Region& reg) const; Transform operator * (const Transform& rhs) const; diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index fe85b34..ce3c71a 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ISurfaceComposer.cpp \ ISurface.cpp \ - ISurfaceFlingerClient.cpp \ + ISurfaceComposerClient.cpp \ LayerState.cpp \ SharedBufferStack.cpp \ Surface.cpp \ diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index bb86199..7049d9e 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -71,11 +71,15 @@ public: { } - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); data.writeInt32(bufferIdx); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -83,6 +87,16 @@ public: return buffer; } + virtual status_t setBufferCount(int bufferCount) + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + remote()->transact(SET_BUFFER_COUNT, data, &reply); + status_t err = reply.readInt32(); + return err; + } + virtual status_t registerBuffers(const BufferHeap& buffers) { Parcel data, reply; @@ -140,12 +154,22 @@ status_t BnSurface::onTransact( case REQUEST_BUFFER: { CHECK_INTERFACE(ISurface, data, reply); int bufferIdx = data.readInt32(); - int usage = data.readInt32(); - sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + uint32_t format = data.readInt32(); + uint32_t usage = data.readInt32(); + sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage)); if (buffer == NULL) return BAD_VALUE; return reply->write(*buffer); } + case SET_BUFFER_COUNT: { + CHECK_INTERFACE(ISurface, data, reply); + int bufferCount = data.readInt32(); + status_t err = setBufferCount(bufferCount); + reply->writeInt32(err); + return NO_ERROR; + } case REGISTER_BUFFERS: { CHECK_INTERFACE(ISurface, data, reply); BufferHeap buffer; diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index b6f4e24..50495c1 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -46,13 +46,13 @@ public: { } - virtual sp<ISurfaceFlingerClient> createConnection() + virtual sp<ISurfaceComposerClient> createConnection() { uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); - return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder()); + return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); } virtual sp<IMemoryHeap> getCblk() const diff --git a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp index def96d7..67c7df8 100644 --- a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp @@ -30,7 +30,7 @@ #include <ui/Rect.h> #include <surfaceflinger/ISurface.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <private/surfaceflinger/LayerState.h> // --------------------------------------------------------------------------- @@ -56,18 +56,18 @@ enum { SET_STATE }; -class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient> +class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> { public: - BpSurfaceFlingerClient(const sp<IBinder>& impl) - : BpInterface<ISurfaceFlingerClient>(impl) + BpSurfaceComposerClient(const sp<IBinder>& impl) + : BpInterface<ISurfaceComposerClient>(impl) { } virtual sp<IMemoryHeap> getControlBlock() const { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); remote()->transact(GET_CBLK, data, &reply); return interface_cast<IMemoryHeap>(reply.readStrongBinder()); } @@ -82,7 +82,7 @@ public: uint32_t flags) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(pid); data.writeString8(name); data.writeInt32(display); @@ -94,11 +94,11 @@ public: params->readFromParcel(reply); return interface_cast<ISurface>(reply.readStrongBinder()); } - + virtual status_t destroySurface(SurfaceID sid) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(sid); remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); @@ -107,7 +107,7 @@ public: virtual status_t setState(int32_t count, const layer_state_t* states) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(count); for (int i=0 ; i<count ; i++) states[i].write(data); @@ -116,18 +116,18 @@ public: } }; -IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient"); +IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); // ---------------------------------------------------------------------- -status_t BnSurfaceFlingerClient::onTransact( +status_t BnSurfaceComposerClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // codes that don't require permission check switch(code) { case GET_CBLK: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IMemoryHeap> ctl(getControlBlock()); reply->writeStrongBinder(ctl->asBinder()); return NO_ERROR; @@ -135,7 +135,7 @@ status_t BnSurfaceFlingerClient::onTransact( } // these must be checked - + IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -150,10 +150,10 @@ status_t BnSurfaceFlingerClient::onTransact( return PERMISSION_DENIED; } } - + switch(code) { case CREATE_SURFACE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); surface_data_t params; int32_t pid = data.readInt32(); String8 name = data.readString8(); @@ -169,12 +169,12 @@ status_t BnSurfaceFlingerClient::onTransact( return NO_ERROR; } break; case DESTROY_SURFACE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); reply->writeInt32( destroySurface( data.readInt32() ) ); return NO_ERROR; } break; case SET_STATE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); int32_t count = data.readInt32(); layer_state_t* states = new layer_state_t[count]; for (int i=0 ; i<count ; i++) @@ -191,7 +191,7 @@ status_t BnSurfaceFlingerClient::onTransact( // ---------------------------------------------------------------------- -status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel) +status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel) { token = parcel.readInt32(); identity = parcel.readInt32(); @@ -201,7 +201,7 @@ status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& par return NO_ERROR; } -status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const +status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const { parcel->writeInt32(token); parcel->writeInt32(identity); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index a17e8ac..8d03145 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -44,15 +44,11 @@ SharedClient::~SharedClient() { // these functions are used by the clients status_t SharedClient::validate(size_t i) const { - if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX)) + if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX)) return BAD_INDEX; return surfaces[i].status; } -uint32_t SharedClient::getIdentity(size_t token) const { - return uint32_t(surfaces[token].identity); -} - // ---------------------------------------------------------------------------- @@ -67,19 +63,47 @@ void SharedBufferStack::init(int32_t i) identity = i; } +status_t SharedBufferStack::setCrop(int buffer, const Rect& crop) +{ + if (uint32_t(buffer) >= NUM_BUFFER_MAX) + return BAD_INDEX; + + buffers[buffer].crop.l = uint16_t(crop.left); + buffers[buffer].crop.t = uint16_t(crop.top); + buffers[buffer].crop.r = uint16_t(crop.right); + buffers[buffer].crop.b = uint16_t(crop.bottom); + return NO_ERROR; +} + status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty) { if (uint32_t(buffer) >= NUM_BUFFER_MAX) return BAD_INDEX; - // in the current implementation we only send a single rectangle - const Rect bounds(dirty.getBounds()); - FlatRegion& reg(dirtyRegion[buffer]); - reg.count = 1; - reg.rects[0] = uint16_t(bounds.left); - reg.rects[1] = uint16_t(bounds.top); - reg.rects[2] = uint16_t(bounds.right); - reg.rects[3] = uint16_t(bounds.bottom); + FlatRegion& reg(buffers[buffer].dirtyRegion); + if (dirty.isEmpty()) { + reg.count = 0; + return NO_ERROR; + } + + size_t count; + Rect const* r = dirty.getArray(&count); + if (count > FlatRegion::NUM_RECT_MAX) { + const Rect bounds(dirty.getBounds()); + reg.count = 1; + reg.rects[0].l = uint16_t(bounds.left); + reg.rects[0].t = uint16_t(bounds.top); + reg.rects[0].r = uint16_t(bounds.right); + reg.rects[0].b = uint16_t(bounds.bottom); + } else { + reg.count = count; + for (size_t i=0 ; i<count ; i++) { + reg.rects[i].l = uint16_t(r[i].left); + reg.rects[i].t = uint16_t(r[i].top); + reg.rects[i].r = uint16_t(r[i].right); + reg.rects[i].b = uint16_t(r[i].bottom); + } + } return NO_ERROR; } @@ -89,18 +113,37 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const if (uint32_t(buffer) >= NUM_BUFFER_MAX) return res; - const FlatRegion& reg(dirtyRegion[buffer]); - res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3])); + const FlatRegion& reg(buffers[buffer].dirtyRegion); + if (reg.count > FlatRegion::NUM_RECT_MAX) + return res; + + if (reg.count == 1) { + const Rect r( + reg.rects[0].l, + reg.rects[0].t, + reg.rects[0].r, + reg.rects[0].b); + res.set(r); + } else { + for (size_t i=0 ; i<reg.count ; i++) { + const Rect r( + reg.rects[i].l, + reg.rects[i].t, + reg.rects[i].r, + reg.rects[i].b); + res.orSelf(r); + } + } return res; } // ---------------------------------------------------------------------------- SharedBufferBase::SharedBufferBase(SharedClient* sharedClient, - int surface, int num, int32_t identity) + int surface, int32_t identity) : mSharedClient(sharedClient), mSharedStack(sharedClient->surfaces + surface), - mNumBuffers(num), mIdentity(identity) + mIdentity(identity) { } @@ -108,16 +151,16 @@ SharedBufferBase::~SharedBufferBase() { } -uint32_t SharedBufferBase::getIdentity() +status_t SharedBufferBase::getStatus() const { SharedBufferStack& stack( *mSharedStack ); - return stack.identity; + return stack.status; } -status_t SharedBufferBase::getStatus() const +int32_t SharedBufferBase::getIdentity() const { SharedBufferStack& stack( *mSharedStack ); - return stack.status; + return stack.identity; } size_t SharedBufferBase::getFrontBuffer() const @@ -132,16 +175,52 @@ String8 SharedBufferBase::dump(char const* prefix) const char buffer[SIZE]; String8 result; SharedBufferStack& stack( *mSharedStack ); - int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; snprintf(buffer, SIZE, - "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] " - "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n", - prefix, stack.head, stack.available, stack.queued, tail, + "%s[ head=%2d, available=%2d, queued=%2d ] " + "reallocMask=%08x, inUse=%2d, identity=%d, status=%d", + prefix, stack.head, stack.available, stack.queued, stack.reallocMask, stack.inUse, stack.identity, stack.status); result.append(buffer); + result.append("\n"); return result; } +status_t SharedBufferBase::waitForCondition(const ConditionBase& condition) +{ + const SharedBufferStack& stack( *mSharedStack ); + SharedClient& client( *mSharedClient ); + const nsecs_t TIMEOUT = s2ns(1); + const int identity = mIdentity; + + Mutex::Autolock _l(client.lock); + while ((condition()==false) && + (stack.identity == identity) && + (stack.status == NO_ERROR)) + { + status_t err = client.cv.waitRelative(client.lock, TIMEOUT); + // handle errors and timeouts + if (CC_UNLIKELY(err != NO_ERROR)) { + if (err == TIMED_OUT) { + if (condition()) { + LOGE("waitForCondition(%s) timed out (identity=%d), " + "but condition is true! We recovered but it " + "shouldn't happen." , condition.name(), stack.identity); + break; + } else { + LOGW("waitForCondition(%s) timed out " + "(identity=%d, status=%d). " + "CPU may be pegged. trying again.", condition.name(), + stack.identity, stack.status); + } + } else { + LOGE("waitForCondition(%s) error (%s) ", + condition.name(), strerror(-err)); + return err; + } + } + } + return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; +} // ============================================================================ // conditions and updates // ============================================================================ @@ -149,24 +228,34 @@ String8 SharedBufferBase::dump(char const* prefix) const SharedBufferClient::DequeueCondition::DequeueCondition( SharedBufferClient* sbc) : ConditionBase(sbc) { } -bool SharedBufferClient::DequeueCondition::operator()() { +bool SharedBufferClient::DequeueCondition::operator()() const { return stack.available > 0; } SharedBufferClient::LockCondition::LockCondition( SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { } -bool SharedBufferClient::LockCondition::operator()() { - return (buf != stack.head || +bool SharedBufferClient::LockCondition::operator()() const { + // NOTE: if stack.head is messed up, we could crash the client + // or cause some drawing artifacts. This is okay, as long as it is + // limited to the client. + return (buf != stack.index[stack.head] || (stack.queued > 0 && stack.inUse != buf)); } SharedBufferServer::ReallocateCondition::ReallocateCondition( SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) { } -bool SharedBufferServer::ReallocateCondition::operator()() { +bool SharedBufferServer::ReallocateCondition::operator()() const { + int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) { + // if stack.head is messed up, we cannot allow the server to + // crash (since stack.head is mapped on the client side) + stack.status = BAD_VALUE; + return false; + } // TODO: we should also check that buf has been dequeued - return (buf != stack.head); + return (buf != stack.index[head]); } // ---------------------------------------------------------------------------- @@ -206,11 +295,12 @@ SharedBufferServer::RetireUpdate::RetireUpdate( : UpdateBase(sbb), numBuffers(numBuffers) { } ssize_t SharedBufferServer::RetireUpdate::operator()() { - // head is only written in this function, which is single-thread. int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; // Preventively lock the current buffer before updating queued. - android_atomic_write(head, &stack.inUse); + android_atomic_write(stack.index[head], &stack.inUse); // Decrement the number of queued buffers int32_t queued; @@ -221,16 +311,15 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { } } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); - // update the head pointer - head = ((head+1 >= numBuffers) ? 0 : head+1); - // lock the buffer before advancing head, which automatically unlocks // the buffer we preventively locked upon entering this function - android_atomic_write(head, &stack.inUse); - // advance head + head = (head + 1) % numBuffers; + android_atomic_write(stack.index[head], &stack.inUse); + + // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); - + // now that head has moved, we can increment the number of available buffers android_atomic_inc(&stack.available); return head; @@ -250,41 +339,31 @@ ssize_t SharedBufferServer::StatusUpdate::operator()() { SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, num, identity), tail(0) + : SharedBufferBase(sharedClient, surface, identity), + mNumBuffers(num), tail(0), undoDequeueTail(0) { + SharedBufferStack& stack( *mSharedStack ); tail = computeTail(); + queued_head = stack.head; } int32_t SharedBufferClient::computeTail() const { SharedBufferStack& stack( *mSharedStack ); - // we need to make sure we read available and head coherently, - // w.r.t RetireUpdate. - int32_t newTail; - int32_t avail; - int32_t head; - do { - avail = stack.available; - head = stack.head; - } while (stack.available != avail); - newTail = head - avail + 1; - if (newTail < 0) { - newTail += mNumBuffers; - } else if (newTail >= mNumBuffers) { - newTail -= mNumBuffers; - } - return newTail; + return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; } ssize_t SharedBufferClient::dequeue() { SharedBufferStack& stack( *mSharedStack ); - if (stack.head == tail && stack.available == 2) { + if (stack.head == tail && stack.available == mNumBuffers) { LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d", tail, stack.head, stack.available, stack.queued); } - + + RWLock::AutoRLock _rd(mLock); + const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD); //LOGD("[%d] about to dequeue a buffer", @@ -301,9 +380,10 @@ ssize_t SharedBufferClient::dequeue() LOGW("dequeue probably called from multiple threads!"); } - int dequeued = tail; + undoDequeueTail = tail; + int dequeued = stack.index[tail]; tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); - LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s", + LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s", dequeued, tail, dump("").string()); mDequeueTime[dequeued] = dequeueTime; @@ -313,16 +393,23 @@ ssize_t SharedBufferClient::dequeue() status_t SharedBufferClient::undoDequeue(int buf) { + RWLock::AutoRLock _rd(mLock); + + // TODO: we can only undo the previous dequeue, we should + // enforce that in the api UndoDequeueUpdate update(this); status_t err = updateCondition( update ); if (err == NO_ERROR) { - tail = computeTail(); + tail = undoDequeueTail; } return err; } status_t SharedBufferClient::lock(int buf) { + RWLock::AutoRLock _rd(mLock); + + SharedBufferStack& stack( *mSharedStack ); LockCondition condition(this, buf); status_t err = waitForCondition(condition); return err; @@ -330,53 +417,100 @@ status_t SharedBufferClient::lock(int buf) status_t SharedBufferClient::queue(int buf) { + RWLock::AutoRLock _rd(mLock); + + SharedBufferStack& stack( *mSharedStack ); + + queued_head = (queued_head + 1) % mNumBuffers; + stack.index[queued_head] = buf; + QueueUpdate update(this); status_t err = updateCondition( update ); LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string()); - SharedBufferStack& stack( *mSharedStack ); + const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); return err; } -bool SharedBufferClient::needNewBuffer(int buffer) const +bool SharedBufferClient::needNewBuffer(int buf) const { SharedBufferStack& stack( *mSharedStack ); - const uint32_t mask = 1<<buffer; + const uint32_t mask = 1<<(31-buf); return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0; } -status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg) +status_t SharedBufferClient::setCrop(int buf, const Rect& crop) +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.setCrop(buf, crop); +} + +status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg) { SharedBufferStack& stack( *mSharedStack ); - return stack.setDirtyRegion(buffer, reg); + return stack.setDirtyRegion(buf, reg); +} + +status_t SharedBufferClient::setBufferCount( + int bufferCount, const SetBufferCountCallback& ipc) +{ + SharedBufferStack& stack( *mSharedStack ); + if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN) + return BAD_VALUE; + + RWLock::AutoWLock _wr(mLock); + + status_t err = ipc(bufferCount); + if (err == NO_ERROR) { + mNumBuffers = bufferCount; + queued_head = (stack.head + stack.queued) % mNumBuffers; + } + return err; } // ---------------------------------------------------------------------------- SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, num, identity) + : SharedBufferBase(sharedClient, surface, identity), + mNumBuffers(num) { mSharedStack->init(identity); mSharedStack->head = num-1; mSharedStack->available = num; mSharedStack->queued = 0; mSharedStack->reallocMask = 0; - memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion)); + memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers)); + for (int i=0 ; i<num ; i++) { + mBufferList.add(i); + mSharedStack->index[i] = i; + } } ssize_t SharedBufferServer::retireAndLock() { + RWLock::AutoRLock _l(mLock); + RetireUpdate update(this, mNumBuffers); ssize_t buf = updateCondition( update ); - LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string()); + if (buf >= 0) { + if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + SharedBufferStack& stack( *mSharedStack ); + buf = stack.index[buf]; + LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", + int(buf), dump("").string()); + } return buf; } -status_t SharedBufferServer::unlock(int buffer) +status_t SharedBufferServer::unlock(int buf) { - UnlockUpdate update(this, buffer); + UnlockUpdate update(this, buf); status_t err = updateCondition( update ); return err; } @@ -389,11 +523,25 @@ void SharedBufferServer::setStatus(status_t status) } } -status_t SharedBufferServer::reallocate() +status_t SharedBufferServer::reallocateAll() { + RWLock::AutoRLock _l(mLock); + SharedBufferStack& stack( *mSharedStack ); - uint32_t mask = (1<<mNumBuffers)-1; - android_atomic_or(mask, &stack.reallocMask); + uint32_t mask = mBufferList.getMask(); + android_atomic_or(mask, &stack.reallocMask); + return NO_ERROR; +} + +status_t SharedBufferServer::reallocateAllExcept(int buffer) +{ + RWLock::AutoRLock _l(mLock); + + SharedBufferStack& stack( *mSharedStack ); + BufferList temp(mBufferList); + temp.remove(buffer); + uint32_t mask = temp.getMask(); + android_atomic_or(mask, &stack.reallocMask); return NO_ERROR; } @@ -403,17 +551,77 @@ int32_t SharedBufferServer::getQueuedCount() const return stack.queued; } -status_t SharedBufferServer::assertReallocate(int buffer) +status_t SharedBufferServer::assertReallocate(int buf) { - ReallocateCondition condition(this, buffer); + /* + * NOTE: it's safe to hold mLock for read while waiting for + * the ReallocateCondition because that condition is not updated + * by the thread that holds mLock for write. + */ + RWLock::AutoRLock _l(mLock); + + // TODO: need to validate "buf" + ReallocateCondition condition(this, buf); status_t err = waitForCondition(condition); return err; } -Region SharedBufferServer::getDirtyRegion(int buffer) const +Region SharedBufferServer::getDirtyRegion(int buf) const { SharedBufferStack& stack( *mSharedStack ); - return stack.getDirtyRegion(buffer); + return stack.getDirtyRegion(buf); +} + +/* + * NOTE: this is not thread-safe on the server-side, meaning + * 'head' cannot move during this operation. The client-side + * can safely operate an usual. + * + */ +status_t SharedBufferServer::resize(int newNumBuffers) +{ + if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + RWLock::AutoWLock _l(mLock); + + // for now we're not supporting shrinking + const int numBuffers = mNumBuffers; + if (newNumBuffers < numBuffers) + return BAD_VALUE; + + SharedBufferStack& stack( *mSharedStack ); + const int extra = newNumBuffers - numBuffers; + + // read the head, make sure it's valid + int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + int base = numBuffers; + int32_t avail = stack.available; + int tail = head - avail + 1; + + if (tail >= 0) { + int8_t* const index = const_cast<int8_t*>(stack.index); + const int nb = numBuffers - head; + memmove(&index[head + extra], &index[head], nb); + base = head; + // move head 'extra' ahead, this doesn't impact stack.index[head]; + stack.head = head + extra; + } + stack.available += extra; + + // fill the new free space with unused buffers + BufferList::const_iterator curr(mBufferList.free_begin()); + for (int i=0 ; i<extra ; i++) { + stack.index[base+i] = *curr; + mBufferList.add(*curr); + ++curr; + } + + mNumBuffers = newNumBuffers; + return NO_ERROR; } SharedBufferStack::Statistics SharedBufferServer::getStats() const @@ -422,6 +630,29 @@ SharedBufferStack::Statistics SharedBufferServer::getStats() const return stack.stats; } +// --------------------------------------------------------------------------- +status_t SharedBufferServer::BufferList::add(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (mList & mask) + return ALREADY_EXISTS; + mList |= mask; + return NO_ERROR; +} + +status_t SharedBufferServer::BufferList::remove(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (!(mList & mask)) + return NAME_NOT_FOUND; + mList &= ~mask; + return NO_ERROR; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 5dd75c3..ac4b198 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -17,8 +17,6 @@ #define LOG_TAG "Surface" #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> @@ -28,8 +26,6 @@ #include <utils/CallStack.h> #include <utils/Log.h> -#include <pixelflinger/pixelflinger.h> - #include <binder/IPCThreadState.h> #include <binder/IMemory.h> @@ -55,6 +51,8 @@ static status_t copyBlt( const sp<GraphicBuffer>& src, const Region& reg) { + // src and dst with, height and format must be identical. no verification + // is done here. status_t err; uint8_t const * src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); @@ -67,7 +65,6 @@ static status_t copyBlt( Region::const_iterator head(reg.begin()); Region::const_iterator tail(reg.end()); if (head != tail && src_bits && dst_bits) { - // NOTE: dst and src must be the same format const size_t bpp = bytesPerPixel(src->format); const size_t dbpr = dst->stride * bpp; const size_t sbpr = src->stride * bpp; @@ -107,7 +104,7 @@ static status_t copyBlt( SurfaceControl::SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<ISurface>& surface, - const ISurfaceFlingerClient::surface_data_t& data, + const ISurfaceComposerClient::surface_data_t& data, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) : mClient(client), mSurface(surface), mToken(data.token), mIdentity(data.identity), @@ -154,75 +151,75 @@ bool SurfaceControl::isSameSurface( } status_t SurfaceControl::setLayer(int32_t layer) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setLayer(mToken, layer); } status_t SurfaceControl::setPosition(int32_t x, int32_t y) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setPosition(mToken, x, y); } status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setSize(mToken, w, h); } status_t SurfaceControl::hide() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->hide(mToken); } status_t SurfaceControl::show(int32_t layer) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->show(mToken, layer); } status_t SurfaceControl::freeze() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->freeze(mToken); } status_t SurfaceControl::unfreeze() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->unfreeze(mToken); } status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setFlags(mToken, flags, mask); } status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setTransparentRegionHint(mToken, transparent); } status_t SurfaceControl::setAlpha(float alpha) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setAlpha(mToken, alpha); } status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy); } status_t SurfaceControl::setFreezeTint(uint32_t tint) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setFreezeTint(mToken, tint); } @@ -233,23 +230,6 @@ status_t SurfaceControl::validate() const mToken, mIdentity, mClient.get()); return NO_INIT; } - SharedClient const* cblk = mClient->mControl; - if (cblk == 0) { - LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); - return NO_INIT; - } - status_t err = cblk->validate(mToken); - if (err != NO_ERROR) { - LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", - mToken, mIdentity, err, strerror(-err)); - return err; - } - uint32_t identity = cblk->getIdentity(mToken); - if (mIdentity != identity) { - LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, identity); - return NO_INIT; - } return NO_ERROR; } @@ -299,22 +279,22 @@ sp<Surface> SurfaceControl::getSurface() const // ============================================================================ Surface::Surface(const sp<SurfaceControl>& surface) - : mClient(surface->mClient), mSurface(surface->mSurface), + : mSurface(surface->mSurface), mToken(surface->mToken), mIdentity(surface->mIdentity), mFormat(surface->mFormat), mFlags(surface->mFlags), mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL), + mInitCheck(NO_INIT), mWidth(surface->mWidth), mHeight(surface->mHeight) { - mSharedBufferClient = new SharedBufferClient( - mClient->mControl, mToken, 2, mIdentity); - + mClient = new SurfaceClient(surface->mClient); init(); } Surface::Surface(const Parcel& parcel) - : mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL) + : mBufferMapper(GraphicBufferMapper::get()), + mSharedBufferClient(NULL), mInitCheck(NO_INIT) { - sp<IBinder> clientBinder = parcel.readStrongBinder(); + sp<IBinder> conn = parcel.readStrongBinder(); mSurface = interface_cast<ISurface>(parcel.readStrongBinder()); mToken = parcel.readInt32(); mIdentity = parcel.readInt32(); @@ -322,15 +302,7 @@ Surface::Surface(const Parcel& parcel) mHeight = parcel.readInt32(); mFormat = parcel.readInt32(); mFlags = parcel.readInt32(); - - // FIXME: what does that mean if clientBinder is NULL here? - if (clientBinder != NULL) { - mClient = SurfaceComposerClient::clientForConnection(clientBinder); - - mSharedBufferClient = new SharedBufferClient( - mClient->mControl, mToken, 2, mIdentity); - } - + mClient = new SurfaceClient(conn); init(); } @@ -342,7 +314,7 @@ void Surface::init() android_native_window_t::queueBuffer = queueBuffer; android_native_window_t::query = query; android_native_window_t::perform = perform; - mSwapRectangle.makeInvalid(); + DisplayInfo dinfo; SurfaceComposerClient::getDisplayInfo(0, &dinfo); const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi; @@ -351,17 +323,27 @@ void Surface::init() const_cast<int&>(android_native_window_t::minSwapInterval) = 1; const_cast<int&>(android_native_window_t::maxSwapInterval) = 1; const_cast<uint32_t&>(android_native_window_t::flags) = 0; - // be default we request a hardware surface - mUsage = GRALLOC_USAGE_HW_RENDER; + mConnected = 0; - mNeedFullUpdate = false; + mSwapRectangle.makeInvalid(); + // two buffers by default + mBuffers.setCapacity(2); + mBuffers.insertAt(0, 2); + + if (mClient != 0 && mClient->initCheck() == NO_ERROR) { + mSharedBufferClient = new SharedBufferClient( + mClient->getSharedClient(), mToken, 2, mIdentity); + } + + mInitCheck = initCheck(); } Surface::~Surface() { // this is a client-side operation, the surface is destroyed, unmap // its buffers in this process. - for (int i=0 ; i<2 ; i++) { + size_t size = mBuffers.size(); + for (size_t i=0 ; i<size ; i++) { if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) { getBufferMapper().unregisterBuffer(mBuffers[i]->handle); } @@ -369,62 +351,78 @@ Surface::~Surface() // clear all references and trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. + mBuffers.clear(); mClient.clear(); mSurface.clear(); delete mSharedBufferClient; IPCThreadState::self()->flushCommands(); } -sp<SurfaceComposerClient> Surface::getClient() const { - return mClient; -} - -sp<ISurface> Surface::getISurface() const { - return mSurface; +status_t Surface::initCheck() const +{ + if (mToken<0 || mClient==0 || mClient->initCheck() != NO_ERROR) { + return NO_INIT; + } + SharedClient const* cblk = mClient->getSharedClient(); + if (cblk == 0) { + LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); + return NO_INIT; + } + return cblk->validate(mToken); } bool Surface::isValid() { - return mToken>=0 && mClient!=0; + return mInitCheck == NO_ERROR; } status_t Surface::validate() const { - sp<SurfaceComposerClient> client(getClient()); - if (mToken<0 || mClient==0) { - LOGE("invalid token (%d, identity=%u) or client (%p)", - mToken, mIdentity, client.get()); - return NO_INIT; + // check that we initialized ourself properly + if (mInitCheck != NO_ERROR) { + LOGE("invalid token (%d, identity=%u) or client (%p)", + mToken, mIdentity, mClient.get()); + return mInitCheck; } - SharedClient const* cblk = mClient->mControl; - if (cblk == 0) { - LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); + + // verify the identity of this surface + uint32_t identity = mSharedBufferClient->getIdentity(); + + // this is a bit of a (temporary) special case, identity==0 means that + // no operation are allowed from the client (eg: dequeue/queue), this + // is used with PUSH_BUFFER surfaces for instance + if (identity == 0) { + LOGE("[Surface] invalid operation (identity=%u)", mIdentity); + return INVALID_OPERATION; + } + + if (mIdentity != identity) { + LOGE("[Surface] using an invalid surface id=%d, " + "identity=%u should be %d", + mToken, mIdentity, identity); return NO_INIT; } - status_t err = cblk->validate(mToken); + + // check the surface didn't become invalid + status_t err = mSharedBufferClient->getStatus(); if (err != NO_ERROR) { LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", mToken, mIdentity, err, strerror(-err)); return err; } - uint32_t identity = cblk->getIdentity(mToken); - if (mIdentity != identity) { - LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, identity); - return NO_INIT; - } + return NO_ERROR; } - -bool Surface::isSameSurface( - const sp<Surface>& lhs, const sp<Surface>& rhs) -{ +bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) { if (lhs == 0 || rhs == 0) return false; - return lhs->mSurface->asBinder() == rhs->mSurface->asBinder(); } +sp<ISurface> Surface::getISurface() const { + return mSurface; +} + // ---------------------------------------------------------------------------- int Surface::setSwapInterval(android_native_window_t* window, int interval) { @@ -467,21 +465,24 @@ int Surface::perform(android_native_window_t* window, // ---------------------------------------------------------------------------- -status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer) { - android_native_buffer_t* out; - status_t err = dequeueBuffer(&out); - if (err == NO_ERROR) { - *buffer = GraphicBuffer::getSelf(out); +bool Surface::needNewBuffer(int bufIdx, + uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const +{ + Mutex::Autolock _l(mSurfaceLock); + + // Always call needNewBuffer(), since it clears the needed buffers flags + bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); + bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]); + bool newNeewBuffer = needNewBuffer || !validBuffer; + if (newNeewBuffer) { + mBufferInfo.get(pWidth, pHeight, pFormat, pUsage); } - return err; + return newNeewBuffer; } -// ---------------------------------------------------------------------------- - - int Surface::dequeueBuffer(android_native_buffer_t** buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; @@ -492,24 +493,28 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return bufIdx; } - // below we make sure we AT LEAST have the usage flags we want - const uint32_t usage(getUsage()); - const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); - if (backBuffer == 0 || - ((uint32_t(backBuffer->usage) & usage) != usage) || - mSharedBufferClient->needNewBuffer(bufIdx)) - { - err = getBufferLocked(bufIdx, usage); - LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)", - bufIdx, usage, strerror(-err)); + // grow the buffer array if needed + const size_t size = mBuffers.size(); + const size_t needed = bufIdx+1; + if (size < needed) { + mBuffers.insertAt(size, needed-size); + } + + uint32_t w, h, format, usage; + if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) { + err = getBufferLocked(bufIdx, w, h, format, usage); + LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)", + bufIdx, w, h, format, usage, strerror(-err)); if (err == NO_ERROR) { // reset the width/height with the what we get from the buffer + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); mWidth = uint32_t(backBuffer->width); mHeight = uint32_t(backBuffer->height); } } // if we still don't have a buffer here, we probably ran out of memory + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); if (!err && backBuffer==0) { err = NO_MEMORY; } @@ -526,12 +531,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) int Surface::lockBuffer(android_native_buffer_t* buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; - int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); err = mSharedBufferClient->lock(bufIdx); LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err)); return err; @@ -539,7 +543,6 @@ int Surface::lockBuffer(android_native_buffer_t* buffer) int Surface::queueBuffer(android_native_buffer_t* buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; @@ -548,14 +551,15 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) mDirtyRegion.set(mSwapRectangle); } - int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); + mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop); mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion); err = mSharedBufferClient->queue(bufIdx); LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err)); if (err == NO_ERROR) { // FIXME: can we avoid this IPC if we know there is one pending? - client->signalServer(); + mClient->signalServer(); } return err; } @@ -578,6 +582,10 @@ int Surface::query(int what, int* value) int Surface::perform(int operation, va_list args) { + status_t err = validate(); + if (err != NO_ERROR) + return err; + int res = NO_ERROR; switch (operation) { case NATIVE_WINDOW_SET_USAGE: @@ -589,6 +597,15 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_DISCONNECT: res = dispatch_disconnect( args ); break; + case NATIVE_WINDOW_SET_CROP: + res = dispatch_crop( args ); + break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + res = dispatch_set_buffer_count( args ); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + res = dispatch_set_buffers_geometry( args ); + break; default: res = NAME_NOT_FOUND; break; @@ -608,12 +625,25 @@ int Surface::dispatch_disconnect(va_list args) { int api = va_arg(args, int); return disconnect( api ); } - +int Surface::dispatch_crop(va_list args) { + android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); + return crop( reinterpret_cast<Rect const*>(rect) ); +} +int Surface::dispatch_set_buffer_count(va_list args) { + size_t bufferCount = va_arg(args, size_t); + return setBufferCount(bufferCount); +} +int Surface::dispatch_set_buffers_geometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + return setBuffersGeometry(w, h, f); +} void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); - mUsage = reqUsage; + mBufferInfo.set(reqUsage); } int Surface::connect(int api) @@ -654,19 +684,55 @@ int Surface::disconnect(int api) return err; } -uint32_t Surface::getUsage() const +int Surface::crop(Rect const* rect) { Mutex::Autolock _l(mSurfaceLock); - return mUsage; + // TODO: validate rect size + mNextBufferCrop = *rect; + return NO_ERROR; } +int Surface::setBufferCount(int bufferCount) +{ + sp<ISurface> s(mSurface); + if (s == 0) return NO_INIT; + + class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { + sp<ISurface> surface; + virtual status_t operator()(int bufferCount) const { + return surface->setBufferCount(bufferCount); + } + public: + SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { } + } ipc(s); + + status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc); + LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); + return err; +} + +int Surface::setBuffersGeometry(int w, int h, int format) +{ + if (w<0 || h<0 || format<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock _l(mSurfaceLock); + mBufferInfo.set(w, h, format); + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + int Surface::getConnectedApi() const { Mutex::Autolock _l(mSurfaceLock); return mConnected; } - // ---------------------------------------------------------------------------- status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -703,45 +769,47 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - sp<GraphicBuffer> backBuffer; - status_t err = dequeueBuffer(&backBuffer); + android_native_buffer_t* out; + status_t err = dequeueBuffer(&out); LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { + sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); err = lockBuffer(backBuffer.get()); LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)", - backBuffer->getIndex(), strerror(-err)); + getBufferIndex(backBuffer), strerror(-err)); if (err == NO_ERROR) { - // we handle copy-back here... - const Rect bounds(backBuffer->width, backBuffer->height); - Region scratch(bounds); + const Region boundsRegion(bounds); + Region scratch(boundsRegion); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); + newDirtyRegion &= boundsRegion; - if (mNeedFullUpdate) { - // reset newDirtyRegion to bounds when a buffer is reallocated - // it would be better if this information was associated with - // the buffer and made available to outside of Surface. - // This will do for now though. - mNeedFullUpdate = false; - newDirtyRegion.set(bounds); - } else { - newDirtyRegion.andSelf(bounds); - } - + // figure out if we can copy the frontbuffer back const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - if (frontBuffer !=0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) - { + const bool canCopyBack = (frontBuffer != 0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + backBuffer->format == frontBuffer->format && + !(mFlags & ISurfaceComposer::eDestroyBackbuffer)); + + // the dirty region we report to surfaceflinger is the one + // given by the user (as opposed to the one *we* return to the + // user). + mDirtyRegion = newDirtyRegion; + + if (canCopyBack) { + // copy the area that is invalid and not repainted this round const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty() && frontBuffer!=0) { - // copy front to back + if (!copyback.isEmpty()) copyBlt(backBuffer, frontBuffer, copyback); - } + } else { + // if we can't copy-back anything, modify the user's dirty + // region to make sure they redraw the whole buffer + newDirtyRegion = boundsRegion; } - mDirtyRegion = newDirtyRegion; + // keep track of the are of the buffer that is "clean" + // (ie: that will be redrawn) mOldDirtyRegion = newDirtyRegion; void* vaddr; @@ -777,7 +845,7 @@ status_t Surface::unlockAndPost() err = queueBuffer(mLockedBuffer.get()); LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)", - mLockedBuffer->getIndex(), strerror(-err)); + getBufferIndex(mLockedBuffer), strerror(-err)); mPostedBuffer = mLockedBuffer; mLockedBuffer = 0; @@ -789,7 +857,13 @@ void Surface::setSwapRectangle(const Rect& r) { mSwapRectangle = r; } -status_t Surface::getBufferLocked(int index, int usage) +int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const +{ + return buffer->getIndex(); +} + +status_t Surface::getBufferLocked(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { sp<ISurface> s(mSurface); if (s == 0) return NO_INIT; @@ -797,20 +871,21 @@ status_t Surface::getBufferLocked(int index, int usage) status_t err = NO_MEMORY; // free the current buffer - sp<GraphicBuffer>& currentBuffer(mBuffers[index]); + sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index)); if (currentBuffer != 0) { getBufferMapper().unregisterBuffer(currentBuffer->handle); currentBuffer.clear(); } - sp<GraphicBuffer> buffer = s->requestBuffer(index, usage); + sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage); LOGE_IF(buffer==0, "ISurface::getBuffer(%d, %08x) returned NULL", index, usage); if (buffer != 0) { // this should never happen by construction LOGE_IF(buffer->handle == NULL, - "Surface (identity=%d) requestBuffer(%d, %08x) returned" - "a buffer with a null handle", mIdentity, index, usage); + "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) " + "returned a buffer with a null handle", + mIdentity, index, w, h, format, usage); err = mSharedBufferClient->getStatus(); LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err); if (!err && buffer->handle != NULL) { @@ -820,14 +895,52 @@ status_t Surface::getBufferLocked(int index, int usage) if (err == NO_ERROR) { currentBuffer = buffer; currentBuffer->setIndex(index); - mNeedFullUpdate = true; } } else { - err = err<0 ? err : NO_MEMORY; + err = err<0 ? err : status_t(NO_MEMORY); } } return err; } +// ---------------------------------------------------------------------------- +Surface::BufferInfo::BufferInfo() + : mWidth(0), mHeight(0), mFormat(0), + mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0) +{ +} + +void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) { + if ((mWidth != w) || (mHeight != h) || (mFormat != format)) { + mWidth = w; + mHeight = h; + mFormat = format; + mDirty |= GEOMETRY; + } +} + +void Surface::BufferInfo::set(uint32_t usage) { + mUsage = usage; +} + +void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const { + *pWidth = mWidth; + *pHeight = mHeight; + *pFormat = mFormat; + *pUsage = mUsage; +} + +bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const { + // make sure we AT LEAST have the usage flags we want + if (mDirty || buffer==0 || + ((buffer->usage & mUsage) != mUsage)) { + mDirty = 0; + return false; + } + return true; +} + +// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp index 85167da..0670d20 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp @@ -17,98 +17,147 @@ #define LOG_TAG "SurfaceComposerClient" #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <sys/types.h> -#include <sys/stat.h> -#include <cutils/memory.h> - -#include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/threads.h> -#include <utils/KeyedVector.h> +#include <utils/SortedVector.h> #include <utils/Log.h> +#include <utils/Singleton.h> #include <binder/IServiceManager.h> #include <binder/IMemory.h> #include <ui/DisplayInfo.h> -#include <ui/Rect.h> #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <surfaceflinger/ISurface.h> #include <surfaceflinger/SurfaceComposerClient.h> #include <private/surfaceflinger/LayerState.h> #include <private/surfaceflinger/SharedBufferStack.h> -#define VERBOSE(...) ((void)0) -//#define VERBOSE LOGD - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { - // --------------------------------------------------------------------------- -// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. -static Mutex gLock; -static sp<ISurfaceComposer> gSurfaceManager; -static DefaultKeyedVector< sp<IBinder>, wp<SurfaceComposerClient> > gActiveConnections; -static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions; -static sp<IMemoryHeap> gServerCblkMemory; -static volatile surface_flinger_cblk_t* gServerCblk; - -static sp<ISurfaceComposer> getComposerService() -{ - sp<ISurfaceComposer> sc; - Mutex::Autolock _l(gLock); - if (gSurfaceManager != 0) { - sc = gSurfaceManager; - } else { - // release the lock while we're waiting... - gLock.unlock(); - - sp<IBinder> binder; - sp<IServiceManager> sm = defaultServiceManager(); - do { - binder = sm->getService(String16("SurfaceFlinger")); - if (binder == 0) { - LOGW("SurfaceFlinger not published, waiting..."); - usleep(500000); // 0.5 s - } - } while(binder == 0); - - // grab the lock again for updating gSurfaceManager - gLock.lock(); - if (gSurfaceManager == 0) { - sc = interface_cast<ISurfaceComposer>(binder); - gSurfaceManager = sc; - } else { - sc = gSurfaceManager; +class ComposerService : public Singleton<ComposerService> +{ + // these are constants + sp<ISurfaceComposer> mComposerService; + sp<IMemoryHeap> mServerCblkMemory; + surface_flinger_cblk_t volatile* mServerCblk; + + ComposerService() : Singleton<ComposerService>() { + const String16 name("SurfaceFlinger"); + while (getService(name, &mComposerService) != NO_ERROR) { + usleep(250000); } + mServerCblkMemory = mComposerService->getCblk(); + mServerCblk = static_cast<surface_flinger_cblk_t volatile *>( + mServerCblkMemory->getBase()); + } + + friend class Singleton<ComposerService>; + +public: + static sp<ISurfaceComposer> getComposerService() { + return ComposerService::getInstance().mComposerService; + } + static surface_flinger_cblk_t const volatile * getControlBlock() { + return ComposerService::getInstance().mServerCblk; } - return sc; +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); + + +static inline sp<ISurfaceComposer> getComposerService() { + return ComposerService::getComposerService(); +} + +static inline surface_flinger_cblk_t const volatile * get_cblk() { + return ComposerService::getControlBlock(); } -static volatile surface_flinger_cblk_t const * get_cblk() +// --------------------------------------------------------------------------- + +class Composer : public Singleton<Composer> { - if (gServerCblk == 0) { - sp<ISurfaceComposer> sm(getComposerService()); - Mutex::Autolock _l(gLock); - if (gServerCblk == 0) { - gServerCblkMemory = sm->getCblk(); - LOGE_IF(gServerCblkMemory==0, "Can't get server control block"); - gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase(); - LOGE_IF(gServerCblk==0, "Can't get server control block address"); + Mutex mLock; + SortedVector< wp<SurfaceComposerClient> > mActiveConnections; + SortedVector<sp<SurfaceComposerClient> > mOpenTransactions; + + Composer() : Singleton<Composer>() { + } + + void addClientImpl(const sp<SurfaceComposerClient>& client) { + Mutex::Autolock _l(mLock); + mActiveConnections.add(client); + } + + void removeClientImpl(const sp<SurfaceComposerClient>& client) { + Mutex::Autolock _l(mLock); + mActiveConnections.remove(client); + } + + void openGlobalTransactionImpl() + { + Mutex::Autolock _l(mLock); + if (mOpenTransactions.size()) { + LOGE("openGlobalTransaction() called more than once. skipping."); + return; + } + const size_t N = mActiveConnections.size(); + for (size_t i=0; i<N; i++) { + sp<SurfaceComposerClient> client(mActiveConnections[i].promote()); + if (client != 0 && mOpenTransactions.indexOf(client) < 0) { + if (client->openTransaction() == NO_ERROR) { + mOpenTransactions.add(client); + } else { + LOGE("openTransaction on client %p failed", client.get()); + // let it go, it'll fail later when the user + // tries to do something with the transaction + } + } } } - return gServerCblk; -} + + void closeGlobalTransactionImpl() + { + mLock.lock(); + SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions); + mOpenTransactions.clear(); + mLock.unlock(); + + sp<ISurfaceComposer> sm(getComposerService()); + sm->openGlobalTransaction(); + const size_t N = clients.size(); + for (size_t i=0; i<N; i++) { + clients[i]->closeTransaction(); + } + sm->closeGlobalTransaction(); + } + + friend class Singleton<Composer>; + +public: + static void addClient(const sp<SurfaceComposerClient>& client) { + Composer::getInstance().addClientImpl(client); + } + static void removeClient(const sp<SurfaceComposerClient>& client) { + Composer::getInstance().removeClientImpl(client); + } + static void openGlobalTransaction() { + Composer::getInstance().openGlobalTransactionImpl(); + } + static void closeGlobalTransaction() { + Composer::getInstance().closeGlobalTransactionImpl(); + } +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- @@ -120,61 +169,27 @@ static inline int compare_type( const layer_state_t& lhs, } SurfaceComposerClient::SurfaceComposerClient() + : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT) { - sp<ISurfaceComposer> sm(getComposerService()); - if (sm == 0) { - _init(0, 0); - return; - } - - _init(sm, sm->createConnection()); - - if (mClient != 0) { - Mutex::Autolock _l(gLock); - VERBOSE("Adding client %p to map", this); - gActiveConnections.add(mClient->asBinder(), this); - } } -SurfaceComposerClient::SurfaceComposerClient( - const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn) -{ - _init(sm, interface_cast<ISurfaceFlingerClient>(conn)); -} - - -status_t SurfaceComposerClient::linkToComposerDeath( - const sp<IBinder::DeathRecipient>& recipient, - void* cookie, uint32_t flags) +void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sm(getComposerService()); - return sm->asBinder()->linkToDeath(recipient, cookie, flags); -} - -void SurfaceComposerClient::_init( - const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn) -{ - VERBOSE("Creating client %p, conn %p", this, conn.get()); - - mPrebuiltLayerState = 0; - mTransactionOpen = 0; - mStatus = NO_ERROR; - mControl = 0; - - mClient = conn; - if (mClient == 0) { - mStatus = NO_INIT; - return; + if (sm != 0) { + sp<ISurfaceComposerClient> conn = sm->createConnection(); + if (conn != 0) { + mClient = conn; + Composer::addClient(this); + mPrebuiltLayerState = new layer_state_t; + mStatus = NO_ERROR; + } } - - mControlMemory = mClient->getControlBlock(); - mSignalServer = sm; - mControl = static_cast<SharedClient *>(mControlMemory->getBase()); } SurfaceComposerClient::~SurfaceComposerClient() { - VERBOSE("Destroying client %p, conn %p", this, mClient.get()); + delete mPrebuiltLayerState; dispose(); } @@ -188,69 +203,31 @@ sp<IBinder> SurfaceComposerClient::connection() const return (mClient != 0) ? mClient->asBinder() : 0; } -sp<SurfaceComposerClient> -SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn) +status_t SurfaceComposerClient::linkToComposerDeath( + const sp<IBinder::DeathRecipient>& recipient, + void* cookie, uint32_t flags) { - sp<SurfaceComposerClient> client; - - { // scope for lock - Mutex::Autolock _l(gLock); - client = gActiveConnections.valueFor(conn).promote(); - } - - if (client == 0) { - // Need to make a new client. - sp<ISurfaceComposer> sm(getComposerService()); - client = new SurfaceComposerClient(sm, conn); - if (client != 0 && client->initCheck() == NO_ERROR) { - Mutex::Autolock _l(gLock); - gActiveConnections.add(conn, client); - //LOGD("we have %d connections", gActiveConnections.size()); - } else { - client.clear(); - } - } - - return client; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->asBinder()->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. - - sp<IMemoryHeap> controlMemory; - sp<ISurfaceFlingerClient> client; - - { - Mutex::Autolock _lg(gLock); - Mutex::Autolock _lm(mLock); - - mSignalServer = 0; - - if (mClient != 0) { - client = mClient; - mClient.clear(); - - ssize_t i = gActiveConnections.indexOfKey(client->asBinder()); - if (i >= 0 && gActiveConnections.valueAt(i) == this) { - VERBOSE("Removing client %p from map at %d", this, int(i)); - gActiveConnections.removeItemsAt(i); - } - } - - delete mPrebuiltLayerState; - mPrebuiltLayerState = 0; - controlMemory = mControlMemory; - mControlMemory.clear(); - mControl = 0; - mStatus = NO_INIT; + sp<ISurfaceComposerClient> client; + Mutex::Autolock _lm(mLock); + if (mClient != 0) { + Composer::removeClient(this); + client = mClient; // hold ref while lock is held + mClient.clear(); } + mStatus = NO_INIT; } status_t SurfaceComposerClient::getDisplayInfo( DisplayID dpy, DisplayInfo* info) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); @@ -268,7 +245,7 @@ status_t SurfaceComposerClient::getDisplayInfo( ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -277,7 +254,7 @@ ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -286,7 +263,7 @@ ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -305,12 +282,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays() return n; } - -void SurfaceComposerClient::signalServer() -{ - mSignalServer->signal(); -} - sp<SurfaceControl> SurfaceComposerClient::createSurface( int pid, DisplayID display, @@ -327,7 +298,6 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return SurfaceComposerClient::createSurface(pid, name, display, w, h, format, flags); - } sp<SurfaceControl> SurfaceComposerClient::createSurface( @@ -341,11 +311,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( { sp<SurfaceControl> result; if (mStatus == NO_ERROR) { - ISurfaceFlingerClient::surface_data_t data; + ISurfaceComposerClient::surface_data_t data; sp<ISurface> surface = mClient->createSurface(&data, pid, name, display, w, h, format, flags); if (surface != 0) { - if (uint32_t(data.token) < NUM_LAYERS_MAX) { + if (uint32_t(data.token) < SharedBufferStack::NUM_LAYERS_MAX) { result = new SurfaceControl(this, surface, data, w, h, format, flags); } } @@ -373,56 +343,14 @@ status_t SurfaceComposerClient::destroySurface(SurfaceID sid) void SurfaceComposerClient::openGlobalTransaction() { - Mutex::Autolock _l(gLock); - - if (gOpenTransactions.size()) { - LOGE("openGlobalTransaction() called more than once. skipping."); - return; - } - - const size_t N = gActiveConnections.size(); - VERBOSE("openGlobalTransaction (%ld clients)", N); - for (size_t i=0; i<N; i++) { - sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i).promote()); - if (client != 0 && gOpenTransactions.indexOf(client) < 0) { - if (client->openTransaction() == NO_ERROR) { - if (gOpenTransactions.add(client) < 0) { - // Ooops! - LOGE( "Unable to add a SurfaceComposerClient " - "to the global transaction set (out of memory?)"); - client->closeTransaction(); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } else { - LOGE("openTransaction on client %p failed", client.get()); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } - } + Composer::openGlobalTransaction(); } void SurfaceComposerClient::closeGlobalTransaction() { - gLock.lock(); - SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions); - gOpenTransactions.clear(); - gLock.unlock(); - - const size_t N = clients.size(); - VERBOSE("closeGlobalTransaction (%ld clients)", N); - - sp<ISurfaceComposer> sm(getComposerService()); - sm->openGlobalTransaction(); - for (size_t i=0; i<N; i++) { - clients[i]->closeTransaction(); - } - sm->closeGlobalTransaction(); - + Composer::closeGlobalTransaction(); } - status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { sp<ISurfaceComposer> sm(getComposerService()); @@ -447,26 +375,16 @@ status_t SurfaceComposerClient::openTransaction() if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); - VERBOSE( "openTransaction (client %p, mTransactionOpen=%d)", - this, mTransactionOpen); mTransactionOpen++; - if (mPrebuiltLayerState == 0) { - mPrebuiltLayerState = new layer_state_t; - } return NO_ERROR; } - status_t SurfaceComposerClient::closeTransaction() { if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); - - VERBOSE( "closeTransaction (client %p, mTransactionOpen=%d)", - this, mTransactionOpen); - if (mTransactionOpen <= 0) { LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " "called more times than openTransaction()", @@ -488,7 +406,7 @@ status_t SurfaceComposerClient::closeTransaction() return NO_ERROR; } -layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) +layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index) { // API usage error, do nothing. if (mTransactionOpen<=0) { @@ -498,7 +416,7 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) } // use mPrebuiltLayerState just to find out if we already have it - layer_state_t& dummy = *mPrebuiltLayerState; + layer_state_t& dummy(*mPrebuiltLayerState); dummy.surface = index; ssize_t i = mStates.indexOf(dummy); if (i < 0) { @@ -508,49 +426,49 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) return mStates.editArray() + i; } -layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id) +layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id) { layer_state_t* s; mLock.lock(); - s = _get_state_l(id); + s = get_state_l(id); if (!s) mLock.unlock(); return s; } -void SurfaceComposerClient::_unlockLayerState() +void SurfaceComposerClient::unlockLayerState() { mLock.unlock(); } status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::ePositionChanged; s->x = x; s->y = y; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eSizeChanged; s->w = w; s->h = h; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eLayerChanged; s->z = z; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } @@ -579,34 +497,34 @@ status_t SurfaceComposerClient::unfreeze(SurfaceID id) status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, uint32_t mask) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eVisibilityChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setTransparentRegionHint( SurfaceID id, const Region& transparentRegion) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eAlphaChanged; s->alpha = alpha; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } @@ -615,7 +533,7 @@ status_t SurfaceComposerClient::setMatrix( float dsdx, float dtdx, float dsdy, float dtdy ) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eMatrixChanged; layer_state_t::matrix22_t matrix; @@ -624,19 +542,56 @@ status_t SurfaceComposerClient::setMatrix( matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eFreezeTintChanged; s->tint = tint; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } +// ---------------------------------------------------------------------------- + +SurfaceClient::SurfaceClient(const sp<SurfaceComposerClient>& client) + : mStatus(NO_INIT), mControl(0) +{ + if (client != 0) { + sp<IBinder> conn = client->connection(); + init(conn); + } +} +SurfaceClient::SurfaceClient(const sp<IBinder>& conn) + : mStatus(NO_INIT), mControl(0) +{ + init(conn); +} +void SurfaceClient::init(const sp<IBinder>& conn) +{ + mComposerService = getComposerService(); + sp<ISurfaceComposerClient> sf(interface_cast<ISurfaceComposerClient>(conn)); + if (sf != 0) { + mConnection = conn; + mControlMemory = sf->getControlBlock(); + mControl = static_cast<SharedClient *>(mControlMemory->getBase()); + mStatus = NO_ERROR; + } +} +status_t SurfaceClient::initCheck() const { + return mStatus; +} +SharedClient* SurfaceClient::getSharedClient() const { + return mControl; +} +void SurfaceClient::signalServer() const { + mComposerService->signal(); +} + +// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libs/surfaceflinger_client/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk new file mode 100644 index 0000000..d3dfe04 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + SharedBufferStackTest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libui \ + libsurfaceflinger_client + +LOCAL_MODULE:= test-sharedbufferstack + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp new file mode 100644 index 0000000..f409f48 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef NDEBUG + +#include <assert.h> +#include <cutils/memory.h> +#include <cutils/log.h> +#include <utils/Errors.h> +#include <private/surfaceflinger/SharedBufferStack.h> + +using namespace android; + +void log(const char* prefix, int *b, size_t num); +void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); + +// ---------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + SharedClient client; + SharedBufferServer s(&client, 0, 4, 0); + SharedBufferClient c(&client, 0, 4, 0); + + printf("basic test 0\n"); + int list0[4] = {0, 1, 2, 3}; + test0(s, c, 4, list0); + + printf("basic test 1\n"); + int list1[4] = {2, 1, 0, 3}; + test0(s, c, 4, list1); + + int b = c.dequeue(); + c.lock(b); + c.queue(b); + s.retireAndLock(); + + printf("basic test 2\n"); + int list2[4] = {1, 2, 3, 0}; + test0(s, c, 4, list2); + + + printf("resize test\n"); + class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { + SharedBufferServer& s; + virtual status_t operator()(int bufferCount) const { + return s.resize(bufferCount); + } + public: + SetBufferCountIPC(SharedBufferServer& s) : s(s) { } + } resize(s); + + c.setBufferCount(6, resize); + int list3[6] = {3, 2, 1, 4, 5, 0}; + test0(s, c, 6, list3); + + return 0; +} + +void log(const char* prefix, int *b, size_t num) +{ + printf("%s: ", prefix); + for (size_t i=0 ; i<num ; i++) { + printf("%d ", b[i]); + } + printf("\n"); +} + +// ---------------------------------------------------------------------------- + +void test0( + SharedBufferServer& s, + SharedBufferClient& c, + size_t num, + int* list) +{ + status_t err; + int b[num], u[num], r[num]; + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==list[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==list[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(b[num-1]); + assert(err == 0); + log("LK", b+num-1, 1); + + err = c.queue(b[num-1]); + assert(err == 0); + log(" Q", b+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==list[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==list[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + u[i] = b[num-2-i]; + } + u[num-1] = b[num-1]; + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(u[i]); + assert(err==0); + } + log(" Q", u, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(b[num-1]); + assert(err == 0); + log("LK", b+num-1, 1); + + err = c.queue(b[num-1]); + assert(err == 0); + log(" Q", b+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==list[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==u[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(u[num-1]); + assert(err == 0); + log("LK", u+num-1, 1); + + err = c.queue(u[num-1]); + assert(err == 0); + log(" Q", u+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==u[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + b[0] = c.dequeue(); + assert(b[0]==u[0]); + log("DQ", b, 1); + + c.undoDequeue(b[0]); + assert(err == 0); + log("UDQ", b, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==u[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(u[num-1]); + assert(err == 0); + log("LK", u+num-1, 1); + + err = c.queue(u[num-1]); + assert(err == 0); + log(" Q", u+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==u[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + printf("\n"); +} diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 6ae7e74..d51664d 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -15,6 +15,8 @@ ** limitations under the License. */ +#define LOG_TAG "GraphicBufferAllocator" + #include <cutils/log.h> #include <utils/Singleton.h> @@ -61,9 +63,9 @@ void GraphicBufferAllocator::dump(String8& result) const const size_t c = list.size(); for (size_t i=0 ; i<c ; i++) { const alloc_rec_t& rec(list.valueAt(i)); - snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u x %4u | %2d | 0x%08x\n", + snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n", list.keyAt(i), rec.size/1024.0f, - rec.w, rec.h, rec.format, rec.usage); + rec.w, rec.s, rec.h, rec.format, rec.usage); result.append(buffer); total += rec.size; } @@ -71,16 +73,13 @@ void GraphicBufferAllocator::dump(String8& result) const result.append(buffer); } -static inline uint32_t clamp(uint32_t c) { - return c>0 ? c : 1; -} - status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, buffer_handle_t* handle, int32_t* stride) { - // make sure to not allocate a 0 x 0 buffer - w = clamp(w); - h = clamp(h); + // make sure to not allocate a N x 0 or 0 x N buffer, since this is + // allowed from an API stand-point allocate a 1x1 buffer instead. + if (!w || !h) + w = h = 1; // we have a h/w allocator and h/w buffer is requested status_t err; @@ -100,9 +99,9 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma alloc_rec_t rec; rec.w = w; rec.h = h; + rec.s = *stride; rec.format = format; rec.usage = usage; - rec.vaddr = 0; rec.size = h * stride[0] * bytesPerPixel(format); list.add(*handle, rec); } else { diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 5a05e6a..60a0d82 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -824,7 +824,7 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, // TODO: look for previously-created shared memory slice? int method; - long uncompressedLen; + size_t uncompressedLen; //printf("USING Zip '%s'\n", pEntry->getFileName()); diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 7e0f881..a1401ad 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -4178,6 +4178,9 @@ void ResTable::print(bool inclValues) const case ResTable_config::SCREENSIZE_LARGE: printf(" (large)"); break; + case ResTable_config::SCREENSIZE_XLARGE: + printf(" (xlarge)"); + break; } printf(" lng=%d", type->config.screenLayout&ResTable_config::MASK_SCREENLONG); diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp index 45f6c8b..16b219c 100644 --- a/libs/utils/ZipFileCRO.cpp +++ b/libs/utils/ZipFileCRO.cpp @@ -39,8 +39,8 @@ ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken, } bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken, - int* pMethod, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { + int* pMethod, size_t* pUncompLen, + size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { ZipFileRO* zip = (ZipFileRO*)zipToken; ZipEntryRO entry = (ZipEntryRO)entryToken; return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 6c701dd..28dc512 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -29,6 +29,22 @@ #include <fcntl.h> #include <errno.h> #include <assert.h> +#include <unistd.h> + +/* + * TEMP_FAILURE_RETRY is defined by some, but not all, versions of + * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's + * not already defined, then define it here. + */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) +#endif using namespace android; @@ -38,6 +54,7 @@ using namespace android; #define kEOCDSignature 0x06054b50 #define kEOCDLen 22 #define kEOCDNumEntries 8 // offset to #of entries in file +#define kEOCDSize 12 // size of the central directory #define kEOCDFileOffset 16 // offset to central directory #define kMaxCommentLen 65535 // longest possible in ushort @@ -90,9 +107,8 @@ int ZipFileRO::entryToIndex(const ZipEntryRO entry) const status_t ZipFileRO::open(const char* zipFileName) { int fd = -1; - off_t length; - assert(mFileMap == NULL); + assert(mDirectoryMap == NULL); /* * Open and map the specified file. @@ -103,172 +119,240 @@ status_t ZipFileRO::open(const char* zipFileName) return NAME_NOT_FOUND; } - length = lseek(fd, 0, SEEK_END); - if (length < 0) { + mFileLength = lseek(fd, 0, SEEK_END); + if (mFileLength < kEOCDLen) { close(fd); return UNKNOWN_ERROR; } - mFileMap = new FileMap(); - if (mFileMap == NULL) { - close(fd); - return NO_MEMORY; - } - if (!mFileMap->create(zipFileName, fd, 0, length, true)) { - LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno)); - close(fd); - return UNKNOWN_ERROR; + if (mFileName != NULL) { + free(mFileName); } + mFileName = strdup(zipFileName); mFd = fd; /* - * Got it mapped, verify it and create data structures for fast access. + * Find the Central Directory and store its size and number of entries. + */ + if (!mapCentralDirectory()) { + goto bail; + } + + /* + * Verify Central Directory and create data structures for fast access. */ if (!parseZipArchive()) { - mFileMap->release(); - mFileMap = NULL; - return UNKNOWN_ERROR; + goto bail; } return OK; + +bail: + free(mFileName); + mFileName = NULL; + close(fd); + return UNKNOWN_ERROR; } /* * Parse the Zip archive, verifying its contents and initializing internal * data structures. */ -bool ZipFileRO::parseZipArchive(void) +bool ZipFileRO::mapCentralDirectory(void) { -#define CHECK_OFFSET(_off) { \ - if ((unsigned int) (_off) >= maxOffset) { \ - LOGE("ERROR: bad offset %u (max %d): %s\n", \ - (unsigned int) (_off), maxOffset, #_off); \ - goto bail; \ - } \ - } - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - const unsigned char* ptr; - size_t length = mFileMap->getDataLength(); - bool result = false; - unsigned int i, numEntries, cdOffset; - unsigned int val; + size_t readAmount = kMaxEOCDSearch; + if (readAmount > (size_t) mFileLength) + readAmount = mFileLength; + + unsigned char* scanBuf = (unsigned char*) malloc(readAmount); + if (scanBuf == NULL) { + LOGW("couldn't allocate scanBuf: %s", strerror(errno)); + free(scanBuf); + return false; + } /* - * The first 4 bytes of the file will either be the local header - * signature for the first file (kLFHSignature) or, if the archive doesn't - * have any files in it, the end-of-central-directory signature - * (kEOCDSignature). + * Make sure this is a Zip archive. */ - val = get4LE(basePtr); - if (val == kEOCDSignature) { - LOGI("Found Zip archive, but it looks empty\n"); - goto bail; - } else if (val != kLFHSignature) { - LOGV("Not a Zip archive (found 0x%08x)\n", val); - goto bail; + if (lseek(mFd, 0, SEEK_SET) != 0) { + LOGW("seek to start failed: %s", strerror(errno)); + free(scanBuf); + return false; + } + + ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t))); + if (actual != (ssize_t) sizeof(int32_t)) { + LOGI("couldn't read first signature from zip archive: %s", strerror(errno)); + free(scanBuf); + return false; + } + + { + unsigned int header = get4LE(scanBuf); + if (header == kEOCDSignature) { + LOGI("Found Zip archive, but it looks empty\n"); + free(scanBuf); + return false; + } else if (header != kLFHSignature) { + LOGV("Not a Zip archive (found 0x%08x)\n", val); + free(scanBuf); + return false; + } } /* - * Find the EOCD. We'll find it immediately unless they have a file - * comment. + * Perform the traditional EOCD snipe hunt. + * + * We're searching for the End of Central Directory magic number, + * which appears at the start of the EOCD block. It's followed by + * 18 bytes of EOCD stuff and up to 64KB of archive comment. We + * need to read the last part of the file into a buffer, dig through + * it to find the magic number, parse some values out, and use those + * to determine the extent of the CD. + * + * We start by pulling in the last part of the file. */ - ptr = basePtr + length - kEOCDLen; + off_t searchStart = mFileLength - readAmount; - while (ptr >= basePtr) { - if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature) + if (lseek(mFd, searchStart, SEEK_SET) != searchStart) { + LOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno)); + free(scanBuf); + return false; + } + actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount)); + if (actual != (ssize_t) readAmount) { + LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno)); + free(scanBuf); + return false; + } + + /* + * Scan backward for the EOCD magic. In an archive without a trailing + * comment, we'll find it on the first try. (We may want to consider + * doing an initial minimal read; if we don't find it, retry with a + * second read as above.) + */ + int i; + for (i = readAmount - kEOCDLen; i >= 0; i--) { + if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) { + LOGV("+++ Found EOCD at buf+%d\n", i); break; - ptr--; + } } - if (ptr < basePtr) { - LOGI("Could not find end-of-central-directory in Zip\n"); - goto bail; + if (i < 0) { + LOGD("Zip: EOCD not found, %s is not zip\n", mFileName); + free(scanBuf); + return false; } + off_t eocdOffset = searchStart + i; + const unsigned char* eocdPtr = scanBuf + i; + + assert(eocdOffset < mFileLength); + /* - * There are two interesting items in the EOCD block: the number of - * entries in the file, and the file offset of the start of the - * central directory. - * - * (There's actually a count of the #of entries in this file, and for - * all files which comprise a spanned archive, but for our purposes - * we're only interested in the current file. Besides, we expect the - * two to be equivalent for our stuff.) + * Grab the CD offset and size, and the number of entries in the + * archive. Verify that they look reasonable. */ - numEntries = get2LE(ptr + kEOCDNumEntries); - cdOffset = get4LE(ptr + kEOCDFileOffset); + unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries); + unsigned int dirSize = get4LE(eocdPtr + kEOCDSize); + unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset); + + if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) { + LOGW("bad offsets (dir %ld, size %u, eocd %ld)\n", + (long) dirOffset, dirSize, (long) eocdOffset); + free(scanBuf); + return false; + } + if (numEntries == 0) { + LOGW("empty archive?\n"); + free(scanBuf); + return false; + } - /* valid offsets are [0,EOCD] */ - unsigned int maxOffset; - maxOffset = (ptr - basePtr) +1; + LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n", + numEntries, dirSize, dirOffset); - LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset); - if (numEntries == 0 || cdOffset >= length) { - LOGW("Invalid entries=%d offset=%d (len=%zd)\n", - numEntries, cdOffset, length); - goto bail; + mDirectoryMap = new FileMap(); + if (mDirectoryMap == NULL) { + LOGW("Unable to create directory map: %s", strerror(errno)); + free(scanBuf); + return false; } + if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) { + LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName, + dirOffset, dirOffset + dirSize, strerror(errno)); + free(scanBuf); + return false; + } + + mNumEntries = numEntries; + mDirectoryOffset = dirOffset; + + return true; +} + +bool ZipFileRO::parseZipArchive(void) +{ + bool result = false; + const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr(); + size_t cdLength = mDirectoryMap->getDataLength(); + int numEntries = mNumEntries; + /* * Create hash table. We have a minimum 75% load factor, possibly as * low as 50% after we round off to a power of 2. */ - mNumEntries = numEntries; - mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3)); - mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize); + mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3); + mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry)); /* * Walk through the central directory, adding entries to the hash * table. */ - ptr = basePtr + cdOffset; - for (i = 0; i < numEntries; i++) { - unsigned int fileNameLen, extraLen, commentLen, localHdrOffset; - const unsigned char* localHdr; - unsigned int hash; - + const unsigned char* ptr = cdPtr; + for (int i = 0; i < numEntries; i++) { if (get4LE(ptr) != kCDESignature) { LOGW("Missed a central dir sig (at %d)\n", i); goto bail; } - if (ptr + kCDELen > basePtr + length) { + if (ptr + kCDELen > cdPtr + cdLength) { LOGW("Ran off the end (at %d)\n", i); goto bail; } - localHdrOffset = get4LE(ptr + kCDELocalOffset); - CHECK_OFFSET(localHdrOffset); + long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); + if (localHdrOffset >= mDirectoryOffset) { + LOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i); + goto bail; + } + + unsigned int fileNameLen, extraLen, commentLen, hash; + fileNameLen = get2LE(ptr + kCDENameLen); extraLen = get2LE(ptr + kCDEExtraLen); commentLen = get2LE(ptr + kCDECommentLen); - //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n", - // i, localHdrOffset, fileNameLen, extraLen, commentLen); - //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen); - /* add the CDE filename to the hash table */ hash = computeHash((const char*)ptr + kCDELen, fileNameLen); addToHash((const char*)ptr + kCDELen, fileNameLen, hash); - localHdr = basePtr + localHdrOffset; - if (get4LE(localHdr) != kLFHSignature) { - LOGW("Bad offset to local header: %d (at %d)\n", - localHdrOffset, i); + ptr += kCDELen + fileNameLen + extraLen + commentLen; + if ((size_t)(ptr - cdPtr) > cdLength) { + LOGW("bad CD advance (%d vs %zd) at entry %d\n", + (int) (ptr - cdPtr), cdLength, i); goto bail; } - - ptr += kCDELen + fileNameLen + extraLen + commentLen; - CHECK_OFFSET(ptr - basePtr); } - + LOGV("+++ zip good scan %d entries\n", numEntries); result = true; bail: return result; -#undef CHECK_OFFSET } - /* * Simple string hash function for non-null-terminated strings. */ @@ -315,7 +399,7 @@ ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const memcmp(mHashTable[ent].name, fileName, nameLen) == 0) { /* match */ - return (ZipEntryRO) (ent + kZipEntryAdj); + return (ZipEntryRO)(long)(ent + kZipEntryAdj); } ent = (ent + 1) & (mHashTableSize-1); @@ -354,20 +438,24 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const * Returns "false" if the offsets to the fields or the contents of the fields * appear to be bogus. */ -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const +bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, + size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const { - int ent = entryToIndex(entry); + bool ret = false; + + const int ent = entryToIndex(entry); if (ent < 0) return false; + HashEntry hashEntry = mHashTable[ent]; + /* * Recover the start of the central directory entry from the filename - * pointer. + * pointer. The filename is the first entry past the fixed-size data, + * so we can just subtract back from that. */ - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name; - size_t zipLength = mFileMap->getDataLength(); + const unsigned char* ptr = (const unsigned char*) hashEntry.name; + off_t cdOffset = mDirectoryOffset; ptr -= kCDELen; @@ -380,48 +468,78 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen, if (pCrc32 != NULL) *pCrc32 = get4LE(ptr + kCDECRC); + size_t compLen = get4LE(ptr + kCDECompLen); + if (pCompLen != NULL) + *pCompLen = compLen; + size_t uncompLen = get4LE(ptr + kCDEUncompLen); + if (pUncompLen != NULL) + *pUncompLen = uncompLen; + /* - * We need to make sure that the lengths are not so large that somebody - * trying to map the compressed or uncompressed data runs off the end - * of the mapped region. + * If requested, determine the offset of the start of the data. All we + * have is the offset to the Local File Header, which is variable size, + * so we have to read the contents of the struct to figure out where + * the actual data starts. + * + * We also need to make sure that the lengths are not so large that + * somebody trying to map the compressed or uncompressed data runs + * off the end of the mapped region. + * + * Note we don't verify compLen/uncompLen if they don't request the + * dataOffset, because dataOffset is expensive to determine. However, + * if they don't have the file offset, they're not likely to be doing + * anything with the contents. */ - unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset); - if (localHdrOffset + kLFHLen >= zipLength) { - LOGE("ERROR: bad local hdr offset in zip\n"); - return false; - } - const unsigned char* localHdr = basePtr + localHdrOffset; - off_t dataOffset = localHdrOffset + kLFHLen - + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen); - if ((unsigned long) dataOffset >= zipLength) { - LOGE("ERROR: bad data offset in zip\n"); - return false; - } + if (pOffset != NULL) { + long localHdrOffset = get4LE(ptr + kCDELocalOffset); + if (localHdrOffset + kLFHLen >= cdOffset) { + LOGE("ERROR: bad local hdr offset in zip\n"); + return false; + } - if (pCompLen != NULL) { - *pCompLen = get4LE(ptr + kCDECompLen); - if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) { - LOGE("ERROR: bad compressed length in zip\n"); + unsigned char lfhBuf[kLFHLen]; + if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { + LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset); return false; } - } - if (pUncompLen != NULL) { - *pUncompLen = get4LE(ptr + kCDEUncompLen); - if (*pUncompLen < 0) { - LOGE("ERROR: negative uncompressed length in zip\n"); + ssize_t actual = + TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); + if (actual != sizeof(lfhBuf)) { + LOGW("failed reading lfh from offset %ld\n", localHdrOffset); + return false; + } + + if (get4LE(lfhBuf) != kLFHSignature) { + LOGW("didn't find signature at start of lfh, offset=%ld\n", + localHdrOffset); return false; } + + off_t dataOffset = localHdrOffset + kLFHLen + + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); + if (dataOffset >= cdOffset) { + LOGW("bad data offset %ld in zip\n", (long) dataOffset); + return false; + } + + /* check lengths */ + if ((off_t)(dataOffset + compLen) > cdOffset) { + LOGW("bad compressed length in zip (%ld + %zd > %ld)\n", + (long) dataOffset, compLen, (long) cdOffset); + return false; + } + if (method == kCompressStored && - (size_t)(dataOffset + *pUncompLen) >= zipLength) + (off_t)(dataOffset + uncompLen) > cdOffset) { - LOGE("ERROR: bad uncompressed length in zip\n"); + LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n", + (long) dataOffset, uncompLen, (long) cdOffset); return false; } - } - if (pOffset != NULL) { *pOffset = dataOffset; } + return true; } @@ -457,14 +575,14 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const */ FileMap* newMap; - long compLen; + size_t compLen; off_t offset; if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL)) return NULL; newMap = new FileMap(); - if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) { + if (!newMap->create(mFileName, mFd, offset, compLen, true)) { newMap->release(); return NULL; } @@ -480,19 +598,26 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const */ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const { - const int kSequentialMin = 32768; + const size_t kSequentialMin = 32768; bool result = false; int ent = entryToIndex(entry); if (ent < 0) return -1; - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); int method; - long uncompLen, compLen; + size_t uncompLen, compLen; off_t offset; + const unsigned char* ptr; getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); + FileMap* file = createEntryFileMap(entry); + if (file == NULL) { + goto bail; + } + + ptr = (const unsigned char*) file->getDataPtr(); + /* * Experiment with madvise hint. When we want to uncompress a file, * we pull some stuff out of the central dir entry and then hit a @@ -507,17 +632,17 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const * pair of system calls are negated by a reduction in page faults. */ if (compLen > kSequentialMin) - mFileMap->advise(FileMap::SEQUENTIAL); + file->advise(FileMap::SEQUENTIAL); if (method == kCompressStored) { - memcpy(buffer, basePtr + offset, uncompLen); + memcpy(buffer, ptr, uncompLen); } else { - if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen)) + if (!inflateBuffer(buffer, ptr, uncompLen, compLen)) goto bail; } if (compLen > kSequentialMin) - mFileMap->advise(FileMap::NORMAL); + file->advise(FileMap::NORMAL); result = true; @@ -537,29 +662,34 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const if (ent < 0) return -1; - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); int method; - long uncompLen, compLen; + size_t uncompLen, compLen; off_t offset; + const unsigned char* ptr; getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - if (method == kCompressStored) { - ssize_t actual; + const FileMap* file = createEntryFileMap(entry); + if (file == NULL) { + goto bail; + } + + ptr = (const unsigned char*) file->getDataPtr(); - actual = write(fd, basePtr + offset, uncompLen); + if (method == kCompressStored) { + ssize_t actual = write(fd, ptr, uncompLen); if (actual < 0) { LOGE("Write failed: %s\n", strerror(errno)); goto bail; - } else if (actual != uncompLen) { - LOGE("Partial write during uncompress (%d of %ld)\n", - (int)actual, uncompLen); + } else if ((size_t) actual != uncompLen) { + LOGE("Partial write during uncompress (%zd of %zd)\n", + actual, uncompLen); goto bail; } else { LOGI("+++ successful write\n"); } } else { - if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen)) + if (!inflateBuffer(fd, ptr, uncompLen, compLen)) goto bail; } @@ -573,7 +703,7 @@ bail: * Uncompress "deflate" data from one buffer to another. */ /*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf, - long uncompLen, long compLen) + size_t uncompLen, size_t compLen) { bool result = false; z_stream zstream; @@ -582,7 +712,7 @@ bail: /* * Initialize the zlib stream struct. */ - memset(&zstream, 0, sizeof(zstream)); + memset(&zstream, 0, sizeof(zstream)); zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; @@ -592,10 +722,10 @@ bail: zstream.avail_out = uncompLen; zstream.data_type = Z_UNKNOWN; - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ + /* + * Use the undocumented "negative window bits" feature to tell zlib + * that there's no zlib header waiting for it. + */ zerr = inflateInit2(&zstream, -MAX_WBITS); if (zerr != Z_OK) { if (zerr == Z_VERSION_ERROR) { @@ -619,8 +749,8 @@ bail: } /* paranoia */ - if ((long) zstream.total_out != uncompLen) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", + if (zstream.total_out != uncompLen) { + LOGW("Size mismatch on inflated file (%ld vs %zd)\n", zstream.total_out, uncompLen); goto z_bail; } @@ -638,10 +768,10 @@ bail: * Uncompress "deflate" data from one buffer to an open file descriptor. */ /*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf, - long uncompLen, long compLen) + size_t uncompLen, size_t compLen) { bool result = false; - const int kWriteBufSize = 32768; + const size_t kWriteBufSize = 32768; unsigned char writeBuf[kWriteBufSize]; z_stream zstream; int zerr; @@ -649,7 +779,7 @@ bail: /* * Initialize the zlib stream struct. */ - memset(&zstream, 0, sizeof(zstream)); + memset(&zstream, 0, sizeof(zstream)); zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; @@ -659,10 +789,10 @@ bail: zstream.avail_out = sizeof(writeBuf); zstream.data_type = Z_UNKNOWN; - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ + /* + * Use the undocumented "negative window bits" feature to tell zlib + * that there's no zlib header waiting for it. + */ zerr = inflateInit2(&zstream, -MAX_WBITS); if (zerr != Z_OK) { if (zerr == Z_VERSION_ERROR) { @@ -708,8 +838,8 @@ bail: assert(zerr == Z_STREAM_END); /* other errors should've been caught */ /* paranoia */ - if ((long) zstream.total_out != uncompLen) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", + if (zstream.total_out != uncompLen) { + LOGW("Size mismatch on inflated file (%ld vs %zd)\n", zstream.total_out, uncompLen); goto z_bail; } |