summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/audioflinger/A2dpAudioInterface.cpp224
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h50
-rw-r--r--libs/audioflinger/Android.mk82
-rw-r--r--libs/audioflinger/AudioDumpInterface.cpp382
-rw-r--r--libs/audioflinger/AudioDumpInterface.h116
-rw-r--r--libs/audioflinger/AudioFlinger.cpp3233
-rw-r--r--libs/audioflinger/AudioFlinger.h544
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.cpp161
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.h49
-rw-r--r--libs/audioflinger/AudioHardwareInterface.cpp109
-rw-r--r--libs/audioflinger/AudioHardwareStub.cpp52
-rw-r--r--libs/audioflinger/AudioHardwareStub.h37
-rw-r--r--libs/audioflinger/AudioMixer.cpp1
-rw-r--r--libs/audioflinger/AudioMixer.h3
-rw-r--r--libs/audioflinger/AudioPolicyManagerGeneric.cpp753
-rw-r--r--libs/audioflinger/AudioPolicyManagerGeneric.h189
-rw-r--r--libs/audioflinger/AudioPolicyService.cpp650
-rw-r--r--libs/audioflinger/AudioPolicyService.h198
-rw-r--r--libs/binder/Android.mk45
-rw-r--r--libs/binder/Binder.cpp (renamed from libs/utils/Binder.cpp)25
-rw-r--r--libs/binder/BpBinder.cpp (renamed from libs/utils/BpBinder.cpp)37
-rw-r--r--libs/binder/IInterface.cpp (renamed from libs/utils/IInterface.cpp)9
-rw-r--r--libs/binder/IMemory.cpp (renamed from libs/utils/IMemory.cpp)28
-rw-r--r--libs/binder/IPCThreadState.cpp (renamed from libs/utils/IPCThreadState.cpp)19
-rw-r--r--libs/binder/IPermissionController.cpp (renamed from libs/utils/IPermissionController.cpp)12
-rw-r--r--libs/binder/IServiceManager.cpp (renamed from libs/utils/IServiceManager.cpp)27
-rw-r--r--libs/binder/MemoryBase.cpp (renamed from libs/utils/MemoryBase.cpp)2
-rw-r--r--libs/binder/MemoryDealer.cpp (renamed from libs/utils/MemoryDealer.cpp)20
-rw-r--r--libs/binder/MemoryHeapBase.cpp (renamed from libs/utils/MemoryHeapBase.cpp)2
-rw-r--r--libs/binder/MemoryHeapPmem.cpp (renamed from libs/utils/MemoryHeapPmem.cpp)6
-rw-r--r--libs/binder/Parcel.cpp (renamed from libs/utils/Parcel.cpp)17
-rw-r--r--libs/binder/Permission.cpp88
-rw-r--r--libs/binder/ProcessState.cpp (renamed from libs/utils/ProcessState.cpp)12
-rw-r--r--libs/binder/Static.cpp53
-rw-r--r--libs/rs/Android.mk117
-rw-r--r--libs/rs/RenderScript.h196
-rw-r--r--libs/rs/RenderScriptEnv.h40
-rw-r--r--libs/rs/java/Android.mk1
-rw-r--r--libs/rs/java/Film/Android.mk25
-rw-r--r--libs/rs/java/Film/AndroidManifest.xml14
-rw-r--r--libs/rs/java/Film/res/raw/filmimage.c110
-rw-r--r--libs/rs/java/Film/res/raw/filmstrip.c114
-rw-r--r--libs/rs/java/Film/src/com/android/film/Film.java90
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmRS.java222
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmStripMesh.java255
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmView.java82
-rw-r--r--libs/rs/java/Fountain/Android.mk25
-rw-r--r--libs/rs/java/Fountain/AndroidManifest.xml13
-rwxr-xr-xlibs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.pngbin0 -> 104862 bytes
-rw-r--r--libs/rs/java/Fountain/res/raw/fountain.c106
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/Fountain.java90
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java112
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainView.java74
-rw-r--r--libs/rs/java/Rollo/Android.mk25
-rw-r--r--libs/rs/java/Rollo/AndroidManifest.xml13
-rw-r--r--libs/rs/java/Rollo/res/raw/browser.pngbin0 -> 5772 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/market.pngbin0 -> 4810 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/photos.pngbin0 -> 4902 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/rollo.c105
-rw-r--r--libs/rs/java/Rollo/res/raw/rollo2.c67
-rw-r--r--libs/rs/java/Rollo/res/raw/settings.pngbin0 -> 3764 bytes
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/Rollo.java90
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java90
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java251
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloView.java208
-rw-r--r--libs/rs/rs.spec449
-rw-r--r--libs/rs/rsAdapter.cpp245
-rw-r--r--libs/rs/rsAdapter.h96
-rw-r--r--libs/rs/rsAllocation.cpp477
-rw-r--r--libs/rs/rsAllocation.h96
-rw-r--r--libs/rs/rsComponent.cpp (renamed from libs/utils/executablepath_darwin.cpp)36
-rw-r--r--libs/rs/rsComponent.h71
-rw-r--r--libs/rs/rsContext.cpp378
-rw-r--r--libs/rs/rsContext.h148
-rw-r--r--libs/rs/rsDevice.cpp62
-rw-r--r--libs/rs/rsDevice.h48
-rw-r--r--libs/rs/rsElement.cpp432
-rw-r--r--libs/rs/rsElement.h96
-rw-r--r--libs/rs/rsFileA3D.cpp384
-rw-r--r--libs/rs/rsFileA3D.h122
-rw-r--r--libs/rs/rsFileA3DDecls.h44
-rw-r--r--libs/rs/rsLight.cpp134
-rw-r--r--libs/rs/rsLight.h64
-rw-r--r--libs/rs/rsLocklessFifo.cpp247
-rw-r--r--libs/rs/rsLocklessFifo.h89
-rw-r--r--libs/rs/rsMatrix.cpp159
-rw-r--r--libs/rs/rsMatrix.h87
-rw-r--r--libs/rs/rsMesh.cpp (renamed from libs/utils/executablepath_linux.cpp)38
-rw-r--r--libs/rs/rsMesh.h90
-rw-r--r--libs/rs/rsObjectBase.cpp69
-rw-r--r--libs/rs/rsObjectBase.h114
-rw-r--r--libs/rs/rsProgram.cpp48
-rw-r--r--libs/rs/rsProgram.h59
-rw-r--r--libs/rs/rsProgramFragment.cpp251
-rw-r--r--libs/rs/rsProgramFragment.h99
-rw-r--r--libs/rs/rsProgramFragmentStore.cpp272
-rw-r--r--libs/rs/rsProgramFragmentStore.h89
-rw-r--r--libs/rs/rsProgramVertex.cpp176
-rw-r--r--libs/rs/rsProgramVertex.h84
-rw-r--r--libs/rs/rsSampler.cpp157
-rw-r--r--libs/rs/rsSampler.h87
-rw-r--r--libs/rs/rsScript.cpp55
-rw-r--r--libs/rs/rsScript.h67
-rw-r--r--libs/rs/rsScriptC.cpp291
-rw-r--r--libs/rs/rsScriptC.h91
-rw-r--r--libs/rs/rsScriptC_Lib.cpp531
-rw-r--r--libs/rs/rsThreadIO.cpp52
-rw-r--r--libs/rs/rsThreadIO.h53
-rw-r--r--libs/rs/rsTriangleMesh.cpp286
-rw-r--r--libs/rs/rsTriangleMesh.h83
-rw-r--r--libs/rs/rsType.cpp222
-rw-r--r--libs/rs/rsType.h134
-rw-r--r--libs/rs/rsUtils.h128
-rw-r--r--libs/rs/rsgApi.cpp.rsg1
-rw-r--r--libs/rs/rsgApiFuncDecl.h.rsg1
-rw-r--r--libs/rs/rsgApiReplay.cpp.rsg1
-rw-r--r--libs/rs/rsgApiStructs.h.rsg1
-rw-r--r--libs/rs/rsg_generator.c291
-rw-r--r--libs/rs/spec.lex171
-rw-r--r--libs/surfaceflinger/Android.mk31
-rw-r--r--libs/surfaceflinger/BufferAllocator.cpp118
-rw-r--r--libs/surfaceflinger/BufferAllocator.h96
-rw-r--r--libs/surfaceflinger/CPUGauge.cpp171
-rw-r--r--libs/surfaceflinger/CPUGauge.h74
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp176
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h24
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp2
-rw-r--r--libs/surfaceflinger/Layer.cpp373
-rw-r--r--libs/surfaceflinger/Layer.h49
-rw-r--r--libs/surfaceflinger/LayerBase.cpp418
-rw-r--r--libs/surfaceflinger/LayerBase.h150
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp259
-rw-r--r--libs/surfaceflinger/LayerBitmap.h117
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp42
-rw-r--r--libs/surfaceflinger/LayerBlur.h2
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp343
-rw-r--r--libs/surfaceflinger/LayerBuffer.h54
-rw-r--r--libs/surfaceflinger/LayerDim.cpp155
-rw-r--r--libs/surfaceflinger/LayerDim.h14
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.cpp206
-rw-r--r--libs/surfaceflinger/MessageQueue.cpp192
-rw-r--r--libs/surfaceflinger/MessageQueue.h127
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp788
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h187
-rw-r--r--libs/surfaceflinger/Tokenizer.cpp5
-rw-r--r--libs/surfaceflinger/Transform.cpp8
-rw-r--r--libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp (renamed from libs/surfaceflinger/GPUHardware/GPUHardware.cpp)12
-rw-r--r--libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h (renamed from libs/surfaceflinger/GPUHardware/GPUHardware.h)0
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp272
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnim.h112
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp269
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h (renamed from libs/surfaceflinger/LayerOrientationAnim.h)43
-rw-r--r--libs/surfaceflinger/purgatory/OrientationAnimation.cpp (renamed from libs/surfaceflinger/OrientationAnimation.cpp)35
-rw-r--r--libs/surfaceflinger/purgatory/OrientationAnimation.h (renamed from libs/surfaceflinger/OrientationAnimation.h)3
-rw-r--r--libs/surfaceflinger/purgatory/VRamHeap.cpp (renamed from libs/surfaceflinger/VRamHeap.cpp)6
-rw-r--r--libs/surfaceflinger/purgatory/VRamHeap.h (renamed from libs/surfaceflinger/VRamHeap.h)0
-rw-r--r--libs/surfaceflinger/tests/overlays/overlays.cpp6
-rw-r--r--libs/surfaceflinger/tests/resize/Android.mk16
-rw-r--r--libs/surfaceflinger/tests/resize/resize.cpp60
-rw-r--r--libs/ui/Android.mk6
-rw-r--r--libs/ui/BufferMapper.cpp80
-rw-r--r--libs/ui/Camera.cpp4
-rw-r--r--libs/ui/EGLDisplaySurface.cpp519
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp161
-rw-r--r--libs/ui/EventHub.cpp68
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp210
-rw-r--r--libs/ui/ICamera.cpp8
-rw-r--r--libs/ui/ICameraClient.cpp6
-rw-r--r--libs/ui/ICameraService.cpp12
-rw-r--r--libs/ui/IOverlay.cpp10
-rw-r--r--libs/ui/ISurface.cpp32
-rw-r--r--libs/ui/ISurfaceComposer.cpp125
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp25
-rw-r--r--libs/ui/LayerState.cpp2
-rw-r--r--libs/ui/Overlay.cpp27
-rw-r--r--libs/ui/Region.cpp636
-rw-r--r--libs/ui/Surface.cpp746
-rw-r--r--libs/ui/SurfaceComposerClient.cpp361
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp81
-rw-r--r--libs/ui/tests/Android.mk16
-rw-r--r--libs/ui/tests/region.cpp62
-rw-r--r--libs/utils/Android.mk62
-rw-r--r--libs/utils/BackupData.cpp8
-rw-r--r--libs/utils/CallStack.cpp3
-rw-r--r--libs/utils/IDataConnection.cpp89
-rw-r--r--libs/utils/InetAddress.cpp236
-rw-r--r--libs/utils/LogSocket.cpp129
-rw-r--r--libs/utils/Pipe.cpp465
-rw-r--r--libs/utils/Socket.cpp388
-rw-r--r--libs/utils/Static.cpp31
-rw-r--r--libs/utils/StringArray.cpp113
-rw-r--r--libs/utils/TextOutput.cpp10
-rw-r--r--libs/utils/Threads.cpp290
-rw-r--r--libs/utils/TimerProbe.cpp131
-rw-r--r--libs/utils/Timers.cpp125
-rw-r--r--libs/utils/ZipEntry.cpp696
-rw-r--r--libs/utils/ZipFile.cpp1296
-rw-r--r--libs/utils/futex_synchro.c176
-rw-r--r--libs/utils/ported.cpp106
199 files changed, 20898 insertions, 9494 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 16a4f2d..6f9e934 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -29,25 +29,41 @@ namespace android {
// ----------------------------------------------------------------------------
-A2dpAudioInterface::A2dpAudioInterface() :
- mOutput(0)
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+// AudioHardwareInterface* hw = 0;
+//
+// hw = AudioHardwareInterface::create();
+// LOGD("new A2dpAudioInterface(hw: %p)", hw);
+// hw = new A2dpAudioInterface(hw);
+// return hw;
+//}
+
+A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
+ mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true)
{
}
A2dpAudioInterface::~A2dpAudioInterface()
{
- delete mOutput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ delete mHardwareInterface;
}
status_t A2dpAudioInterface::initCheck()
{
- return 0;
+ if (mHardwareInterface == 0) return NO_INIT;
+ return mHardwareInterface->initCheck();
}
AudioStreamOut* A2dpAudioInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
- LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+ if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
+ LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
+ return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ }
+
status_t err = 0;
// only one output stream allowed
@@ -59,71 +75,127 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(
// create new output stream
A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
- if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+ if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
mOutput = out;
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
} else {
delete out;
}
-
+
if (status)
*status = err;
return mOutput;
}
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput == 0 || mOutput != out) {
+ LOGW("Attempt to close invalid output stream");
+ }
+ else {
+ delete mOutput;
+ mOutput = 0;
+ }
+}
+
+
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
- status_t *status, AudioSystem::audio_in_acoustics acoustics)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
- if (status)
- *status = -1;
- return NULL;
+ return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+}
+
+void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
+{
+ return mHardwareInterface->closeInputStream(in);
+}
+
+status_t A2dpAudioInterface::setMode(int mode)
+{
+ return mHardwareInterface->setMode(mode);
}
status_t A2dpAudioInterface::setMicMute(bool state)
{
- return 0;
+ return mHardwareInterface->setMicMute(state);
}
status_t A2dpAudioInterface::getMicMute(bool* state)
{
- return 0;
+ return mHardwareInterface->getMicMute(state);
}
-status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
{
- LOGD("setParameter %s,%s\n", key, value);
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ status_t status = NO_ERROR;
+
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ mBluetoothEnabled = (value == "true");
+ if (mOutput) {
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
+ }
+ param.remove(key);
+ }
- if (!key || !value)
- return -EINVAL;
+ if (param.size()) {
+ status_t hwStatus = mHardwareInterface->setParameters(param.toString());
+ if (status == NO_ERROR) {
+ status = hwStatus;
+ }
+ }
- if (strcmp(key, "a2dp_sink_address") == 0) {
- return mOutput->setAddress(value);
+ return status;
+}
+
+String8 A2dpAudioInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter a2dpParam = AudioParameter();
+ String8 value;
+ String8 key;
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mBluetoothEnabled ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
}
- if (strcmp(key, "bluetooth_enabled") == 0) {
- mOutput->setBluetoothEnabled(strcmp(value, "true") == 0);
+
+ String8 keyValuePairs = a2dpParam.toString();
+
+ if (param.size()) {
+ keyValuePairs += ";";
+ keyValuePairs += mHardwareInterface->getParameters(param.toString());
}
- return 0;
+ LOGV("getParameters() %s", keyValuePairs.string());
+ return keyValuePairs;
}
-status_t A2dpAudioInterface::setVoiceVolume(float v)
+size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
- return 0;
+ return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
}
-status_t A2dpAudioInterface::setMasterVolume(float v)
+status_t A2dpAudioInterface::setVoiceVolume(float v)
{
- return 0;
+ return mHardwareInterface->setVoiceVolume(v);
}
-status_t A2dpAudioInterface::doRouting()
+status_t A2dpAudioInterface::setMasterVolume(float v)
{
- return 0;
+ return mHardwareInterface->setMasterVolume(v);
}
status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
{
- return 0;
+ return mHardwareInterface->dumpState(fd, args);
}
// ----------------------------------------------------------------------------
@@ -132,7 +204,7 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
// assume BT enabled to start, this is safe because its only the
// enabled->disabled transition we are worried about
- mBluetoothEnabled(true)
+ mBluetoothEnabled(true), mDevice(0)
{
// use any address by default
strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -140,27 +212,43 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
- int format, int channels, uint32_t rate)
+ uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())){
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mDevice = device;
return NO_ERROR;
}
A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
+ LOGV("A2dpAudioStreamOut destructor");
+ standby();
close();
+ LOGV("A2dpAudioStreamOut destructor returning from close()");
}
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
@@ -230,6 +318,59 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
return result;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
+
+ if (param.get(key, value) == NO_ERROR) {
+ if (value.length() != strlen("00:00:00:00:00:00")) {
+ status = BAD_VALUE;
+ } else {
+ setAddress(value.string());
+ }
+ param.remove(key);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
+ mDevice = device;
+ status = NO_ERROR;
+ } else {
+ status = BAD_VALUE;
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+
+ if (param.get(key, value) == NO_ERROR) {
+ value = mA2dpAddress;
+ param.add(key, value);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
Mutex::Autolock lock(mLock);
@@ -260,12 +401,14 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enable
status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
{
Mutex::Autolock lock(mLock);
+ LOGV("A2dpAudioStreamOut::close() calling close_l()");
return close_l();
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
{
if (mData) {
+ LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
a2dp_cleanup(mData);
mData = NULL;
}
@@ -277,5 +420,4 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<Strin
return NO_ERROR;
}
-
}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 091e775..d6709e2 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -32,38 +32,44 @@ class A2dpAudioInterface : public AudioHardwareBase
class A2dpAudioStreamOut;
public:
- A2dpAudioInterface();
+ A2dpAudioInterface(AudioHardwareInterface* hw);
virtual ~A2dpAudioInterface();
virtual status_t initCheck();
virtual status_t setVoiceVolume(float volume);
virtual status_t setMasterVolume(float volume);
+ virtual status_t setMode(int mode);
+
// mic mute
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- virtual status_t setParameter(const char *key, const char *value);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+// static AudioHardwareInterface* createA2dpInterface();
protected:
- virtual status_t doRouting();
virtual status_t dump(int fd, const Vector<String16>& args);
private:
@@ -71,19 +77,22 @@ private:
public:
A2dpAudioStreamOut();
virtual ~A2dpAudioStreamOut();
- status_t set(int format,
- int channelCount,
- uint32_t sampleRate);
+ status_t set(uint32_t device,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
// SBC codec wants a multiple of 512
virtual size_t bufferSize() const { return 512 * 20; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
friend class A2dpAudioInterface;
@@ -102,11 +111,18 @@ private:
void* mData;
Mutex mLock;
bool mBluetoothEnabled;
+ uint32_t mDevice;
};
+ friend class A2dpAudioStreamOut;
+
A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
};
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 50d516b..c10e02b 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -1,16 +1,30 @@
LOCAL_PATH:= $(call my-dir)
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
include $(CLEAR_VARS)
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ ENABLE_AUDIO_DUMP := true
+endif
+
+
LOCAL_SRC_FILES:= \
AudioHardwareGeneric.cpp \
AudioHardwareStub.cpp \
- AudioDumpInterface.cpp \
AudioHardwareInterface.cpp
+ifeq ($(ENABLE_AUDIO_DUMP),true)
+ LOCAL_SRC_FILES += AudioDumpInterface.cpp
+ LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
+endif
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
libhardware_legacy
@@ -20,8 +34,44 @@ endif
LOCAL_MODULE:= libaudiointerface
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+ LOCAL_SHARED_LIBRARIES += liba2dp
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez)
+endif
+
include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioPolicyManagerGeneric.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_MODULE:= libaudiopolicygeneric
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -29,28 +79,44 @@ LOCAL_SRC_FILES:= \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm
+ AudioResamplerCubic.cpp.arm \
+ AudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
- libhardware_legacy
+ libhardware_legacy \
+ libaudiopolicygeneric
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface
+ LOCAL_CFLAGS += -DGENERIC_AUDIO
+else
+ LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
else
- LOCAL_SHARED_LIBRARIES += libaudio
+ LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudioflinger
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
- LOCAL_SRC_FILES += A2dpAudioInterface.cpp
- LOCAL_SHARED_LIBRARIES += liba2dp
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt -lpthread
+ endif
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index b4940cb..87bb014 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "AudioFlingerDump"
+//#define LOG_NDEBUG 0
#include <stdint.h>
#include <sys/types.h>
@@ -28,68 +29,209 @@
namespace android {
-bool gFirst = true; // true if first write after a standby
-
// ----------------------------------------------------------------------------
AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+ : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8(""))
{
if(hw == 0) {
LOGE("Dump construct hw = 0");
}
mFinalInterface = hw;
- mStreamOut = 0;
+ LOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
}
AudioDumpInterface::~AudioDumpInterface()
{
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ closeOutputStream((AudioStreamOut *)mOutputs[i]);
+ }
if(mFinalInterface) delete mFinalInterface;
- if(mStreamOut) delete mStreamOut;
}
AudioStreamOut* AudioDumpInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AudioStreamOut* outFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ 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;
+ }
+ }
+ } else {
+ if (format != 0 && *format != 0) lFormat = *format;
+ if (channels != 0 && *channels != 0) lChannels = *channels;
+ if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+ if (status) *status = NO_ERROR;
+ }
+ LOGV("openOutputStream(), outFinal %p", outFinal);
+
+ AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal,
+ devices, lFormat, lChannels, lRate);
+ mOutputs.add(dumOutput);
+
+ return dumOutput;
+}
+
+void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)
+{
+ AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out;
+
+ if (mOutputs.indexOf(dumpOut) < 0) {
+ LOGW("Attempt to close invalid output stream");
+ return;
+ }
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ }
+
+ mOutputs.remove(dumpOut);
+ delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
- AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
+ AudioStreamIn* inFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+ uint32_t lRate = 8000;
+
- if(outFinal) {
- mStreamOut = new AudioStreamOutDump(outFinal);
- return mStreamOut;
+ if (mInputs.size() == 0) {
+ inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ if (inFinal == 0) return 0;
+
+ lFormat = inFinal->format();
+ lChannels = inFinal->channels();
+ lRate = inFinal->sampleRate();
} else {
- LOGE("Dump outFinal=0");
- return 0;
+ if (format != 0 && *format != 0) lFormat = *format;
+ if (channels != 0 && *channels != 0) lChannels = *channels;
+ if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+ if (status) *status = NO_ERROR;
+ }
+ LOGV("openInputStream(), inFinal %p", inFinal);
+
+ AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal,
+ devices, lFormat, lChannels, lRate);
+ mInputs.add(dumInput);
+
+ return dumInput;
+}
+void AudioDumpInterface::closeInputStream(AudioStreamIn* in)
+{
+ AudioStreamInDump *dumpIn = (AudioStreamInDump *)in;
+
+ if (mInputs.indexOf(dumpIn) < 0) {
+ LOGW("Attempt to close invalid input stream");
+ return;
+ }
+ dumpIn->standby();
+ if (dumpIn->finalStream() != NULL) {
+ mFinalInterface->closeInputStream(dumpIn->finalStream());
}
+
+ mInputs.remove(dumpIn);
+ delete dumpIn;
}
+
+status_t AudioDumpInterface::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ LOGV("setParameters %s", keyValuePairs.string());
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ mFileName = value;
+ return NO_ERROR;
+ }
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ param.remove(String8("test_cmd_policy"));
+ mPolicyCommands = param.toString();
+ LOGV("test_cmd_policy command %s written", mPolicyCommands.string());
+ return NO_ERROR;
+ }
+
+ if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioDumpInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+
+// LOGV("getParameters %s", keys.string());
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ return mFileName;
+ }
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+// LOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ return mPolicyCommands;
+ }
+
+ if (mFinalInterface != 0 ) return mFinalInterface->getParameters(keys);
+ return String8("");
+}
+
+
// ----------------------------------------------------------------------------
-AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ 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)
{
- mFinalStream = finalStream;
- mOutFile = 0;
+ LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
}
AudioStreamOutDump::~AudioStreamOutDump()
{
Close();
- delete mFinalStream;
}
ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
{
ssize_t ret;
- ret = mFinalStream->write(buffer, bytes);
- if(!mOutFile && gFirst) {
- gFirst = false;
- // check if dump file exist
- mOutFile = fopen(FLINGER_DUMP_NAME, "r");
- if(mOutFile) {
- fclose(mOutFile);
- mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ if (mFinalStream) {
+ ret = mFinalStream->write(buffer, bytes);
+ } else {
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+ ret = bytes;
+ }
+ if(!mOutFile) {
+ 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);
}
}
if (mOutFile) {
@@ -100,13 +242,65 @@ ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
status_t AudioStreamOutDump::standby()
{
+ LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream);
+
Close();
- gFirst = true;
- return mFinalStream->standby();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamOutDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->latency();
+ return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+ return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamOutDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ String8 result = String8("");
+ if (mFinalStream != 0 ) result = mFinalStream->getParameters(keys);
+ return result;
}
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
-void AudioStreamOutDump::Close(void)
+void AudioStreamOutDump::Close()
{
if(mOutFile) {
fclose(mOutFile);
@@ -114,4 +308,140 @@ void AudioStreamOutDump::Close(void)
}
}
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mInFile(0)
+{
+ LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+ Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+ if (mFinalStream) {
+ return mFinalStream->read(buffer, bytes);
+ }
+
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+
+ if(!mInFile) {
+ 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");
+ mInFile = fopen(name, "rb");
+ LOGV("Opening dump file %s, fh %p", name, mInFile);
+ if (mInFile) {
+ fseek(mInFile, 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);
+ }
+ }
+ return bytes;
+}
+
+status_t AudioStreamInDump::standby()
+{
+ LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamInDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+ String8 result = String8("");
+ if (mFinalStream != 0 ) result = mFinalStream->getParameters(keys);
+ return result;
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+ if(mInFile) {
+ fclose(mInFile);
+ mInFile = 0;
+ }
+}
}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index b72c94e..4de4a16 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -20,35 +20,94 @@
#include <stdint.h>
#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
#include <hardware_legacy/AudioHardwareBase.h>
namespace android {
-#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
class AudioStreamOutDump : public AudioStreamOut {
public:
- AudioStreamOutDump( AudioStreamOut* FinalStream);
+ AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
~AudioStreamOutDump();
- virtual ssize_t write(const void* buffer, size_t bytes);
-
- virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); }
- virtual size_t bufferSize() const { return mFinalStream->bufferSize(); }
- virtual int channelCount() const { return mFinalStream->channelCount(); }
- virtual int format() const { return mFinalStream->format(); }
- virtual uint32_t latency() const { return mFinalStream->latency(); }
- virtual status_t setVolume(float volume)
- { return mFinalStream->setVolume(volume); }
+
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+ virtual uint32_t latency() const;
+ virtual status_t setVolume(float left, float right);
virtual status_t standby();
- virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
void Close(void);
+ AudioStreamOut* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
AudioStreamOut *mFinalStream;
- FILE *mOutFile; // output file
+ FILE *mOutFile; // output file
+ int mFileCount;
};
+class AudioStreamInDump : public AudioStreamIn {
+public:
+ AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamInDump();
+
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+
+ virtual status_t setGain(float gain);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamIn* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamIn *mFinalStream;
+ FILE *mInFile; // output file
+};
class AudioDumpInterface : public AudioHardwareBase
{
@@ -56,10 +115,13 @@ class AudioDumpInterface : public AudioHardwareBase
public:
AudioDumpInterface(AudioHardwareInterface* hw);
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
virtual ~AudioDumpInterface();
virtual status_t initCheck()
@@ -75,21 +137,25 @@ public:
virtual status_t getMicMute(bool* state)
{return mFinalInterface->getMicMute(state);}
- virtual status_t setParameter(const char* key, const char* value)
- {return mFinalInterface->setParameter(key, value);}
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
- virtual AudioStreamIn* openInputStream(int inputSource, int format, int channelCount,
- uint32_t sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
- { return mFinalInterface->openInputStream(inputSource, format, channelCount, sampleRate, status, acoustics); }
+ 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);
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+ String8 fileName() const { return mFileName; }
protected:
- virtual status_t doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
-
- AudioHardwareInterface *mFinalInterface;
- AudioStreamOutDump *mStreamOut;
+ AudioHardwareInterface *mFinalInterface;
+ SortedVector<AudioStreamOutDump *> mOutputs;
+ bool mFirstHwOutput;
+ SortedVector<AudioStreamInDump *> mInputs;
+ Mutex mLock;
+ String8 mPolicyCommands;
+ String8 mFileName;
};
}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index f5bdeda..1336131 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -24,10 +24,10 @@
#include <sys/time.h>
#include <sys/resource.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/threads.h>
@@ -71,15 +71,9 @@ static const float MAX_GAIN = 4096.0f;
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
-static const int kStartSleepTime = 30000;
-static const int kStopSleepTime = 30000;
-
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 20000;
-// Maximum number of pending buffers allocated by OutputTrack::write()
-static const uint8_t kMaxOutputTrackBuffers = 5;
-
#define AUDIOFLINGER_SECURITY_ENABLED 1
@@ -121,131 +115,32 @@ static bool settingsAllowed() {
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
- mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
- mRouteRestoreTime(0), mMusicMuteSaved(false)
+ mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false)
{
mHardwareStatus = AUDIO_HW_IDLE;
+
mAudioHardware = AudioHardwareInterface::create();
+
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
- mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status_t status;
- AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mHardwareStatus = AUDIO_HW_IDLE;
- if (hwOutput) {
- mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
- } else {
- LOGE("Failed to initialize hardware output stream, status: %d", status);
- }
-
-#ifdef WITH_A2DP
- // Create A2DP interface
- mA2dpAudioInterface = new A2dpAudioInterface();
- AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- if (a2dpOutput) {
- mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
- if (hwOutput) {
- uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
- MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
- hwOutput->sampleRate(),
- AudioSystem::PCM_16_BIT,
- hwOutput->channelCount(),
- frameCount);
- mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
- }
- } else {
- LOGE("Failed to initialize A2DP output stream, status: %d", status);
- }
-#endif
-
- // FIXME - this should come from settings
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+
setMode(AudioSystem::MODE_NORMAL);
setMasterVolume(1.0f);
setMasterMute(false);
-
- // Start record thread
- mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
- }
- } else {
+ } else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
}
AudioFlinger::~AudioFlinger()
{
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->exit();
- mAudioRecordThread.clear();
- }
- mHardwareMixerThread.clear();
- delete mAudioHardware;
- // deleting mA2dpAudioInterface also deletes mA2dpOutput;
-#ifdef WITH_A2DP
- mA2dpMixerThread.clear();
- delete mA2dpAudioInterface;
-#endif
+ mRecordThreads.clear();
+ mPlaybackThreads.clear();
}
-#ifdef WITH_A2DP
-// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::setA2dpEnabled_l(bool enable)
-{
- SortedVector < sp<MixerThread::Track> > tracks;
- SortedVector < wp<MixerThread::Track> > activeTracks;
-
- LOGV_IF(enable, "set output to A2DP\n");
- LOGV_IF(!enable, "set output to hardware audio\n");
-
- // Transfer tracks playing on MUSIC stream from one mixer to the other
- if (enable) {
- mHardwareMixerThread->getTracks_l(tracks, activeTracks);
- mA2dpMixerThread->putTracks_l(tracks, activeTracks);
- } else {
- mA2dpMixerThread->getTracks_l(tracks, activeTracks);
- mHardwareMixerThread->putTracks_l(tracks, activeTracks);
- }
- mA2dpEnabled = enable;
- mNotifyA2dpChange = true;
- mWaitWorkCV.broadcast();
-}
-
-// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::checkA2dpEnabledChange_l()
-{
- if (mNotifyA2dpChange) {
- // Notify AudioSystem of the A2DP activation/deactivation
- size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
- if (binder != NULL) {
- LOGV("Notifying output change to client %p", binder.get());
- sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
- client->a2dpEnabledChanged(mA2dpEnabled);
- }
- }
- mNotifyA2dpChange = false;
- }
-}
-#endif // WITH_A2DP
-
-bool AudioFlinger::streamForcedToSpeaker(int streamType)
-{
- // NOTE that streams listed here must not be routed to A2DP by default:
- // AudioSystem::routedToA2dpOutput(streamType) == false
- return (streamType == AudioSystem::RING ||
- streamType == AudioSystem::ALARM ||
- streamType == AudioSystem::NOTIFICATION ||
- streamType == AudioSystem::ENFORCED_AUDIBLE);
-}
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
@@ -275,10 +170,7 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
char buffer[SIZE];
String8 result;
int hardwareStatus = mHardwareStatus;
-
- if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
- hardwareStatus = AUDIO_HW_STANDBY;
- }
+
snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
write(fd, result.string(), result.size());
@@ -336,13 +228,16 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
dumpClients(fd, args);
dumpInternals(fd, args);
- mHardwareMixerThread->dump(fd, args);
-#ifdef WITH_A2DP
- mA2dpMixerThread->dump(fd, args);
-#endif
- // dump record client
- if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+ // dump playback threads
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads[i]->dump(fd, args);
+ }
+
+ // dump record threads
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads[i]->dump(fd, args);
+ }
if (mAudioHardware) {
mAudioHardware->dumpState(fd, args);
@@ -352,6 +247,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+
// IAudioFlinger interface
@@ -364,9 +260,10 @@ sp<IAudioTrack> AudioFlinger::createTrack(
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ void *output,
status_t *status)
{
- sp<MixerThread::Track> track;
+ sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
@@ -380,6 +277,12 @@ sp<IAudioTrack> AudioFlinger::createTrack(
{
Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGE("unknown output thread");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
wclient = mClients.valueFor(pid);
@@ -389,16 +292,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(
client = new Client(this, pid);
mClients.add(pid, client);
}
-#ifdef WITH_A2DP
- if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
- track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- } else
-#endif
- {
- track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- }
+ track = thread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
}
if (lStatus == NO_ERROR) {
trackHandle = new TrackHandle(track);
@@ -413,54 +308,59 @@ Exit:
return trackHandle;
}
-uint32_t AudioFlinger::sampleRate(int output) const
+uint32_t AudioFlinger::sampleRate(void *output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->sampleRate();
- }
-#endif
- return mHardwareMixerThread->sampleRate();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("sampleRate() unknown thread %p", output);
+ return 0;
+ }
+ return thread->sampleRate();
}
-int AudioFlinger::channelCount(int output) const
+int AudioFlinger::channelCount(void *output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->channelCount();
- }
-#endif
- return mHardwareMixerThread->channelCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("channelCount() unknown thread %p", output);
+ return 0;
+ }
+ return thread->channelCount();
}
-int AudioFlinger::format(int output) const
+int AudioFlinger::format(void *output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->format();
- }
-#endif
- return mHardwareMixerThread->format();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("format() unknown thread %p", output);
+ return 0;
+ }
+ return thread->format();
}
-size_t AudioFlinger::frameCount(int output) const
+size_t AudioFlinger::frameCount(void *output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->frameCount();
- }
-#endif
- return mHardwareMixerThread->frameCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("frameCount() unknown thread %p", output);
+ return 0;
+ }
+ return thread->frameCount();
}
-uint32_t AudioFlinger::latency(int output) const
+uint32_t AudioFlinger::latency(void *output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->latency();
- }
-#endif
- return mHardwareMixerThread->latency();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("latency() unknown thread %p", output);
+ return 0;
+ }
+ return thread->latency();
}
status_t AudioFlinger::setMasterVolume(float value)
@@ -477,94 +377,12 @@ status_t AudioFlinger::setMasterVolume(float value)
value = 1.0f;
}
mHardwareStatus = AUDIO_HW_IDLE;
- mHardwareMixerThread->setMasterVolume(value);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterVolume(value);
-#endif
-
- return NO_ERROR;
-}
-
-status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- status_t err = NO_ERROR;
-
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
- LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
- return BAD_VALUE;
- }
-
-#ifdef WITH_A2DP
- LOGV("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(),
- IPCThreadState::self()->getCallingPid());
- if (mode == AudioSystem::MODE_NORMAL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
- AutoMutex lock(&mLock);
-
- bool enableA2dp = false;
- if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
- enableA2dp = true;
- }
- if (mA2dpDisableCount > 0) {
- mA2dpSuppressed = enableA2dp;
- } else {
- setA2dpEnabled_l(enableA2dp);
- }
- LOGV("setOutput done\n");
- }
- // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when
- // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only
- // in this case to avoid doing it several times.
- if (mode == AudioSystem::MODE_IN_CALL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) {
- AutoMutex lock(&mLock);
- handleRouteDisablesA2dp_l(routes);
- }
-#endif
- // do nothing if only A2DP routing is affected
- mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
- if (mask) {
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- uint32_t r;
- err = mAudioHardware->getRouting(mode, &r);
- if (err == NO_ERROR) {
- r = (r & ~mask) | (routes & mask);
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- mSavedRoute = r;
- r |= mForcedRoute;
- LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
- }
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- err = mAudioHardware->setRouting(mode, r);
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- return err;
-}
+ mMasterVolume = value;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads[i]->setMasterVolume(value);
-uint32_t AudioFlinger::getRouting(int mode) const
-{
- uint32_t routes = 0;
- if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- routes = mSavedRoute;
- } else {
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- mAudioHardware->getRouting(mode, &routes);
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- } else {
- LOGW("Illegal value: getRouting(%d)", mode);
- }
- return routes;
+ return NO_ERROR;
}
status_t AudioFlinger::setMode(int mode)
@@ -585,15 +403,6 @@ status_t AudioFlinger::setMode(int mode)
return ret;
}
-int AudioFlinger::getMode() const
-{
- int mode = AudioSystem::MODE_INVALID;
- mHardwareStatus = AUDIO_HW_SET_MODE;
- mAudioHardware->getMode(&mode);
- mHardwareStatus = AUDIO_HW_IDLE;
- return mode;
-}
-
status_t AudioFlinger::setMicMute(bool state)
{
// check calling permissions
@@ -623,36 +432,46 @@ status_t AudioFlinger::setMasterMute(bool muted)
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- mHardwareMixerThread->setMasterMute(muted);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterMute(muted);
-#endif
+
+ mMasterMute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads[i]->setMasterMute(muted);
+
return NO_ERROR;
}
float AudioFlinger::masterVolume() const
{
- return mHardwareMixerThread->masterVolume();
+ return mMasterVolume;
}
bool AudioFlinger::masterMute() const
{
- return mHardwareMixerThread->masterMute();
+ return mMasterMute;
}
-status_t AudioFlinger::setStreamVolume(int stream, float value)
+status_t AudioFlinger::setStreamVolume(int stream, float value, void *output)
{
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
- uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
+ PlaybackThread *thread = NULL;
+ if (output) {
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+ }
+
status_t ret = NO_ERROR;
+
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float hwValue;
@@ -669,12 +488,18 @@ status_t AudioFlinger::setStreamVolume(int stream, float value)
mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
ret = mAudioHardware->setVoiceVolume(hwValue);
mHardwareStatus = AUDIO_HW_IDLE;
+
}
- mHardwareMixerThread->setStreamVolume(stream, value);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setStreamVolume(stream, value);
-#endif
+ mStreamTypes[stream].volume = value;
+
+ if (thread == NULL) {
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads[i]->setStreamVolume(stream, value);
+
+ } else {
+ thread->setStreamVolume(stream, value);
+ }
return ret;
}
@@ -686,82 +511,116 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted)
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
return BAD_VALUE;
}
-#ifdef WITH_A2DP
- mA2dpMixerThread->setStreamMute(stream, muted);
-#endif
- if (stream == AudioSystem::MUSIC)
- {
- AutoMutex lock(&mHardwareLock);
- if (mForcedRoute != 0)
- mMusicMuteSaved = muted;
- else
- mHardwareMixerThread->setStreamMute(stream, muted);
- } else {
- mHardwareMixerThread->setStreamMute(stream, muted);
- }
+ mStreamTypes[stream].mute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads[i]->setStreamMute(stream, muted);
return NO_ERROR;
}
-float AudioFlinger::streamVolume(int stream) const
+float AudioFlinger::streamVolume(int stream, void *output) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return 0.0f;
}
-
- float volume = mHardwareMixerThread->streamVolume(stream);
+
+ AutoMutex lock(mLock);
+ float volume;
+ if (output) {
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return 0.0f;
+ }
+ volume = thread->streamVolume(stream);
+ } else {
+ volume = mStreamTypes[stream].volume;
+ }
+
// remove correction applied by setStreamVolume()
if (stream == AudioSystem::VOICE_CALL) {
volume = (volume - 0.01) / 0.99 ;
}
-
+
return volume;
}
bool AudioFlinger::streamMute(int stream) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || stream >= (int)AudioSystem::NUM_STREAM_TYPES) {
return true;
}
-
- if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
- {
- return mMusicMuteSaved;
- }
- return mHardwareMixerThread->streamMute(stream);
+
+ return mStreamTypes[stream].mute;
}
bool AudioFlinger::isMusicActive() const
{
Mutex::Autolock _l(mLock);
- #ifdef WITH_A2DP
- if (isA2dpEnabled()) {
- return mA2dpMixerThread->isMusicActive_l();
- }
- #endif
- return mHardwareMixerThread->isMusicActive_l();
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads[i]->isMusicActive()) {
+ return true;
+ }
+ }
+ return false;
}
-status_t AudioFlinger::setParameter(const char* key, const char* value)
+status_t AudioFlinger::setParameters(void *ioHandle, const String8& keyValuePairs)
{
- status_t result, result2;
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_SET_PARAMETER;
-
- LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
- result = mAudioHardware->setParameter(key, value);
- if (mA2dpAudioInterface) {
- result2 = mA2dpAudioInterface->setParameter(key, value);
- if (result2)
- result = result2;
+ status_t result;
+
+ LOGV("setParameters(): io %p, keyvalue %s, tid %d, calling tid %d",
+ ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
}
- mHardwareStatus = AUDIO_HW_IDLE;
- return result;
+
+ // ioHandle == 0 means the parameters are global to the audio hardware interface
+ if (ioHandle == 0) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+ result = mAudioHardware->setParameters(keyValuePairs);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+ }
+
+ // Check if parameters are for an output
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->setParameters(keyValuePairs);
+ }
+
+ // Check if parameters are for an input
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->setParameters(keyValuePairs);
+ }
+
+ return BAD_VALUE;
+}
+
+String8 AudioFlinger::getParameters(void *ioHandle, const String8& keys)
+{
+// LOGV("getParameters() io %p, keys %s, tid %d, calling tid %d",
+// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
+
+ if (ioHandle == 0) {
+ return mAudioHardware->getParameters(keys);
+ }
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->getParameters(keys);
+ }
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->getParameters(keys);
+ }
+ return String8("");
}
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
@@ -771,7 +630,7 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha
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);
@@ -780,12 +639,21 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
LOGV("Adding notification client %p", binder.get());
binder->linkToDeath(this);
mNotificationClients.add(binder);
- client->a2dpEnabledChanged(isA2dpEnabled());
+ }
+
+ // 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[i]->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+ }
+
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads[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());
Mutex::Autolock _l(mLock);
@@ -800,6 +668,17 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) {
}
}
+void AudioFlinger::audioConfigChanged(int event, void *param1, void *param2) {
+ Mutex::Autolock _l(mLock);
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i);
+ LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->ioConfigChanged(event, param1, param2);
+ }
+}
+
void AudioFlinger::removeClient(pid_t pid)
{
LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
@@ -807,147 +686,139 @@ void AudioFlinger::removeClient(pid_t pid)
mClients.removeItem(pid);
}
-bool AudioFlinger::isA2dpEnabled() const
+// ----------------------------------------------------------------------------
+
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger)
+ : Thread(false),
+ mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
+ mFormat(0), mFrameSize(1), mNewParameters(String8("")), mStandby(false)
{
- return mA2dpEnabled;
}
-void AudioFlinger::handleForcedSpeakerRoute(int command)
+AudioFlinger::ThreadBase::~ThreadBase()
{
- switch(command) {
- case ACTIVE_TRACK_ADDED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount++ == 0) {
- if (mForcedRoute == 0) {
- mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
- LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
- usleep(mHardwareMixerThread->latency()*1000);
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareStatus = AUDIO_HW_IDLE;
- // delay track start so that audio hardware has time to siwtch routes
- usleep(kStartSleepTime);
- }
- }
- mForcedRoute = AudioSystem::ROUTE_SPEAKER;
- mRouteRestoreTime = 0;
- }
- LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
- }
- break;
- case ACTIVE_TRACK_REMOVED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount > 0){
- if (--mForcedSpeakerCount == 0) {
- mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
- }
- LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
- } else {
- LOGE("mForcedSpeakerCount is already zero");
- }
- }
- break;
- case CHECK_ROUTE_RESTORE_TIME:
- case FORCE_ROUTE_RESTORE:
- if (mRouteRestoreTime) {
- AutoMutex lock(mHardwareLock);
- if (mRouteRestoreTime &&
- (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
- mForcedRoute = 0;
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
- mHardwareStatus = AUDIO_HW_IDLE;
- LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
- }
- mRouteRestoreTime = 0;
- }
- }
- break;
- }
}
-#ifdef WITH_A2DP
-// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::handleRouteDisablesA2dp_l(int routes)
-{
- if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) {
- if (mA2dpDisableCount++ == 0) {
- if (mA2dpEnabled) {
- setA2dpEnabled_l(false);
- mA2dpSuppressed = true;
- }
- }
- LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
- } else {
- if (mA2dpDisableCount > 0) {
- if (--mA2dpDisableCount == 0) {
- if (mA2dpSuppressed) {
- setA2dpEnabled_l(true);
- mA2dpSuppressed = false;
- }
- }
- LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
- } else {
- LOGV("mA2dpDisableCount is already zero");
- }
+void AudioFlinger::ThreadBase::exit()
+{
+ // keep a strong ref on ourself so that we want get
+ // destroyed in the middle of requestExitAndWait()
+ sp <ThreadBase> strongMe = this;
+
+ LOGV("ThreadBase::exit");
+ {
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
}
+ requestExitAndWait();
}
-#endif
-// ----------------------------------------------------------------------------
+uint32_t AudioFlinger::ThreadBase::sampleRate() const
+{
+ return mSampleRate;
+}
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
- : Thread(false),
- mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false)
+int AudioFlinger::ThreadBase::channelCount() const
{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
+ return mChannelCount;
+}
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
+int AudioFlinger::ThreadBase::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::ThreadBase::frameCount() const
+{
+ return mFrameCount;
+}
+
+status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
+{
+ status_t result;
+
+ Mutex::Autolock _l(mLock);
+ mNewParameters = keyValuePairs;
+
+ mWaitWorkCV.signal();
+ mParamCond.wait(mLock);
+
+ return mParamStatus;
+}
+
+void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
+{
+ Mutex::Autolock _l(mLock);
+ ConfigEvent *configEvent = new ConfigEvent();
+ configEvent->mEvent = event;
+ configEvent->mParam = param;
+ mConfigEvents.add(configEvent);
+ LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
+ mWaitWorkCV.signal();
+}
+
+void AudioFlinger::ThreadBase::processConfigEvents()
+{
+ mLock.lock();
+ while(!mConfigEvents.isEmpty()) {
+ LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
+ ConfigEvent *configEvent = mConfigEvents[0];
+ mConfigEvents.removeAt(0);
+ // release mLock because audioConfigChanged() will call
+ // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating
+ // potential cross deadlock between AudioFlinger::mLock and mLock
+ mLock.unlock();
+ audioConfigChanged(configEvent->mEvent, configEvent->mParam);
+ delete configEvent;
+ mLock.lock();
}
+ mLock.unlock();
+}
- mFormat = output->format();
- mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
- mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[mFrameCount * 2];
- memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+// ----------------------------------------------------------------------------
+
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : ThreadBase(audioFlinger),
+ mMixBuffer(0), mSuspended(false), mBytesWritten(0), mOutput(output),
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
+{
+ readOutputParameters();
+
+ mMasterVolume = mAudioFlinger->masterVolume();
+ mMasterMute = mAudioFlinger->masterMute();
+
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ 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::MixerThread::~MixerThread()
+AudioFlinger::PlaybackThread::~PlaybackThread()
{
delete [] mMixBuffer;
- delete mAudioMixer;
+ if (mType != DUPLICATING) {
+ mAudioFlinger->mAudioHardware->closeOutputStream(mOutput);
+ }
}
-status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
{
dumpInternals(fd, args);
dumpTracks(fd, args);
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mTracks.size(); ++i) {
@@ -958,7 +829,7 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a
}
}
- snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mActiveTracks.size(); ++i) {
@@ -975,15 +846,13 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
- result.append(buffer);
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ snprintf(buffer, SIZE, "Output thread %p internals\n", this);
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -1000,238 +869,354 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
}
// Thread virtuals
+status_t AudioFlinger::PlaybackThread::readyToRun()
+{
+ if (mSampleRate == 0) {
+ LOGE("No working audio driver found.");
+ return NO_INIT;
+ }
+ LOGI("AudioFlinger's thread %p ready to run", this);
+ return NO_ERROR;
+}
+
+void AudioFlinger::PlaybackThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Playback Thread %p", this);
+
+ run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
+ const sp<AudioFlinger::Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
+{
+ sp<Track> track;
+ status_t lStatus;
+
+ if (mType == DIRECT) {
+ if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) {
+ LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p",
+ sampleRate, format, channelCount, mOutput);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ } else {
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > mSampleRate*2) {
+ LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ }
+
+ if (mOutput == 0) {
+ LOGE("Audio driver not initialized.");
+ lStatus = NO_INIT;
+ goto Exit;
+ }
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+ mTracks.add(track);
+ }
+ lStatus = NO_ERROR;
+
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
+ return track;
+}
+
+uint32_t AudioFlinger::PlaybackThread::latency() const
+{
+ if (mOutput) {
+ return mOutput->latency();
+ }
+ else {
+ return 0;
+ }
+}
+
+status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
+{
+ mMasterVolume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
+{
+ mMasterMute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::PlaybackThread::masterVolume() const
+{
+ return mMasterVolume;
+}
+
+bool AudioFlinger::PlaybackThread::masterMute() const
+{
+ return mMasterMute;
+}
+
+status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value)
+{
+ mStreamTypes[stream].volume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted)
+{
+ mStreamTypes[stream].mute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::PlaybackThread::streamVolume(int stream) const
+{
+ return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::PlaybackThread::streamMute(int stream) const
+{
+ return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::PlaybackThread::isMusicActive() const
+{
+ Mutex::Autolock _l(mLock);
+ size_t count = mActiveTracks.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t == 0) continue;
+ Track* const track = t.get();
+ if (t->type() == AudioSystem::MUSIC)
+ return true;
+ }
+ return false;
+}
+
+// addTrack_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
+{
+ status_t status = ALREADY_EXISTS;
+
+ // here the track could be either new, or restarted
+ // in both cases "unstop" the track
+ if (track->isPaused()) {
+ track->mState = TrackBase::RESUMING;
+ LOGV("PAUSED => RESUMING (%d)", track->name());
+ } else {
+ track->mState = TrackBase::ACTIVE;
+ LOGV("? => ACTIVE (%d)", track->name());
+ }
+ // set retry count for buffer fill
+ track->mRetryCount = kMaxTrackStartupRetries;
+ if (mActiveTracks.indexOf(track) < 0) {
+ // the track is newly added, make sure it fills up all its
+ // buffers before playing. This is to ensure the client will
+ // effectively get the latency it requested.
+ track->mFillingUpStatus = Track::FS_FILLING;
+ track->mResetDone = false;
+ mActiveTracks.add(track);
+ status = NO_ERROR;
+ }
+
+ LOGV("mWaitWorkCV.broadcast");
+ mWaitWorkCV.broadcast();
+
+ return status;
+}
+
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track)
+{
+ track->mState = TrackBase::TERMINATED;
+ if (mActiveTracks.indexOf(track) < 0) {
+ LOGV("remove track (%d) and delete from mixer", track->name());
+ mTracks.remove(track);
+ deleteTrackName_l(track->name());
+ }
+}
+
+String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
+{
+ return mOutput->getParameters(keys);
+}
+
+void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
+ AudioSystem::OutputDescriptor desc;
+ void *param2 = 0;
+
+ LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param);
+
+ switch (event) {
+ case AudioSystem::OUTPUT_OPENED:
+ case AudioSystem::OUTPUT_CONFIG_CHANGED:
+ desc.channels = mChannelCount;
+ desc.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = latency();
+ param2 = &desc;
+ break;
+
+ case AudioSystem::STREAM_CONFIG_CHANGED:
+ param2 = &param;
+ case AudioSystem::OUTPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::PlaybackThread::readOutputParameters()
+{
+ mSampleRate = mOutput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mOutput->channels());
+
+ mFormat = mOutput->format();
+ mFrameSize = mOutput->frameSize();
+ mFrameCount = mOutput->bufferSize() / mFrameSize;
+
+ mMinBytesToWrite = (mOutput->latency() * mSampleRate * mFrameSize) / 1000;
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ if (mMixBuffer != NULL) delete mMixBuffer;
+ mMixBuffer = new int16_t[mFrameCount * 2];
+ memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mAudioMixer(0)
+{
+ mType = PlaybackThread::MIXER;
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
+ }
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+ delete mAudioMixer;
+}
+
bool AudioFlinger::MixerThread::threadLoop()
{
unsigned long sleepTime = kBufferRecoveryInUsecs;
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
size_t enabledTracks = 0;
- nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount * mFrameSize;
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-#ifdef WITH_A2DP
- bool outputTrackActive = false;
-#endif
+ while (!exitPending())
+ {
+ processConfigEvents();
- do {
enabledTracks = 0;
- { // scope for the AudioFlinger::mLock
-
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ { // scope for mLock
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount * mFrameSize;
+ maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
}
- mAudioFlinger->checkA2dpEnabledChange_l();
-#endif
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
// put audio hardware into standby after short delay
- if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
- // wait until we have something to do...
- LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
mOutput->standby();
mStandby = true;
+ mBytesWritten = 0;
}
-
-#ifdef WITH_A2DP
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
-#endif
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
- }
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
- LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
-
- if (mMasterMute == false) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.audio.silent", value, "0");
- if (atoi(value)) {
- LOGD("Silence is golden");
- setMasterMute(true);
- }
- }
-
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- continue;
- }
- // Forced route to speaker is handled by hardware mixer thread
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
- }
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
- // find out which tracks need to be processed
- size_t count = activeTracks.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<Track> t = activeTracks[i].promote();
- if (t == 0) continue;
+ if (exitPending()) break;
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
+ // wait until we have something to do...
+ LOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("MixerThread %p TID %d waking up\n", this, gettid());
- // The first time a track is added we wait
- // for all its buffers to be filled before processing it
- mAudioMixer->setActiveTrack(track->name());
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
- !track->isPaused())
- {
- //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
-
- // compute volume for this track
- int16_t left, right;
- if (track->isMuted() || mMasterMute || track->isPausing()) {
- left = right = 0;
- if (track->isPausing()) {
- LOGV("paused(%d)", track->name());
- track->setPaused();
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
}
- } else {
- float typeVolume = mStreamTypes[track->type()].volume;
- float v = mMasterVolume * typeVolume;
- float v_clamped = v * cblk->volume[0];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = int16_t(v_clamped);
- v_clamped = v * cblk->volume[1];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = int16_t(v_clamped);
}
- // XXX: these things DON'T need to be done each time
- mAudioMixer->setBufferProvider(track);
- mAudioMixer->enable(AudioMixer::MIXING);
-
- int param;
- if ( track->mFillingUpStatus == Track::FS_FILLED) {
- // no ramp for the first volume setting
- track->mFillingUpStatus = Track::FS_ACTIVE;
- if (track->mState == TrackBase::RESUMING) {
- track->mState = TrackBase::ACTIVE;
- param = AudioMixer::RAMP_VOLUME;
- } else {
- param = AudioMixer::VOLUME;
- }
- } else {
- param = AudioMixer::RAMP_VOLUME;
- }
- mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
- mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::FORMAT, track->format());
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::CHANNEL_COUNT, track->channelCount());
- mAudioMixer->setParameter(
- AudioMixer::RESAMPLE,
- AudioMixer::SAMPLE_RATE,
- int(cblk->sampleRate));
-
- // reset retry count
- track->mRetryCount = kMaxTrackRetries;
- enabledTracks++;
- } else {
- //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
- if (track->isStopped()) {
- track->reset();
- }
- if (track->isTerminated() || track->isStopped() || track->isPaused()) {
- // We have consumed all the buffers of this track.
- // Remove it from the list of active tracks.
- LOGV("remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- } else {
- // No buffers for this track. Give it a few chances to
- // fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- }
- }
- // LOGV("disable(%d)", track->name());
- mAudioMixer->disable(AudioMixer::MIXING);
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
}
}
- // remove all the tracks that need to be...
- count = tracksToRemove.size();
- if (UNLIKELY(count)) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<Track>& track = tracksToRemove[i];
- removeActiveTrack_l(track);
- if (track->isTerminated()) {
- mTracks.remove(track);
- deleteTrackName_l(track->mName);
- }
- }
- }
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
}
-
+
if (LIKELY(enabledTracks)) {
// mix buffers...
mAudioMixer->process(curBuf);
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (!outputTrackActive) {
- LOGV("starting output track in mixer for output %d", mOutputType);
- mOutputTrack->start();
- outputTrackActive = true;
- }
- mOutputTrack->write(curBuf, mFrameCount);
- }
-#endif
-
// output audio to hardware
- mLastWriteTime = systemTime();
- mInWrite = true;
- mOutput->write(curBuf, mixBufferSize);
- mNumWrites++;
- mInWrite = false;
- mStandby = false;
- nsecs_t temp = systemTime();
- standbyTime = temp + kStandbyTimeInNsecs;
- nsecs_t delta = temp - mLastWriteTime;
- if (delta > maxPeriod) {
- LOGW("write blocked for %llu msecs", ns2ms(delta));
- mNumDelayedWrites++;
- }
- sleepTime = kBufferRecoveryInUsecs;
- } else {
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mOutputTrack->write(curBuf, 0);
- if (mOutputTrack->bufferQueueEmpty()) {
- mOutputTrack->stop();
- outputTrackActive = false;
- } else {
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- }
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+ if (bytesWritten > 0) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
}
+ sleepTime = kBufferRecoveryInUsecs;
}
-#endif
+ } else {
// There was nothing to mix this round, which means all
// active tracks were late. Sleep a little bit to give
// them another chance. If we're too late, the audio
// hardware will zero-fill for us.
- //LOGV("no buffers - usleep(%lu)", sleepTime);
+ // LOGV("thread %p no buffers - usleep(%lu)", this, sleepTime);
usleep(sleepTime);
if (sleepTime < kMaxBufferRecoveryInUsecs) {
sleepTime += kBufferRecoveryInUsecs;
@@ -1242,101 +1227,165 @@ bool AudioFlinger::MixerThread::threadLoop()
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove.clear();
- } while (true);
-
- return false;
-}
+ }
-status_t AudioFlinger::MixerThread::readyToRun()
-{
- if (mSampleRate == 0) {
- LOGE("No working audio driver found.");
- return NO_INIT;
+ if (!mStandby) {
+ mOutput->standby();
}
- LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
- return NO_ERROR;
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("MixerThread %p exiting", this);
+ return false;
}
-void AudioFlinger::MixerThread::onFirstRef()
+// prepareTracks_l() must be called with ThreadBase::mLock held
+size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
-
- run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
-}
+ size_t enabledTracks = 0;
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
-// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
- const sp<AudioFlinger::Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- const sp<IMemory>& sharedBuffer,
- status_t *status)
-{
- sp<Track> track;
- status_t lStatus;
-
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
- lStatus = BAD_VALUE;
- goto Exit;
- }
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ mAudioMixer->setActiveTrack(track->name());
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
+ // XXX: these things DON'T need to be done each time
+ mAudioMixer->setBufferProvider(track);
+ mAudioMixer->enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mAudioMixer->setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ tracksToRemove->add(track);
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove->add(track);
+ }
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer == 0) || (mBytesWritten >= mMinBytesToWrite)) {
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ enabledTracks++;
+ }
+ }
+ }
}
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer);
- if (track->getCblk() == NULL) {
- lStatus = NO_MEMORY;
- goto Exit;
+ // remove all the tracks that need to be...
+ count = tracksToRemove->size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove->itemAt(i);
+ mActiveTracks.remove(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ deleteTrackName_l(track->mName);
+ }
+ }
}
- mTracks.add(track);
- lStatus = NO_ERROR;
-Exit:
- if(status) {
- *status = lStatus;
- }
- return track;
+ return enabledTracks;
}
-// getTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::getTracks_l(
+void AudioFlinger::MixerThread::getTracks(
SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks)
+ SortedVector < wp<Track> >& activeTracks,
+ int streamType)
{
+ LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.size());
+ Mutex::Autolock _l(mLock);
size_t size = mTracks.size();
- LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+ 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);
- }
+ activeTracks.add(t);
+ }
}
}
}
size = activeTracks.size();
for (size_t i = 0; i < size; i++) {
- removeActiveTrack_l(activeTracks[i]);
+ mActiveTracks.remove(activeTracks[i]);
}
-
+
size = tracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = tracks[i];
@@ -1345,219 +1394,554 @@ void AudioFlinger::MixerThread::getTracks_l(
}
}
-// putTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::putTracks_l(
+void AudioFlinger::MixerThread::putTracks(
SortedVector < sp<Track> >& tracks,
SortedVector < wp<Track> >& activeTracks)
{
-
- LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
-
+ 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->mMixerThread = this;
+ t->mThread = this;
mTracks.add(t);
int j = activeTracks.indexOf(t);
if (j >= 0) {
- addActiveTrack_l(t);
- }
+ mActiveTracks.add(t);
+ }
}
}
-uint32_t AudioFlinger::MixerThread::sampleRate() const
-{
- return mSampleRate;
-}
-
-int AudioFlinger::MixerThread::channelCount() const
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
{
- return mChannelCount;
+ return mAudioMixer->getTrackName();
}
-int AudioFlinger::MixerThread::format() const
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
{
- return mFormat;
+ mAudioMixer->deleteTrackName(name);
}
-size_t AudioFlinger::MixerThread::frameCount() const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameters_l()
{
- return mFrameCount;
-}
+ bool reconfig = false;
-uint32_t AudioFlinger::MixerThread::latency() const
-{
- if (mOutput) {
- return mOutput->latency();
- }
- else {
- return 0;
+ if (mNewParameters != "") {
+ status_t status = NO_ERROR;
+ AudioParameter param = AudioParameter(mNewParameters);
+ int value;
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ if (value != AudioSystem::PCM_16_BIT) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ if (value != AudioSystem::CHANNEL_OUT_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(mNewParameters);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(mNewParameters);
+ }
+ if (status == NO_ERROR && reconfig) {
+ delete mAudioMixer;
+ readOutputParameters();
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ for (size_t i = 0; i < mTracks.size() ; i++) {
+ int name = getTrackName_l();
+ if (name < 0) break;
+ mTracks[i]->mName = name;
+ }
+ sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mNewParameters = "";
+ mParamCond.signal();
}
+ return reconfig;
}
-status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
{
- mMasterVolume = value;
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ PlaybackThread::dumpInternals(fd, args);
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+// ----------------------------------------------------------------------------
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mLeftVolume (1.0), mRightVolume(1.0)
{
- mMasterMute = muted;
- return NO_ERROR;
+ mType = PlaybackThread::DIRECT;
}
-float AudioFlinger::MixerThread::masterVolume() const
+AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
- return mMasterVolume;
}
-bool AudioFlinger::MixerThread::masterMute() const
+
+bool AudioFlinger::DirectOutputThread::threadLoop()
{
- return mMasterMute;
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ sp<Track> trackToRemove;
+ sp<Track> activeTrack;
+ nsecs_t standbyTime = systemTime();
+ int8_t *curBuf;
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ // wait until we have something to do...
+ if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p\n", this);
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+
+ if (exitPending()) break;
+
+ LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+ }
+
+ // find out which tracks need to be processed
+ if (mActiveTracks.size() != 0) {
+ sp<Track> t = mActiveTracks[0].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ float left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = v_clamped/MAX_GAIN;
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = v_clamped/MAX_GAIN;
+ }
+
+ if (left != mLeftVolume || right != mRightVolume) {
+ mOutput->setVolume(left, right);
+ left = mLeftVolume;
+ right = mRightVolume;
+ }
+
+ if (track->mFillingUpStatus == Track::FS_FILLED) {
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ }
+ }
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ activeTrack = t;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ trackToRemove = track;
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ trackToRemove = track;
+ }
+
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer != 0) && (mBytesWritten < mMinBytesToWrite)) {
+ activeTrack = t;
+ }
+ }
+ }
+ }
+
+ // remove all the tracks that need to be...
+ if (UNLIKELY(trackToRemove != 0)) {
+ mActiveTracks.remove(trackToRemove);
+ if (trackToRemove->isTerminated()) {
+ mTracks.remove(trackToRemove);
+ deleteTrackName_l(trackToRemove->mName);
+ }
+ }
+ }
+
+ if (activeTrack != 0) {
+ AudioBufferProvider::Buffer buffer;
+ size_t frameCount = mFrameCount;
+ curBuf = (int8_t *)mMixBuffer;
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ while(frameCount) {
+ buffer.frameCount = frameCount;
+ activeTrack->getNextBuffer(&buffer);
+ if (UNLIKELY(buffer.raw == 0)) {
+ memset(curBuf, 0, frameCount * mFrameSize);
+ break;
+ }
+ memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+ frameCount -= buffer.frameCount;
+ curBuf += buffer.frameCount * mFrameSize;
+ activeTrack->releaseBuffer(&buffer);
+ }
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
+ if (bytesWritten) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ //LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of removed track, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ trackToRemove.clear();
+ activeTrack.clear();
+ }
+
+ if (!mStandby) {
+ mOutput->standby();
+ }
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("DirectOutputThread %p exiting", this);
+ return false;
}
-status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::DirectOutputThread::getTrackName_l()
{
- mStreamTypes[stream].volume = value;
- return NO_ERROR;
+ return 0;
}
-status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
{
- mStreamTypes[stream].mute = muted;
- return NO_ERROR;
}
-float AudioFlinger::MixerThread::streamVolume(int stream) const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
{
- return mStreamTypes[stream].volume;
+ bool reconfig = false;
+
+ if (mNewParameters != "") {
+ status_t status = NO_ERROR;
+ AudioParameter param = AudioParameter(mNewParameters);
+ int value;
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(mNewParameters);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(mNewParameters);
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters();
+ sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mNewParameters = "";
+ mParamCond.signal();
+ }
+ return reconfig;
}
-bool AudioFlinger::MixerThread::streamMute(int stream) const
+// ----------------------------------------------------------------------------
+
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
+ : MixerThread(audioFlinger, mainThread->getOutput())
{
- return mStreamTypes[stream].mute;
+ mType = PlaybackThread::DUPLICATING;
+ addOutputTrack(mainThread);
}
-// isMusicActive_l() must be called with AudioFlinger::mLock held
-bool AudioFlinger::MixerThread::isMusicActive_l() const
+AudioFlinger::DuplicatingThread::~DuplicatingThread()
{
- size_t count = mActiveTracks.size();
- for (size_t i = 0 ; i < count ; ++i) {
- sp<Track> t = mActiveTracks[i].promote();
- if (t == 0) continue;
- Track* const track = t.get();
- if (t->mStreamType == AudioSystem::MUSIC)
- return true;
- }
- return false;
+ mOutputTracks.clear();
}
-// addTrack_l() must be called with AudioFlinger::mLock held
-status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+bool AudioFlinger::DuplicatingThread::threadLoop()
{
- status_t status = ALREADY_EXISTS;
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks = 0;
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+ SortedVector< sp<OutputTrack> > outputTracks;
- // here the track could be either new, or restarted
- // in both cases "unstop" the track
- if (track->isPaused()) {
- track->mState = TrackBase::RESUMING;
- LOGV("PAUSED => RESUMING (%d)", track->name());
- } else {
- track->mState = TrackBase::ACTIVE;
- LOGV("? => ACTIVE (%d)", track->name());
- }
- // set retry count for buffer fill
- track->mRetryCount = kMaxTrackStartupRetries;
- if (mActiveTracks.indexOf(track) < 0) {
- // the track is newly added, make sure it fills up all its
- // buffers before playing. This is to ensure the client will
- // effectively get the latency it requested.
- track->mFillingUpStatus = Track::FS_FILLING;
- track->mResetDone = false;
- addActiveTrack_l(track);
- status = NO_ERROR;
- }
-
- LOGV("mWaitWorkCV.broadcast");
- mAudioFlinger->mWaitWorkCV.broadcast();
+ while (!exitPending())
+ {
+ processConfigEvents();
- return status;
-}
+ enabledTracks = 0;
+ { // scope for the mLock
-// destroyTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
-{
- track->mState = TrackBase::TERMINATED;
- if (mActiveTracks.indexOf(track) < 0) {
- LOGV("remove track (%d) and delete from mixer", track->name());
- mTracks.remove(track);
- deleteTrackName_l(track->name());
- }
-}
+ Mutex::Autolock _l(mLock);
-// addActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
-{
- mActiveTracks.add(t);
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
-
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
- }
- }
-}
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-// removeActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
-{
- mActiveTracks.remove(t);
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ outputTracks.add(mOutputTracks[i]);
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ if (!mStandby) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ mLock.unlock();
+ outputTracks[i]->stop();
+ mLock.lock();
+ }
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ outputTracks.clear();
+
+ if (exitPending()) break;
+
+ LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ continue;
+ }
+ }
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
+ }
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ bool mustSleep = true;
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+ if (!mSuspended) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->write(curBuf, mFrameCount);
+ }
+ mStandby = false;
+ mustSleep = false;
+ mBytesWritten += mixBufferSize;
+ }
+ } else {
+ // flush remaining overflow buffers in output tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ if (outputTracks[i]->isActive()) {
+ outputTracks[i]->write(curBuf, 0);
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ mustSleep = false;
+ }
+ }
}
+ if (mustSleep) {
+// LOGV("threadLoop() sleeping %d", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ } else {
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ outputTracks.clear();
}
-}
-// getTrackName_l() must be called with AudioFlinger::mLock held
-int AudioFlinger::MixerThread::getTrackName_l()
-{
- return mAudioMixer->getTrackName();
+ if (!mStandby) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ mLock.unlock();
+ outputTracks[i]->stop();
+ mLock.lock();
+ }
+ }
+
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ return false;
}
-// deleteTrackName_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::deleteTrackName_l(int name)
+void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
- mAudioMixer->deleteTrackName(name);
+ int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
+ OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
+ mSampleRate,
+ mFormat,
+ mChannelCount,
+ frameCount);
+ thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
+ mOutputTracks.add(outputTrack);
+ LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
}
-size_t AudioFlinger::MixerThread::getOutputFrameCount()
+void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
{
- return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+ mOutputTracks.removeAt(i);
+ return;
+ }
+ }
+ LOGV("removeOutputTrack(): unkonwn thread: %p", thread);
}
+
// ----------------------------------------------------------------------------
// TrackBase constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::TrackBase::TrackBase(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::ThreadBase::TrackBase::TrackBase(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -1566,7 +1950,7 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mMixerThread(mixerThread),
+ mThread(thread),
mClient(client),
mFrameCount(0),
mState(IDLE),
@@ -1574,13 +1958,6 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
mFormat(format),
mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
- mName = mixerThread->getTrackName_l();
- LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- if (mName < 0) {
- LOGE("no more track names availlable");
- return;
- }
-
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
@@ -1634,16 +2011,19 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
}
}
-AudioFlinger::MixerThread::TrackBase::~TrackBase()
+AudioFlinger::PlaybackThread::TrackBase::~TrackBase()
{
if (mCblk) {
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mClient == NULL) {
+ delete mCblk;
+ }
}
mCblkMemory.clear(); // and free the shared memory
mClient.clear();
}
-void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1651,7 +2031,7 @@ void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Bu
buffer->frameCount = 0;
}
-bool AudioFlinger::MixerThread::TrackBase::step() {
+bool AudioFlinger::PlaybackThread::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1663,7 +2043,7 @@ bool AudioFlinger::MixerThread::TrackBase::step() {
return result;
}
-void AudioFlinger::MixerThread::TrackBase::reset() {
+void AudioFlinger::PlaybackThread::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
@@ -1674,27 +2054,27 @@ void AudioFlinger::MixerThread::TrackBase::reset() {
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
+int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const {
return (int)mCblk->sampleRate;
}
-int AudioFlinger::MixerThread::TrackBase::channelCount() const {
+int AudioFlinger::PlaybackThread::TrackBase::channelCount() const {
return (int)mCblk->channels;
}
-void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::PlaybackThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
- int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
- int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+ int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
+ int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;
// Check validity of returned pointer in case the track control block would have been corrupted.
- if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
- (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) {
+ 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",
bufferStart, bufferEnd, mBuffer, mBufferEnd,
@@ -1707,9 +2087,9 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t
// ----------------------------------------------------------------------------
-// Track constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::Track::Track(
- const sp<MixerThread>& mixerThread,
+// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
+AudioFlinger::PlaybackThread::Track::Track(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1717,40 +2097,58 @@ AudioFlinger::MixerThread::Track::Track(
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+ : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
+ mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
{
+ sp<ThreadBase> baseThread = thread.promote();
+ if (baseThread != 0) {
+ PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
+ mName = playbackThread->getTrackName_l();
+ }
+ LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ if (mName < 0) {
+ LOGE("no more track names available");
+ }
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
- mMute = false;
- mSharedBuffer = sharedBuffer;
mStreamType = streamType;
+ // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
+ // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
+ mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
}
-AudioFlinger::MixerThread::Track::~Track()
+AudioFlinger::PlaybackThread::Track::~Track()
{
- wp<Track> weak(this); // never create a strong ref from the dtor
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mState = TERMINATED;
+ LOGV("PlaybackThread::Track destructor");
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ mState = TERMINATED;
+ }
}
-void AudioFlinger::MixerThread::Track::destroy()
+void AudioFlinger::PlaybackThread::Track::destroy()
{
- // NOTE: destroyTrack_l() can remove a strong reference to this Track
+ // NOTE: destroyTrack_l() can remove a strong reference to this Track
// by removing it from mTracks vector, so there is a risk that this Tracks's
- // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
- // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+ // desctructor is called. As the destructor needs to lock mLock,
+ // we must acquire a strong reference on this Track before locking mLock
// here so that the destructor is called only when exiting this function.
- // On the other hand, as long as Track::destroy() is only called by
- // TrackHandle destructor, the TrackHandle still holds a strong ref on
+ // On the other hand, as long as Track::destroy() is only called by
+ // TrackHandle destructor, the TrackHandle still holds a strong ref on
// this Track with its member mTrack.
sp<Track> keep(this);
- { // scope for AudioFlinger::mLock
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->destroyTrack_l(this);
+ { // scope for mLock
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->destroyTrack_l(this);
+ }
}
}
-void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
+void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
mName - AudioMixer::TRACK0,
@@ -1769,7 +2167,7 @@ void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
mCblk->user);
}
-status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -1806,76 +2204,90 @@ status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Bu
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
+ LOGV("getNextBuffer() no more data");
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::MixerThread::Track::isReady() const {
+bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
mCblk->forceReady = 0;
- LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
return true;
}
return false;
}
-status_t AudioFlinger::MixerThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start()
{
- LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->addTrack_l(this);
+ LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->addTrack_l(this);
+ }
return NO_ERROR;
}
-void AudioFlinger::MixerThread::Track::stop()
+void AudioFlinger::PlaybackThread::Track::stop()
{
- LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState > STOPPED) {
- mState = STOPPED;
- // If the track is not active (PAUSED and buffers full), flush buffers
- if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
- reset();
+ LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState > STOPPED) {
+ mState = STOPPED;
+ // If the track is not active (PAUSED and buffers full), flush buffers
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+ reset();
+ }
+ LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
- LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
}
-void AudioFlinger::MixerThread::Track::pause()
+void AudioFlinger::PlaybackThread::Track::pause()
{
LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState == ACTIVE || mState == RESUMING) {
- mState = PAUSING;
- LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState == ACTIVE || mState == RESUMING) {
+ mState = PAUSING;
+ LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ }
}
}
-void AudioFlinger::MixerThread::Track::flush()
+void AudioFlinger::PlaybackThread::Track::flush()
{
LOGV("flush(%d)", mName);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
- return;
- }
- // No point remaining in PAUSED state after a flush => go to
- // STOPPED state
- mState = STOPPED;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+ return;
+ }
+ // No point remaining in PAUSED state after a flush => go to
+ // STOPPED state
+ mState = STOPPED;
- mCblk->lock.lock();
- // NOTE: reset() will reset cblk->user and cblk->server with
- // the risk that at the same time, the AudioMixer is trying to read
- // data. In this case, getNextBuffer() would return a NULL pointer
- // as audio buffer => the AudioMixer code MUST always test that pointer
- // returned by getNextBuffer() is not NULL!
- reset();
- mCblk->lock.unlock();
+ mCblk->lock.lock();
+ // NOTE: reset() will reset cblk->user and cblk->server with
+ // the risk that at the same time, the AudioMixer is trying to read
+ // data. In this case, getNextBuffer() would return a NULL pointer
+ // as audio buffer => the AudioMixer code MUST always test that pointer
+ // returned by getNextBuffer() is not NULL!
+ reset();
+ mCblk->lock.unlock();
+ }
}
-void AudioFlinger::MixerThread::Track::reset()
+void AudioFlinger::PlaybackThread::Track::reset()
{
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
@@ -1885,17 +2297,17 @@ void AudioFlinger::MixerThread::Track::reset()
// written to buffer
mCblk->flowControlFlag = 1;
mCblk->forceReady = 0;
- mFillingUpStatus = FS_FILLING;
+ mFillingUpStatus = FS_FILLING;
mResetDone = true;
}
}
-void AudioFlinger::MixerThread::Track::mute(bool muted)
+void AudioFlinger::PlaybackThread::Track::mute(bool muted)
{
mMute = muted;
}
-void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
+void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right)
{
mVolume[0] = left;
mVolume[1] = right;
@@ -1904,28 +2316,33 @@ void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
// ----------------------------------------------------------------------------
// RecordTrack constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::RecordTrack::RecordTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::RecordThread::RecordTrack::RecordTrack(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
- int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags)
- : TrackBase(mixerThread, client, sampleRate, format,
+ : TrackBase(thread, client, sampleRate, format,
channelCount, frameCount, flags, 0),
- mOverflow(false), mInputSource(inputSource)
+ mOverflow(false)
{
+ LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
+ if (format == AudioSystem::PCM_16_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int16_t);
+ } else if (format == AudioSystem::PCM_8_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int8_t);
+ } else {
+ mCblk->frameSize = sizeof(int8_t);
+ }
}
-AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
{
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->deleteTrackName_l(mName);
}
-status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesAvail;
@@ -1964,180 +2381,231 @@ getNextBuffer_exit:
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::MixerThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start()
{
- return mMixerThread->mAudioFlinger->startRecord(this);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ return recordThread->start(this);
+ }
+ return NO_INIT;
}
-void AudioFlinger::MixerThread::RecordTrack::stop()
+void AudioFlinger::RecordThread::RecordTrack::stop()
{
- mMixerThread->mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ recordThread->stop(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
+ }
}
// ----------------------------------------------------------------------------
-AudioFlinger::MixerThread::OutputTrack::OutputTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
+ const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount)
- : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
- mOutputMixerThread(mixerThread)
+ : Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
+ mActive(false)
{
-
+
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
mCblk->out = 1;
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
mOutBuffer.frameCount = 0;
- mCblk->bufferTimeoutMs = 10;
-
- 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);
-
+ mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
+
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+
}
-AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
{
stop();
}
-status_t AudioFlinger::MixerThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start()
{
status_t status = Track::start();
-
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ mActive = true;
mRetryCount = 127;
return status;
}
-void AudioFlinger::MixerThread::OutputTrack::stop()
+void AudioFlinger::PlaybackThread::OutputTrack::stop()
{
Track::stop();
clearBufferQueue();
mOutBuffer.frameCount = 0;
+ mActive = false;
}
-void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames)
{
Buffer *pInBuffer;
Buffer inBuffer;
uint32_t channels = mCblk->channels;
-
+ bool outputBufferFull = false;
inBuffer.frameCount = frames;
inBuffer.i16 = data;
-
- if (mCblk->user == 0) {
- mOutputMixerThread->mAudioFlinger->mLock.lock();
- bool isMusicActive = mOutputMixerThread->isMusicActive_l();
- mOutputMixerThread->mAudioFlinger->mLock.unlock();
- if (isMusicActive) {
- mCblk->forceReady = 1;
- LOGV("OutputTrack::start() force ready");
- } else if (mCblk->frameCount > frames){
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
- uint32_t startFrames = (mCblk->frameCount - frames);
- LOGV("OutputTrack::start() write %d frames", startFrames);
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[startFrames * channels];
- pInBuffer->frameCount = startFrames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
- } else {
- LOGW ("OutputTrack::write() no more buffers");
+
+ uint32_t waitTimeLeftMs = mWaitTimeMs;
+
+ if (!mActive) {
+ start();
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ MixerThread *mixerThread = (MixerThread *)thread.get();
+ if (mCblk->frameCount > frames){
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
+ uint32_t startFrames = (mCblk->frameCount - frames);
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[startFrames * channels];
+ pInBuffer->frameCount = startFrames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW ("OutputTrack::write() %p no more buffers in queue", this);
+ }
}
- }
+ }
}
- while (1) {
+ while (waitTimeLeftMs) {
// First write pending buffers, then new data
if (mBufferQueue.size()) {
pInBuffer = mBufferQueue.itemAt(0);
} else {
pInBuffer = &inBuffer;
}
-
+
if (pInBuffer->frameCount == 0) {
break;
}
-
+
if (mOutBuffer.frameCount == 0) {
mOutBuffer.frameCount = pInBuffer->frameCount;
- if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ nsecs_t startTime = systemTime();
+ if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ LOGV ("OutputTrack::write() %p no more output buffers", this);
+ outputBufferFull = true;
break;
}
+ uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
+// LOGV("OutputTrack::write() waitTimeMs %d waitTimeLeftMs %d", waitTimeMs, waitTimeLeftMs)
+ if (waitTimeLeftMs >= waitTimeMs) {
+ waitTimeLeftMs -= waitTimeMs;
+ } else {
+ waitTimeLeftMs = 0;
+ }
}
-
+
uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
mCblk->stepUser(outFrames);
pInBuffer->frameCount -= outFrames;
pInBuffer->i16 += outFrames * channels;
mOutBuffer.frameCount -= outFrames;
- mOutBuffer.i16 += outFrames * channels;
-
+ mOutBuffer.i16 += outFrames * channels;
+
if (pInBuffer->frameCount == 0) {
if (mBufferQueue.size()) {
mBufferQueue.removeAt(0);
delete [] pInBuffer->mBuffer;
delete pInBuffer;
+ LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size());
} else {
break;
}
}
}
-
+
// If we could not write all frames, allocate a buffer and queue it for next time.
if (inBuffer.frameCount) {
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
pInBuffer->frameCount = inBuffer.frameCount;
pInBuffer->i16 = pInBuffer->mBuffer;
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
mBufferQueue.add(pInBuffer);
+ LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size());
} else {
- LOGW("OutputTrack::write() no more buffers");
+ LOGW("OutputTrack::write() %p no more overflow buffers", this);
}
}
-
+
// Calling write() with a 0 length buffer, means that no more data will be written:
- // If no more buffers are pending, fill output track buffer to make sure it is started
+ // If no more buffers are pending, fill output track buffer to make sure it is started
// by output mixer.
- if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
- frames = mCblk->frameCount - mCblk->user;
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[frames * channels];
- pInBuffer->frameCount = frames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
+ if (frames == 0 && mBufferQueue.size() == 0) {
+ if (mCblk->user < mCblk->frameCount) {
+ frames = mCblk->frameCount - mCblk->user;
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[frames * channels];
+ pInBuffer->frameCount = frames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ stop();
+ }
}
+ return outputBufferFull;
}
-status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
{
int active;
- int timeout = 0;
status_t result;
audio_track_cblk_t* cblk = mCblk;
uint32_t framesReq = buffer->frameCount;
- LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+// LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
buffer->frameCount = 0;
-
+
uint32_t framesAvail = cblk->framesAvailable();
+
if (framesAvail == 0) {
- return AudioTrack::NO_MORE_BUFFERS;
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (framesAvail == 0) {
+ active = mActive;
+ if (UNLIKELY(!active)) {
+ LOGV("Not active and NO_MORE_BUFFERS");
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ if (result != NO_ERROR) {
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ // read the server count again
+ start_loop_here:
+ framesAvail = cblk->framesAvailable_l();
+ }
}
+// if (framesAvail < framesReq) {
+// return AudioTrack::NO_MORE_BUFFERS;
+// }
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -2155,11 +2623,11 @@ status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvide
}
-void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
{
size_t size = mBufferQueue.size();
Buffer *pBuffer;
-
+
for (size_t i = 0; i < size; i++) {
pBuffer = mBufferQueue.itemAt(i);
delete [] pBuffer->mBuffer;
@@ -2191,7 +2659,7 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const
// ----------------------------------------------------------------------------
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
: BnAudioTrack(),
mTrack(track)
{
@@ -2243,7 +2711,7 @@ status_t AudioFlinger::TrackHandle::onTransact(
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int inputSource,
+ void *input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -2251,14 +2719,13 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t flags,
status_t *status)
{
- sp<MixerThread::RecordTrack> recordTrack;
+ sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
wp<Client> wclient;
- AudioStreamIn* input = 0;
- int inFrameCount;
- size_t inputBufferSize;
status_t lStatus;
+ RecordThread *thread;
+ size_t inFrameCount;
// check calling permissions
if (!recordingAllowed()) {
@@ -2266,30 +2733,15 @@ sp<IAudioRecord> AudioFlinger::openRecord(
goto Exit;
}
- if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) {
- LOGE("invalid stream type");
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
- if (mAudioRecordThread == 0) {
- LOGE("Audio record thread not started");
- lStatus = NO_INIT;
- goto Exit;
- }
-
-
- // Check that audio input stream accepts requested audio parameters
- inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
- if (inputBufferSize == 0) {
- lStatus = BAD_VALUE;
- LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
- goto Exit;
- }
-
// add client to list
{ // scope for mLock
Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
client = wclient.promote();
@@ -2298,12 +2750,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
mClients.add(pid, client);
}
- // frameCount must be a multiple of input buffer size
- inFrameCount = inputBufferSize/channelCount/sizeof(short);
- frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate,
+ recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
format, channelCount, frameCount, flags);
}
if (recordTrack->getCblk() == NULL) {
@@ -2323,22 +2771,9 @@ Exit:
return recordHandle;
}
-status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- return mAudioRecordThread->start(recordTrack);
- }
- return NO_INIT;
-}
-
-void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->stop(recordTrack);
- }
-}
-
// ----------------------------------------------------------------------------
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack)
: BnAudioRecord(),
mRecordTrack(recordTrack)
{
@@ -2370,86 +2805,165 @@ status_t AudioFlinger::RecordHandle::onTransact(
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
- const sp<AudioFlinger>& audioFlinger) :
- mAudioHardware(audioHardware),
- mAudioFlinger(audioFlinger),
- mActive(false)
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels) :
+ ThreadBase(audioFlinger),
+ mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
+ mReqChannelCount = AudioSystem::popCount(channels);
+ mReqSampleRate = sampleRate;
+ readInputParameters();
+ sendConfigEvent(AudioSystem::INPUT_OPENED);
}
-AudioFlinger::AudioRecordThread::~AudioRecordThread()
+
+AudioFlinger::RecordThread::~RecordThread()
{
+ mAudioFlinger->mAudioHardware->closeInputStream(mInput);
+ delete[] mRsmpInBuffer;
+ if (mResampler != 0) {
+ delete mResampler;
+ delete[] mRsmpOutBuffer;
+ }
}
-bool AudioFlinger::AudioRecordThread::threadLoop()
+void AudioFlinger::RecordThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Record Thread %p", this);
+
+ run(buffer, PRIORITY_URGENT_AUDIO);
+}
+bool AudioFlinger::RecordThread::threadLoop()
{
- LOGV("AudioRecordThread: start record loop");
AudioBufferProvider::Buffer buffer;
- int inBufferSize = 0;
- int inFrameCount = 0;
- AudioStreamIn* input = 0;
+ sp<RecordTrack> activeTrack;
- mActive = 0;
-
// start recording
while (!exitPending()) {
- if (!mActive) {
- mLock.lock();
- if (!mActive && !exitPending()) {
- LOGV("AudioRecordThread: loop stopping");
- if (input) {
- delete input;
- input = 0;
+
+ processConfigEvents();
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ checkForNewParameters_l();
+ if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
+ if (!mStandby) {
+ mInput->standby();
+ mStandby = true;
}
- mRecordTrack.clear();
- mStopped.signal();
+ if (exitPending()) break;
+
+ LOGV("RecordThread: loop stopping");
+ // go to sleep
mWaitWorkCV.wait(mLock);
-
- LOGV("AudioRecordThread: loop starting");
- if (mRecordTrack != 0) {
- input = mAudioHardware->openInputStream(
- mRecordTrack->inputSource(),
- mRecordTrack->format(),
- mRecordTrack->channelCount(),
- mRecordTrack->sampleRate(),
- &mStartStatus,
- (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
- if (input != 0) {
- inBufferSize = input->bufferSize();
- inFrameCount = inBufferSize/input->frameSize();
+ LOGV("RecordThread: loop starting");
+ continue;
+ }
+ if (mActiveTrack != 0) {
+ if (mActiveTrack->mState == TrackBase::PAUSING) {
+ mActiveTrack.clear();
+ mStartStopCond.broadcast();
+ } else if (mActiveTrack->mState == TrackBase::RESUMING) {
+ mRsmpInIndex = mFrameCount;
+ if (mReqChannelCount != mActiveTrack->channelCount()) {
+ mActiveTrack.clear();
+ } else {
+ mActiveTrack->mState == TrackBase::ACTIVE;
}
- } else {
- mStartStatus = NO_INIT;
+ mStartStopCond.broadcast();
}
- if (mStartStatus !=NO_ERROR) {
- LOGW("record start failed, status %d", mStartStatus);
- mActive = false;
- mRecordTrack.clear();
- }
- mWaitWorkCV.signal();
+ mStandby = false;
}
- mLock.unlock();
- } else if (mRecordTrack != 0) {
-
- buffer.frameCount = inFrameCount;
- if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
- (int)buffer.frameCount == inFrameCount)) {
- LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
- ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
- if (bytesRead < 0) {
- LOGE("Error reading audio input");
- sleep(1);
+ }
+
+ if (mActiveTrack != 0) {
+ buffer.frameCount = mFrameCount;
+ if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ size_t framesOut = buffer.frameCount;
+ if (mResampler == 0) {
+ // no resampling
+ while (framesOut) {
+ size_t framesIn = mFrameCount - mRsmpInIndex;
+ if (framesIn) {
+ int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
+ int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize;
+ if (framesIn > framesOut)
+ framesIn = framesOut;
+ mRsmpInIndex += framesIn;
+ framesOut -= framesIn;
+ if (mChannelCount == mReqChannelCount ||
+ mFormat != AudioSystem::PCM_16_BIT) {
+ memcpy(dst, src, framesIn * mFrameSize);
+ } else {
+ int16_t *src16 = (int16_t *)src;
+ int16_t *dst16 = (int16_t *)dst;
+ if (mChannelCount == 1) {
+ while (framesIn--) {
+ *dst16++ = *src16;
+ *dst16++ = *src16++;
+ }
+ } else {
+ while (framesIn--) {
+ *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
+ src16 += 2;
+ }
+ }
+ }
+ }
+ if (framesOut && mFrameCount == mRsmpInIndex) {
+ ssize_t bytesRead;
+ if (framesOut == mFrameCount &&
+ (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
+ bytesRead = mInput->read(buffer.raw, mInputBytes);
+ framesOut = 0;
+ } else {
+ bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ mRsmpInIndex = 0;
+ }
+ if (bytesRead < 0) {
+ LOGE("Error reading audio input");
+ sleep(1);
+ mRsmpInIndex = mFrameCount;
+ framesOut = 0;
+ buffer.frameCount = 0;
+ }
+ }
+ }
+ } else {
+ // resampling
+
+ memset(mRsmpOutBuffer, 0, framesOut * 2 * sizeof(int32_t));
+ // alter output frame count as if we were expecting stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ framesOut >>= 1;
+ }
+ mResampler->resample(mRsmpOutBuffer, framesOut, this);
+ // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
+ // are 32 bit aligned which should be always true.
+ if (mChannelCount == 2 && mReqChannelCount == 1) {
+ AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
+ // the resampler always outputs stereo samples: do post stereo to mono conversion
+ int16_t *src = (int16_t *)mRsmpOutBuffer;
+ int16_t *dst = buffer.i16;
+ while (framesOut--) {
+ *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
+ src += 2;
+ }
+ } else {
+ AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+ }
+
}
- mRecordTrack->releaseBuffer(&buffer);
- mRecordTrack->overflow();
+ mActiveTrack->releaseBuffer(&buffer);
+ mActiveTrack->overflow();
}
-
// client isn't retrieving buffers fast enough
else {
- if (!mRecordTrack->setOverflow())
- LOGW("AudioRecordThread: buffer overflow");
+ if (!mActiveTrack->setOverflow())
+ LOGW("RecordThread: buffer overflow");
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
@@ -2458,65 +2972,64 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
}
}
-
- if (input) {
- delete input;
+ if (!mStandby) {
+ mInput->standby();
}
- mRecordTrack.clear();
-
+ mActiveTrack.clear();
+
+ sendConfigEvent(AudioSystem::INPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("RecordThread %p exiting", this);
return false;
}
-status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
{
- LOGV("AudioRecordThread::start");
+ LOGV("RecordThread::start");
AutoMutex lock(&mLock);
- mActive = true;
- // If starting the active track, just reset mActive in case a stop
- // was pending and exit
- if (recordTrack == mRecordTrack.get()) return NO_ERROR;
- if (mRecordTrack != 0) return -EBUSY;
+ if (mActiveTrack != 0) {
+ if (recordTrack != mActiveTrack.get()) return -EBUSY;
- mRecordTrack = recordTrack;
+ if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
+ return NO_ERROR;
+ }
+
+ mActiveTrack = recordTrack;
+ mActiveTrack->mState = TrackBase::RESUMING;
// signal thread to start
LOGV("Signal record thread");
mWaitWorkCV.signal();
- mWaitWorkCV.wait(mLock);
- LOGV("Record started, status %d", mStartStatus);
- return mStartStatus;
-}
-
-void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
- LOGV("AudioRecordThread::stop");
- AutoMutex lock(&mLock);
- if (mActive && (recordTrack == mRecordTrack.get())) {
- mActive = false;
- mStopped.wait(mLock);
+ mStartStopCond.wait(mLock);
+ if (mActiveTrack != 0) {
+ LOGV("Record started OK");
+ return NO_ERROR;
+ } else {
+ LOGV("Record failed to start");
+ return BAD_VALUE;
}
}
-void AudioFlinger::AudioRecordThread::exit()
-{
- LOGV("AudioRecordThread::exit");
- {
- AutoMutex lock(&mLock);
- requestExit();
- mWaitWorkCV.signal();
+void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
+ LOGV("RecordThread::stop");
+ AutoMutex lock(&mLock);
+ if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
+ mActiveTrack->mState = TrackBase::PAUSING;
+ mStartStopCond.wait(mLock);
}
- requestExitAndWait();
}
-status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
pid_t pid = 0;
- if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
- snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+ if (mActiveTrack != 0 && mActiveTrack->mClient != 0) {
+ snprintf(buffer, SIZE, "Record client pid: %d\n", mActiveTrack->mClient->pid());
result.append(buffer);
} else {
result.append("No record client\n");
@@ -2525,6 +3038,463 @@ status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& a
return NO_ERROR;
}
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ size_t framesReq = buffer->frameCount;
+ size_t framesReady = mFrameCount - mRsmpInIndex;
+ int channelCount;
+
+ if (framesReady == 0) {
+ ssize_t bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ if (bytesRead < 0) {
+ LOGE("RecordThread::getNextBuffer() Error reading audio input");
+ sleep(1);
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+ }
+ mRsmpInIndex = 0;
+ framesReady = mFrameCount;
+ }
+
+ if (framesReq > framesReady) {
+ framesReq = framesReady;
+ }
+
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount;
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+}
+
+void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ mRsmpInIndex += buffer->frameCount;
+ buffer->frameCount = 0;
+}
+
+bool AudioFlinger::RecordThread::checkForNewParameters_l()
+{
+ bool reconfig = false;
+
+ if (mNewParameters != "") {
+ status_t status = NO_ERROR;
+ AudioParameter param = AudioParameter(mNewParameters);
+ int value;
+ int reqFormat = mFormat;
+ int reqSamplingRate = mReqSampleRate;
+ int reqChannelCount = mReqChannelCount;
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reqSamplingRate = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ reqFormat = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ reqChannelCount = AudioSystem::popCount(value);
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (mActiveTrack != 0) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mInput->setParameters(mNewParameters);
+ if (status == INVALID_OPERATION) {
+ mInput->standby();
+ status = mInput->setParameters(mNewParameters);
+ }
+ if (reconfig) {
+ if (status == BAD_VALUE &&
+ reqFormat == mInput->format() && reqFormat == AudioSystem::PCM_16_BIT &&
+ ((int)mInput->sampleRate() <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(mInput->channels()) < 3) && (reqChannelCount < 3)) {
+ status = NO_ERROR;
+ }
+ if (status == NO_ERROR) {
+ readInputParameters();
+ sendConfigEvent(AudioSystem::INPUT_CONFIG_CHANGED);
+ }
+ }
+ }
+ mNewParameters = "";
+ mParamStatus = status;
+ mParamCond.signal();
+ }
+ return reconfig;
+}
+
+String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
+{
+ return mInput->getParameters(keys);
+}
+
+void AudioFlinger::RecordThread::audioConfigChanged(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.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = 0;
+ param2 = &desc;
+ break;
+
+ case AudioSystem::INPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::RecordThread::readInputParameters()
+{
+ if (mRsmpInBuffer) delete mRsmpInBuffer;
+ if (mRsmpOutBuffer) delete mRsmpOutBuffer;
+ if (mResampler) delete mResampler;
+ mResampler = 0;
+
+ mSampleRate = mInput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mInput->channels());
+ mFormat = mInput->format();
+ mFrameSize = mInput->frameSize();
+ mInputBytes = mInput->bufferSize();
+ mFrameCount = mInputBytes / mFrameSize;
+ mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
+
+ if (mSampleRate != mReqSampleRate && mChannelCount < 3 && mReqChannelCount < 3)
+ {
+ int channelCount;
+ // optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid
+ // stereo to mono post process as the resampler always outputs stereo.
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ mResampler = AudioResampler::create(16, channelCount, mReqSampleRate);
+ mResampler->setSampleRate(mSampleRate);
+ mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+ mRsmpOutBuffer = new int32_t[mFrameCount * 2];
+
+ // optmization: if mono to mono, alter input frame count as if we were inputing stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ mFrameCount >>= 1;
+ }
+
+ }
+ mRsmpInIndex = mFrameCount;
+}
+
+// ----------------------------------------------------------------------------
+
+void *AudioFlinger::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags)
+{
+ status_t status;
+ PlaybackThread *thread = NULL;
+ mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
+ LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
+ pDevices ? *pDevices : 0,
+ samplingRate,
+ format,
+ channels,
+ flags);
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return NULL;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status);
+ LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
+ output,
+ samplingRate,
+ format,
+ channels,
+ status);
+
+ mHardwareStatus = AUDIO_HW_IDLE;
+ if (output != 0) {
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != AudioSystem::PCM_16_BIT) ||
+ (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ thread = new DirectOutputThread(this, output);
+ LOGV("openOutput() created direct output %p", thread);
+ } else {
+ thread = new MixerThread(this, output);
+ LOGV("openOutput() created mixer output %p", thread);
+ }
+ mPlaybackThreads.add(thread);
+
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = channels;
+ if (pLatencyMs) *pLatencyMs = thread->latency();
+ }
+
+ return thread;
+}
+
+void *AudioFlinger::openDuplicateOutput(void *output1, void *output2)
+{
+ Mutex::Autolock _l(mLock);
+
+ if (checkMixerThread_l(output1) == NULL ||
+ checkMixerThread_l(output2) == NULL) {
+ LOGW("openDuplicateOutput() wrong output mixer type %p or %p", output1, output2);
+ return NULL;
+ }
+
+ DuplicatingThread *thread = new DuplicatingThread(this, (MixerThread *)output1);
+ thread->addOutputTrack( (MixerThread *)output2);
+ mPlaybackThreads.add(thread);
+ return thread;
+}
+
+status_t AudioFlinger::closeOutput(void *output)
+{
+ PlaybackThread *thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeOutput() %p", thread);
+
+ if (thread->type() == PlaybackThread::MIXER) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads[i]->type() == PlaybackThread::DUPLICATING) {
+ DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads[i].get();
+ dupThread->removeOutputTrack((MixerThread *)thread);
+ }
+ }
+ }
+ mPlaybackThreads.remove(thread);
+ }
+ thread->exit();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::suspendOutput(void *output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("suspendOutput() %p", output);
+ thread->suspend();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::restoreOutput(void *output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("restoreOutput() %p", output);
+
+ thread->restore();
+
+ return NO_ERROR;
+}
+
+void *AudioFlinger::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ status_t status;
+ RecordThread *thread = NULL;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t reqSamplingRate = samplingRate;
+ uint32_t reqFormat = format;
+ uint32_t reqChannels = channels;
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return NULL;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamIn *input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
+ input,
+ samplingRate,
+ format,
+ channels,
+ acoustics,
+ status);
+
+ // If the input could not be opened with the requested parameters and we can handle the conversion internally,
+ // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
+ // or stereo to mono conversions on 16 bit PCM inputs.
+ if (input == 0 && status == BAD_VALUE &&
+ reqFormat == format && format == AudioSystem::PCM_16_BIT &&
+ (samplingRate <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(channels) < 3) && (AudioSystem::popCount(reqChannels) < 3)) {
+ LOGV("openInput() reopening with proposed sampling rate and channels");
+ input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ }
+
+ if (input != 0) {
+ // Start record thread
+ thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
+ mRecordThreads.add(thread);
+
+ if (pSamplingRate) *pSamplingRate = reqSamplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = reqChannels;
+
+ input->standby();
+ }
+
+ return thread;
+}
+
+status_t AudioFlinger::closeInput(void *input)
+{
+ RecordThread *thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeInput() %p", thread);
+ mRecordThreads.remove(thread);
+ }
+ thread->exit();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setStreamOutput(uint32_t stream, void *output)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *dstThread = checkMixerThread_l(output);
+ if (dstThread == NULL) {
+ LOGW("setStreamOutput() bad output thread %p", output);
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamOutput() stream %d to output %p", stream, dstThread);
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads[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);
+ dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(void *output) const
+{
+ PlaybackThread *thread = NULL;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads[i] == output) {
+ thread = (PlaybackThread *)output;
+ break;
+ }
+ }
+
+ return thread;
+}
+
+// checkMixerThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(void *output) const
+{
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread != NULL) {
+ if (thread->type() == PlaybackThread::DIRECT) {
+ thread = NULL;
+ }
+ }
+ return (MixerThread *)thread;
+}
+
+// checkRecordThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(void *input) const
+{
+ RecordThread *thread = NULL;
+
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads[i] == input) {
+ thread = (RecordThread *)input;
+ break;
+ }
+ }
+
+ return thread;
+}
+
+// ----------------------------------------------------------------------------
+
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -2532,6 +3502,7 @@ status_t AudioFlinger::onTransact(
}
// ----------------------------------------------------------------------------
+
void AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_flinger"), new AudioFlinger());
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 634934e..06c5846 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -30,8 +30,7 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/MemoryDealer.h>
-#include <utils/KeyedVector.h>
+#include <binder/MemoryDealer.h>
#include <utils/SortedVector.h>
#include <utils/Vector.h>
@@ -44,6 +43,7 @@ namespace android {
class audio_track_cblk_t;
class AudioMixer;
class AudioBuffer;
+class AudioResampler;
// ----------------------------------------------------------------------------
@@ -56,7 +56,7 @@ class AudioBuffer;
static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
{
public:
static void instantiate();
@@ -73,13 +73,14 @@ public:
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ void *output,
status_t *status);
- virtual uint32_t sampleRate(int output) const;
- virtual int channelCount(int output) const;
- virtual int format(int output) const;
- virtual size_t frameCount(int output) const;
- virtual uint32_t latency(int output) const;
+ virtual uint32_t sampleRate(void *output) const;
+ virtual int channelCount(void *output) const;
+ virtual int format(void *output) const;
+ virtual size_t frameCount(void *output) const;
+ virtual uint32_t latency(void *output) const;
virtual status_t setMasterVolume(float value);
virtual status_t setMasterMute(bool muted);
@@ -87,33 +88,51 @@ public:
virtual float masterVolume() const;
virtual bool masterMute() const;
- virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamVolume(int stream, float value, void *output);
virtual status_t setStreamMute(int stream, bool muted);
- virtual float streamVolume(int stream) const;
+ virtual float streamVolume(int stream, void *output) const;
virtual bool streamMute(int stream) const;
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask);
- virtual uint32_t getRouting(int mode) const;
-
virtual status_t setMode(int mode);
- virtual int getMode() const;
virtual status_t setMicMute(bool state);
virtual bool getMicMute() const;
virtual bool isMusicActive() const;
- virtual bool isA2dpEnabled() const;
-
- virtual status_t setParameter(const char* key, const char* value);
+ virtual status_t setParameters(void *ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(void *ioHandle, const String8& keys);
virtual void registerClient(const sp<IAudioFlingerClient>& client);
-
+
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
-
- virtual void wakeUp() { mWaitWorkCV.broadcast(); }
-
+
+ virtual void *openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags);
+
+ virtual void *openDuplicateOutput(void *output1, void *output2);
+
+ virtual status_t closeOutput(void *output);
+
+ virtual status_t suspendOutput(void *output);
+
+ virtual status_t restoreOutput(void *output);
+
+ virtual void *openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+
+ virtual status_t closeInput(void *input);
+
+ virtual status_t setStreamOutput(uint32_t stream, void *output);
+
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -139,7 +158,7 @@ public:
// record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ void *input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -153,30 +172,12 @@ public:
Parcel* reply,
uint32_t flags);
+ void audioConfigChanged(int event, void *param1, void *param2);
+
private:
AudioFlinger();
virtual ~AudioFlinger();
-
- void setOutput(int outputType);
- void doSetOutput(int outputType);
-
-#ifdef WITH_A2DP
- void setA2dpEnabled_l(bool enable);
- void checkA2dpEnabledChange_l();
-#endif
- static bool streamForcedToSpeaker(int streamType);
-
- // Management of forced route to speaker for certain track types.
- enum force_speaker_command {
- ACTIVE_TRACK_ADDED = 0,
- ACTIVE_TRACK_REMOVED,
- CHECK_ROUTE_RESTORE_TIME,
- FORCE_ROUTE_RESTORE
- };
- void handleForcedSpeakerRoute(int command);
-#ifdef WITH_A2DP
- void handleRouteDisablesA2dp_l(int routes);
-#endif
+
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -201,14 +202,17 @@ private:
class TrackHandle;
class RecordHandle;
- class AudioRecordThread;
-
-
- // --- MixerThread ---
- class MixerThread : public Thread {
+ class RecordThread;
+ class PlaybackThread;
+ class MixerThread;
+ class DirectOutputThread;
+ class Track;
+ class RecordTrack;
+
+ class ThreadBase : public Thread {
public:
-
- // --- Track ---
+ ThreadBase (const sp<AudioFlinger>& audioFlinger);
+ virtual ~ThreadBase();
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -230,7 +234,7 @@ private:
// The upper 16 bits are used for track-specific flags.
};
- TrackBase(const sp<MixerThread>& mixerThread,
+ TrackBase(const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -245,9 +249,12 @@ private:
sp<IMemory> getCblk() const;
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class RecordHandle;
- friend class AudioRecordThread;
+ friend class PlaybackThread;
+ friend class RecordThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
TrackBase(const TrackBase&);
TrackBase& operator = (const TrackBase&);
@@ -269,10 +276,6 @@ private:
void* getBuffer(uint32_t offset, uint32_t frames) const;
- int name() const {
- return mName;
- }
-
bool isStopped() const {
return mState == STOPPED;
}
@@ -284,14 +287,13 @@ private:
bool step();
void reset();
- sp<MixerThread> mMixerThread;
+ wp<ThreadBase> mThread;
sp<Client> mClient;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk;
void* mBuffer;
void* mBufferEnd;
uint32_t mFrameCount;
- int mName;
// we don't really need a lock for these
int mState;
int mClientTid;
@@ -299,10 +301,68 @@ private:
uint32_t mFlags;
};
+ class ConfigEvent {
+ public:
+ ConfigEvent() : mEvent(0), mParam(0) {}
+
+ int mEvent;
+ int mParam;
+ };
+
+ uint32_t sampleRate() const;
+ int channelCount() const;
+ int format() const;
+ size_t frameCount() const;
+ void wakeUp() { mWaitWorkCV.broadcast(); }
+ void exit();
+ 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;
+ void sendConfigEvent(int event, int param = 0);
+ void processConfigEvents();
+
+ mutable Mutex mLock;
+
+ protected:
+
+ friend class Track;
+ friend class TrackBase;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+ friend class RecordThread;
+ friend class RecordTrack;
+
+ Condition mWaitWorkCV;
+ sp<AudioFlinger> mAudioFlinger;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ uint32_t mFrameSize;
+ Condition mParamCond;
+ String8 mNewParameters;
+ status_t mParamStatus;
+ Vector<ConfigEvent *> mConfigEvents;
+ bool mStandby;
+ };
+
+ // --- PlaybackThread ---
+ class PlaybackThread : public ThreadBase {
+ public:
+
+ enum type {
+ MIXER,
+ DIRECT,
+ DUPLICATING
+ };
+
// playback track
class Track : public TrackBase {
public:
- Track( const sp<MixerThread>& mixerThread,
+ Track( const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -321,6 +381,9 @@ private:
void destroy();
void mute(bool);
void setVolume(float left, float right);
+ int name() const {
+ return mName;
+ }
int type() const {
return mStreamType;
@@ -328,29 +391,25 @@ private:
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class AudioFlinger;
- friend class AudioFlinger::TrackHandle;
+ friend class TrackHandle;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
Track(const Track&);
Track& operator = (const Track&);
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool isMuted() const {
- return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
- }
-
+ bool isMuted() { return mMute; }
bool isPausing() const {
return mState == PAUSING;
}
-
bool isPaused() const {
return mState == PAUSED;
}
-
bool isReady() const;
-
void setPaused() { mState = PAUSED; }
void reset();
@@ -364,54 +423,20 @@ private:
sp<IMemory> mSharedBuffer;
bool mResetDone;
int mStreamType;
+ int mName;
}; // end of Track
- // record track
- class RecordTrack : public TrackBase {
- public:
- RecordTrack(const sp<MixerThread>& mixerThread,
- const sp<Client>& client,
- int inputSource,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- uint32_t flags);
- ~RecordTrack();
-
- virtual status_t start();
- virtual void stop();
-
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
- bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
- int inputSource() const { return mInputSource; }
-
- private:
- friend class AudioFlinger;
- friend class AudioFlinger::RecordHandle;
- friend class AudioFlinger::AudioRecordThread;
- friend class MixerThread;
-
- RecordTrack(const Track&);
- RecordTrack& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool mOverflow;
- int mInputSource;
- };
// playback track
class OutputTrack : public Track {
public:
-
+
class Buffer: public AudioBufferProvider::Buffer {
public:
int16_t *mBuffer;
};
-
- OutputTrack( const sp<MixerThread>& mixerThread,
+
+ OutputTrack( const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
@@ -420,35 +445,35 @@ private:
virtual status_t start();
virtual void stop();
- void write(int16_t* data, uint32_t frames);
+ bool write(int16_t* data, uint32_t frames);
bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+ bool isActive() { return mActive; }
+ wp<ThreadBase>& thread() { return mThread; }
private:
- status_t obtainBuffer(AudioBufferProvider::Buffer* buffer);
+ status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs);
void clearBufferQueue();
-
- sp<MixerThread> mOutputMixerThread;
+
+ // Maximum number of pending buffers allocated by OutputTrack::write()
+ static const uint8_t kMaxOverFlowBuffers = 3;
+
Vector < Buffer* > mBufferQueue;
AudioBufferProvider::Buffer mOutBuffer;
- uint32_t mFramesWritten;
-
- }; // end of OutputTrack
+ uint32_t mWaitTimeMs;
+ bool mActive;
- MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
- virtual ~MixerThread();
+ }; // end of OutputTrack
+
+ PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args);
// Thread virtuals
- virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
- virtual uint32_t sampleRate() const;
- virtual int channelCount() const;
- virtual int format() const;
- virtual size_t frameCount() const;
virtual uint32_t latency() const;
virtual status_t setMasterVolume(float value);
@@ -463,9 +488,8 @@ private:
virtual float streamVolume(int stream) const;
virtual bool streamMute(int stream) const;
- bool isMusicActive_l() const;
-
-
+ bool isMusicActive() const;
+
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
int streamType,
@@ -475,13 +499,15 @@ private:
int frameCount,
const sp<IMemory>& sharedBuffer,
status_t *status);
-
- void getTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void putTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
-
+
+ AudioStreamOut* getOutput() { return mOutput; }
+
+ virtual int type() const { return mType; }
+ void suspend() { mSuspended = true; }
+ void restore() { mSuspended = false; }
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+
struct stream_type_t {
stream_type_t()
: volume(1.0f),
@@ -492,56 +518,113 @@ private:
bool mute;
};
- private:
+ protected:
+ int mType;
+ int16_t* mMixBuffer;
+ bool mSuspended;
+ int mBytesWritten;
+ bool mMasterMute;
+ SortedVector< wp<Track> > mActiveTracks;
+ private:
friend class AudioFlinger;
friend class Track;
friend class TrackBase;
- friend class RecordTrack;
-
- MixerThread(const Client&);
- MixerThread& operator = (const MixerThread&);
-
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+
+ PlaybackThread(const Client&);
+ PlaybackThread& operator = (const PlaybackThread&);
+
status_t addTrack_l(const sp<Track>& track);
void destroyTrack_l(const sp<Track>& track);
- int getTrackName_l();
- void deleteTrackName_l(int name);
- void addActiveTrack_l(const wp<Track>& t);
- void removeActiveTrack_l(const wp<Track>& t);
- size_t getOutputFrameCount();
+ virtual int getTrackName_l() = 0;
+ virtual void deleteTrackName_l(int name) = 0;
+ void readOutputParameters();
- status_t dumpInternals(int fd, const Vector<String16>& args);
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
-
- sp<AudioFlinger> mAudioFlinger;
- SortedVector< wp<Track> > mActiveTracks;
+
SortedVector< sp<Track> > mTracks;
- stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
- AudioMixer* mAudioMixer;
+ // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
+ stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES + 1];
AudioStreamOut* mOutput;
- int mOutputType;
- uint32_t mSampleRate;
- size_t mFrameCount;
- int mChannelCount;
- int mFormat;
- int16_t* mMixBuffer;
float mMasterVolume;
- bool mMasterMute;
nsecs_t mLastWriteTime;
int mNumWrites;
int mNumDelayedWrites;
- bool mStandby;
bool mInWrite;
- sp <OutputTrack> mOutputTrack;
+ int mMinBytesToWrite;
+ };
+
+ class MixerThread : public PlaybackThread {
+ public:
+ MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~MixerThread();
+
+ // 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);
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ protected:
+ size_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
+
+ AudioMixer* mAudioMixer;
+ };
+
+ class DirectOutputThread : public PlaybackThread {
+ public:
+
+ DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ ~DirectOutputThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+
+ private:
+ float mLeftVolume;
+ float mRightVolume;
};
-
+ class DuplicatingThread : public MixerThread {
+ public:
+ DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread);
+ ~DuplicatingThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ void addOutputTrack(MixerThread* thread);
+ void removeOutputTrack(MixerThread* thread);
+
+ private:
+ SortedVector < sp<OutputTrack> > mOutputTracks;
+ };
+
+ PlaybackThread *checkPlaybackThread_l(void *output) const;
+ MixerThread *checkMixerThread_l(void *output) const;
+ RecordThread *checkRecordThread_l(void *input) const;
+ float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
+
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
public:
- TrackHandle(const sp<MixerThread::Track>& track);
+ TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual status_t start();
virtual void stop();
@@ -553,20 +636,91 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::Track> mTrack;
+ sp<PlaybackThread::Track> mTrack;
};
friend class Client;
- friend class MixerThread::Track;
+ friend class PlaybackThread::Track;
void removeClient(pid_t pid);
+ // record thread
+ class RecordThread : public ThreadBase, public AudioBufferProvider
+ {
+ public:
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack(const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class RecordThread;
+
+ RecordTrack(const RecordTrack&);
+ RecordTrack& operator = (const RecordTrack&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
+ };
+
+
+ RecordThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamIn *input,
+ uint32_t sampleRate,
+ uint32_t channels);
+ ~RecordThread();
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun() { return NO_ERROR; }
+ virtual void onFirstRef();
+
+ status_t start(RecordTrack* recordTrack);
+ void stop(RecordTrack* recordTrack);
+ status_t dump(int fd, const Vector<String16>& args);
+ AudioStreamIn* getInput() { return mInput; }
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual bool checkForNewParameters_l();
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+ void readInputParameters();
+
+ private:
+ RecordThread();
+ AudioStreamIn *mInput;
+ sp<RecordTrack> mActiveTrack;
+ Condition mStartStopCond;
+ AudioResampler *mResampler;
+ int32_t *mRsmpOutBuffer;
+ int16_t *mRsmpInBuffer;
+ size_t mRsmpInIndex;
+ size_t mInputBytes;
+ int mReqChannelCount;
+ uint32_t mReqSampleRate;
+ };
class RecordHandle : public android::BnAudioRecord {
public:
- RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
+ RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual status_t start();
virtual void stop();
@@ -574,66 +728,30 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::RecordTrack> mRecordTrack;
+ sp<RecordThread::RecordTrack> mRecordTrack;
};
- // record thread
- class AudioRecordThread : public Thread
- {
- public:
- AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
- virtual ~AudioRecordThread();
- virtual bool threadLoop();
- virtual status_t readyToRun() { return NO_ERROR; }
- virtual void onFirstRef() {}
-
- status_t start(MixerThread::RecordTrack* recordTrack);
- void stop(MixerThread::RecordTrack* recordTrack);
- void exit();
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- AudioRecordThread();
- AudioHardwareInterface *mAudioHardware;
- sp<AudioFlinger> mAudioFlinger;
- sp<MixerThread::RecordTrack> mRecordTrack;
- Mutex mLock;
- Condition mWaitWorkCV;
- Condition mStopped;
- volatile bool mActive;
- status_t mStartStatus;
- };
+ friend class RecordThread;
+ friend class PlaybackThread;
- friend class AudioRecordThread;
- friend class MixerThread;
- status_t startRecord(MixerThread::RecordTrack* recordTrack);
- void stopRecord(MixerThread::RecordTrack* recordTrack);
-
- mutable Mutex mHardwareLock;
mutable Mutex mLock;
- mutable Condition mWaitWorkCV;
DefaultKeyedVector< pid_t, wp<Client> > mClients;
- sp<MixerThread> mA2dpMixerThread;
- sp<MixerThread> mHardwareMixerThread;
+ mutable Mutex mHardwareLock;
AudioHardwareInterface* mAudioHardware;
- AudioHardwareInterface* mA2dpAudioInterface;
- sp<AudioRecordThread> mAudioRecordThread;
- bool mA2dpEnabled;
- bool mNotifyA2dpChange;
mutable int mHardwareStatus;
- SortedVector< wp<IBinder> > mNotificationClients;
- int mForcedSpeakerCount;
- int mA2dpDisableCount;
-
- // true if A2DP should resume when mA2dpDisableCount returns to zero
- bool mA2dpSuppressed;
- uint32_t mSavedRoute;
- uint32_t mForcedRoute;
- nsecs_t mRouteRestoreTime;
- bool mMusicMuteSaved;
+
+
+ SortedVector< sp<PlaybackThread> > mPlaybackThreads;
+ PlaybackThread::stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ float mMasterVolume;
+ bool mMasterMute;
+
+ SortedVector< sp<RecordThread> > mRecordThreads;
+
+ SortedVector< sp<IBinder> > mNotificationClients;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 1e159b8..57874f3 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -49,8 +49,8 @@ AudioHardwareGeneric::AudioHardwareGeneric()
AudioHardwareGeneric::~AudioHardwareGeneric()
{
if (mFd >= 0) ::close(mFd);
- delete mOutput;
- delete mInput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ closeInputStream((AudioStreamIn *)mInput);
}
status_t AudioHardwareGeneric::initCheck()
@@ -63,7 +63,7 @@ status_t AudioHardwareGeneric::initCheck()
}
AudioStreamOut* AudioHardwareGeneric::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AutoMutex lock(mLock);
@@ -77,7 +77,7 @@ AudioStreamOut* AudioHardwareGeneric::openOutputStream(
// create new output stream
AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
- status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+ status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -89,17 +89,19 @@ AudioStreamOut* AudioHardwareGeneric::openOutputStream(
return mOutput;
}
-void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
- if (out == mOutput) mOutput = 0;
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput && out == mOutput) {
+ delete mOutput;
+ mOutput = 0;
+ }
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
@@ -115,7 +117,7 @@ AudioStreamIn* AudioHardwareGeneric::openInputStream(
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -127,8 +129,11 @@ AudioStreamIn* AudioHardwareGeneric::openInputStream(
return mInput;
}
-void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
- if (in == mInput) mInput = 0;
+void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
+ if (mInput && in == mInput) {
+ delete mInput;
+ mInput = 0;
+ }
}
status_t AudioHardwareGeneric::setVoiceVolume(float v)
@@ -185,30 +190,42 @@ status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
status_t AudioStreamOutGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate)
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate)
{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
AudioStreamOutGeneric::~AudioStreamOutGeneric()
{
- if (mAudioHardware)
- mAudioHardware->closeOutputStream(this);
}
ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
@@ -234,10 +251,12 @@ status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -246,29 +265,68 @@ status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamOutGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
// record functions
status_t AudioStreamInGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+ if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
+ LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate())) {
+ if ((*pFormat != format()) ||
+ (*pChannels != channels()) ||
+ (*pRate != sampleRate())) {
LOGE("Error opening input channel");
+ *pFormat = format();
+ *pChannels = channels();
+ *pRate = sampleRate();
return BAD_VALUE;
}
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
@@ -276,14 +334,12 @@ AudioStreamInGeneric::~AudioStreamInGeneric()
{
// FIXME: remove logging
LOGD("AudioStreamInGeneric destructor");
- if (mAudioHardware)
- mAudioHardware->closeInputStream(this);
}
ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+ LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, (int)bytes, mFd);
AutoMutex lock(mLock);
if (mFd < 0) {
LOGE("Attempt to read from unopened device");
@@ -303,10 +359,12 @@ status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -315,6 +373,39 @@ status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamInGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index c89df87..42da413 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -39,24 +39,28 @@ public:
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate);
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 20; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
class AudioStreamInGeneric : public AudioStreamIn {
@@ -67,24 +71,28 @@ public:
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics);
- uint32_t sampleRate() const { return 8000; }
+ virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return INVALID_OPERATION; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
@@ -101,28 +109,27 @@ public:
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
private:
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index cc1bd8f..37be329 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -18,6 +18,7 @@
#include <cutils/properties.h>
#include <string.h>
#include <unistd.h>
+//#define LOG_NDEBUG 0
#define LOG_TAG "AudioHardwareInterface"
#include <utils/Log.h>
@@ -25,15 +26,17 @@
#include "AudioHardwareStub.h"
#include "AudioHardwareGeneric.h"
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
-//#define DUMP_FLINGER_OUT // if defined allows recording samples in a file
-#ifdef DUMP_FLINGER_OUT
+#ifdef ENABLE_AUDIO_DUMP
#include "AudioDumpInterface.h"
#endif
// change to 1 to log routing calls
-#define LOG_ROUTING_CALLS 0
+#define LOG_ROUTING_CALLS 1
namespace android {
@@ -48,14 +51,6 @@ static const char* routingModeStrings[] =
"IN_CALL"
};
-static const char* routeStrings[] =
-{
- "EARPIECE ",
- "SPEAKER ",
- "BLUETOOTH ",
- "HEADSET ",
- "BLUETOOTH_A2DP "
-};
static const char* routeNone = "NONE";
static const char* displayMode(int mode)
@@ -64,22 +59,6 @@ static const char* displayMode(int mode)
return routingModeStrings[0];
return routingModeStrings[mode+3];
}
-
-static const char* displayRoutes(uint32_t routes)
-{
- static char routeStr[80];
- if (routes == 0)
- return routeNone;
- routeStr[0] = 0;
- int bitMask = 1;
- for (int i = 0; i < 4; ++i, bitMask <<= 1) {
- if (routes & bitMask) {
- strcat(routeStr, routeStrings[i]);
- }
- }
- routeStr[strlen(routeStr)-1] = 0;
- return routeStr;
-}
#endif
// ----------------------------------------------------------------------------
@@ -112,13 +91,17 @@ AudioHardwareInterface* AudioHardwareInterface::create()
hw = new AudioHardwareStub();
}
-#ifdef DUMP_FLINGER_OUT
+#ifdef WITH_A2DP
+ hw = new A2dpAudioInterface(hw);
+#endif
+
+#ifdef ENABLE_AUDIO_DUMP
// This code adds a record of buffers in a file to write calls made by AudioFlinger.
// It replaces the current AudioHardwareInterface object by an intermediate one which
// will record buffers in a file (after sending them to hardware) for testing purpose.
- // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
- // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
-
+ // This feature is enabled by defining symbol ENABLE_AUDIO_DUMP.
+ // The output file is set with setParameters("test_cmd_file_name=<name>"). Pause are not recorded in the file.
+ LOGV("opening PCM dump interface");
hw = new AudioDumpInterface(hw); // replace interface
#endif
return hw;
@@ -132,48 +115,9 @@ AudioStreamIn::~AudioStreamIn() {}
AudioHardwareBase::AudioHardwareBase()
{
- // force a routing update on initialization
- memset(&mRoutes, 0, sizeof(mRoutes));
mMode = 0;
}
-// generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
-{
-#if LOG_ROUTING_CALLS
- LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
-#endif
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- uint32_t old = mRoutes[mode];
- mRoutes[mode] = routes;
- if ((mode != mMode) || (old == routes))
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- const char* oldRouteStr = strdup(displayRoutes(old));
- LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
- displayMode(mode), oldRouteStr, displayRoutes(routes));
- delete oldRouteStr;
-#endif
- return doRouting();
-}
-
-status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
-{
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- *routes = mRoutes[mode];
-#if LOG_ROUTING_CALLS
- LOGD("getRouting: mode=%s, routes=[%s]",
- displayMode(mode), displayRoutes(*routes));
-#endif
- return NO_ERROR;
-}
-
status_t AudioHardwareBase::setMode(int mode)
{
#if LOG_ROUTING_CALLS
@@ -182,29 +126,24 @@ status_t AudioHardwareBase::setMode(int mode)
if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
return BAD_VALUE;
if (mMode == mode)
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
- displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
-#endif
+ return ALREADY_EXISTS;
mMode = mode;
- return doRouting();
+ return NO_ERROR;
}
-status_t AudioHardwareBase::getMode(int* mode)
+// default implementation
+status_t AudioHardwareBase::setParameters(const String8& keyValuePairs)
{
- // Implement: set audio routing
- *mode = mMode;
return NO_ERROR;
}
-status_t AudioHardwareBase::setParameter(const char* key, const char* value)
+// default implementation
+String8 AudioHardwareBase::getParameters(const String8& keys)
{
- // default implementation is to ignore
- return NO_ERROR;
+ String8 result = String8("");
+ return result;
}
-
// default implementation
size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
@@ -233,10 +172,6 @@ status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
result.append(buffer);
- for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
- snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
- result.append(buffer);
- }
::write(fd, result.string(), result.size());
dump(fd, args); // Dump the state of the concrete child.
return NO_ERROR;
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0ab4c60..1a03059 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -43,10 +43,10 @@ status_t AudioHardwareStub::initCheck()
}
AudioStreamOut* AudioHardwareStub::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AudioStreamOutStub* out = new AudioStreamOutStub();
- status_t lStatus = out->set(format, channelCount, sampleRate);
+ status_t lStatus = out->set(format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -56,18 +56,22 @@ AudioStreamOut* AudioHardwareStub::openOutputStream(
return 0;
}
+void AudioHardwareStub::closeOutputStream(AudioStreamOut* out)
+{
+ delete out;
+}
+
AudioStreamIn* AudioHardwareStub::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
AudioStreamInStub* in = new AudioStreamInStub();
- status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -77,6 +81,11 @@ AudioStreamIn* AudioHardwareStub::openInputStream(
return 0;
}
+void AudioHardwareStub::closeInputStream(AudioStreamIn* in)
+{
+ delete in;
+}
+
status_t AudioHardwareStub::setVoiceVolume(float volume)
{
return NO_ERROR;
@@ -107,24 +116,19 @@ status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
// ----------------------------------------------------------------------------
-status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- // fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
{
// fake timing for audio output
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
return bytes;
}
@@ -141,7 +145,7 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
::write(fd, result.string(), result.size());
@@ -150,20 +154,16 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
// ----------------------------------------------------------------------------
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
{
// fake timing for audio input
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
memset(buffer, 0, bytes);
return bytes;
}
@@ -179,7 +179,7 @@ status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index bf63cc5..8f43259 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -29,29 +29,33 @@ namespace android {
class AudioStreamOutStub : public AudioStreamOut {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 0; }
- virtual status_t setVolume(float volume) { return NO_ERROR; }
+ virtual status_t setVolume(float left, float right) { return NO_ERROR; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys) {String8 result = String8(""); return result;}
};
class AudioStreamInStub : public AudioStreamIn {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics);
virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return NO_ERROR; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys) {String8 result = String8(""); return result;}
};
class AudioHardwareStub : public AudioHardwareBase
@@ -67,26 +71,25 @@ public:
virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
- AudioSystem::audio_in_acoustics acoustics);
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
bool mMicMute;
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index b02efcc..19a442a 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -610,7 +610,6 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->in = in;
}
-inline
void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
{
for (size_t i=0 ; i<c ; i++) {
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 72ca28a..15766cd 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -85,6 +85,8 @@ public:
uint32_t trackNames() const { return mTrackNames; }
+ static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
private:
enum {
@@ -176,7 +178,6 @@ private:
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
static void process__validate(state_t* state, void* output);
static void process__nop(state_t* state, void* output);
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
new file mode 100644
index 0000000..4b31815
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
@@ -0,0 +1,753 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "AudioPolicyManagerGeneric"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManagerGeneric.h"
+#include <media/mediarecorder.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+
+ LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ LOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (AudioSystem::isOutputDevice(device)) {
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() connecting device %x", device);
+
+ // register new device as available
+ mAvailableOutputDevices |= device;
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableOutputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+ // handle input devices
+ if (AudioSystem::isInputDevice(device)) {
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableInputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices |= device;
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableInputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+
+ LOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (AudioSystem::isOutputDevice(device)) {
+ if (device & mAvailableOutputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (AudioSystem::isInputDevice(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+void AudioPolicyManagerGeneric::setPhoneState(int state)
+{
+ LOGV("setPhoneState() state %d", state);
+ uint32_t newDevice = 0;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ LOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ LOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+
+ // if leaving or entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (state == AudioSystem::MODE_IN_CALL ||
+ oldState == AudioSystem::MODE_IN_CALL) {
+ bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false;
+ LOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, starting);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ LOGV("setRingerMode() mode %x, mask %x", mode, mask);
+
+ mRingerMode = mode;
+}
+
+void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+ mForceUse[usage] = config;
+}
+
+AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage)
+{
+ return mForceUse[usage];
+}
+
+void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value)
+{
+ LOGV("setSystemProperty() property %s, value %s", property, value);
+ if (strcmp(property, "ro.camera.sound.forced") == 0) {
+ if (atoi(value)) {
+ LOGV("ENFORCED_AUDIBLE cannot be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
+ } else {
+ LOGV("ENFORCED_AUDIBLE can be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
+ }
+ }
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mCurOutput != 0) {
+ LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelcount %d, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannelcount, mDirectOutput);
+
+ if (mTestOutputs[mCurOutput] == 0) {
+ LOGV("getOutput() opening test output");
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = mTestDevice;
+ outputDesc->mSamplingRate = mTestSamplingRate;
+ outputDesc->mFormat = mTestFormat;
+ outputDesc->mChannels = (mTestChannelcount == 1) ? AudioSystem::CHANNEL_OUT_MONO : AudioSystem::CHANNEL_OUT_STEREO;
+ outputDesc->mLatency = mTestLatencyMs;
+ outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+ outputDesc->mRefCount[stream] = 0;
+ mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
+ }
+ return mTestOutputs[mCurOutput];
+ }
+#endif //AUDIO_POLICY_TEST
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != 0 && !AudioSystem::isLinearPCM(format)) ||
+ (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ return NULL;
+ }
+
+ return mHardwareOutput;
+}
+
+status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("startOutput() output %p, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("startOutput() unknow output %p", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, true);
+ }
+
+ // incremenent usage count for this stream on the requested output:
+ outputDesc->changeRefCount(stream, 1);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("stopOutput() output %p, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("stopOutput() unknow output %p", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, false);
+ }
+
+ if (outputDesc->isUsedByStream(stream)) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ return NO_ERROR;
+ } else {
+ LOGW("stopOutput() refcount is already 0 for output %p", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
+{
+ LOGV("releaseOutput() %p", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("releaseOutput() releasing unknown output %p", output);
+ return;
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ int testIndex = testOutputIndex(output);
+ if (testIndex != 0) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ if (outputDesc->refCount() == 0) {
+ mpClientInterface->closeOutput(output);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mTestOutputs[testIndex] = 0;
+ }
+ }
+#endif //AUDIO_POLICY_TEST
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ uint32_t device;
+
+ LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
+ inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = format;
+ inputDesc->mChannels = channels;
+ inputDesc->mAcoustics = acoustics;
+ inputDesc->mRefCount = 0;
+ input = mpClientInterface->openInput(&inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannels,
+ inputDesc->mAcoustics);
+
+ // only accept input with the exact requested set of parameters
+ if ((samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channels != inputDesc->mChannels)) {
+ LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d",
+ samplingRate, format, channels);
+ mpClientInterface->closeInput(input);
+ delete inputDesc;
+ return NULL;
+ }
+ mInputs.add(input, inputDesc);
+ return input;
+}
+
+status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
+{
+ LOGV("startInput() input %p", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("startInput() unknow input %p", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+ {
+ // refuse 2 active AudioRecord clients at the same time
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ if (mInputs.valueAt(i)->mRefCount > 0) {
+ LOGW("startInput() input %p, other input %p already started", input, mInputs.keyAt(i));
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
+{
+ LOGV("stopInput() input %p", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("stopInput() unknow input %p", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ LOGW("stopInput() input %p already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ inputDesc->mRefCount = 0;
+ return NO_ERROR;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
+{
+ LOGV("releaseInput() %p", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("releaseInput() releasing unknown input %p", input);
+ return;
+ }
+ mpClientInterface->closeInput(input);
+ delete mInputs.valueAt(index);
+ mInputs.removeItem(input);
+}
+
+
+
+void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ mStreams[stream].mIndexMin = indexMin;
+ mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+
+ if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
+ mStreams[stream].mIndexCur = index;
+
+ // do not change actual stream volume if the stream is muted
+ if (mStreams[stream].mMuteCount != 0) {
+ return NO_ERROR;
+ }
+
+ // Do not changed in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ // compute and apply stream volume on all outputs according to connected device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ uint32_t device = outputDesc->device();
+
+ float volume = computeVolume((int)stream, index, device);
+
+ LOGV("setStreamVolume() for output %p stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
+ mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (index == 0) {
+ return BAD_VALUE;
+ }
+ LOGV("getStreamVolumeIndex() stream %d", stream);
+ *index = mStreams[stream].mIndexCur;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerGeneric
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface)
+ :
+#ifdef AUDIO_POLICY_TEST
+ Thread(false),
+#endif //AUDIO_POLICY_TEST
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0)
+{
+ mpClientInterface = clientInterface;
+
+ for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+ mForceUse[i] = AudioSystem::FORCE_NONE;
+ }
+
+ // devices available by default are speaker, ear piece and microphone
+ mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER;
+ mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+
+ // open hardware output
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+
+ if (mHardwareOutput == 0) {
+ LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannelcount = 2;
+ mTestLatencyMs = 0;
+ mCurOutput = 0;
+ mDirectOutput = false;
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ mTestOutputs[i] = 0;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric()
+{
+#ifdef AUDIO_POLICY_TEST
+ exit();
+#endif //AUDIO_POLICY_TEST
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ mpClientInterface->closeOutput(mOutputs.keyAt(i));
+ delete mOutputs.valueAt(i);
+ }
+ mOutputs.clear();
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mpClientInterface->closeInput(mInputs.keyAt(i));
+ delete mInputs.valueAt(i);
+ }
+ mInputs.clear();
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerGeneric::threadLoop()
+{
+ LOGV("entering threadLoop()");
+ while (!exitPending())
+ {
+ Mutex::Autolock _l(mLock);
+ mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+ String8 command;
+ command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+ if (command != "") {
+ LOGV("Test command %s received", command.string());
+ AudioParameter param = AudioParameter(command);
+ int valueInt;
+ String8 value;
+ if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_output"));
+ mCurOutput = valueInt;
+ }
+ if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_direct"));
+ if (value == "false") {
+ mDirectOutput = false;
+ } else if (value == "true") {
+ mDirectOutput = true;
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_input"));
+ mTestInput = valueInt;
+ }
+
+ if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_format"));
+ if (value == "PCM 16 bits") {
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ } else if (value == "PCM 8 bits") {
+ mTestFormat = AudioSystem::PCM_8_BIT;
+ } else if (value == "Compressed MP3") {
+ mTestFormat = AudioSystem::MP3;
+ }
+ }
+ if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_channels"));
+ if (value == "Channels Stereo") {
+ mTestChannelcount = 2;
+ } else if (value == "Channels Mono") {
+ mTestChannelcount = 1;
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_sampleRate"));
+ if (valueInt >= 0 && valueInt <= 96000) {
+ mTestSamplingRate = valueInt;
+ }
+ }
+ mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+ }
+ }
+ return false;
+}
+
+void AudioPolicyManagerGeneric::exit()
+{
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output)
+{
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ if (output == mTestOutputs[i]) return i;
+ }
+ return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream)
+{
+ // stream to strategy mapping
+ switch (stream) {
+ case AudioSystem::VOICE_CALL:
+ case AudioSystem::BLUETOOTH_SCO:
+ return STRATEGY_PHONE;
+ case AudioSystem::RING:
+ case AudioSystem::NOTIFICATION:
+ case AudioSystem::ALARM:
+ case AudioSystem::ENFORCED_AUDIBLE:
+ return STRATEGY_SONIFICATION;
+ case AudioSystem::DTMF:
+ return STRATEGY_DTMF;
+ default:
+ LOGE("unknown stream type");
+ case AudioSystem::SYSTEM:
+ // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+ // while key clicks are played produces a poor result
+ case AudioSystem::TTS:
+ case AudioSystem::MUSIC:
+ return STRATEGY_MEDIA;
+ }
+}
+
+
+float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device)
+{
+ float volume = 1.0;
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ // Force max volume if stream cannot be muted
+ if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax;
+
+ int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
+ volume = AudioSystem::linearToLog(volInt);
+
+ return volume;
+}
+
+void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
+{
+ LOGV("setStreamMute() stream %d, mute %d, output %p", stream, on, output);
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ if (on) {
+ if (streamDesc.mMuteCount++ == 0) {
+ if (streamDesc.mCanBeMuted) {
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output);
+ }
+ }
+ } else {
+ if (streamDesc.mMuteCount == 0) {
+ LOGW("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if (--streamDesc.mMuteCount == 0) {
+ uint32_t device = mOutputs.valueFor(output)->mDevice;
+ float volume = computeVolume(stream, streamDesc.mIndexCur, device);
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting)
+{
+ // if the stream pertains to sonification strategy and we are in call we must
+ // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+ // in the device used for phone strategy and play the tone if the selected device does not
+ // interfere with the device used for phone strategy
+ if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
+ LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice);
+ if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) {
+ if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+ LOGV("handleIncallSonification() low visibility");
+ setStreamMute(stream, starting, mHardwareOutput);
+ } else {
+ if (starting) {
+ mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+ } else {
+ mpClientInterface->stopTone();
+ }
+ }
+ }
+ }
+}
+
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
+ mFlags((AudioSystem::output_flags)0), mDevice(0)
+{
+ // clear usage count for all stream types
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ mRefCount[i] = 0;
+ }
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device()
+{
+ return mDevice;
+}
+
+void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+ if ((delta + (int)mRefCount[stream]) < 0) {
+ LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount()
+{
+ uint32_t refcount = 0;
+ for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+ refcount += mRefCount[i];
+ }
+ return refcount;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
+{
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
new file mode 100644
index 0000000..ddcb306
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+#define NUM_TEST_OUTPUTS 5
+
+class AudioPolicyManagerGeneric: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+ AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface);
+ virtual ~AudioPolicyManagerGeneric();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual void setPhoneState(int state);
+ virtual void setRingerMode(uint32_t mode, uint32_t mask);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics);
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual void initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+private:
+
+ enum routing_strategy {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_DTMF,
+ NUM_STRATEGIES
+ };
+
+ // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+ // and keep track of the usage of this output by each audio stream type.
+ class AudioOutputDescriptor
+ {
+ public:
+ AudioOutputDescriptor();
+
+
+ uint32_t device();
+ void changeRefCount(AudioSystem::stream_type, int delta);
+ bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; }
+ uint32_t refCount();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ AudioSystem::output_flags mFlags; //
+ uint32_t mDevice; // current device this output is routed to
+ uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
+ };
+
+ // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+ // and keep track of the usage of this input.
+ class AudioInputDescriptor
+ {
+ public:
+ AudioInputDescriptor();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; // input configuration
+ uint32_t mChannels; //
+ AudioSystem::audio_in_acoustics mAcoustics; //
+ uint32_t mDevice; // current device this input is routed to
+ uint32_t mRefCount; // number of AudioRecord clients using this output
+ };
+
+ // stream descriptor used for volume control
+ class StreamDescriptor
+ {
+ public:
+ StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {}
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ int mIndexCur; // current volume index
+ int mMuteCount; // mute request counter
+ bool mCanBeMuted; // true is the stream can be muted
+ };
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+ // return the output handle of an output routed to the specified device, 0 if no output
+ // is routed to the device
+ float computeVolume(int stream, int index, uint32_t device);
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(int stream, bool on, audio_io_handle_t output);
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(int stream, bool starting);
+
+
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+
+ AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
+ audio_io_handle_t mHardwareOutput; // hardware output handler
+
+ KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; // list ot output descritors
+ KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors
+ uint32_t mAvailableOutputDevices; // bit field of all available output devices
+ uint32_t mAvailableInputDevices; // bit field of all available input devices
+ int mPhoneState; // current phone state
+ uint32_t mRingerMode; // current ringer mode
+ AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
+
+ StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannelcount;
+ uint32_t mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+};
+
+};
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
new file mode 100644
index 0000000..7f6c4ed
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "AudioPolicyService"
+//#define LOG_NDEBUG 0
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <binder/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include "AudioPolicyService.h"
+#include "AudioPolicyManagerGeneric.h"
+#include <cutils/properties.h>
+#include <dlfcn.h>
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+namespace android {
+
+static bool checkPermission() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+ if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioPolicyService::AudioPolicyService()
+ : BnAudioPolicyService() , mpPolicyManager(NULL)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ // start tone playback thread
+ mTonePlaybacThread = new AudioCommandThread();
+ // start audio commands thread
+ mAudioCommandThread = new AudioCommandThread();
+
+#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ LOGV("build for GENERIC_AUDIO - using generic audio policy");
+#else
+ // if running in emulation - use the emulator driver
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ LOGV("Running in emulation - using generic audio policy");
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ }
+ else {
+ LOGV("Using hardware specific audio policy");
+ mpPolicyManager = createAudioPolicyManager(this);
+ }
+#endif
+
+ // load properties
+ property_get("ro.camera.sound.forced", value, "0");
+ mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+}
+
+AudioPolicyService::~AudioPolicyService()
+{
+ mTonePlaybacThread->exit();
+ mTonePlaybacThread.clear();
+ mAudioCommandThread->exit();
+ mAudioCommandThread.clear();
+
+ if (mpPolicyManager) {
+ delete mpPolicyManager;
+ }
+}
+
+
+status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
+ return BAD_VALUE;
+ }
+ if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setDeviceConnectionState() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ return mpPolicyManager->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioPolicyService::setPhoneState(int state)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setPhoneState() tid %d", gettid());
+
+ // TODO: check if it is more appropriate to do it in platform specific policy manager
+ AudioSystem::setMode(state);
+
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setPhoneState(state);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+
+ mpPolicyManager->setRingerMode(mode, mask);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return BAD_VALUE;
+ }
+ if (config < 0 || config >= AudioSystem::NUM_FORCE_CONFIG) {
+ return BAD_VALUE;
+ }
+ LOGV("setForceUse() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setForceUse(usage, config);
+ return NO_ERROR;
+}
+
+AudioSystem::forced_config AudioPolicyService::getForceUse(AudioSystem::force_use usage)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return AudioSystem::FORCE_NONE;
+ }
+ return mpPolicyManager->getForceUse(usage);
+}
+
+audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ if (mpPolicyManager == NULL) {
+ return NULL;
+ }
+ LOGV("getOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);
+}
+
+status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("startOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startOutput(output, stream);
+}
+
+status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("stopOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopOutput(output, stream);
+}
+
+void AudioPolicyService::releaseOutput(audio_io_handle_t output)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ LOGV("releaseOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ if (mpPolicyManager == NULL) {
+ return NULL;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+
+status_t AudioPolicyService::startInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startInput(input);
+}
+
+status_t AudioPolicyService::stopInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopInput(input);
+}
+
+void AudioPolicyService::releaseInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseInput(input);
+}
+
+status_t AudioPolicyService::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ mpPolicyManager->initStreamVolume(stream, indexMin, indexMax);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+ return mpPolicyManager->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ return mpPolicyManager->getStreamVolumeIndex(stream, index);
+}
+
+void AudioPolicyService::binderDied(const wp<IBinder>& who) {
+ LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+}
+
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd, args);
+ } else {
+
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioPolicyService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioPolicyService::onTransact(code, data, reply, flags);
+}
+
+
+// ----------------------------------------------------------------------------
+void AudioPolicyService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.audio_policy"), new AudioPolicyService());
+}
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyClientInterface implementation
+// ----------------------------------------------------------------------------
+
+
+audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openOutput() could not get AudioFlinger");
+ return NULL;
+ }
+
+ return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
+}
+
+audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openDuplicateOutput() could not get AudioFlinger");
+ return NULL;
+ }
+ return af->openDuplicateOutput(output1, output2);
+}
+
+status_t AudioPolicyService::closeOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeOutput(output);
+}
+
+
+status_t AudioPolicyService::suspendOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("suspendOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->suspendOutput(output);
+}
+
+status_t AudioPolicyService::restoreOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("restoreOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->restoreOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openInput() could not get AudioFlinger");
+ return NULL;
+ }
+
+ return af->openInput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, acoustics);
+}
+
+status_t AudioPolicyService::closeInput(audio_io_handle_t input)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeInput(input);
+}
+
+status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output)
+{
+ return mAudioCommandThread->volumeCommand((int)stream, volume, (void *)output);
+}
+
+status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->setStreamOutput(stream, output);
+}
+
+
+void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+{
+ mAudioCommandThread->parametersCommand((void *)ioHandle, keyValuePairs);
+}
+
+String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+ String8 result = AudioSystem::getParameters(ioHandle, keys);
+ return result;
+}
+
+status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
+{
+ mTonePlaybacThread->startToneCommand(tone, stream);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::stopTone()
+{
+ mTonePlaybacThread->stopToneCommand();
+ return NO_ERROR;
+}
+
+
+// ----------- AudioPolicyService::AudioCommandThread implementation ----------
+
+AudioPolicyService::AudioCommandThread::AudioCommandThread()
+ : Thread(false)
+{
+ mpToneGenerator = NULL;
+}
+
+
+AudioPolicyService::AudioCommandThread::~AudioCommandThread()
+{
+ mAudioCommands.clear();
+ if (mpToneGenerator != NULL) delete mpToneGenerator;
+}
+
+void AudioPolicyService::AudioCommandThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "AudioCommandThread");
+
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+}
+
+bool AudioPolicyService::AudioCommandThread::threadLoop()
+{
+ mLock.lock();
+ while (!exitPending())
+ {
+ while(!mAudioCommands.isEmpty()) {
+ AudioCommand *command = mAudioCommands[0];
+ mAudioCommands.removeAt(0);
+ switch (command->mCommand) {
+ case START_TONE: {
+ mLock.unlock();
+ ToneData *data = (ToneData *)command->mParam;
+ LOGV("AudioCommandThread() processing start tone %d on stream %d",
+ data->mType, data->mStream);
+ if (mpToneGenerator != NULL)
+ delete mpToneGenerator;
+ mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
+ mpToneGenerator->startTone(data->mType);
+ delete data;
+ mLock.lock();
+ }break;
+ case STOP_TONE: {
+ mLock.unlock();
+ LOGV("AudioCommandThread() processing stop tone");
+ if (mpToneGenerator != NULL) {
+ mpToneGenerator->stopTone();
+ delete mpToneGenerator;
+ mpToneGenerator = NULL;
+ }
+ mLock.lock();
+ }break;
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %p", data->mStream, data->mVolume, data->mIO);
+ mCommandStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+ mCommandCond.signal();
+ mWaitWorkCV.wait(mLock);
+ delete data;
+ }break;
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ LOGV("AudioCommandThread() processing set parameters string %s, io %p", data->mKeyValuePairs.string(), data->mIO);
+ mCommandStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ mCommandCond.signal();
+ mWaitWorkCV.wait(mLock);
+ delete data;
+ }break;
+ default:
+ LOGW("AudioCommandThread() unknown command %d", command->mCommand);
+ }
+ delete command;
+ }
+ LOGV("AudioCommandThread() going to sleep");
+ mWaitWorkCV.wait(mLock);
+ LOGV("AudioCommandThread() waking up");
+ }
+ mLock.unlock();
+ return false;
+}
+
+void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stream)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = START_TONE;
+ ToneData *data = new ToneData();
+ data->mType = type;
+ data->mStream = stream;
+ command->mParam = (void *)data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
+ mWaitWorkCV.signal();
+}
+
+void AudioPolicyService::AudioCommandThread::stopToneCommand()
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = STOP_TONE;
+ command->mParam = NULL;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding tone stop");
+ mWaitWorkCV.signal();
+}
+
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, void *output)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_VOLUME;
+ VolumeData *data = new VolumeData();
+ data->mStream = stream;
+ data->mVolume = volume;
+ data->mIO = output;
+ command->mParam = data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %p", stream, volume, output);
+ mWaitWorkCV.signal();
+ mCommandCond.wait(mLock);
+ status_t status = mCommandStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(void *ioHandle, const String8& keyValuePairs)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_PARAMETERS;
+ ParametersData *data = new ParametersData();
+ data->mIO = ioHandle;
+ data->mKeyValuePairs = keyValuePairs;
+ command->mParam = data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding set parameter string %s, io %p", keyValuePairs.string(), ioHandle);
+ mWaitWorkCV.signal();
+ mCommandCond.wait(mLock);
+ status_t status = mCommandStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+void AudioPolicyService::AudioCommandThread::exit()
+{
+ LOGV("AudioCommandThread::exit");
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
new file mode 100644
index 0000000..1c46975
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2009 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_AUDIOPOLICYSERVICE_H
+#define ANDROID_AUDIOPOLICYSERVICE_H
+
+#include <media/IAudioPolicyService.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <media/ToneGenerator.h>
+
+namespace android {
+
+class String8;
+
+// ----------------------------------------------------------------------------
+
+class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient
+{
+
+public:
+ static void instantiate();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ //
+ // BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
+ //
+
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual status_t setPhoneState(int state);
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask);
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0);
+ virtual status_t startInput(audio_io_handle_t input);
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags);
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ //
+ // AudioPolicyClientInterface
+ //
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags);
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2);
+ virtual status_t closeOutput(audio_io_handle_t output);
+ virtual status_t suspendOutput(audio_io_handle_t output);
+ virtual status_t restoreOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+ virtual status_t closeInput(audio_io_handle_t input);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output);
+ virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
+ virtual status_t stopTone();
+
+private:
+ AudioPolicyService();
+ virtual ~AudioPolicyService();
+
+ // Thread used for tone playback and to send audio config commands to audio flinger
+ // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because startTone()
+ // and stopTone() are normally called with mLock locked and requesting a tone start or stop will cause
+ // calls to AudioPolicyService and an attempt to lock mLock.
+ // For audio config commands, it is necessary because audio flinger requires that the calling process (user)
+ // has permission to modify audio settings.
+ class AudioCommandThread : public Thread {
+ public:
+
+ // commands for tone AudioCommand
+ enum {
+ START_TONE,
+ STOP_TONE,
+ SET_VOLUME,
+ SET_PARAMETERS
+ };
+
+ AudioCommandThread ();
+ virtual ~AudioCommandThread();
+
+ // Thread virtuals
+ virtual void onFirstRef();
+ virtual bool threadLoop();
+
+ void exit();
+ void startToneCommand(int type = 0, int stream = 0);
+ void stopToneCommand();
+ status_t volumeCommand(int stream, float volume, void *output);
+ status_t parametersCommand(void *ioHandle, const String8& keyValuePairs);
+
+ private:
+ // descriptor for requested tone playback event
+ class AudioCommand {
+ public:
+ int mCommand; // START_TONE, STOP_TONE ...
+ void *mParam;
+ };
+
+ class ToneData {
+ public:
+ int mType; // tone type (START_TONE only)
+ int mStream; // stream type (START_TONE only)
+ };
+
+ class VolumeData {
+ public:
+ int mStream;
+ float mVolume;
+ void *mIO;
+ };
+ class ParametersData {
+ public:
+ void *mIO;
+ String8 mKeyValuePairs;
+ };
+
+
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ Vector<AudioCommand *> mAudioCommands; // list of pending tone events
+ Condition mCommandCond;
+ status_t mCommandStatus;
+ ToneGenerator *mpToneGenerator; // the tone generator
+ };
+
+ // Internal dump utilities.
+ status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
+
+
+ Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing device
+ // connection stated our routing
+ AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
+ sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
+ sp <AudioCommandThread> mTonePlaybacThread; // tone playback thread
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYSERVICE_H
+
+
+
+
+
+
+
+
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
new file mode 100644
index 0000000..2df6775
--- /dev/null
+++ b/libs/binder/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2009 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+ Binder.cpp \
+ BpBinder.cpp \
+ IInterface.cpp \
+ IMemory.cpp \
+ IPCThreadState.cpp \
+ IPermissionController.cpp \
+ IServiceManager.cpp \
+ MemoryDealer.cpp \
+ MemoryBase.cpp \
+ MemoryHeapBase.cpp \
+ MemoryHeapPmem.cpp \
+ Parcel.cpp \
+ Permission.cpp \
+ ProcessState.cpp \
+ Static.cpp
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libutils
+
+LOCAL_MODULE:= libbinder
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/Binder.cpp b/libs/binder/Binder.cpp
index 37e4685..0dd7622 100644
--- a/libs/utils/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include <utils/Binder.h>
+#include <binder/Binder.h>
#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <stdio.h>
@@ -27,6 +27,17 @@ namespace android {
// ---------------------------------------------------------------------------
+IBinder::IBinder()
+ : RefBase()
+{
+}
+
+IBinder::~IBinder()
+{
+}
+
+// ---------------------------------------------------------------------------
+
sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
{
return NULL;
@@ -58,6 +69,8 @@ public:
// ---------------------------------------------------------------------------
+String16 BBinder::sEmptyDescriptor;
+
BBinder::BBinder()
: mExtras(NULL)
{
@@ -73,10 +86,10 @@ status_t BBinder::pingBinder()
return NO_ERROR;
}
-String16 BBinder::getInterfaceDescriptor() const
+const String16& BBinder::getInterfaceDescriptor() const
{
LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
- return String16();
+ return sEmptyDescriptor;
}
status_t BBinder::transact(
diff --git a/libs/utils/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 69ab195..5de87ec 100644
--- a/libs/utils/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "BpBinder"
//#define LOG_NDEBUG 0
-#include <utils/BpBinder.h>
+#include <binder/BpBinder.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <stdio.h>
@@ -98,16 +98,33 @@ BpBinder::BpBinder(int32_t handle)
IPCThreadState::self()->incWeakHandle(handle);
}
-String16 BpBinder::getInterfaceDescriptor() const
+bool BpBinder::isDescriptorCached() const {
+ Mutex::Autolock _l(mLock);
+ return mDescriptorCache.size() ? true : false;
+}
+
+const String16& BpBinder::getInterfaceDescriptor() const
{
- String16 res;
- Parcel send, reply;
- status_t err = const_cast<BpBinder*>(this)->transact(
- INTERFACE_TRANSACTION, send, &reply);
- if (err == NO_ERROR) {
- res = reply.readString16();
+ if (isDescriptorCached() == false) {
+ Parcel send, reply;
+ // do the IPC without a lock held.
+ status_t err = const_cast<BpBinder*>(this)->transact(
+ INTERFACE_TRANSACTION, send, &reply);
+ if (err == NO_ERROR) {
+ String16 res(reply.readString16());
+ Mutex::Autolock _l(mLock);
+ // mDescriptorCache could have been assigned while the lock was
+ // released.
+ if (mDescriptorCache.size() == 0)
+ mDescriptorCache = res;
+ }
}
- return res;
+
+ // we're returning a reference to a non-static object here. Usually this
+ // is not something smart to do, however, with binder objects it is
+ // (usually) safe because they are reference-counted.
+
+ return mDescriptorCache;
}
bool BpBinder::isBinderAlive() const
diff --git a/libs/utils/IInterface.cpp b/libs/binder/IInterface.cpp
index 6ea8178..29acf5d 100644
--- a/libs/utils/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -14,12 +14,19 @@
* limitations under the License.
*/
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
// ---------------------------------------------------------------------------
+IInterface::IInterface()
+ : RefBase() {
+}
+
+IInterface::~IInterface() {
+}
+
sp<IBinder> IInterface::asBinder()
{
return this ? onAsBinder() : NULL;
diff --git a/libs/utils/IMemory.cpp b/libs/binder/IMemory.cpp
index 429bc2b..6c1d225 100644
--- a/libs/utils/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -25,11 +25,11 @@
#include <sys/types.h>
#include <sys/mman.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/CallStack.h>
#define VERBOSE 0
@@ -205,11 +205,11 @@ sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
+BnMemory::BnMemory() {
+}
+
+BnMemory::~BnMemory() {
+}
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
@@ -299,11 +299,11 @@ void BpMemoryHeap::assertReallyMapped() const
ssize_t size = reply.readInt32();
uint32_t flags = reply.readInt32();
- LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
+ LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",
asBinder().get(), parcel_fd, size, err, strerror(-err));
int fd = dup( parcel_fd );
- LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
+ LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",
parcel_fd, size, err, strerror(errno));
int access = PROT_READ;
@@ -316,7 +316,7 @@ void BpMemoryHeap::assertReallyMapped() const
mRealHeap = true;
mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
if (mBase == MAP_FAILED) {
- LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
+ LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
asBinder().get(), size, fd, strerror(errno));
close(fd);
} else {
@@ -357,8 +357,14 @@ uint32_t BpMemoryHeap::getFlags() const {
IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+BnMemoryHeap::BnMemoryHeap() {
+}
+
+BnMemoryHeap::~BnMemoryHeap() {
+}
+
status_t BnMemoryHeap::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case HEAP_ID: {
diff --git a/libs/utils/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 04ae142..c371a23 100644
--- a/libs/utils/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/TextOutput.h>
#include <utils/threads.h>
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
#include <sys/ioctl.h>
#include <signal.h>
@@ -366,13 +366,8 @@ void IPCThreadState::restoreCallingIdentity(int64_t token)
void IPCThreadState::clearCaller()
{
- if (mProcess->supportsProcesses()) {
- mCallingPid = getpid();
- mCallingUid = getuid();
- } else {
- mCallingPid = -1;
- mCallingUid = -1;
- }
+ mCallingPid = getpid();
+ mCallingUid = getuid();
}
void IPCThreadState::flushCommands()
diff --git a/libs/utils/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index f01d38f..bff4c9b 100644
--- a/libs/utils/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -16,14 +16,14 @@
#define LOG_TAG "PermissionController"
-#include <utils/IPermissionController.h>
+#include <binder/IPermissionController.h>
#include <utils/Debug.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
-#include <private/utils/Static.h>
+#include <private/binder/Static.h>
namespace android {
@@ -55,12 +55,6 @@ IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnPermissionController::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/utils/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 9beeadd..0cf4158 100644
--- a/libs/utils/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -16,16 +16,16 @@
#define LOG_TAG "ServiceManager"
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Debug.h>
-#include <utils/IPCThreadState.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/SystemClock.h>
-#include <private/utils/Static.h>
+#include <private/binder/Static.h>
#include <unistd.h>
@@ -53,14 +53,19 @@ bool checkCallingPermission(const String16& permission)
static String16 _permission("permission");
+
bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
{
IPCThreadState* ipcState = IPCThreadState::self();
- int32_t pid = ipcState->getCallingPid();
- int32_t uid = ipcState->getCallingUid();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
if (outPid) *outPid = pid;
- if (outUid) *outUid= uid;
-
+ if (outUid) *outUid = uid;
+ return checkPermission(permission, pid, uid);
+}
+
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
+{
sp<IPermissionController> pc;
gDefaultServiceManagerLock.lock();
pc = gPermissionController;
@@ -178,12 +183,6 @@ IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnServiceManager::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/utils/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index f25e11c..033066b 100644
--- a/libs/utils/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
namespace android {
diff --git a/libs/utils/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index cf8201b..d5ffe7f 100644
--- a/libs/utils/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -16,13 +16,13 @@
#define LOG_TAG "MemoryDealer"
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
#include <stdint.h>
#include <stdio.h>
@@ -38,7 +38,15 @@
#include <sys/file.h>
namespace android {
+// ----------------------------------------------------------------------------
+HeapInterface::HeapInterface() { }
+HeapInterface::~HeapInterface() { }
+
+// ----------------------------------------------------------------------------
+
+AllocatorInterface::AllocatorInterface() { }
+AllocatorInterface::~AllocatorInterface() { }
// ----------------------------------------------------------------------------
@@ -107,7 +115,7 @@ sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
if (new_memory != 0) {
memory = new Allocation(this, offset, size, new_memory);
} else {
- LOGE("couldn't map [%8x, %d]", offset, size);
+ LOGE("couldn't map [%8lx, %u]", offset, size);
if (size) {
/* NOTE: it's VERY important to not free allocations of size 0
* because they're special as they don't have any record in the
@@ -339,6 +347,10 @@ void SimpleBestFitAllocator::dump_l(String8& result,
// ----------------------------------------------------------------------------
+SharedHeap::SharedHeap()
+ : HeapInterface(), MemoryHeapBase()
+{
+}
SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
: MemoryHeapBase(size, flags, name)
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 8251728..ac38f51 100644
--- a/libs/utils/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -29,7 +29,7 @@
#include <cutils/ashmem.h>
#include <cutils/atomic.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index eba2b30..3806a42 100644
--- a/libs/utils/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -27,8 +27,8 @@
#include <cutils/log.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
@@ -108,7 +108,7 @@ void SubRegionMemory::revoke()
// promote() it.
#if HAVE_ANDROID_OS
- if (mSize != NULL) {
+ if (mSize != 0) {
const sp<MemoryHeapPmem>& heap(getHeap());
int our_fd = heap->heapID();
struct pmem_region sub;
diff --git a/libs/utils/Parcel.cpp b/libs/binder/Parcel.cpp
index b0e3750..f40e4bd 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -17,19 +17,19 @@
#define LOG_TAG "Parcel"
//#define LOG_NDEBUG 0
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
#include <utils/Debug.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/TextOutput.h>
#include <utils/misc.h>
-#include <private/utils/binder_module.h>
+#include <private/binder/binder_module.h>
#include <stdio.h>
#include <stdlib.h>
@@ -441,9 +441,14 @@ status_t Parcel::writeInterfaceToken(const String16& interface)
return writeString16(interface);
}
+bool Parcel::checkInterface(IBinder* binder) const
+{
+ return enforceInterface(binder->getInterfaceDescriptor());
+}
+
bool Parcel::enforceInterface(const String16& interface) const
{
- String16 str = readString16();
+ const String16 str(readString16());
if (str == interface) {
return true;
} else {
diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp
new file mode 100644
index 0000000..fd8fe69
--- /dev/null
+++ b/libs/binder/Permission.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 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 <stdint.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Permission.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+Permission::Permission(char const* name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const String16& name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const Permission& rhs)
+ : mPermissionName(rhs.mPermissionName),
+ mGranted(rhs.mGranted),
+ mPid(rhs.mPid)
+{
+}
+
+Permission::~Permission()
+{
+}
+
+bool Permission::operator < (const Permission& rhs) const
+{
+ return mPermissionName < rhs.mPermissionName;
+}
+
+bool Permission::checkCalling() const
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::check(pid_t pid, uid_t uid) const
+{
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::doCheckPermission(pid_t pid, uid_t uid) const
+{
+ if ((uid == 0) || (pid == mPid)) {
+ // root and ourselves is always okay
+ return true;
+ } else {
+ // see if we already granted this permission for this uid
+ Mutex::Autolock _l(mLock);
+ if (mGranted.indexOf(uid) >= 0)
+ return true;
+ }
+
+ bool granted = checkPermission(mPermissionName, pid, uid);
+ if (granted) {
+ Mutex::Autolock _l(mLock);
+ // no need to check again, the old item will be replaced if it is
+ // already there.
+ mGranted.add(uid);
+ }
+ return granted;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4567df6..d7daf73 100644
--- a/libs/utils/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,19 +18,19 @@
#include <cutils/process_name.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IPCThreadState.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/threads.h>
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
new file mode 100644
index 0000000..12b0308
--- /dev/null
+++ b/libs/binder/Static.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <private/binder/Static.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// ------------ ProcessState.cpp
+
+Mutex gProcessMutex;
+sp<ProcessState> gProcess;
+
+class LibUtilsIPCtStatics
+{
+public:
+ LibUtilsIPCtStatics()
+ {
+ }
+
+ ~LibUtilsIPCtStatics()
+ {
+ IPCThreadState::shutdown();
+ }
+};
+
+static LibUtilsIPCtStatics gIPCStatics;
+
+// ------------ ServiceManager.cpp
+
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
new file mode 100644
index 0000000..6b11a25
--- /dev/null
+++ b/libs/rs/Android.mk
@@ -0,0 +1,117 @@
+ifeq ($(BUILD_RENDERSCRIPT),true)
+
+LOCAL_PATH:=$(call my-dir)
+
+
+# Build rsg-generator ====================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := rsg-generator
+
+# These symbols are normally defined by BUILD_XXX, but we need to define them
+# here so that local-intermediates-dir works.
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+intermediates := $(local-intermediates-dir)
+
+GEN := $(addprefix $(intermediates)/, \
+ lex.yy.c \
+ )
+$(GEN): PRIVATE_CUSTOM_TOOL = flex -o $@ $<
+
+$(intermediates)/lex.yy.c : $(LOCAL_PATH)/spec.lex
+ $(transform-generated-source)
+
+$(LOCAL_PATH)/rsg_generator.c : $(intermediates)/lex.yy.c
+
+LOCAL_SRC_FILES:= \
+ rsg_generator.c
+
+include $(BUILD_HOST_EXECUTABLE)
+
+# TODO: This should go into build/core/config.mk
+RSG_GENERATOR:=$(LOCAL_BUILT_MODULE)
+
+
+
+# Build render script lib ====================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libRS
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+intermediates:= $(local-intermediates-dir)
+
+# Generate custom headers
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApiStructs.h \
+ rsgApiFuncDecl.h \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# Generate custom source files
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApi.cpp \
+ rsgApiReplay.cpp \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+LOCAL_SRC_FILES:= \
+ rsAdapter.cpp \
+ rsAllocation.cpp \
+ rsComponent.cpp \
+ rsContext.cpp \
+ rsDevice.cpp \
+ rsElement.cpp \
+ rsFileA3D.cpp \
+ rsLight.cpp \
+ rsLocklessFifo.cpp \
+ rsObjectBase.cpp \
+ rsMatrix.cpp \
+ rsMesh.cpp \
+ rsProgram.cpp \
+ rsProgramFragment.cpp \
+ rsProgramFragmentStore.cpp \
+ rsProgramVertex.cpp \
+ rsSampler.cpp \
+ rsScript.cpp \
+ rsScriptC.cpp \
+ rsScriptC_Lib.cpp \
+ rsThreadIO.cpp \
+ rsType.cpp \
+ rsTriangleMesh.cpp
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libui libacc
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libRS
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Include the subdirectories ====================
+include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk,\
+ java \
+ ))
+
+endif \ No newline at end of file
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
new file mode 100644
index 0000000..855ea63
--- /dev/null
+++ b/libs/rs/RenderScript.h
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#ifndef RENDER_SCRIPT_H
+#define RENDER_SCRIPT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////////////////////
+//
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsFile;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsType;
+typedef void * RsLight;
+
+typedef void * RsProgramVertex;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+
+RsDevice rsDeviceCreate();
+void rsDeviceDestroy(RsDevice);
+
+RsContext rsContextCreate(RsDevice, void *, uint32_t version);
+void rsContextDestroy(RsContext);
+
+enum RsDataType {
+ RS_TYPE_FLOAT,
+ RS_TYPE_UNSIGNED,
+ RS_TYPE_SIGNED
+};
+
+enum RsDataKind {
+ RS_KIND_USER,
+ RS_KIND_RED,
+ RS_KIND_GREEN,
+ RS_KIND_BLUE,
+ RS_KIND_ALPHA,
+ RS_KIND_LUMINANCE,
+ RS_KIND_INTENSITY,
+ RS_KIND_X,
+ RS_KIND_Y,
+ RS_KIND_Z,
+ RS_KIND_W,
+ RS_KIND_S,
+ RS_KIND_T,
+ RS_KIND_Q,
+ RS_KIND_R,
+ RS_KIND_NX,
+ RS_KIND_NY,
+ RS_KIND_NZ,
+ RS_KIND_INDEX
+};
+
+enum RsElementPredefined {
+ RS_ELEMENT_USER_U8,
+ RS_ELEMENT_USER_I8,
+ RS_ELEMENT_USER_U16,
+ RS_ELEMENT_USER_I16,
+ RS_ELEMENT_USER_U32,
+ RS_ELEMENT_USER_I32,
+ RS_ELEMENT_USER_FLOAT,
+
+ RS_ELEMENT_A_8, // 7
+ RS_ELEMENT_RGB_565, // 8
+ RS_ELEMENT_RGBA_5551, // 9
+ RS_ELEMENT_RGBA_4444, // 10
+ RS_ELEMENT_RGB_888, // 11
+ RS_ELEMENT_RGBA_8888, // 12
+
+ RS_ELEMENT_INDEX_16, //13
+ RS_ELEMENT_INDEX_32,
+ RS_ELEMENT_XY_F32,
+ RS_ELEMENT_XYZ_F32,
+ RS_ELEMENT_ST_XY_F32,
+ RS_ELEMENT_ST_XYZ_F32,
+ RS_ELEMENT_NORM_XYZ_F32,
+ RS_ELEMENT_NORM_ST_XYZ_F32,
+};
+
+enum RsSamplerParam {
+ RS_SAMPLER_MIN_FILTER,
+ RS_SAMPLER_MAG_FILTER,
+ RS_SAMPLER_WRAP_S,
+ RS_SAMPLER_WRAP_T,
+ RS_SAMPLER_WRAP_R
+};
+
+enum RsSamplerValue {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP
+};
+
+enum RsDimension {
+ RS_DIMENSION_X,
+ RS_DIMENSION_Y,
+ RS_DIMENSION_Z,
+ RS_DIMENSION_LOD,
+ RS_DIMENSION_FACE,
+
+ RS_DIMENSION_ARRAY_0 = 100,
+ RS_DIMENSION_ARRAY_1,
+ RS_DIMENSION_ARRAY_2,
+ RS_DIMENSION_ARRAY_3,
+ RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
+};
+
+enum RsDepthFunc {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL
+};
+
+enum RsBlendSrcFunc {
+ RS_BLEND_SRC_ZERO,
+ RS_BLEND_SRC_ONE,
+ RS_BLEND_SRC_DST_COLOR,
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR,
+ RS_BLEND_SRC_SRC_ALPHA,
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,
+ RS_BLEND_SRC_DST_ALPHA,
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE
+};
+
+enum RsBlendDstFunc {
+ RS_BLEND_DST_ZERO,
+ RS_BLEND_DST_ONE,
+ RS_BLEND_DST_SRC_COLOR,
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR,
+ RS_BLEND_DST_SRC_ALPHA,
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
+ RS_BLEND_DST_DST_ALPHA,
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA
+};
+
+enum RsTexEnvMode {
+ RS_TEX_ENV_MODE_REPLACE,
+ RS_TEX_ENV_MODE_MODULATE,
+ RS_TEX_ENV_MODE_DECAL
+};
+
+enum RsPrimitive {
+ RS_PRIMITIVE_POINT,
+ RS_PRIMITIVE_LINE,
+ RS_PRIMITIVE_LINE_STRIP,
+ RS_PRIMITIVE_TRIANGLE,
+ RS_PRIMITIVE_TRIANGLE_STRIP,
+ RS_PRIMITIVE_TRIANGLE_FAN
+};
+
+
+#include "rsgApiFuncDecl.h"
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // RENDER_SCRIPT_H
+
+
+
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
new file mode 100644
index 0000000..0789301
--- /dev/null
+++ b/libs/rs/RenderScriptEnv.h
@@ -0,0 +1,40 @@
+#include <stdint.h>
+
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsType;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+typedef void * RsLight;
+
+
+typedef struct {
+ float m[16];
+} rsc_Matrix;
+
+
+typedef struct {
+ float v[4];
+} rsc_Vector4;
+
+#define RS_PROGRAM_VERTEX_MODELVIEW_OFFSET 0
+#define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
+#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
+
+//typedef int (*rsc_RunScript)(uint32_t launchIndex, const rsc_FunctionTable *);
+
+
+/* EnableCap */
+#define GL_LIGHTING 0x0B50
+
+/* LightName */
+#define GL_LIGHT0 0x4000
diff --git a/libs/rs/java/Android.mk b/libs/rs/java/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/rs/java/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Film/Android.mk
new file mode 100644
index 0000000..b7f98fc
--- /dev/null
+++ b/libs/rs/java/Film/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Film
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Film/AndroidManifest.xml b/libs/rs/java/Film/AndroidManifest.xml
new file mode 100644
index 0000000..a5ce8a1
--- /dev/null
+++ b/libs/rs/java/Film/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.film">
+ <application android:label="Film">
+ <activity android:name="Film"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Film/res/raw/filmimage.c b/libs/rs/java/Film/res/raw/filmimage.c
new file mode 100644
index 0000000..3bd9496
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmimage.c
@@ -0,0 +1,110 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(orthoWindow)
+#pragma stateRaster(flat)
+#pragma stateFragment(PgmFragBackground)
+#pragma stateFragmentStore(MyBlend)
+
+
+int main(void* con, int ft, int launchID) {
+ int count, touch, x, y, rate, maxLife, lifeShift;
+ int life;
+ int ct, ct2;
+ int newPart;
+ int drawCount;
+ int dx, dy, idx;
+ int posx,posy;
+ int c;
+ int srcIdx;
+ int dstIdx;
+
+ count = loadI32(con, 0, 1);
+ touch = loadI32(con, 0, 2);
+ x = loadI32(con, 0, 3);
+ y = loadI32(con, 0, 4);
+
+ rate = 4;
+ maxLife = (count / rate) - 1;
+ lifeShift = 0;
+ {
+ life = maxLife;
+ while (life > 255) {
+ life = life >> 1;
+ lifeShift ++;
+ }
+ }
+
+ drawRect(con, 0, 256, 0, 512);
+ contextBindProgramFragment(con, NAMED_PgmFragParts);
+
+ if (touch) {
+ newPart = loadI32(con, 2, 0);
+ for (ct2=0; ct2<rate; ct2++) {
+ dx = scriptRand(con, 0x10000) - 0x8000;
+ dy = scriptRand(con, 0x10000) - 0x8000;
+
+ idx = newPart * 5 + 1;
+ storeI32(con, 2, idx, dx);
+ storeI32(con, 2, idx + 1, dy);
+ storeI32(con, 2, idx + 2, maxLife);
+ storeI32(con, 2, idx + 3, x << 16);
+ storeI32(con, 2, idx + 4, y << 16);
+
+ newPart++;
+ if (newPart >= count) {
+ newPart = 0;
+ }
+ }
+ storeI32(con, 2, 0, newPart);
+ }
+
+ drawCount = 0;
+ for (ct=0; ct < count; ct++) {
+ srcIdx = ct * 5 + 1;
+
+ dx = loadI32(con, 2, srcIdx);
+ dy = loadI32(con, 2, srcIdx + 1);
+ life = loadI32(con, 2, srcIdx + 2);
+ posx = loadI32(con, 2, srcIdx + 3);
+ posy = loadI32(con, 2, srcIdx + 4);
+
+ if (life) {
+ if (posy < (480 << 16)) {
+ dstIdx = drawCount * 9;
+ c = 0xffafcf | ((life >> lifeShift) << 24);
+
+ storeU32(con, 1, dstIdx, c);
+ storeI32(con, 1, dstIdx + 1, posx);
+ storeI32(con, 1, dstIdx + 2, posy);
+
+ storeU32(con, 1, dstIdx + 3, c);
+ storeI32(con, 1, dstIdx + 4, posx + 0x10000);
+ storeI32(con, 1, dstIdx + 5, posy + dy * 4);
+
+ storeU32(con, 1, dstIdx + 6, c);
+ storeI32(con, 1, dstIdx + 7, posx - 0x10000);
+ storeI32(con, 1, dstIdx + 8, posy + dy * 4);
+ drawCount ++;
+ } else {
+ if (dy > 0) {
+ dy = (-dy) >> 1;
+ }
+ }
+
+ posx = posx + dx;
+ posy = posy + dy;
+ dy = dy + 0x400;
+ life --;
+
+ //storeI32(con, 2, srcIdx, dx);
+ storeI32(con, 2, srcIdx + 1, dy);
+ storeI32(con, 2, srcIdx + 2, life);
+ storeI32(con, 2, srcIdx + 3, posx);
+ storeI32(con, 2, srcIdx + 4, posy);
+ }
+ }
+
+ drawTriangleArray(con, NAMED_PartBuffer, drawCount);
+ return 1;
+}
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
new file mode 100644
index 0000000..6885251
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -0,0 +1,114 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(PVBackground)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+/*
+typedef struct FilmScriptUserEnvRec {
+ RsAllocation tex[13];
+ int32_t triangleOffsets[64];
+ float triangleOffsetsTex[64];
+ int32_t triangleOffsetsCount;
+} FilmScriptUserEnv;
+*/
+
+// The script enviroment has 3 env allocations.
+// bank0: (r) The enviroment structure
+// bank1: (r) The position information
+// bank2: (rw) The temporary texture state
+
+int main(int index)
+{
+ int f1,f2,f3,f4, f5,f6,f7,f8, f9,f10,f11,f12, f13,f14,f15,f16;
+ int g1,g2,g3,g4, g5,g6,g7,g8, g9,g10,g11,g12, g13,g14,g15,g16;
+ float trans;
+ float rot;
+ int x;
+ float focusPos; // float
+ int focusID;
+ int lastFocusID;
+ int imgCount;
+
+ trans = loadF(1, 0);
+ rot = loadF(1, 1);
+
+ matrixLoadScale(&f16, 2.f, 2.f, 2.f);
+ matrixTranslate(&f16, 0.f, 0.f, trans);
+ matrixRotate(&f16, 90.f, 0.f, 0.f, 1.f);
+ matrixRotate(&f16, rot, 1.f, 0.f, 0.f);
+ storeMatrix(3, 0, &f16);
+
+ //materialDiffuse(con, 0.0f, 0.0f, 0.0f, 1.0f);
+ //materialSpecular(con, 0.5f, 0.5f, 0.5f, 0.5f);
+ //materialShininess(intToFloat(20));
+ drawTriangleMesh(NAMED_mesh);
+
+
+
+ //int imgId = 0;
+
+ bindProgramFragmentStore(NAMED_PFImages);
+ bindProgramFragment(NAMED_PFSImages);
+ bindProgramVertex(NAMED_PVImages);
+
+ //focusPos = loadF(1, 2);
+ //focusID = 0;
+ //lastFocusID = loadI32(2, 0);
+ //imgCount = 13;
+
+ /*
+ disable(GL_LIGHTING);
+
+
+ if (trans > (-.3)) {
+ focusID = -1.0 - focusPos;
+ if (focusID >= imgCount) {
+ focusID = -1;
+ }
+ } else {
+ focusID = -1;
+ }
+
+ if (focusID != lastFocusID) {
+ if (lastFocusID >= 0) {
+ uploadToTexture(con, env->tex[lastFocusID], 1);
+ }
+ if (focusID >= 0) {
+ uploadToTexture(con, env->tex[focusID], 0);
+ }
+ }
+ storeEnvI32(con, 2, 0, focusID);
+
+
+ for (imgId=1; imgId <= imgCount; imgId++) {
+ float pos = focusPos + imgId + .4f;
+ int offset = (int)floor(pos*2);
+ pos -= 0.75;
+
+ offset += env->triangleOffsetsCount / 2;
+
+ if ((offset < 0) || (offset >= env->triangleOffsetsCount)) {
+ continue;
+ }
+
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > env->triangleOffsetsCount) {
+ end = env->triangleOffsetsCount;
+ }
+
+ programFragmentBindTexture(con, env->fpImages, 0, env->tex[imgId - 1]);
+ matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
+ storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
+ renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
+ }
+*/
+ return 0;
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/Film.java b/libs/rs/java/Film/src/com/android/film/Film.java
new file mode 100644
index 0000000..6e99816
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/Film.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.film;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Film extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private FilmView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FilmView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
new file mode 100644
index 0000000..fca0818
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.film;
+
+import java.io.Writer;
+
+import android.renderscript.RenderScript;
+import android.renderscript.ProgramVertexAlloc;
+import android.renderscript.Matrix;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FilmRS {
+
+ public FilmRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void setFilmStripPosition(int x, int y)
+ {
+ if (x < 50) {
+ x = 50;
+ }
+ if (x > 270) {
+ x = 270;
+ }
+
+ float anim = ((float)x-50) / 270.f;
+ mBufferPos[0] = 2f * anim + 0.5f; // translation
+ mBufferPos[1] = (anim * 40); // rotation
+ mBufferPos[2] = ((float)y) / 16.f - 8; // focusPos
+ mAllocPos.data(mBufferPos);
+ }
+
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private RenderScript.Script mScriptStrip;
+ private RenderScript.Script mScriptImage;
+ private RenderScript.Element mElementVertex;
+ private RenderScript.Element mElementIndex;
+ private RenderScript.Sampler mSampler;
+ private RenderScript.ProgramFragmentStore mPFSBackground;
+ private RenderScript.ProgramFragmentStore mPFSImages;
+ private RenderScript.ProgramFragment mPFBackground;
+ private RenderScript.ProgramFragment mPFImages;
+ private RenderScript.ProgramVertex mPVBackground;
+ private RenderScript.ProgramVertex mPVImages;
+ private ProgramVertexAlloc mPVA;
+
+ private RenderScript.Allocation mAllocEnv;
+ private RenderScript.Allocation mAllocPos;
+ private RenderScript.Allocation mAllocState;
+ private RenderScript.Allocation mAllocPV;
+ private RenderScript.TriangleMesh mMesh;
+ private RenderScript.Light mLight;
+
+ private float[] mBufferPos;
+ private float[] mBufferPV;
+
+ private void initSamplers() {
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN,
+ RenderScript.SamplerValue.LINEAR_MIP_LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_S,
+ RenderScript.SamplerValue.CLAMP);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_T,
+ RenderScript.SamplerValue.CLAMP);
+ mSampler = mRS.samplerCreate();
+ }
+
+ private void initPFS() {
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
+ mRS.programFragmentStoreDitherEnable(true);
+ mPFSBackground = mRS.programFragmentStoreCreate();
+ mPFSBackground.setName("PFSBackground");
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.EQUAL);
+ mRS.programFragmentStoreDitherEnable(false);
+ mRS.programFragmentStoreDepthMask(false);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
+ RenderScript.BlendDstFunc.ONE);
+ mPFSImages = mRS.programFragmentStoreCreate();
+ mPFSImages.setName("PFSImages");
+ }
+
+ private void initPF() {
+ mRS.programFragmentBegin(null, null);
+ mPFBackground = mRS.programFragmentCreate();
+ mPFBackground.setName("PFBackground");
+
+ mRS.programFragmentBegin(null, null);
+ mRS.programFragmentSetTexEnable(0, true);
+ //mRS.programFragmentSetEnvMode(0, RS_TEX_ENV_MODE_REPLACE);
+ //rsProgramFragmentSetType(0, gEnv.tex[0]->getType());
+ mPFImages = mRS.programFragmentCreate();
+ mPFImages.setName("PFImages");
+ }
+
+ private void initPV() {
+ mRS.lightBegin();
+ mLight = mRS.lightCreate();
+ mLight.setPosition(0, -0.5f, -1.0f);
+
+ mRS.programVertexBegin(null, null);
+ mRS.programVertexSetTextureMatrixEnable(true);
+ mRS.programVertexAddLight(mLight);
+ mPVBackground = mRS.programVertexCreate();
+ mPVBackground.setName("PVBackground");
+
+ mRS.programVertexBegin(null, null);
+ mPVImages = mRS.programVertexCreate();
+ mPVImages.setName("PVImages");
+ }
+
+
+ int mParams[] = new int[10];
+
+ private void initRS() {
+ mElementVertex = mRS.elementGetPredefined(
+ RenderScript.ElementPredefined.NORM_ST_XYZ_F32);
+ mElementIndex = mRS.elementGetPredefined(
+ RenderScript.ElementPredefined.INDEX_16);
+
+ mRS.triangleMeshBegin(mElementVertex, mElementIndex);
+ FilmStripMesh fsm = new FilmStripMesh();
+ fsm.init(mRS);
+ mMesh = mRS.triangleMeshCreate();
+ mMesh.setName("mesh");
+
+ initPFS();
+ initSamplers();
+ initPF();
+ initPV();
+ mPFImages.bindSampler(mSampler, 0);
+
+ Log.e("rs", "Done loading named");
+
+ mRS.scriptCBegin();
+ mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ mRS.scriptCSetScript(mRes, R.raw.filmstrip);
+ mRS.scriptCSetRoot(true);
+ mScriptStrip = mRS.scriptCCreate();
+
+ mBufferPos = new float[3];
+ mAllocPos = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferPos.length);
+
+ mPVA = new ProgramVertexAlloc(mRS);
+ mPVBackground.bindAllocation(0, mPVA.mAlloc);
+ mPVImages.bindAllocation(0, mPVA.mAlloc);
+ mPVA.setupProjectionNormalized(320, 480);
+
+
+ mScriptStrip.bindAllocation(mAllocPos, 1);
+ //mScriptStrip.bindAllocation(gStateAlloc, 2);
+ mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
+
+
+/*
+ {
+ Resources res = getResources();
+ Drawable d = res.getDrawable(R.drawable.gadgets_clock_mp3);
+ BitmapDrawable bd = (BitmapDrawable)d;
+ Bitmap b = bd.getBitmap();
+ mTexture = mRS.allocationCreateFromBitmap(b,
+ RenderScript.ElementPredefined.RGB_565,
+ true);
+ mTexture.uploadToTexture(0);
+ }
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA, RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.ALWAYS);
+ mPFS = mRS.programFragmentStoreCreate();
+ mPFS.setName("MyBlend");
+ mRS.contextBindProgramFragmentStore(mPFS);
+ */
+
+ setFilmStripPosition(0, 0);
+
+ mRS.contextBindRootScript(mScriptStrip);
+ }
+}
+
+
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
new file mode 100644
index 0000000..02bffd8
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+
+package com.android.film;
+
+import java.io.Writer;
+import java.lang.Math;
+import android.util.Log;
+
+import android.renderscript.RenderScript;
+
+
+class FilmStripMesh {
+
+ class Vertex {
+ float nx;
+ float ny;
+ float nz;
+ float s;
+ float t;
+ float x;
+ float y;
+ float z;
+
+ Vertex() {
+ nx = 0;
+ ny = 0;
+ nz = 0;
+ s = 0;
+ t = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ void xyz(float _x, float _y, float _z) {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void nxyz(float _x, float _y, float _z) {
+ nx = _x;
+ ny = _y;
+ nz = _z;
+ }
+
+ void st(float _s, float _t) {
+ s = _s;
+ t = _t;
+ }
+
+ void computeNorm(Vertex v1, Vertex v2) {
+ float dx = v1.x - v2.x;
+ float dy = v1.y - v2.y;
+ float dz = v1.z - v2.z;
+ float len = (float)java.lang.Math.sqrt(dx*dx + dy*dy + dz*dz);
+ dx /= len;
+ dy /= len;
+ dz /= len;
+
+ nx = dx * dz;
+ ny = dy * dz;
+ nz = (float)java.lang.Math.sqrt(dx*dx + dy*dy);
+
+ len = (float)java.lang.Math.sqrt(nx*nx + ny*ny + nz*nz);
+ nx /= len;
+ ny /= len;
+ nz /= len;
+ }
+
+ void addToRS(RenderScript rs) {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(x, y, z, s, t, nx, ny, nz);
+ }
+ }
+
+ int[] mTriangleOffsets;
+ float[] mTriangleOffsetsTex;
+ int mTriangleOffsetsCount;
+
+ void init(RenderScript rs)
+ {
+ float vtx[] = new float[] {
+ 60.431003f, 124.482050f,
+ 60.862074f, 120.872604f,
+ 61.705303f, 117.336662f,
+ 62.949505f, 113.921127f,
+ 64.578177f, 110.671304f,
+ 66.569716f, 107.630302f,
+ 68.897703f, 104.838457f,
+ 71.531259f, 102.332803f,
+ 74.435452f, 100.146577f,
+ 77.571757f, 98.308777f,
+ 80.898574f, 96.843781f,
+ 84.371773f, 95.771023f,
+ 87.945283f, 95.104731f,
+ 98.958994f, 95.267098f,
+ 109.489523f, 98.497596f,
+ 118.699582f, 104.539366f,
+ 125.856872f, 112.912022f,
+ 130.392311f, 122.949849f,
+ 131.945283f, 133.854731f,
+ 130.392311f, 144.759613f,
+ 125.856872f, 154.797439f,
+ 118.699582f, 163.170096f,
+ 109.489523f, 169.211866f,
+ 98.958994f, 172.442364f,
+ 87.945283f, 172.604731f,
+ 72.507313f, 172.672927f,
+ 57.678920f, 168.377071f,
+ 44.668135f, 160.067134f,
+ 34.534908f, 148.420104f,
+ 28.104767f, 134.384831f,
+ 25.901557f, 119.104731f,
+ 28.104767f, 103.824631f,
+ 34.534908f, 89.789358f,
+ 44.668135f, 78.142327f,
+ 57.678920f, 69.832390f,
+ 72.507313f, 65.536534f,
+ 87.945283f, 65.604731f,
+ 106.918117f, 65.688542f,
+ 125.141795f, 60.409056f,
+ 141.131686f, 50.196376f,
+ 153.585137f, 35.882502f,
+ 161.487600f, 18.633545f,
+ 164.195283f, -0.145269f,
+ 161.487600f, -18.924084f,
+ 153.585137f, -36.173040f,
+ 141.131686f, -50.486914f,
+ 125.141795f, -60.699594f,
+ 106.918117f, -65.979081f,
+ 87.945283f, -65.895269f,
+ 80f, -65.895269f,
+ 60f, -65.895269f,
+ 40f, -65.895269f,
+ 20f, -65.895269f,
+ 0f, -65.895269f,
+ -20f, -65.895269f,
+ -40f, -65.895269f,
+ -60f, -65.895269f,
+ -80f, -65.895269f,
+ -87.945283f, -65.895269f,
+ -106.918117f, -65.979081f,
+ -125.141795f, -60.699594f,
+ -141.131686f, -50.486914f,
+ -153.585137f, -36.173040f,
+ -161.487600f, -18.924084f,
+ -164.195283f, -0.145269f,
+ -161.487600f, 18.633545f,
+ -153.585137f, 35.882502f,
+ -141.131686f, 50.196376f,
+ -125.141795f, 60.409056f,
+ -106.918117f, 65.688542f,
+ -87.945283f, 65.604731f,
+ -72.507313f, 65.536534f,
+ -57.678920f, 69.832390f,
+ -44.668135f, 78.142327f,
+ -34.534908f, 89.789358f,
+ -28.104767f, 103.824631f,
+ -25.901557f, 119.104731f,
+ -28.104767f, 134.384831f,
+ -34.534908f, 148.420104f,
+ -44.668135f, 160.067134f,
+ -57.678920f, 168.377071f,
+ -72.507313f, 172.672927f,
+ -87.945283f, 172.604731f,
+ -98.958994f, 172.442364f,
+ -109.489523f, 169.211866f,
+ -118.699582f, 163.170096f,
+ -125.856872f, 154.797439f,
+ -130.392311f, 144.759613f,
+ -131.945283f, 133.854731f,
+ -130.392311f, 122.949849f,
+ -125.856872f, 112.912022f,
+ -118.699582f, 104.539366f,
+ -109.489523f, 98.497596f,
+ -98.958994f, 95.267098f,
+ -87.945283f, 95.104731f,
+ -84.371773f, 95.771023f,
+ -80.898574f, 96.843781f,
+ -77.571757f, 98.308777f,
+ -74.435452f, 100.146577f,
+ -71.531259f, 102.332803f,
+ -68.897703f, 104.838457f,
+ -66.569716f, 107.630302f,
+ -64.578177f, 110.671304f,
+ -62.949505f, 113.921127f,
+ -61.705303f, 117.336662f,
+ -60.862074f, 120.872604f,
+ -60.431003f, 124.482050f
+ };
+
+
+ mTriangleOffsets = new int[64];
+ mTriangleOffsetsTex = new float[64];
+
+ mTriangleOffsets[0] = 0;
+ mTriangleOffsetsCount = 1;
+
+ Vertex t = new Vertex();
+ t.nxyz(1, 0, 0);
+ int count = vtx.length / 2;
+
+ float runningS = 0;
+ for (int ct=0; ct < (count-1); ct++) {
+ t.x = -vtx[ct*2] / 100.f;
+ t.z = vtx[ct*2+1] / 100.f;
+ t.s = runningS;
+ t.nx = (vtx[ct*2+3] - vtx[ct*2 +1]);
+ t.ny = (vtx[ct*2+2] - vtx[ct*2 ]);
+ float len = (float)java.lang.Math.sqrt(t.nx * t.nx + t.ny * t.ny);
+ runningS += len / 100;
+ t.nx /= len;
+ t.ny /= len;
+ t.y = -0.5f;
+ t.t = 0;
+ //Log.e("xx", "vtx " + t.x + " " + t.y + " " + t.z);
+ t.addToRS(rs);
+ t.y = .5f;
+ t.t = 1;
+ t.addToRS(rs);
+
+ //LOGE(" %f", runningS);
+ if((runningS*2) > mTriangleOffsetsCount) {
+ //LOGE("**** img %i %i", gTriangleOffsetsCount, ct*2);
+ mTriangleOffsets[mTriangleOffsetsCount] = ct*2;
+ mTriangleOffsetsTex[mTriangleOffsetsCount] = t.s;
+ mTriangleOffsetsCount ++;
+ }
+ }
+
+ count = (count * 2 - 2);
+ for (int ct=0; ct < (count-2); ct+= 2) {
+ rs.triangleMeshAddTriangle(ct, ct+1, ct+2);
+ rs.triangleMeshAddTriangle(ct+1, ct+3, ct+2);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java
new file mode 100644
index 0000000..a743b1b
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.film;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FilmView extends RSSurfaceView {
+
+ public FilmView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private FilmRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new FilmRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+ mRender.setFilmStripPosition((int)ev.getX(), (int)ev.getY());
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk
new file mode 100644
index 0000000..b6a9f10
--- /dev/null
+++ b/libs/rs/java/Fountain/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Fountain
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..dd0e428
--- /dev/null
+++ b/libs/rs/java/Fountain/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.fountain">
+ <application android:label="Fountain">
+ <activity android:name="Fountain"
+ android:theme="@android:style/Theme.Translucent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
new file mode 100755
index 0000000..e91bfb4
--- /dev/null
+++ b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
Binary files differ
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
new file mode 100644
index 0000000..99551fc
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -0,0 +1,106 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(default)
+#pragma stateFragment(PgmFragParts)
+#pragma stateFragmentStore(PFSBlend)
+
+
+int main(int launchID) {
+ int count, touch, x, y, rate, maxLife, lifeShift;
+ int life;
+ int ct, ct2;
+ int newPart;
+ int drawCount;
+ int dx, dy, idx;
+ int posx,posy;
+ int c;
+ int srcIdx;
+ int dstIdx;
+
+ count = loadI32(0, 1);
+ touch = loadI32(0, 2);
+ x = loadI32(0, 3);
+ y = loadI32(0, 4);
+
+ rate = 4;
+ maxLife = (count / rate) - 1;
+ lifeShift = 0;
+ {
+ life = maxLife;
+ while (life > 255) {
+ life = life >> 1;
+ lifeShift ++;
+ }
+ }
+
+ if (touch) {
+ newPart = loadI32(2, 0);
+ for (ct2=0; ct2<rate; ct2++) {
+ dx = (int)((randf(1.f) - 0.5f) * 0x10000);
+ dy = (int)((randf(1.f) - 0.5f) * 0x10000);
+
+ idx = newPart * 5 + 1;
+ storeI32(2, idx, dx);
+ storeI32(2, idx + 1, dy);
+ storeI32(2, idx + 2, maxLife);
+ storeI32(2, idx + 3, x << 16);
+ storeI32(2, idx + 4, y << 16);
+
+ newPart++;
+ if (newPart >= count) {
+ newPart = 0;
+ }
+ }
+ storeI32(2, 0, newPart);
+ }
+
+ drawCount = 0;
+ for (ct=0; ct < count; ct++) {
+ srcIdx = ct * 5 + 1;
+
+ dx = loadI32(2, srcIdx);
+ dy = loadI32(2, srcIdx + 1);
+ life = loadI32(2, srcIdx + 2);
+ posx = loadI32(2, srcIdx + 3);
+ posy = loadI32(2, srcIdx + 4);
+
+ if (life) {
+ if (posy < (480 << 16)) {
+ dstIdx = drawCount * 9;
+ c = 0xffafcf | ((life >> lifeShift) << 24);
+
+ storeI32(1, dstIdx, c);
+ storeI32(1, dstIdx + 1, posx);
+ storeI32(1, dstIdx + 2, posy);
+
+ storeI32(1, dstIdx + 3, c);
+ storeI32(1, dstIdx + 4, posx + 0x10000);
+ storeI32(1, dstIdx + 5, posy + dy * 4);
+
+ storeI32(1, dstIdx + 6, c);
+ storeI32(1, dstIdx + 7, posx - 0x10000);
+ storeI32(1, dstIdx + 8, posy + dy * 4);
+ drawCount ++;
+ } else {
+ if (dy > 0) {
+ dy = (-dy) >> 1;
+ }
+ }
+
+ posx = posx + dx;
+ posy = posy + dy;
+ dy = dy + 0x400;
+ life --;
+
+ //storeI32(2, srcIdx, dx);
+ storeI32(2, srcIdx + 1, dy);
+ storeI32(2, srcIdx + 2, life);
+ storeI32(2, srcIdx + 3, posx);
+ storeI32(2, srcIdx + 4, posy);
+ }
+ }
+
+ drawTriangleArray(NAMED_PartBuffer, drawCount);
+ return 1;
+}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
new file mode 100644
index 0000000..58c78fa
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.fountain;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Fountain extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private FountainView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FountainView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
new file mode 100644
index 0000000..c8e9a1e
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.fountain;
+
+import java.io.Writer;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.renderscript.RenderScript;
+import android.renderscript.ProgramVertexAlloc;
+import android.util.Log;
+
+public class FountainRS {
+
+ public FountainRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void newTouchPosition(int x, int y) {
+ mParams[0] = 1;
+ mParams[1] = x;
+ mParams[2] = y;
+ mIntAlloc.subData1D(2, 3, mParams);
+ }
+
+
+ /////////////////////////////////////////
+
+ private Resources mRes;
+
+ private RenderScript mRS;
+ private RenderScript.Allocation mIntAlloc;
+ private RenderScript.Allocation mPartAlloc;
+ private RenderScript.Allocation mVertAlloc;
+ private RenderScript.Script mScript;
+ private RenderScript.ProgramFragmentStore mPFS;
+ private RenderScript.ProgramFragment mPF;
+
+ private Bitmap mBackground;
+
+ int mParams[] = new int[10];
+
+ private void initRS() {
+ int partCount = 1024;
+
+ mIntAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, 10);
+ mPartAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 3 * 3);
+ mPartAlloc.setName("PartBuffer");
+ mVertAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 5 + 1);
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA, RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.ALWAYS);
+ mRS.programFragmentStoreDepthMask(false);
+ mRS.programFragmentStoreDitherEnable(false);
+ mPFS = mRS.programFragmentStoreCreate();
+ mPFS.setName("PFSBlend");
+
+ mRS.programFragmentBegin(null, null);
+ mPF = mRS.programFragmentCreate();
+ mPF.setName("PgmFragParts");
+
+ mParams[0] = 0;
+ mParams[1] = partCount;
+ mParams[2] = 0;
+ mParams[3] = 0;
+ mParams[4] = 0;
+ mIntAlloc.data(mParams);
+
+ int t2[] = new int[partCount * 4*3];
+ for (int ct=0; ct < t2.length; ct++) {
+ t2[ct] = 0;
+ }
+ mPartAlloc.data(t2);
+
+ mRS.scriptCBegin();
+ mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ mRS.scriptCSetScript(mRes, R.raw.fountain);
+ mRS.scriptCSetRoot(true);
+ mScript = mRS.scriptCCreate();
+
+ mScript.bindAllocation(mIntAlloc, 0);
+ mScript.bindAllocation(mPartAlloc, 1);
+ mScript.bindAllocation(mVertAlloc, 2);
+ mRS.contextBindRootScript(mScript);
+ }
+
+}
+
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
new file mode 100644
index 0000000..be8b24e
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FountainView extends RSSurfaceView {
+
+ public FountainView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private FountainRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new FountainRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+ mRender.newTouchPosition((int)ev.getX(), (int)ev.getY());
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Rollo/Android.mk b/libs/rs/java/Rollo/Android.mk
new file mode 100644
index 0000000..5a4957c
--- /dev/null
+++ b/libs/rs/java/Rollo/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Rollo
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Rollo/AndroidManifest.xml b/libs/rs/java/Rollo/AndroidManifest.xml
new file mode 100644
index 0000000..127a140
--- /dev/null
+++ b/libs/rs/java/Rollo/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.rollo">
+ <application android:label="Rollo">
+ <activity android:name="Rollo"
+ android:theme="@android:style/Theme.Translucent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Rollo/res/raw/browser.png b/libs/rs/java/Rollo/res/raw/browser.png
new file mode 100644
index 0000000..513f0be
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/browser.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/market.png b/libs/rs/java/Rollo/res/raw/market.png
new file mode 100644
index 0000000..83b6910
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/market.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/photos.png b/libs/rs/java/Rollo/res/raw/photos.png
new file mode 100644
index 0000000..1ed8f1e
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/photos.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
new file mode 100644
index 0000000..d338d0d
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -0,0 +1,105 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+float filter(float val, float target, float str)
+{
+ float delta = (target - val);
+ return val + delta * str;
+}
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int row;
+ int col;
+ int imageID;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+
+ float f = loadF(2, 0);
+
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ if (f > 0.02f) {
+ //f = f - 0.02f;
+ //storeF(2, 0, f);
+ }
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
+ }
+
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 5.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
+ float rot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, rot);
+
+ float diam = 8.f;// + curve * 2.f;
+ float scale = 1.0f / zoom;
+
+ rot = rot * scale;
+ float rotStep = 20.0f / 180.0f * 3.14f * scale;
+ rowCount = 4;
+ int index = 0;
+ int iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ float tmpSin = sinf(rot);
+ float tmpCos = cosf(rot);
+
+ float tx1 = tmpSin * diam - (tmpCos * scale);
+ float tx2 = tx1 + (tmpCos * scale * 2.f);
+ float tz1 = tmpCos * diam + (tmpSin * scale);
+ float tz2 = tz1 - (tmpSin * scale * 2.f);
+
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ float ty1 = ((y * 3.0f) - 4.5f) * scale;
+ float ty2 = ty1 + scale * 2.f;
+ bindTexture(NAMED_PF, 0, loadI32(1, y));
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+ if (done && (index != selectedID)) {
+ color(0.4f, 0.4f, 0.4f, 1.0f);
+ }
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ return 0;
+}
+
+
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
new file mode 100644
index 0000000..b04ea73
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -0,0 +1,67 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+void drawLoop(int x, int y, int z, int rot)
+{
+ int ct;
+ int tx;
+ int ty;
+ int tmpSin;
+ int tmpCos;
+ int sz;
+
+ for (ct = 0; ct < 10; ct ++) {
+ tmpSin = sinx((ct * 36 + rot) * 0x10000);
+ tmpCos = cosx((ct * 36 + rot) * 0x10000);
+
+ ty = y + tmpCos * 4;
+ tx = x + tmpSin * 4;
+ pfBindTexture(NAMED_PF, 0, loadI32(1, ct & 3));
+
+ sz = 0xc000;
+ drawQuad(tx - sz, ty - sz, z,
+ tx + sz, ty - sz, z,
+ tx + sz, ty + sz, z,
+ tx - sz, ty + sz, z);
+ }
+}
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int x;
+ int y;
+ int row;
+ int col;
+ int imageID;
+ int tx1;
+ int ty1;
+ int tz1;
+ int tx2;
+ int ty2;
+ int tz2;
+ int tmpSin;
+ int tmpCos;
+ int iconCount;
+ int pressure;
+
+ int ringCount;
+
+
+
+ rotStep = 16 * 0x10000;
+ pressure = loadI32(0, 2);
+ rowCount = 4;
+
+ iconCount = loadI32(0, 1);
+ rot = (-20 + loadI32(0, 0)) * 0x10000;
+
+ for (ringCount = 0; ringCount < 5; ringCount++) {
+ drawLoop(0, 0, 0x90000 + (ringCount * 0x80000));
+ }
+
+ return 0;
+}
+
diff --git a/libs/rs/java/Rollo/res/raw/settings.png b/libs/rs/java/Rollo/res/raw/settings.png
new file mode 100644
index 0000000..dd2cd95
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/settings.png
Binary files differ
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
new file mode 100644
index 0000000..400d801
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.rollo;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Rollo extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private RolloView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new RolloView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
new file mode 100644
index 0000000..d7252fb
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
@@ -0,0 +1,90 @@
+ /*
+ * Copyright (C) 2009 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.
+ */
+
+
+package com.android.rollo;
+
+import java.io.Writer;
+import java.lang.Math;
+
+import android.renderscript.RenderScript;
+
+
+class RolloMesh {
+ static public final float mCardHeight = 1.2f;
+ static public final float mCardWidth = 1.8f;
+ static public final float mTabHeight = 0.2f;
+ static public final float mTabs = 3;
+ static public final float mTabGap = 0.1f;
+
+ static RenderScript.TriangleMesh createCard(RenderScript rs) {
+ RenderScript.Element vtx = rs.elementGetPredefined(
+ RenderScript.ElementPredefined.ST_XYZ_F32);
+ RenderScript.Element idx = rs.elementGetPredefined(
+ RenderScript.ElementPredefined.INDEX_16);
+
+ float w = mCardWidth / 2;
+ float h = mCardHeight;
+ float z = 0;
+
+ rs.triangleMeshBegin(vtx, idx);
+ rs.triangleMeshAddVertex_XYZ_ST(-w, 0, z, 0, 0);
+ rs.triangleMeshAddVertex_XYZ_ST(-w, h, z, 0, 1);
+ rs.triangleMeshAddVertex_XYZ_ST( w, h, z, 1, 1);
+ rs.triangleMeshAddVertex_XYZ_ST( w, 0, z, 1, 0);
+ rs.triangleMeshAddTriangle(0,1,2);
+ rs.triangleMeshAddTriangle(0,2,3);
+ return rs.triangleMeshCreate();
+ }
+
+ static RenderScript.TriangleMesh createTab(RenderScript rs) {
+ RenderScript.Element vtx = rs.elementGetPredefined(
+ RenderScript.ElementPredefined.ST_XYZ_F32);
+ RenderScript.Element idx = rs.elementGetPredefined(
+ RenderScript.ElementPredefined.INDEX_16);
+
+
+ float tabSlope = 0.1f;
+ float num = 0;
+
+ float w = (mCardWidth - ((mTabs - 1) * mTabGap)) / mTabs;
+ float w1 = -(mCardWidth / 2) + ((w + mTabGap) * num);
+ float w2 = w1 + (w * tabSlope);
+ float w3 = w1 + w - (w * tabSlope);
+ float w4 = w1 + w;
+ float h1 = mCardHeight;
+ float h2 = h1 + mTabHeight;
+ float z = 0;
+
+ float stScale = w / mTabHeight / 2;
+ float stScale2 = stScale * (tabSlope / w);
+
+
+ rs.triangleMeshBegin(vtx, idx);
+ rs.triangleMeshAddVertex_XYZ_ST(w1, h1, z, -stScale, 0);
+ rs.triangleMeshAddVertex_XYZ_ST(w2, h2, z, -stScale2, 1);
+ rs.triangleMeshAddVertex_XYZ_ST(w3, h2, z, stScale2, 1);
+ rs.triangleMeshAddVertex_XYZ_ST(w4, h1, z, stScale, 0);
+ rs.triangleMeshAddTriangle(0,1,2);
+ rs.triangleMeshAddTriangle(0,2,3);
+ return rs.triangleMeshCreate();
+ }
+
+
+
+}
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
new file mode 100644
index 0000000..8f48335
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.rollo;
+
+import java.io.Writer;
+
+import android.renderscript.RenderScript;
+import android.renderscript.ProgramVertexAlloc;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class RolloRS {
+ //public static final int STATE_SELECTED_ID = 0;
+ public static final int STATE_DONE = 1;
+ //public static final int STATE_PRESSURE = 2;
+ public static final int STATE_ZOOM = 3;
+ //public static final int STATE_WARP = 4;
+ public static final int STATE_ORIENTATION = 5;
+ public static final int STATE_SELECTION = 6;
+ public static final int STATE_FIRST_VISIBLE = 7;
+ public static final int STATE_COUNT = 8;
+ public static final int STATE_TOUCH = 9;
+
+
+ public RolloRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initNamed();
+ initRS();
+ }
+
+ public void setPosition(float column) {
+ mAllocStateBuf[STATE_FIRST_VISIBLE] = (int)(column * (-20));
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setTouch(boolean touch) {
+ mAllocStateBuf[STATE_TOUCH] = touch ? 1 : 0;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setZoom(float z) {
+ //Log.e("rs", "zoom " + Float.toString(z));
+
+ mAllocStateBuf[STATE_ZOOM] = (int)(z * 1000.f);
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setSelected(int index) {
+ Log.e("rs", "setSelected " + Integer.toString(index));
+
+ mAllocStateBuf[STATE_SELECTION] = index;
+ mAllocStateBuf[STATE_DONE] = 1;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private RenderScript.Script mScript;
+ private RenderScript.Sampler mSampler;
+ private RenderScript.ProgramFragmentStore mPFSBackground;
+ private RenderScript.ProgramFragment mPFBackground;
+ private RenderScript.ProgramFragment mPFImages;
+ private RenderScript.ProgramVertex mPV;
+ private ProgramVertexAlloc mPVAlloc;
+ private RenderScript.Allocation[] mIcons;
+ private RenderScript.Allocation mIconPlate;
+
+ private int[] mAllocStateBuf;
+ private RenderScript.Allocation mAllocState;
+
+ private int[] mAllocIconIDBuf;
+ private RenderScript.Allocation mAllocIconID;
+
+ private int[] mAllocScratchBuf;
+ private RenderScript.Allocation mAllocScratch;
+
+ private void initNamed() {
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN,
+ RenderScript.SamplerValue.LINEAR);//_MIP_LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MAG,
+ RenderScript.SamplerValue.LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_S,
+ RenderScript.SamplerValue.CLAMP);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_T,
+ RenderScript.SamplerValue.CLAMP);
+ mSampler = mRS.samplerCreate();
+
+
+ mRS.programFragmentBegin(null, null);
+ mRS.programFragmentSetTexEnable(0, true);
+ mRS.programFragmentSetTexEnvMode(0, RenderScript.EnvMode.MODULATE);
+ mPFImages = mRS.programFragmentCreate();
+ mPFImages.setName("PF");
+ mPFImages.bindSampler(mSampler, 0);
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
+ mRS.programFragmentStoreDitherEnable(false);
+ mRS.programFragmentStoreDepthMask(false);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
+ RenderScript.BlendDstFunc.ONE);
+ mPFSBackground = mRS.programFragmentStoreCreate();
+ mPFSBackground.setName("PFS");
+
+ mPVAlloc = new ProgramVertexAlloc(mRS);
+ mRS.programVertexBegin(null, null);
+ mRS.programVertexSetTextureMatrixEnable(true);
+ mPV = mRS.programVertexCreate();
+ mPV.setName("PV");
+ mPV.bindAllocation(0, mPVAlloc.mAlloc);
+
+
+
+ mPVAlloc.setupProjectionNormalized(320, 480);
+ //mPVAlloc.setupOrthoNormalized(320, 480);
+ mRS.contextBindProgramVertex(mPV);
+
+ mAllocScratchBuf = new int[32];
+ for(int ct=0; ct < mAllocScratchBuf.length; ct++) {
+ mAllocScratchBuf[ct] = 0;
+ }
+ mAllocScratch = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_I32, mAllocScratchBuf.length);
+ mAllocScratch.data(mAllocScratchBuf);
+
+ Log.e("rs", "Done loading named");
+
+
+
+ {
+ mIcons = new RenderScript.Allocation[4];
+ mAllocIconIDBuf = new int[mIcons.length];
+ mAllocIconID = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_I32, mAllocIconIDBuf.length);
+
+
+ Bitmap b;
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScaled = false;
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.browser, opts);
+ mIcons[0] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.market, opts);
+ mIcons[1] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.photos, opts);
+ mIcons[2] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.settings, opts);
+ mIcons[3] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ for(int ct=0; ct < mIcons.length; ct++) {
+ mIcons[ct].uploadToTexture(0);
+ mAllocIconIDBuf[ct] = mIcons[ct].getID();
+ }
+ mAllocIconID.data(mAllocIconIDBuf);
+
+ RenderScript.Element e = mRS.elementGetPredefined(RenderScript.ElementPredefined.RGB_565);
+ mRS.typeBegin(e);
+ mRS.typeAdd(RenderScript.Dimension.X, 64);
+ mRS.typeAdd(RenderScript.Dimension.Y, 64);
+ RenderScript.Type t = mRS.typeCreate();
+ mIconPlate = mRS.allocationCreateTyped(t);
+ //t.destroy();
+ //e.destroy();
+
+ int tmp[] = new int[64 * 32];
+ for(int ct = 0; ct < (64*32); ct++) {
+ tmp[ct] = 7 | (13 << 5) | (7 << 11);
+ tmp[ct] = tmp[ct] | (tmp[ct] << 16);
+ }
+ for(int ct = 0; ct < 32; ct++) {
+ tmp[ct] = 0;
+ tmp[ct + (63*32)] = 0;
+ }
+ for(int ct = 0; ct < 64; ct++) {
+ tmp[ct * 32] = 0;
+ tmp[ct * 32 + 31] = 0;
+ }
+ mIconPlate.data(tmp);
+ Log.e("xx", "plate");
+ mIconPlate.uploadToTexture(0);
+ mIconPlate.setName("Plate");
+ mPFImages.bindTexture(mIconPlate, 0);
+ }
+
+ }
+
+
+
+ private void initRS() {
+ mRS.scriptCBegin();
+ mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ mRS.scriptCSetScript(mRes, R.raw.rollo);
+ //mRS.scriptCSetScript(mRes, R.raw.rollo2);
+ mRS.scriptCSetRoot(true);
+ //mRS.scriptCSetClearDepth(0);
+ mScript = mRS.scriptCCreate();
+
+ mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, 0, 0, 38, 0, 0};
+ mAllocState = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_I32, mAllocStateBuf.length);
+ mScript.bindAllocation(mAllocState, 0);
+ mScript.bindAllocation(mAllocIconID, 1);
+ mScript.bindAllocation(mAllocScratch, 2);
+ setPosition(0);
+ setZoom(1);
+
+ //RenderScript.File f = mRS.fileOpen("/sdcard/test.a3d");
+
+ mRS.contextBindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
new file mode 100644
index 0000000..b5e02af
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.rollo;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import java.lang.Float;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.graphics.PixelFormat;
+
+
+public class RolloView extends RSSurfaceView {
+ public RolloView(Context context) {
+ super(context);
+ setFocusable(true);
+ getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ private RenderScript mRS;
+ private RolloRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new RolloRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+ boolean mControlMode = false;
+ boolean mZoomMode = false;
+ boolean mFlingMode = false;
+ float mFlingX = 0;
+ float mFlingY = 0;
+ float mColumn = -1;
+ float mOldColumn;
+ float mZoom = 1;
+
+ int mIconCount = 38;
+ int mRows = 4;
+ int mColumns = (mIconCount + mRows - 1) / mRows;
+
+ float mMaxZoom = ((float)mColumns) / 3.f;
+
+
+ void setColumn(boolean clamp)
+ {
+ //Log.e("rs", " col = " + Float.toString(mColumn));
+ float c = mColumn;
+ if(c > (mColumns -2)) {
+ c = (mColumns -2);
+ }
+ if(c < 1) {
+ c = 1;
+ }
+ mRender.setPosition(c);
+ if(clamp) {
+ mColumn = c;
+ }
+ }
+
+ void computeSelection(float x, float y)
+ {
+ float col = mColumn + (x - 0.5f) * 3;
+ int iCol = (int)(col + 0.25f);
+
+ float row = (y / 0.8f) * mRows;
+ int iRow = (int)(row - 0.25f);
+
+ mRender.setSelected(iCol * mRows + iRow);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+
+ float nx = ev.getX() / getWidth();
+ float ny = ev.getY() / getHeight();
+
+ mRender.setTouch(ret);
+
+ if((ny > 0.85f) || mControlMode) {
+ mFlingMode = false;
+
+ // Projector control
+ if((nx > 0.2f) && (nx < 0.8f) || mControlMode) {
+ if(act != ev.ACTION_UP) {
+ float zoom = mMaxZoom;
+ if(mControlMode) {
+ if(!mZoomMode) {
+ zoom = 1.f;
+ }
+ float dx = nx - mFlingX;
+
+ if((ny < 0.9) && mZoomMode) {
+ zoom = mMaxZoom - ((0.9f - ny) * 10.f);
+ if(zoom < 1) {
+ zoom = 1;
+ mZoomMode = false;
+ }
+ mOldColumn = mColumn;
+ }
+ mColumn += dx * 4;// * zoom;
+ if(zoom > 1.01f) {
+ mColumn += (mZoom - zoom) * (nx - 0.5f) * 4 * zoom;
+ }
+ } else {
+ mOldColumn = mColumn;
+ mColumn = ((float)mColumns) / 2;
+ mControlMode = true;
+ mZoomMode = true;
+ }
+ mZoom = zoom;
+ mFlingX = nx;
+ mRender.setZoom(zoom);
+ } else {
+ if(mControlMode && (mZoom < 1.01f)) {
+ computeSelection(nx, ny);
+ }
+ mControlMode = false;
+ mColumn = mOldColumn;
+ mRender.setZoom(1.f);
+ }
+ } else {
+ // Do something with corners here....
+ }
+ setColumn(true);
+
+ } else {
+ // icon control
+ if(act != ev.ACTION_UP) {
+ if(mFlingMode) {
+ mColumn += (mFlingX - nx) * 4;
+ setColumn(true);
+ }
+ mFlingMode = true;
+ mFlingX = nx;
+ mFlingY = ny;
+ } else {
+ mFlingMode = false;
+ }
+ }
+
+
+ return ret;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev)
+ {
+ float x = ev.getX();
+ float y = ev.getY();
+ //Float tx = new Float(x);
+ //Float ty = new Float(y);
+ //Log.e("rs", "tbe " + tx.toString() + ", " + ty.toString());
+
+
+ return true;
+ }
+
+}
+
+
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
new file mode 100644
index 0000000..2f99808
--- /dev/null
+++ b/libs/rs/rs.spec
@@ -0,0 +1,449 @@
+
+
+ContextBindRootScript {
+ param RsScript sampler
+ }
+
+ContextBindProgramFragmentStore {
+ param RsProgramFragmentStore pgm
+ }
+
+ContextBindProgramFragment {
+ param RsProgramFragment pgm
+ }
+
+ContextBindProgramVertex {
+ param RsProgramVertex pgm
+ }
+
+AssignName {
+ param void *obj
+ param const char *name
+ param size_t len
+ }
+
+ElementBegin {
+}
+
+ElementAddPredefined {
+ param RsElementPredefined predef
+ }
+
+ElementAdd {
+ param RsDataKind dataKind
+ param RsDataType dataType
+ param bool isNormalized
+ param size_t bits
+ }
+
+ElementCreate {
+ ret RsElement
+ }
+
+ElementGetPredefined {
+ param RsElementPredefined predef
+ ret RsElement
+ }
+
+ElementDestroy {
+ param RsElement ve
+ }
+
+TypeBegin {
+ param RsElement type
+ }
+
+TypeAdd {
+ param RsDimension dim
+ param size_t value
+ }
+
+TypeCreate {
+ ret RsType
+ }
+
+TypeDestroy {
+ param RsType p
+ }
+
+AllocationCreateTyped {
+ param RsType type
+ ret RsAllocation
+ }
+
+AllocationCreatePredefSized {
+ param RsElementPredefined predef
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateSized {
+ param RsElement e
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateFromFile {
+ param const char *file
+ param bool genMips
+ ret RsAllocation
+ }
+
+AllocationCreateFromBitmap {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
+
+AllocationUploadToTexture {
+ param RsAllocation alloc
+ param uint32_t baseMipLevel
+ }
+
+AllocationUploadToBufferObject {
+ param RsAllocation alloc
+ }
+
+AllocationDestroy {
+ param RsAllocation alloc
+ }
+
+
+AllocationData {
+ param RsAllocation va
+ param const void * data
+ }
+
+Allocation1DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Allocation2DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+
+Adapter1DCreate {
+ ret RsAdapter1D
+ }
+
+Adapter1DBindAllocation {
+ param RsAdapter1D adapt
+ param RsAllocation alloc
+ }
+
+Adapter1DDestroy {
+ param RsAdapter1D adapter
+ }
+
+Adapter1DSetConstraint {
+ param RsAdapter1D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter1DData {
+ param RsAdapter1D adapter
+ param const void * data
+ }
+
+Adapter1DSubData {
+ param RsAdapter1D adapter
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Adapter2DCreate {
+ ret RsAdapter2D
+ }
+
+Adapter2DBindAllocation {
+ param RsAdapter2D adapt
+ param RsAllocation alloc
+ }
+
+Adapter2DDestroy {
+ param RsAdapter2D adapter
+ }
+
+Adapter2DSetConstraint {
+ param RsAdapter2D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter2DData {
+ param RsAdapter2D adapter
+ param const void *data
+ }
+
+Adapter2DSubData {
+ param RsAdapter2D adapter
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+SamplerBegin {
+ }
+
+SamplerSet {
+ param RsSamplerParam p
+ param RsSamplerValue value
+ }
+
+SamplerCreate {
+ ret RsSampler
+ }
+
+SamplerDestroy {
+ param RsSampler s
+ }
+
+TriangleMeshBegin {
+ param RsElement vertex
+ param RsElement index
+ }
+
+TriangleMeshAddVertex {
+ param const void *vtx
+ }
+
+TriangleMeshAddTriangle {
+ param uint32_t idx1
+ param uint32_t idx2
+ param uint32_t idx3
+ }
+
+TriangleMeshCreate {
+ ret RsTriangleMesh
+ }
+
+TriangleMeshDestroy {
+ param RsTriangleMesh mesh
+ }
+
+TriangleMeshRender {
+ param RsTriangleMesh vtm
+ }
+
+TriangleMeshRenderRange {
+ param RsTriangleMesh vtm
+ param uint32_t start
+ param uint32_t count
+ }
+
+ScriptDestroy {
+ param RsScript script
+ }
+
+ScriptBindAllocation {
+ param RsScript vtm
+ param RsAllocation va
+ param uint32_t slot
+ }
+
+
+ScriptCBegin {
+ }
+
+ScriptCSetClearColor {
+ param float r
+ param float g
+ param float b
+ param float a
+ }
+
+ScriptCSetClearDepth {
+ param float depth
+ }
+
+ScriptCSetClearStencil {
+ param uint32_t stencil
+ }
+
+ScriptCAddType {
+ param RsType type
+ }
+
+ScriptCSetRoot {
+ param bool isRoot
+ }
+
+ScriptCSetScript {
+ param void * codePtr
+ }
+
+ScriptCSetText {
+ param const char * text
+ param uint32_t length
+ }
+
+ScriptCCreate {
+ ret RsScript
+ }
+
+
+ProgramFragmentStoreBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentStoreColorMask {
+ param bool r
+ param bool g
+ param bool b
+ param bool a
+ }
+
+ProgramFragmentStoreBlendFunc {
+ param RsBlendSrcFunc srcFunc
+ param RsBlendDstFunc destFunc
+ }
+
+ProgramFragmentStoreDepthMask {
+ param bool enable
+}
+
+ProgramFragmentStoreDither {
+ param bool enable
+}
+
+ProgramFragmentStoreDepthFunc {
+ param RsDepthFunc func
+}
+
+ProgramFragmentStoreCreate {
+ ret RsProgramFragmentStore
+ }
+
+ProgramFragmentStoreDestroy {
+ param RsProgramFragmentStore pfs
+ }
+
+
+ProgramFragmentBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentBindTexture {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsAllocation a
+ }
+
+ProgramFragmentBindSampler {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsSampler s
+ }
+
+ProgramFragmentSetType {
+ param uint32_t slot
+ param RsType t
+ }
+
+ProgramFragmentSetEnvMode {
+ param uint32_t slot
+ param RsTexEnvMode env
+ }
+
+ProgramFragmentSetTexEnable {
+ param uint32_t slot
+ param bool enable
+ }
+
+ProgramFragmentCreate {
+ ret RsProgramFragment
+ }
+
+ProgramFragmentDestroy {
+ param RsProgramFragment pf
+ }
+
+
+ProgramVertexBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramVertexCreate {
+ ret RsProgramVertex
+ }
+
+ProgramVertexBindAllocation {
+ param RsProgramVertex vpgm
+ param uint32_t slot
+ param RsAllocation constants
+ }
+
+ProgramVertexSetType {
+ param uint32_t slot
+ param RsType constants
+ }
+
+ProgramVertexSetTextureMatrixEnable {
+ param bool enable
+ }
+
+ProgramVertexAddLight {
+ param RsLight light
+ }
+
+LightBegin {
+ }
+
+LightSetLocal {
+ param bool isLocal
+ }
+
+LightSetMonochromatic {
+ param bool isMono
+ }
+
+LightCreate {
+ ret RsLight light
+ }
+
+LightDestroy {
+ param RsLight light
+ }
+
+LightSetPosition {
+ param RsLight light
+ param float x
+ param float y
+ param float z
+ }
+
+LightSetColor {
+ param RsLight light
+ param float r
+ param float g
+ param float b
+ }
+
+FileOpen {
+ ret RsFile
+ param const char *name
+ param size_t len
+ }
+
+
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
new file mode 100644
index 0000000..7ac2aed
--- /dev/null
+++ b/libs/rs/rsAdapter.cpp
@@ -0,0 +1,245 @@
+
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Adapter1D::Adapter1D()
+{
+ reset();
+}
+
+Adapter1D::Adapter1D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter1D::reset()
+{
+ mY = 0;
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter1D::getElement(uint32_t x)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, mY);
+ return ptr;
+}
+
+void Adapter1D::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ if (mAllocation.get() && mAllocation.get()->getType()) {
+ void *ptr = getElement(xoff);
+ count *= mAllocation.get()->getType()->getElementSizeBytes();
+ memcpy(ptr, data, count);
+ }
+}
+
+void Adapter1D::data(const void *data)
+{
+ memcpy(getElement(0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+namespace android {
+namespace renderscript {
+
+RsAdapter1D rsi_Adapter1DCreate(Context *rsc)
+{
+ return new Adapter1D();
+}
+
+void rsi_Adapter1DDestroy(Context *rsc, RsAdapter1D va)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->decRef();
+}
+
+void rsi_Adapter1DBindAllocation(Context *rsc, RsAdapter1D va, RsAllocation valloc)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter1DSetConstraint(Context *rsc, RsAdapter1D va, RsDimension dim, uint32_t value)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 1D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ a->setY(value);
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter1DSubData(Context *rsc, RsAdapter1D va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->subData(xoff, count, data);
+}
+
+void rsi_Adapter1DData(Context *rsc, RsAdapter1D va, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->data(data);
+}
+
+}
+}
+
+//////////////////////////
+
+Adapter2D::Adapter2D()
+{
+ reset();
+}
+
+Adapter2D::Adapter2D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter2D::reset()
+{
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter2D::getElement(uint32_t x, uint32_t y) const
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, y);
+ return ptr;
+}
+
+void Adapter2D::subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+
+ uint32_t eSize = mAllocation.get()->getType()->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ memcpy(getElement(xoff, line), src, lineSize);
+ src += lineSize;
+ }
+}
+
+void Adapter2D::data(const void *data)
+{
+ memcpy(getElement(0,0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+RsAdapter2D rsi_Adapter2DCreate(Context *rsc)
+{
+ return new Adapter2D();
+}
+
+void rsi_Adapter2DDestroy(Context *rsc, RsAdapter2D va)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->decRef();
+}
+
+void rsi_Adapter2DBindAllocation(Context *rsc, RsAdapter2D va, RsAllocation valloc)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter2DSetConstraint(Context *rsc, RsAdapter2D va, RsDimension dim, uint32_t value)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 2D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ rsAssert(!"Cannot contrain Y in an 2D adapter");
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter2DData(Context *rsc, RsAdapter2D va, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->data(data);
+}
+
+void rsi_Adapter2DSubData(Context *rsc, RsAdapter2D va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->subData(xoff, yoff, w, h, data);
+}
+
+}
+}
diff --git a/libs/rs/rsAdapter.h b/libs/rs/rsAdapter.h
new file mode 100644
index 0000000..865535e
--- /dev/null
+++ b/libs/rs/rsAdapter.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 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_RS_ADAPTER_H
+#define ANDROID_RS_ADAPTER_H
+
+#include "rsAllocation.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Adapter1D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter1D();
+ Adapter1D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x);
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ inline void setY(uint32_t y) {mY = y;}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void data(const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mY;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+class Adapter2D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter2D();
+ Adapter2D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x, uint32_t y) const;
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+ uint32_t getDimY() const {return mAllocation->getType()->getLODDimY(mLOD);}
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
new file mode 100644
index 0000000..c143307
--- /dev/null
+++ b/libs/rs/rsAllocation.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Allocation::Allocation(const Type *type)
+{
+ mPtr = NULL;
+
+ mCpuWrite = false;
+ mCpuRead = false;
+ mGpuWrite = false;
+ mGpuRead = false;
+
+ mReadWriteRatio = 0;
+ mUpdateSize = 0;
+
+ mIsTexture = false;
+ mTextureID = 0;
+
+ mIsVertexBuffer = false;
+ mBufferID = 0;
+
+ mType.set(type);
+ mPtr = malloc(mType->getSizeBytes());
+ if (!mPtr) {
+ LOGE("Allocation::Allocation, alloc failure");
+ }
+
+}
+
+Allocation::~Allocation()
+{
+}
+
+void Allocation::setCpuWritable(bool)
+{
+}
+
+void Allocation::setGpuWritable(bool)
+{
+}
+
+void Allocation::setCpuReadable(bool)
+{
+}
+
+void Allocation::setGpuReadable(bool)
+{
+}
+
+bool Allocation::fixAllocation()
+{
+ return false;
+}
+
+void Allocation::uploadToTexture(uint32_t lodOffset)
+{
+ //rsAssert(!mTextureId);
+ rsAssert(lodOffset < mType->getLODCount());
+
+ GLenum type = mType->getElement()->getGLType();
+ GLenum format = mType->getElement()->getGLFormat();
+
+ if (!type || !format) {
+ return;
+ }
+
+ if (!mTextureID) {
+ glGenTextures(1, &mTextureID);
+ }
+ glBindTexture(GL_TEXTURE_2D, mTextureID);
+
+ Adapter2D adapt(this);
+ for(uint32_t lod = 0; (lod + lodOffset) < mType->getLODCount(); lod++) {
+ adapt.setLOD(lod+lodOffset);
+
+ uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
+ glTexImage2D(GL_TEXTURE_2D, lod, format,
+ adapt.getDimX(), adapt.getDimY(),
+ 0, format, type, ptr);
+ }
+}
+
+void Allocation::uploadToBufferObject()
+{
+ rsAssert(!mType->getDimY());
+ rsAssert(!mType->getDimZ());
+
+ if (!mBufferID) {
+ glGenBuffers(1, &mBufferID);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
+ glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void Allocation::data(const void *data)
+{
+ memcpy(mPtr, data, mType->getSizeBytes());
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ ptr += eSize * xoff;
+ memcpy(ptr, data, count * eSize);
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = mType->getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ uint8_t *dst = static_cast<uint8_t *>(mPtr);
+ dst += eSize * (xoff + yoff * destW);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ memcpy(dst, src, lineSize);
+ src += lineSize;
+ dst += destW * eSize;
+ }
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data)
+{
+}
+
+
+
+/////////////////
+//
+
+
+namespace android {
+namespace renderscript {
+
+RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
+{
+ const Type * type = static_cast<const Type *>(vtype);
+
+ Allocation * alloc = new Allocation(type);
+ alloc->incRef();
+ return alloc;
+}
+
+RsAllocation rsi_AllocationCreatePredefSized(Context *rsc, RsElementPredefined t, size_t count)
+{
+ RsElement e = rsi_ElementGetPredefined(rsc, t);
+ return rsi_AllocationCreateSized(rsc, e, count);
+}
+
+RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
+{
+ Type * type = new Type();
+ type->setDimX(count);
+ type->setElement(static_cast<Element *>(e));
+ type->compute();
+ return rsi_AllocationCreateTyped(rsc, type);
+}
+
+void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToTexture(baseMipLevel);
+}
+
+void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToBufferObject();
+}
+
+void rsi_AllocationDestroy(Context *rsc, RsAllocation)
+{
+}
+
+static void mip565(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < w; y++) {
+ uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
+ const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
+ const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < h; x++) {
+ *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+}
+
+static void mip8888(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < w; y++) {
+ uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
+ const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
+ const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < h; x++) {
+ *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+
+}
+
+
+typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
+
+static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 2);
+}
+static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count);
+}
+static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 4);
+}
+
+
+static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 3;
+ }
+}
+
+static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 4;
+ }
+}
+
+static ElementConverter_t pickConverter(RsElementPredefined dstFmt, RsElementPredefined srcFmt)
+{
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_565)) {
+ return elementConverter_cpy_16;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_888)) {
+ return elementConverter_888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_8888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGBA_8888) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_cpy_32;
+ }
+
+ LOGE("pickConverter, unsuported combo");
+ return 0;
+}
+
+
+RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ return NULL;
+ }
+ texAlloc->incRef();
+
+ ElementConverter_t cvt = pickConverter(dstFmt, srcFmt);
+ cvt(texAlloc->getPtr(), data, w * h);
+
+ if (genMips) {
+ Adapter2D adapt(texAlloc);
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ mip565(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
+{
+ bool use32bpp = false;
+
+ typedef struct _Win3xBitmapHeader
+ {
+ uint16_t type;
+ uint32_t totalSize;
+ uint32_t reserved;
+ uint32_t offset;
+ int32_t hdrSize; /* Size of this header in bytes */
+ int32_t width; /* Image width in pixels */
+ int32_t height; /* Image height in pixels */
+ int16_t planes; /* Number of color planes */
+ int16_t bpp; /* Number of bits per pixel */
+ /* Fields added for Windows 3.x follow this line */
+ int32_t compression; /* Compression methods used */
+ int32_t sizeOfBitmap; /* Size of bitmap in bytes */
+ int32_t horzResolution; /* Horizontal resolution in pixels per meter */
+ int32_t vertResolution; /* Vertical resolution in pixels per meter */
+ int32_t colorsUsed; /* Number of colors in the image */
+ int32_t colorsImportant; /* Minimum number of important colors */
+ } __attribute__((__packed__)) WIN3XBITMAPHEADER;
+
+ _Win3xBitmapHeader hdr;
+
+ FILE *f = fopen(file, "rb");
+ if (f == NULL) {
+ LOGE("rsAllocationCreateFromBitmap failed to open file %s", file);
+ return NULL;
+ }
+ memset(&hdr, 0, sizeof(hdr));
+ fread(&hdr, sizeof(hdr), 1, f);
+
+ if (hdr.bpp != 24) {
+ LOGE("Unsuported BMP type");
+ fclose(f);
+ return NULL;
+ }
+
+ int32_t texWidth = rsHigherPow2(hdr.width);
+ int32_t texHeight = rsHigherPow2(hdr.height);
+
+ if (use32bpp) {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGBA_8888));
+ } else {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ }
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, texWidth);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, texHeight);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ texAlloc->incRef();
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ fclose(f);
+ return NULL;
+ }
+
+ // offset to letterbox if height is not pow2
+ Adapter2D adapt(texAlloc);
+ uint8_t * fileInBuf = new uint8_t[texWidth * 3];
+ uint32_t yOffset = (hdr.width - hdr.height) / 2;
+
+ if (use32bpp) {
+ uint8_t *tmp = static_cast<uint8_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ tmp[0] = fileInBuf[x*3 + 2];
+ tmp[1] = fileInBuf[x*3 + 1];
+ tmp[2] = fileInBuf[x*3];
+ tmp[3] = 0xff;
+ tmp += 4;
+ }
+ }
+ } else {
+ uint16_t *tmp = static_cast<uint16_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ *tmp = rs888to565(fileInBuf[x*3 + 2], fileInBuf[x*3 + 1], fileInBuf[x*3]);
+ tmp++;
+ }
+ }
+ }
+
+ fclose(f);
+ delete [] fileInBuf;
+
+ if (genMips) {
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ if (use32bpp) {
+ mip8888(adapt2, adapt);
+ } else {
+ mip565(adapt2, adapt);
+ }
+ }
+ }
+
+ return texAlloc;
+}
+
+
+void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->data(data);
+}
+
+void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, count, data);
+}
+
+void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, yoff, w, h, data);
+}
+
+
+}
+}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
new file mode 100644
index 0000000..d0b91fd
--- /dev/null
+++ b/libs/rs/rsAllocation.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 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_STRUCTURED_ALLOCATION_H
+#define ANDROID_STRUCTURED_ALLOCATION_H
+
+#include "rsType.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Allocation : public ObjectBase
+{
+ // The graphics equilivent of malloc. The allocation contains a structure of elements.
+
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Allocation(const Type *);
+ virtual ~Allocation();
+
+ void setCpuWritable(bool);
+ void setGpuWritable(bool);
+ void setCpuReadable(bool);
+ void setGpuReadable(bool);
+
+ bool fixAllocation();
+
+ void * getPtr() const {return mPtr;}
+ const Type * getType() const {return mType.get();}
+
+ void uploadToTexture(uint32_t lodOffset = 0);
+ uint32_t getTextureID() const {return mTextureID;}
+
+ void uploadToBufferObject();
+ uint32_t getBufferObjectID() const {return mBufferID;}
+
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data);
+
+protected:
+ ObjectBaseRef<const Type> mType;
+ void * mPtr;
+
+ // Usage restrictions
+ bool mCpuWrite;
+ bool mCpuRead;
+ bool mGpuWrite;
+ bool mGpuRead;
+
+ // more usage hint data from the application
+ // which can be used by a driver to pick the best memory type.
+ // Likely ignored for now
+ float mReadWriteRatio;
+ float mUpdateSize;
+
+
+ // Is this a legal structure to be used as a texture source.
+ // Initially this will require 1D or 2D and color data
+ bool mIsTexture;
+ uint32_t mTextureID;
+
+ // Is this a legal structure to be used as a vertex source.
+ // Initially this will require 1D and x(yzw). Additional per element data
+ // is allowed.
+ bool mIsVertexBuffer;
+ uint32_t mBufferID;
+
+};
+
+}
+}
+#endif
+
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/rs/rsComponent.cpp
index 2e3c3a0..a931811 100644
--- a/libs/utils/executablepath_darwin.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -14,18 +14,30 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
+#include "rsComponent.h"
-void executablepath(char s[PATH_MAX])
+using namespace android;
+using namespace android::renderscript;
+
+
+Component::Component()
{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
+ mType = FLOAT;
+ mKind = NONE;
+ mIsNormalized = false;
+ mBits = 0;
}
+Component::Component(
+ DataKind dk, DataType dt,
+ bool isNormalized, uint32_t bits)
+{
+ mType = dt;
+ mKind = dk;
+ mIsNormalized = isNormalized;
+ mBits = bits;
+}
+
+Component::~Component()
+{
+}
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
new file mode 100644
index 0000000..e1b0585
--- /dev/null
+++ b/libs/rs/rsComponent.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 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_RS_STRUCTURED_COMPONENT_H
+#define ANDROID_RS_STRUCTURED_COMPONENT_H
+
+#include "rsUtils.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Component : public ObjectBase
+{
+public:
+ enum DataType {
+ FLOAT,
+ UNSIGNED,
+ SIGNED
+ };
+
+ enum DataKind {
+ NONE,
+ RED, GREEN, BLUE, ALPHA, LUMINANCE, INTENSITY,
+ X, Y, Z, W,
+ S, T, Q, R,
+ NX, NY, NZ,
+ INDEX,
+ USER
+ };
+
+
+ Component(DataKind dk, DataType dt, bool isNormalized, uint32_t bits);
+ virtual ~Component();
+
+ DataType getType() const {return mType;}
+ bool getIsNormalized() const {return mIsNormalized;}
+ DataKind getKind() const {return mKind;}
+ uint32_t getBits() const {return mBits;}
+
+protected:
+
+ DataType mType;
+ bool mIsNormalized;
+ DataKind mKind;
+ uint32_t mBits;
+
+private:
+ Component();
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_STRUCTURED_COMPONENT_H
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
new file mode 100644
index 0000000..78b8bf8
--- /dev/null
+++ b/libs/rs/rsContext.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2009 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 "rsDevice.h"
+#include "rsContext.h"
+#include "rsThreadIO.h"
+#include "utils/String8.h"
+#include <ui/FramebufferNativeWindow.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Context * Context::gCon = NULL;
+pthread_key_t Context::gThreadTLSKey = 0;
+
+void Context::initEGL()
+{
+ mNumConfigs = -1;
+
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+#if 1
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+#else
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+#endif
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion);
+ eglChooseConfig(mDisplay, s_configAttribs, &mConfig, 1, &mNumConfigs);
+
+ if (mWndSurface) {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig, mWndSurface,
+ NULL);
+ } else {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig,
+ android_createDisplaySurface(),
+ NULL);
+ }
+
+ mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL);
+ eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+ eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mHeight);
+}
+
+bool Context::runScript(Script *s, uint32_t launchID)
+{
+ ObjectBaseRef<ProgramFragment> frag(mFragment);
+ ObjectBaseRef<ProgramVertex> vtx(mVertex);
+ ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore);
+
+ bool ret = s->run(this, launchID);
+
+ mFragment.set(frag);
+ mVertex.set(vtx);
+ mFragmentStore.set(store);
+ return true;
+
+}
+
+
+bool Context::runRootScript()
+{
+ rsAssert(mRootScript->mEnviroment.mIsRoot);
+
+ glColor4f(1,1,1,1);
+ glEnable(GL_LIGHT0);
+ glViewport(0, 0, mWidth, mHeight);
+
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glClearColor(mRootScript->mEnviroment.mClearColor[0],
+ mRootScript->mEnviroment.mClearColor[1],
+ mRootScript->mEnviroment.mClearColor[2],
+ mRootScript->mEnviroment.mClearColor[3]);
+ glClearDepthf(mRootScript->mEnviroment.mClearDepth);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ return runScript(mRootScript.get(), 0);
+}
+
+void Context::setupCheck()
+{
+ if (mFragmentStore.get()) {
+ mFragmentStore->setupGL();
+ }
+ if (mFragment.get()) {
+ mFragment->setupGL();
+ }
+ if (mVertex.get()) {
+ mVertex->setupGL();
+ }
+
+}
+
+
+void * Context::threadProc(void *vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+
+ gIO = new ThreadIO();
+ rsc->initEGL();
+
+ ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
+ if (!tlsStruct) {
+ LOGE("Error allocating tls storage");
+ return NULL;
+ }
+ tlsStruct->mContext = rsc;
+ tlsStruct->mScript = NULL;
+ int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct);
+ if (status) {
+ LOGE("pthread_setspecific %i", status);
+ }
+
+ rsc->mStateVertex.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setVertex(NULL);
+ rsc->mStateFragment.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setFragment(NULL);
+ rsc->mStateFragmentStore.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setFragmentStore(NULL);
+
+ rsc->mRunning = true;
+ bool mDraw = true;
+ while (!rsc->mExit) {
+ mDraw |= gIO->playCoreCommands(rsc, !mDraw);
+ mDraw &= (rsc->mRootScript.get() != NULL);
+
+ if (mDraw) {
+ mDraw = rsc->runRootScript();
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ }
+ }
+
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ eglTerminate(rsc->mDisplay);
+ return NULL;
+}
+
+Context::Context(Device *dev, Surface *sur)
+{
+ dev->addContext(this);
+ mDev = dev;
+ mRunning = false;
+ mExit = false;
+
+ // see comment in header
+ gCon = this;
+
+ int status;
+ pthread_attr_t threadAttr;
+
+ status = pthread_key_create(&gThreadTLSKey, NULL);
+ if (status) {
+ LOGE("Failed to init thread tls key.");
+ return;
+ }
+
+ status = pthread_attr_init(&threadAttr);
+ if (status) {
+ LOGE("Failed to init thread attribute.");
+ return;
+ }
+
+ sched_param sparam;
+ sparam.sched_priority = ANDROID_PRIORITY_DISPLAY;
+ pthread_attr_setschedparam(&threadAttr, &sparam);
+
+ mWndSurface = sur;
+
+ LOGV("RS Launching thread");
+ status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
+ if (status) {
+ LOGE("Failed to start rs context thread.");
+ }
+
+ while(!mRunning) {
+ sleep(1);
+ }
+
+ pthread_attr_destroy(&threadAttr);
+}
+
+Context::~Context()
+{
+ mExit = true;
+ void *res;
+
+ int status = pthread_join(mThreadId, &res);
+
+ if (mDev) {
+ mDev->removeContext(this);
+ pthread_key_delete(gThreadTLSKey);
+ }
+}
+
+void Context::swapBuffers()
+{
+ eglSwapBuffers(mDisplay, mSurface);
+}
+
+void rsContextSwap(RsContext vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+ rsc->swapBuffers();
+}
+
+void Context::setRootScript(Script *s)
+{
+ mRootScript.set(s);
+}
+
+void Context::setFragmentStore(ProgramFragmentStore *pfs)
+{
+ if (pfs == NULL) {
+ mFragmentStore.set(mStateFragmentStore.mDefault);
+ } else {
+ mFragmentStore.set(pfs);
+ }
+ mFragmentStore->setupGL();
+}
+
+void Context::setFragment(ProgramFragment *pf)
+{
+ if (pf == NULL) {
+ mFragment.set(mStateFragment.mDefault);
+ } else {
+ mFragment.set(pf);
+ }
+ mFragment->setupGL();
+}
+
+void Context::setVertex(ProgramVertex *pv)
+{
+ if (pv == NULL) {
+ mVertex.set(mStateVertex.mDefault);
+ } else {
+ mVertex.set(pv);
+ }
+ mVertex->setupGL();
+}
+
+void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
+{
+ rsAssert(!obj->getName());
+ obj->setName(name, len);
+ mNames.add(obj);
+}
+
+void Context::removeName(ObjectBase *obj)
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (obj == mNames[ct]) {
+ mNames.removeAt(ct);
+ return;
+ }
+ }
+}
+
+ObjectBase * Context::lookupName(const char *name) const
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (!strcmp(name, mNames[ct]->getName())) {
+ return mNames[ct];
+ }
+ }
+ return NULL;
+}
+
+void Context::appendNameDefines(String8 *str) const
+{
+ char buf[256];
+ for (size_t ct=0; ct < mNames.size(); ct++) {
+ str->append("#define NAMED_");
+ str->append(mNames[ct]->getName());
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mNames[ct]);
+ str->append(buf);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_ContextBindRootScript(Context *rsc, RsScript vs)
+{
+ Script *s = static_cast<Script *>(vs);
+ rsc->setRootScript(s);
+}
+
+void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs)
+{
+ Sampler *s = static_cast<Sampler *>(vs);
+
+ if (slot > RS_MAX_SAMPLER_SLOT) {
+ LOGE("Invalid sampler slot");
+ return;
+ }
+
+ s->bindToContext(&rsc->mStateSampler, slot);
+}
+
+void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs)
+{
+ ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs);
+ rsc->setFragmentStore(pfs);
+}
+
+void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ rsc->setFragment(pf);
+}
+
+void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpv);
+ rsc->setVertex(pv);
+}
+
+void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len)
+{
+ ObjectBase *ob = static_cast<ObjectBase *>(obj);
+ rsc->assignName(ob, name, len);
+}
+
+
+}
+}
+
+
+RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version)
+{
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = new Context(dev, (Surface *)sur);
+ return rsc;
+}
+
+void rsContextDestroy(RsContext vrsc)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ delete rsc;
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
new file mode 100644
index 0000000..497dbcf
--- /dev/null
+++ b/libs/rs/rsContext.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 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_RS_CONTEXT_H
+#define ANDROID_RS_CONTEXT_H
+
+#include "rsUtils.h"
+
+#include <utils/Vector.h>
+#include <ui/Surface.h>
+
+#include "rsType.h"
+#include "rsMatrix.h"
+#include "rsAllocation.h"
+#include "rsTriangleMesh.h"
+#include "rsMesh.h"
+#include "rsDevice.h"
+#include "rsScriptC.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rsSampler.h"
+#include "rsLight.h"
+#include "rsProgramFragment.h"
+#include "rsProgramFragmentStore.h"
+#include "rsProgramVertex.h"
+
+#include "rsgApiStructs.h"
+#include "rsLocklessFifo.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context
+{
+public:
+ Context(Device *, Surface *);
+ ~Context();
+
+ static pthread_key_t gThreadTLSKey;
+ struct ScriptTLSStruct {
+ Context * mContext;
+ Script * mScript;
+ };
+
+
+ //StructuredAllocationContext mStateAllocation;
+ ElementState mStateElement;
+ TypeState mStateType;
+ SamplerState mStateSampler;
+ ProgramFragmentState mStateFragment;
+ ProgramFragmentStoreState mStateFragmentStore;
+ ProgramVertexState mStateVertex;
+ LightState mStateLight;
+
+ TriangleMeshContext mStateTriangleMesh;
+
+ ScriptCState mScriptC;
+
+ static Context * getContext() {return gCon;}
+
+ void swapBuffers();
+ void setRootScript(Script *);
+ void setVertex(ProgramVertex *);
+ void setFragment(ProgramFragment *);
+ void setFragmentStore(ProgramFragmentStore *);
+
+ void updateSurface(void *sur);
+
+ const ProgramFragment * getFragment() {return mFragment.get();}
+ const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+
+ void setupCheck();
+
+ void assignName(ObjectBase *obj, const char *name, uint32_t len);
+ void removeName(ObjectBase *obj);
+ ObjectBase * lookupName(const char *name) const;
+ void appendNameDefines(String8 *str) const;
+
+
+ ProgramFragment * getDefaultProgramFragment() const {
+ return mStateFragment.mDefault.get();
+ }
+ ProgramVertex * getDefaultProgramVertex() const {
+ return mStateVertex.mDefault.get();
+ }
+ ProgramFragmentStore * getDefaultProgramFragmentStore() const {
+ return mStateFragmentStore.mDefault.get();
+ }
+
+protected:
+ Device *mDev;
+
+ EGLint mNumConfigs;
+ EGLint mMajorVersion;
+ EGLint mMinorVersion;
+ EGLConfig mConfig;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLDisplay mDisplay;
+
+ bool mRunning;
+ bool mExit;
+
+ pthread_t mThreadId;
+
+ ObjectBaseRef<Script> mRootScript;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+private:
+ Context();
+
+ void initEGL();
+
+ bool runScript(Script *s, uint32_t launchID);
+ bool runRootScript();
+
+ static void * threadProc(void *);
+
+ // todo: put in TLS
+ static Context *gCon;
+ Surface *mWndSurface;
+
+ Vector<ObjectBase *> mNames;
+};
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
new file mode 100644
index 0000000..1b3c41b
--- /dev/null
+++ b/libs/rs/rsDevice.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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 "rsDevice.h"
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Device::Device()
+{
+
+}
+
+Device::~Device()
+{
+
+}
+
+void Device::addContext(Context *rsc)
+{
+ mContexts.add(rsc);
+}
+
+void Device::removeContext(Context *rsc)
+{
+ for (size_t idx=0; idx < mContexts.size(); idx++) {
+ if (mContexts[idx] == rsc) {
+ mContexts.removeAt(idx);
+ break;
+ }
+ }
+}
+
+
+
+RsDevice rsDeviceCreate()
+{
+ Device * d = new Device();
+ return d;
+}
+
+void rsDeviceDestroy(RsDevice dev)
+{
+ Device * d = static_cast<Device *>(dev);
+ delete d;
+
+}
+
diff --git a/libs/rs/rsDevice.h b/libs/rs/rsDevice.h
new file mode 100644
index 0000000..156315f
--- /dev/null
+++ b/libs/rs/rsDevice.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 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_RS_DEVICE_H
+#define ANDROID_RS_DEVICE_H
+
+#include "rsUtils.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class Device {
+public:
+ Device();
+ ~Device();
+
+ void addContext(Context *);
+ void removeContext(Context *);
+
+protected:
+ Vector<Context *> mContexts;
+
+
+};
+
+
+
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
new file mode 100644
index 0000000..069a128
--- /dev/null
+++ b/libs/rs/rsElement.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+void ElementState::initPredefined()
+{
+ Component * u_8 = new Component(Component::USER, Component::UNSIGNED, true, 8);
+ Component * i_8 = new Component(Component::USER, Component::SIGNED, true, 8);
+ Component * u_16 = new Component(Component::USER, Component::UNSIGNED, true, 16);
+ Component * i_16 = new Component(Component::USER, Component::SIGNED, true, 16);
+ Component * u_32 = new Component(Component::USER, Component::UNSIGNED, true, 32);
+ Component * i_32 = new Component(Component::USER, Component::SIGNED, true, 32);
+ Component * f_32 = new Component(Component::USER, Component::FLOAT, true, 32);
+
+
+ Component * r_4 = new Component(Component::RED, Component::UNSIGNED, true, 4);
+ Component * r_5 = new Component(Component::RED, Component::UNSIGNED, true, 5);
+ Component * r_8 = new Component(Component::RED, Component::UNSIGNED, true, 8);
+
+ Component * g_4 = new Component(Component::GREEN, Component::UNSIGNED, true, 4);
+ Component * g_5 = new Component(Component::GREEN, Component::UNSIGNED, true, 5);
+ Component * g_6 = new Component(Component::GREEN, Component::UNSIGNED, true, 6);
+ Component * g_8 = new Component(Component::GREEN, Component::UNSIGNED, true, 8);
+
+ Component * b_4 = new Component(Component::BLUE, Component::UNSIGNED, true, 4);
+ Component * b_5 = new Component(Component::BLUE, Component::UNSIGNED, true, 5);
+ Component * b_8 = new Component(Component::BLUE, Component::UNSIGNED, true, 8);
+
+ Component * a_1 = new Component(Component::ALPHA, Component::UNSIGNED, true, 1);
+ Component * a_4 = new Component(Component::ALPHA, Component::UNSIGNED, true, 4);
+ Component * a_8 = new Component(Component::ALPHA, Component::UNSIGNED, true, 8);
+
+ Component * idx_16 = new Component(Component::INDEX, Component::UNSIGNED, false, 16);
+ Component * idx_32 = new Component(Component::INDEX, Component::UNSIGNED, false, 32);
+
+ Component * x = new Component(Component::X, Component::FLOAT, false, 32);
+ Component * y = new Component(Component::Y, Component::FLOAT, false, 32);
+ Component * z = new Component(Component::Z, Component::FLOAT, false, 32);
+
+ Component * nx = new Component(Component::NX, Component::FLOAT, false, 32);
+ Component * ny = new Component(Component::NY, Component::FLOAT, false, 32);
+ Component * nz = new Component(Component::NZ, Component::FLOAT, false, 32);
+
+ Component * s = new Component(Component::S, Component::FLOAT, false, 32);
+ Component * t = new Component(Component::T, Component::FLOAT, false, 32);
+
+ Element * e;
+
+ e = new Element(1);
+ e->setComponent(0, u_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U8, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I8, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U16, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I16, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U32, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I32, e));
+
+ e = new Element(1);
+ e->setComponent(0, f_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_FLOAT, e));
+
+ e = new Element(1);
+ e->setComponent(0, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_A_8, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_6);
+ e->setComponent(2, b_5);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_565, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_5);
+ e->setComponent(2, b_5);
+ e->setComponent(3, a_1);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_5551, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_4);
+ e->setComponent(1, g_4);
+ e->setComponent(2, b_4);
+ e->setComponent(3, a_4);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_4444, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_888, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ e->setComponent(3, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_8888, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_16, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_32, e));
+
+ e = new Element(2);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XY_F32, e));
+
+ e = new Element(3);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ e->setComponent(2, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XYZ_F32, e));
+
+ e = new Element(4);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XY_F32, e));
+
+ e = new Element(5);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ e->setComponent(4, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XYZ_F32, e));
+
+ e = new Element(6);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, x);
+ e->setComponent(4, y);
+ e->setComponent(5, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_XYZ_F32, e));
+
+ e = new Element(8);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, s);
+ e->setComponent(4, t);
+ e->setComponent(5, x);
+ e->setComponent(6, y);
+ e->setComponent(7, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_ST_XYZ_F32, e));
+}
+
+
+Element::Element()
+{
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+Element::Element(uint32_t count)
+{
+ mComponents = new ObjectBaseRef<Component> [count];
+ mComponentCount = count;
+}
+
+Element::~Element()
+{
+ clear();
+}
+
+void Element::clear()
+{
+ delete [] mComponents;
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+void Element::setComponent(uint32_t idx, Component *c)
+{
+ rsAssert(!mComponents[idx].get());
+ rsAssert(idx < mComponentCount);
+ mComponents[idx].set(c);
+ c->incRef();
+}
+
+
+size_t Element::getSizeBits() const
+{
+ size_t total = 0;
+ for (size_t ct=0; ct < mComponentCount; ct++) {
+ total += mComponents[ct]->getBits();
+ }
+ return total;
+}
+
+size_t Element::getComponentOffsetBits(uint32_t componentNumber) const
+{
+ size_t offset = 0;
+ for (uint32_t ct = 0; ct < componentNumber; ct++) {
+ offset += mComponents[ct]->getBits();
+ }
+ return offset;
+}
+
+uint32_t Element::getGLType() const
+{
+ int bits[4];
+
+ if (mComponentCount > 4) {
+ return 0;
+ }
+
+ for (uint32_t ct=0; ct < mComponentCount; ct++) {
+ bits[ct] = mComponents[ct]->getBits();
+ if (mComponents[ct]->getType() != Component::UNSIGNED) {
+ return 0;
+ }
+ if (!mComponents[ct]->getIsNormalized()) {
+ return 0;
+ }
+ }
+
+ switch(mComponentCount) {
+ case 1:
+ if (bits[0] == 8) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 2:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 3:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 6) &&
+ (bits[2] == 5)) {
+ return GL_UNSIGNED_SHORT_5_6_5;
+ }
+ return 0;
+ case 4:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8) &&
+ (bits[3] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 4) &&
+ (bits[1] == 4) &&
+ (bits[2] == 4) &&
+ (bits[3] == 4)) {
+ return GL_UNSIGNED_SHORT_4_4_4_4;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 5) &&
+ (bits[2] == 5) &&
+ (bits[3] == 1)) {
+ return GL_UNSIGNED_SHORT_5_5_5_1;
+ }
+ }
+ return 0;
+}
+
+uint32_t Element::getGLFormat() const
+{
+ switch(mComponentCount) {
+ case 1:
+ if (mComponents[0]->getKind() == Component::ALPHA) {
+ return GL_ALPHA;
+ }
+ if (mComponents[0]->getKind() == Component::LUMINANCE) {
+ return GL_LUMINANCE;
+ }
+ break;
+ case 2:
+ if ((mComponents[0]->getKind() == Component::LUMINANCE) &&
+ (mComponents[1]->getKind() == Component::ALPHA)) {
+ return GL_LUMINANCE_ALPHA;
+ }
+ break;
+ case 3:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE)) {
+ return GL_RGB;
+ }
+ break;
+ case 4:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE) &&
+ (mComponents[3]->getKind() == Component::ALPHA)) {
+ return GL_RGBA;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+ElementState::ElementState()
+{
+}
+
+ElementState::~ElementState()
+{
+}
+
+/////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_ElementBegin(Context *rsc)
+{
+ rsc->mStateElement.mComponentBuildList.clear();
+}
+
+void rsi_ElementAddPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ RsElement ve = rsi_ElementGetPredefined(rsc, predef);
+ const Element *e = static_cast<const Element *>(ve);
+
+ for(size_t ct = 0; ct < sec->mPredefinedList[predef].mElement->getComponentCount(); ct++) {
+ sec->mComponentBuildList.add(sec->mPredefinedList[predef].mElement->getComponent(ct));
+ }
+}
+
+RsElement rsi_ElementGetPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ if (!sec->mPredefinedList.size()) {
+ sec->initPredefined();
+ }
+
+ if ((predef < 0) ||
+ (static_cast<uint32_t>(predef) >= sec->mPredefinedList.size())) {
+ LOGE("rsElementGetPredefined: Request for bad predefined type");
+ // error
+ return NULL;
+ }
+
+ rsAssert(sec->mPredefinedList[predef].mEnum == predef);
+ Element * e = sec->mPredefinedList[predef].mElement;
+ e->incRef();
+ return e;
+}
+
+void rsi_ElementAdd(Context *rsc, RsDataKind dk, RsDataType dt, bool isNormalized, size_t bits)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+}
+
+RsElement rsi_ElementCreate(Context *rsc)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ Element *se = new Element(sec->mComponentBuildList.size());
+ sec->mAllElements.add(se);
+
+ for (size_t ct = 0; ct < se->getComponentCount(); ct++) {
+ se->setComponent(ct, sec->mComponentBuildList[ct]);
+ }
+
+ rsc->mStateElement.mComponentBuildList.clear();
+ se->incRef();
+ return se;
+}
+
+void rsi_ElementDestroy(Context *rsc, RsElement vse)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Element * se = static_cast<Element *>(vse);
+
+ for (size_t ct = 0; ct < sec->mAllElements.size(); ct++) {
+ if (sec->mAllElements[ct] == se) {
+ sec->mAllElements.removeAt(ct);
+ break;
+ }
+ }
+ se->decRef();
+}
+
+
+}
+}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
new file mode 100644
index 0000000..ea6fa8f
--- /dev/null
+++ b/libs/rs/rsElement.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 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_STRUCTURED_ELEMENT_H
+#define ANDROID_STRUCTURED_ELEMENT_H
+
+#include "rsComponent.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Element : public ObjectBase
+{
+public:
+ Element(uint32_t count);
+ ~Element();
+
+
+ void setComponent(uint32_t idx, Component *c);
+
+ uint32_t getGLType() const;
+ uint32_t getGLFormat() const;
+
+
+ size_t getSizeBits() const;
+ size_t getSizeBytes() const {
+ return (getSizeBits() + 7) >> 3;
+ }
+
+ size_t getComponentOffsetBits(uint32_t componentNumber) const;
+ size_t getComponentOffsetBytes(uint32_t componentNumber) const {
+ return (getComponentOffsetBits(componentNumber) + 7) >> 3;
+ }
+
+ uint32_t getComponentCount() const {return mComponentCount;}
+ Component * getComponent(uint32_t idx) const {return mComponents[idx].get();}
+
+protected:
+ // deallocate any components that are part of this element.
+ void clear();
+
+ size_t mComponentCount;
+ ObjectBaseRef<Component> * mComponents;
+ //uint32_t *mOffsetTable;
+
+ Element();
+};
+
+
+class ElementState {
+public:
+ ElementState();
+ ~ElementState();
+
+ Vector<Element *> mAllElements;
+ Vector<Component *> mComponentBuildList;
+
+
+
+ struct Predefined {
+ Predefined() {
+ mElement = NULL;
+ }
+ Predefined(RsElementPredefined en, Element *e) {
+ mEnum = en;
+ mElement = e;
+ }
+ RsElementPredefined mEnum;
+ Element * mElement;
+ };
+ Vector<Predefined> mPredefinedList;
+
+ void initPredefined();
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_ELEMENT_H
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
new file mode 100644
index 0000000..86d294b
--- /dev/null
+++ b/libs/rs/rsFileA3D.cpp
@@ -0,0 +1,384 @@
+
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+
+#include <utils/String8.h>
+#include "rsFileA3D.h"
+
+#include "rsMesh.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+FileA3D::FileA3D()
+{
+ mRsc = NULL;
+}
+
+FileA3D::~FileA3D()
+{
+}
+
+bool FileA3D::load(Context *rsc, FILE *f)
+{
+ char magicString[12];
+ size_t len;
+
+ LOGE("file open 1");
+ len = fread(magicString, 1, 12, f);
+ if ((len != 12) ||
+ memcmp(magicString, "Android3D_ff", 12)) {
+ return false;
+ }
+
+ LOGE("file open 2");
+ len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f);
+ if (len != sizeof(mMajorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 3");
+ len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f);
+ if (len != sizeof(mMinorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 4");
+ uint32_t flags;
+ len = fread(&flags, 1, sizeof(flags), f);
+ if (len != sizeof(flags)) {
+ return false;
+ }
+ mUse64BitOffsets = (flags & 1) != 0;
+
+ LOGE("file open 64bit = %i", mUse64BitOffsets);
+
+ if (mUse64BitOffsets) {
+ len = fread(&mDataSize, 1, sizeof(mDataSize), f);
+ if (len != sizeof(mDataSize)) {
+ return false;
+ }
+ } else {
+ uint32_t tmp;
+ len = fread(&tmp, 1, sizeof(tmp), f);
+ if (len != sizeof(tmp)) {
+ return false;
+ }
+ mDataSize = tmp;
+ }
+
+ LOGE("file open size = %lli", mDataSize);
+
+ // We should know enough to read the file in at this point.
+ fseek(f, SEEK_SET, 0);
+ mAlloc= malloc(mDataSize);
+ if (!mAlloc) {
+ return false;
+ }
+ mData = (uint8_t *)mAlloc;
+ len = fread(mAlloc, 1, mDataSize, f);
+ if (len != mDataSize) {
+ return false;
+ }
+
+ LOGE("file start processing");
+ return process(rsc);
+}
+
+bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie)
+{
+ bool ret = false;
+ IO io(mData + ie->mOffset, mUse64BitOffsets);
+
+ LOGE("process index, type %i", ie->mType);
+
+ switch(ie->mType) {
+ case CHUNK_ELEMENT:
+ processChunk_Element(rsc, &io, ie);
+ break;
+ case CHUNK_ELEMENT_SOURCE:
+ processChunk_ElementSource(rsc, &io, ie);
+ break;
+ case CHUNK_VERTICIES:
+ processChunk_Verticies(rsc, &io, ie);
+ break;
+ case CHUNK_MESH:
+ processChunk_Mesh(rsc, &io, ie);
+ break;
+ case CHUNK_PRIMITIVE:
+ processChunk_Primitive(rsc, &io, ie);
+ break;
+ default:
+ LOGE("FileA3D Unknown chunk type");
+ break;
+ }
+ return (ie->mRsObj != NULL);
+}
+
+bool FileA3D::process(Context *rsc)
+{
+ LOGE("process");
+ IO io(mData + 12, mUse64BitOffsets);
+ bool ret = true;
+
+ // Build the index first
+ LOGE("process 1");
+ io.loadU32(); // major version, already loaded
+ io.loadU32(); // minor version, already loaded
+ LOGE("process 2");
+
+ io.loadU32(); // flags
+ io.loadOffset(); // filesize, already loaded.
+ LOGE("process 4");
+ uint64_t mIndexOffset = io.loadOffset();
+ uint64_t mStringOffset = io.loadOffset();
+
+ LOGE("process mIndexOffset= 0x%016llx", mIndexOffset);
+ LOGE("process mStringOffset= 0x%016llx", mStringOffset);
+
+ IO index(mData + mIndexOffset, mUse64BitOffsets);
+ IO stringTable(mData + mStringOffset, mUse64BitOffsets);
+
+ uint32_t stringEntryCount = stringTable.loadU32();
+ LOGE("stringEntryCount %i", stringEntryCount);
+ mStrings.setCapacity(stringEntryCount);
+ mStringIndexValues.setCapacity(stringEntryCount);
+ if (stringEntryCount) {
+ uint32_t stringType = stringTable.loadU32();
+ LOGE("stringType %i", stringType);
+ rsAssert(stringType==0);
+ for (uint32_t ct = 0; ct < stringEntryCount; ct++) {
+ uint64_t offset = stringTable.loadOffset();
+ LOGE("string offset 0x%016llx", offset);
+ IO tmp(mData + offset, mUse64BitOffsets);
+ String8 s;
+ tmp.loadString(&s);
+ LOGE("string %s", s.string());
+ mStrings.push(s);
+ }
+ }
+
+ LOGE("strings done");
+ uint32_t indexEntryCount = index.loadU32();
+ LOGE("index count %i", indexEntryCount);
+ mIndex.setCapacity(indexEntryCount);
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ A3DIndexEntry e;
+ uint32_t stringIndex = index.loadU32();
+ LOGE("index %i", ct);
+ LOGE(" string index %i", stringIndex);
+ e.mType = (A3DChunkType)index.loadU32();
+ LOGE(" type %i", e.mType);
+ e.mOffset = index.loadOffset();
+ LOGE(" offset 0x%016llx", e.mOffset);
+
+ if (stringIndex && (stringIndex < mStrings.size())) {
+ e.mID = mStrings[stringIndex];
+ mStringIndexValues.editItemAt(stringIndex) = ct;
+ LOGE(" id %s", e.mID.string());
+ }
+
+ mIndex.push(e);
+ }
+ LOGE("index done");
+
+ // At this point the index should be fully populated.
+ // We can now walk though it and load all the objects.
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ LOGE("processing index entry %i", ct);
+ processIndex(rsc, &mIndex.editItemAt(ct));
+ }
+
+ return ret;
+}
+
+
+FileA3D::IO::IO(const uint8_t *buf, bool use64)
+{
+ mData = buf;
+ mPos = 0;
+ mUse64 = use64;
+}
+
+uint64_t FileA3D::IO::loadOffset()
+{
+ uint64_t tmp;
+ if (mUse64) {
+ mPos = (mPos + 7) & (~7);
+ tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint64_t);
+ return tmp;
+ }
+ return loadU32();
+}
+
+void FileA3D::IO::loadString(String8 *s)
+{
+ LOGE("loadString");
+ uint32_t len = loadU32();
+ LOGE("loadString len %i", len);
+ s->setTo((const char *)&mData[mPos], len);
+ mPos += len;
+}
+
+
+void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh * m = new Mesh;
+
+ m->mPrimitivesCount = io->loadU32();
+ m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount];
+
+ for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) {
+ uint32_t index = io->loadU32();
+
+ m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj;
+ }
+ ie->mRsObj = m;
+}
+
+void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Primitive_t * p = new Mesh::Primitive_t;
+
+ p->mIndexCount = io->loadU32();
+ uint32_t vertIdx = io->loadU32();
+ p->mRestartCounts = io->loadU16();
+ uint32_t bits = io->loadU8();
+ p->mType = (RsPrimitive)io->loadU8();
+
+ LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits);
+
+ p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj;
+
+ p->mIndicies = new uint16_t[p->mIndexCount];
+ for (uint32_t ct = 0; ct < p->mIndexCount; ct++) {
+ switch(bits) {
+ case 8:
+ p->mIndicies[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mIndicies[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mIndicies[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mIndicies[ct]);
+ }
+
+ if (p->mRestartCounts) {
+ p->mRestarts = new uint16_t[p->mRestartCounts];
+ for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) {
+ switch(bits) {
+ case 8:
+ p->mRestarts[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mRestarts[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mRestarts[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mRestarts[ct]);
+ }
+ } else {
+ p->mRestarts = NULL;
+ }
+
+ ie->mRsObj = p;
+}
+
+void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Verticies_t *cv = new Mesh::Verticies_t;
+ cv->mAllocationCount = io->loadU32();
+ cv->mAllocations = new Allocation *[cv->mAllocationCount];
+ LOGE("processChunk_Verticies count %i", cv->mAllocationCount);
+ for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) {
+ uint32_t i = io->loadU32();
+ cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj;
+ LOGE(" idx %i", i);
+ }
+ ie->mRsObj = cv;
+}
+
+void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ rsi_ElementBegin(rsc);
+
+ uint32_t count = io->loadU32();
+ LOGE("processChunk_Element count %i", count);
+ while (count--) {
+ RsDataKind dk = (RsDataKind)io->loadU8();
+ RsDataType dt = (RsDataType)io->loadU8();
+ uint32_t bits = io->loadU8();
+ bool isNorm = io->loadU8() != 0;
+ LOGE(" %i %i %i %i", dk, dt, bits, isNorm);
+ rsi_ElementAdd(rsc, dk, dt, isNorm, bits);
+ }
+ LOGE("processChunk_Element create");
+ ie->mRsObj = rsi_ElementCreate(rsc);
+}
+
+void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ uint32_t index = io->loadU32();
+ uint32_t count = io->loadU32();
+
+ LOGE("processChunk_ElementSource count %i, index %i", count, index);
+
+ RsElement e = (RsElement)mIndex[index].mRsObj;
+
+ RsAllocation a = rsi_AllocationCreateSized(rsc, e, count);
+ Allocation * alloc = static_cast<Allocation *>(a);
+
+ float * data = (float *)alloc->getPtr();
+ while(count--) {
+ *data = io->loadF();
+ LOGE(" %f", *data);
+ data++;
+ }
+ ie->mRsObj = alloc;
+}
+
+namespace android {
+namespace renderscript {
+
+
+RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
+{
+ FileA3D *fa3d = new FileA3D;
+
+ FILE *f = fopen("/sdcard/test.a3d", "rb");
+ if (f) {
+ fa3d->load(rsc, f);
+ fclose(f);
+ return fa3d;
+ }
+ delete fa3d;
+ return NULL;
+}
+
+
+}
+}
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
new file mode 100644
index 0000000..9ee08ec
--- /dev/null
+++ b/libs/rs/rsFileA3D.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 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_RS_FILE_A3D_H
+#define ANDROID_RS_FILE_A3D_H
+
+#include "RenderScript.h"
+#include "rsFileA3DDecls.h"
+#include "rsMesh.h"
+
+#include <utils/String8.h>
+#include <stdio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class FileA3D
+{
+public:
+ FileA3D();
+ ~FileA3D();
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+ uint64_t mIndexOffset;
+ uint64_t mStringTableOffset;
+ bool mUse64BitOffsets;
+
+ struct A3DIndexEntry {
+ String8 mID;
+ A3DChunkType mType;
+ uint64_t mOffset;
+ void * mRsObj;
+ };
+
+ bool load(Context *rsc, FILE *f);
+
+protected:
+ class IO
+ {
+ public:
+ IO(const uint8_t *, bool use64);
+
+ float loadF() {
+ mPos = (mPos + 3) & (~3);
+ float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
+ mPos += sizeof(float);
+ return tmp;
+ }
+ int32_t loadI32() {
+ mPos = (mPos + 3) & (~3);
+ int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
+ mPos += sizeof(int32_t);
+ return tmp;
+ }
+ uint32_t loadU32() {
+ mPos = (mPos + 3) & (~3);
+ uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint32_t);
+ return tmp;
+ }
+ uint16_t loadU16() {
+ mPos = (mPos + 1) & (~1);
+ uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint16_t);
+ return tmp;
+ }
+ uint8_t loadU8() {
+ uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint8_t);
+ return tmp;
+ }
+ uint64_t loadOffset();
+ void loadString(String8 *s);
+ uint64_t getPos() const {return mPos;}
+ const uint8_t * getPtr() const;
+ protected:
+ const uint8_t * mData;
+ uint64_t mPos;
+ bool mUse64;
+ };
+
+
+ bool process(Context *rsc);
+ bool processIndex(Context *rsc, A3DIndexEntry *);
+ void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie);
+
+ const uint8_t * mData;
+ void * mAlloc;
+ uint64_t mDataSize;
+ Context * mRsc;
+
+ Vector<A3DIndexEntry> mIndex;
+ Vector<String8> mStrings;
+ Vector<uint32_t> mStringIndexValues;
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
diff --git a/libs/rs/rsFileA3DDecls.h b/libs/rs/rsFileA3DDecls.h
new file mode 100644
index 0000000..2a08bd3
--- /dev/null
+++ b/libs/rs/rsFileA3DDecls.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 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_RS_FILE_A3D_DECLS_H
+#define ANDROID_RS_FILE_A3D_DECLS_H
+
+
+#define A3D_MAGIC_KEY "Android3D_ff"
+
+namespace android {
+namespace renderscript {
+
+ enum A3DChunkType {
+ CHUNK_EMPTY,
+
+ CHUNK_ELEMENT,
+ CHUNK_ELEMENT_SOURCE,
+ CHUNK_VERTICIES,
+ CHUNK_MESH,
+ CHUNK_PRIMITIVE,
+
+ CHUNK_LAST
+ };
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
+
diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp
new file mode 100644
index 0000000..24b58b6
--- /dev/null
+++ b/libs/rs/rsLight.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Light::Light(bool isLocal, bool isMono)
+{
+ mIsLocal = isLocal;
+ mIsMono = isMono;
+
+ mPosition[0] = 0;
+ mPosition[1] = 0;
+ mPosition[2] = 1;
+ mPosition[3] = 0;
+
+ mColor[0] = 1.f;
+ mColor[1] = 1.f;
+ mColor[2] = 1.f;
+ mColor[3] = 1.f;
+}
+
+Light::~Light()
+{
+}
+
+void Light::setPosition(float x, float y, float z)
+{
+ mPosition[0] = x;
+ mPosition[1] = y;
+ mPosition[2] = z;
+}
+
+void Light::setColor(float r, float g, float b)
+{
+ mColor[0] = r;
+ mColor[1] = g;
+ mColor[2] = b;
+}
+
+void Light::setupGL(uint32_t num) const
+{
+ glLightfv(GL_LIGHT0 + num, GL_DIFFUSE, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_SPECULAR, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_POSITION, mPosition);
+}
+
+////////////////////////////////////////////
+
+LightState::LightState()
+{
+ clear();
+}
+
+LightState::~LightState()
+{
+}
+
+void LightState::clear()
+{
+ mIsLocal = false;
+ mIsMono = false;
+}
+
+
+////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_LightBegin(Context *rsc)
+{
+ rsc->mStateLight.clear();
+}
+
+void rsi_LightSetLocal(Context *rsc, bool isLocal)
+{
+ rsc->mStateLight.mIsLocal = isLocal;
+}
+
+void rsi_LightSetMonochromatic(Context *rsc, bool isMono)
+{
+ rsc->mStateLight.mIsMono = isMono;
+}
+
+RsLight rsi_LightCreate(Context *rsc)
+{
+ Light *l = new Light(rsc->mStateLight.mIsLocal,
+ rsc->mStateLight.mIsMono);
+ l->incRef();
+ return l;
+}
+
+void rsi_LightDestroy(Context *rsc, RsLight vl)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->decRef();
+}
+
+void rsi_LightSetColor(Context *rsc, RsLight vl, float r, float g, float b)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->setColor(r, g, b);
+}
+
+void rsi_LightSetPosition(Context *rsc, RsLight vl, float x, float y, float z)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->setPosition(x, y, z);
+}
+
+
+
+}
+}
diff --git a/libs/rs/rsLight.h b/libs/rs/rsLight.h
new file mode 100644
index 0000000..b0c3386
--- /dev/null
+++ b/libs/rs/rsLight.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 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_LIGHT_H
+#define ANDROID_LIGHT_H
+
+
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Light : public ObjectBase
+{
+public:
+ Light(bool isLocal, bool isMono);
+ virtual ~Light();
+
+ // Values, mutable after creation.
+ void setPosition(float x, float y, float z);
+ void setColor(float r, float g, float b);
+
+ void setupGL(uint32_t num) const;
+
+protected:
+ float mColor[4];
+ float mPosition[4];
+ bool mIsLocal;
+ bool mIsMono;
+};
+
+
+class LightState {
+public:
+ LightState();
+ ~LightState();
+
+ void clear();
+
+ bool mIsMono;
+ bool mIsLocal;
+};
+
+
+}
+}
+#endif //ANDROID_LIGHT_H
+
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
new file mode 100644
index 0000000..c3fee54
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2009 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 "rsLocklessFifo.h"
+
+using namespace android;
+
+
+LocklessCommandFifo::LocklessCommandFifo()
+{
+}
+
+LocklessCommandFifo::~LocklessCommandFifo()
+{
+}
+
+bool LocklessCommandFifo::init(uint32_t sizeInBytes)
+{
+ // Add room for a buffer reset command
+ mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
+ if (!mBuffer) {
+ LOGE("LocklessFifo allocation failure");
+ return false;
+ }
+
+ if (!mSignalToControl.init() || !mSignalToWorker.init()) {
+ LOGE("Signal setup failed");
+ free(mBuffer);
+ return false;
+ }
+
+ mSize = sizeInBytes;
+ mPut = mBuffer;
+ mGet = mBuffer;
+ mEnd = mBuffer + (sizeInBytes) - 1;
+ dumpState("init");
+ return true;
+}
+
+uint32_t LocklessCommandFifo::getFreeSpace() const
+{
+ int32_t freeSpace = 0;
+ //dumpState("getFreeSpace");
+
+ if (mPut >= mGet) {
+ freeSpace = mEnd - mPut;
+ } else {
+ freeSpace = mGet - mPut;
+ }
+
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+ return freeSpace;
+}
+
+bool LocklessCommandFifo::isEmpty() const
+{
+ return mPut == mGet;
+}
+
+
+void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
+{
+ // Add space for command header and loop token;
+ sizeInBytes += 8;
+
+ //dumpState("reserve");
+ if (getFreeSpace() < sizeInBytes) {
+ makeSpace(sizeInBytes);
+ }
+
+ return mPut + 4;
+}
+
+void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
+{
+ //dumpState("commit 1");
+ reinterpret_cast<uint16_t *>(mPut)[0] = command;
+ reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
+ mPut += ((sizeInBytes + 3) & ~3) + 4;
+ //dumpState("commit 2");
+ mSignalToWorker.set();
+}
+
+void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
+{
+ commit(command, sizeInBytes);
+ flush();
+}
+
+void LocklessCommandFifo::flush()
+{
+ //dumpState("flush 1");
+ while(mPut != mGet) {
+ mSignalToControl.wait();
+ }
+ //dumpState("flush 2");
+}
+
+const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
+{
+ while(1) {
+ //dumpState("get");
+ while(isEmpty()) {
+ mSignalToControl.set();
+ mSignalToWorker.wait();
+ }
+
+ *command = reinterpret_cast<const uint16_t *>(mGet)[0];
+ *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
+ if (*command) {
+ // non-zero command is valid
+ return mGet+4;
+ }
+
+ // zero command means reset to beginning.
+ mGet = mBuffer;
+ }
+}
+
+void LocklessCommandFifo::next()
+{
+ uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
+ mGet += ((bytes + 3) & ~3) + 4;
+ if (isEmpty()) {
+ mSignalToControl.set();
+ }
+ //dumpState("next");
+}
+
+void LocklessCommandFifo::makeSpace(uint32_t bytes)
+{
+ //dumpState("make space");
+ if ((mPut+bytes) > mEnd) {
+ // Need to loop regardless of where get is.
+ while((mGet > mPut) && (mBuffer+4 >= mGet)) {
+ sleep(1);
+ }
+
+ // Toss in a reset then the normal wait for space will do the rest.
+ reinterpret_cast<uint16_t *>(mPut)[0] = 0;
+ reinterpret_cast<uint16_t *>(mPut)[1] = 0;
+ mPut = mBuffer;
+ }
+
+ // it will fit here so we just need to wait for space.
+ while(getFreeSpace() < bytes) {
+ sleep(1);
+ }
+
+}
+
+void LocklessCommandFifo::dumpState(const char *s) const
+{
+ LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
+}
+
+LocklessCommandFifo::Signal::Signal()
+{
+ mSet = true;
+}
+
+LocklessCommandFifo::Signal::~Signal()
+{
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCondition);
+}
+
+bool LocklessCommandFifo::Signal::init()
+{
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("LocklessFifo mutex init failure");
+ return false;
+ }
+
+ status = pthread_cond_init(&mCondition, NULL);
+ if (status) {
+ LOGE("LocklessFifo condition init failure");
+ pthread_mutex_destroy(&mMutex);
+ return false;
+ }
+
+ return true;
+}
+
+void LocklessCommandFifo::Signal::set()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
+ return;
+ }
+
+ mSet = true;
+
+ status = pthread_cond_signal(&mCondition);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i on set condition.", status);
+ }
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
+ }
+}
+
+void LocklessCommandFifo::Signal::wait()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for condition.", status);
+ return;
+ }
+
+ if (!mSet) {
+ status = pthread_cond_wait(&mCondition, &mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
+ }
+ }
+ mSet = false;
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
+ }
+}
+
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
new file mode 100644
index 0000000..abeddf7
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 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_RS_LOCKLESS_FIFO_H
+#define ANDROID_RS_LOCKLESS_FIFO_H
+
+
+#include "rsUtils.h"
+
+namespace android {
+
+
+// A simple FIFO to be used as a producer / consumer between two
+// threads. One is writer and one is reader. The common cases
+// will not require locking. It is not threadsafe for multiple
+// readers or writers by design.
+
+class LocklessCommandFifo
+{
+public:
+ bool init(uint32_t size);
+
+ LocklessCommandFifo();
+ ~LocklessCommandFifo();
+
+
+protected:
+ class Signal {
+ public:
+ Signal();
+ ~Signal();
+
+ bool init();
+
+ void set();
+ void wait();
+
+ protected:
+ bool mSet;
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondition;
+ };
+
+ uint8_t * volatile mPut;
+ uint8_t * volatile mGet;
+ uint8_t * mBuffer;
+ uint8_t * mEnd;
+ uint8_t mSize;
+
+ Signal mSignalToWorker;
+ Signal mSignalToControl;
+
+
+
+public:
+ void * reserve(uint32_t bytes);
+ void commit(uint32_t command, uint32_t bytes);
+ void commitSync(uint32_t command, uint32_t bytes);
+
+ void flush();
+ const void * get(uint32_t *command, uint32_t *bytesData);
+ void next();
+
+ void makeSpace(uint32_t bytes);
+
+ bool isEmpty() const;
+ uint32_t getFreeSpace() const;
+
+
+private:
+ void dumpState(const char *) const;
+};
+
+
+}
+#endif
diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp
new file mode 100644
index 0000000..5f68197
--- /dev/null
+++ b/libs/rs/rsMatrix.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2009 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 "rsMatrix.h"
+
+#include "stdlib.h"
+#include "string.h"
+#include "math.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+void Matrix::loadIdentity()
+{
+ set(0, 0, 1);
+ set(1, 0, 0);
+ set(2, 0, 0);
+ set(3, 0, 0);
+
+ set(0, 1, 0);
+ set(1, 1, 1);
+ set(2, 1, 0);
+ set(3, 1, 0);
+
+ set(0, 2, 0);
+ set(1, 2, 0);
+ set(2, 2, 1);
+ set(3, 2, 0);
+
+ set(0, 3, 0);
+ set(1, 3, 0);
+ set(2, 3, 0);
+ set(3, 3, 1);
+}
+
+void Matrix::load(const float *v)
+{
+ memcpy(m, v, sizeof(m));
+}
+
+void Matrix::load(const Matrix *v)
+{
+ memcpy(m, v->m, sizeof(m));
+}
+
+void Matrix::loadRotate(float rot, float x, float y, float z)
+{
+ float c, s;
+ m[3] = 0;
+ m[7] = 0;
+ m[11]= 0;
+ m[12]= 0;
+ m[13]= 0;
+ m[14]= 0;
+ m[15]= 1;
+ rot *= float(M_PI / 180.0f);
+ c = cosf(rot);
+ s = sinf(rot);
+
+ const float len = sqrtf(x*x + y*y + z*z);
+ if (!(len != 1)) {
+ const float recipLen = 1.f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ const float nc = 1.0f - c;
+ const float xy = x * y;
+ const float yz = y * z;
+ const float zx = z * x;
+ const float xs = x * s;
+ const float ys = y * s;
+ const float zs = z * s;
+ m[ 0] = x*x*nc + c;
+ m[ 4] = xy*nc - zs;
+ m[ 8] = zx*nc + ys;
+ m[ 1] = xy*nc + zs;
+ m[ 5] = y*y*nc + c;
+ m[ 9] = yz*nc - xs;
+ m[ 2] = zx*nc - ys;
+ m[ 6] = yz*nc + xs;
+ m[10] = z*z*nc + c;
+}
+
+void Matrix::loadScale(float x, float y, float z)
+{
+ loadIdentity();
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+}
+
+void Matrix::loadTranslate(float x, float y, float z)
+{
+ loadIdentity();
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+}
+
+void Matrix::loadMultiply(const Matrix *lhs, const Matrix *rhs)
+{
+ for (int i=0 ; i<4 ; i++) {
+ float ri0 = 0;
+ float ri1 = 0;
+ float ri2 = 0;
+ float ri3 = 0;
+ for (int j=0 ; j<4 ; j++) {
+ const float rhs_ij = rhs->get(i,j);
+ ri0 += lhs->get(j,0) * rhs_ij;
+ ri1 += lhs->get(j,1) * rhs_ij;
+ ri2 += lhs->get(j,2) * rhs_ij;
+ ri3 += lhs->get(j,3) * rhs_ij;
+ }
+ set(i,0, ri0);
+ set(i,1, ri1);
+ set(i,2, ri2);
+ set(i,3, ri3);
+ }
+}
+
+void Matrix::loadOrtho(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 / (r - l);
+ m[5] = 2 / (t - b);
+ m[10]= -2 / (f - n);
+ m[12]= -(r + l) / (r - l);
+ m[13]= -(t + b) / (t - b);
+ m[14]= -(f + n) / (f - n);
+}
+
+void Matrix::loadFrustum(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 * n / (r - l);
+ m[5] = 2 * n / (t - b);
+ m[8] = (r + l) / (r - l);
+ m[9] = (t + b) / (t - b);
+ m[10]= -(f + n) / (f - n);
+ m[11]= -1;
+ m[14]= -2*f*n / (f - n);
+ m[15]= 0;
+}
+
+
diff --git a/libs/rs/rsMatrix.h b/libs/rs/rsMatrix.h
new file mode 100644
index 0000000..7dc4165
--- /dev/null
+++ b/libs/rs/rsMatrix.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009 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_RS_MATRIX_H
+#define ANDROID_RS_MATRIX_H
+
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+struct Matrix
+{
+ float m[16];
+
+ inline float get(int i, int j) const {
+ return m[i*4 + j];
+ }
+
+ inline void set(int i, int j, float v) {
+ m[i*4 + j] = v;
+ }
+
+ void loadIdentity();
+ void load(const float *);
+ void load(const Matrix *);
+
+ void loadRotate(float rot, float x, float y, float z);
+ void loadScale(float x, float y, float z);
+ void loadTranslate(float x, float y, float z);
+ void loadMultiply(const Matrix *lhs, const Matrix *rhs);
+
+ void loadOrtho(float l, float r, float b, float t, float n, float f);
+ void loadFrustum(float l, float r, float b, float t, float n, float f);
+
+ void multiply(const Matrix *rhs) {
+ Matrix tmp;
+ tmp.loadMultiply(this, rhs);
+ load(&tmp);
+ }
+ void rotate(float rot, float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadRotate(rot, x, y, z);
+ multiply(&tmp);
+ }
+ void scale(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadScale(x, y, z);
+ multiply(&tmp);
+ }
+ void translate(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadTranslate(x, y, z);
+ multiply(&tmp);
+ }
+
+
+
+};
+
+
+
+}
+}
+
+
+
+
+#endif
+
+
+
+
diff --git a/libs/utils/executablepath_linux.cpp b/libs/rs/rsMesh.cpp
index b8d2a3d..aeb52ed 100644
--- a/libs/utils/executablepath_linux.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -14,17 +14,33 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
+#include "rsContext.h"
-void executablepath(char exe[PATH_MAX])
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+Mesh::Mesh()
+{
+ mVerticies = NULL;
+ mVerticiesCount = 0;
+ mPrimitives = NULL;
+ mPrimitivesCount = 0;
+}
+
+Mesh::~Mesh()
+{
+}
+
+
+
+MeshContext::MeshContext()
+{
+}
+
+MeshContext::~MeshContext()
{
- char proc[100];
- sprintf(proc, "/proc/%d/exe", getpid());
-
- int err = readlink(proc, exe, PATH_MAX);
}
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
new file mode 100644
index 0000000..be207a3
--- /dev/null
+++ b/libs/rs/rsMesh.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 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_RS_MESH_H
+#define ANDROID_RS_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Mesh : public ObjectBase
+{
+public:
+ Mesh();
+ ~Mesh();
+
+ struct Verticies_t
+ {
+ Allocation ** mAllocations;
+ uint32_t mAllocationCount;
+
+ size_t mVertexDataSize;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ uint32_t mBufferObject;
+ };
+
+ struct Primitive_t
+ {
+ RsPrimitive mType;
+ Verticies_t *mVerticies;
+
+ uint32_t mIndexCount;
+ uint16_t *mIndicies;
+
+ uint32_t mRestartCounts;
+ uint16_t *mRestarts;
+ };
+
+ Verticies_t * mVerticies;
+ uint32_t mVerticiesCount;
+
+ Primitive_t ** mPrimitives;
+ uint32_t mPrimitivesCount;
+
+
+
+ void analyzeElement();
+protected:
+};
+
+class MeshContext
+{
+public:
+ MeshContext();
+ ~MeshContext();
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
+
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
new file mode 100644
index 0000000..3219c39
--- /dev/null
+++ b/libs/rs/rsObjectBase.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 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 "rsObjectBase.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ObjectBase::ObjectBase()
+{
+ mRefCount = 0;
+ mName = NULL;
+}
+
+ObjectBase::~ObjectBase()
+{
+ rsAssert(!mRefCount);
+}
+
+void ObjectBase::incRef() const
+{
+ mRefCount ++;
+ //LOGV("ObjectBase %p inc ref %i", this, mRefCount);
+}
+
+void ObjectBase::decRef() const
+{
+ rsAssert(mRefCount > 0);
+ mRefCount --;
+ //LOGV("ObjectBase %p dec ref %i", this, mRefCount);
+ if (!mRefCount) {
+ delete this;
+ }
+}
+
+void ObjectBase::setName(const char *name)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[strlen(name) +1];
+ strcpy(mName, name);
+ }
+}
+
+void ObjectBase::setName(const char *name, uint32_t len)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[len + 1];
+ memcpy(mName, name, len);
+ mName[len] = 0;
+ }
+}
+
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
new file mode 100644
index 0000000..b2c3338
--- /dev/null
+++ b/libs/rs/rsObjectBase.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2009 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_RS_OBJECT_BASE_H
+#define ANDROID_RS_OBJECT_BASE_H
+
+#include "rsUtils.h"
+
+
+namespace android {
+namespace renderscript {
+
+// An element is a group of Components that occupies one cell in a structure.
+class ObjectBase
+{
+public:
+ ObjectBase();
+ virtual ~ObjectBase();
+
+ void incRef() const;
+ void decRef() const;
+
+ const char * getName() const {
+ return mName;
+ }
+ void setName(const char *);
+ void setName(const char *, uint32_t len);
+
+private:
+ char * mName;
+ mutable int32_t mRefCount;
+
+
+};
+
+template<class T>
+class ObjectBaseRef
+{
+public:
+ ObjectBaseRef() {
+ mRef = NULL;
+ }
+
+ ObjectBaseRef(const ObjectBaseRef &ref) {
+ mRef = ref.get();
+ if (mRef) {
+ mRef->incRef();
+ }
+ }
+
+ ObjectBaseRef(T *ref) {
+ mRef = ref;
+ if (mRef) {
+ ref->incRef();
+ }
+ }
+
+ ~ObjectBaseRef() {
+ clear();
+ }
+
+ void set(T *ref) {
+ if (mRef != ref) {
+ clear();
+ mRef = ref;
+ if (mRef) {
+ ref->incRef();
+ }
+ }
+ }
+
+ void set(const ObjectBaseRef &ref) {
+ set(ref.mRef);
+ }
+
+ void clear() {
+ if (mRef) {
+ mRef->decRef();
+ }
+ mRef = NULL;
+ }
+
+ inline T * get() const {
+ return mRef;
+ }
+
+ inline T * operator-> () const {
+ return mRef;
+ }
+
+protected:
+ T * mRef;
+
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
new file mode 100644
index 0000000..5a83fb7
--- /dev/null
+++ b/libs/rs/rsProgram.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsProgram.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Program::Program(Element *in, Element *out)
+{
+ mElementIn.set(in);
+ mElementOut.set(out);
+
+
+}
+
+Program::~Program()
+{
+}
+
+
+void Program::setAllocation(Allocation *alloc)
+{
+ mConstants.set(alloc);
+ mDirty = true;
+}
+
+void Program::setupGL()
+{
+
+}
+
+
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
new file mode 100644
index 0000000..913fdd2
--- /dev/null
+++ b/libs/rs/rsProgram.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 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_RS_PROGRAM_H
+#define ANDROID_RS_PROGRAM_H
+
+#include "rsObjectBase.h"
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Program : public ObjectBase
+{
+public:
+ Program(Element *in, Element *out);
+ virtual ~Program();
+
+
+ void setAllocation(Allocation *);
+
+ virtual void setupGL();
+
+protected:
+ // Components not listed in "in" will be passed though
+ // unless overwritten by components in out.
+ ObjectBaseRef<Element> mElementIn;
+ ObjectBaseRef<Element> mElementOut;
+
+ ObjectBaseRef<Allocation> mConstants;
+
+ bool mDirty;
+
+};
+
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
new file mode 100644
index 0000000..628f93e
--- /dev/null
+++ b/libs/rs/rsProgramFragment.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragment::ProgramFragment(Element *in, Element *out) :
+ Program(in, out)
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ mEnvModes[ct] = RS_TEX_ENV_MODE_REPLACE;
+ mTextureDimensions[ct] = 2;
+ }
+ mTextureEnableMask = 0;
+ mEnvModes[1] = RS_TEX_ENV_MODE_DECAL;
+}
+
+ProgramFragment::~ProgramFragment()
+{
+}
+
+void ProgramFragment::setupGL()
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
+ glDisable(GL_TEXTURE_2D);
+ continue;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
+
+ switch(mEnvModes[ct]) {
+ case RS_TEX_ENV_MODE_REPLACE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ break;
+ case RS_TEX_ENV_MODE_MODULATE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ break;
+ case RS_TEX_ENV_MODE_DECAL:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ break;
+ }
+
+ if (mSamplers[ct].get()) {
+ mSamplers[ct]->setupGL();
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+
+ // Gross hack.
+ if (ct == 2) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
+ }
+
+
+ glActiveTexture(GL_TEXTURE0);
+}
+
+
+void ProgramFragment::bindTexture(uint32_t slot, Allocation *a)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ //LOGE("bindtex %i %p", slot, a);
+ mTextures[slot].set(a);
+}
+
+void ProgramFragment::bindSampler(uint32_t slot, Sampler *s)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a Sampler to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mSamplers[slot].set(s);
+}
+
+void ProgramFragment::setType(uint32_t slot, const Element *e, uint32_t dim)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setType to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ if (dim >= 4) {
+ LOGE("Attempt to setType to a dimension > 3");
+ return;
+ }
+
+ mTextureFormats[slot].set(e);
+ mTextureDimensions[slot] = dim;
+}
+
+void ProgramFragment::setEnvMode(uint32_t slot, RsTexEnvMode env)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mEnvModes[slot] = env;
+}
+
+void ProgramFragment::setTexEnable(uint32_t slot, bool enable)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ uint32_t bit = 1 << slot;
+ mTextureEnableMask &= ~bit;
+ if (enable) {
+ mTextureEnableMask |= bit;
+ }
+}
+
+
+
+ProgramFragmentState::ProgramFragmentState()
+{
+ mPF = NULL;
+}
+
+ProgramFragmentState::~ProgramFragmentState()
+{
+ delete mPF;
+
+}
+
+void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragment *pf = new ProgramFragment(NULL, NULL);
+ mDefault.set(pf);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragment.mPF;
+ rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out);
+}
+
+void rsi_ProgramFragmentBindTexture(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsAllocation a)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindTexture(slot, static_cast<Allocation *>(a));
+ if (pf == rsc->getFragment()) {
+ pf->setupGL();
+ }
+}
+
+void rsi_ProgramFragmentBindSampler(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsSampler s)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindSampler(slot, static_cast<Sampler *>(s));
+
+ if (pf == rsc->getFragment()) {
+ pf->setupGL();
+ }
+}
+
+void rsi_ProgramFragmentSetType(Context *rsc, uint32_t slot, RsType vt)
+{
+ const Type *t = static_cast<const Type *>(vt);
+ uint32_t dim = 1;
+ if (t->getDimY()) {
+ dim ++;
+ if (t->getDimZ()) {
+ dim ++;
+ }
+ }
+
+ rsc->mStateFragment.mPF->setType(slot, t->getElement(), dim);
+}
+
+void rsi_ProgramFragmentSetEnvMode(Context *rsc, uint32_t slot, RsTexEnvMode env)
+{
+ rsc->mStateFragment.mPF->setEnvMode(slot, env);
+}
+
+void rsi_ProgramFragmentSetTexEnable(Context *rsc, uint32_t slot, bool enable)
+{
+ rsc->mStateFragment.mPF->setTexEnable(slot, enable);
+}
+
+RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc)
+{
+ ProgramFragment *pf = rsc->mStateFragment.mPF;
+ pf->incRef();
+ rsc->mStateFragment.mPF = 0;
+ return pf;
+}
+
+void rsi_ProgramFragmentDestroy(Context *rsc, RsProgramFragment vpf)
+{
+ ProgramFragment *pf = (ProgramFragment *)vpf;
+ if (pf->getName()) {
+ rsc->removeName(pf);
+ }
+ pf->decRef();
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
new file mode 100644
index 0000000..896d8dd
--- /dev/null
+++ b/libs/rs/rsProgramFragment.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 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_RS_PROGRAM_FRAGMENT_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramFragment : public Program
+{
+public:
+ const static uint32_t MAX_TEXTURE = 2;
+ const static uint32_t MAX_CONSTANTS = 2;
+
+
+
+ ProgramFragment(Element *in, Element *out);
+ virtual ~ProgramFragment();
+
+ virtual void setupGL();
+
+
+
+ void bindTexture(uint32_t slot, Allocation *);
+ void bindSampler(uint32_t slot, Sampler *);
+ void setType(uint32_t slot, const Element *, uint32_t dim);
+
+ void setEnvMode(uint32_t slot, RsTexEnvMode);
+ void setTexEnable(uint32_t slot, bool);
+
+
+
+protected:
+ // The difference between Textures and Constants is how they are accessed
+ // Texture lookups go though a sampler which in effect converts normalized
+ // coordinates into type specific. Multiple samples may also be taken
+ // and filtered.
+ //
+ // Constants are strictly accessed by programetic loads.
+ ObjectBaseRef<Allocation> mTextures[MAX_TEXTURE];
+ ObjectBaseRef<Sampler> mSamplers[MAX_TEXTURE];
+ ObjectBaseRef<const Element> mTextureFormats[MAX_TEXTURE];
+ uint32_t mTextureDimensions[MAX_TEXTURE];
+
+
+ ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS];
+ ObjectBaseRef<Type> mConstantTypes[MAX_CONSTANTS];
+
+
+ // Hacks to create a program for now
+ RsTexEnvMode mEnvModes[MAX_TEXTURE];
+ uint32_t mTextureEnableMask;
+
+
+
+
+
+};
+
+class ProgramFragmentState
+{
+public:
+ ProgramFragmentState();
+ ~ProgramFragmentState();
+
+ ProgramFragment *mPF;
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+ ObjectBaseRef<ProgramFragment> mDefault;
+ Vector<ProgramFragment *> mPrograms;
+};
+
+
+}
+}
+#endif
+
+
+
+
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
new file mode 100644
index 0000000..9ee270f
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsProgramFragmentStore.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragmentStore::ProgramFragmentStore(Element *in, Element *out) :
+ Program(in, out)
+{
+ mDitherEnable = true;
+ mBlendEnable = false;
+ mColorRWriteEnable = true;
+ mColorGWriteEnable = true;
+ mColorBWriteEnable = true;
+ mColorAWriteEnable = true;
+ mBlendSrc = GL_ONE;
+ mBlendDst = GL_ZERO;
+
+
+ mDepthTestEnable = false;
+ mDepthWriteEnable = true;
+ mDepthFunc = GL_LESS;
+
+
+}
+
+ProgramFragmentStore::~ProgramFragmentStore()
+{
+}
+
+void ProgramFragmentStore::setupGL()
+{
+ glColorMask(mColorRWriteEnable,
+ mColorGWriteEnable,
+ mColorBWriteEnable,
+ mColorAWriteEnable);
+ if (mBlendEnable) {
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendSrc, mBlendDst);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ //LOGE("pfs %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc);
+
+ glDepthMask(mDepthWriteEnable);
+ if(mDepthTestEnable || mDepthWriteEnable) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(mDepthFunc);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if (mDitherEnable) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+
+}
+
+void ProgramFragmentStore::setDitherEnable(bool enable)
+{
+ mDitherEnable = enable;
+}
+
+void ProgramFragmentStore::setDepthFunc(RsDepthFunc func)
+{
+ mDepthTestEnable = true;
+
+ switch(func) {
+ case RS_DEPTH_FUNC_ALWAYS:
+ mDepthTestEnable = false;
+ mDepthFunc = GL_ALWAYS;
+ break;
+ case RS_DEPTH_FUNC_LESS:
+ mDepthFunc = GL_LESS;
+ break;
+ case RS_DEPTH_FUNC_LEQUAL:
+ mDepthFunc = GL_LEQUAL;
+ break;
+ case RS_DEPTH_FUNC_GREATER:
+ mDepthFunc = GL_GREATER;
+ break;
+ case RS_DEPTH_FUNC_GEQUAL:
+ mDepthFunc = GL_GEQUAL;
+ break;
+ case RS_DEPTH_FUNC_EQUAL:
+ mDepthFunc = GL_EQUAL;
+ break;
+ case RS_DEPTH_FUNC_NOTEQUAL:
+ mDepthFunc = GL_NOTEQUAL;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setDepthMask(bool mask)
+{
+ mDepthWriteEnable = mask;
+}
+
+void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ mBlendEnable = true;
+ if ((src == RS_BLEND_SRC_ONE) &&
+ (dst == RS_BLEND_DST_ZERO)) {
+ mBlendEnable = false;
+ }
+
+ switch(src) {
+ case RS_BLEND_SRC_ZERO:
+ mBlendSrc = GL_ZERO;
+ break;
+ case RS_BLEND_SRC_ONE:
+ mBlendSrc = GL_ONE;
+ break;
+ case RS_BLEND_SRC_DST_COLOR:
+ mBlendSrc = GL_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_COLOR:
+ mBlendSrc = GL_ONE_MINUS_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA:
+ mBlendSrc = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_DST_ALPHA:
+ mBlendSrc = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA_SATURATE:
+ mBlendSrc = GL_SRC_ALPHA_SATURATE;
+ break;
+ }
+
+ switch(dst) {
+ case RS_BLEND_DST_ZERO:
+ mBlendDst = GL_ZERO;
+ break;
+ case RS_BLEND_DST_ONE:
+ mBlendDst = GL_ONE;
+ break;
+ case RS_BLEND_DST_SRC_COLOR:
+ mBlendDst = GL_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_COLOR:
+ mBlendDst = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_SRC_ALPHA:
+ mBlendDst = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA:
+ mBlendDst = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_DST_ALPHA:
+ mBlendDst = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_DST_ALPHA:
+ mBlendDst = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a)
+{
+ mColorRWriteEnable = r;
+ mColorGWriteEnable = g;
+ mColorBWriteEnable = b;
+ mColorAWriteEnable = a;
+}
+
+
+ProgramFragmentStoreState::ProgramFragmentStoreState()
+{
+ mPFS = NULL;
+}
+
+ProgramFragmentStoreState::~ProgramFragmentStoreState()
+{
+ delete mPFS;
+
+}
+
+void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragmentStore *pfs = new ProgramFragmentStore(NULL, NULL);
+ mDefault.set(pfs);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentStoreBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragmentStore.mPFS;
+ rsc->mStateFragmentStore.mPFS = new ProgramFragmentStore((Element *)in, (Element *)out);
+
+}
+
+void rsi_ProgramFragmentStoreDepthFunc(Context *rsc, RsDepthFunc func)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthFunc(func);
+}
+
+void rsi_ProgramFragmentStoreDepthMask(Context *rsc, bool mask)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthMask(mask);
+}
+
+void rsi_ProgramFragmentStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a)
+{
+ rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a);
+}
+
+void rsi_ProgramFragmentStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst);
+}
+
+RsProgramFragmentStore rsi_ProgramFragmentStoreCreate(Context *rsc)
+{
+ ProgramFragmentStore *pfs = rsc->mStateFragmentStore.mPFS;
+ pfs->incRef();
+ rsc->mStateFragmentStore.mPFS = 0;
+ return pfs;
+}
+
+void rsi_ProgramFragmentStoreDither(Context *rsc, bool enable)
+{
+ rsc->mStateFragmentStore.mPFS->setDitherEnable(enable);
+}
+
+void rsi_ProgramFragmentStoreDestroy(Context *rsc, RsProgramFragmentStore vpfs)
+{
+ ProgramFragmentStore *pfs = (ProgramFragmentStore *)vpfs;
+ if (pfs->getName()) {
+ rsc->removeName(pfs);
+ }
+ pfs->decRef();
+}
+
+
+
+
+}
+}
diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h
new file mode 100644
index 0000000..bd3a9f4
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 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_RS_PROGRAM_FRAGMENT_STORE_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramFragmentStore : public Program
+{
+public:
+
+
+
+ ProgramFragmentStore(Element *in, Element *out);
+ virtual ~ProgramFragmentStore();
+
+ virtual void setupGL();
+
+
+ void setDepthFunc(RsDepthFunc);
+ void setDepthMask(bool);
+
+ void setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst);
+ void setColorMask(bool, bool, bool, bool);
+
+ void setDitherEnable(bool);
+
+protected:
+ bool mDitherEnable;
+
+ bool mBlendEnable;
+ bool mColorRWriteEnable;
+ bool mColorGWriteEnable;
+ bool mColorBWriteEnable;
+ bool mColorAWriteEnable;
+ int32_t mBlendSrc;
+ int32_t mBlendDst;
+
+
+
+ bool mDepthTestEnable;
+ bool mDepthWriteEnable;
+ int32_t mDepthFunc;
+
+
+
+ bool mStencilTestEnable;
+
+
+
+};
+
+class ProgramFragmentStoreState
+{
+public:
+ ProgramFragmentStoreState();
+ ~ProgramFragmentStoreState();
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramFragmentStore> mDefault;
+ ProgramFragmentStore *mPFS;
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
new file mode 100644
index 0000000..417ba6a
--- /dev/null
+++ b/libs/rs/rsProgramVertex.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsProgramVertex.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramVertex::ProgramVertex(Element *in, Element *out) :
+ Program(in, out)
+{
+ mTextureMatrixEnable = false;
+ mLightCount = 0;
+}
+
+ProgramVertex::~ProgramVertex()
+{
+}
+
+static void logMatrix(const char *txt, const float *f)
+{
+ LOGV("Matrix %s, %p", txt, f);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[0], f[4], f[8], f[12]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[1], f[5], f[9], f[13]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[2], f[6], f[10], f[14]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]);
+}
+
+void ProgramVertex::setupGL()
+{
+ const float *f = static_cast<const float *>(mConstants[0]->getPtr());
+
+ glMatrixMode(GL_TEXTURE);
+ if (mTextureMatrixEnable) {
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
+ } else {
+ glLoadIdentity();
+ }
+
+
+ LOGE("lights %i ", mLightCount);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ if (mLightCount) {
+ int v = 1;
+ glEnable(GL_LIGHTING);
+ glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v);
+ for (uint32_t ct = 0; ct < mLightCount; ct++) {
+ const Light *l = mLights[ct].get();
+ glEnable(GL_LIGHT0 + ct);
+ l->setupGL(ct);
+ }
+ for (uint32_t ct = mLightCount; ct < MAX_LIGHTS; ct++) {
+ glDisable(GL_LIGHT0 + ct);
+ }
+ } else {
+ glDisable(GL_LIGHTING);
+ }
+
+ if (!f) {
+ LOGE("Must bind constants to vertex program");
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
+}
+
+void ProgramVertex::setConstantType(uint32_t slot, const Type *t)
+{
+ mConstantTypes[slot].set(t);
+}
+
+void ProgramVertex::bindAllocation(uint32_t slot, Allocation *a)
+{
+ mConstants[slot].set(a);
+}
+
+void ProgramVertex::addLight(const Light *l)
+{
+ if (mLightCount < MAX_LIGHTS) {
+ mLights[mLightCount].set(l);
+ mLightCount++;
+ }
+}
+
+
+ProgramVertexState::ProgramVertexState()
+{
+ mPV = NULL;
+}
+
+ProgramVertexState::~ProgramVertexState()
+{
+ delete mPV;
+}
+
+void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramVertex *pv = new ProgramVertex(NULL, NULL);
+ Allocation *alloc = (Allocation *)
+ rsi_AllocationCreatePredefSized(rsc, RS_ELEMENT_USER_FLOAT, 48);
+ mDefaultAlloc.set(alloc);
+ mDefault.set(pv);
+
+ pv->bindAllocation(0, alloc);
+
+ Matrix m;
+ m.loadOrtho(0,w, h,0, -1,1);
+ alloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0]);
+
+ m.loadIdentity();
+ alloc->subData(RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0]);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramVertexBegin(Context *rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateVertex.mPV;
+ rsc->mStateVertex.mPV = new ProgramVertex((Element *)in, (Element *)out);
+}
+
+RsProgramVertex rsi_ProgramVertexCreate(Context *rsc)
+{
+ ProgramVertex *pv = rsc->mStateVertex.mPV;
+ pv->incRef();
+ rsc->mStateVertex.mPV = 0;
+ return pv;
+}
+
+void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, uint32_t slot, RsAllocation constants)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpgm);
+ pv->bindAllocation(slot, static_cast<Allocation *>(constants));
+}
+
+void rsi_ProgramVertexSetType(Context *rsc, uint32_t slot, RsType constants)
+{
+ rsc->mStateVertex.mPV->setConstantType(slot, static_cast<const Type *>(constants));
+}
+
+void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable)
+{
+ rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
+}
+
+void rsi_ProgramVertexAddLight(Context *rsc, RsLight light)
+{
+ rsc->mStateVertex.mPV->addLight(static_cast<const Light *>(light));
+}
+
+
+}
+}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
new file mode 100644
index 0000000..ac15b70
--- /dev/null
+++ b/libs/rs/rsProgramVertex.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 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_RS_PROGRAM_VERTEX_H
+#define ANDROID_RS_PROGRAM_VERTEX_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramVertex : public Program
+{
+public:
+ const static uint32_t MAX_CONSTANTS = 2;
+ const static uint32_t MAX_LIGHTS = 8;
+
+ ProgramVertex(Element *in, Element *out);
+ virtual ~ProgramVertex();
+
+ virtual void setupGL();
+
+
+ void setConstantType(uint32_t slot, const Type *);
+ void bindAllocation(uint32_t slot, Allocation *);
+ void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
+ void addLight(const Light *);
+
+protected:
+ bool mDirty;
+ uint32_t mLightCount;
+
+ ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS];
+ ObjectBaseRef<const Type> mConstantTypes[MAX_CONSTANTS];
+ ObjectBaseRef<const Light> mLights[MAX_LIGHTS];
+
+
+ // Hacks to create a program for now
+ bool mTextureMatrixEnable;
+
+};
+
+
+class ProgramVertexState
+{
+public:
+ ProgramVertexState();
+ ~ProgramVertexState();
+
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramVertex> mDefault;
+ ObjectBaseRef<Allocation> mDefaultAlloc;
+
+
+
+ ProgramVertex *mPV;
+
+ //ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+
+
+};
+
+
+}
+}
+#endif
+
+
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
new file mode 100644
index 0000000..418f127
--- /dev/null
+++ b/libs/rs/rsSampler.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2009 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 <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "rsContext.h"
+#include "rsSampler.h"
+
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Sampler::Sampler()
+{
+ // Should not get called.
+ rsAssert(0);
+}
+
+Sampler::Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR)
+{
+ mMagFilter = magFilter;
+ mMinFilter = minFilter;
+ mWrapS = wrapS;
+ mWrapT = wrapT;
+ mWrapR = wrapR;
+}
+
+Sampler::~Sampler()
+{
+}
+
+void Sampler::setupGL()
+{
+ GLenum trans[] = {
+ GL_NEAREST, //RS_SAMPLER_NEAREST,
+ GL_LINEAR, //RS_SAMPLER_LINEAR,
+ GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
+ GL_REPEAT, //RS_SAMPLER_WRAP,
+ GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
+
+ };
+
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]);
+
+}
+
+void Sampler::bindToContext(SamplerState *ss, uint32_t slot)
+{
+ ss->mSamplers[slot].set(this);
+ mBoundSlot = slot;
+}
+
+void Sampler::unbindFromContext(SamplerState *ss)
+{
+ int32_t slot = mBoundSlot;
+ mBoundSlot = -1;
+ ss->mSamplers[slot].clear();
+}
+
+void SamplerState::setupGL()
+{
+ for (uint32_t ct=0; ct < RS_MAX_SAMPLER_SLOT; ct++) {
+ Sampler *s = mSamplers[ct].get();
+ if (s) {
+ s->setupGL();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+}
+
+////////////////////////////////
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_SamplerBegin(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ ss->mMagFilter = RS_SAMPLER_LINEAR;
+ ss->mMinFilter = RS_SAMPLER_LINEAR;
+ ss->mWrapS = RS_SAMPLER_WRAP;
+ ss->mWrapT = RS_SAMPLER_WRAP;
+ ss->mWrapR = RS_SAMPLER_WRAP;
+}
+
+void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ switch(param) {
+ case RS_SAMPLER_MAG_FILTER:
+ ss->mMagFilter = value;
+ break;
+ case RS_SAMPLER_MIN_FILTER:
+ ss->mMinFilter = value;
+ break;
+ case RS_SAMPLER_WRAP_S:
+ ss->mWrapS = value;
+ break;
+ case RS_SAMPLER_WRAP_T:
+ ss->mWrapT = value;
+ break;
+ case RS_SAMPLER_WRAP_R:
+ ss->mWrapR = value;
+ break;
+ }
+
+}
+
+RsSampler rsi_SamplerCreate(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+
+ Sampler * s = new Sampler(ss->mMagFilter,
+ ss->mMinFilter,
+ ss->mWrapS,
+ ss->mWrapT,
+ ss->mWrapR);
+ return s;
+}
+
+void rsi_SamplerDestroy(Context *rsc, RsSampler vs)
+{
+ Sampler * s = static_cast<Sampler *>(vs);
+ s->decRef();
+
+}
+
+
+}}
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
new file mode 100644
index 0000000..4b504f6
--- /dev/null
+++ b/libs/rs/rsSampler.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009 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_RS_SAMPLER_H
+#define ANDROID_RS_SAMPLER_H
+
+#include "rsAllocation.h"
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+const static uint32_t RS_MAX_SAMPLER_SLOT = 16;
+
+class SamplerState;
+
+class Sampler : public ObjectBase
+{
+public:
+ Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR);
+
+ virtual ~Sampler();
+
+ void bind(Allocation *);
+ void setupGL();
+
+ void bindToContext(SamplerState *, uint32_t slot);
+ void unbindFromContext(SamplerState *);
+
+protected:
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+ int32_t mBoundSlot;
+
+private:
+ Sampler();
+
+};
+
+
+class SamplerState
+{
+public:
+
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+
+ ObjectBaseRef<Sampler> mSamplers[RS_MAX_SAMPLER_SLOT];
+
+ void setupGL();
+
+};
+
+
+
+}
+}
+#endif //ANDROID_RS_SAMPLER_H
+
+
+
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
new file mode 100644
index 0000000..ae85c9c
--- /dev/null
+++ b/libs/rs/rsScript.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Script::Script()
+{
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+}
+
+Script::~Script()
+{
+}
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_ScriptDestroy(Context * rsc, RsScript vs)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->decRef();
+}
+
+void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint32_t slot)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mSlots[slot].set(static_cast<Allocation *>(va));
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
new file mode 100644
index 0000000..7dd2b61
--- /dev/null
+++ b/libs/rs/rsScript.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 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_RS_SCRIPT_H
+#define ANDROID_RS_SCRIPT_H
+
+#include "rsAllocation.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramVertex;
+class ProgramFragment;
+class ProgramRaster;
+class ProgramFragmentStore;
+
+class Script : public ObjectBase
+{
+public:
+
+ Script();
+ virtual ~Script();
+
+
+ struct Enviroment_t {
+ bool mIsRoot;
+ float mClearColor[4];
+ float mClearDepth;
+ uint32_t mClearStencil;
+
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ //ObjectBaseRef<ProgramRaster> mRaster;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+ };
+ Enviroment_t mEnviroment;
+
+ const Type * mConstantBufferTypes;
+ uint32_t mCounstantBufferCount;
+
+ ObjectBaseRef<Allocation> mSlots[16];
+
+ virtual bool run(Context *, uint32_t launchID) = 0;
+};
+
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
new file mode 100644
index 0000000..842c836
--- /dev/null
+++ b/libs/rs/rsScriptC.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+
+#include "acc/acc.h"
+#include "utils/String8.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+ScriptC::ScriptC()
+{
+ mAccScript = NULL;
+ memset(&mProgram, 0, sizeof(mProgram));
+}
+
+ScriptC::~ScriptC()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+
+bool ScriptC::run(Context *rsc, uint32_t launchIndex)
+{
+ Context::ScriptTLSStruct * tls =
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
+
+ if (mEnviroment.mFragmentStore.get()) {
+ rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
+ }
+ if (mEnviroment.mFragment.get()) {
+ rsc->setFragment(mEnviroment.mFragment.get());
+ }
+ if (mEnviroment.mVertex.get()) {
+ rsc->setVertex(mEnviroment.mVertex.get());
+ }
+
+ bool ret = false;
+ tls->mScript = this;
+ ret = mProgram.mScript(launchIndex) != 0;
+ tls->mScript = NULL;
+ return ret;
+}
+
+ScriptCState::ScriptCState()
+{
+ clear();
+}
+
+ScriptCState::~ScriptCState()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+void ScriptCState::clear()
+{
+ memset(&mProgram, 0, sizeof(mProgram));
+
+ mConstantBufferTypes.clear();
+
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+ mEnviroment.mClearStencil = 0;
+ mEnviroment.mIsRoot = false;
+
+ mAccScript = NULL;
+
+}
+
+static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name)
+{
+ const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name);
+ if (sym) {
+ return sym->mPtr;
+ }
+ LOGE("ScriptC sym lookup failed for %s", name);
+ return NULL;
+}
+
+void ScriptCState::runCompiler(Context *rsc)
+{
+ mAccScript = accCreateScript();
+ String8 tmp;
+
+ rsc->appendNameDefines(&tmp);
+ appendDecls(&tmp);
+ tmp.append("#line 1\n");
+
+ const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
+ int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
+ accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+ accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
+ accCompileScript(mAccScript);
+ accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
+ rsAssert(mProgram.mScript);
+
+ if (!mProgram.mScript) {
+ ACCchar buf[4096];
+ ACCsizei len;
+ accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+ LOGE(buf);
+
+ }
+
+ mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+ mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+ mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+ if (mProgram.mScript) {
+ const static int pragmaMax = 16;
+ ACCsizei pragmaCount;
+ ACCchar * str[pragmaMax];
+ accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+
+ for (int ct=0; ct < pragmaCount; ct+=2) {
+ if (!strcmp(str[ct], "version")) {
+ continue;
+ }
+
+ if (!strcmp(str[ct], "stateVertex")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mVertex.clear();
+ continue;
+ }
+ ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
+ if (pv != NULL) {
+ mEnviroment.mVertex.set(pv);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateRaster")) {
+ LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragment")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragment.clear();
+ continue;
+ }
+ ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
+ if (pf != NULL) {
+ mEnviroment.mFragment.set(pf);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragmentStore")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragmentStore.clear();
+ continue;
+ }
+ ProgramFragmentStore * pfs =
+ (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
+ if (pfs != NULL) {
+ mEnviroment.mFragmentStore.set(pfs);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
+ }
+
+ }
+
+
+ } else {
+ // Deal with an error.
+ }
+
+}
+
+namespace android {
+namespace renderscript {
+
+void rsi_ScriptCBegin(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->clear();
+}
+
+void rsi_ScriptCSetClearColor(Context * rsc, float r, float g, float b, float a)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mClearColor[0] = r;
+ ss->mEnviroment.mClearColor[1] = g;
+ ss->mEnviroment.mClearColor[2] = b;
+ ss->mEnviroment.mClearColor[3] = a;
+}
+
+void rsi_ScriptCSetClearDepth(Context * rsc, float v)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mClearDepth = v;
+}
+
+void rsi_ScriptCSetClearStencil(Context * rsc, uint32_t v)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mClearStencil = v;
+}
+
+void rsi_ScriptCAddType(Context * rsc, RsType vt)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mConstantBufferTypes.add(static_cast<const Type *>(vt));
+}
+
+void rsi_ScriptCSetScript(Context * rsc, void *vp)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+}
+
+void rsi_ScriptCSetRoot(Context * rsc, bool isRoot)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mIsRoot = isRoot;
+}
+
+void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScriptText = text;
+ ss->mProgram.mScriptTextLength = len;
+}
+
+
+RsScript rsi_ScriptCCreate(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+
+ ss->runCompiler(rsc);
+
+ ScriptC *s = new ScriptC();
+ s->incRef();
+ s->mAccScript = ss->mAccScript;
+ ss->mAccScript = NULL;
+ s->mEnviroment = ss->mEnviroment;
+ s->mProgram = ss->mProgram;
+ ss->clear();
+
+ return s;
+}
+
+}
+}
+
+
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
new file mode 100644
index 0000000..860b4d1
--- /dev/null
+++ b/libs/rs/rsScriptC.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 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_RS_SCRIPT_C_H
+#define ANDROID_RS_SCRIPT_C_H
+
+#include "rsScript.h"
+
+#include "RenderScriptEnv.h"
+
+struct ACCscript;
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class ScriptC : public Script
+{
+public:
+ typedef int (*RunScript_t)(uint32_t launchIndex);
+
+ ScriptC();
+ virtual ~ScriptC();
+
+ struct Program_t {
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
+
+
+ int mVersionMajor;
+ int mVersionMinor;
+
+ RunScript_t mScript;
+ };
+
+ Program_t mProgram;
+
+ ACCscript* mAccScript;
+
+ virtual bool run(Context *, uint32_t launchID);
+};
+
+class ScriptCState
+{
+public:
+ ScriptCState();
+ ~ScriptCState();
+
+ ACCscript* mAccScript;
+
+ ScriptC::Program_t mProgram;
+ Script::Enviroment_t mEnviroment;
+
+ Vector<const Type *> mConstantBufferTypes;
+
+ void clear();
+ void runCompiler(Context *rsc);
+
+ struct SymbolTable_t {
+ const char * mName;
+ void * mPtr;
+ const char * mRet;
+ const char * mParam;
+ };
+ static SymbolTable_t gSyms[];
+ static const SymbolTable_t * lookupSymbol(const char *);
+ static void appendDecls(String8 *str);
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
new file mode 100644
index 0000000..129b19f
--- /dev/null
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+
+#include "acc/acc.h"
+#include "utils/String8.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+//////////////////////////////////////////////////////////////////////////////
+// IO routines
+//////////////////////////////////////////////////////////////////////////////
+
+static float SC_loadF(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ //LOGE("loadF %i %i = %f %x", bank, offset, f, ((int *)&f)[0]);
+ return f[offset];
+}
+
+static int32_t SC_loadI32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const int32_t *i = static_cast<const int32_t *>(vp);
+ //LOGE("loadI32 %i %i = %i", bank, offset, t);
+ return i[offset];
+}
+
+static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const uint32_t *i = static_cast<const uint32_t *>(vp);
+ return i[offset];
+}
+
+static void SC_loadVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(v, &f[offset], sizeof(rsc_Vector4));
+}
+
+static void SC_loadMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(m, &f[offset], sizeof(rsc_Matrix));
+}
+
+
+static void SC_storeF(uint32_t bank, uint32_t offset, float v)
+{
+ //LOGE("storeF %i %i %f", bank, offset, v);
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ f[offset] = v;
+}
+
+static void SC_storeI32(uint32_t bank, uint32_t offset, int32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ int32_t *f = static_cast<int32_t *>(vp);
+ static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeU32(uint32_t bank, uint32_t offset, uint32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ uint32_t *f = static_cast<uint32_t *>(vp);
+ static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], v, sizeof(rsc_Vector4));
+}
+
+static void SC_storeMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], m, sizeof(rsc_Matrix));
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Math routines
+//////////////////////////////////////////////////////////////////////////////
+
+static float SC_randf(float max)
+{
+ float r = (float)rand();
+ return r / RAND_MAX * max;
+}
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Matrix routines
+//////////////////////////////////////////////////////////////////////////////
+
+
+static void SC_matrixLoadIdentity(rsc_Matrix *mat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadIdentity();
+}
+
+static void SC_matrixLoadFloat(rsc_Matrix *mat, const float *f)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(f);
+}
+
+static void SC_matrixLoadMat(rsc_Matrix *mat, const rsc_Matrix *newmat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(reinterpret_cast<const Matrix *>(newmat));
+}
+
+static void SC_matrixLoadRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadRotate(rot, x, y, z);
+}
+
+static void SC_matrixLoadScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadScale(x, y, z);
+}
+
+static void SC_matrixLoadTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadTranslate(x, y, z);
+}
+
+static void SC_matrixLoadMultiply(rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadMultiply(reinterpret_cast<const Matrix *>(lhs),
+ reinterpret_cast<const Matrix *>(rhs));
+}
+
+static void SC_matrixMultiply(rsc_Matrix *mat, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->multiply(reinterpret_cast<const Matrix *>(rhs));
+}
+
+static void SC_matrixRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->rotate(rot, x, y, z);
+}
+
+static void SC_matrixScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->scale(x, y, z);
+}
+
+static void SC_matrixTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->translate(x, y, z);
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Context
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindTexture(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Allocation *>(va));
+
+}
+
+static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindSampler(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Sampler *>(vs));
+
+}
+
+static void SC_bindProgramFragmentStore(RsProgramFragmentStore pfs)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragmentStore(rsc, pfs);
+
+}
+
+static void SC_bindProgramFragment(RsProgramFragment pf)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragment(rsc, pf);
+
+}
+
+static void SC_bindProgramVertex(RsProgramVertex pv)
+{
+ GET_TLS();
+ rsi_ContextBindProgramVertex(rsc, pv);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_drawTriangleMesh(RsTriangleMesh mesh)
+{
+ GET_TLS();
+ rsi_TriangleMeshRender(rsc, mesh);
+}
+
+static void SC_drawTriangleMeshRange(RsTriangleMesh mesh, uint32_t start, uint32_t count)
+{
+ GET_TLS();
+ rsi_TriangleMeshRenderRange(rsc, mesh, start, count);
+}
+
+// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
+static void SC_drawTriangleArray(int ialloc, uint32_t count)
+{
+ GET_TLS();
+ RsAllocation alloc = (RsAllocation)ialloc;
+
+ const Allocation *a = (const Allocation *)alloc;
+ const uint32_t *ptr = (const uint32_t *)a->getPtr();
+
+ rsc->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ glVertexPointer(2, GL_FIXED, 12, ptr + 1);
+ //glTexCoordPointer(2, GL_FIXED, 24, ptr + 1);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLES, 0, count * 3);
+}
+
+static void SC_drawQuad(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+{
+ GET_TLS();
+
+ //LOGE("Quad");
+ //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
+ //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
+ //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
+ //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
+
+ float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
+ static const float tex[] = {0,1, 1,1, 1,0, 0,0};
+
+
+ rsc->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE1);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE0);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C" const void * loadVp(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset];
+}
+
+
+
+static void SC_color(float r, float g, float b, float a)
+{
+ glColor4f(r, g, b, a);
+}
+
+
+extern "C" void materialDiffuse(float r, float g, float b, float a)
+{
+ float v[] = {r, g, b, a};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
+}
+
+extern "C" void materialSpecular(float r, float g, float b, float a)
+{
+ float v[] = {r, g, b, a};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
+}
+
+extern "C" void lightPosition(float x, float y, float z, float w)
+{
+ float v[] = {x, y, z, w};
+ glLightfv(GL_LIGHT0, GL_POSITION, v);
+}
+
+extern "C" void materialShininess(float s)
+{
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
+}
+
+extern "C" void uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+{
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
+}
+
+extern "C" void enable(uint32_t p)
+{
+ glEnable(p);
+}
+
+extern "C" void disable(uint32_t p)
+{
+ glDisable(p);
+}
+
+
+
+static void SC_ClearColor(float r, float g, float b, float a)
+{
+ //LOGE("c %f %f %f %f", r, g, b, a);
+ GET_TLS();
+ sc->mEnviroment.mClearColor[0] = r;
+ sc->mEnviroment.mClearColor[1] = g;
+ sc->mEnviroment.mClearColor[2] = b;
+ sc->mEnviroment.mClearColor[3] = a;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Class implementation
+//////////////////////////////////////////////////////////////////////////////
+
+ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
+ // IO
+ { "loadI32", (void *)&SC_loadI32,
+ "int", "(int, int)" },
+ //{ "loadU32", (void *)&SC_loadU32, "unsigned int", "(int, int)" },
+ { "loadF", (void *)&SC_loadF,
+ "float", "(int, int)" },
+ { "loadVec4", (void *)&SC_loadVec4,
+ "void", "(int, int, float *)" },
+ { "loadMatrix", (void *)&SC_loadMatrix,
+ "void", "(int, int, float *)" },
+ { "storeI32", (void *)&SC_storeI32,
+ "void", "(int, int, int)" },
+ //{ "storeU32", (void *)&SC_storeU32, "void", "(int, int, unsigned int)" },
+ { "storeF", (void *)&SC_storeF,
+ "void", "(int, int, float)" },
+ { "storeVec4", (void *)&SC_storeVec4,
+ "void", "(int, int, float *)" },
+ { "storeMatrix", (void *)&SC_storeMatrix,
+ "void", "(int, int, float *)" },
+
+ // math
+ { "sinf", (void *)&sinf,
+ "float", "(float)" },
+ { "cosf", (void *)&cosf,
+ "float", "(float)" },
+ { "fabs", (void *)&fabs,
+ "float", "(float)" },
+ { "randf", (void *)&SC_randf,
+ "float", "(float)" },
+
+ // matrix
+ { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
+ "void", "(float *mat)" },
+ { "matrixLoadFloat", (void *)&SC_matrixLoadFloat,
+ "void", "(float *mat, float *f)" },
+ { "matrixLoadMat", (void *)&SC_matrixLoadMat,
+ "void", "(float *mat, float *newmat)" },
+ { "matrixLoadRotate", (void *)&SC_matrixLoadRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixLoadScale", (void *)&SC_matrixLoadScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadTranslate", (void *)&SC_matrixLoadTranslate,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadMultiply", (void *)&SC_matrixLoadMultiply,
+ "void", "(float *mat, float *lhs, float *rhs)" },
+ { "matrixMultiply", (void *)&SC_matrixMultiply,
+ "void", "(float *mat, float *rhs)" },
+ { "matrixRotate", (void *)&SC_matrixRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixScale", (void *)&SC_matrixScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixTranslate", (void *)&SC_matrixTranslate,
+ "void", "(float *mat, float x, float y, float z)" },
+
+ // context
+ { "bindProgramFragment", (void *)&SC_bindProgramFragment,
+ "void", "(int)" },
+ { "bindProgramFragmentStore", (void *)&SC_bindProgramFragmentStore,
+ "void", "(int)" },
+ { "bindProgramVertex", (void *)&SC_bindProgramVertex,
+ "void", "(int)" },
+ { "bindSampler", (void *)&SC_bindSampler,
+ "void", "(int, int, int)" },
+ { "bindTexture", (void *)&SC_bindTexture,
+ "void", "(int, int, int)" },
+
+ // drawing
+ { "drawQuad", (void *)&SC_drawQuad,
+ "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
+ { "drawTriangleArray", (void *)&SC_drawTriangleArray,
+ "void", "(int ialloc, int count)" },
+ { "drawTriangleMesh", (void *)&SC_drawTriangleMesh,
+ "void", "(int mesh)" },
+ { "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
+ "void", "(int mesh, int start, int count)" },
+
+
+ // misc
+ { "pfClearColor", (void *)&SC_ClearColor,
+ "void", "(float, float, float, float)" },
+
+ { "color", (void *)&SC_color,
+ "void", "(float, float, float, float)" },
+
+ { NULL, NULL, NULL, NULL }
+};
+
+const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+
+ while (syms->mPtr) {
+ if (!strcmp(syms->mName, sym)) {
+ return syms;
+ }
+ syms++;
+ }
+ return NULL;
+}
+
+void ScriptCState::appendDecls(String8 *str)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+ while (syms->mPtr) {
+ str->append(syms->mRet);
+ str->append(" ");
+ str->append(syms->mName);
+ str->append(syms->mParam);
+ str->append(";\n");
+ syms++;
+ }
+}
+
+
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
new file mode 100644
index 0000000..89df59d
--- /dev/null
+++ b/libs/rs/rsThreadIO.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+#include "rsThreadIO.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ThreadIO *android::renderscript::gIO = NULL;
+
+ThreadIO::ThreadIO()
+{
+ mToCore.init(16 * 1024);
+}
+
+ThreadIO::~ThreadIO()
+{
+}
+
+bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
+{
+ uint32_t cmdID = 0;
+ uint32_t cmdSize = 0;
+ bool ret = false;
+ while(!mToCore.isEmpty() || waitForCommand) {
+ ret = true;
+ const void * data = mToCore.get(&cmdID, &cmdSize);
+ waitForCommand = false;
+ //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
+
+ gPlaybackFuncs[cmdID](con, data);
+ mToCore.next();
+ }
+ return ret;
+}
+
+
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
new file mode 100644
index 0000000..72746c5
--- /dev/null
+++ b/libs/rs/rsThreadIO.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009 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_RS_THREAD_IO_H
+#define ANDROID_RS_THREAD_IO_H
+
+#include "rsUtils.h"
+#include "rsLocklessFifo.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class ThreadIO {
+public:
+ ThreadIO();
+ ~ThreadIO();
+
+ // Plays back commands from the client.
+ // Returns true if any commands were processed.
+ bool playCoreCommands(Context *con, bool waitForCommand);
+
+
+ LocklessCommandFifo mToCore;
+ //LocklessCommandFifo mToClient;
+
+ intptr_t mToCoreRet;
+
+};
+
+extern ThreadIO *gIO;
+
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsTriangleMesh.cpp b/libs/rs/rsTriangleMesh.cpp
new file mode 100644
index 0000000..8c7bc92
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+TriangleMesh::TriangleMesh()
+{
+ mVertexElement = NULL;
+ mIndexElement = NULL;
+ mVertexData = NULL;
+ mIndexData = NULL;
+ mTriangleCount = 0;
+ mVertexDataSize = 0;
+ mIndexDataSize = 0;
+
+ mBufferObjects[0] = 0;
+ mBufferObjects[1] = 0;
+
+ mOffsetCoord = 0;
+ mOffsetTex = 0;
+ mOffsetNorm = 0;
+
+ mSizeCoord = 0;
+ mSizeTex = 0;
+ mSizeNorm = 0;
+
+}
+
+TriangleMesh::~TriangleMesh()
+{
+ free(mVertexData);
+ free(mIndexData);
+}
+
+
+
+TriangleMeshContext::TriangleMeshContext()
+{
+ clear();
+}
+
+TriangleMeshContext::~TriangleMeshContext()
+{
+}
+
+void TriangleMeshContext::clear()
+{
+ mVertexElement = NULL;
+ mVertexSizeBits = 0;
+ mIndexElement = NULL;
+ mIndexSizeBits = 0;
+ mTriangleCount = 0;
+ mVertexData.clear();
+ mIndexData.clear();
+}
+
+void TriangleMesh::analyzeElement()
+{
+ for (uint32_t ct=0; ct < mVertexElement->getComponentCount(); ct++) {
+ const Component *c = mVertexElement->getComponent(ct);
+
+ if (c->getKind() == Component::X) {
+ rsAssert(mSizeCoord == 0);
+ mSizeCoord = 1;
+ mOffsetCoord = ct;
+ }
+ if (c->getKind() == Component::Y) {
+ rsAssert(mSizeCoord == 1);
+ mSizeCoord = 2;
+ }
+ if (c->getKind() == Component::Z) {
+ rsAssert(mSizeCoord == 2);
+ mSizeCoord = 3;
+ }
+ if (c->getKind() == Component::W) {
+ rsAssert(mSizeCoord == 4);
+ mSizeCoord = 4;
+ }
+
+ if (c->getKind() == Component::NX) {
+ rsAssert(mSizeNorm == 0);
+ mSizeNorm = 1;
+ mOffsetNorm = ct;
+ }
+ if (c->getKind() == Component::NY) {
+ rsAssert(mSizeNorm == 1);
+ mSizeNorm = 2;
+ }
+ if (c->getKind() == Component::NZ) {
+ rsAssert(mSizeNorm == 2);
+ mSizeNorm = 3;
+ }
+
+ if (c->getKind() == Component::S) {
+ rsAssert(mSizeTex == 0);
+ mSizeTex = 1;
+ mOffsetTex = ct;
+ }
+ if (c->getKind() == Component::T) {
+ rsAssert(mSizeTex == 1);
+ mSizeTex = 2;
+ }
+ }
+ LOGV("TriangleMesh %i,%i %i,%i %i,%i", mSizeCoord, mOffsetCoord, mSizeNorm, mOffsetNorm, mSizeTex, mOffsetTex);
+
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_TriangleMeshBegin(Context *rsc, RsElement vertex, RsElement index)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ tmc->clear();
+ tmc->mVertexElement = static_cast<Element *>(vertex);
+ tmc->mVertexSizeBits = tmc->mVertexElement->getSizeBits();
+ tmc->mIndexElement = static_cast<Element *>(index);
+ tmc->mIndexSizeBits = tmc->mIndexElement->getSizeBits();
+
+ assert(!(tmc->mVertexSizeBits & 0x7));
+ assert(!(tmc->mIndexSizeBits & 0x7));
+}
+
+void rsi_TriangleMeshAddVertex(Context *rsc, const void *data)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ for (uint32_t ct = 0; (ct * 8) < tmc->mVertexSizeBits; ct++) {
+ tmc->mVertexData.add(static_cast<const uint8_t *>(data) [ct]);
+ }
+}
+
+void rsi_TriangleMeshAddTriangle(Context *rsc, uint32_t idx1, uint32_t idx2, uint32_t idx3)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ switch(tmc->mIndexSizeBits) {
+ case 16:
+ tmc->mIndexData.add(idx1);
+ tmc->mIndexData.add(idx2);
+ tmc->mIndexData.add(idx3);
+ break;
+ default:
+ assert(0);
+ }
+
+ tmc->mTriangleCount++;
+}
+
+RsTriangleMesh rsi_TriangleMeshCreate(Context *rsc)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ TriangleMesh * tm = new TriangleMesh();
+ if (!tm) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ // error
+ return 0;
+ }
+
+ tm->mTriangleCount = tmc->mTriangleCount;
+ tm->mIndexDataSize = tmc->mIndexData.size() * tmc->mIndexSizeBits >> 3;
+ tm->mVertexDataSize = tmc->mVertexData.size();
+ tm->mIndexElement = tmc->mIndexElement;
+ tm->mVertexElement = tmc->mVertexElement;
+
+ tm->mIndexData = malloc(tm->mIndexDataSize);
+ tm->mVertexData = malloc(tm->mVertexDataSize);
+ if (!tm->mIndexData || !tm->mVertexData) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ delete tm;
+ return 0;
+ }
+
+ memcpy(tm->mVertexData, tmc->mVertexData.array(), tm->mVertexDataSize);
+ memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize);
+ tm->analyzeElement();
+
+ return tm;
+}
+
+void rsi_TriangleMeshDestroy(Context *rsc, RsTriangleMesh vtm)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ free(tm->mIndexData);
+ free(tm->mVertexData);
+ delete tm;
+}
+
+
+
+void rsi_TriangleMeshRenderRange(Context *rsc, RsTriangleMesh vtm, uint32_t first, uint32_t count)
+{
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ rsc->setupCheck();
+
+ if (!tm->mBufferObjects[0]) {
+ glGenBuffers(2, &tm->mBufferObjects[0]);
+
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ if (first >= tm->mTriangleCount) {
+ return;
+ }
+ if (count >= (tm->mTriangleCount - first)) {
+ count = tm->mTriangleCount - first;
+ }
+ if (!count) {
+ return;
+ }
+
+ const float *f = (const float *)tm->mVertexData;
+
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(tm->mSizeCoord,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetCoord));
+
+ if (tm->mSizeTex) {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(tm->mSizeTex,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetTex));
+ } else {
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+
+ if (tm->mSizeNorm) {
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetNorm));
+ } else {
+ glDisableClientState(GL_NORMAL_ARRAY);
+ }
+
+ glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, (GLvoid *)(first * 3 * 2));
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+void rsi_TriangleMeshRender(Context *rsc, RsTriangleMesh vtm)
+{
+ rsi_TriangleMeshRenderRange(rsc, vtm, 0, 0xffffff);
+}
+
+}}
diff --git a/libs/rs/rsTriangleMesh.h b/libs/rs/rsTriangleMesh.h
new file mode 100644
index 0000000..e56c7c2
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 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_RS_TRIANGLE_MESH_H
+#define ANDROID_RS_TRIANGLE_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class TriangleMesh : public ObjectBase
+{
+public:
+ TriangleMesh();
+ ~TriangleMesh();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+
+ void * mVertexData;
+ void * mIndexData;
+
+ size_t mVertexDataSize;
+ size_t mIndexDataSize;
+ uint32_t mTriangleCount;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ // GL buffer info
+ uint32_t mBufferObjects[2];
+
+ void analyzeElement();
+protected:
+};
+
+class TriangleMeshContext
+{
+public:
+ TriangleMeshContext();
+ ~TriangleMeshContext();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+ size_t mVertexSizeBits;
+ size_t mIndexSizeBits;
+
+ Vector<uint8_t> mVertexData;
+ Vector<uint16_t> mIndexData;
+
+ uint32_t mTriangleCount;
+
+ void clear();
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
new file mode 100644
index 0000000..bbe9720
--- /dev/null
+++ b/libs/rs/rsType.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2009 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 "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Type::Type()
+{
+ mLODs = 0;
+ mLODCount = 0;
+ clear();
+}
+
+Type::~Type()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ }
+}
+
+void Type::clear()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ mLODs = NULL;
+ }
+ mDimX = 0;
+ mDimY = 0;
+ mDimZ = 0;
+ mDimLOD = 0;
+ mFaces = false;
+ mElement.clear();
+}
+
+TypeState::TypeState()
+{
+}
+
+TypeState::~TypeState()
+{
+}
+
+size_t Type::getOffsetForFace(uint32_t face) const
+{
+ rsAssert(mFaces);
+ return 0;
+}
+
+void Type::compute()
+{
+ uint32_t oldLODCount = mLODCount;
+ if (mDimLOD) {
+ uint32_t l2x = rsFindHighBit(mDimX) + 1;
+ uint32_t l2y = rsFindHighBit(mDimY) + 1;
+ uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+
+ mLODCount = rsMax(l2x, l2y);
+ mLODCount = rsMax(mLODCount, l2z);
+ } else {
+ mLODCount = 1;
+ }
+ if (mLODCount != oldLODCount) {
+ delete [] mLODs;
+ mLODs = new LOD[mLODCount];
+ }
+
+ uint32_t tx = mDimX;
+ uint32_t ty = mDimY;
+ uint32_t tz = mDimZ;
+ size_t offset = 0;
+ for (uint32_t lod=0; lod < mLODCount; lod++) {
+ mLODs[lod].mX = tx;
+ mLODs[lod].mY = ty;
+ mLODs[lod].mZ = tz;
+ mLODs[lod].mOffset = offset;
+ offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes();
+ tx = (tx + 1) >> 1;
+ ty = (ty + 1) >> 1;
+ tz = (tz + 1) >> 1;
+ }
+
+ // At this point the offset is the size of a mipmap chain;
+ mMipChainSizeBytes = offset;
+
+ if (mFaces) {
+ offset *= 6;
+ }
+ mTotalSizeBytes = offset;
+
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += x * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y*mLODs[lod].mX + z*mLODs[lod].mX*mLODs[lod].mY) * mElement->getSizeBytes();
+ return offset;
+}
+
+
+//////////////////////////////////////////////////
+//
+namespace android {
+namespace renderscript {
+
+void rsi_TypeBegin(Context *rsc, RsElement vse)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ stc->mX = 0;
+ stc->mY = 0;
+ stc->mZ = 0;
+ stc->mLOD = false;
+ stc->mFaces = false;
+ stc->mElement.set(static_cast<const Element *>(vse));
+}
+
+void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ if (dim < 0) {
+ //error
+ return;
+ }
+
+
+ switch (dim) {
+ case RS_DIMENSION_X:
+ stc->mX = value;
+ return;
+ case RS_DIMENSION_Y:
+ stc->mY = value;
+ return;
+ case RS_DIMENSION_Z:
+ stc->mZ = value;
+ return;
+ case RS_DIMENSION_FACE:
+ stc->mFaces = (value != 0);
+ return;
+ case RS_DIMENSION_LOD:
+ stc->mLOD = (value != 0);
+ return;
+ default:
+ break;
+ }
+
+
+ int32_t arrayNum = dim - RS_DIMENSION_ARRAY_0;
+ if ((dim < 0) || (dim > RS_DIMENSION_MAX)) {
+ LOGE("rsTypeAdd: Bad dimension");
+ //error
+ return;
+ }
+
+ // todo: implement array support
+
+}
+
+RsType rsi_TypeCreate(Context *rsc)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ Type * st = new Type();
+ st->setDimX(stc->mX);
+ st->setDimY(stc->mY);
+ st->setDimZ(stc->mZ);
+ st->setElement(stc->mElement.get());
+ st->setDimLOD(stc->mLOD);
+ st->setDimFaces(stc->mFaces);
+ st->compute();
+
+ stc->mAllTypes.add(st);
+
+ return st;
+}
+
+void rsi_TypeDestroy(Context *rsc, RsType vst)
+{
+ TypeState * stc = &rsc->mStateType;
+ Type * st = static_cast<Type *>(vst);
+
+ for (size_t ct = 0; ct < stc->mAllTypes.size(); ct++) {
+ if (stc->mAllTypes[ct] == st) {
+ stc->mAllTypes.removeAt(ct);
+ break;
+ }
+ }
+ delete st;
+}
+
+}
+}
+
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
new file mode 100644
index 0000000..a717893
--- /dev/null
+++ b/libs/rs/rsType.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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_STRUCTURED_TYPE_H
+#define ANDROID_STRUCTURED_TYPE_H
+
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Type : public ObjectBase
+{
+public:
+ Type();
+ virtual ~Type();
+
+ Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
+
+
+ size_t getOffsetForFace(uint32_t face) const;
+
+ size_t getSizeBytes() const {return mTotalSizeBytes;}
+ size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
+ const Element * getElement() const {return mElement.get();}
+
+ uint32_t getDimX() const {return mDimX;}
+ uint32_t getDimY() const {return mDimY;}
+ uint32_t getDimZ() const {return mDimZ;}
+ uint32_t getDimLOD() const {return mDimLOD;}
+ bool getDimFaces() const {return mFaces;}
+
+ uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
+ uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
+ uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
+ uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+
+ uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
+
+ uint32_t getLODCount() const {return mLODCount;}
+
+
+ void setElement(const Element *e) {mElement.set(e);}
+ void setDimX(uint32_t v) {mDimX = v;}
+ void setDimY(uint32_t v) {mDimY = v;}
+ void setDimZ(uint32_t v) {mDimZ = v;}
+ void setDimFaces(bool v) {mFaces = v;}
+ void setDimLOD(bool v) {mDimLOD = v;}
+
+ void clear();
+ void compute();
+
+
+protected:
+ struct LOD {
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ size_t mOffset;
+ };
+
+ void makeLODTable();
+
+ // Internal structure from most to least significant.
+ // * Array dimensions
+ // * Faces
+ // * Mipmaps
+ // * xyz
+
+ ObjectBaseRef<const Element> mElement;
+
+ // Size of the structure in the various dimensions. A missing Dimension is
+ // specified as a 0 and not a 1.
+ size_t mDimX;
+ size_t mDimY;
+ size_t mDimZ;
+ bool mDimLOD;
+ bool mFaces;
+
+ // A list of array dimensions. The count is the number of array dimensions and the
+ // sizes is a per array size.
+ //Vector<size_t> mDimArraysSizes;
+
+ // count of mipmap levels, 0 indicates no mipmapping
+
+ size_t mMipChainSizeBytes;
+ size_t mTotalSizeBytes;
+ LOD *mLODs;
+ uint32_t mLODCount;
+
+private:
+ Type(const Type &);
+};
+
+
+class TypeState {
+public:
+ TypeState();
+ ~TypeState();
+
+ Vector<Type *> mAllTypes;
+
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ uint32_t mLOD;
+ bool mFaces;
+ ObjectBaseRef<const Element> mElement;
+
+
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_TYPE
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
new file mode 100644
index 0000000..b13e88f
--- /dev/null
+++ b/libs/rs/rsUtils.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 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_RS_UTILS_H
+#define ANDROID_RS_UTILS_H
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "rs"
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <EGL/egl.h>
+#include <math.h>
+
+#include "RenderScript.h"
+
+namespace android {
+namespace renderscript {
+
+#if 1
+#define rsAssert(v) do {if(!(v)) LOGE("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__);} while(0)
+#else
+#define rsAssert(v) while(0)
+#endif
+
+template<typename T>
+T rsMin(T in1, T in2)
+{
+ if (in1 > in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsMax(T in1, T in2)
+{
+ if (in1 < in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsFindHighBit(T val)
+{
+ uint32_t bit = 0;
+ while(val > 1) {
+ bit++;
+ val>>=1;
+ }
+ return bit;
+}
+
+template<typename T>
+bool rsIsPow2(T val)
+{
+ return (val & (val-1)) == 0;
+}
+
+template<typename T>
+T rsHigherPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << (rsFindHighBit(v) + 1);
+}
+
+template<typename T>
+T rsLowerPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << rsFindHighBit(v);
+}
+
+
+static inline uint16_t rs888to565(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint16_t t = 0;
+ t |= b >> 3;
+ t |= (g >> 2) << 5;
+ t |= (r >> 3) << 11;
+ return t;
+}
+
+static inline uint16_t rsBoxFilter565(uint16_t i1, uint16_t i2, uint16_t i3, uint16_t i4)
+{
+ uint32_t r = ((i1 & 0x1f) + (i2 & 0x1f) + (i3 & 0x1f) + (i4 & 0x1f));
+ uint32_t g = ((i1 >> 5) & 0x3f) + ((i2 >> 5) & 0x3f) + ((i3 >> 5) & 0x3f) + ((i4 >> 5) & 0x3f);
+ uint32_t b = ((i1 >> 11) + (i2 >> 11) + (i3 >> 11) + (i4 >> 11));
+ return (r >> 2) | ((g >> 2) << 5) | ((b >> 2) << 11);
+}
+
+static inline uint32_t rsBoxFilter8888(uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4)
+{
+ uint32_t r = (i1 & 0xff) + (i2 & 0xff) + (i3 & 0xff) + (i4 & 0xff);
+ uint32_t g = ((i1 >> 8) & 0xff) + ((i2 >> 8) & 0xff) + ((i3 >> 8) & 0xff) + ((i4 >> 8) & 0xff);
+ uint32_t b = ((i1 >> 16) & 0xff) + ((i2 >> 16) & 0xff) + ((i3 >> 16) & 0xff) + ((i4 >> 16) & 0xff);
+ uint32_t a = ((i1 >> 24) & 0xff) + ((i2 >> 24) & 0xff) + ((i3 >> 24) & 0xff) + ((i4 >> 24) & 0xff);
+ return (r >> 2) | ((g >> 2) << 8) | ((b >> 2) << 16) | ((a >> 2) << 24);
+}
+
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
+
diff --git a/libs/rs/rsgApi.cpp.rsg b/libs/rs/rsgApi.cpp.rsg
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/libs/rs/rsgApi.cpp.rsg
@@ -0,0 +1 @@
+2
diff --git a/libs/rs/rsgApiFuncDecl.h.rsg b/libs/rs/rsgApiFuncDecl.h.rsg
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/libs/rs/rsgApiFuncDecl.h.rsg
@@ -0,0 +1 @@
+1
diff --git a/libs/rs/rsgApiReplay.cpp.rsg b/libs/rs/rsgApiReplay.cpp.rsg
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/libs/rs/rsgApiReplay.cpp.rsg
@@ -0,0 +1 @@
+3
diff --git a/libs/rs/rsgApiStructs.h.rsg b/libs/rs/rsgApiStructs.h.rsg
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/libs/rs/rsgApiStructs.h.rsg
@@ -0,0 +1 @@
+0
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
new file mode 100644
index 0000000..a4d659d
--- /dev/null
+++ b/libs/rs/rsg_generator.c
@@ -0,0 +1,291 @@
+
+
+#include "lex.yy.c"
+
+void printFileHeader(FILE *f)
+{
+ fprintf(f, "/*\n");
+ fprintf(f, " * Copyright (C) 2009 The Android Open Source Project\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n");
+ fprintf(f, " * you may not use this file except in compliance with the License.\n");
+ fprintf(f, " * You may obtain a copy of the License at\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * http://www.apache.org/licenses/LICENSE-2.0\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Unless required by applicable law or agreed to in writing, software\n");
+ fprintf(f, " * distributed under the License is distributed on an \"AS IS\" BASIS,\n");
+ fprintf(f, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
+ fprintf(f, " * See the License for the specific language governing permissions and\n");
+ fprintf(f, " * limitations under the License.\n");
+ fprintf(f, " */\n\n");
+}
+
+void printVarType(FILE *f, const VarType *vt)
+{
+ int ct;
+ if (vt->isConst) {
+ fprintf(f, "const ");
+ }
+
+ switch(vt->type) {
+ case 0:
+ fprintf(f, "void");
+ break;
+ case 1:
+ fprintf(f, "int%i_t", vt->bits);
+ break;
+ case 2:
+ fprintf(f, "uint%i_t", vt->bits);
+ break;
+ case 3:
+ if (vt->bits == 32)
+ fprintf(f, "float");
+ else
+ fprintf(f, "double");
+ break;
+ case 4:
+ fprintf(f, "%s", vt->typename);
+ break;
+ }
+
+ if(vt->ptrLevel) {
+ fprintf(f, " ");
+ for(ct=0; ct < vt->ptrLevel; ct++) {
+ fprintf(f, "*");
+ }
+ }
+
+ if(vt->name[0]) {
+ fprintf(f, " %s", vt->name);
+ }
+}
+
+void printArgList(FILE *f, const ApiEntry * api, int assumePrevious)
+{
+ int ct;
+ for(ct=0; ct < api->paramCount; ct++) {
+ if (ct || assumePrevious) {
+ fprintf(f, ", ");
+ }
+ printVarType(f, &api->params[ct]);
+ }
+}
+
+void printStructures(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "typedef struct RS_CMD_%s_rec RS_CMD_%s;\n", apis[ct].name, apis[ct].name);
+ }
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+ fprintf(f, "#define RS_CMD_ID_%s %i\n", api->name, ct+1);
+ fprintf(f, "struct RS_CMD_%s_rec {\n", api->name);
+ //fprintf(f, " RsCommandHeader _hdr;\n");
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ fprintf(f, " ");
+ printVarType(f, &api->params[ct2]);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext)
+{
+ printVarType(f, &api->ret);
+ fprintf(f, " %s%s (", prefix, api->name);
+ if (addContext) {
+ fprintf(f, "Context *");
+ }
+ printArgList(f, api, addContext);
+ fprintf(f, ")");
+}
+
+void printFuncDecls(FILE *f, const char *prefix, int addContext)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ printFuncDecl(f, &apis[ct], prefix, addContext);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "\n\n");
+}
+
+void printPlaybackFuncs(FILE *f, const char *prefix)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name);
+ }
+}
+
+void printApiCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "using namespace android;\n");
+ fprintf(f, "using namespace android::renderscript;\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ int needFlush = 0;
+ const ApiEntry * api = &apis[ct];
+
+ printFuncDecl(f, api, "rs", 0);
+ fprintf(f, "\n{\n");
+ fprintf(f, " ThreadIO *io = gIO;\n");
+ //fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name);
+ fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+ fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ needFlush += vt->ptrLevel;
+ fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name);
+ }
+ if (api->ret.typename[0]) {
+ needFlush = 1;
+ }
+
+ fprintf(f, " io->mToCore.commit");
+ if (needFlush) {
+ fprintf(f, "Sync");
+ }
+ fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name);
+
+ if (api->ret.typename[0]) {
+ fprintf(f, " return reinterpret_cast<");
+ printVarType(f, &api->ret);
+ fprintf(f, ">(io->mToCoreRet);\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printPlaybackCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+
+ fprintf(f, "void rsp_%s(Context *con, const void *vp)\n", api->name);
+ fprintf(f, "{\n");
+ //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name);
+ fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
+ fprintf(f, " ");
+ if (api->ret.typename[0]) {
+ fprintf(f, "gIO->mToCoreRet = (intptr_t)");
+ }
+ fprintf(f, "rsi_%s(con", api->name);
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ fprintf(f, ",");
+ fprintf(f, "\n cmd->%s", vt->name);
+ }
+ fprintf(f, ");\n");
+
+ fprintf(f, "};\n\n");
+ }
+
+ fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n");
+ fprintf(f, " NULL,\n");
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, " %s%s,\n", "rsp_", apis[ct].name);
+ }
+ fprintf(f, "};\n");
+
+ fprintf(f, "};\n");
+ fprintf(f, "};\n");
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]);
+ return 1;
+ }
+ const char* rsgFile = argv[1];
+ const char* outFile = argv[2];
+ FILE* input = fopen(rsgFile, "r");
+
+ char choice = fgetc(input);
+ fclose(input);
+
+ if (choice < '0' || choice > '3') {
+ fprintf(stderr, "Uknown command: \'%c\'\n", choice);
+ return -2;
+ }
+
+ yylex();
+ // printf("# of lines = %d\n", num_lines);
+
+ FILE *f = fopen(outFile, "w");
+
+ printFileHeader(f);
+ switch(choice) {
+ case '0': // rsgApiStructs.h
+ {
+ fprintf(f, "\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ printStructures(f);
+ printFuncDecls(f, "rsi_", 1);
+ printPlaybackFuncs(f, "rsp_");
+ fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n");
+ fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n");
+
+ fprintf(f, "}\n");
+ fprintf(f, "}\n");
+ }
+ break;
+
+ case '1': // rsgApiFuncDecl.h
+ {
+ printFuncDecls(f, "rs", 0);
+ }
+ break;
+
+ case '2': // rsgApi.cpp
+ {
+ printApiCpp(f);
+ }
+ break;
+
+ case '3': // rsgApiReplay.cpp
+ {
+ printFileHeader(f);
+ printPlaybackCpp(f);
+ }
+ break;
+ }
+ fclose(f);
+ return 0;
+}
diff --git a/libs/rs/spec.lex b/libs/rs/spec.lex
new file mode 100644
index 0000000..0f8e9ab
--- /dev/null
+++ b/libs/rs/spec.lex
@@ -0,0 +1,171 @@
+%option stack
+
+%x comment
+%x api_entry
+%x api_entry2
+%x api_entry_param
+%x var_type
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_]*
+
+
+ int num_lines = 0;
+
+ typedef struct {
+ int isConst;
+ int type;
+ int bits;
+ int ptrLevel;
+ char name[256];
+ char typename[256];
+ } VarType;
+
+ VarType *currType = 0;
+
+ typedef struct {
+ char name[256];
+ int sync;
+ int paramCount;
+ VarType ret;
+ VarType params[16];
+ } ApiEntry;
+
+ ApiEntry apis[128];
+ int apiCount = 0;
+
+ int typeNextState;
+
+%%
+
+"/*" BEGIN(comment);
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++num_lines;
+<comment>"*"+"/" BEGIN(INITIAL);
+
+<*>" " //printf("found ' '\n");
+<*>"\n" ++num_lines; //printf("found lf \n");
+
+{ID} {
+ memset(&apis[apiCount], 0, sizeof(ApiEntry));
+ memcpy(apis[apiCount].name, yytext, yyleng);
+ BEGIN(api_entry);
+ }
+
+<api_entry>"{" {
+ BEGIN(api_entry2);
+ }
+
+<api_entry2>"sync" {
+ apis[apiCount].sync = 1;
+ }
+
+<api_entry2>"ret" {
+ currType = &apis[apiCount].ret;
+ typeNextState = api_entry2;
+ BEGIN(var_type);
+ }
+
+<api_entry2>"param" {
+ currType = &apis[apiCount].params[apis[apiCount].paramCount];
+ apis[apiCount].paramCount++;
+ typeNextState = api_entry_param;
+ BEGIN(var_type);
+ }
+
+<var_type>"const" {
+ currType->isConst = 1;
+ }
+
+<var_type>"i8" {
+ currType->type = 1;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i16" {
+ currType->type = 1;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i32" {
+ currType->type = 1;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i64" {
+ currType->type = 1;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u8" {
+ currType->type = 2;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u16" {
+ currType->type = 2;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u32" {
+ currType->type = 2;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u64" {
+ currType->type = 2;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"f" {
+ currType->type = 3;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"d" {
+ currType->type = 3;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>{ID} {
+ currType->type = 4;
+ currType->bits = 32;
+ memcpy(currType->typename, yytext, yyleng);
+ BEGIN(typeNextState);
+ }
+
+<api_entry_param>"*" {
+ currType->ptrLevel ++;
+ }
+
+<api_entry_param>{ID} {
+ memcpy(currType->name, yytext, yyleng);
+ BEGIN(api_entry2);
+ }
+
+
+<api_entry2>"}" {
+ apiCount++;
+ BEGIN(INITIAL);
+ }
+
+
+%%
+
+
+int yywrap()
+{
+ return 1;
+}
+
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index ec5aa3f..88e76dc 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -5,44 +5,49 @@ LOCAL_SRC_FILES:= \
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- GPUHardware/GPUHardware.cpp \
BlurFilter.cpp.arm \
- CPUGauge.cpp \
+ BufferAllocator.cpp \
Layer.cpp \
LayerBase.cpp \
LayerBuffer.cpp \
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
- LayerOrientationAnim.cpp \
- OrientationAnimation.cpp \
+ MessageQueue.cpp \
SurfaceFlinger.cpp \
Tokenizer.cpp \
- Transform.cpp \
- VRamHeap.cpp
+ Transform.cpp
+LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+ifeq ($(TARGET_BOARD_PLATFORM), msm7k)
+ LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
+ LOCAL_LDLIBS += -lrt -lpthread
endif
endif
LOCAL_SHARED_LIBRARIES := \
- libhardware \
- libutils \
libcutils \
- libui \
- libcorecg \
- libsgl \
libpixelflinger \
+ libhardware \
+ libutils \
+ libskia \
libEGL \
- libGLESv1_CM
+ libGLESv1_CM \
+ libbinder \
+ libui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
+LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc
+
LOCAL_MODULE:= libsurfaceflinger
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/BufferAllocator.cpp b/libs/surfaceflinger/BufferAllocator.cpp
new file mode 100644
index 0000000..cee8b64
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.cpp
@@ -0,0 +1,118 @@
+/*
+**
+** Copyright 2009, 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 <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
+
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include "BufferAllocator.h"
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferAllocator )
+
+Mutex BufferAllocator::sLock;
+KeyedVector<buffer_handle_t, BufferAllocator::alloc_rec_t> BufferAllocator::sAllocList;
+
+BufferAllocator::BufferAllocator()
+ : mAllocDev(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ gralloc_open(module, &mAllocDev);
+ }
+}
+
+BufferAllocator::~BufferAllocator()
+{
+ gralloc_close(mAllocDev);
+}
+
+void BufferAllocator::dump(String8& result) const
+{
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ size_t total = 0;
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "Allocated buffers:\n");
+ result.append(buffer);
+ 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",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.h, rec.format, rec.usage);
+ result.append(buffer);
+ total += rec.size;
+ }
+ snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ result.append(buffer);
+}
+
+status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
+ int usage, buffer_handle_t* handle, int32_t* stride)
+{
+ Mutex::Autolock _l(mLock);
+
+ // we have a h/w allocator and h/w buffer is requested
+ status_t err = mAllocDev->alloc(mAllocDev,
+ w, h, format, usage, handle, stride);
+ LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
+ w, h, format, usage, err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ alloc_rec_t rec;
+ rec.w = w;
+ rec.h = h;
+ rec.format = format;
+ rec.usage = usage;
+ rec.vaddr = 0;
+ rec.size = h * stride[0] * bytesPerPixel(format);
+ list.add(*handle, rec);
+ }
+
+ return err;
+}
+
+status_t BufferAllocator::free(buffer_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+
+ status_t err = mAllocDev->free(mAllocDev, handle);
+ LOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ list.removeItem(handle);
+ }
+
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/BufferAllocator.h b/libs/surfaceflinger/BufferAllocator.h
new file mode 100644
index 0000000..a279ded
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.h
@@ -0,0 +1,96 @@
+/*
+**
+** Copyright 2009, 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_BUFFER_ALLOCATOR_H
+#define ANDROID_BUFFER_ALLOCATOR_H
+
+#include <stdint.h>
+
+#include <cutils/native_handle.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Singleton.h>
+
+#include <ui/PixelFormat.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class BufferAllocator : public Singleton<BufferAllocator>
+{
+public:
+ enum {
+ USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER,
+ USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY,
+ USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN,
+ USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK,
+
+ USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER,
+ USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY,
+ USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN,
+ USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK,
+
+ USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
+
+ USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE,
+ USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER,
+ USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
+ USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
+ };
+
+ static inline BufferAllocator& get() { return getInstance(); }
+
+
+ status_t alloc(uint32_t w, uint32_t h, PixelFormat format, int usage,
+ buffer_handle_t* handle, int32_t* stride);
+
+ status_t free(buffer_handle_t handle);
+
+ void dump(String8& res) const;
+
+private:
+ struct alloc_rec_t {
+ uint32_t w;
+ uint32_t h;
+ PixelFormat format;
+ uint32_t usage;
+ void* vaddr;
+ size_t size;
+ };
+
+ static Mutex sLock;
+ static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList;
+
+ friend class Singleton<BufferAllocator>;
+ BufferAllocator();
+ ~BufferAllocator();
+
+ mutable Mutex mLock;
+ alloc_device_t *mAllocDev;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFER_ALLOCATOR_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
deleted file mode 100644
index 74a9270..0000000
--- a/libs/surfaceflinger/CPUGauge.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "CPUGauge"
-
-#include <stdint.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <math.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/DisplayInfo.h>
-#include <ui/ISurfaceComposer.h>
-#include <ui/ISurfaceFlingerClient.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "CPUGauge.h"
-
-namespace android {
-
-CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval,
- int clock,
- int refclock)
- : Thread(false),
- mInterval(interval), mClock(clock), mRefClock(refclock),
- mReferenceTime(0),
- mReferenceWorkingTime(0), mCpuUsage(0),
- mRefIdleTime(0), mIdleTime(0)
-{
- mFd = fopen("/proc/stat", "r");
- setvbuf(mFd, NULL, _IONBF, 0);
-
- mSession = SurfaceComposerClient::clientForConnection(
- composer->createConnection()->asBinder());
-}
-
-CPUGauge::~CPUGauge()
-{
- fclose(mFd);
-}
-
-const sp<SurfaceComposerClient>& CPUGauge::session() const
-{
- return mSession;
-}
-
-void CPUGauge::onFirstRef()
-{
- run("CPU Gauge");
-}
-
-status_t CPUGauge::readyToRun()
-{
- LOGI("Starting CPU gauge...");
- return NO_ERROR;
-}
-
-bool CPUGauge::threadLoop()
-{
- DisplayInfo dinfo;
- session()->getDisplayInfo(0, &dinfo);
- sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
- session()->openTransaction();
- s->setLayer(INT_MAX);
- session()->closeTransaction();
-
- static const GGLfixed colors[4][4] = {
- { 0x00000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x00000, 0x00000, 0x10000 },
- { 0x00000, 0x00000, 0x00000, 0x10000 },
- };
-
- GGLContext* gl;
- gglInit(&gl);
- gl->activeTexture(gl, 0);
- gl->disable(gl, GGL_TEXTURE_2D);
- gl->disable(gl, GGL_BLEND);
-
- const int w = dinfo.w;
-
- while(!exitPending())
- {
- mLock.lock();
- const float cpuUsage = this->cpuUsage();
- const float totalCpuUsage = 1.0f - idle();
- mLock.unlock();
-
- Surface::SurfaceInfo info;
- s->lock(&info);
- GGLSurface fb;
- fb.version = sizeof(GGLSurface);
- fb.width = info.w;
- fb.height = info.h;
- fb.stride = info.w;
- fb.format = info.format;
- fb.data = (GGLubyte*)info.bits;
-
- gl->colorBuffer(gl, &fb);
- gl->color4xv(gl, colors[3]);
- gl->recti(gl, 0, 0, w, 4);
- gl->color4xv(gl, colors[2]); // red
- gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
- gl->color4xv(gl, colors[0]); // green
- gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
-
- s->unlockAndPost();
-
- usleep(ns2us(mInterval));
- }
-
- gglUninit(gl);
- return false;
-}
-
-void CPUGauge::sample()
-{
- if (mLock.tryLock() == NO_ERROR) {
- const nsecs_t now = systemTime(mRefClock);
- const nsecs_t referenceTime = now-mReferenceTime;
- if (referenceTime >= mInterval) {
- const float reftime = 1.0f / referenceTime;
- const nsecs_t nowWorkingTime = systemTime(mClock);
-
- char buf[256];
- fgets(buf, 256, mFd);
- rewind(mFd);
- char *str = buf+5;
- char const * const usermode = strsep(&str, " "); (void)usermode;
- char const * const usernice = strsep(&str, " "); (void)usernice;
- char const * const systemmode = strsep(&str, " ");(void)systemmode;
- char const * const idle = strsep(&str, " ");
- const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
- mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
- mRefIdleTime = nowIdleTime;
-
- const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
- const float newCpuUsage = float(workingTime) * reftime;
- if (mCpuUsage != newCpuUsage) {
- mCpuUsage = newCpuUsage;
- mReferenceWorkingTime = nowWorkingTime;
- mReferenceTime = now;
- }
- }
- mLock.unlock();
- }
-}
-
-
-}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
deleted file mode 100644
index 5bb53c0..0000000
--- a/libs/surfaceflinger/CPUGauge.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_CPUGAUGE_H
-#define ANDROID_CPUGAUGE_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/SurfaceComposerClient.h>
-
-namespace android {
-
-class CPUGauge : public Thread
-{
-public:
- CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval=s2ns(1),
- int clock=SYSTEM_TIME_THREAD,
- int refclock=SYSTEM_TIME_MONOTONIC);
-
- ~CPUGauge();
-
- const sp<SurfaceComposerClient>& session() const;
-
- void sample();
-
- inline float cpuUsage() const { return mCpuUsage; }
- inline float idle() const { return mIdleTime; }
-
-private:
- virtual void onFirstRef();
- virtual status_t readyToRun();
- virtual bool threadLoop();
-
- Mutex mLock;
-
- sp<SurfaceComposerClient> mSession;
-
- const nsecs_t mInterval;
- const int mClock;
- const int mRefClock;
-
- nsecs_t mReferenceTime;
- nsecs_t mReferenceWorkingTime;
- float mCpuUsage;
- nsecs_t mRefIdleTime;
- float mIdleTime;
- FILE* mFd;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index eec645e..21f87e37 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -23,18 +21,23 @@
#include <cutils/properties.h>
+#include <utils/RefBase.h>
#include <utils/Log.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/PixelFormat.h>
+#include <ui/FramebufferNativeWindow.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
#include <hardware/overlay.h>
+#include <hardware/gralloc.h>
using namespace android;
@@ -108,17 +111,28 @@ PixelFormat DisplayHardware::getFormat() const { return mFormat; }
void DisplayHardware::init(uint32_t dpy)
{
+ hw_module_t const* module;
+
+ mNativeWindow = new FramebufferNativeWindow();
+
+ mOverlayEngine = NULL;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+
+ framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+
+ PixelFormatInfo fbFormatInfo;
+ getPixelFormatInfo(PixelFormat(fbDev->format), &fbFormatInfo);
+
// initialize EGL
const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
+ EGL_BUFFER_SIZE, fbFormatInfo.bitsPerPixel,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h, dummy;
- EGLint numConfigs, n;
- EGLConfig config;
+ EGLint numConfigs=0, n=0;
EGLSurface surface;
EGLContext context;
mFlags = 0;
@@ -129,7 +143,32 @@ void DisplayHardware::init(uint32_t dpy)
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
- eglChooseConfig(display, attribs, &config, 1, &n);
+
+ // Get all the "potential match" configs...
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+ eglChooseConfig(display, attribs, configs, numConfigs, &n);
+ LOGE_IF(n<=0, "no EGLConfig available!");
+ EGLConfig config = configs[0];
+ if (n > 1) {
+ // if there is more than one candidate, go through the list
+ // and pick one that matches our framebuffer format
+ int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+ int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+ int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+ int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
+ for (int i=0 ; i<n ; i++) {
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &a);
+ if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) {
+ config = configs[i];
+ break;
+ }
+ }
+ }
+ delete [] configs;
/*
* Gather EGL extensions
@@ -145,12 +184,11 @@ void DisplayHardware::init(uint32_t dpy)
LOGI("extensions: %s", egl_extensions);
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
- // TODO: get this from the devfb driver (probably should be HAL module)
- mFlags |= SWAP_RECTANGLE_EXTENSION;
-
- // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
- mFlags |= UPDATE_ON_DEMAND;
+ if (mNativeWindow->isUpdateOnDemand()) {
+ mFlags |= UPDATE_ON_DEMAND;
+ }
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -160,33 +198,29 @@ void DisplayHardware::init(uint32_t dpy)
* Create our main surface
*/
- mDisplaySurface = new EGLDisplaySurface();
-
- surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
- //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+ checkEGLErrors("eglCreateWindowSurface");
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
-
- GLint value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiX = 160.0f;
- } else {
- mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
- }
- value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiY = 160.0f;
- } else {
- mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
+ mFlags |= SWAP_RECTANGLE;
}
- mRefreshRate = 60.f; // TODO: get the real refresh rate
+ // when we have the choice between UPDATE_ON_DEMAND and SWAP_RECTANGLE
+ // choose UPDATE_ON_DEMAND, which is more efficient
+ if (mFlags & UPDATE_ON_DEMAND)
+ mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+ mDpiX = mNativeWindow->xdpi;
+ mDpiY = mNativeWindow->ydpi;
+ mRefreshRate = fbDev->fps;
char property[PROPERTY_VALUE_MAX];
/* Read density from build-specific ro.sf.lcd_density property
@@ -230,7 +264,10 @@ void DisplayHardware::init(uint32_t dpy)
if (strstr(gl_extensions, "GL_OES_draw_texture")) {
mFlags |= DRAW_TEXTURE_EXTENSION;
}
- if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+ if (strstr( gl_extensions, "GL_OES_EGL_image") &&
+ (strstr(egl_extensions, "EGL_KHR_image_base") ||
+ strstr(egl_extensions, "EGL_KHR_image")) &&
+ strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
mFlags |= DIRECT_TEXTURE;
}
@@ -241,19 +278,8 @@ void DisplayHardware::init(uint32_t dpy)
mConfig = config;
mSurface = surface;
mContext = context;
- mFormat = GGL_PIXEL_FORMAT_RGB_565;
-
- hw_module_t const* module;
-
- mBlitEngine = NULL;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- mOverlayEngine = NULL;
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- overlay_control_open(module, &mOverlayEngine);
- }
+ mFormat = fbDev->format;
+ mPageFlipCount = 0;
}
/*
@@ -267,7 +293,6 @@ void DisplayHardware::fini()
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- copybit_close(mBlitEngine);
overlay_control_close(mOverlayEngine);
}
@@ -281,28 +306,8 @@ void DisplayHardware::acquireScreen() const
DisplayHardwareBase::acquireScreen();
}
-void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
-{
- img->w = mDisplaySurface->stride;
- img->h = mDisplaySurface->height;
- img->format = mDisplaySurface->format;
- img->offset = mDisplaySurface->offset;
- img->base = (void*)mDisplaySurface->base;
- img->fd = mDisplaySurface->fd;
-}
-
-void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
-{
- fb->version= sizeof(GGLSurface);
- fb->width = mDisplaySurface->width;
- fb->height = mDisplaySurface->height;
- fb->stride = mDisplaySurface->stride;
- fb->format = mDisplaySurface->format;
- fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
-}
-
uint32_t DisplayHardware::getPageFlipCount() const {
- return mDisplaySurface->getPageFlipCount();
+ return mPageFlipCount;
}
/*
@@ -316,21 +321,20 @@ void DisplayHardware::flip(const Region& dirty) const
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
- Region newDirty(dirty);
- newDirty.andSelf(Rect(mWidth, mHeight));
-
- if (mFlags & BUFFER_PRESERVED) {
- const Region copyback(mDirty.subtract(newDirty));
- mDirty = newDirty;
- mDisplaySurface->copyFrontToBack(copyback);
- }
-
- if (mFlags & SWAP_RECTANGLE_EXTENSION) {
- const Rect& b(newDirty.bounds());
- mDisplaySurface->setSwapRectangle(
+#ifdef EGL_ANDROID_swap_rectangle
+ if (mFlags & SWAP_RECTANGLE) {
+ const Region newDirty(dirty.intersect(bounds()));
+ const Rect b(newDirty.getBounds());
+ eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
+ }
+#endif
+
+ if (mFlags & UPDATE_ON_DEMAND) {
+ mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
-
+
+ mPageFlipCount++;
eglSwapBuffers(dpy, surface);
checkEGLErrors("eglSwapBuffers");
@@ -348,11 +352,3 @@ void DisplayHardware::makeCurrent() const
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
-
-void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyFrontToImage(front);
-}
-
-void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyBackToImage(front);
-}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 550a4d1..8972d51 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,31 +22,35 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
-struct copybit_device_t;
+struct framebuffer_device_t;
struct copybit_image_t;
-struct copybit_t;
namespace android {
-class EGLDisplaySurface;
+class FramebufferNativeWindow;
class DisplayHardware : public DisplayHardwareBase
{
public:
enum {
DIRECT_TEXTURE = 0x00000002,
- SWAP_RECTANGLE_EXTENSION= 0x00000004,
COPY_BITS_EXTENSION = 0x00000008,
NPOT_EXTENSION = 0x00000100,
DRAW_TEXTURE_EXTENSION = 0x00000200,
BUFFER_PRESERVED = 0x00010000,
UPDATE_ON_DEMAND = 0x00020000, // video driver feature
SLOW_CONFIG = 0x00040000, // software
+ SWAP_RECTANGLE = 0x00080000,
};
DisplayHardware(
@@ -73,15 +77,9 @@ public:
void makeCurrent() const;
uint32_t getPageFlipCount() const;
- void getDisplaySurface(copybit_image_t* img) const;
- void getDisplaySurface(GGLSurface* fb) const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
- copybit_device_t* getBlitEngine() const { return mBlitEngine; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
- void copyFrontToImage(const copybit_image_t& front) const;
- void copyBackToImage(const copybit_image_t& front) const;
-
Rect bounds() const {
return Rect(mWidth, mHeight);
}
@@ -102,9 +100,9 @@ private:
int mHeight;
PixelFormat mFormat;
uint32_t mFlags;
- mutable Region mDirty;
- sp<EGLDisplaySurface> mDisplaySurface;
- copybit_device_t* mBlitEngine;
+ mutable uint32_t mPageFlipCount;
+
+ sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f75e5c2..1d09f84 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 96395a8..9916158 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -14,26 +14,24 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <cutils/properties.h>
+#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/Surface.h>
#include "clz.h"
#include "Layer.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
@@ -49,13 +47,12 @@ const char* const Layer::typeID = "Layer";
// ---------------------------------------------------------------------------
-Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i),
mSecure(false),
mFrontBufferIndex(1),
mNeedsBlending(true),
- mResizeTransactionDone(false),
- mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+ mResizeTransactionDone(false)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
@@ -63,12 +60,25 @@ Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
Layer::~Layer()
{
- client->free(clientIndex());
- // this should always be called from the OpenGL thread
- if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ destroy();
+ // the actual buffers will be destroyed here
+}
+
+void Layer::destroy()
+{
+ for (int 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;
+ }
+ mBuffers[i].free();
}
+ mSurface.clear();
}
void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
@@ -79,148 +89,206 @@ void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
lcblk->flags |= eNoCopyBack;
}
-sp<LayerBaseClient::Surface> Layer::getSurface() const
+sp<LayerBaseClient::Surface> Layer::createSurface() const
{
return mSurface;
}
-status_t Layer::setBuffers( Client* client,
- uint32_t w, uint32_t h,
+status_t Layer::ditch()
+{
+ // the layer is not on screen anymore. free as much resources as possible
+ destroy();
+ return NO_ERROR;
+}
+
+status_t Layer::setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags)
{
PixelFormatInfo info;
status_t err = getPixelFormatInfo(format, &info);
if (err) return err;
- // TODO: if eHardware is explicitly requested, we should fail
- // on systems where we can't allocate memory that can be used with
- // DMA engines for instance.
-
- // FIXME: we always ask for hardware for now (this should come from copybit)
- flags |= ISurfaceComposer::eHardware;
+ uint32_t bufferFlags = 0;
+ if (flags & ISurfaceComposer::eGPU)
+ bufferFlags |= Buffer::GPU;
- const uint32_t memory_flags = flags &
- (ISurfaceComposer::eGPU |
- ISurfaceComposer::eHardware |
- ISurfaceComposer::eSecure);
-
- // pixel-alignment. the final alignment may be bigger because
- // we always force a 4-byte aligned bpr.
- uint32_t alignment = 1;
+ if (flags & ISurfaceComposer::eSecure)
+ bufferFlags |= Buffer::SECURE;
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this value should come from the h/w
- alignment = 8;
+ /* FIXME we need this code for msm7201A
+ if (bufferFlags & Buffer::GPU) {
// FIXME: this is msm7201A specific, as its GPU only supports
// BGRA_8888.
if (format == PIXEL_FORMAT_RGBA_8888) {
format = PIXEL_FORMAT_BGRA_8888;
}
}
+ */
- mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+ mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
- sp<MemoryDealer> allocators[2];
for (int i=0 ; i<2 ; i++) {
- allocators[i] = client->createAllocator(memory_flags);
- if (allocators[i] == 0)
- return NO_MEMORY;
- mBuffers[i].init(allocators[i]);
- int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
- if (err != NO_ERROR)
+ err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags);
+ if (err != NO_ERROR) {
return err;
- mBuffers[i].clear(); // clear the bits for security
- mBuffers[i].getInfo(lcblk->surface + i);
+ }
}
-
- mSurface = new Surface(clientIndex(),
- allocators[0]->getMemoryHeap(),
- allocators[1]->getMemoryHeap(),
- mIdentity);
-
+ mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
}
void Layer::reloadTexture(const Region& dirty)
{
- if (UNLIKELY(mTextureName == -1U)) {
- // create the texture name the first time
- // can't do that in the ctor, because it runs in another thread.
- mTextureName = createTexture();
+ const sp<Buffer>& buffer(frontBuffer().getBuffer());
+ if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) {
+ int index = mFrontBufferIndex;
+ if (LIKELY(!mTextures[index].dirty)) {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ } else {
+ // we need to recreate the texture
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+ // create the new texture name if needed
+ if (UNLIKELY(mTextures[index].name == -1U)) {
+ mTextures[index].name = createTexture();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ }
+
+ // free the previous image
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, mTextures[index].image);
+ mTextures[index].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
+ };
+ mTextures[index].image = eglCreateImageKHR(
+ dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)clientBuf, attrs);
+
+ LOGE_IF(mTextures[index].image == EGL_NO_IMAGE_KHR,
+ "eglCreateImageKHR() failed. err=0x%4x",
+ eglGetError());
+
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+ (GLeglImageOES)mTextures[index].image);
+ GLint error = glGetError();
+ if (UNLIKELY(error != GL_NO_ERROR)) {
+ // this failed, for instance, because we don't support
+ // NPOT.
+ // FIXME: do something!
+ mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+ } else {
+ // Everything went okay!
+ mTextures[index].dirty = false;
+ mTextures[index].width = clientBuf->width;
+ mTextures[index].height = clientBuf->height;
+ }
+ }
+ }
+ } else {
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_RARELY);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ if (UNLIKELY(mTextures[0].name == -1U)) {
+ mTextures[0].name = createTexture();
+ }
+ loadTexture(&mTextures[0], mTextures[0].name, dirty, t);
+ buffer->unlock();
+ }
}
- const GGLSurface& t(frontBuffer().surface());
- loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
}
void Layer::onDraw(const Region& clip) const
{
- if (UNLIKELY(mTextureName == -1LU)) {
- //LOGW("Layer %p doesn't have a texture", this);
+ const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
+ mFrontBufferIndex : 0;
+ GLuint textureName = mTextures[index].name;
+
+ if (UNLIKELY(textureName == -1LU)) {
+ LOGW("Layer %p doesn't have a texture", this);
// the texture has not been created yet, this Layer has
// in fact never been drawn into. this happens frequently with
// SurfaceView.
clearWithOpenGL(clip);
return;
}
+ drawWithOpenGL(clip, mTextures[index]);
+}
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- const LayerBitmap& front(frontBuffer());
- const GGLSurface& t(front.surface());
+sp<SurfaceBuffer> Layer::peekBuffer()
+{
+ /*
+ * This is called from the client's Surface::lock(), after it locked
+ * the surface successfully. We're therefore guaranteed that the
+ * back-buffer is not in use by ourselves.
+ * Of course, we need to validate all this, which is not trivial.
+ *
+ * FIXME: A resize could happen at any time here. What to do about this?
+ * - resize() form post()
+ * - resize() from doTransaction()
+ *
+ * We'll probably need an internal lock for this.
+ *
+ *
+ * TODO: We need to make sure that post() doesn't swap
+ * the buffers under us.
+ */
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- const State& s(drawingState());
-
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- front.getBitmapSurface(&src);
- copybit_rect_t srect = { 0, 0, t.width, t.height };
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER,
- s.flags & ISurfaceComposer::eLayerDither ?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
-
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ // it's okay to read swapState for the purpose of figuring out the
+ // backbuffer index, which cannot change (since the app has locked it).
+ const uint32_t state = lcblk->swapState;
+ const int32_t backBufferIndex = layer_cblk_t::backBuffer(state);
+
+ // get rid of the EGL image, since we shouldn't need it anymore
+ // (note that we're in a different thread than where it is being used)
+ if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image);
+ mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR;
}
-
- if (!can_use_copybit || err) {
- drawWithOpenGL(clip, mTextureName, t);
+
+ LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
+ sp<SurfaceBuffer> buffer = layerBitmap.allocate();
+
+ LOGD_IF(DEBUG_RESIZE,
+ "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)",
+ this, backBufferIndex,
+ layerBitmap.getWidth(),
+ layerBitmap.getHeight(),
+ layerBitmap.getBuffer()->getWidth(),
+ layerBitmap.getBuffer()->getHeight());
+
+ if (UNLIKELY(buffer == 0)) {
+ // XXX: what to do, what to do?
+ } else {
+ // texture is now dirty...
+ mTextures[backBufferIndex].dirty = true;
+ // ... so it the visible region (because we consider the surface's
+ // buffer size for visibility calculations)
+ forceVisibilityTransaction();
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
+ return buffer;
}
-status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+void Layer::scheduleBroadcast()
{
- LOGD_IF(DEBUG_RESIZE,
- "reallocateBuffer (layer=%p), "
- "requested (%dx%d), "
- "index=%d, (%dx%d), (%dx%d)",
- this,
- int(w), int(h),
- int(index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
-
- status_t err = mBuffers[index].resize(w, h);
- if (err == NO_ERROR) {
- mBuffers[index].getInfo(lcblk->surface + index);
- } else {
- LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
- index, w, h, err, strerror(err));
- // XXX: what to do, what to do? We could try to free some
- // hidden surfaces, instead of killing this one?
+ sp<Client> ourClient(client.promote());
+ if (ourClient != 0) {
+ mFlinger->scheduleBroadcast(ourClient);
}
- return err;
}
uint32_t Layer::doTransaction(uint32_t flags)
@@ -232,7 +300,7 @@ uint32_t Layer::doTransaction(uint32_t flags)
// that the size changed back to its previous value before the buffer
// was resized (in the eLocked case below), in which case, we still
// need to execute the code below so the clients have a chance to be
- // release. resze() deals with the fact that the size can be the same.
+ // release. resize() deals with the fact that the size can be the same.
/*
* Various states we could be in...
@@ -276,8 +344,8 @@ uint32_t Layer::doTransaction(uint32_t flags)
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// if we get there we're pretty screwed. the only reasonable
// thing to do is to pretend we should do the resize since
// backbufferChanged is set (this also will give a chance to
@@ -299,8 +367,8 @@ uint32_t Layer::doTransaction(uint32_t flags)
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
if (state & eLocked) {
// if the buffer is locked, we can't resize anything because
@@ -314,10 +382,11 @@ uint32_t Layer::doTransaction(uint32_t flags)
status_t err =
resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
if (err == NO_ERROR) {
- const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ const uint32_t mask = clientBackBufferIndex ?
+ eResizeBuffer1 : eResizeBuffer0;
android_atomic_and(~mask, &(lcblk->swapState));
// since a buffer became available, we can let the client go...
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
mResizeTransactionDone = true;
// we're being resized and there is a freeze display request,
@@ -353,14 +422,15 @@ status_t Layer::resize(
{
/*
* handle resize (backbuffer and frontbuffer reallocation)
+ * this is called from post() or from doTransaction()
*/
const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
// if the new (transaction) size is != from the the backbuffer
// then we need to reallocate the backbuffer
- bool backbufferChanged = (clientBackBuffer.width() != width) ||
- (clientBackBuffer.height() != height);
+ bool backbufferChanged = (clientBackBuffer.getWidth() != width) ||
+ (clientBackBuffer.getHeight() != height);
LOGD_IF(!backbufferChanged,
"(%s) eResizeRequested (layer=%p), but size not changed: "
@@ -372,18 +442,28 @@ status_t Layer::resize(
int(currentState().w), int(currentState().h),
long(lcblk->swapState),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// this can happen when changing the size back and forth quickly
status_t err = NO_ERROR;
if (backbufferChanged) {
- err = reallocateBuffer(clientBackBufferIndex, width, height);
- }
- if (UNLIKELY(err != NO_ERROR)) {
- // couldn't reallocate the surface
- android_atomic_write(eInvalidSurface, &lcblk->swapState);
- memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), requested (%dx%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, int(width), int(height), int(clientBackBufferIndex),
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
+
+ err = mBuffers[clientBackBufferIndex].setSize(width, height);
+ if (UNLIKELY(err != NO_ERROR)) {
+ // This really should never happen
+ LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+ clientBackBufferIndex, width, height, err, strerror(err));
+ // couldn't reallocate the surface
+ android_atomic_write(eInvalidSurface, &lcblk->swapState);
+ }
}
return err;
}
@@ -415,7 +495,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
if (UNLIKELY(state & eInvalidSurface)) {
// if eInvalidSurface is set, this means the surface
// became invalid during a transaction (NO_MEMORY for instance)
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
return;
}
@@ -457,15 +537,21 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
} while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
*previousSate = oldValue;
-
+
const int32_t index = (newValue & eIndex) ^ 1;
mFrontBufferIndex = index;
+ /* NOTE: it's safe to set this flag here because this is only touched
+ * from LayerBitmap::allocate(), which by construction cannot happen
+ * while we're in post().
+ */
+ lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty;
+
// ... post the new front-buffer
Region dirty(lcblk->region + index);
- dirty.andSelf(frontBuffer().bounds());
+ dirty.andSelf(frontBuffer().getBounds());
- //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+ //LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
// oldValue, newValue, mFrontBufferIndex);
//dirty.dump("dirty");
@@ -476,8 +562,8 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
"index=%d, (%dx%d), (%dx%d)",
this, newValue,
int(1-index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// here, we just posted the surface and we have resolved
// the front/back buffer indices. The client is blocked, so
@@ -522,8 +608,8 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
Point Layer::getPhysicalSize() const
{
- const LayerBitmap& front(frontBuffer());
- return Point(front.width(), front.height());
+ sp<const Buffer> front(frontBuffer().getBuffer());
+ return Point(front->getWidth(), front->getHeight());
}
void Layer::unlockPageFlip(
@@ -547,7 +633,7 @@ void Layer::unlockPageFlip(
// client could be blocked, so signal them so they get a
// chance to reevaluate their condition.
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
}
}
@@ -558,9 +644,30 @@ void Layer::finishPageFlip()
"layer %p wasn't locked!", this);
android_atomic_and(~eBusy, &(lcblk->swapState));
}
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
}
+// ---------------------------------------------------------------------------
+
+Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner)
+ : Surface(flinger, id, owner->getIdentity(), owner)
+{
+}
+
+Layer::SurfaceLayer::~SurfaceLayer()
+{
+}
+
+sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer()
+{
+ sp<SurfaceBuffer> buffer = 0;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ buffer = owner->peekBuffer();
+ }
+ return buffer;
+}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 2867f2b..4c13d6e 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -27,6 +27,11 @@
#include <pixelflinger/pixelflinger.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "LayerBitmap.h"
#include "LayerBase.h"
#include "Transform.h"
@@ -37,11 +42,12 @@ namespace android {
class Client;
class LayerBitmap;
-class MemoryDealer;
class FreezeLock;
// ---------------------------------------------------------------------------
+const int NUM_BUFFERS = 2;
+
class Layer : public LayerBaseClient
{
public:
@@ -51,16 +57,15 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
Layer(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~Layer();
inline PixelFormat pixelFormat() const {
- return frontBuffer().pixelFormat();
+ return frontBuffer().getPixelFormat();
}
- status_t setBuffers( Client* client,
- uint32_t w, uint32_t h,
+ status_t setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
virtual void onDraw(const Region& clip) const;
@@ -73,8 +78,8 @@ public:
virtual void finishPageFlip();
virtual bool needsBlending() const { return mNeedsBlending; }
virtual bool isSecure() const { return mSecure; }
- virtual GLuint getTextureName() const { return mTextureName; }
- virtual sp<Surface> getSurface() const;
+ virtual sp<Surface> createSurface() const;
+ virtual status_t ditch();
const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
@@ -96,21 +101,37 @@ private:
status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
- status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
-
+ sp<SurfaceBuffer> peekBuffer();
+ void destroy();
+ void scheduleBroadcast();
+
+
+ class SurfaceLayer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner);
+ ~SurfaceLayer();
+
+ private:
+ virtual sp<SurfaceBuffer> getBuffer();
+
+ sp<Layer> getOwner() const {
+ return static_cast<Layer*>(Surface::getOwner().get());
+ }
+ };
+ friend class SurfaceLayer;
+
sp<Surface> mSurface;
bool mSecure;
- LayerBitmap mBuffers[2];
+ LayerBitmap mBuffers[NUM_BUFFERS];
+ Texture mTextures[NUM_BUFFERS];
int32_t mFrontBufferIndex;
bool mNeedsBlending;
bool mResizeTransactionDone;
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
-
- GLuint mTextureName;
- GLuint mTextureWidth;
- GLuint mTextureHeight;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 0cf53f7..a841ab3 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -53,19 +53,13 @@ const char* const LayerBaseClient::typeID = "LayerBaseClient";
// ---------------------------------------------------------------------------
-Vector<GLuint> LayerBase::deletedTextures;
-
-int32_t LayerBase::sIdentity = 0;
-
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
mFlinger(flinger),
mTransformed(false),
mOrientation(0),
- mCanUseCopyBit(false),
mTransactionFlags(0),
mPremultipliedAlpha(true),
- mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
mInvalidate(0)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
@@ -265,43 +259,6 @@ void LayerBase::validateVisibility(const Transform& planeTransform)
mTransformed = transformed;
mLeft = tr.tx();
mTop = tr.ty();
-
- // see if we can/should use 2D h/w with the new configuration
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
- const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
- mCanUseCopyBit = true;
- if ((mOrientation < 0) && (step > 1)) {
- // arbitrary orientations not supported
- mCanUseCopyBit = false;
- } else if ((mOrientation > 0) && (step > 90)) {
- // 90 deg rotations not supported
- mCanUseCopyBit = false;
- } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
- // arbitrary scaling not supported
- mCanUseCopyBit = false;
- }
-#if HONOR_PREMULTIPLIED_ALPHA
- else if (needsBlending() && mPremultipliedAlpha) {
- // pre-multiplied alpha not supported
- mCanUseCopyBit = false;
- }
-#endif
- else {
- // here, we determined we can use copybit
- if (tr.getType() & SkMatrix::kScale_Mask) {
- // and we have scaling
- if (!transparentRegionScreen.isRect()) {
- // we punt because blending is cheap (h/w) and the region is
- // complex, which may causes artifacts when copying
- // scaled content
- transparentRegionScreen.clear();
- }
- }
- }
- }
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
@@ -329,8 +286,9 @@ void LayerBase::invalidate()
void LayerBase::drawRegion(const Region& reg) const
{
- Region::iterator iterator(reg);
- if (iterator) {
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ if (it != end) {
Rect r;
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const int32_t fbWidth = hw.getWidth();
@@ -338,7 +296,8 @@ void LayerBase::drawRegion(const Region& reg) const
const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
{ fbWidth, fbHeight }, { 0, fbHeight } };
glVertexPointer(2, GL_SHORT, 0, vertices);
- while (iterator.iterate(&r)) {
+ 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);
@@ -403,12 +362,14 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
- Rect r;
- Region::iterator iterator(clip);
- if (iterator) {
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_SCISSOR_TEST);
glVertexPointer(2, GL_FIXED, 0, mVertices);
- while (iterator.iterate(&r)) {
+ 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);
@@ -416,15 +377,17 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
}
}
-void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t, int transform) const
+void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
-
+
// bind our texture
- validateTexture(textureName);
+ validateTexture(texture.name);
+ uint32_t width = texture.width;
+ uint32_t height = texture.height;
+
glEnable(GL_TEXTURE_2D);
// Dithering...
@@ -472,8 +435,9 @@ void LayerBase::drawWithOpenGL(const Region& clip,
|| !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
{
//StopWatch watch("GL transformed");
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
// always use high-quality filtering with fast configurations
bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
@@ -490,21 +454,23 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
- if (transform == HAL_TRANSFORM_ROT_90) {
+ // the texture's source is rotated
+ if (texture.transform == HAL_TRANSFORM_ROT_90) {
+ // TODO: handle the other orientations
glTranslatef(0, 1, 0);
glRotatef(-90, 0, 0, 1);
}
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
// find the smallest power-of-two that will accommodate our surface
- GLuint tw = 1 << (31 - clz(t.width));
- GLuint th = 1 << (31 - clz(t.height));
- if (tw < t.width) tw <<= 1;
- if (th < t.height) th <<= 1;
+ GLuint tw = 1 << (31 - clz(width));
+ GLuint th = 1 << (31 - clz(height));
+ if (tw < width) tw <<= 1;
+ if (th < height) th <<= 1;
// this divide should be relatively fast because it's
// a power-of-two (optimized path in libgcc)
- GLfloat ws = GLfloat(t.width) /tw;
- GLfloat hs = GLfloat(t.height)/th;
+ GLfloat ws = GLfloat(width) /tw;
+ GLfloat hs = GLfloat(height)/th;
glScalef(ws, hs, 1.0f);
}
@@ -512,8 +478,8 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
- Rect r;
- while (iterator.iterate(&r)) {
+ 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);
@@ -526,18 +492,19 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- Rect r;
- GLint crop[4] = { 0, t.height, t.width, -t.height };
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
+ GLint crop[4] = { 0, height, width, -height };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
int x = tx();
int y = ty();
- y = fbHeight - (y + t.height);
- while (iterator.iterate(&r)) {
+ y = fbHeight - (y + height);
+ 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, t.width, t.height);
+ glDrawTexiOES(x, y, 0, width, height);
}
}
}
@@ -550,13 +517,16 @@ void LayerBase::validateTexture(GLint textureName) const
// this is currently done in loadTexture() below
}
-void LayerBase::loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const
+void LayerBase::loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const
{
// TODO: defer the actual texture reload until LayerBase::validateTexture
// is called.
+ texture->name = textureName;
+ GLuint& textureWidth(texture->width);
+ GLuint& textureHeight(texture->height);
+
uint32_t flags = mFlags;
glBindTexture(GL_TEXTURE_2D, textureName);
@@ -565,8 +535,7 @@ void LayerBase::loadTexture(const Region& dirty,
/*
* In OpenGL ES we can't specify a stride with glTexImage2D (however,
- * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
- * stride).
+ * 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).
*
@@ -579,9 +548,11 @@ void LayerBase::loadTexture(const Region& dirty,
*
* This should never be a problem with POT textures
*/
-
- tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
-
+
+ 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
*/
@@ -594,119 +565,98 @@ void LayerBase::loadTexture(const Region& dirty,
texture_h = 1 << (31 - clz(t.height));
if (texture_w < t.width) texture_w <<= 1;
if (texture_h < t.height) texture_h <<= 1;
- if (texture_w != tw || texture_h != th) {
- // we can't use DIRECT_TEXTURE since we changed the size
- // of the texture
- flags &= ~DisplayHardware::DIRECT_TEXTURE;
- }
}
-
- if (flags & DisplayHardware::DIRECT_TEXTURE) {
- // here we're guaranteed that texture_{w|h} == t{w|h}
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGB, tw, th, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
- // TODO: add GL_BGRA extension
- } else {
- // oops, we don't handle this format, try the regular path
- goto regular;
- }
- textureWidth = tw;
- textureHeight = th;
- } else {
+
regular:
- Rect bounds(dirty.bounds());
- GLvoid* data = 0;
- if (texture_w!=textureWidth || texture_h!=textureHeight) {
- // texture size changed, we need to create a new one
-
- if (!textureWidth || !textureHeight) {
- // this is the first time, load the whole texture
- if (texture_w==tw && texture_h==th) {
- // we can do it one pass
- data = t.data;
- } else {
- // we have to create the texture first because it
- // doesn't match the size of the buffer
- bounds.set(Rect(tw, th));
- }
- }
-
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGB, texture_w, texture_h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, data);
- } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
- t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
- // just show the Y plane of YUV buffers
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture_w!=textureWidth || texture_h!=textureHeight) {
+ // texture size changed, we need to create a new one
+
+ if (!textureWidth || !textureHeight) {
+ // this is the first time, load the whole texture
+ if (texture_w==tw && texture_h==th) {
+ // we can do it one pass
data = t.data;
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_LUMINANCE, texture_w, texture_h, 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, textureName, t.format);
- textureName = -1;
+ // we have to create the texture first because it
+ // doesn't match the size of the buffer
+ bounds.set(Rect(tw, th));
}
- textureWidth = texture_w;
- textureHeight = texture_h;
}
- if (!data && textureName>=0) {
- if (t.format == GGL_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.width*2);
- } else if (t.format == GGL_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.width*2);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGBA, GL_UNSIGNED_BYTE,
- t.data + bounds.top*t.width*4);
- }
+
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture_w, texture_h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, texture_w, texture_h, 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, textureName, t.format);
+ textureName = -1;
+ }
+ textureWidth = texture_w;
+ textureHeight = texture_h;
+ }
+ if (!data && textureName>=0) {
+ if (t.format == GGL_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 == GGL_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 == GGL_PIXEL_FORMAT_RGBA_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 ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // 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);
}
}
-}
-
-bool LayerBase::canUseCopybit() const
-{
- return mCanUseCopyBit;
}
// ---------------------------------------------------------------------------
+int32_t LayerBaseClient::sIdentity = 0;
+
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i)
- : LayerBase(flinger, display), client(c),
- lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
- mIndex(i)
+ const sp<Client>& client, int32_t i)
+ : LayerBase(flinger, display), client(client),
+ lcblk( client!=0 ? &(client->ctrlblk->layers[i]) : 0 ),
+ mIndex(i),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
{
- if (client) {
- client->bindLayer(this, i);
+}
+void LayerBaseClient::onFirstRef()
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
+ client->bindLayer(this, mIndex);
// Initialize this layer's control block
memset(this->lcblk, 0, sizeof(layer_cblk_t));
this->lcblk->identity = mIdentity;
@@ -717,23 +667,121 @@ LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
LayerBaseClient::~LayerBaseClient()
{
- if (client) {
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
client->free(mIndex);
}
}
-int32_t LayerBaseClient::serverIndex() const {
- if (client) {
+int32_t LayerBaseClient::serverIndex() const
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
return (client->cid<<16)|mIndex;
}
return 0xFFFF0000 | mIndex;
}
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+{
+ sp<Surface> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = createSurface();
+ mClientSurface = s;
+ }
+ return s;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
+{
+ return new Surface(mFlinger, clientIndex(), mIdentity,
+ const_cast<LayerBaseClient *>(this));
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::Surface::Surface(
+ const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner)
+ : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner)
+{
+}
+
+
+LayerBaseClient::Surface::~Surface()
+{
+ /*
+ * This is a good place to clean-up all client resources
+ */
+
+ // destroy client resources
+ sp<LayerBaseClient> layer = getOwner();
+ if (layer != 0) {
+ mFlinger->destroySurface(layer);
+ }
+}
+
+sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
+ sp<LayerBaseClient> owner(mOwner.promote());
+ return owner;
+}
+
+
+void LayerBaseClient::Surface::getSurfaceData(
+ ISurfaceFlingerClient::surface_data_t* params) const
+{
+ params->token = mToken;
+ params->identity = mIdentity;
+}
+
+status_t LayerBaseClient::Surface::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ return BnSurface::onTransact(code, data, reply, flags);
+}
+
+sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer()
{
- return new Surface(clientIndex(), mIdentity);
+ return NULL;
+}
+
+status_t LayerBaseClient::Surface::registerBuffers(
+ const ISurface::BufferHeap& buffers)
+{
+ return INVALID_OPERATION;
}
+void LayerBaseClient::Surface::postBuffer(ssize_t offset)
+{
+}
+
+void LayerBaseClient::Surface::unregisterBuffers()
+{
+}
+
+sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
+ uint32_t w, uint32_t h, int32_t format)
+{
+ return NULL;
+};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index a020f44..6fb1d1c 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -20,8 +20,13 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include <private/ui/LayerState.h>
+#include <utils/RefBase.h>
+
#include <ui/Region.h>
#include <ui/Overlay.h>
@@ -37,10 +42,12 @@ class SurfaceFlinger;
class DisplayHardware;
class GraphicPlane;
class Client;
+class SurfaceBuffer;
+class Buffer;
// ---------------------------------------------------------------------------
-class LayerBase
+class LayerBase : public RefBase
{
// poor man's dynamic_cast below
template<typename T>
@@ -69,10 +76,7 @@ public:
}
- static Vector<GLuint> deletedTextures;
-
LayerBase(SurfaceFlinger* flinger, DisplayID display);
- virtual ~LayerBase();
DisplayID dpy;
mutable bool contentDirty;
@@ -201,21 +205,29 @@ public:
/**
* isSecure - true if this surface is secure, that is if it prevents
- * screenshots or vns servers.
+ * screenshots or VNC servers.
*/
virtual bool isSecure() const { return false; }
- enum { // flags for doTransaction()
- eVisibleRegion = 0x00000002,
- eRestartTransaction = 0x00000008
- };
+ /** signal this layer that it's not needed any longer. called from the
+ * main thread */
+ virtual status_t ditch() { return NO_ERROR; }
+
+
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ eRestartTransaction = 0x00000008
+ };
inline const State& drawingState() const { return mDrawingState; }
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
- static int compareCurrentStateZ(LayerBase*const* layerA, LayerBase*const* layerB) {
+ static int compareCurrentStateZ(
+ sp<LayerBase> const * layerA,
+ sp<LayerBase> const * layerB) {
return layerA[0]->currentState().z - layerB[0]->currentState().z;
}
@@ -229,20 +241,24 @@ protected:
GLuint createTexture() const;
- void drawWithOpenGL(const Region& clip,
- GLint textureName,
- const GGLSurface& surface,
- int transform = 0) const;
-
+ struct Texture {
+ Texture() : name(-1U), width(0), height(0),
+ image(EGL_NO_IMAGE_KHR), transform(0), dirty(true) { }
+ GLuint name;
+ GLuint width;
+ GLuint height;
+ EGLImageKHR image;
+ uint32_t transform;
+ bool dirty;
+ };
+
void clearWithOpenGL(const Region& clip) const;
+ void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ void loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const;
- void loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const;
-
- bool canUseCopybit() const;
- SurfaceFlinger* mFlinger;
+ sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
// cached during validateVisibility()
@@ -250,7 +266,6 @@ protected:
int32_t mOrientation;
GLfixed mVertices[4][2];
Rect mTransformedBounds;
- bool mCanUseCopyBit;
int mLeft;
int mTop;
@@ -262,16 +277,16 @@ protected:
// don't change, don't need a lock
bool mPremultipliedAlpha;
- // only read
- const uint32_t mIdentity;
-
// atomic
volatile int32_t mInvalidate;
+protected:
+ virtual ~LayerBase();
+
private:
- void validateTexture(GLint textureName) const;
- static int32_t sIdentity;
+ LayerBase(const LayerBase& rhs);
+ void validateTexture(GLint textureName) const;
};
@@ -287,66 +302,63 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBaseClient();
+ virtual void onFirstRef();
-
- Client* const client;
+ wp<Client> client;
layer_cblk_t* const lcblk;
+ inline uint32_t getIdentity() const { return mIdentity; }
inline int32_t clientIndex() const { return mIndex; }
int32_t serverIndex() const;
- virtual sp<Surface> getSurface() const;
- uint32_t getIdentity() const { return mIdentity; }
+ sp<Surface> getSurface();
+ virtual sp<Surface> createSurface() const;
+
class Surface : public BnSurface
{
public:
- Surface(SurfaceID id, int identity) {
- mParams.token = id;
- mParams.identity = identity;
- }
- Surface(SurfaceID id,
- const sp<IMemoryHeap>& heap0,
- const sp<IMemoryHeap>& heap1,
- int identity)
- {
- mParams.token = id;
- mParams.identity = identity;
- mParams.heap[0] = heap0;
- mParams.heap[1] = heap1;
- }
- virtual ~Surface() {
- // TODO: We now have a point here were we can clean-up the
- // client's mess.
- // This is also where surface id should be recycled.
- //LOGD("Surface %d, heaps={%p, %p} destroyed",
- // mId, mHeap[0].get(), mHeap[1].get());
- }
-
+
virtual void getSurfaceData(
- ISurfaceFlingerClient::surface_data_t* params) const {
- *params = mParams;
- }
-
- virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
- { return INVALID_OPERATION; }
- virtual void postBuffer(ssize_t offset) { }
- virtual void unregisterBuffers() { };
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format) {
- return NULL;
- };
+ ISurfaceFlingerClient::surface_data_t* params) const;
+
+ protected:
+ Surface(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner);
+ virtual ~Surface();
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ sp<LayerBaseClient> getOwner() const;
private:
- ISurfaceFlingerClient::surface_data_t mParams;
+ virtual sp<SurfaceBuffer> getBuffer();
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
+ int32_t format);
+
+ protected:
+ friend class LayerBaseClient;
+ sp<SurfaceFlinger> mFlinger;
+ int32_t mToken;
+ int32_t mIdentity;
+ wp<LayerBaseClient> mOwner;
};
-private:
- int32_t mIndex;
+ friend class Surface;
+private:
+ int32_t mIndex;
+ mutable Mutex mLock;
+ mutable wp<Surface> mClientSurface;
+ // only read
+ const uint32_t mIdentity;
+ static int32_t sIdentity;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 397ddc8..9fffbbf 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -14,174 +14,197 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/memory.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/IMemory.h>
+
#include <ui/PixelFormat.h>
+#include <ui/Surface.h>
#include <pixelflinger/pixelflinger.h>
+#include "BufferAllocator.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
namespace android {
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
-LayerBitmap::LayerBitmap()
- : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+ : SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags),
+ mVStride(0)
{
- memset(&mSurface, 0, sizeof(mSurface));
+ this->format = format;
+ if (w>0 && h>0) {
+ mInitCheck = initSize(w, h);
+ }
}
-LayerBitmap::~LayerBitmap()
+Buffer::~Buffer()
{
- mSurface.data = 0;
+ if (handle) {
+ BufferAllocator& allocator(BufferAllocator::get());
+ allocator.free(handle);
+ }
}
-status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
-{
- if (mAllocator != NULL)
- return BAD_VALUE;
- mAllocator = allocator;
- return NO_ERROR;
+status_t Buffer::initCheck() const {
+ return mInitCheck;
}
-status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags)
+android_native_buffer_t* Buffer::getNativeBuffer() const
{
- const sp<MemoryDealer>& allocator(mAllocator);
- if (allocator == NULL)
- return NO_INIT;
-
- if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
- format == mSurface.format))
- { // same format and size, do nothing.
- return NO_ERROR;
- }
-
- PixelFormatInfo info;
- getPixelFormatInfo(format, &info);
-
- uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
- const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
- const uint32_t Bpp = info.bytesPerPixel;
- uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
- stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
- size_t size = info.getScanlineSize(stride) * h;
- if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
- size_t pagesize = getpagesize();
- size = (size + (pagesize-1)) & ~(pagesize-1);
- }
+ return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
+}
- /* FIXME: we should be able to have a h/v stride because the user of the
- * surface might have stride limitation (for instance h/w codecs often do)
+status_t Buffer::initSize(uint32_t w, uint32_t h)
+{
+ status_t err = NO_ERROR;
+
+ BufferAllocator& allocator = BufferAllocator::get();
+
+ /*
+ * buffers used for software rendering, but h/w composition
+ * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
+ *
+ * buffers used for h/w rendering and h/w composition
+ * are allocated with HW_RENDER | HW_TEXTURE
+ *
+ * buffers used with h/w rendering and either NPOT or no egl_image_ext
+ * are allocated with SW_READ_RARELY | HW_RENDER
+ *
*/
- int32_t vstride = 0;
-
- mAlignment = alignment;
- mAllocFlags = allocFlags;
- mOffset = 0;
- if (mSize != size) {
- // would be nice to have a reallocate() api
- mBitsMemory.clear(); // free-memory
- mBitsMemory = allocator->allocate(size, allocFlags);
- mSize = size;
+
+ if (mFlags & Buffer::SECURE) {
+ // secure buffer, don't store it into the GPU
+ usage = BufferAllocator::USAGE_SW_READ_OFTEN |
+ BufferAllocator::USAGE_SW_WRITE_OFTEN;
} else {
- // don't erase memory if we didn't have to reallocate
- flags &= ~SECURE_BITS;
- }
- if (mBitsMemory != 0) {
- mOffset = mBitsMemory->offset();
- mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
- mSurface.version = sizeof(GGLSurface);
- mSurface.width = w;
- mSurface.height = h;
- mSurface.stride = stride;
- mSurface.vstride = vstride;
- mSurface.format = format;
- if (flags & SECURE_BITS)
- clear();
+ if (mFlags & Buffer::GPU) {
+ // the client wants to do GL rendering
+ usage = BufferAllocator::USAGE_HW_RENDER |
+ BufferAllocator::USAGE_HW_TEXTURE;
+ } else {
+ // software rendering-client, h/w composition
+ usage = BufferAllocator::USAGE_SW_READ_OFTEN |
+ BufferAllocator::USAGE_SW_WRITE_OFTEN |
+ BufferAllocator::USAGE_HW_TEXTURE;
+ }
}
- if (mBitsMemory==0 || mSurface.data==0) {
- LOGE("not enough memory for layer bitmap "
- "size=%u (w=%d, h=%d, stride=%d, format=%d)",
- size, int(w), int(h), int(stride), int(format));
- allocator->dump("LayerBitmap");
- mSurface.data = 0;
- mSize = -1U;
- return NO_MEMORY;
+ err = allocator.alloc(w, h, format, usage, &handle, &stride);
+
+ if (err == NO_ERROR) {
+ if (err == NO_ERROR) {
+ width = w;
+ height = h;
+ mVStride = 0;
+ }
}
- return NO_ERROR;
+
+ return err;
}
-void LayerBitmap::clear()
+status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
{
- // NOTE: this memset should not be necessary, at least for
- // opaque surface. However, for security reasons it's better to keep it
- // (in the case of pmem, it's possible that the memory contains old
- // data)
- if (mSurface.data) {
- memset(mSurface.data, 0, mSize);
- //if (bytesPerPixel(mSurface.format) == 4) {
- // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
- //} else {
- // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
- //}
+ void* vaddr;
+ status_t res = SurfaceBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->vstride = mVStride;
+ sur->data = static_cast<GGLubyte*>(vaddr);
}
+ return res;
}
-status_t LayerBitmap::getInfo(surface_info_t* info) const
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
+
+LayerBitmap::LayerBitmap()
+ : mInfo(0), mWidth(0), mHeight(0)
{
- if (mSurface.data == 0) {
- memset(info, 0, sizeof(surface_info_t));
- info->bits_offset = NO_MEMORY;
- return NO_MEMORY;
- }
- info->w = uint16_t(width());
- info->h = uint16_t(height());
- info->stride= uint16_t(stride());
- info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat()));
- info->format= uint8_t(pixelFormat());
- info->flags = surface_info_t::eBufferDirty;
- info->bits_offset = ssize_t(mOffset);
+}
+
+LayerBitmap::~LayerBitmap()
+{
+}
+
+status_t LayerBitmap::init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+{
+ if (info == NULL)
+ return BAD_VALUE;
+
+ mFormat = format;
+ mFlags = flags;
+ mWidth = w;
+ mHeight = h;
+
+ mInfo = info;
+ memset(info, 0, sizeof(surface_info_t));
+ info->flags = surface_info_t::eNeedNewBuffer;
+
+ // init the buffer, but don't trigger an allocation
+ mBuffer = new Buffer(0, 0, format, flags);
return NO_ERROR;
}
-status_t LayerBitmap::resize(uint32_t w, uint32_t h)
+status_t LayerBitmap::setSize(uint32_t w, uint32_t h)
{
- int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
- return err;
+ Mutex::Autolock _l(mLock);
+ if ((w != mWidth) || (h != mHeight)) {
+ mWidth = w;
+ mHeight = h;
+ // this will signal the client that it needs to asks us for a new buffer
+ mInfo->flags = surface_info_t::eNeedNewBuffer;
+ }
+ return NO_ERROR;
}
-size_t LayerBitmap::size() const
+sp<Buffer> LayerBitmap::allocate()
{
- return mSize;
+ Mutex::Autolock _l(mLock);
+ sp<Buffer> buffer(mBuffer);
+ const uint32_t w = mWidth;
+ const uint32_t h = mHeight;
+ if (buffer!=0 && (w != buffer->getWidth() || h != buffer->getHeight())) {
+ surface_info_t* info = mInfo;
+ buffer = new Buffer(w, h, mFormat, mFlags);
+ status_t err = buffer->initCheck();
+ if (LIKELY(err == NO_ERROR)) {
+ info->flags = surface_info_t::eBufferDirty;
+ info->status = NO_ERROR;
+ } else {
+ memset(info, 0, sizeof(surface_info_t));
+ info->status = NO_MEMORY;
+ }
+ mBuffer = buffer;
+ }
+ return buffer;
}
-void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
+status_t LayerBitmap::free()
{
- const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
- void* sbase = mh->base();
- const GGLSurface& t(surface());
- img->w = t.stride ?: t.width;
- img->h = t.vstride ?: t.height;
- img->format = t.format;
- img->offset = intptr_t(t.data) - intptr_t(sbase);
- img->base = sbase;
- img->fd = mh->heapID();
+ mBuffer.clear();
+ mWidth = 0;
+ mHeight = 0;
+ return NO_ERROR;
}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 9ad64c4..22525ce 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -20,63 +20,114 @@
#include <stdint.h>
#include <sys/types.h>
+#include <hardware/gralloc.h>
+
#include <utils/Atomic.h>
+
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
+#include <ui/Surface.h>
+
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/SharedState.h>
+#include <private/ui/SurfaceBuffer.h>
+
class copybit_image_t;
+struct android_native_buffer_t;
namespace android {
// ---------------------------------------------------------------------------
-
class IMemory;
-class MemoryDealer;
class LayerBitmap;
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer
+// ===========================================================================
-class LayerBitmap
+class NativeBuffer;
+
+class Buffer : public SurfaceBuffer
{
public:
-
enum {
- // erase memory to ensure security when necessary
- SECURE_BITS = 0x00000001
+ DONT_CLEAR = 0x00000001,
+ GPU = 0x00000002,
+ SECURE = 0x00000004
};
- LayerBitmap();
- ~LayerBitmap();
- status_t init(const sp<MemoryDealer>& allocator);
+ // creates w * h buffer
+ Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
+
+ // return status
+ status_t initCheck() const;
+
+ uint32_t getWidth() const { return width; }
+ uint32_t getHeight() const { return height; }
+ uint32_t getStride() const { return stride; }
+ uint32_t getUsage() const { return usage; }
+ PixelFormat getPixelFormat() const { return format; }
+ Rect getBounds() const { return Rect(width, height); }
+
+ status_t lock(GGLSurface* surface, uint32_t usage);
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+private:
+ friend class LightRefBase<Buffer>;
+ Buffer(const Buffer& rhs);
+ virtual ~Buffer();
+ Buffer& operator = (const Buffer& rhs);
+ const Buffer& operator = (const Buffer& rhs) const;
- status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags = 0);
- void clear();
+ status_t initSize(uint32_t w, uint32_t h);
- status_t getInfo(surface_info_t* info) const;
- status_t resize(uint32_t w, uint32_t h);
+ ssize_t mInitCheck;
+ uint32_t mFlags;
+ uint32_t mVStride;
+};
- const GGLSurface& surface() const { return mSurface; }
- Rect bounds() const { return Rect(width(), height()); }
- uint32_t width() const { return surface().width; }
- uint32_t height() const { return surface().height; }
- uint32_t stride() const { return surface().stride; }
- PixelFormat pixelFormat() const { return surface().format; }
- void* serverBits() const { return surface().data; }
- size_t size() const;
- const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
- void getBitmapSurface(copybit_image_t* img) const;
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
+class LayerBitmap
+{
+public:
+ enum {
+ DONT_CLEAR = Buffer::DONT_CLEAR,
+ GPU = Buffer::GPU,
+ SECURE = Buffer::SECURE
+ };
+ LayerBitmap();
+ ~LayerBitmap();
+
+ status_t init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
+
+ status_t setSize(uint32_t w, uint32_t h);
+
+ sp<Buffer> allocate();
+ status_t free();
+
+ sp<const Buffer> getBuffer() const { return mBuffer; }
+ sp<Buffer> getBuffer() { return mBuffer; }
+
+ uint32_t getWidth() const { return mWidth; }
+ uint32_t getHeight() const { return mHeight; }
+ PixelFormat getPixelFormat() const { return mBuffer->getPixelFormat(); }
+ Rect getBounds() const { return mBuffer->getBounds(); }
+
private:
- sp<MemoryDealer> mAllocator;
- sp<IMemory> mBitsMemory;
- uint32_t mAllocFlags;
- ssize_t mOffset;
- GGLSurface mSurface;
- size_t mSize;
- uint32_t mAlignment;
+ surface_info_t* mInfo;
+ sp<Buffer> mBuffer;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ // protects setSize() and allocate()
+ mutable Mutex mLock;
};
}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index d3e456f..00abd5a 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -40,7 +38,7 @@ const char* const LayerBlur::typeID = "LayerBlur";
// ---------------------------------------------------------------------------
LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
{
@@ -49,8 +47,7 @@ LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
LayerBlur::~LayerBlur()
{
if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ glDeleteTextures(1, &mTextureName);
}
}
@@ -139,8 +136,9 @@ void LayerBlur::onDraw(const Region& clip) const
glGenTextures(1, &mTextureName);
}
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
@@ -201,27 +199,25 @@ void LayerBlur::onDraw(const Region& clip) const
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
+ 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);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- // 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 (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, w, h);
- }
+ // 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);
}
}
}
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 24b1156..0c3e6eb 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -39,7 +39,7 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBlur();
virtual void onDraw(const Region& clip) const;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 00fab70..90e7f50 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
@@ -25,17 +23,16 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <hardware/copybit.h>
#include "LayerBuffer.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "gralloc_priv.h" // needed for msm / copybit
namespace android {
@@ -47,7 +44,7 @@ const char* const LayerBuffer::typeID = "LayerBuffer";
// ---------------------------------------------------------------------------
LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i),
mNeedsBlending(false)
{
@@ -55,30 +52,24 @@ LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
LayerBuffer::~LayerBuffer()
{
- sp<SurfaceBuffer> s(getClientSurface());
- if (s != 0) {
- s->disown();
- mClientSurface.clear();
- }
}
-sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+void LayerBuffer::onFirstRef()
{
- Mutex::Autolock _l(mLock);
- return mClientSurface.promote();
+ LayerBaseClient::onFirstRef();
+ mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
+ const_cast<LayerBuffer *>(this));
}
-sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
{
- sp<SurfaceBuffer> s;
- Mutex::Autolock _l(mLock);
- s = mClientSurface.promote();
- if (s == 0) {
- s = new SurfaceBuffer(clientIndex(),
- const_cast<LayerBuffer *>(this));
- mClientSurface = s;
- }
- return s;
+ return mSurface;
+}
+
+status_t LayerBuffer::ditch()
+{
+ mSurface.clear();
+ return NO_ERROR;
}
bool LayerBuffer::needsBlending() const {
@@ -192,82 +183,49 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() {
// LayerBuffer::SurfaceBuffer
// ============================================================================
-LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
-: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner)
+ : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
{
}
LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
{
unregisterBuffers();
- mOwner = 0;
-}
-
-status_t LayerBuffer::SurfaceBuffer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case REGISTER_BUFFERS:
- case UNREGISTER_BUFFERS:
- case CREATE_OVERLAY:
- {
- // codes that require permission check
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int self_pid = getpid();
- if (LIKELY(pid != self_pid)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- const int uid = ipc->getCallingUid();
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- }
- }
- return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
}
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(
+ const ISurface::BufferHeap& buffers)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
return owner->registerBuffers(buffers);
return NO_INIT;
}
void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->postBuffer(offset);
}
void LayerBuffer::SurfaceBuffer::unregisterBuffers()
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->unregisterBuffers();
}
sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
uint32_t w, uint32_t h, int32_t format) {
sp<OverlayRef> result;
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
result = owner->createOverlay(w, h, format);
return result;
}
-void LayerBuffer::SurfaceBuffer::disown()
-{
- Mutex::Autolock _l(mLock);
- mOwner = 0;
-}
-
// ============================================================================
// LayerBuffer::Buffer
// ============================================================================
@@ -276,20 +234,30 @@ LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
: mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
+
src.crop.l = 0;
src.crop.t = 0;
src.crop.r = buffers.w;
src.crop.b = buffers.h;
- src.img.w = buffers.hor_stride ?: buffers.w;
- src.img.h = buffers.ver_stride ?: buffers.h;
- src.img.format = buffers.format;
- src.img.offset = offset;
- src.img.base = buffers.heap->base();
- src.img.fd = buffers.heap->heapID();
+
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
+ src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
+
+ // FIXME: gross hack, we should never access private_handle_t from here,
+ // but this is needed by msm drivers
+ private_handle_t* hnd = new private_handle_t(
+ buffers.heap->heapID(), buffers.heap->getSize(), 0);
+ hnd->offset = offset;
+ src.img.handle = hnd;
}
LayerBuffer::Buffer::~Buffer()
{
+ NativeBuffer& src(mNativeBuffer);
+ if (src.img.handle)
+ delete (private_handle_t*)src.img.handle;
}
// ============================================================================
@@ -323,8 +291,7 @@ bool LayerBuffer::Source::transformed() const {
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
const ISurface::BufferHeap& buffers)
- : Source(layer), mStatus(NO_ERROR),
- mBufferSize(0), mTextureName(-1U)
+ : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
{
if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
@@ -363,13 +330,21 @@ LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
mLayer.forceVisibilityTransaction();
-
+
+ hw_module_t const* module;
+ mBlitEngine = NULL;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
}
LayerBuffer::BufferSource::~BufferSource()
{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
+ if (mTexture.name != -1U) {
+ glDeleteTextures(1, &mTexture.name);
+ }
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
}
}
@@ -427,19 +402,19 @@ bool LayerBuffer::BufferSource::transformed() const
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
- sp<Buffer> buffer(getBuffer());
- if (UNLIKELY(buffer == 0)) {
+ sp<Buffer> ourBuffer(getBuffer());
+ if (UNLIKELY(ourBuffer == 0)) {
// nothing to do, we don't have a buffer
mLayer.clearWithOpenGL(clip);
return;
}
status_t err = NO_ERROR;
- NativeBuffer src(buffer->getBuffer());
+ NativeBuffer src(ourBuffer->getBuffer());
const Rect& transformedBounds = mLayer.getTransformedBounds();
- const int can_use_copybit = mLayer.canUseCopybit();
+ copybit_device_t* copybit = mBlitEngine;
- if (can_use_copybit) {
+ if (copybit) {
const int src_width = src.crop.r - src.crop.l;
const int src_height = src.crop.b - src.crop.t;
int W = transformedBounds.width();
@@ -448,89 +423,108 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
int t(W); W=H; H=t;
}
- /* With LayerBuffer, it is likely that we'll have to rescale the
- * surface, because this is often used for video playback or
- * camera-preview. Since we want these operation as fast as possible
- * we make sure we can use the 2D H/W even if it doesn't support
- * the requested scale factor, in which case we perform the scaling
- * in several passes. */
-
- copybit_device_t* copybit = mLayer.mFlinger->getBlitEngine();
- const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
- const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
-
- float xscale = 1.0f;
- if (src_width > W*min) xscale = 1.0f / min;
- else if (src_width*mag < W) xscale = mag;
-
- float yscale = 1.0f;
- if (src_height > H*min) yscale = 1.0f / min;
- else if (src_height*mag < H) yscale = mag;
-
- if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
- if (UNLIKELY(mTemporaryDealer == 0)) {
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- mTempBitmap.init(mTemporaryDealer);
+#ifdef EGL_ANDROID_get_render_buffer
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLSurface draw = eglGetCurrentSurface(EGL_DRAW);
+ EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
+ android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
+ if (nb == 0) {
+ err = BAD_VALUE;
+ } else {
+ copybit_image_t dst;
+ dst.w = nb->width;
+ dst.h = nb->height;
+ dst.format = nb->format;
+ dst.base = NULL; // unused by copybit on msm7k
+ dst.handle = (native_handle_t *)nb->handle;
+
+ /* With LayerBuffer, it is likely that we'll have to rescale the
+ * surface, because this is often used for video playback or
+ * camera-preview. Since we want these operation as fast as possible
+ * we make sure we can use the 2D H/W even if it doesn't support
+ * the requested scale factor, in which case we perform the scaling
+ * in several passes. */
+
+ const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+ float xscale = 1.0f;
+ if (src_width > W*min) xscale = 1.0f / min;
+ else if (src_width*mag < W) xscale = mag;
+
+ float yscale = 1.0f;
+ if (src_height > H*min) yscale = 1.0f / min;
+ else if (src_height*mag < H) yscale = mag;
+
+ if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+ const int tmp_w = floorf(src_width * xscale);
+ const int tmp_h = floorf(src_height * yscale);
+
+ if (mTempBitmap==0 ||
+ mTempBitmap->getWidth() < tmp_w ||
+ mTempBitmap->getHeight() < tmp_h) {
+ mTempBitmap.clear();
+ mTempBitmap = new android::Buffer(tmp_w, tmp_h, src.img.format);
+ err = mTempBitmap->initCheck();
+ }
+
+ if (LIKELY(err == NO_ERROR)) {
+ NativeBuffer tmp;
+ tmp.img.w = tmp_w;
+ tmp.img.h = tmp_h;
+ tmp.img.format = src.img.format;
+ tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
+ tmp.crop.l = 0;
+ tmp.crop.t = 0;
+ tmp.crop.r = tmp.img.w;
+ tmp.crop.b = tmp.img.h;
+
+ region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+ src = tmp;
+ }
}
- const int tmp_w = floorf(src_width * xscale);
- const int tmp_h = floorf(src_height * yscale);
- err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
-
- if (LIKELY(err == NO_ERROR)) {
- NativeBuffer tmp;
- mTempBitmap.getBitmapSurface(&tmp.img);
- tmp.crop.l = 0;
- tmp.crop.t = 0;
- tmp.crop.r = tmp.img.w;
- tmp.crop.b = tmp.img.h;
-
- region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- err = copybit->stretch(copybit,
- &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
- src = tmp;
+ const Rect& transformedBounds = mLayer.getTransformedBounds();
+ const copybit_rect_t& drect =
+ reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ const State& s(mLayer.drawingState());
+ region_iterator it(clip);
+
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
}
- }
- const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
- const State& s(mLayer.drawingState());
- region_iterator it(clip);
-
- // pick the right orientation for this buffer
- int orientation = mLayer.getOrientation();
- if (UNLIKELY(mBufferHeap.transform)) {
- Transform rot90;
- GraphicPlane::orientationToTransfrom(
- ISurfaceComposer::eOrientation90, 0, 0, &rot90);
- const Transform& planeTransform(mLayer.graphicPlane(0).transform());
- const Layer::State& s(mLayer.drawingState());
- Transform tr(planeTransform * s.transform * rot90);
- orientation = tr.getOrientation();
- }
-
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
- err = copybit->stretch(copybit,
- &dst, &src.img, &drect, &src.crop, &it);
- if (err != NO_ERROR) {
- LOGE("copybit failed (%s)", strerror(err));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ err = copybit->stretch(copybit,
+ &dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
}
}
-
- if (!can_use_copybit || err) {
- if (UNLIKELY(mTextureName == -1LU)) {
- mTextureName = mLayer.createTexture();
+#endif
+
+ if (!copybit || err)
+ {
+ // OpenGL fall-back
+ if (UNLIKELY(mTexture.name == -1LU)) {
+ mTexture.name = mLayer.createTexture();
}
GLuint w = 0;
GLuint h = 0;
@@ -541,10 +535,11 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
t.stride = src.img.w;
t.vstride= src.img.h;
t.format = src.img.format;
- t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
+ t.data = (GGLubyte*)src.img.base;
const Region dirty(Rect(t.width, t.height));
- mLayer.loadTexture(dirty, mTextureName, t, w, h);
- mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
+ mLayer.loadTexture(&mTexture, mTexture.name, dirty, t);
+ mTexture.transform = mBufferHeap.transform;
+ mLayer.drawWithOpenGL(clip, mTexture);
}
}
@@ -580,6 +575,7 @@ LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
mFormat = overlay->format;
mWidthStride = overlay->w_stride;
mHeightStride = overlay->h_stride;
+ mInitialized = false;
mOverlayHandle = overlay->getHandleRef(overlay);
@@ -599,6 +595,11 @@ LayerBuffer::OverlaySource::~OverlaySource()
}
}
+void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
+{
+ mLayer.clearWithOpenGL(clip);
+}
+
void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
{
const Layer::State& front(mLayer.drawingState());
@@ -614,8 +615,9 @@ void LayerBuffer::OverlaySource::onVisibilityResolved(
// this code-path must be as tight as possible, it's called each time
// the screen is composited.
if (UNLIKELY(mOverlay != 0)) {
- if (mVisibilityChanged) {
+ if (mVisibilityChanged || !mInitialized) {
mVisibilityChanged = false;
+ mInitialized = true;
const Rect& bounds = mLayer.getTransformedBounds();
int x = bounds.left;
int y = bounds.top;
@@ -627,8 +629,9 @@ void LayerBuffer::OverlaySource::onVisibilityResolved(
if (mOverlay) {
overlay_control_device_t* overlay_dev = mOverlayDevice;
overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
- overlay_dev->setParameter(overlay_dev, mOverlay,
+ overlay_dev->setParameter(overlay_dev, mOverlay,
OVERLAY_TRANSFORM, mLayer.getOrientation());
+ overlay_dev->commit(overlay_dev, mOverlay);
}
}
}
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2dc77f1..8057219 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -20,18 +20,18 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <private/ui/LayerState.h>
-#include <EGL/eglnatives.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
+struct copybit_device_t;
+
namespace android {
// ---------------------------------------------------------------------------
-class MemoryDealer;
class Region;
class OverlayRef;
@@ -51,7 +51,6 @@ class LayerBuffer : public LayerBaseClient
LayerBuffer& mLayer;
};
-
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -59,12 +58,14 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBuffer();
+ virtual void onFirstRef();
virtual bool needsBlending() const;
- virtual sp<LayerBaseClient::Surface> getSurface() const;
+ 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);
@@ -121,14 +122,14 @@ private:
virtual void unregisterBuffers();
virtual bool transformed() const;
private:
- mutable Mutex mLock;
- sp<Buffer> mBuffer;
- status_t mStatus;
- ISurface::BufferHeap mBufferHeap;
- size_t mBufferSize;
- mutable sp<MemoryDealer> mTemporaryDealer;
- mutable LayerBitmap mTempBitmap;
- mutable GLuint mTextureName;
+ mutable Mutex mLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable sp<android::Buffer> mTempBitmap;
+ mutable LayerBase::Texture mTexture;
+ copybit_device_t* mBlitEngine;
};
class OverlaySource : public Source {
@@ -137,6 +138,7 @@ private:
sp<OverlayRef>* overlayRef,
uint32_t w, uint32_t h, int32_t format);
virtual ~OverlaySource();
+ virtual void onDraw(const Region& clip) const;
virtual void onTransaction(uint32_t flags);
virtual void onVisibilityResolved(const Transform& planeTransform);
private:
@@ -173,40 +175,34 @@ private:
int32_t mWidthStride;
int32_t mHeightStride;
mutable Mutex mLock;
+ bool mInitialized;
};
class SurfaceBuffer : public LayerBaseClient::Surface
{
public:
- SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+ SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner);
virtual ~SurfaceBuffer();
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+
virtual sp<OverlayRef> createOverlay(
uint32_t w, uint32_t h, int32_t format);
- void disown();
private:
- LayerBuffer* getOwner() const {
- Mutex::Autolock _l(mLock);
- return mOwner;
+ sp<LayerBuffer> getOwner() const {
+ return static_cast<LayerBuffer*>(Surface::getOwner().get());
}
- mutable Mutex mLock;
- LayerBuffer* mOwner;
};
-
- friend class SurfaceFlinger;
- sp<SurfaceBuffer> getClientSurface() const;
-
+
mutable Mutex mLock;
sp<Source> mSource;
-
+ sp<Surface> mSurface;
bool mInvalidate;
bool mNeedsBlending;
- mutable wp<SurfaceBuffer> mClientSurface;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 0c347cc..8e9df9c 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -25,7 +23,6 @@
#include "LayerDim.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
@@ -33,27 +30,74 @@ namespace android {
const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
const char* const LayerDim::typeID = "LayerDim";
-sp<MemoryDealer> LayerDim::mDimmerDealer;
-LayerBitmap LayerDim::mDimmerBitmap;
+
+bool LayerDim::sUseTexture;
+GLuint LayerDim::sTexId;
+EGLImageKHR LayerDim::sImage;
+int32_t LayerDim::sWidth;
+int32_t LayerDim::sHeight;
// ---------------------------------------------------------------------------
LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
- : LayerBaseClient(flinger, display, client, i)
+ const sp<Client>& client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i)
{
}
void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
{
- // must only be called once.
- mDimmerDealer = flinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- if (mDimmerDealer != 0) {
- mDimmerBitmap.init(mDimmerDealer);
- mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
- mDimmerBitmap.clear();
+ sTexId = -1;
+ sImage = EGL_NO_IMAGE_KHR;
+ sWidth = w;
+ sHeight = h;
+ sUseTexture = false;
+
+#ifdef DIM_WITH_TEXTURE
+
+#warning "using a texture to implement LayerDim"
+
+ /* On some h/w like msm7K, it is faster to use a texture because the
+ * software renderer will defer to copybit, for this to work we need to
+ * use an EGLImage texture so copybit can actually make use of it.
+ * This burns a full-screen worth of graphic memory.
+ */
+
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ uint32_t flags = hw.getFlags();
+
+ if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
+ // TODO: api to pass the usage flags
+ sp<Buffer> buffer = new Buffer(w, h, PIXEL_FORMAT_RGB_565);
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ glGenTextures(1, &sTexId);
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
+ if (sImage == EGL_NO_IMAGE_KHR) {
+ LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+ return;
+ }
+
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
+ GLint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ eglDestroyImageKHR(dpy, sImage);
+ LOGE("glEGLImageTargetTexture2DOES() failed. err=0x%4x", error);
+ return;
+ }
+
+ // initialize the texture with zeros
+ GGLSurface t;
+ buffer->lock(&t, GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ memset(t.data, 0, t.stride * t.height * 2);
+ buffer->unlock();
+ sUseTexture = true;
}
+#endif
}
LayerDim::~LayerDim()
@@ -63,49 +107,56 @@ LayerDim::~LayerDim()
void LayerDim::onDraw(const Region& clip) const
{
const State& s(drawingState());
-
- Region::iterator iterator(clip);
- if (s.alpha>0 && iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (s.alpha>0 && (it != end)) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- mDimmerBitmap.getBitmapSurface(&src);
- const copybit_rect_t& srect(drect);
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0, 0, alpha);
+
+#ifdef DIM_WITH_TEXTURE
+ if (sUseTexture) {
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ const GLshort texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_SHORT, 0, texCoords);
+ } else
+#endif
+ {
+ glDisable(GL_TEXTURE_2D);
}
- if (!can_use_copybit || err) {
- const GGLfixed alpha = (s.alpha << 16)/255;
- const uint32_t fbHeight = hw.getHeight();
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_DITHER);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glColor4x(0, 0, 0, alpha);
- glVertexPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
+ GLshort w = sWidth;
+ GLshort h = sHeight;
+ const GLshort vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+
+ 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/LayerDim.h b/libs/surfaceflinger/LayerDim.h
index 3e37a47..33bd49d 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -20,6 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -29,6 +32,11 @@ namespace android {
class LayerDim : public LayerBaseClient
{
+ static bool sUseTexture;
+ static GLuint sTexId;
+ static EGLImageKHR sImage;
+ static int32_t sWidth;
+ static int32_t sHeight;
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -36,7 +44,7 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerDim();
virtual void onDraw(const Region& clip) const;
@@ -44,10 +52,6 @@ public:
virtual bool isSecure() const { return false; }
static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
-
-private:
- static sp<MemoryDealer> mDimmerDealer;
- static LayerBitmap mDimmerBitmap;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
deleted file mode 100644
index 79e5328..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/StopWatch.h>
-
-#include <core/SkBitmap.h>
-
-#include <ui/EGLDisplaySurface.h>
-
-#include "BlurFilter.h"
-#include "LayerBase.h"
-#include "LayerOrientationAnim.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "OrientationAnimation.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
-const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
-
-// ---------------------------------------------------------------------------
-
-// Animation...
-const float DURATION = ms2ns(200);
-const float BOUNCES_PER_SECOND = 0.5f;
-const float DIM_TARGET = 0.40f;
-#define INTERPOLATED_TIME(_t) (_t)
-
-// ---------------------------------------------------------------------------
-
-LayerOrientationAnim::LayerOrientationAnim(
- SurfaceFlinger* flinger, DisplayID display,
- OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut)
- : LayerOrientationAnimBase(flinger, display), mAnim(anim),
- mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
- mTextureName(-1), mTextureNameIn(-1)
-{
- // blur that texture.
- mOrientationCompleted = false;
- mNeedsBlending = false;
-}
-
-LayerOrientationAnim::~LayerOrientationAnim()
-{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
- }
- if (mTextureNameIn != -1U) {
- LayerBase::deletedTextures.add(mTextureNameIn);
- }
-}
-
-bool LayerOrientationAnim::needsBlending() const
-{
- return mNeedsBlending;
-}
-
-Point LayerOrientationAnim::getPhysicalSize() const
-{
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- return Point(hw.getWidth(), hw.getHeight());
-}
-
-void LayerOrientationAnim::validateVisibility(const Transform&)
-{
- const Layer::State& s(drawingState());
- const Transform tr(s.transform);
- const Point size(getPhysicalSize());
- uint32_t w = size.x;
- uint32_t h = size.y;
- mTransformedBounds = tr.makeBounds(w, h);
- mLeft = tr.tx();
- mTop = tr.ty();
- transparentRegionScreen.clear();
- mTransformed = true;
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- mCanUseCopyBit = true;
- }
-}
-
-void LayerOrientationAnim::onOrientationCompleted()
-{
- mAnim->onAnimationFinished();
-}
-
-void LayerOrientationAnim::onDraw(const Region& clip) const
-{
- float alphaIn = DIM_TARGET;
-
- // clear screen
- // TODO: with update on demand, we may be able
- // to not erase the screen at all during the animation
- if (!mOrientationCompleted) {
- glDisable(GL_BLEND);
- glDisable(GL_DITHER);
- glDisable(GL_SCISSOR_TEST);
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-
- copybit_image_t dst;
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- hw.getDisplaySurface(&dst);
-
- copybit_image_t src;
- mBitmapIn.getBitmapSurface(&src);
-
- copybit_image_t srcOut;
- mBitmapOut.getBitmapSurface(&srcOut);
-
- const int w = dst.w;
- const int h = dst.h;
- const int xc = uint32_t(dst.w-w)/2;
- const int yc = uint32_t(dst.h-h)/2;
- const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
- const copybit_rect_t srect = { 0, 0, src.w, src.h };
- const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
-
- int err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
- if (alphaIn > 0) {
- region_iterator it(reg);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_ENABLE);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alphaIn*255));
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_DISABLE);
- }
- LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
- }
- if (!can_use_copybit || err) {
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = src.w;
- t.height = src.h;
- t.stride = src.w;
- t.vstride= src.h;
- t.format = src.format;
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
-
- Transform tr;
- tr.set(xc, yc);
-
- // FIXME: we should not access mVertices and mDrawingState like that,
- // but since we control the animation, we know it's going to work okay.
- // eventually we'd need a more formal way of doing things like this.
- LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
- tr.transform(self.mVertices[0], 0, 0);
- tr.transform(self.mVertices[1], 0, src.h);
- tr.transform(self.mVertices[2], src.w, src.h);
- tr.transform(self.mVertices[3], src.w, 0);
- if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
- // Too slow to do this in software
- self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
- }
-
- if (alphaIn > 0.0f) {
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
- if (UNLIKELY(mTextureNameIn == -1LU)) {
- mTextureNameIn = createTexture();
- GLuint w=0, h=0;
- const Region dirty(Rect(t.width, t.height));
- loadTexture(dirty, mTextureNameIn, t, w, h);
- }
- self.mDrawingState.alpha = int(alphaIn*255);
- drawWithOpenGL(reg, mTextureNameIn, t);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp
new file mode 100644
index 0000000..b43d801
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2009 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 <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void MessageList::insert(const sp<MessageBase>& node)
+{
+ LIST::iterator cur(mList.begin());
+ LIST::iterator end(mList.end());
+ while (cur != end) {
+ if (*node < **cur) {
+ mList.insert(cur, node);
+ return;
+ }
+ ++cur;
+ }
+ mList.insert(++end, node);
+}
+
+void MessageList::remove(MessageList::LIST::iterator pos)
+{
+ mList.erase(pos);
+}
+
+// ---------------------------------------------------------------------------
+
+MessageQueue::MessageQueue()
+ : mInvalidate(false)
+{
+ mInvalidateMessage = new MessageBase(INVALIDATE);
+}
+
+MessageQueue::~MessageQueue()
+{
+}
+
+MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
+{
+ MessageList::value_type result;
+
+ bool again;
+ do {
+ const nsecs_t timeoutTime = systemTime() + timeout;
+ while (true) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime();
+ nsecs_t nextEventTime = -1;
+
+ // invalidate messages are always handled first
+ if (mInvalidate) {
+ mInvalidate = false;
+ mInvalidateMessage->when = now;
+ result = mInvalidateMessage;
+ break;
+ }
+
+ LIST::iterator cur(mMessages.begin());
+ if (cur != mMessages.end()) {
+ result = *cur;
+ }
+
+ if (result != 0) {
+ if (result->when <= now) {
+ // there is a message to deliver
+ mMessages.remove(cur);
+ break;
+ }
+ if (timeout>=0 && timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ nextEventTime = result->when;
+ result = 0;
+ }
+
+ if (timeout >= 0 && nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ }
+
+ if (nextEventTime >= 0) {
+ //LOGD("nextEventTime = %lld ms", nextEventTime);
+ if (nextEventTime > 0) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ const nsecs_t reltime = nextEventTime - systemTime();
+ if (reltime > 0) {
+ mCondition.waitRelative(mLock, reltime);
+ }
+ }
+ } else {
+ //LOGD("going to wait");
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mCondition.wait(mLock);
+ }
+ }
+ // here we're not holding the lock anymore
+
+ if (result == 0)
+ break;
+
+ again = result->handler();
+ if (again) {
+ // the message has been processed. release our reference to it
+ // without holding the lock.
+ result = 0;
+ }
+
+ } while (again);
+
+ return result;
+}
+
+status_t MessageQueue::postMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ return queueMessage(message, relTime, flags);
+}
+
+status_t MessageQueue::invalidate() {
+ Mutex::Autolock _l(mLock);
+ mInvalidate = true;
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t MessageQueue::queueMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ message->when = systemTime() + relTime;
+ mMessages.insert(message);
+
+ //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
+ //dumpLocked(message);
+
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+void MessageQueue::dump(const MessageList::value_type& message)
+{
+ Mutex::Autolock _l(mLock);
+ dumpLocked(message);
+}
+
+void MessageQueue::dumpLocked(const MessageList::value_type& message)
+{
+ LIST::const_iterator cur(mMessages.begin());
+ LIST::const_iterator end(mMessages.end());
+ int c = 0;
+ while (cur != end) {
+ const char tick = (*cur == message) ? '>' : ' ';
+ LOGD("%c %d: msg{.what=%08x, when=%lld}",
+ tick, c, (*cur)->what, (*cur)->when);
+ ++cur;
+ c++;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h
new file mode 100644
index 0000000..dc8138d
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 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_MESSAGE_QUEUE_H
+#define ANDROID_MESSAGE_QUEUE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MessageBase;
+
+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(); }
+ inline LIST::const_iterator end() const { return mList.end(); }
+ inline bool isEmpty() const { return mList.empty(); }
+ void insert(const sp<MessageBase>& node);
+ void remove(LIST::iterator pos);
+};
+
+// ============================================================================
+
+class MessageBase :
+ public LightRefBase<MessageBase>
+{
+public:
+ nsecs_t when;
+ uint32_t what;
+ int32_t arg0;
+
+ MessageBase() : when(0), what(0), arg0(0) { }
+ MessageBase(uint32_t what, int32_t arg0=0)
+ : when(0), what(what), arg0(arg0) { }
+
+ // return true if message has a handler
+ virtual bool handler() { return false; }
+
+protected:
+ virtual ~MessageBase() { }
+
+private:
+ friend class LightRefBase<MessageBase>;
+};
+
+inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
+ return lhs.when < rhs.when;
+}
+
+// ---------------------------------------------------------------------------
+
+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
+ };
+
+ MessageList::value_type waitMessage(nsecs_t timeout = -1);
+
+ status_t postMessage(const MessageList::value_type& message,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ status_t invalidate();
+
+ void dump(const MessageList::value_type& message);
+
+private:
+ status_t queueMessage(const MessageList::value_type& message,
+ nsecs_t reltime, uint32_t flags);
+ void dumpLocked(const MessageList::value_type& message);
+
+ Mutex mLock;
+ Condition mCondition;
+ MessageList mMessages;
+ bool mInvalidate;
+ MessageList::value_type mInvalidateMessage;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index fb25663..7a7574f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
@@ -23,6 +21,7 @@
#include <fcntl.h>
#include <errno.h>
#include <math.h>
+#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -30,36 +29,30 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
#include <ui/DisplayInfo.h>
-#include <ui/EGLDisplaySurface.h>
#include <pixelflinger/pixelflinger.h>
#include <GLES/gl.h>
#include "clz.h"
-#include "CPUGauge.h"
+#include "BufferAllocator.h"
#include "Layer.h"
#include "LayerBlur.h"
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
-#include "GPUHardware/GPUHardware.h"
-
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -93,30 +86,30 @@ SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
}
ssize_t SurfaceFlinger::LayerVector::indexOf(
- LayerBase* key, size_t guess) const
+ const sp<LayerBase>& key, size_t guess) const
{
if (guess<size() && lookup.keyAt(guess) == key)
return guess;
const ssize_t i = lookup.indexOfKey(key);
if (i>=0) {
const size_t idx = lookup.valueAt(i);
- LOG_ASSERT(layers[idx]==key,
+ LOGE_IF(layers[idx]!=key,
"LayerVector[%p]: layers[%d]=%p, key=%p",
- this, int(idx), layers[idx], key);
+ this, int(idx), layers[idx].get(), key.get());
return idx;
}
return i;
}
ssize_t SurfaceFlinger::LayerVector::add(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
size_t count = layers.size();
ssize_t l = 0;
ssize_t h = count-1;
ssize_t mid;
- LayerBase* const* a = layers.array();
+ sp<LayerBase> const* a = layers.array();
while (l <= h) {
mid = l + (h - l)/2;
const int c = cmp(a+mid, &layer);
@@ -139,14 +132,14 @@ ssize_t SurfaceFlinger::LayerVector::add(
return order;
}
-ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
+ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
{
const ssize_t keyIndex = lookup.indexOfKey(layer);
if (keyIndex >= 0) {
const size_t index = lookup.valueAt(keyIndex);
- LOG_ASSERT(layers[index]==layer,
+ LOGE_IF(layers[index]!=layer,
"LayerVector[%p]: layers[%u]=%p, layer=%p",
- this, int(index), layers[index], layer);
+ this, int(index), layers[index].get(), layer.get());
layers.removeItemsAt(index);
lookup.removeItemsAt(keyIndex);
const size_t count = lookup.size();
@@ -161,8 +154,8 @@ ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
}
ssize_t SurfaceFlinger::LayerVector::reorder(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
// XXX: it's a little lame. but oh well...
ssize_t err = remove(layer);
@@ -180,7 +173,11 @@ SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
mTransactionCount(0),
+ mLayersRemoved(false),
mBootTime(systemTime()),
+ mHardwareTest("android.permission.HARDWARE_TEST"),
+ mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
+ mDump("android.permission.DUMP"),
mLastScheduledBroadcast(NULL),
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
@@ -188,11 +185,7 @@ SurfaceFlinger::SurfaceFlinger()
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
- mDebugCpu(0),
- mDebugFps(0),
mDebugBackground(0),
- mSyncObject(),
- mDeplayedTransactionPending(0),
mConsoleSignals(0),
mSecureFrameBuffer(0)
{
@@ -207,28 +200,16 @@ void SurfaceFlinger::init()
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
- property_get("debug.sf.showcpu", value, "0");
- mDebugCpu = atoi(value);
property_get("debug.sf.showbackground", value, "0");
mDebugBackground = atoi(value);
- property_get("debug.sf.showfps", value, "0");
- mDebugFps = atoi(value);
LOGI_IF(mDebugRegion, "showupdates enabled");
- LOGI_IF(mDebugCpu, "showcpu enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
- LOGI_IF(mDebugFps, "showfps enabled");
}
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
- delete mOrientationAnimation;
-}
-
-copybit_device_t* SurfaceFlinger::getBlitEngine() const
-{
- return graphicPlane(0).displayHardware().getBlitEngine();
}
overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
@@ -236,29 +217,9 @@ overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
return graphicPlane(0).displayHardware().getOverlayEngine();
}
-sp<IMemory> SurfaceFlinger::getCblk() const
+sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
- return mServerCblkMemory;
-}
-
-status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu)
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- status_t err = mGPU->request(pid, callback, gpu);
- return err;
-}
-
-status_t SurfaceFlinger::revokeGPU()
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- return mGPU->friendlyRevoke();
+ return mServerHeap;
}
sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
@@ -266,33 +227,34 @@ sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
Mutex::Autolock _l(mStateLock);
uint32_t token = mTokens.acquire();
- Client* client = new Client(token, this);
- if ((client == 0) || (client->ctrlblk == 0)) {
+ sp<Client> client = new Client(token, this);
+ if (client->ctrlblk == 0) {
mTokens.release(token);
return 0;
}
status_t err = mClientsMap.add(token, client);
if (err < 0) {
- delete client;
mTokens.release(token);
return 0;
}
sp<BClient> bclient =
- new BClient(this, token, client->controlBlockMemory());
+ new BClient(this, token, client->getControlBlockMemory());
return bclient;
}
void SurfaceFlinger::destroyConnection(ClientID cid)
{
Mutex::Autolock _l(mStateLock);
- Client* const client = mClientsMap.valueFor(cid);
- if (client) {
+ sp<Client> client = mClientsMap.valueFor(cid);
+ if (client != 0) {
// free all the layers this client owns
- const Vector<LayerBaseClient*>& layers = client->getLayers();
+ Vector< wp<LayerBaseClient> > layers(client->getLayers());
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- LayerBaseClient* const layer = layers[i];
- removeLayer_l(layer);
+ sp<LayerBaseClient> layer(layers[i].promote());
+ if (layer != 0) {
+ purgatorizeLayer_l(layer);
+ }
}
// the resources associated with this client will be freed
@@ -339,41 +301,15 @@ void SurfaceFlinger::onFirstRef()
mReadyToRunBarrier.wait();
}
-
static inline uint16_t pack565(int r, int g, int b) {
return (r<<11)|(g<<5)|b;
}
-// this is defined in libGLES_CM.so
-extern ISurfaceComposer* GLES_localSurfaceManager;
-
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- // create the shared control-block
- mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
- LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
- mServerCblkMemory = mServerHeap->allocate(4096);
- LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
-
- mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
- LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
- new(mServerCblk) surface_flinger_cblk_t;
-
- // get a reference to the GPU if we have one
- mGPU = GPUFactory::getGPU();
-
- // create the surface Heap manager, which manages the heaps
- // (be it in RAM or VRAM) where surfaces are allocated
- // We give 8 MB per client.
- mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
-
-
- GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
-
// we only support one display currently
int dpy = 0;
@@ -384,6 +320,16 @@ status_t SurfaceFlinger::readyToRun()
plane.setDisplayHardware(hw);
}
+ // create the shared control-block
+ mServerHeap = new MemoryHeapBase(4096,
+ MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+
+ new(mServerCblk) surface_flinger_cblk_t;
+
// initialize primary screen
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
@@ -450,13 +396,6 @@ status_t SurfaceFlinger::readyToRun()
* We're now ready to accept clients...
*/
- mOrientationAnimation = new OrientationAnimation(this);
-
- // start CPU gauge display
- if (mDebugCpu)
- mCpuGauge = new CPUGauge(this, ms2ns(500));
-
-
// start boot animation
property_set("ctl.start", "bootanim");
@@ -471,45 +410,53 @@ status_t SurfaceFlinger::readyToRun()
void SurfaceFlinger::waitForEvent()
{
- // wait for something to do
- if (UNLIKELY(isFrozen())) {
- // wait 5 seconds
- const nsecs_t freezeDisplayTimeout = ms2ns(5000);
- const nsecs_t now = systemTime();
- if (mFreezeDisplayTime == 0) {
- mFreezeDisplayTime = now;
+ while (true) {
+ nsecs_t timeout = -1;
+ if (UNLIKELY(isFrozen())) {
+ // wait 5 seconds
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ timeout = waitTime>0 ? waitTime : 0;
}
- nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
- int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
- if (err != NO_ERROR) {
+
+ MessageList::value_type msg = mEventQueue.waitMessage(timeout);
+ if (msg != 0) {
+ mFreezeDisplayTime = 0;
+ switch (msg->what) {
+ case MessageQueue::INVALIDATE:
+ // invalidate message, just return to the main loop
+ return;
+ }
+ } else {
+ // we timed out
if (isFrozen()) {
// we timed out and are still frozen
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
mFreezeDisplay, mFreezeCount);
mFreezeCount = 0;
mFreezeDisplay = false;
+ return;
}
}
- } else {
- mFreezeDisplayTime = 0;
- mSyncObject.wait();
}
}
void SurfaceFlinger::signalEvent() {
- mSyncObject.open();
+ mEventQueue.invalidate();
}
void SurfaceFlinger::signal() const {
- mSyncObject.open();
+ // this is the IPC call
+ const_cast<SurfaceFlinger*>(this)->signalEvent();
}
void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
{
- if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
- sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
- delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
- }
+ mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay);
}
// ----------------------------------------------------------------------------
@@ -548,11 +495,6 @@ bool SurfaceFlinger::threadLoop()
unlockClients();
executeScheduledBroadcasts();
- // sample the cpu gauge
- if (UNLIKELY(mDebugCpu)) {
- handleDebugCpu();
- }
-
postFramebuffer();
} else {
// pretend we did the post
@@ -565,28 +507,18 @@ bool SurfaceFlinger::threadLoop()
void SurfaceFlinger::postFramebuffer()
{
- const bool skip = mOrientationAnimation->run();
- if (UNLIKELY(skip)) {
+ if (isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
return;
}
if (!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
hw.flip(mInvalidRegion);
-
mInvalidRegion.clear();
-
- if (Layer::deletedTextures.size()) {
- glDeleteTextures(
- Layer::deletedTextures.size(),
- Layer::deletedTextures.array());
- Layer::deletedTextures.clear();
- }
}
}
@@ -601,15 +533,13 @@ void SurfaceFlinger::handleConsoleEvents()
}
if (mDeferReleaseConsole && hw.canDraw()) {
- // We got the release signal before the aquire signal
+ // We got the release signal before the acquire signal
mDeferReleaseConsole = false;
- revokeGPU();
hw.releaseScreen();
}
if (what & eConsoleReleased) {
if (hw.canDraw()) {
- revokeGPU();
hw.releaseScreen();
} else {
mDeferReleaseConsole = true;
@@ -621,9 +551,25 @@ void SurfaceFlinger::handleConsoleEvents()
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
- Mutex::Autolock _l(mStateLock);
+ Vector< sp<LayerBase> > ditchedLayers;
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ }
+
+ // do this without lock held
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+}
+
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
/*
@@ -634,7 +580,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
if (layersNeedTransaction) {
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@@ -681,7 +627,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
mFreezeDisplayTime = 0;
- mOrientationAnimation->onOrientationChanged(type);
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
@@ -689,17 +634,24 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mFreezeDisplay = mCurrentState.freezeDisplay;
}
- // some layers might have been removed, so
- // we need to update the regions they're exposing.
- size_t c = mRemovedLayers.size();
- if (c) {
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
mVisibleRegionsDirty = true;
}
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
- if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
- // layers have been added
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ if (mLayersRemoved) {
mVisibleRegionsDirty = true;
+ const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+ const size_t count = previousLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(previousLayers[i]);
+ if (currentLayers.indexOf( layer ) < 0) {
+ // this layer is not visible anymore
+ ditchedLayers.add(layer);
+ }
+ }
}
// get rid of all resources we don't need anymore
@@ -729,7 +681,7 @@ void SurfaceFlinger::computeVisibleRegions(
size_t i = currentLayers.size();
while (i--) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
layer->validateVisibility(planeTransform);
// start with the whole surface at its current location
@@ -782,7 +734,7 @@ void SurfaceFlinger::computeVisibleRegions(
// accumulate to the screen dirty region
dirtyRegion.orSelf(dirty);
- // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+ // Update aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
aboveCoveredLayers.orSelf(visibleRegion);
@@ -790,7 +742,7 @@ void SurfaceFlinger::computeVisibleRegions(
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
- // If a secure layer is partially visible, lockdown the screen!
+ // If a secure layer is partially visible, lock down the screen!
if (layer->isSecure() && !visibleRegion.isEmpty()) {
secureFrameBuffer = true;
}
@@ -830,9 +782,9 @@ bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
{
bool recomputeVisibleRegions = false;
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->lockPageFlip(recomputeVisibleRegions);
}
return recomputeVisibleRegions;
@@ -843,37 +795,58 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
+
void SurfaceFlinger::handleRepaint()
{
- // set the frame buffer
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+ if (mInvalidRegion.isEmpty()) {
+ // nothing to do
+ return;
+ }
if (UNLIKELY(mDebugRegion)) {
debugFlashRegions();
}
- // compute the invalid region
- mInvalidRegion.orSelf(mDirtyRegion);
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
uint32_t flags = hw.getFlags();
- if (flags & DisplayHardware::BUFFER_PRESERVED) {
- // here we assume DisplayHardware::flip()'s implementation
- // performs the copy-back optimization.
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
+ {
+ // we can redraw only what's dirty, but since SWAP_RECTANGLE only
+ // takes a rectangle, we must make sure to update that whole
+ // rectangle in that case
+ if (flags & DisplayHardware::SWAP_RECTANGLE) {
+ // FIXME: we really should be able to pass a region to
+ // SWAP_RECTANGLE so that we don't have to redraw all this.
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // in the BUFFER_PRESERVED case, obviously, we can update only
+ // what's needed and nothing more.
+ // NOTE: this is NOT a common case, as preserving the backbuffer
+ // is costly and usually involves copying the whole update back.
+ }
} else {
if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
- // we need to fully redraw the part that will be updated
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because UPDATE_ON_DEMAND only takes one
+ // rectangle instead of a region (see DisplayHardware::flip())
mDirtyRegion.set(mInvalidRegion.bounds());
} else {
- // we need to redraw everything
+ // we need to redraw everything (the whole screen)
mDirtyRegion.set(hw.bounds());
mInvalidRegion = mDirtyRegion;
}
@@ -896,9 +869,9 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
const SurfaceFlinger& flinger(*this);
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase const* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase const * const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
const Region& visibleRegion(layer->visibleRegionScreen);
if (!visibleRegion.isEmpty()) {
const Region clip(dirty.intersect(visibleRegion));
@@ -913,14 +886,14 @@ void SurfaceFlinger::unlockClients()
{
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->finishPageFlip();
}
}
-void SurfaceFlinger::scheduleBroadcast(Client* client)
+void SurfaceFlinger::scheduleBroadcast(const sp<Client>& client)
{
if (mLastScheduledBroadcast != client) {
mLastScheduledBroadcast = client;
@@ -930,50 +903,56 @@ void SurfaceFlinger::scheduleBroadcast(Client* client)
void SurfaceFlinger::executeScheduledBroadcasts()
{
- SortedVector<Client*>& list = mScheduledBroadcasts;
+ SortedVector< wp<Client> >& list(mScheduledBroadcasts);
size_t count = list.size();
while (count--) {
- per_client_cblk_t* const cblk = list[count]->ctrlblk;
- if (cblk->lock.tryLock() == NO_ERROR) {
- cblk->cv.broadcast();
- list.removeAt(count);
- cblk->lock.unlock();
- } else {
- // schedule another round
- LOGW("executeScheduledBroadcasts() skipped, "
- "contention on the client. We'll try again later...");
- signalDelayedEvent(ms2ns(4));
+ sp<Client> client = list[count].promote();
+ if (client != 0) {
+ per_client_cblk_t* const cblk = client->ctrlblk;
+ if (cblk->lock.tryLock() == NO_ERROR) {
+ cblk->cv.broadcast();
+ list.removeAt(count);
+ cblk->lock.unlock();
+ } else {
+ // schedule another round
+ LOGW("executeScheduledBroadcasts() skipped, "
+ "contention on the client. We'll try again later...");
+ signalDelayedEvent(ms2ns(4));
+ }
}
}
mLastScheduledBroadcast = 0;
}
-void SurfaceFlinger::handleDebugCpu()
-{
- Mutex::Autolock _l(mDebugLock);
- if (mCpuGauge != 0)
- mCpuGauge->sample();
-}
-
void SurfaceFlinger::debugFlashRegions()
{
- if (UNLIKELY(!mDirtyRegion.isRect())) {
- // TODO: do this only if we don't have preserving
- // swapBuffer. If we don't have update-on-demand,
- // redraw everything.
- composeSurfaces(Region(mDirtyRegion.bounds()));
- }
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t flags = hw.getFlags();
+ if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))) {
+ const Region repaint((flags & DisplayHardware::UPDATE_ON_DEMAND) ?
+ mDirtyRegion.bounds() : hw.bounds());
+ composeSurfaces(repaint);
+ }
+
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
- glColor4x(0x10000, 0, 0x10000, 0x10000);
+ static int toggle = 0;
+ toggle = 1 - toggle;
+ if (toggle) {
+ glColor4x(0x10000, 0, 0x10000, 0x10000);
+ } else {
+ glColor4x(0x10000, 0x10000, 0, 0x10000);
+ }
- Rect r;
- Region::iterator iterator(mDirtyRegion);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = mDirtyRegion.begin();
+ Region::const_iterator const end = mDirtyRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
GLfloat vertices[][2] = {
{ r.left, r.top },
{ r.left, r.bottom },
@@ -983,10 +962,12 @@ void SurfaceFlinger::debugFlashRegions()
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- hw.flip(mDirtyRegion.merge(mInvalidRegion));
- mInvalidRegion.clear();
+
+ if (mInvalidRegion.isEmpty()) {
+ mDirtyRegion.dump("mDirtyRegion");
+ mInvalidRegion.dump("mInvalidRegion");
+ }
+ hw.flip(mInvalidRegion);
if (mDebugRegion > 1)
usleep(mDebugRegion * 1000);
@@ -1010,9 +991,10 @@ void SurfaceFlinger::drawWormhole() const
if (LIKELY(!mDebugBackground)) {
glClearColorx(0,0,0,0);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
@@ -1030,9 +1012,10 @@ void SurfaceFlinger::drawWormhole() const
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -1058,7 +1041,7 @@ void SurfaceFlinger::debugShowFPS() const
// XXX: mFPS has the value we want
}
-status_t SurfaceFlinger::addLayer(LayerBase* layer)
+status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
addLayer_l(layer);
@@ -1066,62 +1049,72 @@ status_t SurfaceFlinger::addLayer(LayerBase* layer)
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
- removeLayer_l(layer);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR)
+ setTransactionFlags(eTransactionNeeded);
+ return err;
}
-status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
{
layer->forceVisibilityTransaction();
setTransactionFlags(eTraversalNeeded);
return NO_ERROR;
}
-status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(
layer, &LayerBase::compareCurrentStateZ);
- LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
mLayerMap.add(lbc->serverIndex(), lbc);
}
- mRemovedLayers.remove(layer);
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
{
ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
if (index >= 0) {
- mRemovedLayers.add(layerBase);
- LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
- if (layer) {
+ mLayersRemoved = true;
+ sp<LayerBaseClient> layer =
+ LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get());
+ if (layer != 0) {
mLayerMap.removeItem(layer->serverIndex());
}
return NO_ERROR;
}
+ return status_t(index);
+}
+
+status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
+{
+ // remove the layer from the main list (through a transaction).
+ ssize_t err = removeLayer_l(layerBase);
+
// it's possible that we don't find a layer, because it might
// have been destroyed already -- this is not technically an error
- // from the user because there is a race between destroySurface,
- // destroyclient and destroySurface-from-a-transaction.
- return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+ // from the user because there is a race between BClient::destroySurface(),
+ // ~BClient() and ~ISurface().
+ return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
}
+
void SurfaceFlinger::free_resources_l()
{
// Destroy layers that were removed
- destroy_all_removed_layers_l();
-
+ mLayersRemoved = false;
+
// free resources associated with disconnected clients
- SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
- Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts);
+ Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
const size_t count = disconnectedClients.size();
for (size_t i=0 ; i<count ; i++) {
- Client* client = disconnectedClients[i];
+ sp<Client> client = disconnectedClients[i];
// if this client is the scheduled broadcast list,
// remove it from there (and we don't need to signal it
// since it is dead).
@@ -1130,27 +1123,10 @@ void SurfaceFlinger::free_resources_l()
scheduledBroadcasts.removeItemsAt(index);
}
mTokens.release(client->cid);
- delete client;
}
disconnectedClients.clear();
}
-void SurfaceFlinger::destroy_all_removed_layers_l()
-{
- size_t c = mRemovedLayers.size();
- while (c--) {
- LayerBase* const removed_layer = mRemovedLayers[c];
-
- LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
- "layer %p removed but still in the current state list",
- removed_layer);
-
- delete removed_layer;
- }
- mRemovedLayers.clear();
-}
-
-
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -1191,7 +1167,7 @@ status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1205,7 +1181,7 @@ status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1234,7 +1210,7 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
- LayerBaseClient* layer = 0;
+ sp<LayerBaseClient> layer;
sp<LayerBaseClient::Surface> surfaceHandle;
if (int32_t(w|h) < 0) {
@@ -1244,14 +1220,14 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
}
Mutex::Autolock _l(mStateLock);
- Client* const c = mClientsMap.valueFor(clientId);
- if (UNLIKELY(!c)) {
+ sp<Client> client = mClientsMap.valueFor(clientId);
+ if (UNLIKELY(client == 0)) {
LOGE("createSurface() failed, client not found (id=%d)", clientId);
return surfaceHandle;
}
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
- int32_t id = c->generateId(pid);
+ int32_t id = client->generateId(pid);
if (uint32_t(id) >= NUM_LAYERS_MAX) {
LOGE("createSurface() failed, generateId = %d", id);
return surfaceHandle;
@@ -1260,20 +1236,20 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+ layer = createPushBuffersSurfaceLocked(client, d, id, w, h, flags);
} else {
- layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+ layer = createNormalSurfaceLocked(client, d, id, w, h, format, flags);
}
break;
case eFXSurfaceBlur:
- layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+ layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
break;
case eFXSurfaceDim:
- layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+ layer = createDimSurfaceLocked(client, d, id, w, h, flags);
break;
}
- if (layer) {
+ if (layer != 0) {
setTransactionFlags(eTransactionNeeded);
surfaceHandle = layer->getSurface();
if (surfaceHandle != 0)
@@ -1283,8 +1259,8 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
return surfaceHandle;
}
-LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
{
// initialize the surfaces
@@ -1298,57 +1274,99 @@ LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
break;
}
- Layer* layer = new Layer(this, display, client, id);
- status_t err = layer->setBuffers(client, w, h, format, flags);
+ sp<Layer> layer = new Layer(this, display, client, id);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (LIKELY(err == NO_ERROR)) {
layer->initStates(w, h, flags);
addLayer_l(layer);
} else {
LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
- delete layer;
- return 0;
+ layer.clear();
}
return layer;
}
-LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBlur* layer = new LayerBlur(this, display, client, id);
+ sp<LayerBlur> layer = new LayerBlur(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerDim* layer = new LayerDim(this, display, client, id);
+ sp<LayerDim> layer = new LayerDim(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+ sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-status_t SurfaceFlinger::destroySurface(SurfaceID index)
+status_t SurfaceFlinger::removeSurface(SurfaceID index)
{
+ /*
+ * called by the window manager, when a surface should be marked for
+ * destruction.
+ *
+ * The surface is removed from the current and drawing lists, but placed
+ * in the purgatory queue, so it's not destroyed right-away (we need
+ * to wait for all client's references to go away first).
+ */
+
Mutex::Autolock _l(mStateLock);
- LayerBaseClient* const layer = getLayerUser_l(index);
- status_t err = removeLayer_l(layer);
- if (err < 0)
- return err;
- setTransactionFlags(eTransactionNeeded);
+ sp<LayerBaseClient> layer = getLayerUser_l(index);
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR) {
+ setTransactionFlags(eTransactionNeeded);
+ }
+ return err;
+}
+
+status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
+{
+ // called by ~ISurface() when all references are gone
+
+ class MessageDestroySurface : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<LayerBaseClient> layer;
+ public:
+ MessageDestroySurface(
+ SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
+ : flinger(flinger), layer(layer) { }
+ virtual bool handler() {
+ sp<LayerBaseClient> l(layer);
+ layer.clear(); // clear it outside of the lock;
+ Mutex::Autolock _l(flinger->mStateLock);
+ /*
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
+ * However, a buggy client could have not done that.
+ * Since we know we don't have any more clients, we don't need
+ * to use the purgatory.
+ */
+ status_t err = flinger->removeLayer_l(l);
+ LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ return true;
+ }
+ };
+
+ mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
return NO_ERROR;
}
@@ -1362,18 +1380,9 @@ status_t SurfaceFlinger::setClientState(
cid <<= 16;
for (int i=0 ; i<count ; i++) {
const layer_state_t& s = states[i];
- LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
- if (layer) {
+ sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid));
+ if (layer != 0) {
const uint32_t what = s.what;
- // check if it has been destroyed first
- if (what & eDestroyed) {
- if (removeLayer_l(layer) == NO_ERROR) {
- flags |= eTransactionNeeded;
- // we skip everything else... well, no, not really
- // we skip ONLY that transaction.
- continue;
- }
- }
if (what & ePositionChanged) {
if (layer->setPosition(s.x, s.y))
flags |= eTraversalNeeded;
@@ -1415,9 +1424,10 @@ status_t SurfaceFlinger::setClientState(
return NO_ERROR;
}
-LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+sp<LayerBaseClient> SurfaceFlinger::getLayerUser_l(SurfaceID s) const
{
- return mLayerMap.valueFor(s);
+ sp<LayerBaseClient> layer = mLayerMap.valueFor(s);
+ return layer;
}
void SurfaceFlinger::screenReleased(int dpy)
@@ -1439,9 +1449,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
const size_t SIZE = 1024;
char buffer[SIZE];
String8 result;
- if (checkCallingPermission(
- String16("android.permission.DUMP")) == false)
- { // not allowed
+ if (!mDump.checkCalling()) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump SurfaceFlinger from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
@@ -1452,7 +1460,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
size_t s = mClientsMap.size();
char name[64];
for (size_t i=0 ; i<s ; i++) {
- Client* client = mClientsMap.valueAt(i);
+ sp<Client> client = mClientsMap.valueAt(i);
sprintf(name, " Client (id=0x%08x)", client->cid);
client->dump(name);
}
@@ -1460,7 +1468,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
/*** LayerBase ***/
- LayerBase const * const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
const Layer::State& s = layer->drawingState();
snprintf(buffer, SIZE,
"+ %s %p\n"
@@ -1468,7 +1476,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
"needsBlending=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- layer->getTypeID(), layer,
+ layer->getTypeID(), layer.get(),
s.z, layer->tx(), layer->ty(), s.w, s.h,
layer->needsBlending(), layer->contentDirty,
s.alpha, s.flags,
@@ -1477,30 +1485,33 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
result.append(buffer);
buffer[0] = 0;
/*** LayerBaseClient ***/
- LayerBaseClient* const lbc =
- LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc =
+ LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
+ sp<Client> client(lbc->client.promote());
snprintf(buffer, SIZE,
" "
"id=0x%08x, client=0x%08x, identity=%u\n",
- lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+ lbc->clientIndex(), client.get() ? client->cid : 0,
lbc->getIdentity());
}
result.append(buffer);
buffer[0] = 0;
/*** Layer ***/
- Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
- if (l) {
+ sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
+ if (l != 0) {
const LayerBitmap& buf0(l->getBuffer(0));
const LayerBitmap& buf1(l->getBuffer(1));
snprintf(buffer, SIZE,
" "
- "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
" freezeLock=%p, swapState=0x%08x\n",
l->pixelFormat(),
- buf0.width(), buf0.height(), buf0.stride(),
- buf1.width(), buf1.height(), buf1.stride(),
- l->getTextureName(), l->getFreezeLock().get(),
+ buf0.getWidth(), buf0.getHeight(),
+ buf0.getBuffer()->getStride(),
+ buf1.getWidth(), buf1.getHeight(),
+ buf1.getBuffer()->getStride(),
+ l->getFreezeLock().get(),
l->lcblk->swapState);
}
result.append(buffer);
@@ -1516,20 +1527,10 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
mFreezeDisplay?"yes":"no", mFreezeCount,
mCurrentState.orientation, hw.canDraw());
result.append(buffer);
-
- sp<AllocatorInterface> allocator;
- if (mGPU != 0) {
- snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
- result.append(buffer);
- allocator = mGPU->getAllocator();
- if (allocator != 0) {
- allocator->dump(result, "GPU Allocator");
- }
- }
- allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
- if (allocator != 0) {
- allocator->dump(result, "PMEM Allocator");
- }
+ snprintf(buffer, SIZE, " client count: %d\n", mClientsMap.size());
+ result.append(buffer);
+ const BufferAllocator& alloc(BufferAllocator::get());
+ alloc.dump(result);
}
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -1546,57 +1547,34 @@ status_t SurfaceFlinger::onTransact(
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
- case REVOKE_GPU:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
+ if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
}
}
}
-
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ if (UNLIKELY(!mHardwareTest.checkCalling())) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
int n;
switch (code) {
- case 1000: // SHOW_CPU
- n = data.readInt32();
- mDebugCpu = n ? 1 : 0;
- if (mDebugCpu) {
- if (mCpuGauge == 0) {
- mCpuGauge = new CPUGauge(this, ms2ns(500));
- }
- } else {
- if (mCpuGauge != 0) {
- mCpuGauge->requestExitAndWait();
- Mutex::Autolock _l(mDebugLock);
- mCpuGauge.clear();
- }
- }
+ case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
return NO_ERROR;
- case 1001: // SHOW_FPS
- n = data.readInt32();
- mDebugFps = n ? 1 : 0;
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
return NO_ERROR;
case 1002: // SHOW_UPDATES
n = data.readInt32();
@@ -1613,21 +1591,11 @@ status_t SurfaceFlinger::onTransact(
signalEvent();
}
return NO_ERROR;
- case 1005: // ask GPU revoke
- if (mGPU != 0) {
- mGPU->friendlyRevoke();
- }
- return NO_ERROR;
- case 1006: // revoke GPU
- if (mGPU != 0) {
- mGPU->unconditionalRevoke();
- }
- return NO_ERROR;
case 1007: // set mFreezeCount
mFreezeCount = data.readInt32();
return NO_ERROR;
case 1010: // interrogate.
- reply->writeInt32(mDebugCpu);
+ reply->writeInt32(0);
reply->writeInt32(0);
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
@@ -1651,16 +1619,15 @@ status_t SurfaceFlinger::onTransact(
Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
{
- mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
const int pgsize = getpagesize();
- const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
- mCblkHeap = new MemoryDealer(cblksize);
- mCblkMemory = mCblkHeap->allocate(cblksize);
- if (mCblkMemory != 0) {
- ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
- if (ctrlblk) { // construct the shared structure in-place.
- new(ctrlblk) per_client_cblk_t;
- }
+ const int cblksize = ((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+
+ mCblkHeap = new MemoryHeapBase(cblksize, 0,
+ "SurfaceFlinger Client control-block");
+
+ ctrlblk = static_cast<per_client_cblk_t *>(mCblkHeap->getBase());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) per_client_cblk_t;
}
}
@@ -1671,10 +1638,6 @@ Client::~Client() {
}
}
-const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
- return mFlinger->getSurfaceHeapManager();
-}
-
int32_t Client::generateId(int pid)
{
const uint32_t i = clz( ~mBitmap );
@@ -1686,13 +1649,15 @@ int32_t Client::generateId(int pid)
mBitmap |= 1<<(31-i);
return i;
}
-status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+
+status_t Client::bindLayer(const sp<LayerBaseClient>& layer, int32_t id)
{
ssize_t idx = mInUse.indexOf(id);
if (idx < 0)
return NAME_NOT_FOUND;
return mLayers.insertAt(layer, idx);
}
+
void Client::free(int32_t id)
{
ssize_t idx = mInUse.remove(uint8_t(id));
@@ -1702,27 +1667,18 @@ void Client::free(int32_t id)
}
}
-sp<MemoryDealer> Client::createAllocator(uint32_t flags)
-{
- sp<MemoryDealer> allocator;
- allocator = getSurfaceHeapManager()->createHeap(
- flags, getClientPid(), mSharedHeapAllocator);
- return allocator;
-}
-
bool Client::isValid(int32_t i) const {
return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
}
-const uint8_t* Client::inUseArray() const {
- return mInUse.array();
-}
-size_t Client::numActiveLayers() const {
- return mInUse.size();
-}
-LayerBaseClient* Client::getLayerUser(int32_t i) const {
+
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+ sp<LayerBaseClient> lbc;
ssize_t idx = mInUse.indexOf(uint8_t(i));
- if (idx<0) return 0;
- return mLayers[idx];
+ if (idx >= 0) {
+ lbc = mLayers[idx].promote();
+ LOGE_IF(lbc==0, "getLayerUser(i=%d), idx=%d is dead", int(i), int(idx));
+ }
+ return lbc;
}
void Client::dump(const char* what)
@@ -1734,7 +1690,7 @@ void Client::dump(const char* what)
#pragma mark -
#endif
-BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk)
: mId(cid), mFlinger(flinger), mCblk(cblk)
{
}
@@ -1744,8 +1700,8 @@ BClient::~BClient() {
mFlinger->destroyConnection(mId);
}
-void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
- *ctrl = mCblk;
+sp<IMemoryHeap> BClient::getControlBlock() const {
+ return mCblk;
}
sp<ISurface> BClient::createSurface(
@@ -1759,7 +1715,7 @@ sp<ISurface> BClient::createSurface(
status_t BClient::destroySurface(SurfaceID sid)
{
sid |= (mId << 16); // add the client-part to id
- return mFlinger->destroySurface(sid);
+ return mFlinger->removeSurface(sid);
}
status_t BClient::setState(int32_t count, const layer_state_t* states)
@@ -1859,6 +1815,10 @@ const Transform& GraphicPlane::transform() const {
return mGlobalTransform;
}
+EGLDisplay GraphicPlane::getEGLDisplay() const {
+ return mHw->getEGLDisplay();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 15913f2..e8687a7 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -25,7 +25,10 @@
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
-#include <utils/MemoryDealer.h>
+#include <utils/RefBase.h>
+
+#include <binder/IMemory.h>
+#include <binder/Permission.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceComposer.h>
@@ -33,13 +36,13 @@
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
-#include <private/ui/SurfaceFlingerSynchro.h>
#include "Barrier.h"
-#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
+#include "MessageQueue.h"
+
struct copybit_device_t;
struct overlay_device_t;
@@ -51,13 +54,8 @@ class Client;
class BClient;
class DisplayHardware;
class FreezeLock;
-class GPUHardwareInterface;
-class IGPUCallback;
class Layer;
class LayerBuffer;
-class LayerOrientationAnim;
-class OrientationAnimation;
-class SurfaceHeapManager;
typedef int32_t ClientID;
@@ -66,7 +64,7 @@ typedef int32_t ClientID;
// ---------------------------------------------------------------------------
-class Client
+class Client : public RefBase
{
public:
Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
@@ -74,17 +72,19 @@ public:
int32_t generateId(int pid);
void free(int32_t id);
- status_t bindLayer(LayerBaseClient* layer, int32_t id);
- sp<MemoryDealer> createAllocator(uint32_t memory_type);
+ status_t bindLayer(const sp<LayerBaseClient>& layer, int32_t id);
inline bool isValid(int32_t i) const;
- inline const uint8_t* inUseArray() const;
- inline size_t numActiveLayers() const;
- LayerBaseClient* getLayerUser(int32_t i) const;
- const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
- const sp<IMemory>& controlBlockMemory() const { return mCblkMemory; }
+ sp<LayerBaseClient> getLayerUser(int32_t i) const;
void dump(const char* what);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const;
+
+ const Vector< wp<LayerBaseClient> >& getLayers() const {
+ return mLayers;
+ }
+
+ const sp<IMemoryHeap>& getControlBlockMemory() const {
+ return mCblkHeap;
+ }
// pointer to this client's control block
per_client_cblk_t* ctrlblk;
@@ -92,17 +92,14 @@ public:
private:
- int getClientPid() const { return mPid; }
+ int getClientPid() const { return mPid; }
- int mPid;
- uint32_t mBitmap;
- SortedVector<uint8_t> mInUse;
- Vector<LayerBaseClient*> mLayers;
- sp<MemoryDealer> mCblkHeap;
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mSharedHeapAllocator;
- sp<MemoryDealer> mPMemAllocator;
- sp<IMemory> mCblkMemory;
+ int mPid;
+ uint32_t mBitmap;
+ SortedVector<uint8_t> mInUse;
+ Vector< wp<LayerBaseClient> > mLayers;
+ sp<IMemoryHeap> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
};
// ---------------------------------------------------------------------------
@@ -125,6 +122,8 @@ public:
const DisplayHardware& displayHardware() const;
const Transform& transform() const;
+ EGLDisplay getEGLDisplay() const;
+
private:
GraphicPlane(const GraphicPlane&);
GraphicPlane operator = (const GraphicPlane&);
@@ -160,7 +159,7 @@ public:
// ISurfaceComposer interface
virtual sp<ISurfaceFlingerClient> createConnection();
- virtual sp<IMemory> getCblk() const;
+ virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
virtual void openGlobalTransaction();
virtual void closeGlobalTransaction();
@@ -168,56 +167,52 @@ public:
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
- virtual status_t requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu);
- virtual status_t revokeGPU();
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const {
- return mSurfaceHeapManager;
- }
-
- const sp<GPUHardwareInterface>& getGPU() const {
- return mGPU;
- }
-
- copybit_device_t* getBlitEngine() const;
overlay_control_device_t* getOverlayEngine() const;
- status_t removeLayer(LayerBase* layer);
- status_t addLayer(LayerBase* layer);
- status_t invalidateLayerVisibility(LayerBase* layer);
+ status_t removeLayer(const sp<LayerBase>& layer);
+ status_t addLayer(const sp<LayerBase>& layer);
+ status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
private:
friend class BClient;
friend class LayerBase;
friend class LayerBuffer;
friend class LayerBaseClient;
+ friend class LayerBaseClient::Surface;
friend class Layer;
friend class LayerBlur;
+ friend class LayerDim;
sp<ISurface> createSurface(ClientID client, int pid,
ISurfaceFlingerClient::surface_data_t* params,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags);
- LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ sp<LayerBaseClient> createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags);
- LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- status_t destroySurface(SurfaceID surface_id);
- status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+ status_t removeSurface(SurfaceID surface_id);
+ status_t destroySurface(const sp<LayerBaseClient>& layer);
+ status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
class LayerVector {
@@ -225,15 +220,15 @@ private:
inline LayerVector() { }
LayerVector(const LayerVector&);
inline size_t size() const { return layers.size(); }
- inline LayerBase*const* array() const { return layers.array(); }
- ssize_t add(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t remove(LayerBase*);
- ssize_t reorder(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t indexOf(LayerBase* key, size_t guess=0) const;
- inline LayerBase* operator [] (size_t i) const { return layers[i]; }
+ inline sp<LayerBase> const* array() const { return layers.array(); }
+ ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t remove(const sp<LayerBase>&);
+ ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const;
+ inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
private:
- KeyedVector<LayerBase*, size_t> lookup;
- Vector<LayerBase*> layers;
+ KeyedVector< sp<LayerBase> , size_t> lookup;
+ Vector< sp<LayerBase> > layers;
};
struct State {
@@ -247,25 +242,6 @@ private:
uint8_t freezeDisplay;
};
- class DelayedTransaction : public Thread
- {
- friend class SurfaceFlinger;
- sp<SurfaceFlinger> mFlinger;
- nsecs_t mDelay;
- public:
- DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
- : Thread(false), mFlinger(flinger), mDelay(delay) {
- }
- virtual bool threadLoop() {
- usleep(mDelay / 1000);
- if (android_atomic_and(~1,
- &mFlinger->mDeplayedTransactionPending) == 1) {
- mFlinger->signalEvent();
- }
- return false;
- }
- };
-
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
@@ -279,6 +255,9 @@ private:
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(
+ uint32_t transactionFlags,
+ Vector< sp<LayerBase> >& ditchedLayers);
void computeVisibleRegions(
LayerVector& currentLayers,
@@ -289,8 +268,7 @@ private:
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRepaint();
- void handleDebugCpu();
- void scheduleBroadcast(Client* client);
+ void scheduleBroadcast(const sp<Client>& client);
void executeScheduledBroadcasts();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
@@ -298,10 +276,10 @@ private:
void destroyConnection(ClientID cid);
- LayerBaseClient* getLayerUser_l(SurfaceID index) const;
- status_t addLayer_l(LayerBase* layer);
- status_t removeLayer_l(LayerBase* layer);
- void destroy_all_removed_layers_l();
+ sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const;
+ status_t addLayer_l(const sp<LayerBase>& layer);
+ 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);
@@ -323,6 +301,11 @@ private:
void debugShowFPS() const;
void drawWormhole() const;
+
+ mutable MessageQueue mEventQueue;
+
+
+
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState;
@@ -330,53 +313,43 @@ private:
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
-
+
// protected by mStateLock (but we could use another lock)
Tokenizer mTokens;
- DefaultKeyedVector<ClientID, Client*> mClientsMap;
- DefaultKeyedVector<SurfaceID, LayerBaseClient*> mLayerMap;
+ DefaultKeyedVector<ClientID, sp<Client> > mClientsMap;
+ DefaultKeyedVector<SurfaceID, sp<LayerBaseClient> > mLayerMap;
GraphicPlane mGraphicPlanes[1];
- SortedVector<LayerBase*> mRemovedLayers;
- Vector<Client*> mDisconnectedClients;
+ bool mLayersRemoved;
+ Vector< sp<Client> > mDisconnectedClients;
// constant members (no synchronization needed for access)
- sp<MemoryDealer> mServerHeap;
- sp<IMemory> mServerCblkMemory;
+ sp<IMemoryHeap> mServerHeap;
surface_flinger_cblk_t* mServerCblk;
- sp<SurfaceHeapManager> mSurfaceHeapManager;
- sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
nsecs_t mBootTime;
+ Permission mHardwareTest;
+ Permission mAccessSurfaceFlinger;
+ Permission mDump;
// Can only accessed from the main thread, these members
// don't need synchronization
Region mDirtyRegion;
Region mInvalidRegion;
Region mWormholeRegion;
- Client* mLastScheduledBroadcast;
- SortedVector<Client*> mScheduledBroadcasts;
+ wp<Client> mLastScheduledBroadcast;
+ SortedVector< wp<Client> > mScheduledBroadcasts;
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
- friend class OrientationAnimation;
- OrientationAnimation* mOrientationAnimation;
-
- // access protected by mDebugLock
- mutable Mutex mDebugLock;
- sp<CPUGauge> mCpuGauge;
// don't use a lock for these, we don't care
int mDebugRegion;
- int mDebugCpu;
- int mDebugFps;
int mDebugBackground;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
- mutable SurfaceFlingerSynchro mSyncObject;
- volatile int32_t mDeplayedTransactionPending;
// atomic variables
enum {
@@ -409,11 +382,11 @@ class BClient : public BnSurfaceFlingerClient
{
public:
BClient(SurfaceFlinger *flinger, ClientID cid,
- const sp<IMemory>& cblk);
+ const sp<IMemoryHeap>& cblk);
~BClient();
// ISurfaceFlingerClient interface
- virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+ virtual sp<IMemoryHeap> getControlBlock() const;
virtual sp<ISurface> createSurface(
surface_data_t* params, int pid,
@@ -426,7 +399,7 @@ public:
private:
ClientID mId;
SurfaceFlinger* mFlinger;
- sp<IMemory> mCblk;
+ sp<IMemoryHeap> mCblk;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
index ef51d6a..be3a239 100644
--- a/libs/surfaceflinger/Tokenizer.cpp
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -162,9 +162,10 @@ void Tokenizer::dump() const
{
const run_t* ranges = mRanges.array();
const size_t c = mRanges.size();
- printf("Tokenizer (%p, size = %lu)\n", this, c);
+ printf("Tokenizer (%p, size = %d)\n", this, int(c));
for (size_t i=0 ; i<c ; i++) {
- printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ printf("%u: (%u, %u)\n", i,
+ uint32_t(ranges[i].first), uint32_t(ranges[i].length));
}
}
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index e8b0f45..1501536 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -177,10 +177,10 @@ Region Transform::transform(const Region& reg) const
Region out;
if (UNLIKELY(transformed())) {
if (LIKELY(preserveRects())) {
- Rect r;
- Region::iterator iterator(reg);
- while (iterator.iterate(&r)) {
- out.orSelf(transform(r));
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ while (it != end) {
+ out.orSelf(transform(*it++));
}
} else {
out.set(transform(reg.bounds()));
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
index 7168bf2..2de628b 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
@@ -30,12 +30,12 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IBinder.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IBinder.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IPCThreadState.h>
#include <utils/StopWatch.h>
#include <ui/ISurfaceComposer.h>
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
index 3354528..3354528 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.h
+++ b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..41c42d1
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include "BlurFilter.h"
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+// Animation...
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.5f;
+//const float BOUNCES_AMPLITUDE = 1.0f/16.0f;
+const float BOUNCES_AMPLITUDE = 0;
+const float DIM_TARGET = 0.40f;
+//#define INTERPOLATED_TIME(_t) ((_t)*(_t))
+#define INTERPOLATED_TIME(_t) (_t)
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ // blur that texture.
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mNeedsBlending = false;
+ mAlphaInLerp.set(1.0f, DIM_TARGET);
+ mAlphaOutLerp.set(0.5f, 1.0f);
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ const nsecs_t now = systemTime();
+ float alphaIn, alphaOut;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapOut->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp(interpolatedTime);
+ } else {
+ mAnim->onAnimationFinished();
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp.getOut();
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp(interpolatedTime);
+ alphaOut = 0.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ alphaIn = mAlphaInLerp.getOut();
+ if (BOUNCES_AMPLITUDE > 0.0f) {
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ if (alphaIn > 1.0f) alphaIn = 1.0f;
+ else if (alphaIn < 0.0f) alphaIn = 0.0f;
+ alphaIn += BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ }
+ alphaOut = 0.0f;
+ }
+ mAlphaOutLerp.setIn(alphaIn);
+ }
+ drawScaled(1.0f, alphaIn, alphaOut);
+}
+
+void LayerOrientationAnim::drawScaled(float scale, float alphaIn, float alphaOut) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ if (scale==1.0f && (alphaIn>=1.0f || alphaOut>=1.0f)) {
+ // we don't need to erase the screen in that case
+ } else {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+
+ copybit_image_t srcOut;
+ mBitmapOut->getBitmapSurface(&srcOut);
+
+ const int w = dst.w*scale;
+ const int h = dst.h*scale;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+ const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(scale,0,0,scale);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alphaIn > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaIn*255);
+ drawWithOpenGL(reg, mTextureNameIn, t);
+ }
+
+ if (alphaOut > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(srcOut.base) + srcOut.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaOut*255);
+ drawWithOpenGL(reg, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.h b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
new file mode 100644
index 0000000..a1a2654
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <binder/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+
+class LayerOrientationAnimBase : public LayerBase
+{
+public:
+ LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
+ : LayerBase(flinger, display) {
+ }
+ virtual void onOrientationCompleted() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class LayerOrientationAnim : public LayerOrientationAnimBase
+{
+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; }
+
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float scale, float alphaIn, float alphaOut) const;
+
+ class Lerp {
+ float in;
+ float outMinusIn;
+ public:
+ Lerp() : in(0), outMinusIn(0) { }
+ Lerp(float in, float out) : in(in), outMinusIn(out-in) { }
+ float getIn() const { return in; };
+ float getOut() const { return in + outMinusIn; }
+ void set(float in, float out) {
+ this->in = in;
+ this->outMinusIn = out-in;
+ }
+ void setIn(float in) {
+ this->in = in;
+ }
+ void setOut(float out) {
+ this->outMinusIn = out - this->in;
+ }
+ float operator()(float t) const {
+ return outMinusIn*t + in;
+ }
+ };
+
+ OrientationAnimation* mAnim;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+
+ mutable Lerp mAlphaInLerp;
+ mutable Lerp mAlphaOutLerp;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
new file mode 100644
index 0000000..dc6b632
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
+const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
+
+// ---------------------------------------------------------------------------
+
+const float ROTATION = M_PI * 0.5f;
+const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.8;
+const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
+
+LayerOrientationAnimRotate::LayerOrientationAnimRotate(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastAngle = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+ const GraphicPlane& plane(graphicPlane(0));
+ mOriginalTargetOrientation = plane.getOrientation();
+}
+
+LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnimRotate::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnimRotate::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnimRotate::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnimRotate::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnimRotate::onDraw(const Region& clip) const
+{
+ // Animation...
+
+ const nsecs_t now = systemTime();
+ float angle, scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // FIXME: code below is gross
+ mFirstRedraw = false;
+ mNeedsBlending = false;
+ LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = normalizedTime;
+ } else {
+ mAnim->onAnimationFinished();
+ angle = ROTATION;
+ alpha = 1.0f;
+ scale = 1.0f;
+ }
+ } else {
+ // FIXME: works only for portrait framebuffers
+ const Point size(getPhysicalSize());
+ const float TARGET_SCALE = size.x * (1.0f / size.y);
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = ROTATION * squaredTime;
+ scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
+ alpha = 0;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ angle = ROTATION;
+ if (BOUNCES_AMPLITUDE) {
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ angle += BOUNCES_AMPLITUDE * sinf(phi);
+ }
+ scale = TARGET_SCALE;
+ alpha = 0;
+ }
+ mLastAngle = angle;
+ mLastScale = scale;
+ }
+ drawScaled(angle, scale, alpha);
+}
+
+void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ const int w = dst.w;
+ const int h = dst.h;
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ if (!mOriginalTargetOrientation) {
+ f = -f;
+ }
+
+ Transform tr;
+ tr.set(f, w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = 255; //-int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+
+ if (alpha > 0) {
+ const float sign = (!mOriginalTargetOrientation) ? 1.0f : -1.0f;
+ tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureNameIn, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
index 12b6f1c..a88eec0 100644
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
-#define ANDROID_LAYER_ORIENTATION_ANIM_H
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -30,19 +30,7 @@ namespace android {
// ---------------------------------------------------------------------------
class OrientationAnimation;
-
-class LayerOrientationAnimBase : public LayerBase
-{
-public:
- LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
- : LayerBase(flinger, display) {
- }
- virtual void onOrientationCompleted() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class LayerOrientationAnim : public LayerOrientationAnimBase
+class LayerOrientationAnimRotate : public LayerOrientationAnimBase
{
public:
static const uint32_t typeInfo;
@@ -50,11 +38,11 @@ public:
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
- LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ LayerOrientationAnimRotate(SurfaceFlinger* flinger, DisplayID display,
OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut);
- virtual ~LayerOrientationAnim();
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnimRotate();
void onOrientationCompleted();
@@ -64,10 +52,19 @@ public:
virtual bool needsBlending() const;
virtual bool isSecure() const { return false; }
private:
+ void drawScaled(float angle, float scale, float alpha) const;
+
OrientationAnimation* mAnim;
- LayerBitmap mBitmapIn;
- LayerBitmap mBitmapOut;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
bool mOrientationCompleted;
+ int mOriginalTargetOrientation;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastAngle;
+ mutable float mLastScale;
mutable GLuint mTextureName;
mutable GLuint mTextureNameIn;
mutable bool mNeedsBlending;
@@ -77,4 +74,4 @@ private:
}; // namespace android
-#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
index 12c0eef..a6c9c28 100644
--- a/libs/surfaceflinger/OrientationAnimation.cpp
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
@@ -14,16 +14,14 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdint.h>
#include <sys/types.h>
#include <limits.h>
#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
@@ -34,9 +32,6 @@ namespace android {
OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
{
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
- ISurfaceComposer::eHardware);
}
OrientationAnimation::~OrientationAnimation()
@@ -97,22 +92,22 @@ bool OrientationAnimation::prepare()
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
- LayerBitmap bitmap;
- bitmap.init(mTemporaryDealer);
- bitmap.setBits(w, h, 1, hw.getFormat());
-
- LayerBitmap bitmapIn;
- bitmapIn.init(mTemporaryDealer);
- bitmapIn.setBits(w, h, 1, hw.getFormat());
+ sp<Buffer> bitmap = new Buffer(w, h, hw.getFormat());
+ sp<Buffer> bitmapIn = new Buffer(w, h, hw.getFormat());
copybit_image_t front;
- bitmap.getBitmapSurface(&front);
- hw.copyFrontToImage(front);
+ bitmap->getBitmapSurface(&front);
+ hw.copyFrontToImage(front); // FIXME: we need an extension to do this
- LayerOrientationAnimBase* l;
+ sp<LayerOrientationAnimBase> l;
- l = new LayerOrientationAnim(
- mFlinger.get(), 0, this, bitmap, bitmapIn);
+ if (mType & 0x80) {
+ l = new LayerOrientationAnimRotate(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ } else {
+ l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ }
l->initStates(w, h, 0);
l->setLayer(INT_MAX-1);
@@ -131,7 +126,7 @@ bool OrientationAnimation::phase1()
return true;
}
- //mLayerOrientationAnim->invalidate();
+ mLayerOrientationAnim->invalidate();
return false;
}
@@ -146,7 +141,7 @@ bool OrientationAnimation::finished()
{
mState = DONE;
mFlinger->removeLayer(mLayerOrientationAnim);
- mLayerOrientationAnim = NULL;
+ mLayerOrientationAnim.clear();
return true;
}
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/purgatory/OrientationAnimation.h
index cafa38d..8ba6621 100644
--- a/libs/surfaceflinger/OrientationAnimation.h
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.h
@@ -72,8 +72,7 @@ private:
bool finished();
sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mTemporaryDealer;
- LayerOrientationAnimBase* mLayerOrientationAnim;
+ sp< LayerOrientationAnimBase > mLayerOrientationAnim;
int mState;
uint32_t mType;
};
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/purgatory/VRamHeap.cpp
index 5f633bd..f3ed790 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/purgatory/VRamHeap.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
@@ -35,8 +33,6 @@
#include <utils/MemoryHeapPmem.h>
#include <utils/MemoryHeapBase.h>
-#include <EGL/eglnatives.h>
-
#include "GPUHardware/GPUHardware.h"
#include "SurfaceFlinger.h"
#include "VRamHeap.h"
@@ -100,7 +96,7 @@ sp<MemoryDealer> SurfaceHeapManager::createHeap(
}
}
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
+ if (flags & ISurfaceComposer::eGPU) {
// FIXME: this is msm7201A specific, where gpu surfaces may not be secure
if (!(flags & ISurfaceComposer::eSecure)) {
// if GPU doesn't work, we try eHardware
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/purgatory/VRamHeap.h
index 9140167..9140167 100644
--- a/libs/surfaceflinger/VRamHeap.h
+++ b/libs/surfaceflinger/purgatory/VRamHeap.h
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp
index f3c046f..0b9322e 100644
--- a/libs/surfaceflinger/tests/overlays/overlays.cpp
+++ b/libs/surfaceflinger/tests/overlays/overlays.cpp
@@ -1,6 +1,6 @@
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <ui/Surface.h>
diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/libs/surfaceflinger/tests/resize/Android.mk
new file mode 100644
index 0000000..ef1532f
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ resize.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-resize
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/libs/surfaceflinger/tests/resize/resize.cpp
new file mode 100644
index 0000000..21c6ab6
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/resize.cpp
@@ -0,0 +1,60 @@
+#include <cutils/memory.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Surface.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+#include <ui/SurfaceComposerClient.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+ static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+ return s->getISurface();
+ }
+};
+};
+
+int main(int argc, char** argv)
+{
+ // set up the thread-pool
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ // create a client to surfaceflinger
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+
+ // create pushbuffer surface
+ sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240,
+ PIXEL_FORMAT_RGB_565);
+
+
+ client->openTransaction();
+ surface->setLayer(100000);
+ client->closeTransaction();
+
+ Surface::SurfaceInfo info;
+ surface->lock(&info);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ android_memset16((uint16_t*)info.bits, 0xF800, bpr*info.h);
+ surface->unlockAndPost();
+
+ surface->lock(&info);
+ android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
+ surface->unlockAndPost();
+
+ client->openTransaction();
+ surface->setSize(320, 240);
+ client->closeTransaction();
+
+
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 7bbe38b..49939ca 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -2,12 +2,12 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ BufferMapper.cpp \
Camera.cpp \
CameraParameters.cpp \
- EGLDisplaySurface.cpp \
- EGLNativeWindowSurface.cpp \
EventHub.cpp \
EventRecurrence.cpp \
+ FramebufferNativeWindow.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
ICamera.cpp \
@@ -27,9 +27,9 @@ LOCAL_SRC_FILES:= \
SurfaceFlingerSynchro.cpp
LOCAL_SHARED_LIBRARIES := \
- libcorecg \
libcutils \
libutils \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
diff --git a/libs/ui/BufferMapper.cpp b/libs/ui/BufferMapper.cpp
new file mode 100644
index 0000000..92a9a86
--- /dev/null
+++ b/libs/ui/BufferMapper.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BufferMapper"
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/BufferMapper.h>
+#include <ui/Rect.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferMapper )
+
+BufferMapper::BufferMapper()
+ : mAllocMod(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ mAllocMod = (gralloc_module_t const *)module;
+ }
+}
+
+status_t BufferMapper::registerBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->registerBuffer(mAllocMod, handle);
+ LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unregisterBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr)
+{
+ status_t err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr);
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unlock(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unlock(mAllocMod, handle);
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 5015379..12a7725 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -19,9 +19,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <ui/Camera.h>
#include <ui/ICameraService.h>
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
deleted file mode 100644
index d06c98b..0000000
--- a/libs/ui/EGLDisplaySurface.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- **
- ** Copyright 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.
- */
-
-#define LOG_TAG "EGLDisplaySurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <hardware/copybit.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/EGLDisplaySurface.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/msm_mdp.h>
-#endif
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-
-// ----------------------------------------------------------------------------
-
-egl_native_window_t* android_createDisplaySurface()
-{
- egl_native_window_t* s = new android::EGLDisplaySurface();
- s->memory_type = NATIVE_MEMORY_TYPE_GPU;
- return s;
-}
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLDisplaySurface::EGLDisplaySurface()
- : EGLNativeSurface<EGLDisplaySurface>()
-{
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
- egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::connect = 0;
- egl_native_window_t::disconnect = 0;
-
- mFb[0].data = 0;
- mFb[1].data = 0;
- mBlitEngine = 0;
- egl_native_window_t::fd = mapFrameBuffer();
- if (egl_native_window_t::fd >= 0) {
-
- hw_module_t const* module;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- const float in2mm = 25.4f;
- float refreshRate = 1000000000000000LLU / (
- float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
- * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
- * mInfo.pixclock);
-
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::width = buffer.width;
- egl_native_window_t::height = buffer.height;
- egl_native_window_t::stride = buffer.stride;
- egl_native_window_t::format = buffer.format;
- egl_native_window_t::base = intptr_t(mFb[0].data);
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- egl_native_window_t::flags = 0;
- egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
- egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
- egl_native_window_t::fps = refreshRate;
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
- // no error, set the magic word
- egl_native_window_t::magic = 0x600913;
- }
- mSwapCount = -1;
- mPageFlipCount = 0;
-}
-
-EGLDisplaySurface::~EGLDisplaySurface()
-{
- magic = 0;
- copybit_close(mBlitEngine);
- mBlitEngine = 0;
- close(egl_native_window_t::fd);
- munmap(mFb[0].data, mSize);
- if (!(mFlags & PAGE_FLIP))
- free((void*)mFb[1].data);
-}
-
-void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->incStrong(that);
-}
-void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->decStrong(that);
-}
-uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mInfo.reserved[0] = 0x54445055; // "UPDT";
- mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
- mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-}
-
-uint32_t EGLDisplaySurface::swapBuffers()
-{
-#define SHOW_FPS 0
-#if SHOW_FPS
- nsecs_t now = systemTime();
- if (mSwapCount == -1) {
- mTime = now;
- mSwapCount = 0;
- mSleep = 0;
- } else {
- nsecs_t d = now-mTime;
- if (d >= seconds(1)) {
- double fps = (mSwapCount * double(seconds(1))) / double(d);
- LOGD("%f fps, sleep=%d / frame",
- fps, (int)ns2us(mSleep / mSwapCount));
- mSwapCount = 0;
- mTime = now;
- mSleep = 0;
- } else {
- mSwapCount++;
- }
- }
-#endif
- /* If we can't do the page_flip, just copy the back buffer to the front */
- if (!(mFlags & PAGE_FLIP)) {
- memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
- return 0;
- }
-
- // do the actual flip
- mIndex = 1 - mIndex;
- mInfo.activate = FB_ACTIVATE_VBL;
- mInfo.yoffset = mIndex ? mInfo.yres : 0;
- if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
- LOGE("FBIOPUT_VSCREENINFO failed");
- return 0;
- }
-
- /*
- * this is a monstrous hack: Because the h/w accelerator is not able
- * to render directly into the framebuffer, we need to copy its
- * internal framebuffer out to the fb.
- * oem[0] is used to access the fd of internal fb.
- * All this is needed only in standalone mode, in SurfaceFlinger mode
- * we control where the GPU renders.
- * We do this only if we have copybit, since this hack is needed only
- * with msm7k.
- */
- if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
- copybit_device_t *copybit = mBlitEngine;
- copybit_rect_t sdrect = { 0, 0,
- egl_native_window_t::width, egl_native_window_t::height };
- copybit_image_t dst = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format,
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base,
- egl_native_window_t::fd
- };
- copybit_image_t src = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format, // XXX: use proper format
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base, // XXX: use proper base
- egl_native_window_t::oem[0]
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
- }
-
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
-
-#if SHOW_FPS
- mSleep += systemTime()-now;
-#endif
-
- mPageFlipCount++;
-
- // We don't support screen-size changes for now
- return 0;
-}
-
-int32_t EGLDisplaySurface::getPageFlipCount() const
-{
- return mPageFlipCount;
-}
-
-void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t dst = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(copyback);
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- /* no extra copy needed since we copied back to front instead of
- * flipping */
- if (!(mFlags & PAGE_FLIP)) {
- return;
- }
-
- Region::iterator iterator(copyback);
- if (iterator) {
- Rect r;
- uint8_t* const screen_src = mFb[ mIndex].data;
- uint8_t* const screen_dst = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
- uint8_t* s = screen_src + o;
- uint8_t* d = screen_dst + o;
- if (size == bpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += bpr;
- s += bpr;
- } while (--h > 0);
- }
- }
- }
- }
-}
-
-void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[ mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-
-status_t EGLDisplaySurface::mapFrameBuffer()
-{
- char const * const device_template[] = {
- "/dev/graphics/fb%u",
- "/dev/fb%u",
- 0 };
- int fd = -1;
- int i=0;
- char name[64];
- while ((fd==-1) && device_template[i]) {
- snprintf(name, 64, device_template[i], 0);
- fd = open(name, O_RDWR, 0);
- i++;
- }
- if (fd < 0)
- return -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.yres_virtual = info.yres * 2;
- info.bits_per_pixel = 16;
- /* Explicitly request 5/6/5 */
- info.red.offset = 11;
- info.red.length = 5;
- info.green.offset = 5;
- info.green.length = 6;
- info.blue.offset = 0;
- info.blue.length = 5;
- info.transp.offset = 0;
- info.transp.length = 0;
- info.activate = FB_ACTIVATE_NOW;
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
- if (int(info.width) <= 0 || int(info.height) <= 0) {
- // the driver doesn't return that information
- // default to 160 dpi
- info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
- info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
- }
-
- float xdpi = (info.xres * 25.4f) / info.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "using (fd=%d)\n"
- "id = %s\n"
- "xres = %d px\n"
- "yres = %d px\n"
- "xres_virtual = %d px\n"
- "yres_virtual = %d px\n"
- "bpp = %d\n"
- "r = %2u:%u\n"
- "g = %2u:%u\n"
- "b = %2u:%u\n",
- fd,
- finfo.id,
- info.xres,
- info.yres,
- info.xres_virtual,
- info.yres_virtual,
- info.bits_per_pixel,
- info.red.offset, info.red.length,
- info.green.offset, info.green.length,
- info.blue.offset, info.blue.length
- );
-
- LOGI( "width = %d mm (%f dpi)\n"
- "height = %d mm (%f dpi)\n"
- "refresh rate = %.2f Hz\n",
- info.width, xdpi,
- info.height, ydpi,
- fps
- );
-
-
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- /*
- * Open and map the display.
- */
-
- void* buffer = (uint16_t*) mmap(
- 0, finfo.smem_len,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, 0);
-
- if (buffer == MAP_FAILED)
- return -errno;
-
- // at least for now, always clear the fb
- memset(buffer, 0, finfo.smem_len);
-
- uint8_t* offscreen[2];
- offscreen[0] = (uint8_t*)buffer;
- if (flags & PAGE_FLIP) {
- offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
- } else {
- offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
- if (offscreen[1] == 0) {
- munmap(buffer, finfo.smem_len);
- return NO_MEMORY;
- }
- }
-
- mFlags = flags;
- mInfo = info;
- mFinfo = finfo;
- mSize = finfo.smem_len;
- mIndex = 0;
- for (int i=0 ; i<2 ; i++) {
- mFb[i].version = sizeof(GGLSurface);
- mFb[i].width = info.xres;
- mFb[i].height = info.yres;
- mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
- mFb[i].data = (GGLubyte*)(offscreen[i]);
- mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
- }
- return fd;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
deleted file mode 100644
index f1071cf..0000000
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "EGLNativeWindowSurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-#include <ui/EGLNativeWindowSurface.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
- : EGLNativeSurface<EGLNativeWindowSurface>(),
- mSurface(surface), mConnected(false)
-{
- egl_native_window_t::magic = 0x600913;
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
- egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
- egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
-
- DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
- egl_native_window_t::xdpi = dinfo.xdpi;
- egl_native_window_t::ydpi = dinfo.ydpi;
- egl_native_window_t::fps = dinfo.fps;
- egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
-}
-
-EGLNativeWindowSurface::~EGLNativeWindowSurface()
-{
- disconnect();
- mSurface.clear();
- magic = 0;
-}
-
-void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->incStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->decStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->connect();
-}
-
-void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->disconnect();
-}
-
-uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
-}
-
-uint32_t EGLNativeWindowSurface::swapBuffers()
-{
- const int w = egl_native_window_t::width;
- const int h = egl_native_window_t::height;
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->unlockAndPost();
- surface->lock(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-
- // update size if it changed
- if (w != int(info.w) || h != int(info.h)) {
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- return EGL_NATIVES_FLAG_SIZE_CHANGED;
- }
- return 0;
-}
-
-void EGLNativeWindowSurface::connect()
-{
- if (!mConnected) {
- Surface::SurfaceInfo info;
- mSurface->lock(&info);
- mSurface->setSwapRectangle(Rect(info.w, info.h));
- mConnected = true;
-
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- // FIXME: egl_native_window_t::memory_type used to be set from
- // mSurface, but we wanted to break this dependency. We set it to
- // GPU because the software rendered doesn't care, but the h/w
- // accelerator needs it. Eventually, this value should go away
- // completely, since memory will be managed by OpenGL.
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
- egl_native_window_t::fd = 0;
- }
-}
-
-void EGLNativeWindowSurface::disconnect()
-{
- if (mConnected) {
- mSurface->unlock();
- mConnected = false;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..59c9476 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -19,10 +19,10 @@
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
-#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <utils.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
@@ -83,7 +83,7 @@ EventHub::EventHub(void)
: mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
, mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0)
+ , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
{
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
@@ -100,11 +100,6 @@ EventHub::~EventHub(void)
// we should free stuff here...
}
-void EventHub::onFirstRef()
-{
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
-}
-
status_t EventHub::errorCheck() const
{
return mError;
@@ -239,6 +234,41 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const
return 0;
}
+status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+
+ if (mHaveFirstKeyboard) {
+ device = getDevice(mFirstKeyboardId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ }
+
+ *outKeycode = 0;
+ *outFlags = 0;
+ return NAME_NOT_FOUND;
+}
+
+void EventHub::addExcludedDevice(const char* deviceName)
+{
+ String8 name(deviceName);
+ mExcludedDevices.push_back(name);
+}
+
EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
@@ -276,7 +306,12 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
// Note that we only allow one caller to getEvent(), so don't need
// to do locking here... only when adding/removing devices.
-
+
+ if (!mOpened) {
+ mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+ mOpened = true;
+ }
+
while(1) {
// First, report any devices that had last been added/removed.
@@ -474,6 +509,20 @@ int EventHub::open_device(const char *deviceName)
//fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
name[0] = '\0';
}
+
+ // check to see if the device is on our excluded list
+ List<String8>::iterator iter = mExcludedDevices.begin();
+ List<String8>::iterator end = mExcludedDevices.end();
+ for ( ; iter != end; iter++) {
+ const char* test = *iter;
+ if (strcmp(name, test) == 0) {
+ LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ }
+
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
location[0] = '\0';
@@ -733,6 +782,7 @@ int EventHub::read_notify(int nfd)
int event_pos = 0;
struct inotify_event *event;
+LOGD("EventHub::read_notify nfd: %d\n", nfd);
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
new file mode 100644
index 0000000..8c8fd6b
--- /dev/null
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -0,0 +1,210 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "FramebufferNativeWindow"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/threads.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class NativeBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ NativeBuffer,
+ LightRefBase<NativeBuffer> >
+{
+public:
+ NativeBuffer(int w, int h, int f, int u) : BASE() {
+ android_native_buffer_t::width = w;
+ android_native_buffer_t::height = h;
+ android_native_buffer_t::format = f;
+ android_native_buffer_t::usage = u;
+ }
+private:
+ friend class LightRefBase<NativeBuffer>;
+ ~NativeBuffer() { }; // this class cannot be overloaded
+};
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ * In fact this is an implementation of android_native_window_t on top of
+ * the framebuffer.
+ *
+ * Currently it is pretty simple, it manages only two buffers (the front and
+ * back buffer).
+ *
+ */
+
+FramebufferNativeWindow::FramebufferNativeWindow()
+ : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
+{
+ hw_module_t const* module;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ int stride;
+ framebuffer_open(module, &fbDev);
+ gralloc_open(module, &grDev);
+ int err;
+
+
+ mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+ // initialize the buffer FIFO
+ mNumBuffers = 2;
+ mNumFreeBuffers = 2;
+ mBufferHead = mNumBuffers-1;
+ buffers[0] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+ buffers[1] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);
+
+ LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);
+
+ LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+ }
+
+ const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags;
+ const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
+ const_cast<int&>(android_native_window_t::minSwapInterval) =
+ fbDev->minSwapInterval;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) =
+ fbDev->maxSwapInterval;
+
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+}
+
+FramebufferNativeWindow::~FramebufferNativeWindow() {
+ grDev->free(grDev, buffers[0]->handle);
+ grDev->free(grDev, buffers[1]->handle);
+ gralloc_close(grDev);
+ framebuffer_close(fbDev);
+}
+
+status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
+{
+ if (!mUpdateOnDemand) {
+ return INVALID_OPERATION;
+ }
+ return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+int FramebufferNativeWindow::setSwapInterval(
+ android_native_window_t* window, int interval)
+{
+ framebuffer_device_t* fb = getSelf(window)->fbDev;
+ return fb->setSwapInterval(fb, interval);
+}
+
+int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+
+ // wait for a free buffer
+ while (!self->mNumFreeBuffers) {
+ self->mCondition.wait(self->mutex);
+ }
+ // get this buffer
+ self->mNumFreeBuffers--;
+ int index = self->mBufferHead++;
+ if (self->mBufferHead >= self->mNumBuffers)
+ self->mBufferHead = 0;
+
+ *buffer = self->buffers[index].get();
+
+ return 0;
+}
+
+int FramebufferNativeWindow::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+
+ // wait that the buffer we're locking is not front anymore
+ while (self->front == buffer) {
+ self->mCondition.wait(self->mutex);
+ }
+
+ return NO_ERROR;
+}
+
+int FramebufferNativeWindow::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ int res = fb->post(fb, handle);
+ self->front = static_cast<NativeBuffer*>(buffer);
+ self->mNumFreeBuffers++;
+ self->mCondition.broadcast();
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+
+EGLNativeWindowType android_createDisplaySurface(void)
+{
+ return new android::FramebufferNativeWindow();
+}
+
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index ab0fef1..805c2ca 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ICamera.h>
namespace android {
@@ -221,12 +221,6 @@ IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index 59a6cf2..42b4da4 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -78,12 +78,6 @@ IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
index e5687fe..84986c6 100644
--- a/libs/ui/ICameraService.cpp
+++ b/libs/ui/ICameraService.cpp
@@ -18,9 +18,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ICameraService.h>
@@ -49,12 +49,6 @@ IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
index fed47c2..65e6b4f 100644
--- a/libs/ui/IOverlay.cpp
+++ b/libs/ui/IOverlay.cpp
@@ -18,8 +18,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
#include <ui/IOverlay.h>
@@ -49,12 +49,6 @@ IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnOverlay::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index d5e9f81..9fbae1e 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -14,19 +14,25 @@
* limitations under the License.
*/
+#define LOG_TAG "ISurface"
+
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
+#include <ui/Surface.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
+// ----------------------------------------------------------------------
+
ISurface::BufferHeap::BufferHeap()
: w(0), h(0), hor_stride(0), ver_stride(0), format(0),
transform(0), flags(0)
@@ -55,6 +61,8 @@ ISurface::BufferHeap::~BufferHeap()
{
}
+// ----------------------------------------------------------------------
+
class BpSurface : public BpInterface<ISurface>
{
public:
@@ -63,6 +71,15 @@ public:
{
}
+ virtual sp<SurfaceBuffer> getBuffer()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ remote()->transact(GET_BUFFER, data, &reply);
+ sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
+ return buffer;
+ }
+
virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
@@ -112,16 +129,15 @@ IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
+ case GET_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ sp<SurfaceBuffer> buffer(getBuffer());
+ return SurfaceBuffer::writeToParcel(reply, buffer.get());
+ }
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
BufferHeap buffer;
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
index 76597e1..fd2a590 100644
--- a/libs/ui/ISurfaceComposer.cpp
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -20,10 +20,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -54,12 +54,12 @@ public:
return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
}
- virtual sp<IMemory> getCblk() const
+ virtual sp<IMemoryHeap> getCblk() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
- return interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual void openGlobalTransaction()
@@ -114,36 +114,6 @@ public:
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback, gpu_info_t* gpu)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(callback->asBinder());
- remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
- gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->count = reply.readInt32();
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
- if (gpu->count > maxCount)
- return BAD_VALUE;
-
- for (size_t i=0 ; i<gpu->count ; i++) {
- gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->regions[i].reserved = reply.readInt32();
- }
- return reply.readInt32();
- }
-
- virtual status_t revokeGPU()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
- return reply.readInt32();
- }
-
virtual void signal() const
{
Parcel data, reply;
@@ -156,124 +126,61 @@ IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
- if (err == NO_ERROR)
- return err;
-
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
switch(code) {
case CREATE_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case OPEN_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
openGlobalTransaction();
} break;
case CLOSE_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
closeGlobalTransaction();
} break;
case SET_ORIENTATION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
int orientation = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( setOrientation(dpy, orientation, flags) );
} break;
case FREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( freezeDisplay(dpy, flags) );
} break;
case UNFREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( unfreezeDisplay(dpy, flags) );
} break;
case BOOT_FINISHED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case REVOKE_GPU: {
- reply->writeInt32( revokeGPU() );
- } break;
case SIGNAL: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
signal();
} break;
case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();
reply->writeStrongBinder(b);
} break;
- case REQUEST_GPU: {
- // TODO: this should be protected by a permission
- gpu_info_t info;
- sp<IGPUCallback> callback
- = interface_cast<IGPUCallback>(data.readStrongBinder());
- status_t res = requestGPU(callback, &info);
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
- if (info.count > maxCount)
- return BAD_VALUE;
-
- reply->writeStrongBinder(info.regs->asBinder());
- reply->writeInt32(info.count);
- for (size_t i=0 ; i<info.count ; i++) {
- reply->writeStrongBinder(info.regions[i].region->asBinder());
- reply->writeInt32(info.regions[i].reserved);
- }
- reply->writeInt32(res);
- } break;
default:
- return UNKNOWN_TRANSACTION;
+ return BBinder::onTransact(code, data, reply, flags);
}
return NO_ERROR;
}
// ----------------------------------------------------------------------------
-enum {
- // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
- GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpGPUCallback : public BpInterface<IGPUCallback>
-{
-public:
- BpGPUCallback(const sp<IBinder>& impl)
- : BpInterface<IGPUCallback>(impl)
- {
- }
-
- virtual void gpuLost()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
- remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
-
-status_t BnGPUCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GPU_LOST: {
- CHECK_INTERFACE(IGPUCallback, data, reply);
- gpuLost();
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dab5f71..51e8422 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -21,10 +21,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurface.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -64,12 +64,12 @@ public:
{
}
- virtual void getControlBlocks(sp<IMemory>* ctl) const
+ virtual sp<IMemoryHeap> getControlBlock() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
remote()->transact(GET_CBLK, data, &reply);
- *ctl = interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual sp<ISurface> createSurface( surface_data_t* params,
@@ -118,12 +118,6 @@ IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -132,8 +126,7 @@ status_t BnSurfaceFlingerClient::onTransact(
switch(code) {
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
- sp<IMemory> ctl;
- getControlBlocks(&ctl);
+ sp<IMemoryHeap> ctl(getControlBlock());
reply->writeStrongBinder(ctl->asBinder());
return NO_ERROR;
} break;
@@ -198,8 +191,6 @@ status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& par
{
token = parcel.readInt32();
identity = parcel.readInt32();
- heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
- heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
return NO_ERROR;
}
@@ -207,8 +198,6 @@ status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) co
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
return NO_ERROR;
}
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
index 0b6374b..a53ffb7 100644
--- a/libs/ui/LayerState.cpp
+++ b/libs/ui/LayerState.cpp
@@ -15,7 +15,7 @@
*/
#include <utils/Errors.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <private/ui/LayerState.h>
namespace android {
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index 59c6514..4854d6a 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <utils/IMemory.h>
-#include <utils/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
#include <utils/Errors.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/IOverlay.h>
#include <ui/Overlay.h>
@@ -59,6 +59,18 @@ status_t Overlay::queueBuffer(overlay_buffer_t buffer)
return mOverlayData->queueBuffer(mOverlayData, buffer);
}
+status_t Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setCrop(mOverlayData, x, y, w, h);
+}
+
+status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->getCrop(mOverlayData, x, y, w, h);
+}
+
int32_t Overlay::getBufferCount() const
{
if (mStatus != NO_ERROR) return mStatus;
@@ -73,6 +85,15 @@ void* Overlay::getBufferAddress(overlay_buffer_t buffer)
void Overlay::destroy() {
if (mStatus != NO_ERROR) return;
+
+ // Must delete the objects in reverse creation order, thus the
+ // data side must be closed first and then the destroy send to
+ // the control side.
+ if (mOverlayData) {
+ overlay_data_close(mOverlayData);
+ mOverlayData = NULL;
+ }
+
mOverlayRef->mOverlayChannel->destroy();
}
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 26e694a..d21ed57 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -16,295 +16,661 @@
#define LOG_TAG "Region"
-#include <stdio.h>
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
+#include <limits.h>
+
+#include <utils/Log.h>
#include <utils/String8.h>
+
+#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Point.h>
+
+#include <private/ui/RegionHelper.h>
+
+// ----------------------------------------------------------------------------
+#define VALIDATE_REGIONS (false)
+#define VALIDATE_WITH_CORECG (false)
+// ----------------------------------------------------------------------------
+
+#if VALIDATE_WITH_CORECG
+#include <core/SkRegion.h>
+#endif
namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+ op_nand = region_operator<Rect>::op_nand,
+ op_and = region_operator<Rect>::op_and,
+ op_or = region_operator<Rect>::op_or,
+ op_xor = region_operator<Rect>::op_xor
+};
// ----------------------------------------------------------------------------
Region::Region()
+ : mBounds(0,0)
{
}
Region::Region(const Region& rhs)
- : mRegion(rhs.mRegion)
-{
-}
-
-Region::Region(const SkRegion& rhs)
- : mRegion(rhs)
-{
-}
-
-Region::~Region()
+ : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
{
}
Region::Region(const Rect& rhs)
+ : mBounds(rhs)
{
- set(rhs);
}
Region::Region(const Parcel& parcel)
{
- read(parcel);
+ status_t err = read(parcel);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
}
Region::Region(const void* buffer)
{
- read(buffer);
+ status_t err = read(buffer);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
}
-Region& Region::operator = (const Region& rhs)
+Region::~Region()
{
- mRegion = rhs.mRegion;
- return *this;
}
-const SkRegion& Region::toSkRegion() const
+Region& Region::operator = (const Region& rhs)
{
- return mRegion;
+#if VALIDATE_REGIONS
+ validate(rhs, "operator=");
+#endif
+ mBounds = rhs.mBounds;
+ mStorage = rhs.mStorage;
+ return *this;
}
-Rect Region::bounds() const
+Region& Region::makeBoundsSelf()
{
- const SkIRect& b(mRegion.getBounds());
- return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+ mStorage.clear();
+ return *this;
}
void Region::clear()
{
- mRegion.setEmpty();
+ mBounds.clear();
+ mStorage.clear();
}
void Region::set(const Rect& r)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.setRect(ir);
+ mBounds = r;
+ mStorage.clear();
+}
+
+void Region::set(uint32_t w, uint32_t h)
+{
+ mBounds = Rect(int(w), int(h));
+ mStorage.clear();
}
// ----------------------------------------------------------------------------
-Region& Region::orSelf(const Rect& r)
+void Region::addRectUnchecked(int l, int t, int r, int b)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kUnion_Op);
- return *this;
+ mStorage.add(Rect(l,t,r,b));
+#if VALIDATE_REGIONS
+ validate(*this, "addRectUnchecked");
+#endif
}
-Region& Region::andSelf(const Rect& r)
-{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r) {
+ return operationSelf(r, op_or);
+}
+Region& Region::andSelf(const Rect& r) {
+ return operationSelf(r, op_and);
+}
+Region& Region::subtractSelf(const Rect& r) {
+ return operationSelf(r, op_nand);
+}
+Region& Region::operationSelf(const Rect& r, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, r);
return *this;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, op_or);
}
-
Region& Region::andSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+ return operationSelf(rhs, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs);
return *this;
}
Region& Region::translateSelf(int x, int y) {
- if (x|y) mRegion.translate(x, y);
+ if (x|y) translate(*this, x, y);
return *this;
}
-Region Region::merge(const Region& rhs) const {
- Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
- return result;
-}
+// ----------------------------------------------------------------------------
-Region Region::intersect(const Region& rhs) const {
+const Region Region::merge(const Rect& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Rect& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Rect& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Rect& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::subtract(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Region& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Region& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Region& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::translate(int x, int y) const {
+const Region Region::translate(int x, int y) const {
Region result;
- mRegion.translate(x, y, &result.mRegion);
+ translate(result, *this, x, y);
return result;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_or);
}
-
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kDifference_Op);
+ return operationSelf(rhs, dx, dy, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs, dx, dy);
return *this;
}
-Region Region::merge(const Region& rhs, int dx, int dy) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_or);
+}
+const Region Region::intersect(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_and);
+}
+const Region Region::subtract(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_nand);
+}
+const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
+ boolean_operation(op, result, *this, rhs, dx, dy);
return result;
}
-Region Region::intersect(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+// This is our region rasterizer, which merges rects and spans together
+// to obtain an optimal region.
+class Region::rasterizer : public region_operator<Rect>::region_rasterizer
+{
+ Rect& bounds;
+ Vector<Rect>& storage;
+ Rect* head;
+ Rect* tail;
+ Vector<Rect> span;
+ Rect* cur;
+public:
+ rasterizer(Region& reg)
+ : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
+ bounds.top = bounds.bottom = 0;
+ bounds.left = INT_MAX;
+ bounds.right = INT_MIN;
+ storage.clear();
+ }
+
+ ~rasterizer() {
+ if (span.size()) {
+ flushSpan();
+ }
+ if (storage.size()) {
+ bounds.top = storage.itemAt(0).top;
+ bounds.bottom = storage.top().bottom;
+ if (storage.size() == 1) {
+ storage.clear();
+ }
+ } else {
+ bounds.left = 0;
+ bounds.right = 0;
+ }
+ }
+
+ virtual void operator()(const Rect& rect) {
+ //LOGD(">>> %3d, %3d, %3d, %3d",
+ // rect.left, rect.top, rect.right, rect.bottom);
+ if (span.size()) {
+ if (cur->top != rect.top) {
+ flushSpan();
+ } else if (cur->right == rect.left) {
+ cur->right = rect.right;
+ return;
+ }
+ }
+ span.add(rect);
+ cur = span.editArray() + (span.size() - 1);
+ }
+private:
+ template<typename T>
+ static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
+ template<typename T>
+ static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
+ void flushSpan() {
+ bool merge = false;
+ if (tail-head == ssize_t(span.size())) {
+ Rect const* p = cur;
+ Rect const* q = head;
+ if (p->top == q->bottom) {
+ merge = true;
+ while (q != tail) {
+ if ((p->left != q->left) || (p->right != q->right)) {
+ merge = false;
+ break;
+ }
+ p++, q++;
+ }
+ }
+ }
+ if (merge) {
+ const int bottom = span[0].bottom;
+ Rect* r = head;
+ while (r != tail) {
+ r->bottom = bottom;
+ r++;
+ }
+ } else {
+ bounds.left = min(span.itemAt(0).left, bounds.left);
+ bounds.right = max(span.top().right, bounds.right);
+ storage.appendVector(span);
+ tail = storage.editArray() + storage.size();
+ head = tail - span.size();
+ }
+ span.clear();
+ }
+};
+
+bool Region::validate(const Region& reg, const char* name)
+{
+ bool result = true;
+ const_iterator cur = reg.begin();
+ const_iterator const tail = reg.end();
+ const_iterator prev = cur++;
+ Rect b(*prev);
+ while (cur != tail) {
+ b.left = b.left < cur->left ? b.left : cur->left;
+ b.top = b.top < cur->top ? b.top : cur->top;
+ b.right = b.right > cur->right ? b.right : cur->right;
+ b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+ if (cur->top == prev->top) {
+ if (cur->bottom != prev->bottom) {
+ LOGE("%s: invalid span %p", name, cur);
+ result = false;
+ } else if (cur->left < prev->right) {
+ LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ } else if (cur->top < prev->bottom) {
+ LOGE("%s: spans overlap vertically prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ prev = cur;
+ cur++;
+ }
+ if (b != reg.getBounds()) {
+ result = false;
+ LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+ b.left, b.top, b.right, b.bottom,
+ reg.getBounds().left, reg.getBounds().top,
+ reg.getBounds().right, reg.getBounds().bottom);
+ }
+ if (result == false) {
+ reg.dump(name);
+ }
return result;
}
-Region Region::subtract(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
- return result;
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Region& rhs, int dx, int dy)
+{
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ size_t rhs_count;
+ Rect const * const rhs_rects = rhs.getArray(&rhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#if VALIDATE_REGIONS
+ validate(lhs, "boolean_operation: lhs");
+ validate(rhs, "boolean_operation: rhs");
+ validate(dst, "boolean_operation: dst");
+#endif
+
+#if VALIDATE_WITH_CORECG
+ SkRegion sk_lhs;
+ SkRegion sk_rhs;
+ SkRegion sk_dst;
+
+ for (size_t i=0 ; i<lhs_count ; i++)
+ sk_lhs.op(
+ lhs_rects[i].left + dx,
+ lhs_rects[i].top + dy,
+ lhs_rects[i].right + dx,
+ lhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ for (size_t i=0 ; i<rhs_count ; i++)
+ sk_rhs.op(
+ rhs_rects[i].left + dx,
+ rhs_rects[i].top + dy,
+ rhs_rects[i].right + dx,
+ rhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ const char* name = "---";
+ SkRegion::Op sk_op;
+ switch (op) {
+ case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+ case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
+ case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
+ }
+ sk_dst.op(sk_lhs, sk_rhs, sk_op);
+
+ if (sk_dst.isEmpty() && dst.isEmpty())
+ return;
+
+ bool same = true;
+ Region::const_iterator head = dst.begin();
+ Region::const_iterator const tail = dst.end();
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ if (head != tail) {
+ if (
+ head->left != it.rect().fLeft ||
+ head->top != it.rect().fTop ||
+ head->right != it.rect().fRight ||
+ head->bottom != it.rect().fBottom
+ ) {
+ same = false;
+ break;
+ }
+ } else {
+ same = false;
+ break;
+ }
+ head++;
+ it.next();
+ }
+
+ if (head != tail) {
+ same = false;
+ }
+
+ if(!same) {
+ LOGD("---\nregion boolean %s failed", name);
+ lhs.dump("lhs");
+ rhs.dump("rhs");
+ dst.dump("dst");
+ LOGD("should be");
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ LOGD(" [%3d, %3d, %3d, %3d]",
+ it.rect().fLeft,
+ it.rect().fTop,
+ it.rect().fRight,
+ it.rect().fBottom);
+ it.next();
+ }
+ }
+#endif
}
-// ----------------------------------------------------------------------------
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Rect& rhs, int dx, int dy)
+{
+#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+ boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
+#else
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#endif
+}
-Region::iterator::iterator(const Region& r)
- : mIt(r.mRegion)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs)
{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
}
-int Region::iterator::iterate(Rect* rect)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs)
{
- if (mIt.done())
- return 0;
- const SkIRect& r(mIt.rect());
- rect->left = r.fLeft;
- rect->top = r.fTop;
- rect->right = r.fRight;
- rect->bottom= r.fBottom;
- mIt.next();
- return 1;
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
}
-// ----------------------------------------------------------------------------
+void Region::translate(Region& reg, int dx, int dy)
+{
+ if (!reg.isEmpty()) {
+#if VALIDATE_REGIONS
+ validate(reg, "translate (before)");
+#endif
+ reg.mBounds.translate(dx, dy);
+ size_t count = reg.mStorage.size();
+ Rect* rects = reg.mStorage.editArray();
+ while (count) {
+ rects->translate(dx, dy);
+ rects++;
+ count--;
+ }
+#if VALIDATE_REGIONS
+ validate(reg, "translate (after)");
+#endif
+ }
+}
+
+void Region::translate(Region& dst, const Region& reg, int dx, int dy)
+{
+ dst = reg;
+ translate(dst, dx, dy);
+}
-// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
+// ----------------------------------------------------------------------------
status_t Region::write(Parcel& parcel) const
{
- int32_t size = mRegion.flatten(NULL);
- parcel.writeInt32(size);
- mRegion.flatten(parcel.writeInplace(size));
+#if VALIDATE_REGIONS
+ validate(*this, "write(Parcel)");
+#endif
+ status_t err;
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ void* buffer = parcel.writeInplace(sizeNeeded);
+ if (!buffer) return NO_MEMORY;
+ ssize_t written = Region::write(buffer, sizeNeeded);
+ if (written < 0) return status_t(written);
return NO_ERROR;
}
status_t Region::read(const Parcel& parcel)
{
- size_t size = parcel.readInt32();
- mRegion.unflatten(parcel.readInplace(size));
+ void const* buffer = parcel.readInplace(sizeof(int32_t));
+ if (!buffer) return NO_MEMORY;
+ const size_t count = *static_cast<int32_t const *>(buffer);
+ void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
+ if (!dummy) return NO_MEMORY;
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ const ssize_t read = Region::read(buffer);
+ if (read < 0) return status_t(read);
+#if VALIDATE_REGIONS
+ validate(*this, "read(Parcel)");
+#endif
return NO_ERROR;
}
ssize_t Region::write(void* buffer, size_t size) const
{
- size_t sizeNeeded = mRegion.flatten(NULL);
+#if VALIDATE_REGIONS
+ validate(*this, "write(buffer)");
+#endif
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
if (sizeNeeded > size) return NO_MEMORY;
- return mRegion.flatten(buffer);
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ *p = count;
+ memcpy(p+1, &mBounds, sizeof(Rect));
+ if (count) {
+ memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+ }
+ return ssize_t(sizeNeeded);
}
ssize_t Region::read(const void* buffer)
{
- return mRegion.unflatten(buffer);
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ const size_t count = *p;
+ memcpy(&mBounds, p+1, sizeof(Rect));
+ mStorage.clear();
+ if (count) {
+ mStorage.insertAt(0, count);
+ memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
+ }
+#if VALIDATE_REGIONS
+ validate(*this, "read(buffer)");
+#endif
+ return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
}
ssize_t Region::writeEmpty(void* buffer, size_t size)
{
- if (size < 4) return NO_MEMORY;
- // this needs to stay in sync with SkRegion
- *static_cast<int32_t*>(buffer) = -1;
- return 4;
+ const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
+ if (sizeNeeded > size) return NO_MEMORY;
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ memset(p, 0, sizeNeeded);
+ return ssize_t(sizeNeeded);
}
bool Region::isEmpty(void* buffer)
{
- // this needs to stay in sync with SkRegion
- return *static_cast<int32_t*>(buffer) == -1;
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ Rect const* const b = reinterpret_cast<Rect const *>(p+1);
+ return b->isEmpty();
+}
+
+// ----------------------------------------------------------------------------
+
+Region::const_iterator Region::begin() const {
+ return isRect() ? &mBounds : mStorage.array();
+}
+
+Region::const_iterator Region::end() const {
+ return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
+}
+
+Rect const* Region::getArray(size_t* count) const {
+ const_iterator const b(begin());
+ const_iterator const e(end());
+ if (count) *count = e-b;
+ return b;
}
-size_t Region::rects(Vector<Rect>& rectList) const
+size_t Region::getRects(Vector<Rect>& rectList) const
{
- rectList.clear();
- if (!isEmpty()) {
- SkRegion::Iterator iterator(mRegion);
- while( !iterator.done() ) {
- const SkIRect& ir(iterator.rect());
- rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
- iterator.next();
- }
+ rectList = mStorage;
+ if (rectList.isEmpty()) {
+ rectList.clear();
+ rectList.add(mBounds);
}
return rectList.size();
}
+// ----------------------------------------------------------------------------
+
void Region::dump(String8& out, const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
-
+ const_iterator head = begin();
+ const_iterator const tail = end();
+
size_t SIZE = 256;
char buffer[SIZE];
-
- snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size());
+
+ snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
+ what, this, tail-head);
out.append(buffer);
- for (size_t i=0 ; i<r.size() ; i++) {
+ while (head != tail) {
snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
out.append(buffer);
+ head++;
}
}
void Region::dump(const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
- LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size());
- for (size_t i=0 ; i<r.size() ; i++) {
+ const_iterator head = begin();
+ const_iterator const tail = end();
+ LOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
+ while (head != tail) {
LOGD(" [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
+ head++;
}
}
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..aef47fd 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,202 +23,333 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
+#include <ui/BufferMapper.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
+#include <pixelflinger/pixelflinger.h>
+
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
-// ---------------------------------------------------------------------------
+// ============================================================================
+// SurfaceBuffer
+// ============================================================================
-Surface::Surface(const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner)
- : mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity),
- mFormat(format), mFlags(flags), mOwner(owner)
+SurfaceBuffer::SurfaceBuffer()
+ : BASE(), mOwner(false), mBufferMapper(BufferMapper::get())
{
- mSwapRectangle.makeInvalid();
- mSurfaceHeapBase[0] = 0;
- mSurfaceHeapBase[1] = 0;
- mHeap[0] = data.heap[0];
- mHeap[1] = data.heap[1];
-}
-
-Surface::Surface(Surface const* rhs)
- : mOwner(false)
-{
- mToken = rhs->mToken;
- mIdentity= rhs->mIdentity;
- mClient = rhs->mClient;
- mSurface = rhs->mSurface;
- mHeap[0] = rhs->mHeap[0];
- mHeap[1] = rhs->mHeap[1];
- mFormat = rhs->mFormat;
- mFlags = rhs->mFlags;
- mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
- mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
- mSwapRectangle.makeInvalid();
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
}
-Surface::~Surface()
+SurfaceBuffer::SurfaceBuffer(const Parcel& data)
+ : BASE(), mOwner(true), mBufferMapper(BufferMapper::get())
{
- if (mOwner && mToken>=0 && mClient!=0) {
- mClient->destroySurface(mToken);
- }
- mClient.clear();
- mSurface.clear();
- mHeap[0].clear();
- mHeap[1].clear();
- IPCThreadState::self()->flushCommands();
+ // we own the handle in this case
+ width = data.readInt32();
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
}
-sp<Surface> Surface::dup() const
+SurfaceBuffer::~SurfaceBuffer()
{
- Surface const * r = this;
- if (this && mOwner) {
- // the only reason we need to do this is because of Java's garbage
- // collector: because we're creating a copy of the Surface
- // instead of a reference, we can garantee that when our last
- // reference goes away, the real surface will be deleted.
- // Without this hack (the code is correct too), we'd have to
- // wait for a GC for the surface to go away.
- r = new Surface(this);
+ if (handle && mOwner) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
}
- return const_cast<Surface*>(r);
}
-status_t Surface::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
+status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr)
+{
+ const Rect lockBounds(width, height);
+ status_t res = lock(usage, lockBounds, vaddr);
+ return res;
}
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
+status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
+{
+ if (rect.left < 0 || rect.right > this->width ||
+ rect.top < 0 || rect.bottom > this->height) {
+ LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
+ rect.left, rect.top, rect.right, rect.bottom,
+ this->width, this->height);
+ return BAD_VALUE;
+ }
+ status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
+ return res;
}
-status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->lockSurface(this, info, dirty, blocking);
+status_t SurfaceBuffer::unlock()
+{
+ status_t res = getBufferMapper().unlock(handle);
+ return res;
}
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
+status_t SurfaceBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
+{
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ reply->writeNativeHandle(buffer->handle);
+ return NO_ERROR;
}
-status_t Surface::unlock() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockSurface(this);
+// ----------------------------------------------------------------------
+
+static status_t copyBlt(
+ const sp<SurfaceBuffer>& dst,
+ const sp<SurfaceBuffer>& src,
+ const Region& reg)
+{
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ 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;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
}
-status_t Surface::setLayer(int32_t layer) {
- return mClient->setLayer(this, layer);
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::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),
+ mFormat(format), mFlags(flags)
+{
}
-status_t Surface::setPosition(int32_t x, int32_t y) {
- return mClient->setPosition(this, x, y);
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
}
-status_t Surface::setSize(uint32_t w, uint32_t h) {
- return mClient->setSize(this, w, h);
+
+void SurfaceControl::destroy()
+{
+ if (isValid()) {
+ mClient->destroySurface(mToken);
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
}
-status_t Surface::hide() {
- return mClient->hide(this);
+
+void SurfaceControl::clear()
+{
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
}
-status_t Surface::show(int32_t layer) {
- return mClient->show(this, layer);
+
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-status_t Surface::freeze() {
- return mClient->freeze(this);
+
+status_t SurfaceControl::setLayer(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setLayer(mToken, layer);
}
-status_t Surface::unfreeze() {
- return mClient->unfreeze(this);
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setPosition(mToken, x, y);
}
-status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
- return mClient->setFlags(this, flags, mask);
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setSize(mToken, w, h);
}
-status_t Surface::setTransparentRegionHint(const Region& transparent) {
- return mClient->setTransparentRegionHint(this, transparent);
+status_t SurfaceControl::hide() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->hide(mToken);
}
-status_t Surface::setAlpha(float alpha) {
- return mClient->setAlpha(this, alpha);
+status_t SurfaceControl::show(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->show(mToken, layer);
}
-status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
+status_t SurfaceControl::freeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->freeze(mToken);
}
-status_t Surface::setFreezeTint(uint32_t tint) {
- return mClient->setFreezeTint(this, tint);
+status_t SurfaceControl::unfreeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->unfreeze(mToken);
}
-
-Region Surface::dirtyRegion() const {
- return mDirtyRegion;
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFlags(mToken, flags, mask);
}
-void Surface::setDirtyRegion(const Region& region) const {
- mDirtyRegion = region;
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setTransparentRegionHint(mToken, transparent);
}
-const Rect& Surface::swapRectangle() const {
- return mSwapRectangle;
+status_t SurfaceControl::setAlpha(float alpha) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setAlpha(mToken, alpha);
}
-void Surface::setSwapRectangle(const Rect& r) {
- mSwapRectangle = r;
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setFreezeTint(uint32_t tint) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFreezeTint(mToken, tint);
}
-sp<Surface> Surface::readFromParcel(Parcel* parcel)
+status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const
{
- sp<SurfaceComposerClient> client;
- ISurfaceFlingerClient::surface_data_t data;
- sp<IBinder> clientBinder= parcel->readStrongBinder();
- sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
- data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.token = parcel->readInt32();
- data.identity = parcel->readInt32();
- PixelFormat format = parcel->readInt32();
- uint32_t flags = parcel->readInt32();
-
- if (clientBinder != NULL)
- client = SurfaceComposerClient::clientForConnection(clientBinder);
-
- return new Surface(client, surface, data, 0, 0, format, flags, false);
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ 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;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
}
-status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
{
- uint32_t flags=0;
- uint32_t format=0;
+ uint32_t flags = 0;
+ uint32_t format = 0;
SurfaceID token = -1;
uint32_t identity = 0;
sp<SurfaceComposerClient> client;
sp<ISurface> sur;
- sp<IMemoryHeap> heap[2];
- if (surface->isValid()) {
- token = surface->mToken;
- identity = surface->mIdentity;
- client = surface->mClient;
- sur = surface->mSurface;
- heap[0] = surface->mHeap[0];
- heap[1] = surface->mHeap[1];
- format = surface->mFormat;
- flags = surface->mFlags;
+ if (SurfaceControl::isValid(control)) {
+ token = control->mToken;
+ identity = control->mIdentity;
+ client = control->mClient;
+ sur = control->mSurface;
+ format = control->mFormat;
+ flags = control->mFlags;
}
parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
parcel->writeInt32(token);
parcel->writeInt32(identity);
parcel->writeInt32(format);
@@ -226,30 +357,351 @@ status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
return NO_ERROR;
}
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
+
+Surface::Surface(const sp<SurfaceControl>& surface)
+ : mClient(surface->mClient), mSurface(surface->mSurface),
+ mToken(surface->mToken), mIdentity(surface->mIdentity),
+ mFormat(surface->mFormat), mFlags(surface->mFlags),
+ mBufferMapper(BufferMapper::get())
+{
+ init();
+}
+
+Surface::Surface(const Parcel& parcel)
+ : mBufferMapper(BufferMapper::get())
+{
+ sp<IBinder> clientBinder = parcel.readStrongBinder();
+ mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
+ mToken = parcel.readInt32();
+ mIdentity = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+
+ if (clientBinder != NULL)
+ mClient = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ init();
+}
+
+void Surface::init()
+{
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ mSwapRectangle.makeInvalid();
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ 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;
+}
+
+
+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++) {
+ if (mBuffers[i] != 0) {
+ getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
+ }
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+status_t Surface::validate(per_client_cblk_t const* cblk) const
+{
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ 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;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+
+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();
}
-void* Surface::heapBase(int i) const
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval)
+{
+ return 0;
+}
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
{
- void* heapBase = mSurfaceHeapBase[i];
- // map lazily so it doesn't get mapped in clients that don't need it
- if (heapBase == 0) {
- const sp<IMemoryHeap>& heap(mHeap[i]);
- if (heap != 0) {
- heapBase = static_cast<uint8_t*>(heap->base());
- if (heapBase == MAP_FAILED) {
- heapBase = NULL;
- LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
- heap->asBinder().get(), heap.get());
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
+{
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ *buffer = SurfaceBuffer::getSelf(out);
+ return err;
+}
+
+status_t Surface::lockBuffer(const sp<SurfaceBuffer>& buffer)
+{
+ return lockBuffer(buffer.get());
+}
+
+status_t Surface::queueBuffer(const sp<SurfaceBuffer>& buffer)
+{
+ return queueBuffer(buffer.get());
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ // FIXME: dequeueBuffer() needs proper implementation
+
+ Mutex::Autolock _l(mSurfaceLock);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ SurfaceID index(mToken);
+
+ int32_t backIdx = cblk->lock_layer(size_t(index),
+ per_client_cblk_t::BLOCKING);
+
+ if (backIdx < 0)
+ return status_t(backIdx);
+
+ mBackbufferIndex = backIdx;
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+
+ volatile const surface_info_t* const back = lcblk->surface + backIdx;
+ if (back->flags & surface_info_t::eNeedNewBuffer) {
+ getBufferLocked(backIdx);
+ }
+
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+
+ return NO_ERROR;
+}
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ // FIXME: lockBuffer() needs proper implementation
+ return 0;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
+ }
+
+ // transmit the dirty region
+ SurfaceID index(mToken);
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ _send_dirty_region(lcblk, mDirtyRegion);
+
+ uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+ if (!(newstate & eNextFlipPending))
+ mClient->signalServer();
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ // FIXME: needs some locking here
+
+ sp<SurfaceBuffer> backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer);
+ if (err == NO_ERROR) {
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region scratch(bounds);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
+ volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
+ if (back->flags & surface_info_t::eBufferDirty) {
+ // content is meaningless in this case and the whole surface
+ // needs to be redrawn.
+ newDirtyRegion.set(bounds);
+ } else {
+ newDirtyRegion.andSelf(bounds);
+ const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
+ if (backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ !(lcblk->flags & eNoCopyBack))
+ {
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer, copyback);
+ }
+ }
}
- mSurfaceHeapBase[i] = heapBase;
+ mDirtyRegion = newDirtyRegion;
+ mOldDirtyRegion = newDirtyRegion;
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer %d (%p)",
+ mBackbufferIndex, backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ // FIXME: needs some locking here
+
+ if (mLockedBuffer == 0)
+ return BAD_VALUE;
+
+ status_t res = mLockedBuffer->unlock();
+ LOGW_IF(res, "failed unlocking buffer %d (%p)",
+ mBackbufferIndex, mLockedBuffer->handle);
+
+ status_t err = queueBuffer(mLockedBuffer);
+ mLockedBuffer = 0;
+ return err;
+}
+
+void Surface::_send_dirty_region(
+ layer_cblk_t* lcblk, const Region& dirty)
+{
+ const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+ flat_region_t* flat_region = lcblk->region + index;
+ status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+ if (err < NO_ERROR) {
+ // region doesn't fit, use the bounds
+ const Region reg(dirty.bounds());
+ reg.write(flat_region, sizeof(flat_region_t));
+ }
+}
+
+void Surface::setSwapRectangle(const Rect& r) {
+ mSwapRectangle = r;
+}
+
+status_t Surface::getBufferLocked(int index)
+{
+ status_t err = NO_MEMORY;
+ sp<SurfaceBuffer> buffer = mSurface->getBuffer();
+ LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
+ if (buffer != 0) {
+ sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ getBufferMapper().unregisterBuffer(currentBuffer->handle);
+ currentBuffer.clear();
+ }
+ err = getBufferMapper().registerBuffer(buffer->handle);
+ LOGW_IF(err, "map(...) failed %d (%s)", err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
}
}
- return heapBase;
+ return err;
}
}; // namespace android
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..d2cef78 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,27 +29,21 @@
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/IMemory.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
#include <ui/ISurface.h>
#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <ui/Point.h>
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceFlingerSynchro.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include <utils/BpBinder.h>
-
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
@@ -65,7 +59,7 @@ static Mutex gLock;
static sp<ISurfaceComposer> gSurfaceManager;
static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions;
-static sp<IMemory> gServerCblkMemory;
+static sp<IMemoryHeap> gServerCblkMemory;
static volatile surface_flinger_cblk_t* gServerCblk;
const sp<ISurfaceComposer>& _get_surface_manager()
@@ -100,7 +94,7 @@ static volatile surface_flinger_cblk_t const * get_cblk()
if (gServerCblk == 0) {
gServerCblkMemory = sm->getCblk();
LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
- gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
LOGE_IF(gServerCblk==0, "Can't get server control block address");
}
}
@@ -109,50 +103,8 @@ static volatile surface_flinger_cblk_t const * get_cblk()
// ---------------------------------------------------------------------------
-static void copyBlt(const GGLSurface& dst,
- const GGLSurface& src, const Region& reg)
-{
- Region::iterator iterator(reg);
- if (iterator) {
- // NOTE: dst and src must be the same format
- Rect r;
- const size_t bpp = bytesPerPixel(src.format);
- const size_t dbpr = dst.stride * bpp;
- const size_t sbpr = src.stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
- uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-surface_flinger_cblk_t::surface_flinger_cblk_t()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-per_client_cblk_t::per_client_cblk_t()
-{
-}
-
// these functions are used by the clients
-inline status_t per_client_cblk_t::validate(size_t i) const {
+status_t per_client_cblk_t::validate(size_t i) const {
if (uint32_t(i) >= NUM_LAYERS_MAX)
return BAD_INDEX;
if (layers[i].swapState & eInvalidSurface)
@@ -248,8 +200,9 @@ int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
// make sure this buffer is valid
- if (layer->surface[index].bits_offset < 0) {
- return status_t(layer->surface[index].bits_offset);
+ status_t err = layer->surface[index].status;
+ if (err < 0) {
+ return err;
}
if (inspect) {
@@ -273,7 +226,7 @@ done:
uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
{
- // atomically set eFlipRequested and clear eLocked and optionnaly
+ // atomically set eFlipRequested and clear eLocked and optionally
// set eNextFlipPending if eFlipRequested was already set
layer_cblk_t * const layer = layers + i;
@@ -290,7 +243,7 @@ uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
if (oldvalue & eFlipRequested)
newvalue |= eNextFlipPending;
- // if eFlipRequested was alread set, set eNextFlipPending
+ // if eFlipRequested was already set, set eNextFlipPending
} while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
@@ -298,9 +251,9 @@ uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
int(newvalue));
- // from this point, the server can kick in at anytime and use the first
+ // from this point, the server can kick in at any time and use the first
// buffer, so we cannot use it anymore, and we must use the 'other'
- // buffer instead (or wait if it is not availlable yet, see lock_layer).
+ // buffer instead (or wait if it is not available yet, see lock_layer).
return newvalue;
}
@@ -360,9 +313,9 @@ void SurfaceComposerClient::_init(
return;
}
- mClient->getControlBlocks(&mControlMemory);
+ mControlMemory = mClient->getControlBlock();
mSignalServer = new SurfaceFlingerSynchro(sm);
- mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+ mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@@ -376,32 +329,6 @@ status_t SurfaceComposerClient::initCheck() const
return mStatus;
}
-status_t SurfaceComposerClient::validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface)
-{
- SurfaceID index = surface->ID();
- if (cblk == 0) {
- LOGE("cblk is null (surface id=%d, identity=%u)",
- index, surface->getIdentity());
- return NO_INIT;
- }
-
- status_t err = cblk->validate(index);
- if (err != NO_ERROR) {
- LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
- index, surface->getIdentity(), err, strerror(-err));
- return err;
- }
-
- if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
- LOGE("using an invalid surface id=%d, identity=%u should be %d",
- index, surface->getIdentity(), cblk->layers[index].identity);
- return NO_INIT;
- }
-
- return NO_ERROR;
-}
-
sp<IBinder> SurfaceComposerClient::connection() const
{
return (mClient != 0) ? mClient->asBinder() : 0;
@@ -437,9 +364,8 @@ void SurfaceComposerClient::dispose()
{
// this can be called more than once.
- sp<IMemory> controlMemory;
+ sp<IMemoryHeap> controlMemory;
sp<ISurfaceFlingerClient> client;
- sp<IMemoryHeap> surfaceHeap;
{
Mutex::Autolock _lg(gLock);
@@ -462,9 +388,7 @@ void SurfaceComposerClient::dispose()
delete mPrebuiltLayerState;
mPrebuiltLayerState = 0;
controlMemory = mControlMemory;
- surfaceHeap = mSurfaceHeap;
mControlMemory.clear();
- mSurfaceHeap.clear();
mControl = 0;
mStatus = NO_INIT;
}
@@ -528,7 +452,13 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays()
return n;
}
-sp<Surface> SurfaceComposerClient::createSurface(
+
+void SurfaceComposerClient::signalServer()
+{
+ mSignalServer->signal();
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
int pid,
DisplayID display,
uint32_t w,
@@ -536,14 +466,14 @@ sp<Surface> SurfaceComposerClient::createSurface(
PixelFormat format,
uint32_t flags)
{
- sp<Surface> result;
+ sp<SurfaceControl> result;
if (mStatus == NO_ERROR) {
ISurfaceFlingerClient::surface_data_t data;
sp<ISurface> surface = mClient->createSurface(&data, pid,
display, w, h, format, flags);
if (surface != 0) {
if (uint32_t(data.token) < NUM_LAYERS_MAX) {
- result = new Surface(this, surface, data, w, h, format, flags);
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
}
}
}
@@ -568,186 +498,6 @@ status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
return err;
}
-status_t SurfaceComposerClient::nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info)
-{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = surface->mBackbufferIndex;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- info->w = front->w;
- info->h = front->h;
- info->format = front->format;
- info->base = surface->heapBase(1-backIdx);
- info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
- info->bpr = front->bpr;
-
- return 0;
-}
-
-status_t SurfaceComposerClient::lockSurface(
- Surface* surface,
- Surface::SurfaceInfo* other,
- Region* dirty,
- bool blocking)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = cblk->lock_layer(size_t(index),
- per_client_cblk_t::BLOCKING);
- if (backIdx >= 0) {
- surface->mBackbufferIndex = backIdx;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const back = lcblk->surface + backIdx;
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- other->w = back->w;
- other->h = back->h;
- other->format = back->format;
- other->base = surface->heapBase(backIdx);
- other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
- other->bpr = back->bpr;
-
- const Rect bounds(other->w, other->h);
- Region newDirtyRegion;
-
- if (back->flags & surface_info_t::eBufferDirty) {
- /* it is safe to write *back here, because we're guaranteed
- * SurfaceFlinger is not touching it (since it just granted
- * access to us) */
- const_cast<surface_info_t*>(back)->flags &=
- ~surface_info_t::eBufferDirty;
-
- // content is meaningless in this case and the whole surface
- // needs to be redrawn.
-
- newDirtyRegion.set(bounds);
- if (dirty) {
- *dirty = newDirtyRegion;
- }
-
- //if (bytesPerPixel(other->format) == 4) {
- // android_memset32(
- // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
- //} else {
- // android_memset16( // fill with green
- // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
- //}
- }
- else
- {
- if (dirty) {
- dirty->andSelf(Region(bounds));
- newDirtyRegion = *dirty;
- } else {
- newDirtyRegion.set(bounds);
- }
-
- Region copyback;
- if (!(lcblk->flags & eNoCopyBack)) {
- const Region previousDirtyRegion(surface->dirtyRegion());
- copyback = previousDirtyRegion.subtract(newDirtyRegion);
- }
-
- if (!copyback.isEmpty()) {
- // copy front to back
- GGLSurface cb;
- cb.version = sizeof(GGLSurface);
- cb.width = back->w;
- cb.height = back->h;
- cb.stride = back->stride;
- cb.data = (GGLubyte*)surface->heapBase(backIdx);
- cb.data += back->bits_offset;
- cb.format = back->format;
-
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = front->w;
- t.height = front->h;
- t.stride = front->stride;
- t.data = (GGLubyte*)surface->heapBase(1-backIdx);
- t.data += front->bits_offset;
- t.format = front->format;
-
- //const Region copyback(lcblk->region + 1-backIdx);
- copyBlt(cb, t, copyback);
- }
- }
-
- // update dirty region
- surface->setDirtyRegion(newDirtyRegion);
- }
- return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
-}
-
-void SurfaceComposerClient::_signal_server()
-{
- mSignalServer->signal();
-}
-
-void SurfaceComposerClient::_send_dirty_region(
- layer_cblk_t* lcblk, const Region& dirty)
-{
- const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
- flat_region_t* flat_region = lcblk->region + index;
- status_t err = dirty.write(flat_region, sizeof(flat_region_t));
- if (err < NO_ERROR) {
- // region doesn't fit, use the bounds
- const Region reg(dirty.bounds());
- reg.write(flat_region, sizeof(flat_region_t));
- }
-}
-
-status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- Region dirty(surface->dirtyRegion());
- const Rect& swapRect(surface->swapRectangle());
- if (swapRect.isValid()) {
- dirty.set(swapRect);
- }
-
- // transmit the dirty region
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- _send_dirty_region(lcblk, dirty);
- uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
- if (!(newstate & eNextFlipPending))
- _signal_server();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::unlockSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- cblk->unlock_layer(size_t(index));
- return NO_ERROR;
-}
-
void SurfaceComposerClient::openGlobalTransaction()
{
Mutex::Autolock _l(gLock);
@@ -866,14 +616,8 @@ status_t SurfaceComposerClient::closeTransaction()
return NO_ERROR;
}
-layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)
{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface.get());
- if (err != NO_ERROR)
- return 0;
-
// API usage error, do nothing.
if (mTransactionOpen<=0) {
LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
@@ -892,11 +636,11 @@ layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
return mStates.editArray() + i;
}
-layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id)
{
layer_state_t* s;
mLock.lock();
- s = _get_state_l(surface);
+ s = _get_state_l(id);
if (!s) mLock.unlock();
return s;
}
@@ -906,9 +650,9 @@ void SurfaceComposerClient::_unlockLayerState()
mLock.unlock();
}
-status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::ePositionChanged;
s->x = x;
@@ -917,9 +661,9 @@ status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t
return NO_ERROR;
}
-status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eSizeChanged;
s->w = w;
@@ -928,9 +672,9 @@ status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h
return NO_ERROR;
}
-status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eLayerChanged;
s->z = z;
@@ -938,32 +682,32 @@ status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
return NO_ERROR;
}
-status_t SurfaceComposerClient::hide(Surface* surface)
+status_t SurfaceComposerClient::hide(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerHidden,
+ return setFlags(id, ISurfaceComposer::eLayerHidden,
ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+ return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::freeze(Surface* surface)
+status_t SurfaceComposerClient::freeze(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+ return setFlags(id, ISurfaceComposer::eLayerFrozen,
ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::unfreeze(Surface* surface)
+status_t SurfaceComposerClient::unfreeze(SurfaceID id)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+ return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::setFlags(Surface* surface,
+status_t SurfaceComposerClient::setFlags(SurfaceID id,
uint32_t flags, uint32_t mask)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eVisibilityChanged;
s->flags &= ~mask;
@@ -973,11 +717,10 @@ status_t SurfaceComposerClient::setFlags(Surface* surface,
return NO_ERROR;
}
-
status_t SurfaceComposerClient::setTransparentRegionHint(
- Surface* surface, const Region& transparentRegion)
+ SurfaceID id, const Region& transparentRegion)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
@@ -985,9 +728,9 @@ status_t SurfaceComposerClient::setTransparentRegionHint(
return NO_ERROR;
}
-status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eAlphaChanged;
s->alpha = alpha;
@@ -996,11 +739,11 @@ status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
}
status_t SurfaceComposerClient::setMatrix(
- Surface* surface,
+ SurfaceID id,
float dsdx, float dtdx,
float dsdy, float dtdy )
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eMatrixChanged;
layer_state_t::matrix22_t matrix;
@@ -1013,9 +756,9 @@ status_t SurfaceComposerClient::setMatrix(
return NO_ERROR;
}
-status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eFreezeTintChanged;
s->tint = tint;
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
index 5cd9755..c81db71 100644
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -14,19 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlingerSynchro"
-
#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
#include <private/ui/SurfaceFlingerSynchro.h>
@@ -34,61 +22,10 @@ namespace android {
// ---------------------------------------------------------------------------
-SurfaceFlingerSynchro::Barrier::Barrier()
- : state(CLOSED) {
-}
-
-SurfaceFlingerSynchro::Barrier::~Barrier() {
-}
-
-void SurfaceFlingerSynchro::Barrier::open() {
- asm volatile ("":::"memory");
- Mutex::Autolock _l(lock);
- state = OPENED;
- cv.broadcast();
-}
-
-void SurfaceFlingerSynchro::Barrier::close() {
- Mutex::Autolock _l(lock);
- state = CLOSED;
-}
-
-void SurfaceFlingerSynchro::Barrier::waitAndClose()
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- cv.wait(lock);
- }
- state = CLOSED;
-}
-
-status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout)
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- int err = cv.waitRelative(lock, timeout);
- if (err != 0)
- return err;
- }
- state = CLOSED;
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
: mSurfaceComposer(flinger)
{
}
-
-SurfaceFlingerSynchro::SurfaceFlingerSynchro()
-{
-}
-
SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
{
}
@@ -99,24 +36,6 @@ status_t SurfaceFlingerSynchro::signal()
return NO_ERROR;
}
-status_t SurfaceFlingerSynchro::wait()
-{
- mBarrier.waitAndClose();
- return NO_ERROR;
-}
-
-status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
-{
- if (timeout == 0)
- return SurfaceFlingerSynchro::wait();
- return mBarrier.waitAndClose(timeout);
-}
-
-void SurfaceFlingerSynchro::open()
-{
- mBarrier.open();
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
new file mode 100644
index 0000000..6cc4a5a
--- /dev/null
+++ b/libs/ui/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ region.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-region
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/ui/tests/region.cpp b/libs/ui/tests/region.cpp
new file mode 100644
index 0000000..0deb2ba
--- /dev/null
+++ b/libs/ui/tests/region.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Debug.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+using namespace android;
+
+int main()
+{
+ Region reg0( Rect( 0, 0, 100, 100 ) );
+ Region reg1 = reg0;
+ Region reg2, reg3;
+
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(150, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(300, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ //reg2 = reg0 | reg0.translate(0, 100);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+
+ //reg3 = reg0 | reg0.translate(0, 150);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+ //reg3.dump("reg3");
+
+ LOGD("---");
+ reg2 = reg0 | reg0.translate(100, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+ reg2.dump("reg2");
+
+ return 0;
+}
+
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 9bdd64a..59409a2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -32,52 +32,24 @@ commonSources:= \
StopWatch.cpp \
String8.cpp \
String16.cpp \
+ StringArray.cpp \
SystemClock.cpp \
TextOutput.cpp \
Threads.cpp \
- TimerProbe.cpp \
Timers.cpp \
VectorImpl.cpp \
ZipFileCRO.cpp \
ZipFileRO.cpp \
ZipUtils.cpp \
- misc.cpp \
- ported.cpp \
- LogSocket.cpp
+ misc.cpp
-#
-# The cpp files listed here do not belong in the device
-# build. Consult with the swetland before even thinking about
-# putting them in commonSources.
-#
-# They're used by the simulator runtime and by host-side tools like
-# aapt and the simulator front-end.
-#
-hostSources:= \
- InetAddress.cpp \
- Pipe.cpp \
- Socket.cpp \
- ZipEntry.cpp \
- ZipFile.cpp
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
-
-ifeq ($(HOST_OS),linux)
-# Use the futex based mutex and condition variable
-# implementation from android-arm because it's shared mem safe
- LOCAL_SRC_FILES += \
- futex_synchro.c \
- executablepath_linux.cpp
-endif
-ifeq ($(HOST_OS),darwin)
- LOCAL_SRC_FILES += \
- executablepath_darwin.cpp
-endif
+LOCAL_SRC_FILES:= $(commonSources)
LOCAL_MODULE:= libutils
@@ -103,37 +75,18 @@ include $(CLEAR_VARS)
# we have the common sources, plus some device-specific stuff
LOCAL_SRC_FILES:= \
$(commonSources) \
- Binder.cpp \
- BpBinder.cpp \
- IInterface.cpp \
- IMemory.cpp \
- IPCThreadState.cpp \
- MemoryDealer.cpp \
- MemoryBase.cpp \
- MemoryHeapBase.cpp \
- MemoryHeapPmem.cpp \
- Parcel.cpp \
- ProcessState.cpp \
- IPermissionController.cpp \
- IServiceManager.cpp \
Unicode.cpp \
BackupData.cpp \
BackupHelpers.cpp
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_SRC_FILES += $(hostSources)
-endif
-
ifeq ($(TARGET_OS),linux)
-# Use the futex based mutex and condition variable
-# implementation from android-arm because it's shared mem safe
-LOCAL_SRC_FILES += futex_synchro.c
LOCAL_LDLIBS += -lrt -ldl
endif
LOCAL_C_INCLUDES += \
external/zlib \
external/icu4c/common
+
LOCAL_LDLIBS += -lpthread
LOCAL_SHARED_LIBRARIES := \
@@ -144,15 +97,10 @@ LOCAL_SHARED_LIBRARIES := \
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
-LOCAL_SHARED_LIBRARIES += \
- libdl
+LOCAL_SHARED_LIBRARIES += libdl
endif # linux-x86
endif # sim
LOCAL_MODULE:= libutils
-
-#LOCAL_CFLAGS+=
-#LOCAL_LDFLAGS:=
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index cce754a..be04777 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -298,10 +298,12 @@ BackupDataReader::SkipEntityData()
}
if (m_header.entity.dataSize > 0) {
int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
- return pos == -1 ? (int)errno : (int)NO_ERROR;
- } else {
- return NO_ERROR;
+ if (pos == -1) {
+ return errno;
+ }
}
+ SKIP_PADDING();
+ return NO_ERROR;
}
ssize_t
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 2fdaa71..55b6024 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -311,7 +311,8 @@ String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
} else {
void const* start = 0;
name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
- snprintf(tmp, 256, "pc %08lx %s", uintptr_t(ip)-uintptr_t(start), name);
+ snprintf(tmp, 256, "pc %08lx %s",
+ long(uintptr_t(ip)-uintptr_t(start)), name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp
deleted file mode 100644
index c6d49aa..0000000
--- a/libs/utils/IDataConnection.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2006 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 <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Parcel.h>
-
-#include <utils/IDataConnection.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-enum
-{
- CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
-};
-
-class BpDataConnection : public BpInterface<IDataConnection>
-{
-public:
- BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
- : BpInterface<IDataConnection>(impl)
- {
- }
-
- virtual void connect()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IDataConnection::descriptor());
- remote()->transact(CONNECT_TRANSACTION, data, &reply);
- }
-
- virtual void disconnect()
- {
- Parcel data, reply;
- remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code)
- {
- case CONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- connect();
- return NO_ERROR;
- }
-
- case DISCONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- disconnect();
- return NO_ERROR;
- }
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp
deleted file mode 100644
index 39a0a68..0000000
--- a/libs/utils/InetAddress.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-#ifdef HAVE_WINSOCK
-# include <winsock2.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-//# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include <utils/inet_address.h>
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * InetAddress
- * ===========================================================================
- */
-
-// lock for the next couple of functions; could tuck into InetAddress
-static Mutex* gGHBNLock;
-
-/*
- * Lock/unlock access to the hostent struct returned by gethostbyname().
- */
-static inline void lock_gethostbyname(void)
-{
- if (gGHBNLock == NULL)
- gGHBNLock = new Mutex;
- gGHBNLock->lock();
-}
-static inline void unlock_gethostbyname(void)
-{
- assert(gGHBNLock != NULL);
- gGHBNLock->unlock();
-}
-
-
-/*
- * Constructor -- just init members. This is private so that callers
- * are required to use getByName().
- */
-InetAddress::InetAddress(void)
- : mAddress(NULL), mLength(-1), mName(NULL)
-{
-}
-
-/*
- * Destructor -- free address storage.
- */
-InetAddress::~InetAddress(void)
-{
- delete[] (char*) mAddress;
- delete[] mName;
-}
-
-/*
- * Copy constructor.
- */
-InetAddress::InetAddress(const InetAddress& orig)
-{
- *this = orig; // use assignment code
-}
-
-/*
- * Assignment operator.
- */
-InetAddress& InetAddress::operator=(const InetAddress& addr)
-{
- // handle self-assignment
- if (this == &addr)
- return *this;
- // copy mLength and mAddress
- mLength = addr.mLength;
- if (mLength > 0) {
- mAddress = new char[mLength];
- memcpy(mAddress, addr.mAddress, mLength);
- LOG(LOG_DEBUG, "socket",
- "HEY: copied %d bytes in assignment operator\n", mLength);
- } else {
- mAddress = NULL;
- }
- // copy mName
- mName = new char[strlen(addr.mName)+1];
- strcpy(mName, addr.mName);
-
- return *this;
-}
-
-/*
- * Create a new object from a name or a dotted-number IP notation.
- *
- * Returns NULL on failure.
- */
-InetAddress*
-InetAddress::getByName(const char* host)
-{
- InetAddress* newAddr = NULL;
- struct sockaddr_in addr;
- struct hostent* he;
- DurationTimer hostTimer, lockTimer;
-
- // gethostbyname() isn't reentrant, so we need to lock things until
- // we can copy the data out.
- lockTimer.start();
- lock_gethostbyname();
- hostTimer.start();
-
- he = gethostbyname(host);
- if (he == NULL) {
- LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
- unlock_gethostbyname();
- return NULL;
- }
-
- memcpy(&addr.sin_addr, he->h_addr, he->h_length);
- addr.sin_family = he->h_addrtype;
- addr.sin_port = 0;
-
- // got it, unlock us
- hostTimer.stop();
- he = NULL;
- unlock_gethostbyname();
-
- lockTimer.stop();
- if ((long) lockTimer.durationUsecs() > 100000) {
- long lockTime = (long) lockTimer.durationUsecs();
- long hostTime = (long) hostTimer.durationUsecs();
- LOG(LOG_DEBUG, "socket",
- "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
- host, lockTime / 1000000.0, hostTime / 1000000.0,
- (lockTime - hostTime) / 1000000.0);
- }
-
- // Alloc storage and copy it over.
- newAddr = new InetAddress();
- if (newAddr == NULL)
- return NULL;
-
- newAddr->mLength = sizeof(struct sockaddr_in);
- newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
- if (newAddr->mAddress == NULL) {
- delete newAddr;
- return NULL;
- }
- memcpy(newAddr->mAddress, &addr, newAddr->mLength);
-
- // Keep this for debug messages.
- newAddr->mName = new char[strlen(host)+1];
- if (newAddr->mName == NULL) {
- delete newAddr;
- return NULL;
- }
- strcpy(newAddr->mName, host);
-
- return newAddr;
-}
-
-
-/*
- * ===========================================================================
- * InetSocketAddress
- * ===========================================================================
- */
-
-/*
- * Create an address with the host wildcard (INADDR_ANY).
- */
-bool InetSocketAddress::create(int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName("0.0.0.0");
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const InetAddress* addr, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = new InetAddress(*addr); // make a copy
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const char* host, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName(host);
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
deleted file mode 100644
index 55c1b99..0000000
--- a/libs/utils/LogSocket.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2008 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 HAVE_WINSOCK
-//#define SOCKETLOG
-#endif
-
-#ifdef SOCKETLOG
-
-#define LOG_TAG "SOCKETLOG"
-
-#include <string.h>
-#include <cutils/log.h>
-#include "utils/LogSocket.h"
-#include "utils/logger.h"
-#include "cutils/hashmap.h"
-
-// defined in //device/data/etc/event-log-tags
-#define SOCKET_CLOSE_LOG 51000
-
-static Hashmap* statsMap = NULL;
-
-#define LOG_LIST_NUMBER 5
-
-typedef struct SocketStats {
- int fd;
- unsigned int send;
- unsigned int recv;
- unsigned int ip;
- unsigned short port;
- short reason;
-}SocketStats;
-
-SocketStats *get_socket_stats(int fd) {
- if (statsMap == NULL) {
- statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
- }
-
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s == NULL) {
- // LOGD("create SocketStats for fd %d", fd);
- s = (SocketStats*) malloc(sizeof(SocketStats));
- memset(s, 0, sizeof(SocketStats));
- s->fd = fd;
- hashmapPut(statsMap, &s->fd, s);
- }
- return s;
-}
-
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
- // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
- SocketStats *s = get_socket_stats(fd);
- s->ip = ip;
- s->port = port;
-}
-
-void add_send_stats(int fd, int send) {
- if (send <=0) {
- LOGE("add_send_stats send %d", send);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->send += send;
- // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-void add_recv_stats(int fd, int recv) {
- if (recv <=0) {
- LOGE("add_recv_stats recv %d", recv);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->recv += recv;
- // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-char* put_int(char* buf, int value) {
- *buf = EVENT_TYPE_INT;
- buf++;
- memcpy(buf, &value, sizeof(int));
- return buf + sizeof(int);
-}
-
-void log_socket_close(int fd, short reason) {
- if (statsMap) {
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s != NULL) {
- if (s->send != 0 || s->recv != 0) {
- s->reason = reason;
- // 5 int + list type need 2 bytes
- char buf[LOG_LIST_NUMBER * 5 + 2];
- buf[0] = EVENT_TYPE_LIST;
- buf[1] = LOG_LIST_NUMBER;
- char* writePos = buf + 2;
- writePos = put_int(writePos, s->send);
- writePos = put_int(writePos, s->recv);
- writePos = put_int(writePos, s->ip);
- writePos = put_int(writePos, s->port);
- writePos = put_int(writePos, s->reason);
-
- android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
- // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
- }
- hashmapRemove(statsMap, &s->fd);
- free(s);
- }
- }
-}
-
-#else
-void add_send_stats(int fd, int send) {}
-void add_recv_stats(int fd, int recv) {}
-void log_socket_close(int fd, short reason) {}
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
-#endif
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
deleted file mode 100644
index 613906b..0000000
--- a/libs/utils/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Unidirectional pipe.
-//
-
-#include <utils/Pipe.h>
-#include <utils/Log.h>
-
-#if defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-
-/*
- * Constructor. Do little.
- */
-Pipe::Pipe(void)
- : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
- mWriteHandle(kInvalidHandle)
-{
-}
-
-/*
- * Destructor. Use the system-appropriate close call.
- */
-Pipe::~Pipe(void)
-{
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle))
- LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
- mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- FlushFileBuffers((HANDLE)mWriteHandle);
- if (!CloseHandle((HANDLE)mWriteHandle))
- LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
- mWriteHandle);
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
- (int) mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
- (int) mWriteHandle);
- }
-#endif
-}
-
-/*
- * Create the pipe.
- *
- * Use the POSIX stuff for everything but Windows.
- */
-bool Pipe::create(void)
-{
- assert(mReadHandle == kInvalidHandle);
- assert(mWriteHandle == kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- /* we use this across processes, so they need to be inheritable */
- HANDLE handles[2];
- SECURITY_ATTRIBUTES saAttr;
-
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = (unsigned long) handles[0];
- mWriteHandle = (unsigned long) handles[1];
- return true;
-#else
- int fds[2];
-
- if (pipe(fds) != 0) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = fds[0];
- mWriteHandle = fds[1];
- return true;
-#endif
-}
-
-/*
- * Create a "half pipe". Please, no Segway riding.
- */
-bool Pipe::createReader(unsigned long handle)
-{
- mReadHandle = handle;
- assert(mWriteHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Create a "half pipe" for writing.
- */
-bool Pipe::createWriter(unsigned long handle)
-{
- mWriteHandle = handle;
- assert(mReadHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Return "true" if create() has been called successfully.
- */
-bool Pipe::isCreated(void)
-{
- // one or the other should be open
- return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
-}
-
-
-/*
- * Read data from the pipe.
- *
- * For Linux and Darwin, just call read(). For Windows, implement
- * non-blocking reads by calling PeekNamedPipe first.
- */
-int Pipe::read(void* buf, int count)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail = count;
- DWORD bytesRead;
-
- if (mReadNonBlocking) {
- // use PeekNamedPipe to adjust read count expectations
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return -1;
- }
-
- if (totalBytesAvail == 0)
- return 0;
- }
-
- if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
- NULL))
- {
- DWORD err = GetLastError();
- if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
- return 0;
- LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
- return -1;
- }
-
- return (int) bytesRead;
-#else
- int cc;
- cc = ::read(mReadHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Write data to the pipe.
- *
- * POSIX systems are trivial, Windows uses a different call and doesn't
- * handle non-blocking writes.
- *
- * If we add non-blocking support here, we probably want to make it an
- * all-or-nothing write.
- *
- * DO NOT use LOG() here, we could be writing a log message.
- */
-int Pipe::write(const void* buf, int count)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD bytesWritten;
-
- if (mWriteNonBlocking) {
- // BUG: can't use PeekNamedPipe() to get the amount of space
- // left. Looks like we need to use "overlapped I/O" functions.
- // I just don't care that much.
- }
-
- if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
- // can't LOG, use stderr
- fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
- return -1;
- }
-
- return (int) bytesWritten;
-#else
- int cc;
- cc = ::write(mWriteHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Figure out if there is data available on the read fd.
- *
- * We return "true" on error because we want the caller to try to read
- * from the pipe. They'll notice the read failure and do something
- * appropriate.
- */
-bool Pipe::readReady(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail;
-
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return true;
- }
-
- return (totalBytesAvail != 0);
-#else
- errno = 0;
- fd_set readfds;
- struct timeval tv = { 0, 0 };
- int cc;
-
- FD_ZERO(&readfds);
- FD_SET(mReadHandle, &readfds);
-
- cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
- if (cc < 0) {
- LOG(LOG_ERROR, "pipe", "select() failed\n");
- return true;
- } else if (cc == 0) {
- /* timed out, nothing available */
- return false;
- } else if (cc == 1) {
- /* our fd is ready */
- return true;
- } else {
- LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
- return true;
- }
-#endif
-}
-
-/*
- * Enable or disable non-blocking mode for the read descriptor.
- *
- * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
- * actually be in non-blocking mode. If this matters -- i.e. you're not
- * using a select() call -- put a call to readReady() in front of the
- * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
- * Darwin.
- */
-bool Pipe::setReadNonBlocking(bool val)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
- return false;
- }
-#endif
-
- mReadNonBlocking = val;
- return true;
-}
-
-/*
- * Enable or disable non-blocking mode for the write descriptor.
- *
- * As with setReadNonBlocking(), this does not work on the Mac.
- */
-bool Pipe::setWriteNonBlocking(bool val)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
-#endif
-
- mWriteNonBlocking = val;
- return true;
-}
-
-/*
- * Specify whether a file descriptor can be inherited by a child process.
- * Under Linux this means setting the close-on-exec flag, under Windows
- * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
- */
-bool Pipe::disallowReadInherit(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-bool Pipe::disallowWriteInherit(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-
-/*
- * Close read descriptor.
- */
-bool Pipe::closeRead(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing read handle\n");
- return false;
- }
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing read fd\n");
- return false;
- }
- }
-#endif
- mReadHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Close write descriptor.
- */
-bool Pipe::closeWrite(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mWriteHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mWriteHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing write handle\n");
- return false;
- }
- }
-#else
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing write fd\n");
- return false;
- }
- }
-#endif
- mWriteHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Get the read handle.
- */
-unsigned long Pipe::getReadHandle(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
- return mReadHandle;
-}
-
-/*
- * Get the write handle.
- */
-unsigned long Pipe::getWriteHandle(void)
-{
- assert(mWriteHandle != kInvalidHandle);
-
- return mWriteHandle;
-}
-
diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp
deleted file mode 100644
index 51509a3..0000000
--- a/libs/utils/Socket.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-
-#ifdef HAVE_WINSOCK
-// This needs to come first, or Cygwin gets concerned about a potential
-// clash between WinSock and <sys/types.h>.
-# include <winsock2.h>
-#endif
-
-#include <utils/Socket.h>
-#include <utils/inet_address.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#ifndef HAVE_WINSOCK
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * Socket
- * ===========================================================================
- */
-
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET (-1)
-#endif
-#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
-
-/*static*/ bool Socket::mBootInitialized = false;
-
-/*
- * Extract system-dependent error code.
- */
-static inline int getSocketError(void) {
-#ifdef HAVE_WINSOCK
- return WSAGetLastError();
-#else
- return errno;
-#endif
-}
-
-/*
- * One-time initialization for socket code.
- */
-/*static*/ bool Socket::bootInit(void)
-{
-#ifdef HAVE_WINSOCK
- WSADATA wsaData;
- int err;
-
- err = WSAStartup(MAKEWORD(2, 0), &wsaData);
- if (err != 0) {
- LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
- return false;
- }
-
- LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
- LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
-#endif
-
- mBootInitialized = true;
- return true;
-}
-
-/*
- * One-time shutdown for socket code.
- */
-/*static*/ void Socket::finalShutdown(void)
-{
-#ifdef HAVE_WINSOCK
- WSACleanup();
-#endif
- mBootInitialized = false;
-}
-
-
-/*
- * Simple constructor. Allow the application to create us and then make
- * bind/connect calls.
- */
-Socket::Socket(void)
- : mSock(UNDEF_SOCKET)
-{
- if (!mBootInitialized)
- LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
-}
-
-/*
- * Destructor. Closes the socket and resets our storage.
- */
-Socket::~Socket(void)
-{
- close();
-}
-
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const char* host, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(host, port))
- return -1;
-
- //return doConnect(sockAddr);
- int foo;
- foo = doConnect(sockAddr);
- return foo;
-}
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const InetAddress* addr, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(addr, port))
- return -1;
-
- return doConnect(sockAddr);
-}
-
-/*
- * Finish creating a socket by connecting to the remote host.
- *
- * Returns 0 on success.
- */
-int Socket::doConnect(const InetSocketAddress& sockAddr)
-{
-#ifdef HAVE_WINSOCK
- SOCKET sock;
-#else
- int sock;
-#endif
- const InetAddress* addr = sockAddr.getAddress();
- int port = sockAddr.getPort();
- struct sockaddr_in inaddr;
- DurationTimer connectTimer;
-
- assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
- memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
- inaddr.sin_port = htons(port);
-
- //fprintf(stderr, "--- connecting to %s:%d\n",
- // sockAddr.getHostName(), port);
-
- sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock == INVALID_SOCKET) {
- int err = getSocketError();
- LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.start();
-
- if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
- int err = getSocketError();
- LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
- sockAddr.getHostName(), port, err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.stop();
- if ((long) connectTimer.durationUsecs() > 100000) {
- LOG(LOG_INFO, "socket",
- "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
- port, ((long) connectTimer.durationUsecs()) / 1000000.0);
- }
-
- mSock = (unsigned long) sock;
- LOG(LOG_VERBOSE, "socket",
- "--- connected to %s:%d\n", sockAddr.getHostName(), port);
- return 0;
-}
-
-
-/*
- * Close the socket if it needs closing.
- */
-bool Socket::close(void)
-{
- if (mSock != UNDEF_SOCKET) {
- //fprintf(stderr, "--- closing socket %lu\n", mSock);
-#ifdef HAVE_WINSOCK
- if (::closesocket((SOCKET) mSock) != 0)
- return false;
-#else
- if (::close((int) mSock) != 0)
- return false;
-#endif
- }
-
- mSock = UNDEF_SOCKET;
-
- return true;
-}
-
-/*
- * Read data from socket.
- *
- * Standard semantics: read up to "len" bytes into "buf". Returns the
- * number of bytes read, or less than zero on error.
- */
-int Socket::read(void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = recv(sock, (char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-/*
- * Write data to a socket.
- *
- * Standard semantics: write up to "len" bytes into "buf". Returns the
- * number of bytes written, or less than zero on error.
- */
-int Socket::write(const void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = send(sock, (const char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-
-/*
- * ===========================================================================
- * Socket tests
- * ===========================================================================
- */
-
-/*
- * Read all data from the socket. The data is read into a buffer that
- * expands as needed.
- *
- * On exit, the buffer is returned, and the length of the data is stored
- * in "*sz". A null byte is added to the end, but is not included in
- * the length.
- */
-static char* socketReadAll(const Socket& s, int *sz)
-{
- int max, r;
- char *data, *ptr, *tmp;
-
- data = (char*) malloc(max = 32768);
- if (data == NULL)
- return NULL;
-
- ptr = data;
-
- for (;;) {
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max *= 2);
- if(tmp == 0) {
- free(data);
- return 0;
- }
- }
- r = s.read(ptr, max - (ptr - data));
- if (r == 0)
- break;
- if (r < 0) {
- LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
- break;
- }
- ptr += r;
- }
-
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max + 1);
- if (tmp == NULL) {
- free(data);
- return NULL;
- }
- }
- *ptr = '\0';
- *sz = (ptr - data);
- return data;
-}
-
-/*
- * Exercise the Socket class.
- */
-void android::TestSockets(void)
-{
- printf("----- SOCKET TEST ------\n");
- Socket::bootInit();
-
- char* buf = NULL;
- int len, cc;
- const char* kTestStr =
- "GET / HTTP/1.0\n"
- "Connection: close\n"
- "\n";
-
- Socket sock;
- if (sock.connect("www.google.com", 80) != 0) {
- fprintf(stderr, "socket connected failed\n");
- goto bail;
- }
-
- cc = sock.write(kTestStr, strlen(kTestStr));
- if (cc != (int) strlen(kTestStr)) {
- fprintf(stderr, "write failed, res=%d\n", cc);
- goto bail;
- }
- buf = socketReadAll(sock, &len);
-
- printf("GOT '%s'\n", buf);
-
-bail:
- sock.close();
- free(buf);
-}
-
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
index 93f7e4f..4dfa578 100644
--- a/libs/utils/Static.cpp
+++ b/libs/utils/Static.cpp
@@ -20,7 +20,6 @@
#include <private/utils/Static.h>
#include <utils/BufferedTextOutput.h>
-#include <utils/IPCThreadState.h>
#include <utils/Log.h>
namespace android {
@@ -87,34 +86,4 @@ TextOutput& alog(gLogTextOutput);
TextOutput& aout(gStdoutTextOutput);
TextOutput& aerr(gStderrTextOutput);
-#ifndef LIBUTILS_NATIVE
-
-// ------------ ProcessState.cpp
-
-Mutex gProcessMutex;
-sp<ProcessState> gProcess;
-
-class LibUtilsIPCtStatics
-{
-public:
- LibUtilsIPCtStatics()
- {
- }
-
- ~LibUtilsIPCtStatics()
- {
- IPCThreadState::shutdown();
- }
-};
-
-static LibUtilsIPCtStatics gIPCStatics;
-
-// ------------ ServiceManager.cpp
-
-Mutex gDefaultServiceManagerLock;
-sp<IServiceManager> gDefaultServiceManager;
-sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/libs/utils/StringArray.cpp b/libs/utils/StringArray.cpp
new file mode 100644
index 0000000..aa42d68
--- /dev/null
+++ b/libs/utils/StringArray.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/StringArray.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+StringArray::StringArray()
+ : mMax(0), mCurrent(0), mArray(NULL)
+{
+}
+
+StringArray:: ~StringArray() {
+ for (int i = 0; i < mCurrent; i++)
+ delete[] mArray[i];
+ delete[] mArray;
+}
+
+//
+// Add a string. A copy of the string is made.
+//
+bool StringArray::push_back(const char* str) {
+ if (mCurrent >= mMax) {
+ char** tmp;
+
+ if (mMax == 0)
+ mMax = 16; // initial storage
+ else
+ mMax *= 2;
+
+ tmp = new char*[mMax];
+ if (tmp == NULL)
+ return false;
+
+ memcpy(tmp, mArray, mCurrent * sizeof(char*));
+ delete[] mArray;
+ mArray = tmp;
+ }
+
+ int len = strlen(str);
+ mArray[mCurrent] = new char[len+1];
+ memcpy(mArray[mCurrent], str, len+1);
+ mCurrent++;
+
+ return true;
+}
+
+//
+// Delete an entry.
+//
+void StringArray::erase(int idx) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ if (idx < mCurrent-1) {
+ memmove(&mArray[idx], &mArray[idx+1],
+ (mCurrent-1 - idx) * sizeof(char*));
+ }
+ mCurrent--;
+}
+
+//
+// Sort the array.
+//
+void StringArray::sort(int (*compare)(const void*, const void*)) {
+ qsort(mArray, mCurrent, sizeof(char*), compare);
+}
+
+//
+// Pass this to the sort routine to do an ascending alphabetical sort.
+//
+int StringArray::cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
+ return strcmp(*(const char**)pstr1, *(const char**)pstr2);
+}
+
+//
+// Set entry N to specified string.
+// [should use operator[] here]
+//
+void StringArray::setEntry(int idx, const char* str) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ int len = strlen(str);
+ mArray[idx] = new char[len+1];
+ memcpy(mArray[idx], str, len+1);
+}
+
+
+}; // namespace android
diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp
index cebee99..e04823d 100644
--- a/libs/utils/TextOutput.cpp
+++ b/libs/utils/TextOutput.cpp
@@ -22,9 +22,17 @@
#include <stdlib.h>
#include <string.h>
+namespace android {
+
// ---------------------------------------------------------------------------
-namespace android {
+TextOutput::TextOutput() {
+}
+
+TextOutput::~TextOutput() {
+}
+
+// ---------------------------------------------------------------------------
TextOutput& operator<<(TextOutput& to, bool val)
{
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 9287c0b..4036c49 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -38,10 +38,6 @@
# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
#endif
-#if defined(HAVE_FUTEX)
-#include <private/utils/futex_synchro.h>
-#endif
-
#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif
@@ -56,10 +52,6 @@ using namespace android;
// ----------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
-#if 0
-#pragma mark -
-#pragma mark PTHREAD
-#endif
// ----------------------------------------------------------------------------
/*
@@ -163,10 +155,6 @@ android_thread_id_t androidGetThreadId()
// ----------------------------------------------------------------------------
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#pragma mark WIN32_THREADS
-#endif
// ----------------------------------------------------------------------------
/*
@@ -252,11 +240,6 @@ android_thread_id_t androidGetThreadId()
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Common Thread functions
-#endif
-
int androidCreateThread(android_thread_func_t fn, void* arg)
{
return createThreadEtc(fn, arg);
@@ -294,109 +277,9 @@ namespace android {
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Mutex
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-/*
- * Simple pthread wrapper.
- */
-
-Mutex::Mutex()
-{
- _init();
-}
-
-Mutex::Mutex(const char* name)
-{
- // XXX: name not used for now
- _init();
-}
-
-void Mutex::_init()
-{
- pthread_mutex_t* pMutex = new pthread_mutex_t;
- pthread_mutex_init(pMutex, NULL);
- mState = pMutex;
-}
-
-Mutex::~Mutex()
-{
- delete (pthread_mutex_t*) mState;
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- pthread_mutex_unlock((pthread_mutex_t*) mState);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
-
-#define STATE ((futex_mutex_t*) (&mState))
-
-Mutex::Mutex()
-{
- _init();
-}
-
-Mutex::Mutex(const char* name)
-{
- _init();
-}
-
-void
-Mutex::_init()
-{
- futex_mutex_init(STATE);
-}
-
-Mutex::~Mutex()
-{
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- futex_mutex_unlock(STATE);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=futex_mutex_trylock(STATE)) == EINTR) ;
- return -res;
-}
-#undef STATE
-
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
Mutex::Mutex()
{
@@ -456,161 +339,9 @@ status_t Mutex::tryLock()
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Condition
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- pthread_cond_t* pCond = new pthread_cond_t;
-
- pthread_cond_init(pCond, NULL);
- mState = pCond;
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
- pthread_cond_destroy((pthread_cond_t*) mState);
- delete (pthread_cond_t*) mState;
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int cc;
- while ((cc = pthread_cond_wait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- assert(mutex.mState != NULL);
-
- struct timespec ts;
- ts.tv_sec = abstime/1000000000;
- ts.tv_nsec = abstime-(ts.tv_sec*1000000000);
-
- int cc;
- while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- pthread_cond_signal((pthread_cond_t*) mState);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- pthread_cond_broadcast((pthread_cond_t*) mState);
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
-
-#define STATE ((futex_cond_t*) (&mState))
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- futex_cond_init(STATE);
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int res;
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ;
-
- return -res;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- nsecs_t reltime = abstime - systemTime();
- if (reltime <= 0) return true;
- return waitRelative(mutex, reltime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- assert(mutex.mState != NULL);
- int res;
- unsigned msec = ns2ms(reltime);
- if(msec == 0)
- return true;
- // This code will not time out at the correct time if interrupted by signals
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ;
- return res;
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- futex_cond_signal(STATE);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- futex_cond_broadcast(STATE);
-}
-
-#undef STATE
-
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
/*
* Windows doesn't have a condition variable solution. It's possible
@@ -753,14 +484,6 @@ status_t Condition::wait(Mutex& mutex)
return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
}
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- WinCondition* condState = (WinCondition*) mState;
- HANDLE hMutex = (HANDLE) mutex.mState;
-
- return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
-}
-
status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
{
return wait(mutex, systemTime()+reltime);
@@ -841,11 +564,6 @@ void Condition::broadcast()
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Thread::Thread
-#endif
-
/*
* This is our thread object!
*/
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
deleted file mode 100644
index 835480d..0000000
--- a/libs/utils/TimerProbe.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2008 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 <utils/TimerProbe.h>
-
-#if ENABLE_TIMER_PROBE
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "time"
-
-namespace android {
-
-Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
-TimerProbe* TimerProbe::gExecuteChain;
-int TimerProbe::gIndent;
-timespec TimerProbe::gRealBase;
-
-TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
-{
- mNext = gExecuteChain;
- gExecuteChain = this;
- mIndent = gIndent;
- gIndent += 1;
- if (mIndent > 0) {
- if (*slot == 0) {
- int count = gBuckets.add();
- *slot = count;
- Bucket& bucket = gBuckets.editItemAt(count);
- memset(&bucket, 0, sizeof(Bucket));
- bucket.mTag = tag;
- bucket.mSlotPtr = slot;
- bucket.mIndent = mIndent;
- }
- mBucket = *slot;
- }
- clock_gettime(CLOCK_REALTIME, &mRealStart);
- if (gRealBase.tv_sec == 0)
- gRealBase = mRealStart;
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
-}
-
-void TimerProbe::end()
-{
- timespec realEnd, pEnd, tEnd;
- clock_gettime(CLOCK_REALTIME, &realEnd);
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
- print(realEnd, pEnd, tEnd);
- mTag = NULL;
-}
-
-TimerProbe::~TimerProbe()
-{
- if (mTag != NULL)
- end();
- gExecuteChain = mNext;
- gIndent--;
-}
-
-
-uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
-{
- int sec = end.tv_sec - start.tv_sec;
- int nsec = end.tv_nsec - start.tv_nsec;
- if (nsec < 0) {
- sec--;
- nsec += 1000000000;
- }
- return sec * 1000000 + nsec / 1000;
-}
-
-void TimerProbe::print(const timespec& r, const timespec& p,
- const timespec& t) const
-{
- uint32_t es = ElapsedTime(gRealBase, mRealStart);
- uint32_t er = ElapsedTime(mRealStart, r);
- uint32_t ep = ElapsedTime(mPStart, p);
- uint32_t et = ElapsedTime(mTStart, t);
- if (mIndent > 0) {
- Bucket& bucket = gBuckets.editItemAt(mBucket);
- if (bucket.mStart == 0)
- bucket.mStart = es;
- bucket.mReal += er;
- bucket.mProcess += ep;
- bucket.mThread += et;
- bucket.mCount++;
- return;
- }
- int index = 0;
- int buckets = gBuckets.size();
- int count = 1;
- const char* tag = mTag;
- int indent = mIndent;
- do {
- LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
- tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
- er, ep, ep * 100 / er, et, et * 100 / er);
- if (index >= buckets)
- break;
- Bucket& bucket = gBuckets.editItemAt(index);
- count = bucket.mCount;
- es = bucket.mStart;
- er = bucket.mReal;
- ep = bucket.mProcess;
- et = bucket.mThread;
- tag = bucket.mTag;
- indent = bucket.mIndent;
- *bucket.mSlotPtr = 0;
- } while (++index); // always true
- gBuckets.clear();
-}
-
-}; // namespace android
-
-#endif
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 2abc811..784f035 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -18,7 +18,6 @@
// Timer functions.
//
#include <utils/Timers.h>
-#include <utils/ported.h> // may need usleep
#include <utils/Log.h>
#include <stdlib.h>
@@ -54,130 +53,6 @@ nsecs_t systemTime(int clock)
#endif
}
-//#define MONITOR_USLEEP
-
-/*
- * Sleep long enough that we'll wake up "interval" milliseconds after
- * the previous snooze.
- *
- * The "nextTick" argument is updated on each call, and should be passed
- * in every time. Set its fields to zero on the first call.
- *
- * Returns the #of intervals we have overslept, which will be zero if we're
- * on time. [Currently just returns 0 or 1.]
- */
-int sleepForInterval(long interval, struct timeval* pNextTick)
-{
- struct timeval now;
- long long timeBeforeNext;
- long sleepTime = 0;
- bool overSlept = false;
- //int usleepBias = 0;
-
-#ifdef USLEEP_BIAS
- /*
- * Linux likes to add 9000ms or so.
- * [not using this for now]
- */
- //usleepBias = USLEEP_BIAS;
-#endif
-
- gettimeofday(&now, NULL);
-
- if (pNextTick->tv_sec == 0) {
- /* special-case for first time through */
- *pNextTick = now;
- sleepTime = interval;
- android::DurationTimer::addToTimeval(pNextTick, interval);
- } else {
- /*
- * Compute how much time there is before the next tick. If this
- * value is negative, we've run over. If we've run over a little
- * bit we can shorten the next frame to keep the pace steady, but
- * if we've dramatically overshot we need to re-sync.
- */
- timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
- //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // (long) timeBeforeNext);
- if (timeBeforeNext < -interval) {
- /* way over */
- overSlept = true;
- sleepTime = 0;
- *pNextTick = now;
- } else if (timeBeforeNext <= 0) {
- /* slightly over, keep the pace steady */
- overSlept = true;
- sleepTime = 0;
- } else if (timeBeforeNext <= interval) {
- /* right on schedule */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
- /* sleep call returned early; do a longer sleep this time */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval) {
- /* we went back in time -- somebody updated system clock? */
- /* (could also be a *seriously* broken usleep()) */
- LOG(LOG_DEBUG, "",
- " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
- sleepTime = 0;
- *pNextTick = now;
- }
- android::DurationTimer::addToTimeval(pNextTick, interval);
- }
- //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // sleepTime);
-
- /*
- * Sleep for the designated period of time.
- *
- * Linux tends to sleep for longer than requested, often by 17-18ms.
- * MinGW tends to sleep for less than requested, by as much as 14ms,
- * but occasionally oversleeps for 40+ms (looks like some external
- * factors plus round-off on a 64Hz clock). Cygwin is pretty steady.
- *
- * If you start the MinGW version, and then launch the Cygwin version,
- * the MinGW clock becomes more erratic. Not entirely sure why.
- *
- * (There's a lot of stuff here; it's really just a usleep() call with
- * a bunch of instrumentation.)
- */
- if (sleepTime > 0) {
-#if defined(MONITOR_USLEEP)
- struct timeval before, after;
- long long actual;
-
- gettimeofday(&before, NULL);
- usleep((long) sleepTime);
- gettimeofday(&after, NULL);
-
- /* check usleep() accuracy; default Linux threads are pretty sloppy */
- actual = android::DurationTimer::subtractTimevals(&after, &before);
- if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
- (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
- {
- LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
- (long) actual);
- }
-#else
-#ifdef HAVE_WIN32_THREADS
- Sleep( sleepTime/1000 );
-#else
- usleep((long) sleepTime);
-#endif
-#endif
- }
-
- //printf("slept %d\n", sleepTime);
-
- if (overSlept)
- return 1; // close enough
- else
- return 0;
-}
-
-
/*
* ===========================================================================
* DurationTimer
diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
deleted file mode 100644
index 96f9fc4..0000000
--- a/libs/utils/ZipEntry.cpp
+++ /dev/null
@@ -1,696 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-//
-// Access to entries in a Zip archive.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipEntry.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Initialize a new ZipEntry structure from a FILE* positioned at a
- * CentralDirectoryEntry.
- *
- * On exit, the file pointer will be at the start of the next CDE or
- * at the EOCD.
- */
-status_t ZipEntry::initFromCDE(FILE* fp)
-{
- status_t result;
- long posn;
- bool hasDD;
-
- //LOGV("initFromCDE ---\n");
-
- /* read the CDE */
- result = mCDE.read(fp);
- if (result != NO_ERROR) {
- LOGD("mCDE.read failed\n");
- return result;
- }
-
- //mCDE.dump();
-
- /* using the info in the CDE, go load up the LFH */
- posn = ftell(fp);
- if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
- LOGD("local header seek failed (%ld)\n",
- mCDE.mLocalHeaderRelOffset);
- return UNKNOWN_ERROR;
- }
-
- result = mLFH.read(fp);
- if (result != NO_ERROR) {
- LOGD("mLFH.read failed\n");
- return result;
- }
-
- if (fseek(fp, posn, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- //mLFH.dump();
-
- /*
- * We *might* need to read the Data Descriptor at this point and
- * integrate it into the LFH. If this bit is set, the CRC-32,
- * compressed size, and uncompressed size will be zero. In practice
- * these seem to be rare.
- */
- hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
- if (hasDD) {
- // do something clever
- //LOGD("+++ has data descriptor\n");
- }
-
- /*
- * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
- * flag is set, because the LFH is incomplete. (Not a problem, since we
- * prefer the CDE values.)
- */
- if (!hasDD && !compareHeaders()) {
- LOGW("WARNING: header mismatch\n");
- // keep going?
- }
-
- /*
- * If the mVersionToExtract is greater than 20, we may have an
- * issue unpacking the record -- could be encrypted, compressed
- * with something we don't support, or use Zip64 extensions. We
- * can defer worrying about that to when we're extracting data.
- */
-
- return NO_ERROR;
-}
-
-/*
- * Initialize a new entry. Pass in the file name and an optional comment.
- *
- * Initializes the CDE and the LFH.
- */
-void ZipEntry::initNew(const char* fileName, const char* comment)
-{
- assert(fileName != NULL && *fileName != '\0'); // name required
-
- /* most fields are properly initialized by constructor */
- mCDE.mVersionMadeBy = kDefaultMadeBy;
- mCDE.mVersionToExtract = kDefaultVersion;
- mCDE.mCompressionMethod = kCompressStored;
- mCDE.mFileNameLength = strlen(fileName);
- if (comment != NULL)
- mCDE.mFileCommentLength = strlen(comment);
- mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- strcpy((char*) mCDE.mFileName, fileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- /* TODO: stop assuming null-terminated ASCII here? */
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- strcpy((char*) mCDE.mFileComment, comment);
- }
-
- copyCDEtoLFH();
-}
-
-/*
- * Initialize a new entry, starting with the ZipEntry from a different
- * archive.
- *
- * Initializes the CDE and the LFH.
- */
-status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
- const ZipEntry* pEntry)
-{
- /*
- * Copy everything in the CDE over, then fix up the hairy bits.
- */
- memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- if (mCDE.mFileName == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- if (mCDE.mFileComment == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
- }
- if (mCDE.mExtraFieldLength > 0) {
- /* we null-terminate this, though it may not be a string */
- mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
- if (mCDE.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
- mCDE.mExtraFieldLength+1);
- }
-
- /* construct the LFH from the CDE */
- copyCDEtoLFH();
-
- /*
- * The LFH "extra" field is independent of the CDE "extra", so we
- * handle it here.
- */
- assert(mLFH.mExtraField == NULL);
- mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
- if (mLFH.mExtraFieldLength > 0) {
- mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
- if (mLFH.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
- mLFH.mExtraFieldLength+1);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Insert pad bytes in the LFH by tweaking the "extra" field. This will
- * potentially confuse something that put "extra" data in here earlier,
- * but I can't find an actual problem.
- */
-status_t ZipEntry::addPadding(int padding)
-{
- if (padding <= 0)
- return INVALID_OPERATION;
-
- //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
- // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
-
- if (mLFH.mExtraFieldLength > 0) {
- /* extend existing field */
- unsigned char* newExtra;
-
- newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
- if (newExtra == NULL)
- return NO_MEMORY;
- memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
- memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
-
- delete[] mLFH.mExtraField;
- mLFH.mExtraField = newExtra;
- mLFH.mExtraFieldLength += padding;
- } else {
- /* create new field */
- mLFH.mExtraField = new unsigned char[padding];
- memset(mLFH.mExtraField, 0, padding);
- mLFH.mExtraFieldLength = padding;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Set the fields in the LFH equal to the corresponding fields in the CDE.
- *
- * This does not touch the LFH "extra" field.
- */
-void ZipEntry::copyCDEtoLFH(void)
-{
- mLFH.mVersionToExtract = mCDE.mVersionToExtract;
- mLFH.mGPBitFlag = mCDE.mGPBitFlag;
- mLFH.mCompressionMethod = mCDE.mCompressionMethod;
- mLFH.mLastModFileTime = mCDE.mLastModFileTime;
- mLFH.mLastModFileDate = mCDE.mLastModFileDate;
- mLFH.mCRC32 = mCDE.mCRC32;
- mLFH.mCompressedSize = mCDE.mCompressedSize;
- mLFH.mUncompressedSize = mCDE.mUncompressedSize;
- mLFH.mFileNameLength = mCDE.mFileNameLength;
- // the "extra field" is independent
-
- delete[] mLFH.mFileName;
- if (mLFH.mFileNameLength > 0) {
- mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
- strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
- } else {
- mLFH.mFileName = NULL;
- }
-}
-
-/*
- * Set some information about a file after we add it.
- */
-void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod)
-{
- mCDE.mCompressionMethod = compressionMethod;
- mCDE.mCRC32 = crc32;
- mCDE.mCompressedSize = compLen;
- mCDE.mUncompressedSize = uncompLen;
- mCDE.mCompressionMethod = compressionMethod;
- if (compressionMethod == kCompressDeflated) {
- mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
- }
- copyCDEtoLFH();
-}
-
-/*
- * See if the data in mCDE and mLFH match up. This is mostly useful for
- * debugging these classes, but it can be used to identify damaged
- * archives.
- *
- * Returns "false" if they differ.
- */
-bool ZipEntry::compareHeaders(void) const
-{
- if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
- LOGV("cmp: VersionToExtract\n");
- return false;
- }
- if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
- LOGV("cmp: GPBitFlag\n");
- return false;
- }
- if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
- LOGV("cmp: CompressionMethod\n");
- return false;
- }
- if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
- LOGV("cmp: LastModFileTime\n");
- return false;
- }
- if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
- LOGV("cmp: LastModFileDate\n");
- return false;
- }
- if (mCDE.mCRC32 != mLFH.mCRC32) {
- LOGV("cmp: CRC32\n");
- return false;
- }
- if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
- LOGV("cmp: CompressedSize\n");
- return false;
- }
- if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
- LOGV("cmp: UncompressedSize\n");
- return false;
- }
- if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
- LOGV("cmp: FileNameLength\n");
- return false;
- }
-#if 0 // this seems to be used for padding, not real data
- if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
- LOGV("cmp: ExtraFieldLength\n");
- return false;
- }
-#endif
- if (mCDE.mFileName != NULL) {
- if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
- LOGV("cmp: FileName\n");
- return false;
- }
- }
-
- return true;
-}
-
-
-/*
- * Convert the DOS date/time stamp into a UNIX time stamp.
- */
-time_t ZipEntry::getModWhen(void) const
-{
- struct tm parts;
-
- parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
- parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
- parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
- parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
- parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
- parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
- parts.tm_wday = parts.tm_yday = 0;
- parts.tm_isdst = -1; // DST info "not available"
-
- return mktime(&parts);
-}
-
-/*
- * Set the CDE/LFH timestamp from UNIX time.
- */
-void ZipEntry::setModWhen(time_t when)
-{
-#ifdef HAVE_LOCALTIME_R
- struct tm tmResult;
-#endif
- time_t even;
- unsigned short zdate, ztime;
-
- struct tm* ptm;
-
- /* round up to an even number of seconds */
- even = (time_t)(((unsigned long)(when) + 1) & (~1));
-
- /* expand */
-#ifdef HAVE_LOCALTIME_R
- ptm = localtime_r(&even, &tmResult);
-#else
- ptm = localtime(&even);
-#endif
-
- int year;
- year = ptm->tm_year;
- if (year < 80)
- year = 80;
-
- zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
- ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
-
- mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
- mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::LocalFileHeader
- * ===========================================================================
- */
-
-/*
- * Read a local file header.
- *
- * On entry, "fp" points to the signature at the start of the header.
- * On exit, "fp" points to the start of data.
- */
-status_t ZipEntry::LocalFileHeader::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kLFHLen];
-
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
-
- if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
-
- // TODO: validate sizes
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* grab extra field */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a local file header.
- */
-status_t ZipEntry::LocalFileHeader::write(FILE* fp)
-{
- unsigned char buf[kLFHLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x0e], mCRC32);
- ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
-
- if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Dump the contents of a LocalFileHeader object.
- */
-void ZipEntry::LocalFileHeader::dump(void) const
-{
- LOGD(" LocalFileHeader contents:\n");
- LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u\n",
- mFileNameLength, mExtraFieldLength);
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::CentralDirEntry
- * ===========================================================================
- */
-
-/*
- * Read the central dir entry that appears next in the file.
- *
- * On entry, "fp" should be positioned on the signature bytes for the
- * entry. On exit, "fp" will point at the signature word for the next
- * entry or for the EOCD.
- */
-status_t ZipEntry::CentralDirEntry::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kCDELen];
-
- /* no re-use */
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
- assert(mFileComment == NULL);
-
- if (fread(buf, 1, kCDELen, fp) != kCDELen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("Whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
- mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
- mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
- mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
- mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
- mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
-
- // TODO: validate sizes and offsets
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* read "extra field" */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-
- /* grab comment, if any */
- if (mFileCommentLength != 0) {
- mFileComment = new unsigned char[mFileCommentLength+1];
- if (mFileComment == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileComment[mFileCommentLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a central dir entry.
- */
-status_t ZipEntry::CentralDirEntry::write(FILE* fp)
-{
- unsigned char buf[kCDELen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
- ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x10], mCRC32);
- ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
- ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
- ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
- ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
- ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
- ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
-
- if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- /* write comment */
- if (mFileCommentLength != 0) {
- if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of a CentralDirEntry object.
- */
-void ZipEntry::CentralDirEntry::dump(void) const
-{
- LOGD(" CentralDirEntry contents:\n");
- LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
- mFileNameLength, mExtraFieldLength, mFileCommentLength);
- LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
- mDiskNumberStart, mInternalAttrs, mExternalAttrs,
- mLocalHeaderRelOffset);
-
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
- if (mFileComment != NULL)
- LOGD(" comment: '%s'\n", mFileComment);
-}
-
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
deleted file mode 100644
index 6f27d17..0000000
--- a/libs/utils/ZipFile.cpp
+++ /dev/null
@@ -1,1296 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-//
-// Access to Zip archives.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipFile.h>
-#include <utils/ZipUtils.h>
-#include <utils/Log.h>
-
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8 // normally in zutil.h?
-
-#include <memory.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Some environments require the "b", some choke on it.
- */
-#define FILE_OPEN_RO "rb"
-#define FILE_OPEN_RW "r+b"
-#define FILE_OPEN_RW_CREATE "w+b"
-
-/* should live somewhere else? */
-static status_t errnoToStatus(int err)
-{
- if (err == ENOENT)
- return NAME_NOT_FOUND;
- else if (err == EACCES)
- return PERMISSION_DENIED;
- else
- return UNKNOWN_ERROR;
-}
-
-/*
- * Open a file and parse its guts.
- */
-status_t ZipFile::open(const char* zipFileName, int flags)
-{
- bool newArchive = false;
-
- assert(mZipFp == NULL); // no reopen
-
- if ((flags & kOpenTruncate))
- flags |= kOpenCreate; // trunc implies create
-
- if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
- return INVALID_OPERATION; // not both
- if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
- return INVALID_OPERATION; // not neither
- if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
- return INVALID_OPERATION; // create requires write
-
- if (flags & kOpenTruncate) {
- newArchive = true;
- } else {
- newArchive = (access(zipFileName, F_OK) != 0);
- if (!(flags & kOpenCreate) && newArchive) {
- /* not creating, must already exist */
- LOGD("File %s does not exist", zipFileName);
- return NAME_NOT_FOUND;
- }
- }
-
- /* open the file */
- const char* openflags;
- if (flags & kOpenReadWrite) {
- if (newArchive)
- openflags = FILE_OPEN_RW_CREATE;
- else
- openflags = FILE_OPEN_RW;
- } else {
- openflags = FILE_OPEN_RO;
- }
- mZipFp = fopen(zipFileName, openflags);
- if (mZipFp == NULL) {
- int err = errno;
- LOGD("fopen failed: %d\n", err);
- return errnoToStatus(err);
- }
-
- status_t result;
- if (!newArchive) {
- /*
- * Load the central directory. If that fails, then this probably
- * isn't a Zip archive.
- */
- result = readCentralDir();
- } else {
- /*
- * Newly-created. The EndOfCentralDir constructor actually
- * sets everything to be the way we want it (all zeroes). We
- * set mNeedCDRewrite so that we create *something* if the
- * caller doesn't add any files. (We could also just unlink
- * the file if it's brand new and nothing was added, but that's
- * probably doing more than we really should -- the user might
- * have a need for empty zip files.)
- */
- mNeedCDRewrite = true;
- result = NO_ERROR;
- }
-
- if (flags & kOpenReadOnly)
- mReadOnly = true;
- else
- assert(!mReadOnly);
-
- return result;
-}
-
-/*
- * Return the Nth entry in the archive.
- */
-ZipEntry* ZipFile::getEntryByIndex(int idx) const
-{
- if (idx < 0 || idx >= (int) mEntries.size())
- return NULL;
-
- return mEntries[idx];
-}
-
-/*
- * Find an entry by name.
- */
-ZipEntry* ZipFile::getEntryByName(const char* fileName) const
-{
- /*
- * Do a stupid linear string-compare search.
- *
- * There are various ways to speed this up, especially since it's rare
- * to intermingle changes to the archive with "get by name" calls. We
- * don't want to sort the mEntries vector itself, however, because
- * it's used to recreate the Central Directory.
- *
- * (Hash table works, parallel list of pointers in sorted order is good.)
- */
- int idx;
-
- for (idx = mEntries.size()-1; idx >= 0; idx--) {
- ZipEntry* pEntry = mEntries[idx];
- if (!pEntry->getDeleted() &&
- strcmp(fileName, pEntry->getFileName()) == 0)
- {
- return pEntry;
- }
- }
-
- return NULL;
-}
-
-/*
- * Empty the mEntries vector.
- */
-void ZipFile::discardEntries(void)
-{
- int count = mEntries.size();
-
- while (--count >= 0)
- delete mEntries[count];
-
- mEntries.clear();
-}
-
-
-/*
- * Find the central directory and read the contents.
- *
- * The fun thing about ZIP archives is that they may or may not be
- * readable from start to end. In some cases, notably for archives
- * that were written to stdout, the only length information is in the
- * central directory at the end of the file.
- *
- * Of course, the central directory can be followed by a variable-length
- * comment field, so we have to scan through it backwards. The comment
- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
- * itself, plus apparently sometimes people throw random junk on the end
- * just for the fun of it.
- *
- * This is all a little wobbly. If the wrong value ends up in the EOCD
- * area, we're hosed. This appears to be the way that everbody handles
- * it though, so we're in pretty good company if this fails.
- */
-status_t ZipFile::readCentralDir(void)
-{
- status_t result = NO_ERROR;
- unsigned char* buf = NULL;
- off_t fileLength, seekStart;
- long readAmount;
- int i;
-
- fseek(mZipFp, 0, SEEK_END);
- fileLength = ftell(mZipFp);
- rewind(mZipFp);
-
- /* too small to be a ZIP archive? */
- if (fileLength < EndOfCentralDir::kEOCDLen) {
- LOGD("Length is %ld -- too small\n", (long)fileLength);
- result = INVALID_OPERATION;
- goto bail;
- }
-
- buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
- if (buf == NULL) {
- LOGD("Failure allocating %d bytes for EOCD search",
- EndOfCentralDir::kMaxEOCDSearch);
- result = NO_MEMORY;
- goto bail;
- }
-
- if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
- seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
- readAmount = EndOfCentralDir::kMaxEOCDSearch;
- } else {
- seekStart = 0;
- readAmount = (long) fileLength;
- }
- if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
- LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* read the last part of the file into the buffer */
- if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
- LOGD("short file? wanted %ld\n", readAmount);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* find the end-of-central-dir magic */
- for (i = readAmount - 4; i >= 0; i--) {
- if (buf[i] == 0x50 &&
- ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
- {
- LOGV("+++ Found EOCD at buf+%d\n", i);
- break;
- }
- }
- if (i < 0) {
- LOGD("EOCD not found, not Zip\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /* extract eocd values */
- result = mEOCD.readBuf(buf + i, readAmount - i);
- if (result != NO_ERROR) {
- LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
- goto bail;
- }
- //mEOCD.dump();
-
- if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
- mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
- {
- LOGD("Archive spanning not supported\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /*
- * So far so good. "mCentralDirSize" is the size in bytes of the
- * central directory, so we can just seek back that far to find it.
- * We can also seek forward mCentralDirOffset bytes from the
- * start of the file.
- *
- * We're not guaranteed to have the rest of the central dir in the
- * buffer, nor are we guaranteed that the central dir will have any
- * sort of convenient size. We need to skip to the start of it and
- * read the header, then the other goodies.
- *
- * The only thing we really need right now is the file comment, which
- * we're hoping to preserve.
- */
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- LOGD("Failure seeking to central dir offset %ld\n",
- mEOCD.mCentralDirOffset);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Loop through and read the central dir entries.
- */
- LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
- int entry;
- for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
- ZipEntry* pEntry = new ZipEntry;
-
- result = pEntry->initFromCDE(mZipFp);
- if (result != NO_ERROR) {
- LOGD("initFromCDE failed\n");
- delete pEntry;
- goto bail;
- }
-
- mEntries.add(pEntry);
- }
-
-
- /*
- * If all went well, we should now be back at the EOCD.
- */
- {
- unsigned char checkBuf[4];
- if (fread(checkBuf, 1, 4, mZipFp) != 4) {
- LOGD("EOCD check read failed\n");
- result = INVALID_OPERATION;
- goto bail;
- }
- if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
- LOGD("EOCD read check failed\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
- LOGV("+++ EOCD read check passed\n");
- }
-
-bail:
- delete[] buf;
- return result;
-}
-
-
-/*
- * Add a new file to the archive.
- *
- * This requires creating and populating a ZipEntry structure, and copying
- * the data into the file at the appropriate position. The "appropriate
- * position" is the current location of the central directory, which we
- * casually overwrite (we can put it back later).
- *
- * If we were concerned about safety, we would want to make all changes
- * in a temp file and then overwrite the original after everything was
- * safely written. Not really a concern for us.
- */
-status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result = NO_ERROR;
- long lfhPosn, startPosn, endPosn, uncompressedLen;
- FILE* inputFp = NULL;
- unsigned long crc;
- time_t modWhen;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- assert(compressionMethod == ZipEntry::kCompressDeflated ||
- compressionMethod == ZipEntry::kCompressStored);
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- /* make sure it doesn't already exist */
- if (getEntryByName(storageName) != NULL)
- return ALREADY_EXISTS;
-
- if (!data) {
- inputFp = fopen(fileName, FILE_OPEN_RO);
- if (inputFp == NULL)
- return errnoToStatus(errno);
- }
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- pEntry->initNew(storageName, NULL);
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH, even though it's still mostly blank. We need it
- * as a place-holder. In theory the LFH isn't necessary, but in
- * practice some utilities demand it.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
- startPosn = ftell(mZipFp);
-
- /*
- * Copy the data in, possibly compressing it as we go.
- */
- if (sourceType == ZipEntry::kCompressStored) {
- if (compressionMethod == ZipEntry::kCompressDeflated) {
- bool failed = false;
- result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
- if (result != NO_ERROR) {
- LOGD("compression failed, storing\n");
- failed = true;
- } else {
- /*
- * Make sure it has compressed "enough". This probably ought
- * to be set through an API call, but I don't expect our
- * criteria to change over time.
- */
- long src = inputFp ? ftell(inputFp) : size;
- long dst = ftell(mZipFp) - startPosn;
- if (dst + (dst / 10) > src) {
- LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
- src, dst);
- failed = true;
- }
- }
-
- if (failed) {
- compressionMethod = ZipEntry::kCompressStored;
- if (inputFp) rewind(inputFp);
- fseek(mZipFp, startPosn, SEEK_SET);
- /* fall through to kCompressStored case */
- }
- }
- /* handle "no compression" request, or failed compression from above */
- if (compressionMethod == ZipEntry::kCompressStored) {
- if (inputFp) {
- result = copyFpToFp(mZipFp, inputFp, &crc);
- } else {
- result = copyDataToFp(mZipFp, data, size, &crc);
- }
- if (result != NO_ERROR) {
- // don't need to truncate; happens in CDE rewrite
- LOGD("failed copying data in\n");
- goto bail;
- }
- }
-
- // currently seeked to end of file
- uncompressedLen = inputFp ? ftell(inputFp) : size;
- } else if (sourceType == ZipEntry::kCompressDeflated) {
- /* we should support uncompressed-from-compressed, but it's not
- * important right now */
- assert(compressionMethod == ZipEntry::kCompressDeflated);
-
- bool scanResult;
- int method;
- long compressedLen;
-
- scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
- &compressedLen, &crc);
- if (!scanResult || method != ZipEntry::kCompressDeflated) {
- LOGD("this isn't a deflated gzip file?");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
- if (result != NO_ERROR) {
- LOGD("failed copying gzip data in\n");
- goto bail;
- }
- } else {
- assert(false);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * We could write the "Data Descriptor", but there doesn't seem to
- * be any point since we're going to go back and write the LFH.
- *
- * Update file offsets.
- */
- endPosn = ftell(mZipFp); // seeked to end of compressed data
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
- compressionMethod);
- modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
- pEntry->setModWhen(modWhen);
- pEntry->setLFHOffset(lfhPosn);
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Go back and write the LFH.
- */
- if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
-bail:
- if (inputFp != NULL)
- fclose(inputFp);
- delete pEntry;
- return result;
-}
-
-/*
- * Add an entry by copying it from another zip file. If "padding" is
- * nonzero, the specified number of bytes will be added to the "extra"
- * field in the header.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
-status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result;
- long lfhPosn, endPosn;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- if (pEntry == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
- if (result != NO_ERROR)
- goto bail;
- if (padding != 0) {
- result = pEntry->addPadding(padding);
- if (result != NO_ERROR)
- goto bail;
- }
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH. Since we're not recompressing the data, we already
- * have all of the fields filled out.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Copy the data over.
- *
- * If the "has data descriptor" flag is set, we want to copy the DD
- * fields as well. This is a fixed-size area immediately following
- * the data.
- */
- if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- off_t copyLen;
- copyLen = pSourceEntry->getCompressedLen();
- if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
- copyLen += ZipEntry::kDataDescriptorLen;
-
- if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
- != NO_ERROR)
- {
- LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Update file offsets.
- */
- endPosn = ftell(mZipFp);
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
- result = NO_ERROR;
-
-bail:
- delete pEntry;
- return result;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data.
- */
-status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (1) {
- count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
- if (ferror(srcFp) || ferror(dstFp))
- return errnoToStatus(errno);
- if (count == 0)
- break;
-
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "dstFp" will be seeked immediately past the data.
- */
-status_t ZipFile::copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32)
-{
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
- if (size > 0) {
- *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
- if (fwrite(data, 1, size, dstFp) != size) {
- LOGD("fwrite %d bytes failed\n", (int) size);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy some of the bytes in "src" to "dst".
- *
- * If "pCRC32" is NULL, the CRC will not be computed.
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data just written.
- */
-status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (length) {
- long readSize;
-
- readSize = sizeof(tmpBuf);
- if (readSize > length)
- readSize = length;
-
- count = fread(tmpBuf, 1, readSize, srcFp);
- if ((long) count != readSize) { // error or unexpected EOF
- LOGD("fread %d bytes failed\n", (int) readSize);
- return UNKNOWN_ERROR;
- }
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
-
- length -= readSize;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Compress all of the data in "srcFp" and write it to "dstFp".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the compressed data.
- */
-status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
- const void* data, size_t size, unsigned long* pCRC32)
-{
- status_t result = NO_ERROR;
- const size_t kBufSize = 32768;
- unsigned char* inBuf = NULL;
- unsigned char* outBuf = NULL;
- z_stream zstream;
- bool atEof = false; // no feof() aviailable yet
- unsigned long crc;
- int zerr;
-
- /*
- * Create an input buffer and an output buffer.
- */
- inBuf = new unsigned char[kBufSize];
- outBuf = new unsigned char[kBufSize];
- if (inBuf == NULL || outBuf == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- zstream.data_type = Z_UNKNOWN;
-
- zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
- Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
- if (zerr != Z_OK) {
- result = UNKNOWN_ERROR;
- if (zerr == Z_VERSION_ERROR) {
- LOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
- }
-
- crc = crc32(0L, Z_NULL, 0);
-
- /*
- * Loop while we have data.
- */
- do {
- size_t getSize;
- int flush;
-
- /* only read if the input buffer is empty */
- if (zstream.avail_in == 0 && !atEof) {
- LOGV("+++ reading %d bytes\n", (int)kBufSize);
- if (data) {
- getSize = size > kBufSize ? kBufSize : size;
- memcpy(inBuf, data, getSize);
- data = ((const char*)data) + getSize;
- size -= getSize;
- } else {
- getSize = fread(inBuf, 1, kBufSize, srcFp);
- if (ferror(srcFp)) {
- LOGD("deflate read failed (errno=%d)\n", errno);
- goto z_bail;
- }
- }
- if (getSize < kBufSize) {
- LOGV("+++ got %d bytes, EOF reached\n",
- (int)getSize);
- atEof = true;
- }
-
- crc = crc32(crc, inBuf, getSize);
-
- zstream.next_in = inBuf;
- zstream.avail_in = getSize;
- }
-
- if (atEof)
- flush = Z_FINISH; /* tell zlib that we're done */
- else
- flush = Z_NO_FLUSH; /* more to come! */
-
- zerr = deflate(&zstream, flush);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
- result = UNKNOWN_ERROR;
- goto z_bail;
- }
-
- /* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
- {
- LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
- if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
- (size_t)(zstream.next_out - outBuf))
- {
- LOGD("write %d failed in deflate\n",
- (int) (zstream.next_out - outBuf));
- goto z_bail;
- }
-
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- *pCRC32 = crc;
-
-z_bail:
- deflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- delete[] inBuf;
- delete[] outBuf;
-
- return result;
-}
-
-/*
- * Mark an entry as deleted.
- *
- * We will eventually need to crunch the file down, but if several files
- * are being removed (perhaps as part of an "update" process) we can make
- * things considerably faster by deferring the removal to "flush" time.
- */
-status_t ZipFile::remove(ZipEntry* pEntry)
-{
- /*
- * Should verify that pEntry is actually part of this archive, and
- * not some stray ZipEntry from a different file.
- */
-
- /* mark entry as deleted, and mark archive as dirty */
- pEntry->setDeleted();
- mNeedCDRewrite = true;
- return NO_ERROR;
-}
-
-/*
- * Flush any pending writes.
- *
- * In particular, this will crunch out deleted entries, and write the
- * Central Directory and EOCD if we have stomped on them.
- */
-status_t ZipFile::flush(void)
-{
- status_t result = NO_ERROR;
- long eocdPosn;
- int i, count;
-
- if (mReadOnly)
- return INVALID_OPERATION;
- if (!mNeedCDRewrite)
- return NO_ERROR;
-
- assert(mZipFp != NULL);
-
- result = crunchArchive();
- if (result != NO_ERROR)
- return result;
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- count = mEntries.size();
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- pEntry->mCDE.write(mZipFp);
- }
-
- eocdPosn = ftell(mZipFp);
- mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
-
- mEOCD.write(mZipFp);
-
- /*
- * If we had some stuff bloat up during compression and get replaced
- * with plain files, or if we deleted some entries, there's a lot
- * of wasted space at the end of the file. Remove it now.
- */
- if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
- LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
- // not fatal
- }
-
- /* should we clear the "newly added" flag in all entries now? */
-
- mNeedCDRewrite = false;
- return NO_ERROR;
-}
-
-/*
- * Crunch deleted files out of an archive by shifting the later files down.
- *
- * Because we're not using a temp file, we do the operation inside the
- * current file.
- */
-status_t ZipFile::crunchArchive(void)
-{
- status_t result = NO_ERROR;
- int i, count;
- long delCount, adjust;
-
-#if 0
- printf("CONTENTS:\n");
- for (i = 0; i < (int) mEntries.size(); i++) {
- printf(" %d: lfhOff=%ld del=%d\n",
- i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
- }
- printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
-#endif
-
- /*
- * Roll through the set of files, shifting them as appropriate. We
- * could probably get a slight performance improvement by sliding
- * multiple files down at once (because we could use larger reads
- * when operating on batches of small files), but it's not that useful.
- */
- count = mEntries.size();
- delCount = adjust = 0;
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- long span;
-
- if (pEntry->getLFHOffset() != 0) {
- long nextOffset;
-
- /* Get the length of this entry by finding the offset
- * of the next entry. Directory entries don't have
- * file offsets, so we need to find the next non-directory
- * entry.
- */
- nextOffset = 0;
- for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
- nextOffset = mEntries[ii]->getLFHOffset();
- if (nextOffset == 0)
- nextOffset = mEOCD.mCentralDirOffset;
- span = nextOffset - pEntry->getLFHOffset();
-
- assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
- } else {
- /* This is a directory entry. It doesn't have
- * any actual file contents, so there's no need to
- * move anything.
- */
- span = 0;
- }
-
- //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
- // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
-
- if (pEntry->getDeleted()) {
- adjust += span;
- delCount++;
-
- delete pEntry;
- mEntries.removeAt(i);
-
- /* adjust loop control */
- count--;
- i--;
- } else if (span != 0 && adjust > 0) {
- /* shuffle this entry back */
- //printf("+++ Shuffling '%s' back %ld\n",
- // pEntry->getFileName(), adjust);
- result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
- pEntry->getLFHOffset(), span);
- if (result != NO_ERROR) {
- /* this is why you use a temp file */
- LOGE("error during crunch - archive is toast\n");
- return result;
- }
-
- pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
- }
- }
-
- /*
- * Fix EOCD info. We have to wait until the end to do some of this
- * because we use mCentralDirOffset to determine "span" for the
- * last entry.
- */
- mEOCD.mCentralDirOffset -= adjust;
- mEOCD.mNumEntries -= delCount;
- mEOCD.mTotalNumEntries -= delCount;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
-
- assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
- assert(mEOCD.mNumEntries == count);
-
- return result;
-}
-
-/*
- * Works like memmove(), but on pieces of a file.
- */
-status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
-{
- if (dst == src || n <= 0)
- return NO_ERROR;
-
- unsigned char readBuf[32768];
-
- if (dst < src) {
- /* shift stuff toward start of file; must read from start */
- while (n != 0) {
- size_t getSize = sizeof(readBuf);
- if (getSize > n)
- getSize = n;
-
- if (fseek(fp, (long) src, SEEK_SET) != 0) {
- LOGD("filemove src seek %ld failed\n", (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fread(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove read %ld off=%ld failed\n",
- (long) getSize, (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fseek(fp, (long) dst, SEEK_SET) != 0) {
- LOGD("filemove dst seek %ld failed\n", (long) dst);
- return UNKNOWN_ERROR;
- }
-
- if (fwrite(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove write %ld off=%ld failed\n",
- (long) getSize, (long) dst);
- return UNKNOWN_ERROR;
- }
-
- src += getSize;
- dst += getSize;
- n -= getSize;
- }
- } else {
- /* shift stuff toward end of file; must read from end */
- assert(false); // write this someday, maybe
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Get the modification time from a file descriptor.
- */
-time_t ZipFile::getModTime(int fd)
-{
- struct stat sb;
-
- if (fstat(fd, &sb) < 0) {
- LOGD("HEY: fstat on fd %d failed\n", fd);
- return (time_t) -1;
- }
-
- return sb.st_mtime;
-}
-
-
-#if 0 /* this is a bad idea */
-/*
- * Get a copy of the Zip file descriptor.
- *
- * We don't allow this if the file was opened read-write because we tend
- * to leave the file contents in an uncertain state between calls to
- * flush(). The duplicated file descriptor should only be valid for reads.
- */
-int ZipFile::getZipFd(void) const
-{
- if (!mReadOnly)
- return INVALID_OPERATION;
- assert(mZipFp != NULL);
-
- int fd;
- fd = dup(fileno(mZipFp));
- if (fd < 0) {
- LOGD("didn't work, errno=%d\n", errno);
- }
-
- return fd;
-}
-#endif
-
-
-#if 0
-/*
- * Expand data.
- */
-bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
-{
- return false;
-}
-#endif
-
-// free the memory when you're done
-void* ZipFile::uncompress(const ZipEntry* entry)
-{
- size_t unlen = entry->getUncompressedLen();
- size_t clen = entry->getCompressedLen();
-
- void* buf = malloc(unlen);
- if (buf == NULL) {
- return NULL;
- }
-
- fseek(mZipFp, 0, SEEK_SET);
-
- off_t offset = entry->getFileOffset();
- if (fseek(mZipFp, offset, SEEK_SET) != 0) {
- goto bail;
- }
-
- switch (entry->getCompressionMethod())
- {
- case ZipEntry::kCompressStored: {
- ssize_t amt = fread(buf, 1, unlen, mZipFp);
- if (amt != (ssize_t)unlen) {
- goto bail;
- }
-#if 0
- printf("data...\n");
- const unsigned char* p = (unsigned char*)buf;
- const unsigned char* end = p+unlen;
- for (int i=0; i<32 && p < end; i++) {
- printf("0x%08x ", (int)(offset+(i*0x10)));
- for (int j=0; j<0x10 && p < end; j++) {
- printf(" %02x", *p);
- p++;
- }
- printf("\n");
- }
-#endif
-
- }
- break;
- case ZipEntry::kCompressDeflated: {
- if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
- goto bail;
- }
- }
- break;
- default:
- goto bail;
- }
- return buf;
-
-bail:
- free(buf);
- return NULL;
-}
-
-
-/*
- * ===========================================================================
- * ZipFile::EndOfCentralDir
- * ===========================================================================
- */
-
-/*
- * Read the end-of-central-dir fields.
- *
- * "buf" should be positioned at the EOCD signature, and should contain
- * the entire EOCD area including the comment.
- */
-status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
-{
- /* don't allow re-use */
- assert(mComment == NULL);
-
- if (len < kEOCDLen) {
- /* looks like ZIP file got truncated */
- LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
- kEOCDLen, len);
- return INVALID_OPERATION;
- }
-
- /* this should probably be an assert() */
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
- return UNKNOWN_ERROR;
-
- mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
- mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
- mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
- mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
- mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
- mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
- mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
-
- // TODO: validate mCentralDirOffset
-
- if (mCommentLen > 0) {
- if (kEOCDLen + mCommentLen > len) {
- LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
- kEOCDLen, mCommentLen, len);
- return UNKNOWN_ERROR;
- }
- mComment = new unsigned char[mCommentLen];
- memcpy(mComment, buf + kEOCDLen, mCommentLen);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Write an end-of-central-directory section.
- */
-status_t ZipFile::EndOfCentralDir::write(FILE* fp)
-{
- unsigned char buf[kEOCDLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
- ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
- ZipEntry::putShortLE(&buf[0x08], mNumEntries);
- ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
- ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
- ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
- ZipEntry::putShortLE(&buf[0x14], mCommentLen);
-
- if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
- return UNKNOWN_ERROR;
- if (mCommentLen > 0) {
- assert(mComment != NULL);
- if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of an EndOfCentralDir object.
- */
-void ZipFile::EndOfCentralDir::dump(void) const
-{
- LOGD(" EndOfCentralDir contents:\n");
- LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
- mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
- LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
- mCentralDirSize, mCentralDirOffset, mCommentLen);
-}
-
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
deleted file mode 100644
index ab48c69..0000000
--- a/libs/utils/futex_synchro.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2008 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 <stdio.h>
-#include <limits.h>
-
-#include <sys/time.h>
-#include <sched.h>
-
-#include <errno.h>
-
-#include <private/utils/futex_synchro.h>
-
-
-// This futex glue code is need on desktop linux, but is already part of bionic.
-#if !defined(HAVE_FUTEX_WRAPPERS)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-typedef unsigned int u32;
-#define asmlinkage
-#define __user
-#include <linux/futex.h>
-#include <utils/Atomic.h>
-
-
-int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
-{
- int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
- return err == 0 ? 0 : -errno;
-}
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout)
-{
- return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0);
-}
-
-int __futex_wake(volatile void *ftx, int count)
-{
- return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0);
-}
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
-{
- return android_atomic_cmpxchg(old, _new, ptr);
-}
-
-int __atomic_swap(int _new, volatile int *ptr)
-{
- return android_atomic_swap(_new, ptr);
-}
-
-int __atomic_dec(volatile int *ptr)
-{
- return android_atomic_dec(ptr);
-}
-
-#else // !defined(__arm__)
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
-int __futex_wake(volatile void *ftx, int count);
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
-int __atomic_swap(int _new, volatile int *ptr);
-int __atomic_dec(volatile int *ptr);
-
-#endif // !defined(HAVE_FUTEX_WRAPPERS)
-
-
-// lock states
-//
-// 0: unlocked
-// 1: locked, no waiters
-// 2: locked, maybe waiters
-
-void futex_mutex_init(futex_mutex_t *m)
-{
- m->value = 0;
-}
-
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- if(msec == FUTEX_WAIT_INFINITE) {
- while(__atomic_swap(2, &m->value) != 0) {
- __futex_wait(&m->value, 2, 0);
- }
- } else {
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- while(__atomic_swap(2, &m->value) != 0) {
- if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) {
- return -1;
- }
- }
- }
- return 0;
-}
-
-int futex_mutex_trylock(futex_mutex_t *m)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- return -1;
-}
-
-void futex_mutex_unlock(futex_mutex_t *m)
-{
- if(__atomic_dec(&m->value) != 1) {
- m->value = 0;
- __futex_wake(&m->value, 1);
- }
-}
-
-/* XXX *technically* there is a race condition that could allow
- * XXX a signal to be missed. If thread A is preempted in _wait()
- * XXX after unlocking the mutex and before waiting, and if other
- * XXX threads call signal or broadcast UINT_MAX times (exactly),
- * XXX before thread A is scheduled again and calls futex_wait(),
- * XXX then the signal will be lost.
- */
-
-void futex_cond_init(futex_cond_t *c)
-{
- c->value = 0;
-}
-
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec)
-{
- if(msec == FUTEX_WAIT_INFINITE){
- int oldvalue = c->value;
- futex_mutex_unlock(m);
- __futex_wait(&c->value, oldvalue, 0);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return 0;
- } else {
- int oldvalue = c->value;
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- futex_mutex_unlock(m);
- const int err = __futex_wait(&c->value, oldvalue, &ts);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return err;
- }
-}
-
-void futex_cond_signal(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, 1);
-}
-
-void futex_cond_broadcast(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, INT_MAX);
-}
-
diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp
deleted file mode 100644
index 656e46f..0000000
--- a/libs/utils/ported.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Ports of standard functions that don't exist on a specific platform.
-//
-// Note these are NOT in the "android" namespace.
-//
-#include <utils/ported.h>
-
-#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP)
-# include <sys/time.h>
-# include <windows.h>
-#endif
-
-
-#if defined(NEED_GETTIMEOFDAY)
-/*
- * Replacement gettimeofday() for Windows environments (primarily MinGW).
- *
- * Ignores "tz".
- */
-int gettimeofday(struct timeval* ptv, struct timezone* tz)
-{
- long long nsTime; // time in 100ns units since Jan 1 1601
- FILETIME ft;
-
- if (tz != NULL) {
- // oh well
- }
-
- ::GetSystemTimeAsFileTime(&ft);
- nsTime = (long long) ft.dwHighDateTime << 32 |
- (long long) ft.dwLowDateTime;
- // convert to time in usec since Jan 1 1970
- ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL);
- ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL);
-
- return 0;
-}
-#endif
-
-#if defined(NEED_USLEEP)
-//
-// Replacement usleep for Windows environments (primarily MinGW).
-//
-void usleep(unsigned long usec)
-{
- // Win32 API function Sleep() takes milliseconds
- ::Sleep((usec + 500) / 1000);
-}
-#endif
-
-#if 0 //defined(NEED_PIPE)
-//
-// Replacement pipe() command for MinGW
-//
-// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the
-// SecurityAttributes argument to CreatePipe(). This means the handles
-// aren't inherited when a new process is created. The examples I've seen
-// use it, possibly because there's a lot of junk going on behind the
-// scenes. (I'm assuming "process" and "thread" are different here, so
-// we should be okay spinning up a thread.) The recommended practice is
-// to dup() the descriptor you want the child to have.
-//
-// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O.
-// You can't use select() either, since that only works on sockets. The
-// Windows API calls that are useful here all operate on a HANDLE, not
-// an integer file descriptor, and I don't think you can get there from
-// here. The "named pipe" stuff is insane.
-//
-int pipe(int filedes[2])
-{
- return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT);
-}
-#endif
-
-#if defined(NEED_SETENV)
-/*
- * MinGW lacks these. For now, just stub them out so the code compiles.
- */
-int setenv(const char* name, const char* value, int overwrite)
-{
- return 0;
-}
-void unsetenv(const char* name)
-{
-}
-char* getenv(const char* name)
-{
- return NULL;
-}
-#endif