summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-11-12 18:45:53 -0800
committerJean-Baptiste Queru <jbq@google.com>2009-11-13 13:53:39 -0800
commitcc8c35cee5de7fdf2d79a1a3716120b64301cdfe (patch)
treea9acd18ab5526d297928f96c094ca22eaa33e593
parentcdcee265cad1fe10960bd3df32ac76c4afbd3963 (diff)
downloadframeworks_native-cc8c35cee5de7fdf2d79a1a3716120b64301cdfe.zip
frameworks_native-cc8c35cee5de7fdf2d79a1a3716120b64301cdfe.tar.gz
frameworks_native-cc8c35cee5de7fdf2d79a1a3716120b64301cdfe.tar.bz2
eclair snapshot
-rw-r--r--camera/libcameraservice/Android.mk11
-rw-r--r--camera/libcameraservice/CameraHardwareStub.cpp111
-rw-r--r--camera/libcameraservice/CameraHardwareStub.h57
-rw-r--r--camera/libcameraservice/CameraService.cpp661
-rw-r--r--camera/libcameraservice/CameraService.h44
-rw-r--r--cmds/keystore/Android.mk42
-rw-r--r--cmds/keystore/certtool.h91
-rw-r--r--cmds/keystore/common.h60
-rw-r--r--cmds/keystore/keymgmt.c426
-rw-r--r--cmds/keystore/keymgmt.h82
-rw-r--r--cmds/keystore/keystore.c542
-rw-r--r--cmds/keystore/keystore.h (renamed from include/utils/executablepath.h)25
-rw-r--r--cmds/keystore/keystore_cli.c97
-rw-r--r--cmds/keystore/keystore_get.h88
-rw-r--r--cmds/keystore/netkeystore.c411
-rw-r--r--cmds/keystore/netkeystore.h96
-rw-r--r--cmds/keystore/tests/netkeystore_test.c249
-rw-r--r--cmds/runtime/Android.mk1
-rw-r--r--cmds/runtime/ServiceManager.cpp4
-rw-r--r--cmds/runtime/ServiceManager.h2
-rw-r--r--cmds/runtime/main_runtime.cpp8
-rw-r--r--cmds/surfaceflinger/Android.mk1
-rw-r--r--cmds/surfaceflinger/main_surfaceflinger.cpp6
-rw-r--r--im/java/android/im/BrandingResourceIDs.java52
-rw-r--r--im/java/android/im/IImPlugin.aidl69
-rw-r--r--include/binder/Binder.h (renamed from include/utils/Binder.h)5
-rw-r--r--include/binder/BpBinder.h (renamed from include/utils/BpBinder.h)6
-rw-r--r--include/binder/IBinder.h (renamed from include/utils/IBinder.h)6
-rw-r--r--include/binder/IInterface.h (renamed from include/utils/IInterface.h)26
-rw-r--r--include/binder/IMemory.h (renamed from include/utils/IMemory.h)10
-rw-r--r--include/binder/IPCThreadState.h (renamed from include/utils/IPCThreadState.h)4
-rw-r--r--include/binder/IPermissionController.h (renamed from include/utils/IPermissionController.h)2
-rw-r--r--include/binder/IServiceManager.h (renamed from include/utils/IServiceManager.h)6
-rw-r--r--include/binder/MemoryBase.h (renamed from include/utils/MemoryBase.h)2
-rw-r--r--include/binder/MemoryDealer.h (renamed from include/utils/MemoryDealer.h)33
-rw-r--r--include/binder/MemoryHeapBase.h (renamed from include/utils/MemoryHeapBase.h)9
-rw-r--r--include/binder/MemoryHeapPmem.h (renamed from include/utils/MemoryHeapPmem.h)6
-rw-r--r--include/binder/Parcel.h (renamed from include/utils/Parcel.h)16
-rw-r--r--include/binder/Permission.h68
-rw-r--r--include/binder/ProcessState.h (renamed from include/utils/ProcessState.h)2
-rw-r--r--include/private/binder/Static.h (renamed from libs/utils/executablepath_darwin.cpp)34
-rw-r--r--include/private/binder/binder_module.h (renamed from include/private/utils/binder_module.h)0
-rw-r--r--include/private/opengles/gl_context.h45
-rw-r--r--include/private/ui/LayerState.h2
-rw-r--r--include/private/ui/RegionHelper.h284
-rw-r--r--include/private/ui/SharedBufferStack.h359
-rw-r--r--include/private/ui/SharedState.h168
-rw-r--r--include/private/ui/SurfaceFlingerSynchro.h76
-rw-r--r--include/private/ui/android_natives_priv.h (renamed from im/java/android/im/ImPluginConsts.java)14
-rw-r--r--include/private/ui/sw_gralloc_handle.h83
-rw-r--r--include/private/utils/Static.h23
-rw-r--r--include/private/utils/futex_synchro.h60
-rw-r--r--include/tts/TtsEngine.h6
-rw-r--r--include/ui/Camera.h31
-rw-r--r--include/ui/CameraHardwareInterface.h163
-rw-r--r--include/ui/CameraParameters.h196
-rw-r--r--include/ui/EGLDisplaySurface.h86
-rw-r--r--include/ui/EGLNativeWindowSurface.h59
-rw-r--r--include/ui/EGLUtils.h53
-rw-r--r--include/ui/EventHub.h29
-rw-r--r--include/ui/FramebufferNativeWindow.h88
-rw-r--r--include/ui/GraphicBuffer.h136
-rw-r--r--include/ui/GraphicBufferAllocator.h96
-rw-r--r--include/ui/GraphicBufferMapper.h64
-rw-r--r--include/ui/ICamera.h12
-rw-r--r--include/ui/ICameraClient.h6
-rw-r--r--include/ui/ICameraService.h4
-rw-r--r--include/ui/IOverlay.h2
-rw-r--r--include/ui/ISurface.h8
-rw-r--r--include/ui/ISurfaceComposer.h44
-rw-r--r--include/ui/ISurfaceFlingerClient.h8
-rw-r--r--include/ui/Overlay.h12
-rw-r--r--include/ui/PixelFormat.h36
-rw-r--r--include/ui/Rect.h8
-rw-r--r--include/ui/Region.h129
-rw-r--r--include/ui/Surface.h215
-rw-r--r--include/ui/SurfaceComposerClient.h79
-rw-r--r--include/ui/android_native_buffer.h62
-rw-r--r--include/ui/egl/android_natives.h263
-rw-r--r--include/utils/Debug.h33
-rw-r--r--include/utils/Errors.h2
-rw-r--r--include/utils/KeyedVector.h2
-rw-r--r--include/utils/List.h272
-rw-r--r--include/utils/LogSocket.h20
-rw-r--r--include/utils/Pipe.h108
-rw-r--r--include/utils/RefBase.h4
-rw-r--r--include/utils/ResourceTypes.h37
-rw-r--r--include/utils/Singleton.h69
-rw-r--r--include/utils/Socket.h80
-rw-r--r--include/utils/SortedVector.h3
-rw-r--r--include/utils/StringArray.h83
-rw-r--r--include/utils/TextOutput.h4
-rw-r--r--include/utils/TimerProbe.h72
-rw-r--r--include/utils/Timers.h13
-rw-r--r--include/utils/TypeHelpers.h141
-rw-r--r--include/utils/Vector.h3
-rw-r--r--include/utils/VectorImpl.h1
-rw-r--r--include/utils/ZipEntry.h345
-rw-r--r--include/utils/ZipFile.h269
-rw-r--r--include/utils/inet_address.h103
-rw-r--r--include/utils/misc.h2
-rw-r--r--include/utils/ported.h50
-rw-r--r--include/utils/string_array.h135
-rw-r--r--include/utils/threads.h120
-rw-r--r--libs/audioflinger/A2dpAudioInterface.cpp265
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h54
-rw-r--r--libs/audioflinger/Android.mk83
-rw-r--r--libs/audioflinger/AudioDumpInterface.cpp454
-rw-r--r--libs/audioflinger/AudioDumpInterface.h117
-rw-r--r--libs/audioflinger/AudioFlinger.cpp3503
-rw-r--r--libs/audioflinger/AudioFlinger.h557
-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.cpp64
-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.cpp945
-rw-r--r--libs/audioflinger/AudioPolicyManagerGeneric.h196
-rw-r--r--libs/audioflinger/AudioPolicyService.cpp911
-rw-r--r--libs/audioflinger/AudioPolicyService.h222
-rw-r--r--libs/binder/Android.mk (renamed from cmds/keystore/tests/Android.mk)41
-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)39
-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)16
-rw-r--r--libs/binder/MemoryHeapPmem.cpp (renamed from libs/utils/MemoryHeapPmem.cpp)8
-rw-r--r--libs/binder/Parcel.cpp (renamed from libs/utils/Parcel.cpp)177
-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/surfaceflinger/Android.mk34
-rw-r--r--libs/surfaceflinger/BlurFilter.cpp52
-rw-r--r--libs/surfaceflinger/CPUGauge.cpp171
-rw-r--r--libs/surfaceflinger/CPUGauge.h74
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp253
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h29
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp2
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp585
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.h63
-rw-r--r--libs/surfaceflinger/Layer.cpp783
-rw-r--r--libs/surfaceflinger/Layer.h98
-rw-r--r--libs/surfaceflinger/LayerBase.cpp695
-rw-r--r--libs/surfaceflinger/LayerBase.h195
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp187
-rw-r--r--libs/surfaceflinger/LayerBitmap.h84
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp119
-rw-r--r--libs/surfaceflinger/LayerBlur.h8
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp351
-rw-r--r--libs/surfaceflinger/LayerBuffer.h96
-rw-r--r--libs/surfaceflinger/LayerDim.cpp159
-rw-r--r--libs/surfaceflinger/LayerDim.h19
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.cpp206
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.h80
-rw-r--r--libs/surfaceflinger/MessageQueue.cpp192
-rw-r--r--libs/surfaceflinger/MessageQueue.h127
-rw-r--r--libs/surfaceflinger/OrientationAnimation.cpp155
-rw-r--r--libs/surfaceflinger/OrientationAnimation.h85
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp949
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h201
-rw-r--r--libs/surfaceflinger/Tokenizer.cpp5
-rw-r--r--libs/surfaceflinger/Transform.cpp8
-rw-r--r--libs/surfaceflinger/Transform.h8
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp178
-rw-r--r--libs/surfaceflinger/VRamHeap.h78
-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.mk18
-rw-r--r--libs/ui/Camera.cpp21
-rw-r--r--libs/ui/CameraParameters.cpp139
-rw-r--r--libs/ui/EGLDisplaySurface.cpp519
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp161
-rw-r--r--libs/ui/EGLUtils.cpp136
-rw-r--r--libs/ui/EventHub.cpp193
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp279
-rw-r--r--libs/ui/GraphicBuffer.cpp239
-rw-r--r--libs/ui/GraphicBufferAllocator.cpp141
-rw-r--r--libs/ui/GraphicBufferMapper.cpp228
-rw-r--r--libs/ui/ICamera.cpp47
-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.cpp36
-rw-r--r--libs/ui/ISurfaceComposer.cpp125
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp35
-rw-r--r--libs/ui/LayerState.cpp2
-rw-r--r--libs/ui/Overlay.cpp39
-rw-r--r--libs/ui/Region.cpp636
-rw-r--r--libs/ui/SharedBufferStack.cpp424
-rw-r--r--libs/ui/Surface.cpp799
-rw-r--r--libs/ui/SurfaceComposerClient.cpp595
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp123
-rw-r--r--libs/ui/tests/Android.mk16
-rw-r--r--libs/ui/tests/region.cpp69
-rw-r--r--libs/utils/Android.mk62
-rw-r--r--libs/utils/BackupData.cpp31
-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/ResourceTypes.cpp23
-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.cpp308
-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
-rw-r--r--opengl/include/EGL/eglext.h24
-rw-r--r--opengl/include/EGL/eglnatives.h271
-rw-r--r--opengl/include/EGL/eglplatform.h5
-rw-r--r--opengl/include/GLES/glplatform.h6
-rw-r--r--opengl/include/GLES2/gl2.h620
-rw-r--r--opengl/include/GLES2/gl2ext.h518
-rw-r--r--opengl/include/GLES2/gl2platform.h29
-rw-r--r--opengl/libagl/Android.mk24
-rw-r--r--opengl/libagl/TextureObjectManager.cpp47
-rw-r--r--opengl/libagl/TextureObjectManager.h70
-rw-r--r--opengl/libagl/array.cpp130
-rw-r--r--opengl/libagl/copybit.cpp631
-rw-r--r--opengl/libagl/copybit.h75
-rw-r--r--opengl/libagl/egl.cpp951
-rw-r--r--opengl/libagl/light.cpp11
-rw-r--r--opengl/libagl/matrix.cpp15
-rw-r--r--opengl/libagl/primitives.cpp2
-rw-r--r--opengl/libagl/state.cpp82
-rw-r--r--opengl/libagl/texture.cpp301
-rw-r--r--opengl/libagl/texture.h10
-rw-r--r--opengl/libs/Android.mk90
-rw-r--r--opengl/libs/EGL/Loader.cpp287
-rw-r--r--opengl/libs/EGL/Loader.h90
-rw-r--r--opengl/libs/EGL/egl.cpp1174
-rw-r--r--opengl/libs/EGL/egl_entries.in (renamed from opengl/libs/egl_entries.in)5
-rw-r--r--opengl/libs/EGL/gpu.cpp217
-rw-r--r--opengl/libs/EGL/hooks.cpp60
-rw-r--r--opengl/libs/GLES2/gl2.cpp119
-rw-r--r--opengl/libs/GLES2/gl2_api.in426
-rw-r--r--opengl/libs/GLES2/gl2ext_api.in105
-rw-r--r--opengl/libs/GLES_CM/gl.cpp53
-rw-r--r--opengl/libs/egl_impl.h12
-rw-r--r--opengl/libs/entries.in349
-rw-r--r--opengl/libs/gl_entries.in145
-rw-r--r--opengl/libs/gl_enums.in261
-rw-r--r--opengl/libs/glext_entries.in90
-rw-r--r--opengl/libs/hooks.h38
-rw-r--r--opengl/libs/tools/enumextract.sh32
-rwxr-xr-xopengl/libs/tools/genfiles21
-rwxr-xr-xopengl/libs/tools/glapigen15
-rwxr-xr-xopengl/libs/tools/glentrygen15
-rw-r--r--opengl/tests/angeles/Android.mk2
-rw-r--r--opengl/tests/angeles/app-linux.cpp (renamed from opengl/tests/angeles/app-linux.c)52
-rw-r--r--opengl/tests/fillrate/Android.mk17
-rw-r--r--opengl/tests/fillrate/fillrate.cpp161
-rw-r--r--opengl/tests/filter/Android.mk4
-rw-r--r--opengl/tests/filter/filter.cpp (renamed from opengl/tests/filter/filter.c)72
-rw-r--r--opengl/tests/finish/Android.mk4
-rw-r--r--opengl/tests/finish/finish.cpp (renamed from opengl/tests/finish/finish.c)40
-rw-r--r--opengl/tests/gl2_basic/Android.mk19
-rw-r--r--opengl/tests/gl2_basic/gl2_basic.cpp357
-rw-r--r--opengl/tests/gl2_jni/Android.mk51
-rw-r--r--opengl/tests/gl2_jni/AndroidManifest.xml35
-rw-r--r--opengl/tests/gl2_jni/jni/gl_code.cpp165
-rw-r--r--opengl/tests/gl2_jni/res/values/strings.xml29
-rw-r--r--opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java46
-rw-r--r--opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java (renamed from libs/utils/executablepath_linux.cpp)29
-rw-r--r--opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java139
-rw-r--r--opengl/tests/gl_basic/Android.mk17
-rw-r--r--opengl/tests/gl_basic/gl_basic.cpp357
-rw-r--r--opengl/tests/gl_jni/Android.mk53
-rw-r--r--opengl/tests/gl_jni/AndroidManifest.xml38
-rw-r--r--opengl/tests/gl_jni/jni/gl_code.cpp183
-rw-r--r--opengl/tests/gl_jni/res/values/strings.xml29
-rw-r--r--opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java45
-rw-r--r--opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java (renamed from include/utils.h)33
-rw-r--r--opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java90
-rw-r--r--opengl/tests/gralloc/Android.mk16
-rw-r--r--opengl/tests/gralloc/gralloc.cpp110
-rw-r--r--opengl/tests/linetex/Android.mk17
-rw-r--r--opengl/tests/linetex/linetex.cpp116
-rw-r--r--opengl/tests/swapinterval/Android.mk17
-rw-r--r--opengl/tests/swapinterval/swapinterval.cpp121
-rw-r--r--opengl/tests/textures/Android.mk4
-rw-r--r--opengl/tests/textures/textures.cpp (renamed from opengl/tests/textures/textures.c)29
-rw-r--r--opengl/tests/tritex/Android.mk2
-rw-r--r--opengl/tests/tritex/tritex.cpp (renamed from opengl/tests/tritex/tritex.c)26
-rw-r--r--opengl/tools/glgen/specs/gles11/checks.spec123
-rw-r--r--opengl/tools/glgen/specs/jsr239/glspec-checks119
-rw-r--r--opengl/tools/glgen/src/JniCodeEmitter.java10
-rw-r--r--vpn/java/android/net/vpn/VpnManager.java21
-rw-r--r--vpn/java/android/net/vpn/VpnType.java20
303 files changed, 24710 insertions, 18187 deletions
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index 96cc512..ecaebff 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -25,6 +25,10 @@ LOCAL_SRC_FILES:= \
LOCAL_MODULE:= libcamerastub
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
+
LOCAL_SHARED_LIBRARIES:= libui
include $(BUILD_STATIC_LIBRARY)
@@ -42,12 +46,17 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
+ libbinder \
libcutils \
libmedia
LOCAL_MODULE:= libcameraservice
-LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
+LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\"
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
ifeq ($(USE_CAMERA_STUB), true)
LOCAL_STATIC_LIBRARIES += libcamerastub
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index a7af57c..8ad1f69 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -33,13 +33,11 @@ CameraHardwareStub::CameraHardwareStub()
mRawHeap(0),
mFakeCamera(0),
mPreviewFrameSize(0),
- mRawPictureCallback(0),
- mJpegPictureCallback(0),
- mPictureCallbackCookie(0),
- mPreviewCallback(0),
- mPreviewCallbackCookie(0),
- mAutoFocusCallback(0),
- mAutoFocusCallbackCookie(0),
+ mNotifyCb(0),
+ mDataCb(0),
+ mDataCbTimestamp(0),
+ mCallbackCookie(0),
+ mMsgEnabled(0),
mCurrentPreviewFrame(0)
{
initDefaultParameters();
@@ -112,6 +110,36 @@ sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
return mRawHeap;
}
+void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+{
+ Mutex::Autolock lock(mLock);
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCallbackCookie = user;
+}
+
+void CameraHardwareStub::enableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled |= msgType;
+}
+
+void CameraHardwareStub::disableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled &= ~msgType;
+}
+
+bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ return (mMsgEnabled & msgType);
+}
+
// ---------------------------------------------------------------------------
int CameraHardwareStub::previewThread()
@@ -150,7 +178,8 @@ int CameraHardwareStub::previewThread()
//LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
// Notify the client of a new frame.
- mPreviewCallback(buffer, mPreviewCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
+ mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
// Advance the buffer pointer.
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
@@ -162,15 +191,13 @@ int CameraHardwareStub::previewThread()
return NO_ERROR;
}
-status_t CameraHardwareStub::startPreview(preview_callback cb, void* user)
+status_t CameraHardwareStub::startPreview()
{
Mutex::Autolock lock(mLock);
if (mPreviewThread != 0) {
// already running
return INVALID_OPERATION;
}
- mPreviewCallback = cb;
- mPreviewCallbackCookie = user;
mPreviewThread = new PreviewThread(this);
return NO_ERROR;
}
@@ -197,7 +224,7 @@ bool CameraHardwareStub::previewEnabled() {
return mPreviewThread != 0;
}
-status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+status_t CameraHardwareStub::startRecording()
{
return UNKNOWN_ERROR;
}
@@ -225,30 +252,24 @@ int CameraHardwareStub::beginAutoFocusThread(void *cookie)
int CameraHardwareStub::autoFocusThread()
{
- if (mAutoFocusCallback != NULL) {
- mAutoFocusCallback(true, mAutoFocusCallbackCookie);
- mAutoFocusCallback = NULL;
- return NO_ERROR;
- }
- return UNKNOWN_ERROR;
+ if (mMsgEnabled & CAMERA_MSG_FOCUS)
+ mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
+ return NO_ERROR;
}
-status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
- void *user)
+status_t CameraHardwareStub::autoFocus()
{
Mutex::Autolock lock(mLock);
-
- if (mAutoFocusCallback != NULL) {
- return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
- }
-
- mAutoFocusCallback = af_cb;
- mAutoFocusCallbackCookie = user;
if (createThread(beginAutoFocusThread, this) == false)
return UNKNOWN_ERROR;
return NO_ERROR;
}
+status_t CameraHardwareStub::cancelAutoFocus()
+{
+ return NO_ERROR;
+}
+
/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
{
CameraHardwareStub *c = (CameraHardwareStub *)cookie;
@@ -257,10 +278,10 @@ status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
int CameraHardwareStub::pictureThread()
{
- if (mShutterCallback)
- mShutterCallback(mPictureCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_SHUTTER)
+ mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
- if (mRawPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
//FIXME: use a canned YUV image!
// In the meantime just make another fake camera picture.
int w, h;
@@ -268,42 +289,28 @@ int CameraHardwareStub::pictureThread()
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
FakeCamera cam(w, h);
cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
- if (mRawPictureCallback)
- mRawPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
}
- if (mJpegPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
- if (mJpegPictureCallback)
- mJpegPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
}
return NO_ERROR;
}
-status_t CameraHardwareStub::takePicture(shutter_callback shutter_cb,
- raw_callback raw_cb,
- jpeg_callback jpeg_cb,
- void* user)
+status_t CameraHardwareStub::takePicture()
{
stopPreview();
- mShutterCallback = shutter_cb;
- mRawPictureCallback = raw_cb;
- mJpegPictureCallback = jpeg_cb;
- mPictureCallbackCookie = user;
if (createThread(beginPictureThread, this) == false)
return -1;
return NO_ERROR;
}
-status_t CameraHardwareStub::cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg)
+status_t CameraHardwareStub::cancelPicture()
{
- if (cancel_shutter) mShutterCallback = NULL;
- if (cancel_raw) mRawPictureCallback = NULL;
- if (cancel_jpeg) mJpegPictureCallback = NULL;
return NO_ERROR;
}
@@ -361,6 +368,12 @@ CameraParameters CameraHardwareStub::getParameters() const
return mParameters;
}
+status_t CameraHardwareStub::sendCommand(int32_t command, int32_t arg1,
+ int32_t arg2)
+{
+ return BAD_VALUE;
+}
+
void CameraHardwareStub::release()
{
}
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 0d26d47..8a67024 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -21,8 +21,8 @@
#include "FakeCamera.h"
#include <utils/threads.h>
#include <ui/CameraHardwareInterface.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <utils/threads.h>
namespace android {
@@ -32,26 +32,33 @@ public:
virtual sp<IMemoryHeap> getPreviewHeap() const;
virtual sp<IMemoryHeap> getRawHeap() const;
- virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user);
+
+ virtual void enableMsgType(int32_t msgType);
+ virtual void disableMsgType(int32_t msgType);
+ virtual bool msgTypeEnabled(int32_t msgType);
+
+ virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t startRecording(recording_callback cb, void* user);
+ virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
- virtual status_t autoFocus(autofocus_callback, void *user);
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user);
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg);
+ virtual status_t autoFocus();
+ virtual status_t cancelAutoFocus();
+ virtual status_t takePicture();
+ virtual status_t cancelPicture();
virtual status_t dump(int fd, const Vector<String16>& args) const;
virtual status_t setParameters(const CameraParameters& params);
virtual CameraParameters getParameters() const;
+ virtual status_t sendCommand(int32_t command, int32_t arg1,
+ int32_t arg2);
virtual void release();
static sp<CameraHardwareInterface> createInstance();
@@ -67,8 +74,15 @@ private:
class PreviewThread : public Thread {
CameraHardwareStub* mHardware;
public:
- PreviewThread(CameraHardwareStub* hw)
- : Thread(false), mHardware(hw) { }
+ PreviewThread(CameraHardwareStub* hw) :
+#ifdef SINGLE_PROCESS
+ // In single process mode this thread needs to be a java thread,
+ // since we won't be calling through the binder.
+ Thread(true),
+#else
+ Thread(false),
+#endif
+ mHardware(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
@@ -102,18 +116,15 @@ private:
bool mPreviewRunning;
int mPreviewFrameSize;
- shutter_callback mShutterCallback;
- raw_callback mRawPictureCallback;
- jpeg_callback mJpegPictureCallback;
- void *mPictureCallbackCookie;
-
// protected by mLock
sp<PreviewThread> mPreviewThread;
- preview_callback mPreviewCallback;
- void *mPreviewCallbackCookie;
- autofocus_callback mAutoFocusCallback;
- void *mAutoFocusCallbackCookie;
+ notify_callback mNotifyCb;
+ data_callback mDataCb;
+ data_callback_timestamp mDataCbTimestamp;
+ void *mCallbackCookie;
+
+ int32_t mMsgEnabled;
// only used from PreviewThread
int mCurrentPreviewFrame;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index e4b6791..df59dcf 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -20,12 +20,12 @@
#define LOG_TAG "CameraService"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/Errors.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/ICameraService.h>
#include <media/mediaplayer.h>
@@ -33,7 +33,6 @@
#include "CameraService.h"
#include <cutils/atomic.h>
-#include <cutils/properties.h>
namespace android {
@@ -60,6 +59,7 @@ extern "C" {
#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
+#define DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE 0
#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
static int debug_frame_cnt;
@@ -195,17 +195,11 @@ void CameraService::decUsers() {
android_atomic_dec(&mUsers);
}
-static sp<MediaPlayer> newMediaPlayer(const char *file)
+static sp<MediaPlayer> newMediaPlayer(const char *file)
{
sp<MediaPlayer> mp = new MediaPlayer();
if (mp->setDataSource(file) == NO_ERROR) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (atoi(value)) {
- mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
- } else {
- mp->setAudioStreamType(AudioSystem::SYSTEM);
- }
+ mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
mp->prepare();
} else {
mp.clear();
@@ -225,8 +219,20 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
mHardware = openCameraHardware();
mUseOverlay = mHardware->useOverlay();
+ mHardware->setCallbacks(notifyCallback,
+ dataCallback,
+ dataCallbackTimestamp,
+ mCameraService.get());
+
+ // Enable zoom, error, and focus messages by default
+ mHardware->enableMsgType(CAMERA_MSG_ERROR |
+ CAMERA_MSG_ZOOM |
+ CAMERA_MSG_FOCUS);
+
mMediaPlayerClick = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
mMediaPlayerBeep = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+ mOverlayW = 0;
+ mOverlayH = 0;
// Callback is disabled by default
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
@@ -261,7 +267,7 @@ status_t CameraService::Client::lock()
status_t CameraService::Client::unlock()
{
int callingPid = getCallingPid();
- LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
+ LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
Mutex::Autolock _l(mLock);
// allow anyone to use camera
status_t result = checkPid();
@@ -303,7 +309,7 @@ status_t CameraService::Client::connect(const sp<ICameraClient>& client)
oldClient = mCameraClient;
// did the client actually change?
- if (client->asBinder() == mCameraClient->asBinder()) {
+ if ((mCameraClient != NULL) && (client->asBinder() == mCameraClient->asBinder())) {
LOGD("Connect to the same client");
return NO_ERROR;
}
@@ -396,9 +402,20 @@ void CameraService::Client::disconnect()
// idle state.
mHardware->stopPreview();
// Cancel all picture callbacks.
- mHardware->cancelPicture(true, true, true);
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+ mHardware->cancelPicture();
+ // Turn off remaining messages.
+ mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
// Release the hardware resources.
mHardware->release();
+ // Release the held overlay resources.
+ if (mUseOverlay)
+ {
+ mOverlayRef = 0;
+ }
mHardware.clear();
mCameraService->removeClient(mCameraClient);
@@ -420,11 +437,21 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
result = NO_ERROR;
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() != mSurface->asBinder()) {
- if (mSurface != 0 && !mUseOverlay) {
+ if (mSurface != 0) {
LOGD("clearing old preview surface %p", mSurface.get());
- mSurface->unregisterBuffers();
+ if ( !mUseOverlay)
+ {
+ mSurface->unregisterBuffers();
+ }
+ else
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ }
}
mSurface = surface;
+ mOverlayRef = 0;
// If preview has been already started, set overlay or register preview
// buffers now.
if (mHardware->previewEnabled()) {
@@ -446,6 +473,13 @@ void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
+
+ if(mUseOverlay) {
+ if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ else
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
}
// start preview mode
@@ -504,7 +538,7 @@ status_t CameraService::Client::startRecordingMode()
}
// start recording mode
- ret = mHardware->startRecording(recordingCallback, mCameraService.get());
+ ret = mHardware->startRecording();
if (ret != NO_ERROR) {
LOGE("mHardware->startRecording() failed with status %d", ret);
}
@@ -518,27 +552,47 @@ status_t CameraService::Client::setOverlay()
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
- const char *format = params.getPreviewFormat();
- int fmt;
- if (!strcmp(format, "yuv422i"))
- fmt = OVERLAY_FORMAT_YCbCr_422_I;
- else if (!strcmp(format, "rgb565"))
- fmt = OVERLAY_FORMAT_RGB_565;
- else {
- LOGE("Invalid preview format for overlays");
- return -EINVAL;
+ if ( w != mOverlayW || h != mOverlayH )
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ mOverlayRef = 0;
}
status_t ret = NO_ERROR;
if (mSurface != 0) {
- sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
- ret = mHardware->setOverlay(new Overlay(ref));
+ if (mOverlayRef.get() == NULL) {
+
+ // FIXME:
+ // Surfaceflinger may hold onto the previous overlay reference for some
+ // time after we try to destroy it. retry a few times. In the future, we
+ // should make the destroy call block, or possibly specify that we can
+ // wait in the createOverlay call if the previous overlay is in the
+ // process of being destroyed.
+ for (int retry = 0; retry < 50; ++retry) {
+ mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT);
+ if (mOverlayRef != NULL) break;
+ LOGD("Overlay create failed - retrying");
+ usleep(20000);
+ }
+ if ( mOverlayRef.get() == NULL )
+ {
+ LOGE("Overlay Creation Failed!");
+ return -EINVAL;
+ }
+ ret = mHardware->setOverlay(new Overlay(mOverlayRef));
+ }
} else {
ret = mHardware->setOverlay(NULL);
}
if (ret != NO_ERROR) {
LOGE("mHardware->setOverlay() failed with status %d\n", ret);
}
+
+ mOverlayW = w;
+ mOverlayH = h;
+
return ret;
}
@@ -588,10 +642,10 @@ status_t CameraService::Client::startPreviewMode()
ret = setOverlay();
}
if (ret != NO_ERROR) return ret;
- ret = mHardware->startPreview(NULL, mCameraService.get());
+ ret = mHardware->startPreview();
} else {
- ret = mHardware->startPreview(previewCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ ret = mHardware->startPreview();
if (ret != NO_ERROR) return ret;
// If preview display has been set, register preview buffers now.
if (mSurface != 0) {
@@ -606,7 +660,7 @@ status_t CameraService::Client::startPreviewMode()
status_t CameraService::Client::startPreview()
{
LOGD("startPreview (pid %d)", getCallingPid());
-
+
return startCameraMode(CAMERA_PREVIEW_MODE);
}
@@ -618,6 +672,9 @@ status_t CameraService::Client::startRecording()
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
}
+
+ mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+
return startCameraMode(CAMERA_RECORDING_MODE);
}
@@ -626,21 +683,30 @@ void CameraService::Client::stopPreview()
{
LOGD("stopPreview (pid %d)", getCallingPid());
- Mutex::Autolock lock(mLock);
- if (checkPid() != NO_ERROR) return;
+ // hold main lock during state transition
+ {
+ Mutex::Autolock lock(mLock);
+ if (checkPid() != NO_ERROR) return;
- if (mHardware == 0) {
- LOGE("mHardware is NULL, returning.");
- return;
- }
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return;
+ }
- mHardware->stopPreview();
- LOGD("stopPreview(), hardware stopped OK");
+ mHardware->stopPreview();
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ LOGD("stopPreview(), hardware stopped OK");
- if (mSurface != 0 && !mUseOverlay) {
- mSurface->unregisterBuffers();
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->unregisterBuffers();
+ }
+ }
+
+ // hold preview buffer lock
+ {
+ Mutex::Autolock lock(mPreviewLock);
+ mPreviewBuffer.clear();
}
- mPreviewBuffer.clear();
}
// stop recording mode
@@ -648,21 +714,31 @@ void CameraService::Client::stopRecording()
{
LOGD("stopRecording (pid %d)", getCallingPid());
- Mutex::Autolock lock(mLock);
- if (checkPid() != NO_ERROR) return;
+ // hold main lock during state transition
+ {
+ Mutex::Autolock lock(mLock);
+ if (checkPid() != NO_ERROR) return;
- if (mHardware == 0) {
- LOGE("mHardware is NULL, returning.");
- return;
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return;
+ }
+
+ if (mMediaPlayerBeep.get() != NULL) {
+ mMediaPlayerBeep->seekTo(0);
+ mMediaPlayerBeep->start();
+ }
+
+ mHardware->stopRecording();
+ mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+ LOGD("stopRecording(), hardware stopped OK");
}
- if (mMediaPlayerBeep.get() != NULL) {
- mMediaPlayerBeep->seekTo(0);
- mMediaPlayerBeep->start();
+ // hold preview buffer lock
+ {
+ Mutex::Autolock lock(mPreviewLock);
+ mPreviewBuffer.clear();
}
- mHardware->stopRecording();
- LOGD("stopRecording(), hardware stopped OK");
- mPreviewBuffer.clear();
}
// release a recording frame
@@ -749,69 +825,25 @@ static void dump_to_file(const char *fname,
}
#endif
-// preview callback - frame buffer update
-void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
+status_t CameraService::Client::autoFocus()
{
- LOGV("previewCallback()");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
-#if DEBUG_HEAP_LEAKS && 0 // debugging
- if (gWeakHeap == NULL) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (gWeakHeap != heap) {
- LOGD("SETTING PREVIEW HEAP");
- heap->trackMe(true, true);
- gWeakHeap = heap;
- }
- }
-#endif
-
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
- {
- if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- dump_to_file("/data/preview.yuv",
- (uint8_t *)heap->base() + offset, size);
- }
- }
-#endif
+ LOGD("autoFocus (pid %d)", getCallingPid());
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postPreviewFrame(mem);
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPid();
+ if (result != NO_ERROR) return result;
-#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
- if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
- client->printRefs();
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
}
-#endif
-}
-// recording callback
-void CameraService::Client::recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user)
-{
- LOGV("recordingCallback");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postRecordingFrame(timestamp, mem);
+ return mHardware->autoFocus();
}
-// take a picture - image is returned in callback
-status_t CameraService::Client::autoFocus()
+status_t CameraService::Client::cancelAutoFocus()
{
- LOGD("autoFocus (pid %d)", getCallingPid());
+ LOGD("cancelAutoFocus (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPid();
@@ -822,8 +854,7 @@ status_t CameraService::Client::autoFocus()
return INVALID_OPERATION;
}
- return mHardware->autoFocus(autoFocusCallback,
- mCameraService.get());
+ return mHardware->cancelAutoFocus();
}
// take a picture - image is returned in callback
@@ -840,65 +871,155 @@ status_t CameraService::Client::takePicture()
return INVALID_OPERATION;
}
- return mHardware->takePicture(shutterCallback,
- yuvPictureCallback,
- jpegPictureCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+
+ return mHardware->takePicture();
}
-// picture callback - snapshot taken
-void CameraService::Client::shutterCallback(void *user)
+// snapshot taken
+void CameraService::Client::handleShutter(
+ image_rect_type *size // The width and height of yuv picture for
+ // registerBuffer. If this is NULL, use the picture
+ // size from parameters.
+)
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
// Play shutter sound.
- if (client->mMediaPlayerClick.get() != NULL) {
- client->mMediaPlayerClick->seekTo(0);
- client->mMediaPlayerClick->start();
+ if (mMediaPlayerClick.get() != NULL) {
+ mMediaPlayerClick->seekTo(0);
+ mMediaPlayerClick->start();
}
// Screen goes black after the buffer is unregistered.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->unregisterBuffers();
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->unregisterBuffers();
}
- client->postShutter();
+ sp<ICameraClient> c = mCameraClient;
+ if (c != NULL) {
+ c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+ }
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
// It takes some time before yuvPicture callback to be called.
// Register the buffer for raw image here to reduce latency.
- if (client->mSurface != 0 && !client->mUseOverlay) {
+ if (mSurface != 0 && !mUseOverlay) {
int w, h;
- CameraParameters params(client->mHardware->getParameters());
- params.getPictureSize(&w, &h);
+ CameraParameters params(mHardware->getParameters());
uint32_t transform = 0;
if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
LOGV("portrait mode");
transform = ISurface::BufferHeap::ROT_90;
}
+
+ if (size == NULL) {
+ params.getPictureSize(&w, &h);
+ } else {
+ w = size->width;
+ h = size->height;
+ w &= ~1;
+ h &= ~1;
+ LOGD("Snapshot image width=%d, height=%d", w, h);
+ }
ISurface::BufferHeap buffers(w, h, w, h,
- PIXEL_FORMAT_YCbCr_420_SP, transform, 0, client->mHardware->getRawHeap());
+ PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap());
- client->mSurface->registerBuffers(buffers);
+ mSurface->registerBuffers(buffers);
}
}
-// picture callback - raw image ready
-void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
- void *user)
+// preview callback - frame buffer update
+void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+ if (gWeakHeap == NULL) {
+ if (gWeakHeap != heap) {
+ LOGD("SETTING PREVIEW HEAP");
+ heap->trackMe(true, true);
+ gWeakHeap = heap;
+ }
+ }
+#endif
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+ {
+ if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
+ dump_to_file("/data/preview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+ }
+#endif
+
+ if (!mUseOverlay)
+ {
+ Mutex::Autolock surfaceLock(mSurfaceLock);
+ if (mSurface != NULL) {
+ mSurface->postBuffer(offset);
+ }
}
- if (mem == NULL) {
- client->postRaw(NULL);
- client->postError(UNKNOWN_ERROR);
+
+ // local copy of the callback flags
+ int flags = mPreviewCallbackFlag;
+
+ // is callback enabled?
+ if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ // If the enable bit is off, the copy-out and one-shot bits are ignored
+ LOGV("frame callback is diabled");
return;
}
+ // hold a strong pointer to the client
+ sp<ICameraClient> c = mCameraClient;
+
+ // clear callback flags if no client or one-shot mode
+ if ((c == NULL) || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+ LOGV("Disable preview callback");
+ mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ // TODO: Shouldn't we use this API for non-overlay hardware as well?
+ if (mUseOverlay)
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
+
+ // Is the received frame copied out or not?
+ if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ LOGV("frame is copied");
+ copyFrameAndPostCopiedFrame(c, heap, offset, size);
+ } else {
+ LOGV("frame is forwarded");
+ c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
+ }
+}
+
+// picture callback - postview image ready
+void CameraService::Client::handlePostview(const sp<IMemory>& mem)
+{
+#if DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/postview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+#endif
+
+ sp<ICameraClient> c = mCameraClient;
+ if (c != NULL) {
+ c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
+ }
+ mHardware->disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+}
+
+// picture callback - raw image ready
+void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)
+{
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -906,80 +1027,148 @@ void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
gWeakHeap = heap; // debugging
#endif
- //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
+ //LOGV("handleRawPicture(%d, %d)", offset, size);
#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
dump_to_file("/data/photo.yuv",
(uint8_t *)heap->base() + offset, size);
#endif
// Put the YUV version of the snapshot in the preview display.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->postBuffer(offset);
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->postBuffer(offset);
+ }
+
+ sp<ICameraClient> c = mCameraClient;
+ if (c != NULL) {
+ c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
+ }
+ mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);
+}
+
+// picture callback - compressed picture ready
+void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem)
+{
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/photo.jpg",
+ (uint8_t *)heap->base() + offset, size);
}
+#endif
- client->postRaw(mem);
+ sp<ICameraClient> c = mCameraClient;
+ if (c != NULL) {
+ c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
+ }
+ mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+}
+
+void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user)
+{
+ LOGV("notifyCallback(%d)", msgType);
+
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ switch (msgType) {
+ case CAMERA_MSG_SHUTTER:
+ // ext1 is the dimension of the yuv picture.
+ client->handleShutter((image_rect_type *)ext1);
+ break;
+ default:
+ sp<ICameraClient> c = client->mCameraClient;
+ if (c != NULL) {
+ c->notifyCallback(msgType, ext1, ext2);
+ }
+ break;
+ }
#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (NOTIFY CALLBACK) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
}
-// picture callback - jpeg ready
-void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
+void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user)
{
+ LOGV("dataCallback(%d)", msgType);
+
sp<Client> client = getClientFromCookie(user);
if (client == 0) {
return;
}
- if (mem == NULL) {
- client->postJpeg(NULL);
- client->postError(UNKNOWN_ERROR);
+
+ sp<ICameraClient> c = client->mCameraClient;
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data callback");
+ if (c != NULL) {
+ c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ c->dataCallback(msgType, NULL);
+ }
return;
}
- /** We absolutely CANNOT call into user code with a lock held **/
-
-#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
- {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- dump_to_file("/data/photo.jpg",
- (uint8_t *)heap->base() + offset, size);
+ switch (msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ client->handlePreviewData(dataPtr);
+ break;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ client->handlePostview(dataPtr);
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ client->handleRawPicture(dataPtr);
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ client->handleCompressedPicture(dataPtr);
+ break;
+ default:
+ if (c != NULL) {
+ c->dataCallback(msgType, dataPtr);
+ }
+ break;
}
-#endif
-
- client->postJpeg(mem);
#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
}
-void CameraService::Client::autoFocusCallback(bool focused, void *user)
+void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user)
{
- LOGV("autoFocusCallback");
+ LOGV("dataCallbackTimestamp(%d)", msgType);
sp<Client> client = getClientFromCookie(user);
if (client == 0) {
return;
}
+ sp<ICameraClient> c = client->mCameraClient;
- client->postAutoFocus(focused);
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data with timestamp callback");
+ if (c != NULL) {
+ c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ c->dataCallbackTimestamp(0, msgType, NULL);
+ }
+ return;
+ }
+
+ if (c != NULL) {
+ c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+ }
#if DEBUG_CLIENT_REFERENCES
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (DATA CALLBACK TIMESTAMP) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
@@ -1000,8 +1189,7 @@ status_t CameraService::Client::setParameters(const String8& params)
}
CameraParameters p(params);
- mHardware->setParameters(p);
- return NO_ERROR;
+ return mHardware->setParameters(p);
}
// get preview/capture parameters - key/value pairs
@@ -1019,114 +1207,55 @@ String8 CameraService::Client::getParameters() const
return params;
}
-void CameraService::Client::postAutoFocus(bool focused)
+status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
{
- LOGV("postAutoFocus");
- mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0);
-}
-
-void CameraService::Client::postShutter()
-{
- LOGD("postShutter");
- mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
-}
+ LOGD("sendCommand (pid %d)", getCallingPid());
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPid();
+ if (result != NO_ERROR) return result;
-void CameraService::Client::postRaw(const sp<IMemory>& mem)
-{
- LOGD("postRaw");
- mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
-}
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
+ }
-void CameraService::Client::postJpeg(const sp<IMemory>& mem)
-{
- LOGD("postJpeg");
- mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
+ return mHardware->sendCommand(cmd, arg1, arg2);
}
-void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
+void CameraService::Client::copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client,
+ const sp<IMemoryHeap>& heap, size_t offset, size_t size)
{
LOGV("copyFrameAndPostCopiedFrame");
// It is necessary to copy out of pmem before sending this to
// the callback. For efficiency, reuse the same MemoryHeapBase
// provided it's big enough. Don't allocate the memory or
// perform the copy if there's no callback.
- if (mPreviewBuffer == 0) {
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
- } else if (size > mPreviewBuffer->virtualSize()) {
- mPreviewBuffer.clear();
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+
+ // hold the preview lock while we grab a reference to the preview buffer
+ sp<MemoryHeapBase> previewBuffer;
+ {
+ Mutex::Autolock lock(mPreviewLock);
+ if (mPreviewBuffer == 0) {
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ } else if (size > mPreviewBuffer->virtualSize()) {
+ mPreviewBuffer.clear();
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ }
if (mPreviewBuffer == 0) {
LOGE("failed to allocate space for preview buffer");
return;
}
+ previewBuffer = mPreviewBuffer;
}
- memcpy(mPreviewBuffer->base(),
+ memcpy(previewBuffer->base(),
(uint8_t *)heap->base() + offset, size);
- sp<MemoryBase> frame = new MemoryBase(mPreviewBuffer, 0, size);
+ sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
if (frame == 0) {
LOGE("failed to allocate space for frame callback");
return;
}
- mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
-}
-
-void CameraService::Client::postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame)
-{
- LOGV("postRecordingFrame");
- if (frame == 0) {
- LOGW("frame is a null pointer");
- return;
- }
- mCameraClient->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, frame);
-}
-
-void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
-{
- LOGV("postPreviewFrame");
- if (mem == 0) {
- LOGW("mem is a null pointer");
- return;
- }
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- {
- Mutex::Autolock surfaceLock(mSurfaceLock);
- if (mSurface != NULL) {
- mSurface->postBuffer(offset);
- }
- }
-
- // Is the callback enabled or not?
- if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
- // If the enable bit is off, the copy-out and one-shot bits are ignored
- LOGV("frame callback is diabled");
- return;
- }
-
- // Is the received frame copied out or not?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
- LOGV("frame is copied out");
- copyFrameAndPostCopiedFrame(heap, offset, size);
- } else {
- LOGV("frame is directly sent out without copying");
- mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
- }
-
- // Is this is one-shot only?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
- LOGV("One-shot only, thus clear the bits and disable frame callback");
- mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- FRAME_CALLBACK_FLAG_ENABLE_MASK);
- }
-}
-
-void CameraService::Client::postError(status_t error)
-{
- mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0);
+ client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
}
status_t CameraService::dump(int fd, const Vector<String16>& args)
@@ -1160,12 +1289,6 @@ status_t CameraService::dump(int fd, const Vector<String16>& args)
}
-#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 CameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index ea93789..3e3e54f 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -23,10 +23,9 @@
#include <ui/CameraHardwareInterface.h>
#include <ui/Camera.h>
-class android::MemoryHeapBase;
-
namespace android {
+class MemoryHeapBase;
class MediaPlayer;
// ----------------------------------------------------------------------------
@@ -110,6 +109,9 @@ private:
// auto focus
virtual status_t autoFocus();
+ // cancel auto focus
+ virtual status_t cancelAutoFocus();
+
// take a picture - returns an IMemory (ref-counted mmap)
virtual status_t takePicture();
@@ -119,6 +121,9 @@ private:
// get preview/capture parameters - key/value pairs
virtual String8 getParameters() const;
+ // send command to camera driver
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
// our client...
const sp<ICameraClient>& getCameraClient() const { return mCameraClient; }
@@ -132,22 +137,21 @@ private:
status_t checkPid();
- static void recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
- static void previewCallback(const sp<IMemory>& mem, void* user);
- static void shutterCallback(void *user);
- static void yuvPictureCallback(const sp<IMemory>& mem, void* user);
- static void jpegPictureCallback(const sp<IMemory>& mem, void* user);
- static void autoFocusCallback(bool focused, void* user);
+ static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+ static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+ static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user);
+
static sp<Client> getClientFromCookie(void* user);
- void postShutter();
- void postRaw(const sp<IMemory>& mem);
- void postJpeg(const sp<IMemory>& mem);
- void postPreviewFrame(const sp<IMemory>& mem);
- void postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame);
- void copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
- void postError(status_t error);
- void postAutoFocus(bool focused);
+ void handlePreviewData(const sp<IMemory>&);
+ void handleShutter(image_rect_type *image);
+ void handlePostview(const sp<IMemory>&);
+ void handleRawPicture(const sp<IMemory>&);
+ void handleCompressedPicture(const sp<IMemory>&);
+
+ void copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client,
+ const sp<IMemoryHeap>& heap, size_t offset, size_t size);
// camera operation mode
enum camera_mode {
@@ -177,7 +181,6 @@ private:
mutable Condition mReady;
sp<CameraService> mCameraService;
sp<ISurface> mSurface;
- sp<MemoryHeapBase> mPreviewBuffer;
int mPreviewCallbackFlag;
sp<MediaPlayer> mMediaPlayerClick;
@@ -189,6 +192,13 @@ private:
sp<CameraHardwareInterface> mHardware;
pid_t mClientPid;
bool mUseOverlay;
+
+ sp<OverlayRef> mOverlayRef;
+ int mOverlayW;
+ int mOverlayH;
+
+ mutable Mutex mPreviewLock;
+ sp<MemoryHeapBase> mPreviewBuffer;
};
// ----------------------------------------------------------------------------
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
index 3daf44e..15a199f 100644
--- a/cmds/keystore/Android.mk
+++ b/cmds/keystore/Android.mk
@@ -1,22 +1,36 @@
+#
+# 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.
+#
+
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- netkeystore.c keymgmt.c
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, system-core)/cutils \
- external/openssl/include
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils libssl
-
-LOCAL_STATIC_LIBRARIES :=
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := keystore.c
+LOCAL_C_INCLUDES := external/openssl/include
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto
LOCAL_MODULE:= keystore
+include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := keystore_cli.c
+LOCAL_C_INCLUDES := external/openssl/include
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto
+LOCAL_MODULE:= keystore_cli
+LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
-endif # !simulator))
+endif
diff --git a/cmds/keystore/certtool.h b/cmds/keystore/certtool.h
deleted file mode 100644
index aefad66..0000000
--- a/cmds/keystore/certtool.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-**
-** 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 __CERTTOOL_H__
-#define __CERTTOOL_H__
-
-#include <stdio.h>
-#include <string.h>
-#include <cutils/sockets.h>
-#include <cutils/log.h>
-
-#include "common.h"
-#include "netkeystore.h"
-
-#define CERT_NAME_LEN (2 * MAX_KEY_NAME_LENGTH + 2)
-
-/*
- * The specific function 'get_cert' is used in daemons to get the key value
- * from keystore. Caller should allocate the buffer and the length of the buffer
- * should be MAX_KEY_VALUE_LENGTH.
- */
-static inline int get_cert(const char *certname, unsigned char *value, int *size)
-{
- int count, fd, ret = -1;
- LPC_MARSHAL cmd;
- char delimiter[] = "_";
- char *namespace, *keyname;
- char *context = NULL;
- char cname[CERT_NAME_LEN];
-
- if ((certname == NULL) || (value == NULL)) {
- LOGE("get_cert: certname or value is null\n");
- return -1;
- }
-
- if (strlcpy(cname, certname, CERT_NAME_LEN) >= CERT_NAME_LEN) {
- LOGE("get_cert: keyname is too long\n");
- return -1;
- }
-
- fd = socket_local_client(SOCKET_PATH,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (fd == -1) {
- LOGE("Keystore service is not up and running.\n");
- return -1;
- }
-
- cmd.opcode = GET;
- if (((namespace = strtok_r(cname, delimiter, &context)) == NULL) ||
- ((keyname = strtok_r(NULL, delimiter, &context)) == NULL)) {
- goto err;
- }
- if ((cmd.len = snprintf((char*)cmd.data, BUFFER_MAX, "%s %s", namespace, keyname))
- > (2 * MAX_KEY_NAME_LENGTH + 1)) goto err;
-
- if (write_marshal(fd, &cmd)) {
- LOGE("Incorrect command or command line is too long.\n");
- goto err;
- }
- if (read_marshal(fd, &cmd)) {
- LOGE("Failed to read the result.\n");
- goto err;
- }
-
- // copy the result if succeeded.
- if (!cmd.retcode && cmd.len <= BUFFER_MAX) {
- memcpy(value, cmd.data, cmd.len);
- ret = 0;
- *size = cmd.len;
- }
-err:
- close(fd);
- return ret;
-}
-
-#endif
diff --git a/cmds/keystore/common.h b/cmds/keystore/common.h
deleted file mode 100644
index a18114e..0000000
--- a/cmds/keystore/common.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-**
-** 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 __COMMON_H__
-#define __COMMON_H__
-
-#define SOCKET_PATH "keystore"
-#define KEYSTORE_DIR "/data/misc/keystore/"
-
-#define READ_TIMEOUT 3
-#define MAX_KEY_NAME_LENGTH 64
-#define MAX_NAMESPACE_LENGTH MAX_KEY_NAME_LENGTH
-#define MAX_KEY_VALUE_LENGTH 4096
-
-#define BUFFER_MAX MAX_KEY_VALUE_LENGTH
-
-typedef enum {
- BOOTUP,
- UNINITIALIZED,
- LOCKED,
- UNLOCKED,
-} KEYSTORE_STATE;
-
-typedef enum {
- LOCK,
- UNLOCK,
- PASSWD,
- GETSTATE,
- LISTKEYS,
- GET,
- PUT,
- REMOVE,
- RESET,
- MAX_OPCODE
-} KEYSTORE_OPCODE;
-
-typedef struct {
- uint32_t len;
- union {
- uint32_t opcode;
- uint32_t retcode;
- };
- unsigned char data[BUFFER_MAX + 1];
-} LPC_MARSHAL;
-
-#endif
diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c
deleted file mode 100644
index 9a1f845..0000000
--- a/cmds/keystore/keymgmt.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
-** 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-#include <cutils/log.h>
-
-#include "common.h"
-#include "keymgmt.h"
-
-static int retry_count = 0;
-static unsigned char iv[IV_LEN];
-static KEYSTORE_STATE state = BOOTUP;
-static AES_KEY encryptKey, decryptKey;
-
-inline void unlock_keystore(unsigned char *master_key)
-{
- AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey);
- AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey);
- memset(master_key, 0, sizeof(master_key));
- state = UNLOCKED;
-}
-
-inline void lock_keystore()
-{
- memset(&encryptKey, 0 , sizeof(AES_KEY));
- memset(&decryptKey, 0 , sizeof(AES_KEY));
- state = LOCKED;
-}
-
-inline void get_encrypt_key(char *passwd, AES_KEY *key)
-{
- unsigned char user_key[USER_KEY_LEN];
- gen_key(passwd, user_key, USER_KEY_LEN);
- AES_set_encrypt_key(user_key, AES_KEY_LEN, key);
-}
-
-inline void get_decrypt_key(char *passwd, AES_KEY *key)
-{
- unsigned char user_key[USER_KEY_LEN];
- gen_key(passwd, user_key, USER_KEY_LEN);
- AES_set_decrypt_key(user_key, AES_KEY_LEN, key);
-}
-
-static int gen_random_blob(unsigned char *key, int size)
-{
- int ret = 0;
- int fd = open("/dev/urandom", O_RDONLY);
- if (fd == -1) return -1;
- if (read(fd, key, size) != size) ret = -1;
- close(fd);
- return ret;
-}
-
-static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob,
- const char *keyfile)
-{
- int size, fd, ret = -1;
- unsigned char enc_blob[MAX_BLOB_LEN];
- char tmpfile[KEYFILE_LEN];
-
- if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) {
- LOGE("keyfile name is too long or null");
- return -1;
- }
- strcpy(tmpfile, keyfile);
- strcat(tmpfile, ".tmp");
-
- // prepare the blob
- if (IV_LEN > USER_KEY_LEN) {
- LOGE("iv length is too long.");
- return -1;
- }
- memcpy(blob->iv, iv, IV_LEN);
- blob->blob_size = get_blob_size(blob);
- if (blob->blob_size > MAX_BLOB_LEN) {
- LOGE("blob data size is too large.");
- return -1;
- }
- memcpy(enc_blob, blob->blob, blob->blob_size);
- AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
- blob->blob_size, enc_key, iv, AES_ENCRYPT);
- // write to keyfile
- size = data_blob_size(blob);
- if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1;
- if (write(fd, blob, size) == size) ret = 0;
- close(fd);
- if (!ret) {
- unlink(keyfile);
- rename(tmpfile, keyfile);
- chmod(keyfile, 0440);
- }
- return ret;
-}
-
-static int load_n_decrypt(const char *keyname, const char *keyfile,
- AES_KEY *key, DATA_BLOB *blob)
-{
- int fd, ret = -1;
- if ((fd = open(keyfile, O_RDONLY)) == -1) return -1;
- // get the encrypted blob and iv
- if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) ||
- (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) ||
- (blob->blob_size > MAX_BLOB_LEN)) {
- goto err;
- } else {
- unsigned char enc_blob[MAX_BLOB_LEN];
- if (read(fd, enc_blob, blob->blob_size) !=
- (int) blob->blob_size) goto err;
- // decrypt the blob
- AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob,
- blob->blob_size, key, blob->iv, AES_DECRYPT);
- if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0;
- }
-err:
- close(fd);
- return ret;
-}
-
-static int store_master_key(char *upasswd, unsigned char *master_key)
-{
- AES_KEY key;
- DATA_BLOB blob;
-
- // prepare the blob
- if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1;
- strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
- blob.value_size = USER_KEY_LEN;
- if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) {
- LOGE("master_key length is too long.");
- return -1;
- }
- memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
-
- // generate the encryption key
- get_encrypt_key(upasswd, &key);
- return encrypt_n_save(&key, &blob, MASTER_KEY);
-}
-
-static int get_master_key(char *upasswd, unsigned char *master_key)
-{
- AES_KEY key;
- int size, ret = 0;
- DATA_BLOB blob;
-
- get_decrypt_key(upasswd, &key);
- ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
- if (blob.value_size > USER_KEY_LEN) {
- LOGE("the blob's value size is too large");
- return -1;
- }
- if (!ret) memcpy(master_key, blob.value, blob.value_size);
- return ret;
-}
-
-static int create_master_key(char *upasswd)
-{
- int ret;
- unsigned char mpasswd[AES_KEY_LEN];
- unsigned char master_key[USER_KEY_LEN];
-
- gen_random_blob(mpasswd, AES_KEY_LEN);
- gen_key((char*)mpasswd, master_key, USER_KEY_LEN);
- if ((ret = store_master_key(upasswd, master_key)) == 0) {
- unlock_keystore(master_key);
- }
- memset(master_key, 0, USER_KEY_LEN);
- memset(mpasswd, 0, AES_KEY_LEN);
-
- return ret;
-}
-
-static int change_passwd(char *data)
-{
- unsigned char master_key[USER_KEY_LEN];
- char *old_pass, *new_pass = NULL, *p, *delimiter=" ";
- int ret, count = 0;
- char *context = NULL;
-
- old_pass = p = strtok_r(data, delimiter, &context);
- while (p != NULL) {
- count++;
- new_pass = p;
- p = strtok_r(NULL, delimiter, &context);
- }
- if (count != 2) return -1;
- if (strlen(new_pass) < MIN_PASSWD_LENGTH) return -1;
- if ((ret = get_master_key(old_pass, master_key)) == 0) {
- ret = store_master_key(new_pass, master_key);
- retry_count = 0;
- } else {
- ret = MAX_RETRY_COUNT - ++retry_count;
- if (ret == 0) {
- retry_count = 0;
- LOGE("passwd:reach max retry count, reset the keystore now.");
- reset_keystore();
- return -1;
- }
-
- }
- return ret;
-}
-
-int remove_key(const char *namespace, const char *keyname)
-{
- char keyfile[KEYFILE_LEN];
-
- if (state != UNLOCKED) return -state;
- if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
- (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
- LOGE("keyname is too long.");
- return -1;
- }
- sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
- return unlink(keyfile);
-}
-
-int put_key(const char *namespace, const char *keyname,
- unsigned char *data, int size)
-{
- DATA_BLOB blob;
- uint32_t real_size;
- char keyfile[KEYFILE_LEN];
-
- if (state != UNLOCKED) {
- LOGE("Can not store key with current state %d\n", state);
- return -state;
- }
- if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
- (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
- LOGE("keyname is too long.");
- return -1;
- }
- sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
- strcpy(blob.keyname, keyname);
- blob.value_size = size;
- if (size > MAX_KEY_VALUE_LENGTH) {
- LOGE("the data size is too large.");
- return -1;
- }
- memcpy(blob.value, data, size);
- return encrypt_n_save(&encryptKey, &blob, keyfile);
-}
-
-int get_key(const char *namespace, const char *keyname,
- unsigned char *data, int *size)
-{
- int ret;
- DATA_BLOB blob;
- uint32_t blob_size;
- char keyfile[KEYFILE_LEN];
-
- if (state != UNLOCKED) {
- LOGE("Can not retrieve key value with current state %d\n", state);
- return -state;
- }
- if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
- (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
- LOGE("keyname is too long.");
- return -1;
- }
- sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
- ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
- if (!ret) {
- if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
- LOGE("blob value size is too large.");
- ret = -1;
- } else {
- *size = blob.value_size;
- memcpy(data, blob.value, *size);
- }
- }
- return ret;
-}
-
-int list_keys(const char *namespace, char reply[BUFFER_MAX])
-{
- DIR *d;
- struct dirent *de;
-
- if (state != UNLOCKED) {
- LOGE("Can not list key with current state %d\n", state);
- return -1;
- }
-
- if (!namespace || ((d = opendir("."))) == NULL) {
- LOGE("cannot open keystore dir or namespace is null\n");
- return -1;
- }
-
- if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) {
- LOGE("namespace is too long.");
- return -1;
- }
-
- reply[0] = 0;
- while ((de = readdir(d))) {
- char *prefix, *name, *keyfile = de->d_name;
- char *context = NULL;
-
- if (de->d_type != DT_REG) continue;
- if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context))
- == NULL) continue;
- if (strcmp(prefix, namespace)) continue;
- if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue;
- // append the key name into reply
- if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX);
- if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) {
- LOGE("too many files under keystore directory\n");
- return -1;
- }
- }
- closedir(d);
- return 0;
-}
-
-int passwd(char *data)
-{
- if (state == UNINITIALIZED) {
- if (strchr(data, ' ')) return -1;
- if (strlen(data) < MIN_PASSWD_LENGTH) return -1;
- return create_master_key(data);
- }
- return change_passwd(data);
-}
-
-int lock()
-{
- switch(state) {
- case UNLOCKED:
- lock_keystore();
- case LOCKED:
- return 0;
- default:
- return -1;
- }
-}
-
-int unlock(char *passwd)
-{
- unsigned char master_key[USER_KEY_LEN];
- int ret = get_master_key(passwd, master_key);
- if (!ret) {
- unlock_keystore(master_key);
- retry_count = 0;
- } else {
- ret = MAX_RETRY_COUNT - ++retry_count;
- if (ret == 0) {
- retry_count = 0;
- LOGE("unlock:reach max retry count, reset the keystore now.");
- reset_keystore();
- return -1;
- }
- }
- return ret;
-}
-
-KEYSTORE_STATE get_state()
-{
- return state;
-}
-
-int reset_keystore()
-{
- int ret = 0;
- DIR *d;
- struct dirent *de;
-
- if ((d = opendir(".")) == NULL) {
- LOGE("cannot open keystore dir\n");
- return -1;
- }
- while ((de = readdir(d))) {
- if (unlink(de->d_name) != 0) ret = -1;
- }
- closedir(d);
- state = UNINITIALIZED;
- if (ret == 0) {
- LOGI("keystore is reset.");
- } else {
- LOGI("keystore can not be cleaned up entirely.");
- }
- return ret;
-}
-
-int init_keystore(const char *dir)
-{
- int fd;
-
- if (dir) mkdir(dir, 0770);
- if (!dir || chdir(dir)) {
- LOGE("Can not open/create the keystore directory %s\n",
- dir ? dir : "(null)");
- return -1;
- }
- gen_random_blob(iv, IV_LEN);
- if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) {
- state = UNINITIALIZED;
- return 0;
- }
- close(fd);
- state = LOCKED;
- return 0;
-}
diff --git a/cmds/keystore/keymgmt.h b/cmds/keystore/keymgmt.h
deleted file mode 100644
index 0e928db..0000000
--- a/cmds/keystore/keymgmt.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-** 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 __KEYMGMT_H__
-#define __KEYMGMT_H__
-
-#define MASTER_KEY_TAG "master_key"
-#define MASTER_KEY ".keymaster"
-#define MAX_PATH_LEN 128
-#define SALT "Android Keystore 0.1"
-#define NAME_DELIMITER "_"
-#define KEYFILE_NAME "%s"NAME_DELIMITER"%s"
-#define KEYGEN_ITER 1024
-#define AES_KEY_LEN 128
-#define USER_KEY_LEN (AES_KEY_LEN/8)
-#define IV_LEN USER_KEY_LEN
-#define MAX_RETRY_COUNT 6
-#define MIN_PASSWD_LENGTH 8
-
-#define gen_key(passwd, key, len) \
- PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), \
- (unsigned char*)SALT, \
- strlen(SALT), KEYGEN_ITER, \
- len, key)
-
-#define KEYFILE_LEN MAX_NAMESPACE_LENGTH + MAX_KEY_NAME_LENGTH + 6
-
-#define get_blob_size(blob) \
- (((blob->value_size + sizeof(uint32_t) + MAX_KEY_NAME_LENGTH \
- + USER_KEY_LEN - 1) / USER_KEY_LEN) * USER_KEY_LEN)
-
-#define MAX_BLOB_LEN ((MAX_KEY_VALUE_LENGTH + MAX_KEY_NAME_LENGTH + \
- sizeof(uint32_t) + USER_KEY_LEN - 1) / USER_KEY_LEN)\
- * USER_KEY_LEN
-
-#define data_blob_size(blob) USER_KEY_LEN + sizeof(uint32_t) + blob->blob_size
-
-typedef struct {
- unsigned char iv[USER_KEY_LEN];
- uint32_t blob_size;
- union {
- unsigned char blob[1];
- struct {
- uint32_t value_size;
- char keyname[MAX_KEY_NAME_LENGTH];
- unsigned char value[MAX_KEY_VALUE_LENGTH];
- } __attribute__((packed));
- };
-} DATA_BLOB;
-
-typedef struct {
- char tag[USER_KEY_LEN];
- unsigned char master_key[USER_KEY_LEN];
-} MASTER_BLOB;
-
-int put_key(const char *namespace, const char *keyname,
- unsigned char *data, int size);
-int get_key(const char *namespace, const char *keyname,
- unsigned char *data, int *size);
-int remove_key(const char *namespace, const char *keyname);
-int list_keys(const char *namespace, char reply[BUFFER_MAX]);
-int passwd(char *data);
-int lock();
-int unlock(char *passwd);
-KEYSTORE_STATE get_state();
-int reset_keystore();
-int init_keystore(const char *dir);
-
-#endif
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
new file mode 100644
index 0000000..ba74c78
--- /dev/null
+++ b/cmds/keystore/keystore.c
@@ -0,0 +1,542 @@
+/*
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+#define LOG_TAG "keystore"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+
+#include "keystore.h"
+
+/* KeyStore is a secured storage for key-value pairs. In this implementation,
+ * each file stores one key-value pair. Keys are encoded in file names, and
+ * values are encrypted with checksums. The encryption key is protected by a
+ * user-defined password. To keep things simple, buffers are always larger than
+ * the maximum space we needed, so boundary checks on buffers are omitted. */
+
+#define KEY_SIZE 120
+#define VALUE_SIZE 32768
+#define PASSWORD_SIZE VALUE_SIZE
+
+/* Here is the encoding of keys. This is necessary in order to allow arbitrary
+ * characters in keys. Characters in [0-~] are not encoded. Others are encoded
+ * into two bytes. The first byte is one of [+-.] which represents the first
+ * two bits of the character. The second byte encodes the rest of the bits into
+ * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
+ * that Base64 cannot be used here due to the need of prefix match on keys. */
+
+static int encode_key(char *out, uint8_t *in, int length)
+{
+ int i;
+ for (i = length; i > 0; --i, ++in, ++out) {
+ if (*in >= '0' && *in <= '~') {
+ *out = *in;
+ } else {
+ *out = '+' + (*in >> 6);
+ *++out = '0' + (*in & 0x3F);
+ ++length;
+ }
+ }
+ *out = 0;
+ return length;
+}
+
+static int decode_key(uint8_t *out, char *in, int length)
+{
+ int i;
+ for (i = 0; i < length; ++i, ++in, ++out) {
+ if (*in >= '0' && *in <= '~') {
+ *out = *in;
+ } else {
+ *out = (*in - '+') << 6;
+ *out |= (*++in - '0') & 0x3F;
+ --length;
+ }
+ }
+ *out = 0;
+ return length;
+}
+
+/* Here is the protocol used in both requests and responses:
+ * code [length_1 message_1 ... length_n message_n] end-of-file
+ * where code is one byte long and lengths are unsigned 16-bit integers in
+ * network order. Thus the maximum length of a message is 65535 bytes. */
+
+static int the_socket = -1;
+
+static int recv_code(int8_t *code)
+{
+ return recv(the_socket, code, 1, 0) == 1;
+}
+
+static int recv_message(uint8_t *message, int length)
+{
+ uint8_t bytes[2];
+ if (recv(the_socket, &bytes[0], 1, 0) != 1 ||
+ recv(the_socket, &bytes[1], 1, 0) != 1) {
+ return -1;
+ } else {
+ int offset = bytes[0] << 8 | bytes[1];
+ if (length < offset) {
+ return -1;
+ }
+ length = offset;
+ offset = 0;
+ while (offset < length) {
+ int n = recv(the_socket, &message[offset], length - offset, 0);
+ if (n <= 0) {
+ return -1;
+ }
+ offset += n;
+ }
+ }
+ return length;
+}
+
+static int recv_end_of_file()
+{
+ uint8_t byte;
+ return recv(the_socket, &byte, 1, 0) == 0;
+}
+
+static void send_code(int8_t code)
+{
+ send(the_socket, &code, 1, 0);
+}
+
+static void send_message(uint8_t *message, int length)
+{
+ uint16_t bytes = htons(length);
+ send(the_socket, &bytes, 2, 0);
+ send(the_socket, message, length, 0);
+}
+
+/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to
+ * compute their checksums. To make the files portable, the length is stored in
+ * network order. Note that the first four bytes are reserved for future use and
+ * are always set to zero in this implementation. */
+
+static int the_entropy = -1;
+
+static struct __attribute__((packed)) {
+ uint32_t reserved;
+ uint8_t vector[AES_BLOCK_SIZE];
+ uint8_t encrypted[0];
+ uint8_t digest[MD5_DIGEST_LENGTH];
+ uint8_t digested[0];
+ int32_t length;
+ uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
+} blob;
+
+static int8_t encrypt_blob(char *name, AES_KEY *aes_key)
+{
+ uint8_t vector[AES_BLOCK_SIZE];
+ int length = blob.length;
+ int fd;
+
+ if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) {
+ return SYSTEM_ERROR;
+ }
+
+ length += blob.value - blob.digested;
+ blob.length = htonl(blob.length);
+ MD5(blob.digested, length, blob.digest);
+
+ length += blob.digested - blob.encrypted;
+ length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
+ memcpy(vector, blob.vector, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
+ AES_ENCRYPT);
+
+ blob.reserved = 0;
+ length += blob.encrypted - (uint8_t *)&blob;
+
+ fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1 || write(fd, &blob, length) != length) {
+ return SYSTEM_ERROR;
+ }
+ close(fd);
+ return rename(".tmp", name) ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static int8_t decrypt_blob(char *name, AES_KEY *aes_key)
+{
+ int fd = open(name, O_RDONLY);
+ int length;
+
+ if (fd == -1) {
+ return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
+ }
+ length = read(fd, &blob, sizeof(blob));
+ close(fd);
+
+ length -= blob.encrypted - (uint8_t *)&blob;
+ if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
+ return VALUE_CORRUPTED;
+ }
+
+ AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key,
+ blob.vector, AES_DECRYPT);
+ length -= blob.digested - blob.encrypted;
+ if (!memcmp(blob.digest, MD5(blob.digested, length, NULL),
+ MD5_DIGEST_LENGTH)) {
+ return VALUE_CORRUPTED;
+ }
+
+ length -= blob.value - blob.digested;
+ blob.length = ntohl(blob.length);
+ return (length < blob.length) ? VALUE_CORRUPTED : NO_ERROR;
+}
+
+/* Here are the actions. Each of them is a function without arguments. All
+ * information is defined in global variables, which are set properly before
+ * performing an action. The number of parameters required by each action is
+ * fixed and defined in a table. If the return value of an action is positive,
+ * it will be treated as a response code and transmitted to the client. Note
+ * that the lengths of parameters are checked when they are received, so
+ * boundary checks on parameters are omitted. */
+
+#define MAX_PARAM 2
+#define MAX_RETRY 4
+
+static uid_t uid = -1;
+static int8_t state = UNINITIALIZED;
+static int8_t retry = MAX_RETRY;
+
+static struct {
+ int length;
+ uint8_t value[VALUE_SIZE];
+} params[MAX_PARAM];
+
+static AES_KEY encryption_key;
+static AES_KEY decryption_key;
+
+static int8_t test()
+{
+ return state;
+}
+
+static int8_t get()
+{
+ char name[NAME_MAX];
+ int n = sprintf(name, "%u_", uid);
+ encode_key(&name[n], params[0].value, params[0].length);
+ n = decrypt_blob(name, &decryption_key);
+ if (n != NO_ERROR) {
+ return n;
+ }
+ send_code(NO_ERROR);
+ send_message(blob.value, blob.length);
+ return -NO_ERROR;
+}
+
+static int8_t insert()
+{
+ char name[NAME_MAX];
+ int n = sprintf(name, "%u_", uid);
+ encode_key(&name[n], params[0].value, params[0].length);
+ blob.length = params[1].length;
+ memcpy(blob.value, params[1].value, params[1].length);
+ return encrypt_blob(name, &encryption_key);
+}
+
+static int8_t delete()
+{
+ char name[NAME_MAX];
+ int n = sprintf(name, "%u_", uid);
+ encode_key(&name[n], params[0].value, params[0].length);
+ return (unlink(name) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static int8_t exist()
+{
+ char name[NAME_MAX];
+ int n = sprintf(name, "%u_", uid);
+ encode_key(&name[n], params[0].value, params[0].length);
+ if (access(name, R_OK) == -1) {
+ return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+static int8_t saw()
+{
+ DIR *dir = opendir(".");
+ struct dirent *file;
+ char name[NAME_MAX];
+ int n;
+
+ if (!dir) {
+ return SYSTEM_ERROR;
+ }
+ n = sprintf(name, "%u_", uid);
+ n += encode_key(&name[n], params[0].value, params[0].length);
+ send_code(NO_ERROR);
+ while ((file = readdir(dir)) != NULL) {
+ if (!strncmp(name, file->d_name, n)) {
+ char *p = &file->d_name[n];
+ params[0].length = decode_key(params[0].value, p, strlen(p));
+ send_message(params[0].value, params[0].length);
+ }
+ }
+ closedir(dir);
+ return -NO_ERROR;
+}
+
+static int8_t reset()
+{
+ DIR *dir = opendir(".");
+ struct dirent *file;
+
+ memset(&encryption_key, 0, sizeof(encryption_key));
+ memset(&decryption_key, 0, sizeof(decryption_key));
+ state = UNINITIALIZED;
+ retry = MAX_RETRY;
+
+ if (!dir) {
+ return SYSTEM_ERROR;
+ }
+ while ((file = readdir(dir)) != NULL) {
+ unlink(file->d_name);
+ }
+ closedir(dir);
+ return NO_ERROR;
+}
+
+#define MASTER_KEY_FILE ".masterkey"
+#define MASTER_KEY_SIZE 16
+
+static void generate_key(uint8_t *key, uint8_t *password, int length)
+{
+ PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
+ sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+}
+
+static int8_t password()
+{
+ uint8_t key[MASTER_KEY_SIZE];
+ AES_KEY aes_key;
+ int n;
+
+ if (state == UNINITIALIZED) {
+ blob.length = MASTER_KEY_SIZE;
+ if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
+ return SYSTEM_ERROR;
+ }
+ } else {
+ generate_key(key, params[0].value, params[0].length);
+ AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
+ n = decrypt_blob(MASTER_KEY_FILE, &aes_key);
+ if (n == SYSTEM_ERROR) {
+ return SYSTEM_ERROR;
+ }
+ if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
+ if (retry <= 0) {
+ reset();
+ return UNINITIALIZED;
+ }
+ return WRONG_PASSWORD + --retry;
+ }
+ }
+
+ if (params[1].length == -1) {
+ memcpy(key, blob.value, MASTER_KEY_SIZE);
+ } else {
+ generate_key(key, params[1].value, params[1].length);
+ AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
+ memcpy(key, blob.value, MASTER_KEY_SIZE);
+ n = encrypt_blob(MASTER_KEY_FILE, &aes_key);
+ }
+
+ if (n == NO_ERROR) {
+ AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
+ AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
+ state = NO_ERROR;
+ retry = MAX_RETRY;
+ }
+ return n;
+}
+
+static int8_t lock()
+{
+ memset(&encryption_key, 0, sizeof(encryption_key));
+ memset(&decryption_key, 0, sizeof(decryption_key));
+ state = LOCKED;
+ return NO_ERROR;
+}
+
+static int8_t unlock()
+{
+ params[1].length = -1;
+ return password();
+}
+
+/* Here are the permissions, actions, users, and the main function. */
+
+enum perm {
+ TEST = 1,
+ GET = 2,
+ INSERT = 4,
+ DELETE = 8,
+ EXIST = 16,
+ SAW = 32,
+ RESET = 64,
+ PASSWORD = 128,
+ LOCK = 256,
+ UNLOCK = 512,
+};
+
+static struct action {
+ int8_t (*run)();
+ int8_t code;
+ int8_t state;
+ uint32_t perm;
+ int lengths[MAX_PARAM];
+} actions[] = {
+ {test, 't', 0, TEST, {0}},
+ {get, 'g', NO_ERROR, GET, {KEY_SIZE}},
+ {insert, 'i', NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}},
+ {delete, 'd', 0, DELETE, {KEY_SIZE}},
+ {exist, 'e', 0, EXIST, {KEY_SIZE}},
+ {saw, 's', 0, SAW, {KEY_SIZE}},
+ {reset, 'r', 0, RESET, {0}},
+ {password, 'p', 0, PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}},
+ {lock, 'l', NO_ERROR, LOCK, {0}},
+ {unlock, 'u', LOCKED, UNLOCK, {PASSWORD_SIZE}},
+ {NULL, 0 , 0, 0, {0}},
+};
+
+static struct user {
+ uid_t uid;
+ uid_t euid;
+ uint32_t perms;
+} users[] = {
+ {AID_SYSTEM, 0, ~GET},
+ {AID_VPN, AID_SYSTEM, GET},
+ {AID_WIFI, AID_SYSTEM, GET},
+ {0, 0, TEST | GET | INSERT | DELETE | EXIST | SAW},
+};
+
+static int8_t process(int8_t code) {
+ struct user *user = users;
+ struct action *action = actions;
+ int i;
+
+ while (user->uid && user->uid != uid) {
+ ++user;
+ }
+ while (action->code && action->code != code) {
+ ++action;
+ }
+ if (!action->code) {
+ return UNDEFINED_ACTION;
+ }
+ if (!(action->perm & user->perms)) {
+ return PERMISSION_DENIED;
+ }
+ if (action->state && action->state != state) {
+ return state;
+ }
+ if (user->euid) {
+ uid = user->euid;
+ }
+ for (i = 0; i < MAX_PARAM && action->lengths[i]; ++i) {
+ params[i].length = recv_message(params[i].value, action->lengths[i]);
+ if (params[i].length == -1) {
+ return PROTOCOL_ERROR;
+ }
+ }
+ if (!recv_end_of_file()) {
+ return PROTOCOL_ERROR;
+ }
+ return action->run();
+}
+
+#define RANDOM_DEVICE "/dev/urandom"
+
+int main(int argc, char **argv)
+{
+ int control_socket = android_get_control_socket("keystore");
+ if (argc < 2) {
+ LOGE("A directory must be specified!");
+ return 1;
+ }
+ if (chdir(argv[1]) == -1) {
+ LOGE("chdir: %s: %s", argv[1], strerror(errno));
+ return 1;
+ }
+ if ((the_entropy = open(RANDOM_DEVICE, O_RDONLY)) == -1) {
+ LOGE("open: %s: %s", RANDOM_DEVICE, strerror(errno));
+ return 1;
+ }
+ if (listen(control_socket, 3) == -1) {
+ LOGE("listen: %s", strerror(errno));
+ return 1;
+ }
+
+ signal(SIGPIPE, SIG_IGN);
+ if (access(MASTER_KEY_FILE, R_OK) == 0) {
+ state = LOCKED;
+ }
+
+ while ((the_socket = accept(control_socket, NULL, 0)) != -1) {
+ struct timeval tv = {.tv_sec = 3};
+ struct ucred cred;
+ socklen_t size = sizeof(cred);
+ int8_t request;
+
+ setsockopt(the_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ setsockopt(the_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
+ if (getsockopt(the_socket, SOL_SOCKET, SO_PEERCRED, &cred, &size)) {
+ LOGW("getsockopt: %s", strerror(errno));
+ } else if (recv_code(&request)) {
+ int8_t old_state = state;
+ int8_t response;
+ uid = cred.uid;
+
+ if ((response = process(request)) > 0) {
+ send_code(response);
+ response = -response;
+ }
+
+ LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
+ cred.uid, request, -response, old_state, state, retry);
+ }
+ close(the_socket);
+ }
+ LOGE("accept: %s", strerror(errno));
+ return 1;
+}
diff --git a/include/utils/executablepath.h b/cmds/keystore/keystore.h
index c979432..5ef51e9 100644
--- a/include/utils/executablepath.h
+++ b/cmds/keystore/keystore.h
@@ -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,15 +14,20 @@
* limitations under the License.
*/
-#ifndef _UTILS_EXECUTABLEPATH_H
-#define _UTILS_EXECUTABLEPATH_H
+#ifndef __KEYSTORE_H__
+#define __KEYSTORE_H__
-#include <limits.h>
+enum response_code {
+ NO_ERROR = 1,
+ LOCKED = 2,
+ UNINITIALIZED = 3,
+ SYSTEM_ERROR = 4,
+ PROTOCOL_ERROR = 5,
+ PERMISSION_DENIED = 6,
+ KEY_NOT_FOUND = 7,
+ VALUE_CORRUPTED = 8,
+ UNDEFINED_ACTION = 9,
+ WRONG_PASSWORD = 10,
+};
-// returns the path to this executable
-#if __cplusplus
-extern "C"
#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _UTILS_EXECUTABLEPATH_H
diff --git a/cmds/keystore/keystore_cli.c b/cmds/keystore/keystore_cli.c
new file mode 100644
index 0000000..e8afb5a
--- /dev/null
+++ b/cmds/keystore/keystore_cli.c
@@ -0,0 +1,97 @@
+/*
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <cutils/sockets.h>
+
+#include "keystore.h"
+
+char *responses[256] = {
+ [NO_ERROR] = "No error",
+ [LOCKED] = "Locked",
+ [UNINITIALIZED] = "Uninitialized",
+ [SYSTEM_ERROR] = "System error",
+ [PROTOCOL_ERROR] = "Protocol error",
+ [PERMISSION_DENIED] = "Permission denied",
+ [KEY_NOT_FOUND] = "Key not found",
+ [VALUE_CORRUPTED] = "Value corrupted",
+ [UNDEFINED_ACTION] = "Undefined action",
+ [WRONG_PASSWORD] = "Wrong password (last chance)",
+ [WRONG_PASSWORD + 1] = "Wrong password (2 tries left)",
+ [WRONG_PASSWORD + 2] = "Wrong password (3 tries left)",
+ [WRONG_PASSWORD + 3] = "Wrong password (4 tries left)",
+};
+
+#define MAX_RESPONSE (WRONG_PASSWORD + 3)
+
+int main(int argc, char **argv)
+{
+ uint8_t bytes[65536];
+ uint8_t code;
+ int sock, i;
+
+ if (argc < 2) {
+ printf("Usage: %s action [parameter ...]\n", argv[0]);
+ return 0;
+ }
+
+ sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock == -1) {
+ puts("Failed to connect");
+ return 1;
+ }
+
+ send(sock, argv[1], 1, 0);
+ for (i = 2; i < argc; ++i) {
+ uint16_t length = strlen(argv[i]);
+ bytes[0] = length >> 8;
+ bytes[1] = length;
+ send(sock, &bytes, 2, 0);
+ send(sock, argv[i], length, 0);
+ }
+ shutdown(sock, SHUT_WR);
+
+ if (recv(sock, &code, 1, 0) != 1) {
+ puts("Failed to receive");
+ return 1;
+ }
+ printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
+ while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
+ int length;
+ int offset;
+ if ((i = recv(sock, &bytes[1], 1, 0)) != 1) {
+ puts("Failed to receive");
+ return 1;
+ }
+ length = bytes[0] << 8 | bytes[1];
+ for (offset = 0; offset < length; offset += i) {
+ i = recv(sock, &bytes[offset], length - offset, 0);
+ if (i <= 0) {
+ puts("Failed to receive");
+ return 1;
+ }
+ }
+ fwrite(bytes, 1, length, stdout);
+ puts("");
+ }
+ return 0;
+}
diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h
index 7665e81..0e7e1ae 100644
--- a/cmds/keystore/keystore_get.h
+++ b/cmds/keystore/keystore_get.h
@@ -1,53 +1,69 @@
/*
-**
-** 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.
-*/
+ * 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 __KEYSTORE_GET_H__
#define __KEYSTORE_GET_H__
#include <stdio.h>
-#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
-#include "certtool.h"
+#include <cutils/sockets.h>
-/* This function is provided to native components to get values from keystore.
- * Users are required to link against libcutils. If something goes wrong, NULL
- * is returned. Otherwise it returns the value in dynamically allocated memory
- * and sets the size if the pointer is not NULL. One can release the memory by
- * calling free(). */
-static char *keystore_get(const char *key, int *size)
+#define KEYSTORE_MESSAGE_SIZE 65535
+
+/* This function is provided for native components to get values from keystore.
+ * Users are required to link against libcutils. The lengths of keys and values
+ * are limited to KEYSTORE_MESSAGE_SIZE. This function returns the length of
+ * the requested value or -1 if something goes wrong. */
+static int keystore_get(const char *key, char *value)
{
- char buffer[MAX_KEY_VALUE_LENGTH];
- char *value;
- int length;
+ int length = strlen(key);
+ uint8_t bytes[2] = {length >> 8, length};
+ uint8_t code = 'g';
+ int sock;
- if (get_cert(key, (unsigned char *)buffer, &length) != 0) {
- return NULL;
+ if (length > KEYSTORE_MESSAGE_SIZE) {
+ return -1;
}
- value = malloc(length + 1);
- if (!value) {
- return NULL;
+ sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock == -1) {
+ return -1;
}
- memcpy(value, buffer, length);
- value[length] = 0;
- if (size) {
- *size = length;
+ if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 &&
+ send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 &&
+ recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 &&
+ recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) {
+ int offset = 0;
+ length = bytes[0] << 8 | bytes[1];
+ while (offset < length) {
+ int n = recv(sock, &value[offset], length - offset, 0);
+ if (n <= 0) {
+ length = -1;
+ break;
+ }
+ offset += n;
+ }
}
- return value;
+ close(sock);
+ return length;
}
#endif
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
deleted file mode 100644
index 637e0d8..0000000
--- a/cmds/keystore/netkeystore.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
-** 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.
-*/
-
-#define LOG_TAG "keystore"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <utime.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <private/android_filesystem_config.h>
-
-#include <cutils/sockets.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include "netkeystore.h"
-#include "keymgmt.h"
-
-#define DBG 1
-#define CMD_PUT_WITH_FILE "putfile"
-
-typedef void CMD_FUNC(LPC_MARSHAL *cmd, LPC_MARSHAL *reply);
-
-struct cmdinfo {
- const char *name;
- CMD_FUNC *func;
-};
-
-static CMD_FUNC do_lock;
-static CMD_FUNC do_unlock;
-static CMD_FUNC do_passwd;
-static CMD_FUNC do_get_state;;
-static CMD_FUNC do_listkeys;
-static CMD_FUNC do_get_key;
-static CMD_FUNC do_put_key;
-static CMD_FUNC do_remove_key;
-static CMD_FUNC do_reset_keystore;
-
-#define str(x) #x
-
-struct cmdinfo cmds[] = {
- { str(LOCK), do_lock },
- { str(UNLOCK), do_unlock },
- { str(PASSWD), do_passwd },
- { str(GETSTATE), do_get_state },
- { str(LISTKEYS), do_listkeys },
- { str(GET), do_get_key },
- { str(PUT), do_put_key },
- { str(REMOVE), do_remove_key },
- { str(RESET), do_reset_keystore },
-};
-
-static struct ucred cr;
-
-static int check_get_perm(int uid)
-{
- if (uid == AID_WIFI || uid == AID_VPN) return 0;
- return -1;
-}
-
-static int check_reset_perm(int uid)
-{
- if (uid == AID_SYSTEM) return 0;
- return -1;
-}
-
-static int parse_keyname(char *name, uint32_t len,
- char *namespace, char *keyname)
-{
- int count = 0;
- char *c = namespace, *p = namespace, *t = name;
-
- if (!name || !namespace || !keyname) return -1;
- while (t < name + len && (*t != 0)) {
- if (*t == ' ') {
- if (c == keyname) return -1;
- *p = count = 0;
- c = p = keyname;
- t++;
- } else {
- if (!isalnum(*t)) return -1;
- *p++ = *t++;
- // also check if the keyname/namespace is too long.
- if (count++ == MAX_KEY_NAME_LENGTH) return -1;
- }
- }
- *p = 0;
- return 0;
-}
-
-// args of passwd():
-// firstPassword - for the first time
-// oldPassword newPassword - for changing the password
-static void do_passwd(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- reply->retcode = passwd((char*)cmd->data);
-}
-
-// args of lock():
-// no argument
-static void do_lock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- reply->retcode = lock();
-}
-
-// args of unlock():
-// password
-static void do_unlock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- reply->retcode = unlock((char*)cmd->data);
-}
-
-// args of get_state():
-// no argument
-static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- reply->retcode = get_state();
-}
-
-// args of listkeys():
-// namespace
-static void do_listkeys(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- reply->retcode = list_keys((const char*)cmd->data, (char*)reply->data);
- if (!reply->retcode) reply->len = strlen((char*)reply->data);
-}
-
-// args of get():
-// namespace keyname
-static void do_get_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- char namespace[MAX_KEY_NAME_LENGTH];
- char keyname[MAX_KEY_NAME_LENGTH];
-
- if (check_get_perm(cr.uid)) {
- LOGE("uid %d doesn't have the permission to get key value\n", cr.uid);
- reply->retcode = -1;
- return;
- }
-
- if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) {
- reply->retcode = -1;
- } else {
- reply->retcode = get_key(namespace, keyname, reply->data,
- (int*)&reply->len);
- }
-}
-
-static int get_value_index(LPC_MARSHAL *cmd)
-{
- uint32_t count = 0, i;
- for (i = 0 ; i < cmd->len ; ++i) {
- if (cmd->data[i] == ' ') {
- if (++count == 2) return ++i;
- }
- }
- return -1;
-}
-
-// args of put():
-// namespace keyname keyvalue
-static void do_put_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- char namespace[MAX_KEY_NAME_LENGTH];
- char keyname[MAX_KEY_NAME_LENGTH];
-
- int p = get_value_index(cmd);
- if (p == -1) {
- reply->retcode = -1;
- } else {
- unsigned char *value;
- if (parse_keyname((char*)cmd->data, p - 1, namespace, keyname)) {
- reply->retcode = -1;
- return;
- }
- value = &cmd->data[p];
- int len = cmd->len - p;
- reply->retcode = put_key(namespace, keyname, value, len);
- }
-}
-
-// args of remove_key():
-// namespace keyname
-static void do_remove_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- char namespace[MAX_KEY_NAME_LENGTH];
- char keyname[MAX_KEY_NAME_LENGTH];
- if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) {
- reply->retcode = -1;
- return;
- }
- reply->retcode = remove_key(namespace, keyname);
-}
-
-// args of reset_keystore():
-// no argument
-static void do_reset_keystore(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- if (check_reset_perm(cr.uid)) {
- LOGE("uid %d doesn't have the permission to reset the keystore\n",
- cr.uid);
- reply->retcode = -1;
- return;
- }
- reply->retcode = reset_keystore();
-}
-
-static void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
-{
- uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo);
-
- if (cmd->opcode >= cmd_max) {
- LOGE("the opcode (%d) is not valid", cmd->opcode);
- reply->retcode = -1;
- return;
- }
- cmds[cmd->opcode].func(cmd, reply);
-}
-
-static int set_read_timeout(int socket)
-{
- struct timeval tv;
- tv.tv_sec = READ_TIMEOUT;
- if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
- {
- LOGE("setsockopt failed");
- return -1;
- }
- return 0;
-}
-
-static int append_input_from_file(const char *filename, LPC_MARSHAL *cmd)
-{
- int fd, len, ret = 0;
-
- // get opcode of the function put()
- if ((fd = open(filename, O_RDONLY)) == -1) {
- fprintf(stderr, "Can not open file %s\n", filename);
- return -1;
- }
- cmd->data[cmd->len] = ' ';
- cmd->len++;
- len = read(fd, cmd->data + cmd->len, BUFFER_MAX - cmd->len);
- if (len < 0 || (len == (int)(BUFFER_MAX - cmd->len))) {
- ret = -1;
- } else {
- cmd->len += len;
- }
- close(fd);
- return ret;
-}
-
-static int flatten_str_args(int argc, const char **argv, LPC_MARSHAL *cmd)
-{
- int i, len = 0;
- char *buf = (char*)cmd->data;
- buf[0] = 0;
- for (i = 0 ; i < argc ; ++i) {
- if (i == 0) {
- len = strlcpy(buf, argv[i], BUFFER_MAX);
- } else {
- len += snprintf(buf + len, BUFFER_MAX - len, " %s", argv[i]);
- }
- if (len >= BUFFER_MAX) return -1;
- }
- if (len) cmd->len = len;
- return 0;
-}
-
-static int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd)
-{
- uint32_t i, len = 0;
- uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]);
-
- for (i = 0 ; i < cmd_max ; ++i) {
- if (!strcasecmp(argv[0], cmds[i].name)) break;
- }
-
- if (i == cmd_max) {
- // check if this is a command to put the key value with a file.
- if (strcmp(argv[0], CMD_PUT_WITH_FILE) != 0) return -1;
- cmd->opcode = PUT;
- if (argc != 4) {
- fprintf(stderr, "%s args\n\tnamespace keyname filename\n",
- argv[0]);
- return -1;
- }
- if (flatten_str_args(argc - 2, argv + 1, cmd)) return -1;
- return append_input_from_file(argv[3], cmd);
- } else {
- cmd->opcode = i;
- return flatten_str_args(argc - 1, argv + 1, cmd);
- }
-}
-
-static int shell_command(const int argc, const char **argv)
-{
- int fd, i;
- LPC_MARSHAL cmd;
-
- if (parse_cmd(argc, argv , &cmd)) {
- fprintf(stderr, "Incorrect command or command line is too long.\n");
- exit(1);
- }
- fd = socket_local_client(SOCKET_PATH,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (fd == -1) {
- fprintf(stderr, "Keystore service is not up and running.\n");
- exit(1);
- }
-
- if (write_marshal(fd, &cmd)) {
- fprintf(stderr, "Incorrect command or command line is too long.\n");
- exit(1);
- }
- if (read_marshal(fd, &cmd)) {
- fprintf(stderr, "Failed to read the result.\n");
- exit(1);
- }
- cmd.data[cmd.len] = 0;
- fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!");
- if (cmd.len) fprintf(stdout, "\t%s\n", (char*)cmd.data);
- close(fd);
- return 0;
-}
-
-int main(const int argc, const char *argv[])
-{
- struct sockaddr addr;
- socklen_t alen;
- int lsocket, s;
- LPC_MARSHAL cmd, reply;
-
- if (argc > 1) {
- return shell_command(argc - 1, argv + 1);
- }
-
- if (init_keystore(KEYSTORE_DIR)) {
- LOGE("Can not initialize the keystore, the directory exist?\n");
- exit(1);
- }
-
- lsocket = android_get_control_socket(SOCKET_PATH);
- if (lsocket < 0) {
- LOGE("Failed to get socket from environment: %s\n", strerror(errno));
- exit(1);
- }
- if (listen(lsocket, 5)) {
- LOGE("Listen on socket failed: %s\n", strerror(errno));
- exit(1);
- }
- fcntl(lsocket, F_SETFD, FD_CLOEXEC);
- memset(&reply, 0, sizeof(LPC_MARSHAL));
-
- for (;;) {
- socklen_t cr_size = sizeof(cr);
- alen = sizeof(addr);
- s = accept(lsocket, &addr, &alen);
-
- /* retrieve the caller info here */
- if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
- close(s);
- LOGE("Unable to recieve socket options\n");
- continue;
- }
-
- if (s < 0) {
- LOGE("Accept failed: %s\n", strerror(errno));
- continue;
- }
- fcntl(s, F_SETFD, FD_CLOEXEC);
- if (set_read_timeout(s)) {
- close(s);
- continue;
- }
-
- // read the command, execute and send the result back.
- if(read_marshal(s, &cmd)) goto err;
- if (DBG) LOGD("new connection\n");
- execute(&cmd, &reply);
- write_marshal(s, &reply);
-err:
- memset(&reply, 0, sizeof(LPC_MARSHAL));
- if (DBG) LOGD("closing connection\n");
- close(s);
- }
-
- return 0;
-}
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
deleted file mode 100644
index a87a667..0000000
--- a/cmds/keystore/netkeystore.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-**
-** 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 __NETKEYSTORE_H__
-#define __NETKEYSTORE_H__
-
-#include <stdio.h>
-#include <cutils/sockets.h>
-#include <cutils/log.h>
-
-#include "common.h"
-
-static inline int readx(int s, void *_buf, int count)
-{
- char *buf = _buf;
- int n = 0, r;
- if (count < 0) return -1;
- while (n < count) {
- r = read(s, buf + n, count - n);
- if (r < 0) {
- if (errno == EINTR) continue;
- LOGE("read error: %s\n", strerror(errno));
- return -1;
- }
- if (r == 0) {
- LOGE("eof\n");
- return -1; /* EOF */
- }
- n += r;
- }
- return 0;
-}
-
-static inline int writex(int s, const void *_buf, int count)
-{
- const char *buf = _buf;
- int n = 0, r;
- if (count < 0) return -1;
- while (n < count) {
- r = write(s, buf + n, count - n);
- if (r < 0) {
- if (errno == EINTR) continue;
- LOGE("write error: %s\n", strerror(errno));
- return -1;
- }
- n += r;
- }
- return 0;
-}
-
-static inline int read_marshal(int s, LPC_MARSHAL *cmd)
-{
- if (readx(s, cmd, 2 * sizeof(uint32_t))) {
- LOGE("failed to read header\n");
- return -1;
- }
- if (cmd->len > BUFFER_MAX) {
- LOGE("invalid size %d\n", cmd->len);
- return -1;
- }
- if (readx(s, cmd->data, cmd->len)) {
- LOGE("failed to read data\n");
- return -1;
- }
- cmd->data[cmd->len] = 0;
- return 0;
-}
-
-static inline int write_marshal(int s, LPC_MARSHAL *cmd)
-{
- if (writex(s, cmd, 2 * sizeof(uint32_t))) {
- LOGE("failed to write marshal header\n");
- return -1;
- }
- if (writex(s, cmd->data, cmd->len)) {
- LOGE("failed to write marshal data\n");
- return -1;
- }
- return 0;
-}
-
-#endif
diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c
deleted file mode 100644
index e7e686b..0000000
--- a/cmds/keystore/tests/netkeystore_test.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "common.h"
-#include "keymgmt.h"
-
-typedef int FUNC_PTR();
-typedef struct {
- const char *name;
- FUNC_PTR *func;
-} TESTFUNC;
-
-#define FUNC_NAME(x) { #x, test_##x }
-#define FUNC_BODY(x) int test_##x()
-
-#define TEST_PASSWD "12345678"
-#define TEST_NPASSWD "11111111"
-#define TEST_DIR "/data/local/tmp/keystore"
-#define READONLY_DIR "/proc/keystore"
-#define TEST_NAMESPACE "test"
-#define TEST_KEYNAME "key"
-#define TEST_KEYNAME2 "key2"
-#define TEST_KEYVALUE "ANDROID"
-
-void setup()
-{
- if (init_keystore(TEST_DIR) != 0) {
- fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR);
- exit(-1);
- }
-}
-
-void teardown()
-{
- reset_keystore();
- rmdir(TEST_DIR);
-}
-
-FUNC_BODY(init_keystore)
-{
- if (init_keystore(READONLY_DIR) == 0) return -1;
-
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(reset_keystore)
-{
- chdir("/procx");
- if (reset_keystore() == 0) return -1;
- chdir(TEST_DIR);
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(get_state)
-{
- if (get_state() != UNINITIALIZED) return -1;
- passwd(TEST_PASSWD);
- if (get_state() != UNLOCKED) return -1;
- lock();
- if (get_state() != LOCKED) return -1;
- reset_keystore();
- if (get_state() != UNINITIALIZED) return -1;
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(passwd)
-{
- char buf[512];
-
- if (passwd(" 23432dsfsdf") == 0) return -1;
- if (passwd("dsfsdf") == 0) return -1;
- passwd(TEST_PASSWD);
- lock();
- if (unlock("55555555") == 0) return -1;
- if (unlock(TEST_PASSWD) != 0) return -1;
-
- // change the password
- sprintf(buf, "%s %s", "klfdjdsklfjg", "abcdefghi");
- if (passwd(buf) == 0) return -1;
-
- sprintf(buf, "%s %s", TEST_PASSWD, TEST_NPASSWD);
- if (passwd(buf) != 0) return -1;
- lock();
-
- if (unlock(TEST_PASSWD) == 0) return -1;
- if (unlock(TEST_NPASSWD) != 0) return -1;
-
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(lock)
-{
- if (lock() == 0) return -1;
- passwd(TEST_PASSWD);
- if (lock() != 0) return -1;
- if (lock() != 0) return -1;
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(unlock)
-{
- int i = MAX_RETRY_COUNT;
- passwd(TEST_PASSWD);
- lock();
- while (i > 1) {
- if (unlock(TEST_NPASSWD) != --i) return -1;
- }
- if (unlock(TEST_NPASSWD) != -1) return -1;
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(put_key)
-{
- int i = 0;
- char keyname[512];
-
- if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE)) == 0) return -1;
- passwd(TEST_PASSWD);
- if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE)) != 0) return -1;
-
- for(i = 0; i < 500; i++) keyname[i] = 'K';
- keyname[i] = 0;
- if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE)) == 0) return -1;
- if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- MAX_KEY_VALUE_LENGTH + 1) == 0) return -1;
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(get_key)
-{
- int size;
- unsigned char data[MAX_KEY_VALUE_LENGTH];
-
- if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1;
-
- passwd(TEST_PASSWD);
- put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE));
- if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1;
- if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1;
-
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(remove_key)
-{
- if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
-
- passwd(TEST_PASSWD);
- if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
-
- put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE));
- if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1;
-
- return EXIT_SUCCESS;
-}
-
-FUNC_BODY(list_keys)
-{
- int i;
- char buf[128];
- char reply[BUFFER_MAX];
-
- for(i = 0; i < 100; i++) buf[i] = 'K';
- buf[i] = 0;
-
- if (list_keys(TEST_NAMESPACE, reply) == 0) return -1;
-
- passwd(TEST_PASSWD);
- if (list_keys(buf, reply) == 0) return -1;
-
- if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
- if (strcmp(reply, "") != 0) return -1;
-
- put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE));
- if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
- if (strcmp(reply, TEST_KEYNAME) != 0) return -1;
-
- put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE,
- strlen(TEST_KEYVALUE));
-
- if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
- sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME);
- if (strcmp(reply, buf) != 0) return -1;
-
- return EXIT_SUCCESS;
-}
-
-TESTFUNC all_tests[] = {
- FUNC_NAME(init_keystore),
- FUNC_NAME(reset_keystore),
- FUNC_NAME(get_state),
- FUNC_NAME(passwd),
- FUNC_NAME(lock),
- FUNC_NAME(unlock),
- FUNC_NAME(put_key),
- FUNC_NAME(get_key),
- FUNC_NAME(remove_key),
- FUNC_NAME(list_keys),
-};
-
-int main(int argc, char **argv) {
- int i, ret;
- for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) {
- setup();
- if ((ret = all_tests[i].func()) != EXIT_SUCCESS) {
- fprintf(stderr, "ERROR in function %s\n", all_tests[i].name);
- return ret;
- } else {
- fprintf(stderr, "function %s PASSED!\n", all_tests[i].name);
- }
- teardown();
- }
- return EXIT_SUCCESS;
-}
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
index 521eb2b..6a72d10 100644
--- a/cmds/runtime/Android.mk
+++ b/cmds/runtime/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libutils \
+ libbinder \
libandroid_runtime \
libcutils \
libui \
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
index 758a95c..b2bef07 100644
--- a/cmds/runtime/ServiceManager.cpp
+++ b/cmds/runtime/ServiceManager.cpp
@@ -9,9 +9,9 @@
#include <utils/Debug.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <private/utils/Static.h>
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
index d09cec8..090ca6d 100644
--- a/cmds/runtime/ServiceManager.h
+++ b/cmds/runtime/ServiceManager.h
@@ -4,7 +4,7 @@
#ifndef ANDROID_SERVICE_MANAGER_H
#define ANDROID_SERVICE_MANAGER_H
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 476f38a..21e0e4d 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -7,9 +7,11 @@
#include "ServiceManager.h"
#include "SignalHandler.h"
-#include <utils.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/zygote.h>
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
index 37c3d94..bfa58a1 100644
--- a/cmds/surfaceflinger/Android.mk
+++ b/cmds/surfaceflinger/Android.mk
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libsurfaceflinger \
+ libbinder \
libutils
LOCAL_C_INCLUDES := \
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 7c89578..d650721 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.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 <SurfaceFlinger.h>
diff --git a/im/java/android/im/BrandingResourceIDs.java b/im/java/android/im/BrandingResourceIDs.java
deleted file mode 100644
index 9960722..0000000
--- a/im/java/android/im/BrandingResourceIDs.java
+++ /dev/null
@@ -1,52 +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.
- */
-package android.im;
-
-/**
- * @hide
- * Defines the IDs of branding resources.
- */
-public interface BrandingResourceIDs {
- /**
- * The logo icon of the provider which is displayed in the landing page.
- */
- public static final int DRAWABLE_LOGO = 100;
- /**
- * The icon of online presence status.
- */
- public static final int DRAWABLE_PRESENCE_ONLINE = 102;
- /**
- * The icon of busy presence status.
- */
- public static final int DRAWABLE_PRESENCE_BUSY = 103;
- /**
- * The icon of away presence status.
- */
- public static final int DRAWABLE_PRESENCE_AWAY = 104;
- /**
- * The icon of invisible presence status.
- */
- public static final int DRAWABLE_PRESENCE_INVISIBLE = 105;
- /**
- * The icon of offline presence status.
- */
- public static final int DRAWABLE_PRESENCE_OFFLINE = 106;
- /**
- * The label of the menu to go to the contact list screen.
- */
- public static final int STRING_MENU_CONTACT_LIST = 107;
-
-}
diff --git a/im/java/android/im/IImPlugin.aidl b/im/java/android/im/IImPlugin.aidl
deleted file mode 100644
index 229cd0e..0000000
--- a/im/java/android/im/IImPlugin.aidl
+++ /dev/null
@@ -1,69 +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.
- */
-package android.im;
-
-/**
- * @hide
- */
-interface IImPlugin {
- /**
- * Notify the plugin the front door activity is created. This gives the plugin a chance to
- * start its own servics, etc.
- */
- void onStart();
-
- /**
- * Notify the plugin the front door activity is stopping.
- */
- void onStop();
-
- /**
- * Sign in to the service for the account passed in.
- *
- * @param account the account id for the accont to be signed into.
- */
- void signIn(long account);
-
- /**
- * Sign out of the service for the account passed in.
- *
- * @param account the account id for the accont to be signed out of.
- */
- void signOut(long account);
-
- /**
- * Returns the package name used to load the resources for the given provider name.
- *
- * @return The package name to load the resourcs for the given provider.
- */
- String getResourcePackageNameForProvider(String providerName);
-
- /**
- * Returns a map of branding resources for the given provider. The keys are defined
- * in {@link android.im.BrandingResourceIDs}. The values are the resource identifiers generated
- * by the aapt tool.
- *
- * @return The map of branding resources for the given provider.
- */
- Map getResourceMapForProvider(String providerName);
-
- /*
- * Returns a list of supported IM providers.
- *
- * @return a List of supported providers.
- */
- List getSupportedProviders();
-}
diff --git a/include/utils/Binder.h b/include/binder/Binder.h
index b5b8d98..47b2bb9 100644
--- a/include/utils/Binder.h
+++ b/include/binder/Binder.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_BINDER_H
#define ANDROID_BINDER_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -27,7 +27,7 @@ class BBinder : public IBinder
public:
BBinder();
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -71,6 +71,7 @@ private:
Extras* mExtras;
void* mReserved0;
+ static String16 sEmptyDescriptor;
};
// ---------------------------------------------------------------------------
diff --git a/include/utils/BpBinder.h b/include/binder/BpBinder.h
index 7b96e29..7ef93aa 100644
--- a/include/utils/BpBinder.h
+++ b/include/binder/BpBinder.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_BPBINDER_H
#define ANDROID_BPBINDER_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -31,7 +31,7 @@ public:
inline int32_t handle() const { return mHandle; }
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -106,6 +106,7 @@ private:
};
void reportOneDeath(const Obituary& obit);
+ bool isDescriptorCached() const;
mutable Mutex mLock;
volatile int32_t mAlive;
@@ -113,6 +114,7 @@ private:
Vector<Obituary>* mObituaries;
ObjectManager mObjects;
Parcel* mConstantData;
+ mutable String16 mDescriptorCache;
};
}; // namespace android
diff --git a/include/utils/IBinder.h b/include/binder/IBinder.h
index 7370330..884b5c1 100644
--- a/include/utils/IBinder.h
+++ b/include/binder/IBinder.h
@@ -56,7 +56,7 @@ public:
FLAG_ONEWAY = 0x00000001
};
- inline IBinder() { }
+ IBinder();
/**
* Check if this IBinder implements the interface named by
@@ -69,7 +69,7 @@ public:
* Return the canonical name of the interface provided by this IBinder
* object.
*/
- virtual String16 getInterfaceDescriptor() const = 0;
+ virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
@@ -147,7 +147,7 @@ public:
virtual BpBinder* remoteBinder();
protected:
- inline virtual ~IBinder() { }
+ virtual ~IBinder();
private:
};
diff --git a/include/utils/IInterface.h b/include/binder/IInterface.h
index 959722a..273d922 100644
--- a/include/utils/IInterface.h
+++ b/include/binder/IInterface.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IINTERFACE_H
#define ANDROID_IINTERFACE_H
-#include <utils/Binder.h>
+#include <binder/Binder.h>
namespace android {
@@ -27,10 +27,12 @@ namespace android {
class IInterface : public virtual RefBase
{
public:
+ IInterface();
sp<IBinder> asBinder();
sp<const IBinder> asBinder() const;
-
+
protected:
+ virtual ~IInterface();
virtual IBinder* onAsBinder() = 0;
};
@@ -49,7 +51,7 @@ class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
@@ -72,11 +74,14 @@ protected:
#define DECLARE_META_INTERFACE(INTERFACE) \
static const String16 descriptor; \
static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
- virtual String16 getInterfaceDescriptor() const; \
+ virtual const String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const String16 I##INTERFACE::descriptor(NAME); \
- String16 I##INTERFACE::getInterfaceDescriptor() const { \
+ const String16& I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
@@ -92,9 +97,16 @@ protected:
} \
return intr; \
} \
+ I##INTERFACE::I##INTERFACE() { } \
+ I##INTERFACE::~I##INTERFACE() { } \
+
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ if (!data.checkInterface(this)) { return PERMISSION_DENIED; } \
+
// ----------------------------------------------------------------------
-// No user-servicable parts after this...
+// No user-serviceable parts after this...
template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
@@ -105,7 +117,7 @@ inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
}
template<typename INTERFACE>
-inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
+inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
{
return INTERFACE::getInterfaceDescriptor();
}
diff --git a/include/utils/IMemory.h b/include/binder/IMemory.h
index 35a3fd7..ae042cb 100644
--- a/include/utils/IMemory.h
+++ b/include/binder/IMemory.h
@@ -23,7 +23,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
@@ -59,6 +59,10 @@ public:
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+
+ BnMemoryHeap();
+protected:
+ virtual ~BnMemoryHeap();
};
// ----------------------------------------------------------------------------
@@ -85,6 +89,10 @@ public:
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+
+ BnMemory();
+protected:
+ virtual ~BnMemory();
};
// ----------------------------------------------------------------------------
diff --git a/include/utils/IPCThreadState.h b/include/binder/IPCThreadState.h
index 0490fd3..78306b2 100644
--- a/include/utils/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -18,8 +18,8 @@
#define ANDROID_IPC_THREAD_STATE_H
#include <utils/Errors.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
#include <utils/Vector.h>
#ifdef HAVE_WIN32_PROC
diff --git a/include/utils/IPermissionController.h b/include/binder/IPermissionController.h
index cb1dd34..f9d371b 100644
--- a/include/utils/IPermissionController.h
+++ b/include/binder/IPermissionController.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IPERMISSION_CONTROLLER_H
#define ANDROID_IPERMISSION_CONTROLLER_H
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/include/utils/IServiceManager.h b/include/binder/IServiceManager.h
index e3d99fe..24e9e99 100644
--- a/include/utils/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -18,8 +18,8 @@
#ifndef ANDROID_ISERVICE_MANAGER_H
#define ANDROID_ISERVICE_MANAGER_H
-#include <utils/IInterface.h>
-#include <utils/IPermissionController.h>
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
#include <utils/Vector.h>
#include <utils/String16.h>
@@ -78,6 +78,8 @@ status_t getService(const String16& name, sp<INTERFACE>* outService)
bool checkCallingPermission(const String16& permission);
bool checkCallingPermission(const String16& permission,
int32_t* outPid, int32_t* outUid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+
// ----------------------------------------------------------------------
diff --git a/include/utils/MemoryBase.h b/include/binder/MemoryBase.h
index eb5a9d2..463e26d 100644
--- a/include/utils/MemoryBase.h
+++ b/include/binder/MemoryBase.h
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/utils/MemoryDealer.h b/include/binder/MemoryDealer.h
index 454b627..03ac70a 100644
--- a/include/utils/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -39,6 +39,10 @@ class HeapInterface : public virtual BnMemoryHeap
public:
// all values must be page-aligned
virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+
+ HeapInterface();
+protected:
+ virtual ~HeapInterface();
};
// ----------------------------------------------------------------------------
@@ -61,6 +65,10 @@ public:
virtual void dump(const char* what, uint32_t flags = 0) const = 0;
virtual void dump(String8& res,
const char* what, uint32_t flags = 0) const = 0;
+
+ AllocatorInterface();
+protected:
+ virtual ~AllocatorInterface();
};
// ----------------------------------------------------------------------------
@@ -71,6 +79,7 @@ public:
class SharedHeap : public HeapInterface, public MemoryHeapBase
{
public:
+ SharedHeap();
SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
virtual ~SharedHeap();
virtual sp<IMemory> mapMemory(size_t offset, size_t size);
@@ -117,13 +126,22 @@ public:
mFirst = mLast = newNode;
newNode->prev = newNode->next = 0;
} else {
- insertBefore(mFirst, newNode);
+ newNode->prev = 0;
+ newNode->next = mFirst;
+ mFirst->prev = newNode;
+ mFirst = newNode;
}
}
void insertTail(NODE* newNode) {
- if (mLast == 0) insertBeginning(newNode);
- else insertAfter(mLast, newNode);
+ if (mLast == 0) {
+ insertHead(newNode);
+ } else {
+ newNode->prev = mLast;
+ newNode->next = 0;
+ mLast->next = newNode;
+ mLast = newNode;
+ }
}
NODE* remove(NODE* node) {
@@ -200,8 +218,6 @@ public:
const sp<HeapInterface>& heap,
const sp<AllocatorInterface>& allocator);
- virtual ~MemoryDealer();
-
virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
virtual void deallocate(size_t offset);
virtual void dump(const char* what, uint32_t flags = 0) const;
@@ -210,6 +226,9 @@ public:
sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
sp<AllocatorInterface> getAllocator() const { return allocator(); }
+protected:
+ virtual ~MemoryDealer();
+
private:
const sp<HeapInterface>& heap() const;
const sp<AllocatorInterface>& allocator() const;
diff --git a/include/utils/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
index 574acf4..d793c24 100644
--- a/include/utils/MemoryHeapBase.h
+++ b/include/binder/MemoryHeapBase.h
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
namespace android {
@@ -35,14 +35,15 @@ public:
MAP_ONCE = IMemoryHeap::MAP_ONCE,
// memory won't be mapped locally, but will be mapped in the remote
// process.
- DONT_MAP_LOCALLY = 0x00000100
+ DONT_MAP_LOCALLY = 0x00000100,
+ NO_CACHING = 0x00000200
};
/*
* maps the memory referenced by fd. but DOESN'T take ownership
* of the filedescriptor (it makes a copy with dup()
*/
- MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
/*
* maps memory from the given device
@@ -82,7 +83,7 @@ protected:
int flags = 0, const char* device = NULL);
private:
- status_t mapfd(int fd, size_t size);
+ status_t mapfd(int fd, size_t size, uint32_t offset = 0);
int mFD;
size_t mSize;
diff --git a/include/utils/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
index 60335ad..dbf26ff 100644
--- a/include/utils/MemoryHeapPmem.h
+++ b/include/binder/MemoryHeapPmem.h
@@ -20,9 +20,9 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IMemory.h>
#include <utils/SortedVector.h>
namespace android {
diff --git a/include/utils/Parcel.h b/include/binder/Parcel.h
index af1490a..ba6c711 100644
--- a/include/utils/Parcel.h
+++ b/include/binder/Parcel.h
@@ -57,7 +57,8 @@ public:
status_t writeInterfaceToken(const String16& interface);
bool enforceInterface(const String16& interface) const;
-
+ bool checkInterface(IBinder*) const;
+
void freeData();
const size_t* objects() const;
@@ -73,6 +74,7 @@ public:
status_t writeInt64(int64_t val);
status_t writeFloat(float val);
status_t writeDouble(double val);
+ status_t writeIntPtr(intptr_t val);
status_t writeCString(const char* str);
status_t writeString8(const String8& str);
status_t writeString16(const String16& str);
@@ -108,6 +110,8 @@ public:
status_t readFloat(float *pArg) const;
double readDouble() const;
status_t readDouble(double *pArg) const;
+ intptr_t readIntPtr() const;
+ status_t readIntPtr(intptr_t *pArg) const;
const char* readCString() const;
String8 readString8() const;
@@ -147,7 +151,7 @@ public:
release_func relFunc, void* relCookie);
void print(TextOutput& to, uint32_t flags = 0) const;
-
+
private:
Parcel(const Parcel& o);
Parcel& operator=(const Parcel& o);
@@ -162,6 +166,14 @@ private:
void initState();
void scanForFds() const;
+ template<class T>
+ status_t readAligned(T *pArg) const;
+
+ template<class T> T readAligned() const;
+
+ template<class T>
+ status_t writeAligned(T val);
+
status_t mError;
uint8_t* mData;
size_t mDataSize;
diff --git a/include/binder/Permission.h b/include/binder/Permission.h
new file mode 100644
index 0000000..9542d50
--- /dev/null
+++ b/include/binder/Permission.h
@@ -0,0 +1,68 @@
+/*
+ * 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 BINDER_PERMISSION_H
+#define BINDER_PERMISSION_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <utils/SortedVector.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Permission caches the result of the permission check for the given
+ * permission name and the provided uid/pid. It also handles a few
+ * known cases efficiently (caller is in the same process or is root).
+ * The package manager does something similar but lives in dalvik world
+ * and is therefore extremely slow to access.
+ */
+
+class Permission
+{
+public:
+ Permission(char const* name);
+ Permission(const String16& name);
+ Permission(const Permission& rhs);
+ virtual ~Permission();
+
+ bool operator < (const Permission& rhs) const;
+
+ // checks the current binder call's caller has access to this permission
+ bool checkCalling() const;
+
+ // checks the specified pid/uid has access to this permission
+ bool check(pid_t pid, uid_t uid) const;
+
+protected:
+ virtual bool doCheckPermission(pid_t pid, uid_t uid) const;
+
+private:
+ Permission& operator = (const Permission& rhs) const;
+ const String16 mPermissionName;
+ mutable SortedVector<uid_t> mGranted;
+ const pid_t mPid;
+ mutable Mutex mLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* BINDER_PERMISSION_H */
diff --git a/include/utils/ProcessState.h b/include/binder/ProcessState.h
index 39584f4..feeb3c3 100644
--- a/include/utils/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_PROCESS_STATE_H
#define ANDROID_PROCESS_STATE_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/String16.h>
diff --git a/libs/utils/executablepath_darwin.cpp b/include/private/binder/Static.h
index 2e3c3a0..5b0f9fc 100644
--- a/libs/utils/executablepath_darwin.cpp
+++ b/include/private/binder/Static.h
@@ -14,18 +14,26 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
+// All static variables go here, to control initialization and
+// destruction order in the library.
-void executablepath(char s[PATH_MAX])
-{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
-}
+#include <utils/threads.h>
+#include <binder/IBinder.h>
+#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/binder/binder_module.h
index fdf327e..fdf327e 100644
--- a/include/private/utils/binder_module.h
+++ b/include/private/binder/binder_module.h
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index a85f275..26cde38 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -26,10 +26,14 @@
#endif
#include <private/pixelflinger/ggl_context.h>
+#include <hardware/copybit.h>
+#include <hardware/gralloc.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
+struct android_native_buffer_t;
+
namespace android {
const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10;
@@ -39,7 +43,7 @@ class EGLSurfaceManager;
class EGLBufferObjectManager;
namespace gl {
-
+
struct ogles_context_t;
struct matrixx_t;
struct transform_t;
@@ -96,7 +100,7 @@ struct vec4_t {
struct vertex_t {
enum {
- // these constant matter for our clipping
+ // these constant matter for our clipping
CLIP_L = 0x0001, // clipping flags
CLIP_R = 0x0002,
CLIP_B = 0x0004,
@@ -106,7 +110,7 @@ struct vertex_t {
EYE = 0x0040,
RESERVED = 0x0080,
-
+
USER_CLIP_0 = 0x0100, // user clipping flags
USER_CLIP_1 = 0x0200,
USER_CLIP_2 = 0x0400,
@@ -121,7 +125,7 @@ struct vertex_t {
USER_CLIP_ALL = 0x3F00,
CLIP_ALL = 0x3F3F,
};
-
+
// the fields below are arranged to minimize d-cache usage
// we group together, by cache-line, the fields most likely to be used
@@ -130,7 +134,7 @@ struct vertex_t {
vec4_t eye;
};
vec4_t clip;
-
+
uint32_t flags;
size_t index; // cache tag, and vertex index
GLfixed fog;
@@ -142,7 +146,7 @@ struct vertex_t {
vec4_t color;
vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
uint32_t reserved1[4];
-
+
inline void clear() {
flags = index = locked = mru = 0;
}
@@ -199,7 +203,7 @@ struct array_machine_t {
GLenum indicesType;
buffer_t const* array_buffer;
buffer_t const* element_array_buffer;
-
+
void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
@@ -285,6 +289,7 @@ struct light_t {
vec4_t normalizedObjPosition;
vec4_t spotDir;
vec4_t normalizedSpotDir;
+ vec4_t objViewer;
GLfixed spotExp;
GLfixed spotCutoff;
GLfixed spotCutoffCosine;
@@ -410,7 +415,7 @@ struct transform_t {
matrixx_t matrix;
uint32_t flags;
uint32_t ops;
-
+
union {
struct {
void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
@@ -509,17 +514,17 @@ struct viewport_t {
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
+ GLsizei h;
struct {
GLint x;
GLint y;
- } surfaceport;
+ } surfaceport;
struct {
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
- } scissor;
+ GLsizei h;
+ } scissor;
};
// ----------------------------------------------------------------------------
@@ -594,6 +599,14 @@ struct prims_t {
void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
};
+struct copybits_context_t {
+ // A handle to the blit engine, if it exists, else NULL.
+ copybit_device_t* blitEngine;
+ int32_t minScale;
+ int32_t maxScale;
+ android_native_buffer_t* drawSurfaceBuffer;
+};
+
struct ogles_context_t {
context_t rasterizer;
array_machine_t arrays __attribute__((aligned(32)));
@@ -617,6 +630,14 @@ struct ogles_context_t {
uint32_t transformTextures : 1;
EGLSurfaceManager* surfaceManager;
EGLBufferObjectManager* bufferObjectManager;
+
+ // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
+ // defined, but it is always present because ogles_context_t is a public
+ // struct that is used by clients of libagl. We want the size and offsets
+ // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
+
+ copybits_context_t copybits;
+
GLenum error;
static inline ogles_context_t* get() {
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h
index b6fcd80..f1a2618 100644
--- a/include/private/ui/LayerState.h
+++ b/include/private/ui/LayerState.h
@@ -25,8 +25,6 @@
#include <ui/ISurfaceFlingerClient.h>
#include <ui/Region.h>
-#include <private/ui/SharedState.h>
-
namespace android {
class Parcel;
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
new file mode 100644
index 0000000..8d76533
--- /dev/null
+++ b/include/private/ui/RegionHelper.h
@@ -0,0 +1,284 @@
+/*
+ * 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_UI_PRIVATE_REGION_HELPER_H
+#define ANDROID_UI_PRIVATE_REGION_HELPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+template<typename RECT>
+class region_operator
+{
+ typedef typename RECT::value_type TYPE;
+ static const TYPE max_value = 0x7FFFFFF;
+
+public:
+ /*
+ * Common boolean operations:
+ * value is computed as 0b101 op 0b110
+ * other boolean operation are possible, simply compute
+ * their corresponding value with the above formulae and use
+ * it when instantiating a region_operator.
+ */
+ static const uint32_t LHS = 0x5; // 0b101
+ static const uint32_t RHS = 0x6; // 0b110
+ enum {
+ op_nand = LHS & ~RHS,
+ op_and = LHS & RHS,
+ op_or = LHS | RHS,
+ op_xor = LHS ^ RHS
+ };
+
+ struct region {
+ RECT const* rects;
+ size_t count;
+ TYPE dx;
+ TYPE dy;
+ inline region(const region& rhs)
+ : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
+ inline region(RECT const* r, size_t c)
+ : rects(r), count(c), dx(), dy() { }
+ inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
+ : rects(r), count(c), dx(dx), dy(dy) { }
+ };
+
+ class region_rasterizer {
+ friend class region_operator;
+ virtual void operator()(const RECT& rect) = 0;
+ public:
+ virtual ~region_rasterizer() { };
+ };
+
+ inline region_operator(int op, const region& lhs, const region& rhs)
+ : op_mask(op), spanner(lhs, rhs)
+ {
+ }
+
+ void operator()(region_rasterizer& rasterizer) {
+ RECT current;
+ do {
+ SpannerInner spannerInner(spanner.lhs, spanner.rhs);
+ int inside = spanner.next(current.top, current.bottom);
+ spannerInner.prepare(inside);
+ do {
+ TYPE left, right;
+ int inside = spannerInner.next(current.left, current.right);
+ if ((op_mask >> inside) & 1) {
+ if (current.left < current.right &&
+ current.top < current.bottom) {
+ rasterizer(current);
+ }
+ }
+ } while(!spannerInner.isDone());
+ } while(!spanner.isDone());
+ }
+
+private:
+ uint32_t op_mask;
+
+ class SpannerBase
+ {
+ public:
+ enum {
+ lhs_before_rhs = 0,
+ lhs_after_rhs = 1,
+ lhs_coincide_rhs = 2
+ };
+
+ protected:
+ TYPE lhs_head;
+ TYPE lhs_tail;
+ TYPE rhs_head;
+ TYPE rhs_tail;
+
+ inline int next(TYPE& head, TYPE& tail,
+ bool& more_lhs, bool& more_rhs)
+ {
+ int inside;
+ more_lhs = false;
+ more_rhs = false;
+ if (lhs_head < rhs_head) {
+ inside = lhs_before_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_head) {
+ tail = lhs_tail;
+ more_lhs = true;
+ } else {
+ lhs_head = rhs_head;
+ tail = rhs_head;
+ }
+ } else if (rhs_head < lhs_head) {
+ inside = lhs_after_rhs;
+ head = rhs_head;
+ if (rhs_tail <= lhs_head) {
+ tail = rhs_tail;
+ more_rhs = true;
+ } else {
+ rhs_head = lhs_head;
+ tail = lhs_head;
+ }
+ } else {
+ inside = lhs_coincide_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_tail) {
+ tail = rhs_head = lhs_tail;
+ more_lhs = true;
+ }
+ if (rhs_tail <= lhs_tail) {
+ tail = lhs_head = rhs_tail;
+ more_rhs = true;
+ }
+ }
+ return inside;
+ }
+ };
+
+ class Spanner : protected SpannerBase
+ {
+ friend class region_operator;
+ region lhs;
+ region rhs;
+
+ public:
+ inline Spanner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
+ SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy;
+ SpannerBase::rhs_head = rhs.rects->top + rhs.dy;
+ SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy;
+ }
+
+ inline bool isDone() const {
+ return !rhs.count && !lhs.count;
+ }
+
+ inline int next(TYPE& top, TYPE& bottom)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
+ // got to next span
+ size_t count = reg.count;
+ RECT const * rects = reg.rects;
+ RECT const * const end = rects + count;
+ const int top = rects->top;
+ while (rects != end && rects->top == top) {
+ rects++;
+ count--;
+ }
+ if (rects != end) {
+ aTop = rects->top + reg.dy;
+ aBottom = rects->bottom + reg.dy;
+ } else {
+ aTop = max_value;
+ aBottom = max_value;
+ }
+ reg.rects = rects;
+ reg.count = count;
+ }
+ };
+
+ class SpannerInner : protected SpannerBase
+ {
+ region lhs;
+ region rhs;
+
+ public:
+ inline SpannerInner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ }
+
+ inline void prepare(int inside) {
+ if (inside == SpannerBase::lhs_before_rhs) {
+ SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
+ SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+ SpannerBase::rhs_head = max_value;
+ SpannerBase::rhs_tail = max_value;
+ } else if (inside == SpannerBase::lhs_after_rhs) {
+ SpannerBase::lhs_head = max_value;
+ SpannerBase::lhs_tail = max_value;
+ SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
+ SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+ } else {
+ SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
+ SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+ SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
+ SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+ }
+ }
+
+ inline bool isDone() const {
+ return SpannerBase::lhs_head == max_value &&
+ SpannerBase::rhs_head == max_value;
+ }
+
+ inline int next(TYPE& left, TYPE& right)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& left, TYPE& right) {
+ if (reg.rects && reg.count) {
+ const int cur_span_top = reg.rects->top;
+ reg.rects++;
+ reg.count--;
+ if (!reg.count || reg.rects->top != cur_span_top) {
+ left = max_value;
+ right = max_value;
+ } else {
+ left = reg.rects->left + reg.dx;
+ right = reg.rects->right + reg.dx;
+ }
+ }
+ }
+ };
+
+ Spanner spanner;
+};
+
+// ----------------------------------------------------------------------------
+};
+
+#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
new file mode 100644
index 0000000..bbc1822
--- /dev/null
+++ b/include/private/ui/SharedBufferStack.h
@@ -0,0 +1,359 @@
+/*
+ * 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_UI_SHARED_BUFFER_STACK_H
+#define ANDROID_UI_SHARED_BUFFER_STACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+
+#include <utils/Debug.h>
+#include <utils/threads.h>
+#include <utils/String8.h>
+
+#include <ui/Rect.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * These classes manage a stack of buffers in shared memory.
+ *
+ * SharedClient: represents a client with several stacks
+ * SharedBufferStack: represents a stack of buffers
+ * SharedBufferClient: manipulates the SharedBufferStack from the client side
+ * SharedBufferServer: manipulates the SharedBufferStack from the server side
+ *
+ * Buffers can be dequeued until there are none available, they can be locked
+ * unless they are in use by the server, which is only the case for the last
+ * dequeue-able buffer. When these various conditions are not met, the caller
+ * waits until the condition is met.
+ *
+ *
+ * CAVEATS:
+ *
+ * In the current implementation there are several limitations:
+ * - buffers must be locked in the same order they've been dequeued
+ * - buffers must be enqueued in the same order they've been locked
+ * - dequeue() is not reentrant
+ * - no error checks are done on the condition above
+ *
+ */
+
+// When changing these values, the COMPILE_TIME_ASSERT at the end of this
+// file need to be updated.
+const unsigned int NUM_LAYERS_MAX = 31;
+const unsigned int NUM_BUFFER_MAX = 4;
+const unsigned int NUM_DISPLAY_MAX = 4;
+
+// ----------------------------------------------------------------------------
+
+class Region;
+class SharedBufferStack;
+class SharedClient;
+
+// ----------------------------------------------------------------------------
+
+// should be 128 bytes (32 longs)
+class SharedBufferStack
+{
+ friend class SharedClient;
+ friend class SharedBufferBase;
+ friend class SharedBufferClient;
+ friend class SharedBufferServer;
+
+public:
+ struct FlatRegion { // 12 bytes
+ static const unsigned int NUM_RECT_MAX = 1;
+ uint32_t count;
+ uint16_t rects[4*NUM_RECT_MAX];
+ };
+
+ struct Statistics { // 4 longs
+ typedef int32_t usecs_t;
+ usecs_t totalTime;
+ usecs_t reserved[3];
+ };
+
+ SharedBufferStack();
+ void init(int32_t identity);
+ status_t setDirtyRegion(int buffer, const Region& reg);
+ Region getDirtyRegion(int buffer) const;
+
+ // these attributes are part of the conditions/updates
+ volatile int32_t head; // server's current front buffer
+ volatile int32_t available; // number of dequeue-able buffers
+ volatile int32_t queued; // number of buffers waiting for post
+ volatile int32_t inUse; // buffer currently in use by SF
+ volatile status_t status; // surface's status code
+
+ // not part of the conditions
+ volatile int32_t reallocMask;
+
+ int32_t identity; // surface's identity (const)
+ int32_t reserved32[9];
+ Statistics stats;
+ FlatRegion dirtyRegion[NUM_BUFFER_MAX]; // 12*4=48 bytes
+};
+
+// ----------------------------------------------------------------------------
+
+// 4 KB max
+class SharedClient
+{
+public:
+ SharedClient();
+ ~SharedClient();
+
+ status_t validate(size_t token) const;
+ uint32_t getIdentity(size_t token) const;
+
+private:
+ friend class SharedBufferBase;
+ friend class SharedBufferClient;
+ friend class SharedBufferServer;
+
+ // FIXME: this should be replaced by a lock-less primitive
+ Mutex lock;
+ Condition cv;
+ SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
+};
+
+// ============================================================================
+
+class SharedBufferBase
+{
+public:
+ SharedBufferBase(SharedClient* sharedClient, int surface, int num,
+ int32_t identity);
+ ~SharedBufferBase();
+ uint32_t getIdentity();
+ status_t getStatus() const;
+ size_t getFrontBuffer() const;
+ String8 dump(char const* prefix) const;
+
+protected:
+ SharedClient* const mSharedClient;
+ SharedBufferStack* const mSharedStack;
+ const int mNumBuffers;
+ const int mIdentity;
+
+ friend struct Update;
+ friend struct QueueUpdate;
+
+ struct ConditionBase {
+ SharedBufferStack& stack;
+ inline ConditionBase(SharedBufferBase* sbc)
+ : stack(*sbc->mSharedStack) { }
+ };
+
+ struct UpdateBase {
+ SharedBufferStack& stack;
+ inline UpdateBase(SharedBufferBase* sbb)
+ : stack(*sbb->mSharedStack) { }
+ };
+
+ template <typename T>
+ status_t waitForCondition(T condition);
+
+ template <typename T>
+ status_t updateCondition(T update);
+};
+
+template <typename T>
+status_t SharedBufferBase::waitForCondition(T condition)
+{
+ const SharedBufferStack& stack( *mSharedStack );
+ SharedClient& client( *mSharedClient );
+ const nsecs_t TIMEOUT = s2ns(1);
+ Mutex::Autolock _l(client.lock);
+ while ((condition()==false) &&
+ (stack.identity == mIdentity) &&
+ (stack.status == NO_ERROR))
+ {
+ status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
+
+ // handle errors and timeouts
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ if (err == TIMED_OUT) {
+ if (condition()) {
+ LOGE("waitForCondition(%s) timed out (identity=%d), "
+ "but condition is true! We recovered but it "
+ "shouldn't happen." , T::name(),
+ stack.identity);
+ break;
+ } else {
+ LOGW("waitForCondition(%s) timed out "
+ "(identity=%d, status=%d). "
+ "CPU may be pegged. trying again.", T::name(),
+ stack.identity, stack.status);
+ }
+ } else {
+ LOGE("waitForCondition(%s) error (%s) ",
+ T::name(), strerror(-err));
+ return err;
+ }
+ }
+ }
+ return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
+}
+
+
+template <typename T>
+status_t SharedBufferBase::updateCondition(T update) {
+ SharedClient& client( *mSharedClient );
+ Mutex::Autolock _l(client.lock);
+ ssize_t result = update();
+ client.cv.broadcast();
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+
+class SharedBufferClient : public SharedBufferBase
+{
+public:
+ SharedBufferClient(SharedClient* sharedClient, int surface, int num,
+ int32_t identity);
+
+ ssize_t dequeue();
+ status_t undoDequeue(int buf);
+
+ status_t lock(int buf);
+ status_t queue(int buf);
+ bool needNewBuffer(int buffer) const;
+ status_t setDirtyRegion(int buffer, const Region& reg);
+
+private:
+ friend struct Condition;
+ friend struct DequeueCondition;
+ friend struct LockCondition;
+
+ int32_t computeTail() const;
+
+ struct QueueUpdate : public UpdateBase {
+ inline QueueUpdate(SharedBufferBase* sbb);
+ inline ssize_t operator()();
+ };
+
+ struct UndoDequeueUpdate : public UpdateBase {
+ inline UndoDequeueUpdate(SharedBufferBase* sbb);
+ inline ssize_t operator()();
+ };
+
+ // --
+
+ struct DequeueCondition : public ConditionBase {
+ inline DequeueCondition(SharedBufferClient* sbc);
+ inline bool operator()();
+ static inline const char* name() { return "DequeueCondition"; }
+ };
+
+ struct LockCondition : public ConditionBase {
+ int buf;
+ inline LockCondition(SharedBufferClient* sbc, int buf);
+ inline bool operator()();
+ static inline const char* name() { return "LockCondition"; }
+ };
+
+ int32_t tail;
+ // statistics...
+ nsecs_t mDequeueTime[NUM_BUFFER_MAX];
+};
+
+// ----------------------------------------------------------------------------
+
+class SharedBufferServer : public SharedBufferBase
+{
+public:
+ SharedBufferServer(SharedClient* sharedClient, int surface, int num,
+ int32_t identity);
+
+ ssize_t retireAndLock();
+ status_t unlock(int buffer);
+ void setStatus(status_t status);
+ status_t reallocate();
+ status_t assertReallocate(int buffer);
+ int32_t getQueuedCount() const;
+
+ Region getDirtyRegion(int buffer) const;
+
+ SharedBufferStack::Statistics getStats() const;
+
+
+private:
+ struct UnlockUpdate : public UpdateBase {
+ const int lockedBuffer;
+ inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
+ inline ssize_t operator()();
+ };
+
+ struct RetireUpdate : public UpdateBase {
+ const int numBuffers;
+ inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
+ inline ssize_t operator()();
+ };
+
+ struct StatusUpdate : public UpdateBase {
+ const status_t status;
+ inline StatusUpdate(SharedBufferBase* sbb, status_t status);
+ inline ssize_t operator()();
+ };
+
+ struct ReallocateCondition : public ConditionBase {
+ int buf;
+ inline ReallocateCondition(SharedBufferBase* sbb, int buf);
+ inline bool operator()();
+ static inline const char* name() { return "ReallocateCondition"; }
+ };
+};
+
+// ===========================================================================
+
+struct display_cblk_t
+{
+ uint16_t w;
+ uint16_t h;
+ uint8_t format;
+ uint8_t orientation;
+ uint8_t reserved[2];
+ float fps;
+ float density;
+ float xdpi;
+ float ydpi;
+ uint32_t pad[2];
+};
+
+struct surface_flinger_cblk_t // 4KB max
+{
+ uint8_t connected;
+ uint8_t reserved[3];
+ uint32_t pad[7];
+ display_cblk_t displays[NUM_DISPLAY_MAX];
+};
+
+// ---------------------------------------------------------------------------
+
+COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
+COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
+COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_UI_SHARED_BUFFER_STACK_H */
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
deleted file mode 100644
index 546d0ad..0000000
--- a/include/private/ui/SharedState.h
+++ /dev/null
@@ -1,168 +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_UI_SHARED_STATE_H
-#define ANDROID_UI_SHARED_STATE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/threads.h>
-
-namespace android {
-
-/*
- * These structures are shared between the composer process and its clients
- */
-
-// ---------------------------------------------------------------------------
-
-struct surface_info_t { // 4 longs, 16 bytes
- enum {
- eBufferDirty = 0x01
- };
- uint16_t w;
- uint16_t h;
- uint16_t stride;
- uint16_t bpr;
- uint16_t reserved;
- uint8_t format;
- uint8_t flags;
- ssize_t bits_offset;
-};
-
-// ---------------------------------------------------------------------------
-
-const uint32_t NUM_LAYERS_MAX = 31;
-
-enum { // layer_cblk_t swapState
- eIndex = 0x00000001,
- eFlipRequested = 0x00000002,
-
- eResizeBuffer0 = 0x00000004,
- eResizeBuffer1 = 0x00000008,
- eResizeRequested = eResizeBuffer0 | eResizeBuffer1,
-
- eBusy = 0x00000010,
- eLocked = 0x00000020,
- eNextFlipPending = 0x00000040,
- eInvalidSurface = 0x00000080
-};
-
-enum { // layer_cblk_t flags
- eLayerNotPosted = 0x00000001,
- eNoCopyBack = 0x00000002,
- eReserved = 0x0000007C,
- eBufferIndexShift = 7,
- eBufferIndex = 1<<eBufferIndexShift,
-};
-
-struct flat_region_t // 40 bytes
-{
- int32_t count;
- int16_t l;
- int16_t t;
- int16_t r;
- int16_t b;
- uint16_t runs[14];
-};
-
-struct layer_cblk_t // (128 bytes)
-{
- volatile int32_t swapState; // 4
- volatile int32_t flags; // 4
- volatile int32_t identity; // 4
- int32_t reserved; // 4
- surface_info_t surface[2]; // 32
- flat_region_t region[2]; // 80
-
- static inline int backBuffer(uint32_t state) {
- return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
- }
- static inline int frontBuffer(uint32_t state) {
- return 1 - backBuffer(state);
- }
-};
-
-// ---------------------------------------------------------------------------
-
-struct per_client_cblk_t // 4KB max
-{
- Mutex lock;
- Condition cv;
- layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
-
- enum {
- BLOCKING = 0x00000001,
- INSPECT = 0x00000002
- };
-
- per_client_cblk_t();
-
- // these functions are used by the clients
- status_t validate(size_t i) const;
- int32_t lock_layer(size_t i, uint32_t flags);
- uint32_t unlock_layer_and_post(size_t i);
- void unlock_layer(size_t i);
-};
-// ---------------------------------------------------------------------------
-
-const uint32_t NUM_DISPLAY_MAX = 4;
-
-struct display_cblk_t
-{
- uint16_t w;
- uint16_t h;
- uint8_t format;
- uint8_t orientation;
- uint8_t reserved[2];
- float fps;
- float density;
- float xdpi;
- float ydpi;
- uint32_t pad[2];
-};
-
-struct surface_flinger_cblk_t // 4KB max
-{
- surface_flinger_cblk_t();
-
- uint8_t connected;
- uint8_t reserved[3];
- uint32_t pad[7];
-
- display_cblk_t displays[NUM_DISPLAY_MAX];
-};
-
-// ---------------------------------------------------------------------------
-
-template<bool> struct CTA;
-template<> struct CTA<true> { };
-
-// compile-time assertions. just to avoid catastrophes.
-inline void compile_time_asserts() {
- CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
- (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
- CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
- (void)sizeof__per_client_cblk_t__le_4096; // we don't want a warning
- CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
- (void)sizeof__surface_flinger_cblk_t__le_4096; // we don't want a warning
-}
-
-}; // namespace android
-
-#endif // ANDROID_UI_SHARED_STATE_H
-
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
deleted file mode 100644
index ff91b61..0000000
--- a/include/private/ui/SurfaceFlingerSynchro.h
+++ /dev/null
@@ -1,76 +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 ANDROID_SURFACE_FLINGER_SYNCHRO_H
-#define ANDROID_SURFACE_FLINGER_SYNCHRO_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <ui/ISurfaceComposer.h>
-
-namespace android {
-
-class SurfaceFlinger;
-
-class SurfaceFlingerSynchro
-{
-public:
-
- // client constructor
- SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
- ~SurfaceFlingerSynchro();
-
- // signal surfaceflinger for some work
- status_t signal();
-
-private:
- class Barrier {
- public:
- Barrier();
- ~Barrier();
- void open();
- void close();
- void waitAndClose();
- status_t waitAndClose(nsecs_t timeout);
- private:
- enum { OPENED, CLOSED };
- mutable Mutex lock;
- mutable Condition cv;
- volatile int state;
- };
-
- friend class SurfaceFlinger;
-
- // server constructor
- SurfaceFlingerSynchro();
-
- void open();
-
- // wait until there is some work to do
- status_t wait();
- status_t wait(nsecs_t timeout);
-
- sp<ISurfaceComposer> mSurfaceComposer;
- Barrier mBarrier;
-};
-
-}; // namespace android
-
-#endif // ANDROID_SURFACE_FLINGER_SYNCHRO_H
-
diff --git a/im/java/android/im/ImPluginConsts.java b/include/private/ui/android_natives_priv.h
index 416493f..6b9f524 100644
--- a/im/java/android/im/ImPluginConsts.java
+++ b/include/private/ui/android_natives_priv.h
@@ -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,14 +14,4 @@
* limitations under the License.
*/
-package android.im;
-
-/**
- * @hide
- */
-public class ImPluginConsts {
- /**
- * The intent action name for the plugin service.
- */
- public static final String PLUGIN_ACTION_NAME = "android.im.plugin";
-} \ No newline at end of file
+#include <ui/android_native_buffer.h>
diff --git a/include/private/ui/sw_gralloc_handle.h b/include/private/ui/sw_gralloc_handle.h
new file mode 100644
index 0000000..b3d333e
--- /dev/null
+++ b/include/private/ui/sw_gralloc_handle.h
@@ -0,0 +1,83 @@
+/*
+ * 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 ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H
+#define ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/cdefs.h>
+#include <hardware/gralloc.h>
+#include <errno.h>
+
+#include <cutils/native_handle.h>
+
+namespace android {
+
+/*****************************************************************************/
+
+struct sw_gralloc_handle_t : public native_handle
+{
+ // file-descriptors
+ int fd;
+ // ints
+ int magic;
+ int size;
+ int base;
+ int prot;
+ int pid;
+
+ static const int sNumInts = 5;
+ static const int sNumFds = 1;
+ static const int sMagic = '_sgh';
+
+ sw_gralloc_handle_t() :
+ fd(-1), magic(sMagic), size(0), base(0), prot(0), pid(getpid())
+ {
+ version = sizeof(native_handle);
+ numInts = sNumInts;
+ numFds = sNumFds;
+ }
+ ~sw_gralloc_handle_t() {
+ magic = 0;
+ }
+
+ static int validate(const native_handle* h) {
+ const sw_gralloc_handle_t* hnd = (const sw_gralloc_handle_t*)h;
+ if (!h || h->version != sizeof(native_handle) ||
+ h->numInts != sNumInts || h->numFds != sNumFds ||
+ hnd->magic != sMagic)
+ {
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ static status_t alloc(uint32_t w, uint32_t h, int format,
+ int usage, buffer_handle_t* handle, int32_t* stride);
+ static status_t free(sw_gralloc_handle_t* hnd);
+ static status_t registerBuffer(sw_gralloc_handle_t* hnd);
+ static status_t unregisterBuffer(sw_gralloc_handle_t* hnd);
+ static status_t lock(sw_gralloc_handle_t* hnd, int usage,
+ int l, int t, int w, int h, void** vaddr);
+ static status_t unlock(sw_gralloc_handle_t* hnd);
+};
+
+/*****************************************************************************/
+
+}; // namespace android
+
+#endif /* ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H */
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
index f1439b7..d95ae0d 100644
--- a/include/private/utils/Static.h
+++ b/include/private/utils/Static.h
@@ -20,14 +20,6 @@
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#ifndef LIBUTILS_NATIVE
-#include <utils/IBinder.h>
-#include <utils/IMemory.h>
-#include <utils/ProcessState.h>
-#include <utils/IPermissionController.h>
-#include <utils/IServiceManager.h>
-#endif
-
namespace android {
// For TextStream.cpp
extern Vector<int32_t> gTextBuffers;
@@ -40,19 +32,4 @@ extern void terminate_string8();
extern void initialize_string16();
extern void terminate_string16();
-
-
-#ifndef LIBUTILS_NATIVE
-
-// For ProcessState.cpp
-extern Mutex gProcessMutex;
-extern sp<ProcessState> gProcess;
-
-// For ServiceManager.cpp
-extern Mutex gDefaultServiceManagerLock;
-extern sp<IServiceManager> gDefaultServiceManager;
-extern sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
deleted file mode 100644
index ac2ab19..0000000
--- a/include/private/utils/futex_synchro.h
+++ /dev/null
@@ -1,60 +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 _FUTEX_SYNCHRO_H
-#define _FUTEX_SYNCHRO_H
-
-#ifndef HAVE_FUTEX
-#error "HAVE_FUTEX not defined"
-#endif
-
-#define FUTEX_WAIT_INFINITE (0)
-
-typedef struct futex_mutex_t futex_mutex_t;
-
-struct futex_mutex_t
-{
- volatile int value;
-};
-
-typedef struct futex_cond_t futex_cond_t;
-
-struct futex_cond_t
-{
- volatile int value;
-};
-
-
-#if __cplusplus
-extern "C" {
-#endif
-
-void futex_mutex_init(futex_mutex_t *m);
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
-void futex_mutex_unlock(futex_mutex_t *m);
-int futex_mutex_trylock(futex_mutex_t *m);
-
-void futex_cond_init(futex_cond_t *c);
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
-void futex_cond_signal(futex_cond_t *c);
-void futex_cond_broadcast(futex_cond_t *c);
-
-#if __cplusplus
-} // extern "C"
-#endif
-
-#endif // _FUTEX_SYNCHRO_H
-
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 21cb73b..28b0d2f 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -43,7 +43,7 @@ enum tts_callback_status {
// @param [inout] void *& - The userdata pointer set in the original
// synth call
// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] audio_format - The AudioSystem::audio_format enum
+// @param [in] uint32_t - The audio format
// @param [in] int - The number of channels
// @param [inout] int8_t *& - A buffer of audio data only valid during the
// execution of the callback
@@ -54,7 +54,7 @@ enum tts_callback_status {
// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
// there is more data to produce.
typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
- AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
+ uint32_t, int, int8_t *&, size_t&, tts_synth_status);
class TtsEngine;
extern "C" TtsEngine* getTtsEngine();
@@ -80,6 +80,8 @@ enum tts_support_result {
class TtsEngine
{
public:
+ virtual ~TtsEngine() {}
+
// Initialize the TTS engine and returns whether initialization succeeded.
// @param synthDoneCBPtr synthesis callback function pointer
// @return TTS_SUCCESS, or TTS_FAILURE
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index afb07b5..5219772 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -66,15 +66,22 @@ namespace android {
// msgType in notifyCallback and dataCallback functions
enum {
- CAMERA_MSG_ERROR = 0,
- CAMERA_MSG_SHUTTER,
- CAMERA_MSG_FOCUS,
- CAMERA_MSG_ZOOM,
- CAMERA_MSG_PREVIEW_FRAME,
- CAMERA_MSG_VIDEO_FRAME,
- CAMERA_MSG_POSTVIEW_FRAME,
- CAMERA_MSG_RAW_IMAGE,
- CAMERA_MSG_COMPRESSED_IMAGE
+ CAMERA_MSG_ERROR = 0x001,
+ CAMERA_MSG_SHUTTER = 0x002,
+ CAMERA_MSG_FOCUS = 0x004,
+ CAMERA_MSG_ZOOM = 0x008,
+ CAMERA_MSG_PREVIEW_FRAME = 0x010,
+ CAMERA_MSG_VIDEO_FRAME = 0x020,
+ CAMERA_MSG_POSTVIEW_FRAME = 0x040,
+ CAMERA_MSG_RAW_IMAGE = 0x080,
+ CAMERA_MSG_COMPRESSED_IMAGE = 0x100,
+ CAMERA_MSG_ALL_MSGS = 0x1FF
+};
+
+// cmdType in sendCommand functions
+enum {
+ CAMERA_CMD_START_SMOOTH_ZOOM = 1,
+ CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
};
// camera fatal errors
@@ -142,6 +149,9 @@ public:
// autoFocus - status returned from callback
status_t autoFocus();
+ // cancel auto focus
+ status_t cancelAutoFocus();
+
// take a picture - picture returned from callback
status_t takePicture();
@@ -151,6 +161,9 @@ public:
// get preview/capture parameters - key/value pairs
String8 getParameters() const;
+ // send command to camera driver
+ status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
void setListener(const sp<CameraListener>& listener);
void setPreviewCallbackFlags(int preview_callback_flag);
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 822b4a8..240c134 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -17,30 +17,37 @@
#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/RefBase.h>
+#include <ui/ISurface.h>
+#include <ui/Camera.h>
#include <ui/CameraParameters.h>
#include <ui/Overlay.h>
namespace android {
+/**
+ * The size of image for display.
+ */
+typedef struct image_rect_struct
+{
+ uint32_t width; /* Image width */
+ uint32_t height; /* Image height */
+} image_rect_type;
-/** Callback for startPreview() */
-typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
-
-/** Callback for startRecord() */
-typedef void (*recording_callback)(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
-
-/** Callback for takePicture() */
-typedef void (*shutter_callback)(void* user);
-/** Callback for takePicture() */
-typedef void (*raw_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*notify_callback)(int32_t msgType,
+ int32_t ext1,
+ int32_t ext2,
+ void* user);
-/** Callback for takePicture() */
-typedef void (*jpeg_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*data_callback)(int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
-/** Callback for autoFocus() */
-typedef void (*autofocus_callback)(bool focused, void* user);
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+ int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
/**
* CameraHardwareInterface.h defines the interface to the
@@ -57,28 +64,21 @@ typedef void (*autofocus_callback)(bool focused, void* user);
* CameraService calls getPreviewHeap() to establish access to the
* preview heap so it can be registered with SurfaceFlinger for
* efficient display updating while in preview mode.
- * -# startPreview() is called, which is passed a preview_callback()
- * function and a user parameter. The camera instance then periodically
- * calls preview_callback() each time a new preview frame is available.
- * The callback routine has two parameters: the first is a pointer to
- * the IMemory containing the frame and the second a user parameter. If
- * the preview_callback code needs to use this memory after returning,
- * it must copy the data.
+ * -# startPreview() is called. The camera instance then periodically
+ * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ * a new preview frame is available. If data callback code needs to use
+ * this memory after returning, it must copy the data.
*
- * Prior to taking a picture, CameraService calls autofocus() with
- * autofocus_callback() and a user parameter. When auto focusing has
- * completed, the camera instance calls autofocus_callback(), which informs
- * the application whether focusing was successful. The camera instance
- * only calls autofocus_callback() once and it is up to the application to
- * call autoFocus() again if refocusing is desired.
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up to the application to call autoFocus()
+ * again if refocusing is desired.
*
* CameraService calls takePicture() to request the camera instance take a
- * picture. This method has two callbacks: raw_callback() and jpeg_callback().
- * When the raw image is available, raw_callback() is called with a pointer
- * to the IMemory containing the raw image. When the jpeg image is available,
- * jpeg_callback() is called with a pointer to the IMemory containing the
- * jpeg image. As with preview_callback(), the memory must be copied if it's
- * needed after returning.
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
*/
class CameraHardwareInterface : public virtual RefBase {
public:
@@ -90,17 +90,45 @@ public:
/** Return the IMemoryHeap for the raw image heap */
virtual sp<IMemoryHeap> getRawHeap() const = 0;
+ /** Set the notification and data callbacks */
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user) = 0;
+
+ /**
+ * The following three functions all take a msgtype,
+ * which is a bitmask of the messages defined in
+ * include/ui/Camera.h
+ */
+
+ /**
+ * Enable a message, or set of messages.
+ */
+ virtual void enableMsgType(int32_t msgType) = 0;
+
+ /**
+ * Disable a message, or a set of messages.
+ */
+ virtual void disableMsgType(int32_t msgType) = 0;
+
/**
- * Start preview mode. When a preview image is available
- * preview_callback is called with the user parameter. The
- * call back parameter may be null.
+ * Query whether a message, or a set of messages, is enabled.
+ * Note that this is operates as an AND, if any of the messages
+ * queried are off, this will return false.
*/
- virtual status_t startPreview(preview_callback cb, void* user) = 0;
+ virtual bool msgTypeEnabled(int32_t msgType) = 0;
+
+ /**
+ * Start preview mode.
+ */
+ virtual status_t startPreview() = 0;
+
/**
* Only used if overlays are used for camera preview.
*/
- virtual bool useOverlay() {return false;}
- virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
+ virtual bool useOverlay() {return false;}
+ virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
/**
* Stop a previously started preview.
@@ -113,11 +141,11 @@ public:
virtual bool previewEnabled() = 0;
/**
- * Start record mode. When a record image is available recording_callback()
- * is called with the user parameter. Every record frame must be released
+ * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+ * message is sent with the corresponding frame. Every record frame must be released
* by calling releaseRecordingFrame().
*/
- virtual status_t startRecording(recording_callback cb, void* user) = 0;
+ virtual status_t startRecording() = 0;
/**
* Stop a previously started recording.
@@ -128,41 +156,37 @@ public:
* Returns true if recording is enabled.
*/
virtual bool recordingEnabled() = 0;
-
+
/**
- * Release a record frame previously returned by the recording_callback()
- * passed to startRecord().
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
*/
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
/**
- * Start auto focus, the callback routine is called
- * once when focusing is complete. autoFocus() will
- * be called again if another auto focus is needed.
+ * Start auto focus, the notification callback routine is called
+ * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+ * will be called again if another auto focus is needed.
*/
- virtual status_t autoFocus(autofocus_callback,
- void* user) = 0;
+ virtual status_t autoFocus() = 0;
/**
- * Take a picture. The raw_callback is called when
- * the uncompressed image is available. The jpeg_callback
- * is called when the compressed image is available. These
- * call backs may be null. The user parameter is passed
- * to each of the call back routines.
+ * Cancels auto-focus function. If the auto-focus is still in progress,
+ * this function will cancel it. Whether the auto-focus is in progress
+ * or not, this function will return the focus position to the default.
+ * If the camera does not support auto-focus, this is a no-op.
*/
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user) = 0;
+ virtual status_t cancelAutoFocus() = 0;
/**
- * Cancel a picture that was started with takePicture. You may cancel any
- * of the shutter, raw, or jpeg callbacks. Calling this method when no
- * picture is being taken is a no-op.
+ * Take a picture.
*/
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg) = 0;
+ virtual status_t takePicture() = 0;
+
+ /**
+ * Cancel a picture that was started with takePicture. Calling this
+ * method when no picture is being taken is a no-op.
+ */
+ virtual status_t cancelPicture() = 0;
/** Set the camera parameters. */
virtual status_t setParameters(const CameraParameters& params) = 0;
@@ -171,11 +195,16 @@ public:
virtual CameraParameters getParameters() const = 0;
/**
+ * Send command to camera driver.
+ */
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+
+ /**
* Release the hardware resources owned by this object. Note that this is
* *not* done in the destructor.
*/
virtual void release() = 0;
-
+
/**
* Dump state of the camera hardware
*/
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index 9ca1806..9e4e140 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -69,11 +69,205 @@ public:
void dump() const;
status_t dump(int fd, const Vector<String16>& args) const;
+ // Parameter keys to communicate between camera application and driver.
+ // The access (read/write, read only, or write only) is viewed from the
+ // perspective of applications, not driver.
+
+ // Preview frame size in pixels (width x height).
+ // Example value: "480x320". Read/Write.
+ static const char KEY_PREVIEW_SIZE[];
+ // Supported preview frame sizes in pixels.
+ // Example value: "800x600,480x320". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+ // The image format for preview frames.
+ // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read/write.
+ static const char KEY_PREVIEW_FORMAT[];
+ // Supported image formats for preview frames.
+ // Example value: "yuv420sp,yuv422i-yuyv". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
+ // Number of preview frames per second.
+ // Example value: "15". Read/write.
+ static const char KEY_PREVIEW_FRAME_RATE[];
+ // Supported number of preview frames per second.
+ // Example value: "24,15,10". Read.
+ static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
+ // The dimensions for captured pictures in pixels (width x height).
+ // Example value: "1024x768". Read/write.
+ static const char KEY_PICTURE_SIZE[];
+ // Supported dimensions for captured pictures in pixels.
+ // Example value: "2048x1536,1024x768". Read only.
+ static const char KEY_SUPPORTED_PICTURE_SIZES[];
+ // The image format for captured pictures.
+ // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
+ static const char KEY_PICTURE_FORMAT[];
+ // Supported image formats for captured pictures.
+ // Example value: "jpeg,rgb565". Read only.
+ static const char KEY_SUPPORTED_PICTURE_FORMATS[];
+ // The width (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "512". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_WIDTH[];
+ // The height (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "384". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
+ // Supported EXIF thumbnail sizes (width x height).
+ // Example value: "512x384,320x240". Read only.
+ static const char KEY_SUPPORTED_THUMBNAIL_SIZES[];
+ // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
+ // with 100 being the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_QUALITY[];
+ // Jpeg quality of captured picture. The range is 1 to 100, with 100 being
+ // the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_QUALITY[];
+ // The orientation of the device in degrees. For example, suppose the
+ // natural position of the device is landscape. If the user takes a picture
+ // in landscape mode in 2048x1536 resolution, the rotation will be set to
+ // "0". If the user rotates the phone 90 degrees clockwise, the rotation
+ // should be set to "90".
+ // The camera driver can set orientation in the EXIF header without rotating
+ // the picture. Or the driver can rotate the picture and the EXIF thumbnail.
+ // If the Jpeg picture is rotated, the orientation in the EXIF header should
+ // be missing or 1 (row #0 is top and column #0 is left side). The driver
+ // should not set default value for this parameter.
+ // Example value: "0" or "90" or "180" or "270". Write only.
+ static const char KEY_ROTATION[];
+ // GPS latitude coordinate. This will be stored in JPEG EXIF header.
+ // Example value: "25.032146". Write only.
+ static const char KEY_GPS_LATITUDE[];
+ // GPS longitude coordinate. This will be stored in JPEG EXIF header.
+ // Example value: "121.564448". Write only.
+ static const char KEY_GPS_LONGITUDE[];
+ // GPS altitude. This will be stored in JPEG EXIF header.
+ // Example value: "21.0". Write only.
+ static const char KEY_GPS_ALTITUDE[];
+ // GPS timestamp (UTC in seconds since January 1, 1970). This should be
+ // stored in JPEG EXIF header.
+ // Example value: "1251192757". Write only.
+ static const char KEY_GPS_TIMESTAMP[];
+ // Current white balance setting.
+ // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
+ static const char KEY_WHITE_BALANCE[];
+ // Supported white balance settings.
+ // Example value: "auto,incandescent,daylight". Read only.
+ static const char KEY_SUPPORTED_WHITE_BALANCE[];
+ // Current color effect setting.
+ // Example value: "none" or EFFECT_XXX constants. Read/write.
+ static const char KEY_EFFECT[];
+ // Supported color effect settings.
+ // Example value: "none,mono,sepia". Read only.
+ static const char KEY_SUPPORTED_EFFECTS[];
+ // Current antibanding setting.
+ // Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
+ static const char KEY_ANTIBANDING[];
+ // Supported antibanding settings.
+ // Example value: "auto,50hz,60hz,off". Read only.
+ static const char KEY_SUPPORTED_ANTIBANDING[];
+ // Current scene mode.
+ // Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
+ static const char KEY_SCENE_MODE[];
+ // Supported scene mode settings.
+ // Example value: "auto,night,fireworks". Read only.
+ static const char KEY_SUPPORTED_SCENE_MODES[];
+ // Current flash mode.
+ // Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
+ static const char KEY_FLASH_MODE[];
+ // Supported flash modes.
+ // Example value: "auto,on,off". Read only.
+ static const char KEY_SUPPORTED_FLASH_MODES[];
+ // Current focus mode. If the camera does not support auto-focus, the value
+ // should be FOCUS_MODE_FIXED. If the focus mode is not FOCUS_MODE_FIXED or
+ // or FOCUS_MODE_INFINITY, applications should call
+ // CameraHardwareInterface.autoFocus to start the focus.
+ // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
+ static const char KEY_FOCUS_MODE[];
+ // Supported focus modes.
+ // Example value: "auto,macro,fixed". Read only.
+ static const char KEY_SUPPORTED_FOCUS_MODES[];
+
+ // Values for white balance settings.
+ static const char WHITE_BALANCE_AUTO[];
+ static const char WHITE_BALANCE_INCANDESCENT[];
+ static const char WHITE_BALANCE_FLUORESCENT[];
+ static const char WHITE_BALANCE_WARM_FLUORESCENT[];
+ static const char WHITE_BALANCE_DAYLIGHT[];
+ static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
+ static const char WHITE_BALANCE_TWILIGHT[];
+ static const char WHITE_BALANCE_SHADE[];
+
+ // Values for effect settings.
+ static const char EFFECT_NONE[];
+ static const char EFFECT_MONO[];
+ static const char EFFECT_NEGATIVE[];
+ static const char EFFECT_SOLARIZE[];
+ static const char EFFECT_SEPIA[];
+ static const char EFFECT_POSTERIZE[];
+ static const char EFFECT_WHITEBOARD[];
+ static const char EFFECT_BLACKBOARD[];
+ static const char EFFECT_AQUA[];
+
+ // Values for antibanding settings.
+ static const char ANTIBANDING_AUTO[];
+ static const char ANTIBANDING_50HZ[];
+ static const char ANTIBANDING_60HZ[];
+ static const char ANTIBANDING_OFF[];
+
+ // Values for flash mode settings.
+ // Flash will not be fired.
+ static const char FLASH_MODE_OFF[];
+ // Flash will be fired automatically when required. The flash may be fired
+ // during preview, auto-focus, or snapshot depending on the driver.
+ static const char FLASH_MODE_AUTO[];
+ // Flash will always be fired during snapshot. The flash may also be
+ // fired during preview or auto-focus depending on the driver.
+ static const char FLASH_MODE_ON[];
+ // Flash will be fired in red-eye reduction mode.
+ static const char FLASH_MODE_RED_EYE[];
+ // Constant emission of light during preview, auto-focus and snapshot.
+ // This can also be used for video recording.
+ static const char FLASH_MODE_TORCH[];
+
+ // Values for scene mode settings.
+ static const char SCENE_MODE_AUTO[];
+ static const char SCENE_MODE_ACTION[];
+ static const char SCENE_MODE_PORTRAIT[];
+ static const char SCENE_MODE_LANDSCAPE[];
+ static const char SCENE_MODE_NIGHT[];
+ static const char SCENE_MODE_NIGHT_PORTRAIT[];
+ static const char SCENE_MODE_THEATRE[];
+ static const char SCENE_MODE_BEACH[];
+ static const char SCENE_MODE_SNOW[];
+ static const char SCENE_MODE_SUNSET[];
+ static const char SCENE_MODE_STEADYPHOTO[];
+ static const char SCENE_MODE_FIREWORKS[];
+ static const char SCENE_MODE_SPORTS[];
+ static const char SCENE_MODE_PARTY[];
+ static const char SCENE_MODE_CANDLELIGHT[];
+
+ // Formats for setPreviewFormat and setPictureFormat.
+ static const char PIXEL_FORMAT_YUV422SP[];
+ static const char PIXEL_FORMAT_YUV420SP[]; // NV21
+ static const char PIXEL_FORMAT_YUV422I[]; // YUY2
+ static const char PIXEL_FORMAT_RGB565[];
+ static const char PIXEL_FORMAT_JPEG[];
+
+ // Values for focus mode settings.
+ // Auto-focus mode.
+ static const char FOCUS_MODE_AUTO[];
+ // Focus is set at infinity. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_INFINITY[];
+ static const char FOCUS_MODE_MACRO[];
+ // Focus is fixed. The camera is always in this mode if the focus is not
+ // adjustable. If the camera has auto-focus, this mode can fix the
+ // focus, which is usually at hyperfocal distance. Applications should
+ // not call CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_FIXED[];
+
private:
DefaultKeyedVector<String8,String8> mMap;
};
-
}; // namespace android
#endif
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
deleted file mode 100644
index a8b5853..0000000
--- a/include/ui/EGLDisplaySurface.h
+++ /dev/null
@@ -1,86 +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_EGL_DISPLAY_SURFACE_H
-#define ANDROID_EGL_DISPLAY_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/EGLNativeSurface.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <linux/fb.h>
-
-#include <EGL/egl.h>
-
-struct copybit_device_t;
-struct copybit_image_t;
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Region;
-class Rect;
-
-class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
-{
-public:
- EGLDisplaySurface();
- ~EGLDisplaySurface();
-
- int32_t getPageFlipCount() const;
- void copyFrontToBack(const Region& copyback);
- void copyFrontToImage(const copybit_image_t& dst);
- void copyBackToImage(const copybit_image_t& dst);
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
-
- uint32_t swapBuffers();
-
- status_t mapFrameBuffer();
-
- enum {
- PAGE_FLIP = 0x00000001
- };
- GGLSurface mFb[2];
- int mIndex;
- uint32_t mFlags;
- size_t mSize;
- fb_var_screeninfo mInfo;
- fb_fix_screeninfo mFinfo;
- int32_t mPageFlipCount;
- nsecs_t mTime;
- int32_t mSwapCount;
- nsecs_t mSleep;
- uint32_t mFeatureFlags;
- copybit_device_t* mBlitEngine;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_DISPLAY_SURFACE_H
-
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
deleted file mode 100644
index 3494234..0000000
--- a/include/ui/EGLNativeWindowSurface.h
+++ /dev/null
@@ -1,59 +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_EGL_NATIVE_WINDOW_SURFACE_H
-#define ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ui/EGLNativeSurface.h>
-#include <EGL/egl.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Surface;
-
-class EGLNativeWindowSurface : public EGLNativeSurface<EGLNativeWindowSurface>
-{
-public:
- EGLNativeWindowSurface(const sp<Surface>& surface);
- ~EGLNativeWindowSurface();
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
- static void hook_connect(NativeWindowType window);
- static void hook_disconnect(NativeWindowType window);
-
- uint32_t swapBuffers();
- void connect();
- void disconnect();
-
- sp<Surface> mSurface;
- bool mConnected;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
diff --git a/include/ui/EGLUtils.h b/include/ui/EGLUtils.h
new file mode 100644
index 0000000..a5bff81
--- /dev/null
+++ b/include/ui/EGLUtils.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_UI_EGLUTILS_H
+#define ANDROID_UI_EGLUTILS_H
+
+#include <utils/Errors.h>
+#include <ui/PixelFormat.h>
+#include <EGL/egl.h>
+
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class EGLUtils
+{
+public:
+
+ static const char *strerror(EGLint err);
+
+ static status_t selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig);
+
+ static status_t selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_UI_EGLUTILS_H */
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3848d8c..3b18c77 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -20,7 +20,10 @@
#include <utils/String8.h>
#include <utils/threads.h>
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <linux/input.h>
@@ -52,7 +55,9 @@ public:
CLASS_KEYBOARD = 0x00000001,
CLASS_ALPHAKEY = 0x00000002,
CLASS_TOUCHSCREEN = 0x00000004,
- CLASS_TRACKBALL = 0x00000008
+ CLASS_TRACKBALL = 0x00000008,
+ CLASS_TOUCHSCREEN_MT= 0x00000010,
+ CLASS_DPAD = 0x00000020
};
uint32_t getDeviceClasses(int32_t deviceId) const;
@@ -70,6 +75,13 @@ public:
int getKeycodeState(int key) const;
int getKeycodeState(int32_t deviceId, int key) const;
+ status_t scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const;
+
+ // exclude a particular device from opening
+ // this can be used to ignore input devices for sensors
+ void addExcludedDevice(const char* deviceName);
+
// special type codes when devices are added/removed.
enum {
DEVICE_ADDED = 0x10000000,
@@ -82,10 +94,9 @@ public:
virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen);
-
+
protected:
virtual ~EventHub();
- virtual void onFirstRef();
private:
bool openPlatformInput(void);
@@ -108,17 +119,18 @@ private:
String8 keylayoutFilename;
device_t* next;
- device_t(int32_t _id, const char* _path);
+ device_t(int32_t _id, const char* _path, const char* name);
~device_t();
};
device_t* getDevice(int32_t deviceId) const;
+ bool hasKeycode(device_t* device, int keycode) const;
// Protect all internal state.
mutable Mutex mLock;
bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+ int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
struct device_ent {
device_t* device;
@@ -133,7 +145,10 @@ private:
device_t **mDevices;
struct pollfd *mFDs;
int mFDCount;
-
+
+ bool mOpened;
+ List<String8> mExcludedDevices;
+
// device ids that report particular switches.
#ifdef EV_SW
int32_t mSwitches[SW_MAX+1];
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
new file mode 100644
index 0000000..8ea3ab9
--- /dev/null
+++ b/include/ui/FramebufferNativeWindow.h
@@ -0,0 +1,88 @@
+/*
+ * 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_FRAMEBUFFER_NATIVE_WINDOW_H
+#define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <utils/threads.h>
+#include <ui/Rect.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include <ui/egl/android_natives.h>
+
+
+extern "C" EGLNativeWindowType android_createDisplaySurface(void);
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Surface;
+class NativeBuffer;
+
+// ---------------------------------------------------------------------------
+
+class FramebufferNativeWindow
+ : public EGLNativeBase<
+ android_native_window_t,
+ FramebufferNativeWindow,
+ LightRefBase<FramebufferNativeWindow> >
+{
+public:
+ FramebufferNativeWindow();
+
+ framebuffer_device_t const * getDevice() const { return fbDev; }
+
+ bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+ status_t setUpdateRectangle(const Rect& updateRect);
+ status_t compositionComplete();
+
+private:
+ friend class LightRefBase<FramebufferNativeWindow>;
+ ~FramebufferNativeWindow(); // this class cannot be overloaded
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+
+ framebuffer_device_t* fbDev;
+ alloc_device_t* grDev;
+
+ sp<NativeBuffer> buffers[2];
+ sp<NativeBuffer> front;
+
+ mutable Mutex mutex;
+ Condition mCondition;
+ int32_t mNumBuffers;
+ int32_t mNumFreeBuffers;
+ int32_t mBufferHead;
+ bool mUpdateOnDemand;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
new file mode 100644
index 0000000..b9c491b
--- /dev/null
+++ b/include/ui/GraphicBuffer.h
@@ -0,0 +1,136 @@
+/*
+ * 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_GRAPHIC_BUFFER_H
+#define ANDROID_GRAPHIC_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/android_native_buffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <pixelflinger/pixelflinger.h>
+
+struct android_native_buffer_t;
+
+namespace android {
+
+class GraphicBufferMapper;
+class Parcel;
+
+// ===========================================================================
+// GraphicBuffer
+// ===========================================================================
+
+class GraphicBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ GraphicBuffer,
+ LightRefBase<GraphicBuffer> >
+{
+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
+ };
+
+ GraphicBuffer();
+
+ // creates w * h buffer
+ GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+ // create a buffer from an existing handle
+ GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t stride, native_handle_t* handle, bool keepOwnership);
+
+ // 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 reallocate(uint32_t w, uint32_t h, PixelFormat f, uint32_t usage);
+
+ status_t lock(uint32_t usage, void** vaddr);
+ status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
+ status_t lock(GGLSurface* surface, uint32_t usage);
+ status_t unlock();
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+ void setIndex(int index);
+ int getIndex() const;
+ void setVerticalStride(uint32_t vstride);
+ uint32_t getVerticalStride() const;
+
+protected:
+ GraphicBuffer(const Parcel& reply);
+ virtual ~GraphicBuffer();
+
+ enum {
+ ownNone = 0,
+ ownHandle = 1,
+ ownData = 2,
+ };
+
+ inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
+ uint8_t mOwner;
+
+private:
+ friend class Surface;
+ friend class BpSurface;
+ friend class BnSurface;
+ friend class LightRefBase<GraphicBuffer>;
+ GraphicBuffer(const GraphicBuffer& rhs);
+ GraphicBuffer& operator = (const GraphicBuffer& rhs);
+ const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
+
+ status_t initSize(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t usage);
+
+ static status_t writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer);
+
+ GraphicBufferMapper& mBufferMapper;
+ ssize_t mInitCheck;
+ uint32_t mVStride;
+ int mIndex;
+};
+
+}; // namespace android
+
+#endif // ANDROID_GRAPHIC_BUFFER_H
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
new file mode 100644
index 0000000..be9c79b
--- /dev/null
+++ b/include/ui/GraphicBufferAllocator.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 GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
+{
+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 GraphicBufferAllocator& 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<GraphicBufferAllocator>;
+ GraphicBufferAllocator();
+ ~GraphicBufferAllocator();
+
+ mutable Mutex mLock;
+ alloc_device_t *mAllocDev;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFER_ALLOCATOR_H
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
new file mode 100644
index 0000000..697a02a
--- /dev/null
+++ b/include/ui/GraphicBufferMapper.h
@@ -0,0 +1,64 @@
+/*
+ * 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_UI_BUFFER_MAPPER_H
+#define ANDROID_UI_BUFFER_MAPPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Singleton.h>
+
+#include <hardware/gralloc.h>
+
+
+struct gralloc_module_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Rect;
+
+class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
+{
+public:
+ static inline GraphicBufferMapper& get() { return getInstance(); }
+
+ status_t registerBuffer(buffer_handle_t handle);
+
+ status_t unregisterBuffer(buffer_handle_t handle);
+
+ status_t lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr);
+
+ status_t unlock(buffer_handle_t handle);
+
+ // dumps information about the mapping of this handle
+ void dump(buffer_handle_t handle);
+
+private:
+ friend class Singleton<GraphicBufferMapper>;
+ GraphicBufferMapper();
+ gralloc_module_t const *mAllocMod;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_UI_BUFFER_MAPPER_H
+
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index 241fb63..5642691 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -18,10 +18,10 @@
#define ANDROID_HARDWARE_ICAMERA_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ISurface.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/String8.h>
#include <ui/Camera.h>
@@ -76,6 +76,9 @@ public:
// auto focus
virtual status_t autoFocus() = 0;
+ // cancel auto focus
+ virtual status_t cancelAutoFocus() = 0;
+
// take a picture
virtual status_t takePicture() = 0;
@@ -84,6 +87,9 @@ public:
// get preview/capture parameters - key/value pairs
virtual String8 getParameters() const = 0;
+
+ // send command to camera driver
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index 1001c71..236d0f6 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -18,9 +18,9 @@
#define ANDROID_HARDWARE_ICAMERA_APP_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <utils/Timers.h>
namespace android {
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
index c652c51..061681a 100644
--- a/include/ui/ICameraService.h
+++ b/include/ui/ICameraService.h
@@ -18,8 +18,8 @@
#define ANDROID_HARDWARE_ICAMERASERVICE_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ICameraClient.h>
#include <ui/ICamera.h>
diff --git a/include/ui/IOverlay.h b/include/ui/IOverlay.h
index 699b1b0..af3add1 100644
--- a/include/ui/IOverlay.h
+++ b/include/ui/IOverlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 87b320f..2ca0026 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -21,11 +21,12 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
namespace android {
@@ -33,6 +34,7 @@ typedef int32_t SurfaceID;
class IMemoryHeap;
class OverlayRef;
+class GraphicBuffer;
class ISurface : public IInterface
{
@@ -42,11 +44,13 @@ protected:
UNREGISTER_BUFFERS,
POST_BUFFER, // one-way transaction
CREATE_OVERLAY,
+ REQUEST_BUFFER,
};
public:
DECLARE_META_INTERFACE(Surface);
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0;
class BufferHeap {
public:
@@ -78,9 +82,7 @@ public:
};
virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
-
virtual void postBuffer(ssize_t offset) = 0; // one-way
-
virtual void unregisterBuffers() = 0;
virtual sp<OverlayRef> createOverlay(
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
index 5c64b22..25d954c 100644
--- a/include/ui/ISurfaceComposer.h
+++ b/include/ui/ISurfaceComposer.h
@@ -22,7 +22,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -32,7 +32,6 @@ namespace android {
// ----------------------------------------------------------------------------
class DisplayInfo;
-class IGPUCallback;
class ISurfaceComposer : public IInterface
{
@@ -41,8 +40,6 @@ public:
enum { // (keep in sync with Surface.java)
eHidden = 0x00000004,
- eGPU = 0x00000008,
- eHardware = 0x00000010,
eDestroyBackbuffer = 0x00000020,
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
@@ -63,7 +60,6 @@ public:
eTransparentRegionChanged = 0x00000020,
eVisibilityChanged = 0x00000040,
eFreezeTintChanged = 0x00000080,
- eDestroyed = 0x00000100
};
enum {
@@ -94,7 +90,7 @@ public:
virtual sp<ISurfaceFlingerClient> createConnection() = 0;
/* retrieve the control block */
- virtual sp<IMemory> getCblk() const = 0;
+ virtual sp<IMemoryHeap> getCblk() const = 0;
/* open/close transactions. recquires ACCESS_SURFACE_FLINGER permission */
virtual void openGlobalTransaction() = 0;
@@ -112,37 +108,12 @@ public:
*/
virtual void bootFinished() = 0;
- /* get access to the GPU. Access is relinquished when releasing regs */
- struct gpu_info_t {
- struct gpu_region_t {
- sp<IMemory> region;
- size_t reserved;
- };
- sp<IMemory> regs;
- size_t count;
- gpu_region_t regions[2];
- };
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback,
- gpu_info_t* gpu) = 0;
-
- /* take the gpu back from any apps using it. They'll get a
- * EGL_CONTEXT_LOST error */
- virtual status_t revokeGPU() = 0;
-
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
};
-class IGPUCallback : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(GPUCallback);
- virtual void gpuLost() = 0; //one-way
-};
-
// ----------------------------------------------------------------------------
class BnSurfaceComposer : public BnInterface<ISurfaceComposer>
@@ -159,8 +130,6 @@ public:
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
- REQUEST_GPU,
- REVOKE_GPU,
SIGNAL
};
@@ -170,15 +139,6 @@ public:
uint32_t flags = 0);
};
-class BnGPUCallback : public BnInterface<IGPUCallback>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 5b9361d..5d231e6 100644
--- a/include/ui/ISurfaceFlingerClient.h
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/ISurface.h>
@@ -52,12 +52,14 @@ public:
struct surface_data_t {
int32_t token;
int32_t identity;
- sp<IMemoryHeap> heap[2];
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
};
- virtual void getControlBlocks(sp<IMemory>* ctl) const = 0;
+ virtual sp<IMemoryHeap> getControlBlock() const = 0;
virtual sp<ISurface> createSurface( surface_data_t* data,
int pid,
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
index 66514b4..a9ae1c4 100644
--- a/include/ui/Overlay.h
+++ b/include/ui/Overlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -82,6 +82,16 @@ public:
/* release the overlay buffer and post it */
status_t queueBuffer(overlay_buffer_t buffer);
+ /* change the width and height of the overlay */
+ status_t resizeInput(uint32_t width, uint32_t height);
+
+ status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
+
+ status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
+
+ /* set the buffer attributes */
+ status_t setParameter(int param, int value);
+
/* returns the address of a given buffer if supported, NULL otherwise. */
void* getBufferAddress(overlay_buffer_t buffer);
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index 14af823..6d87321b 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -84,6 +84,13 @@ typedef int32_t PixelFormat;
struct PixelFormatInfo
{
+ enum {
+ INDEX_ALPHA = 0,
+ INDEX_RED = 1,
+ INDEX_GREEN = 2,
+ INDEX_BLUE = 3
+ };
+
enum { // components
ALPHA = 1,
RGB = 2,
@@ -95,20 +102,33 @@ struct PixelFormatInfo
Y_CB_CR_I = 8,
};
+ struct szinfo {
+ uint8_t h;
+ uint8_t l;
+ };
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
+ size_t getSize(size_t ci) const {
+ return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
+ }
size_t version;
PixelFormat format;
size_t bytesPerPixel;
size_t bitsPerPixel;
- uint8_t h_alpha;
- uint8_t l_alpha;
- uint8_t h_red;
- uint8_t l_red;
- uint8_t h_green;
- uint8_t l_green;
- uint8_t h_blue;
- uint8_t l_blue;
+ union {
+ szinfo cinfo[4];
+ struct {
+ uint8_t h_alpha;
+ uint8_t l_alpha;
+ uint8_t h_red;
+ uint8_t l_red;
+ uint8_t h_green;
+ uint8_t l_green;
+ uint8_t h_blue;
+ uint8_t l_blue;
+ };
+ };
uint8_t components;
uint8_t reserved0[3];
uint32_t reserved1;
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index da72944..a213c09 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -30,6 +30,8 @@ public:
int right;
int bottom;
+ typedef int value_type;
+
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
@@ -46,7 +48,11 @@ public:
}
void makeInvalid();
-
+
+ inline void clear() {
+ left = top = right = bottom = 0;
+ }
+
// a valid rectangle has a non negative width and height
inline bool isValid() const {
return (width()>=0) && (height()>=0);
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 7689673..2bcad5b 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -21,14 +21,12 @@
#include <sys/types.h>
#include <utils/Vector.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/Rect.h>
#include <hardware/copybit.h>
-#include <core/SkRegion.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -40,7 +38,6 @@ class Region
public:
Region();
Region(const Region& rhs);
- explicit Region(const SkRegion& rhs);
explicit Region(const Rect& rhs);
explicit Region(const Parcel& parcel);
explicit Region(const void* buffer);
@@ -48,65 +45,78 @@ public:
Region& operator = (const Region& rhs);
- inline bool isEmpty() const { return mRegion.isEmpty(); }
- inline bool isRect() const { return mRegion.isRect(); }
-
- Rect bounds() const;
+ inline bool isEmpty() const { return mBounds.isEmpty(); }
+ inline bool isRect() const { return mStorage.isEmpty(); }
- const SkRegion& toSkRegion() const;
+ inline Rect getBounds() const { return mBounds; }
+ inline Rect bounds() const { return getBounds(); }
+ // the region becomes its bounds
+ Region& makeBoundsSelf();
+
void clear();
void set(const Rect& r);
+ void set(uint32_t w, uint32_t h);
Region& orSelf(const Rect& rhs);
Region& andSelf(const Rect& rhs);
+ Region& subtractSelf(const Rect& rhs);
// boolean operators, applied on this
Region& orSelf(const Region& rhs);
Region& andSelf(const Region& rhs);
Region& subtractSelf(const Region& rhs);
+ // boolean operators
+ const Region merge(const Rect& rhs) const;
+ const Region intersect(const Rect& rhs) const;
+ const Region subtract(const Rect& rhs) const;
+
+ // boolean operators
+ const Region merge(const Region& rhs) const;
+ const Region intersect(const Region& rhs) const;
+ const Region subtract(const Region& rhs) const;
+
// these translate rhs first
Region& translateSelf(int dx, int dy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
- // boolean operators
- Region merge(const Region& rhs) const;
- Region intersect(const Region& rhs) const;
- Region subtract(const Region& rhs) const;
-
// these translate rhs first
- Region translate(int dx, int dy) const;
- Region merge(const Region& rhs, int dx, int dy) const;
- Region intersect(const Region& rhs, int dx, int dy) const;
- Region subtract(const Region& rhs, int dx, int dy) const;
+ const Region translate(int dx, int dy) const;
+ const Region merge(const Region& rhs, int dx, int dy) const;
+ const Region intersect(const Region& rhs, int dx, int dy) const;
+ const Region subtract(const Region& rhs, int dx, int dy) const;
// convenience operators overloads
- inline Region operator | (const Region& rhs) const;
- inline Region operator & (const Region& rhs) const;
- inline Region operator - (const Region& rhs) const;
- inline Region operator + (const Point& pt) const;
+ inline const Region operator | (const Region& rhs) const;
+ inline const Region operator & (const Region& rhs) const;
+ inline const Region operator - (const Region& rhs) const;
+ inline const Region operator + (const Point& pt) const;
inline Region& operator |= (const Region& rhs);
inline Region& operator &= (const Region& rhs);
inline Region& operator -= (const Region& rhs);
inline Region& operator += (const Point& pt);
- class iterator {
- SkRegion::Iterator mIt;
- public:
- iterator(const Region& r);
- inline operator bool () const { return !done(); }
- int iterate(Rect* rect);
- private:
- inline bool done() const {
- return const_cast<SkRegion::Iterator&>(mIt).done();
- }
- };
+
+ /* various ways to access the rectangle list */
+
+ typedef Rect const* const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
- size_t rects(Vector<Rect>& rectList) const;
+ /* no user serviceable parts here... */
+
+ size_t getRects(Vector<Rect>& rectList) const;
+ Rect const* getArray(size_t* count) const;
+
+
+ // add a rectangle to the internal list. This rectangle must
+ // be sorted in Y and X and must not make the region invalid.
+ void addRectUnchecked(int l, int t, int r, int b);
// flatten/unflatten a region to/from a Parcel
status_t write(Parcel& parcel) const;
@@ -123,20 +133,46 @@ public:
void dump(const char* what, uint32_t flags=0) const;
private:
- SkRegion mRegion;
+ class rasterizer;
+ friend class rasterizer;
+
+ Region& operationSelf(const Rect& r, int op);
+ Region& operationSelf(const Region& r, int op);
+ Region& operationSelf(const Region& r, int dx, int dy, int op);
+ const Region operation(const Rect& rhs, int op) const;
+ const Region operation(const Region& rhs, int op) const;
+ const Region operation(const Region& rhs, int dx, int dy, int op) const;
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs, int dx, int dy);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs, int dx, int dy);
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs);
+
+ static void translate(Region& reg, int dx, int dy);
+ static void translate(Region& dst, const Region& reg, int dx, int dy);
+
+ static bool validate(const Region& reg, const char* name);
+
+ Rect mBounds;
+ Vector<Rect> mStorage;
};
-Region Region::operator | (const Region& rhs) const {
+const Region Region::operator | (const Region& rhs) const {
return merge(rhs);
}
-Region Region::operator & (const Region& rhs) const {
+const Region Region::operator & (const Region& rhs) const {
return intersect(rhs);
}
-Region Region::operator - (const Region& rhs) const {
+const Region Region::operator - (const Region& rhs) const {
return subtract(rhs);
}
-Region Region::operator + (const Point& pt) const {
+const Region Region::operator + (const Point& pt) const {
return translate(pt.x, pt.y);
}
@@ -157,16 +193,23 @@ Region& Region::operator += (const Point& pt) {
// ---------------------------------------------------------------------------
struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region) : i(region) {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
this->next = iterate;
}
private:
static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- return static_cast<const region_iterator*>(self)
- ->i.iterate(reinterpret_cast<Rect*>(rect));
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
}
- mutable Region::iterator i;
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
};
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 33953a9..70303cd 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -28,48 +28,41 @@
#include <ui/Region.h>
#include <ui/ISurfaceFlingerClient.h>
+#include <ui/egl/android_natives.h>
+
namespace android {
// ---------------------------------------------------------------------------
+class GraphicBufferMapper;
+class IOMX;
class Rect;
+class Surface;
class SurfaceComposerClient;
+class SharedClient;
+class SharedBufferClient;
-class Surface : public RefBase
-{
+// ---------------------------------------------------------------------------
+class SurfaceControl : public RefBase
+{
public:
- struct SurfaceInfo {
- uint32_t w;
- uint32_t h;
- uint32_t bpr;
- PixelFormat format;
- void* bits;
- void* base;
- uint32_t reserved[2];
- };
-
- bool isValid() const { return this && mToken>=0 && mClient!=0; }
+ static bool isValid(const sp<SurfaceControl>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+ bool isValid() {
+ return mToken>=0 && mClient!=0;
+ }
+ static bool isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
+
SurfaceID ID() const { return mToken; }
-
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
- status_t unlockAndPost();
- status_t unlock();
-
- void* heapBase(int i) const;
uint32_t getFlags() const { return mFlags; }
+ uint32_t getIdentity() const { return mIdentity; }
- // setSwapRectangle() is mainly used by EGL
- void setSwapRectangle(const Rect& r);
- const Rect& swapRectangle() const;
- status_t nextBuffer(SurfaceInfo* info);
-
- sp<Surface> dup() const;
- static sp<Surface> readFromParcel(Parcel* parcel);
- static status_t writeToParcel(const sp<Surface>& surface, Parcel* parcel);
- static bool isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs);
-
+ // release surface data from java
+ void clear();
+
status_t setLayer(int32_t layer);
status_t setPosition(int32_t x, int32_t y);
status_t setSize(uint32_t w, uint32_t h);
@@ -83,8 +76,17 @@ public:
status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
status_t setFreezeTint(uint32_t tint);
- uint32_t getIdentity() const { return mIdentity; }
+ static status_t writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel);
+
+ sp<Surface> getSurface() const;
+
private:
+ // can't be copied
+ SurfaceControl& operator = (SurfaceControl& rhs);
+ SurfaceControl(const SurfaceControl& rhs);
+
+
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
@@ -92,43 +94,158 @@ private:
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
+ // for testing
friend class Test;
const sp<ISurface>& getISurface() const { return mSurface; }
+
- // can't be copied
- Surface& operator = (Surface& rhs);
- Surface(const Surface& rhs);
+ friend class Surface;
- Surface(const sp<SurfaceComposerClient>& client,
+ 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,
- bool owner = true);
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
- Surface(Surface const* rhs);
+ ~SurfaceControl();
- ~Surface();
+ status_t validate(SharedClient const* cblk) const;
+ void destroy();
+
+ sp<SurfaceComposerClient> mClient;
+ sp<ISurface> mSurface;
+ SurfaceID mToken;
+ uint32_t mIdentity;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ mutable Mutex mLock;
+
+ mutable sp<Surface> mSurfaceData;
+};
+
+// ---------------------------------------------------------------------------
- Region dirtyRegion() const;
- void setDirtyRegion(const Region& region) const;
+class Surface
+ : public EGLNativeBase<android_native_window_t, Surface, RefBase>
+{
+public:
+ struct SurfaceInfo {
+ uint32_t w;
+ uint32_t h;
+ uint32_t s;
+ uint32_t usage;
+ PixelFormat format;
+ void* bits;
+ uint32_t reserved[2];
+ };
+
+ Surface(const Parcel& data);
+
+ static bool isValid(const sp<Surface>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+
+ static bool isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs);
+
+ bool isValid();
+ SurfaceID ID() const { return mToken; }
+ uint32_t getFlags() const { return mFlags; }
+ uint32_t getIdentity() const { return mIdentity; }
+
+ // the lock/unlock APIs must be used from the same thread
+ status_t lock(SurfaceInfo* info, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t unlockAndPost();
- // this locks protects calls to lockSurface() / unlockSurface()
- // and is called by SurfaceComposerClient.
- Mutex& getLock() const { return mSurfaceLock; }
+ // setSwapRectangle() is intended to be used by GL ES clients
+ void setSwapRectangle(const Rect& r);
+
+private:
+ // can't be copied
+ Surface& operator = (Surface& rhs);
+ Surface(const Surface& rhs);
+
+ Surface(const sp<SurfaceControl>& control);
+ void init();
+ ~Surface();
+
+ friend class SurfaceComposerClient;
+ friend class SurfaceControl;
+
+
+ // camera and camcorder need access to the ISurface binder interface for preview
+ friend class Camera;
+ friend class MediaRecorder;
+ // mediaplayer needs access to ISurface for display
+ friend class MediaPlayer;
+ friend class IOMX;
+ // this is just to be able to write some unit tests
+ friend class Test;
+ sp<SurfaceComposerClient> getClient() const;
+ sp<ISurface> getISurface() const;
+
+ status_t getBufferLocked(int index, int usage);
+
+ status_t validate(SharedClient const* cblk) const;
+
+ inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
+
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+
+ int dequeueBuffer(android_native_buffer_t** buffer);
+ int lockBuffer(android_native_buffer_t* buffer);
+ int queueBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value);
+ int perform(int operation, va_list args);
+
+ status_t dequeueBuffer(sp<GraphicBuffer>* buffer);
+
+
+ void setUsage(uint32_t reqUsage);
+ uint32_t getUsage() const;
+
+ // constants
sp<SurfaceComposerClient> mClient;
sp<ISurface> mSurface;
- sp<IMemoryHeap> mHeap[2];
SurfaceID mToken;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
- const bool mOwner;
- mutable void* mSurfaceHeapBase[2];
+ GraphicBufferMapper& mBufferMapper;
+ SharedBufferClient* mSharedBufferClient;
+
+ // protected by mSurfaceLock
+ Rect mSwapRectangle;
+ uint32_t mUsage;
+
+ // protected by mSurfaceLock. These are also used from lock/unlock
+ // but in that case, they must be called form the same thread.
+ sp<GraphicBuffer> mBuffers[2];
mutable Region mDirtyRegion;
- mutable Rect mSwapRectangle;
- mutable uint8_t mBackbufferIndex;
+
+ // must be used from the lock/unlock thread
+ sp<GraphicBuffer> mLockedBuffer;
+ sp<GraphicBuffer> mPostedBuffer;
+ mutable Region mOldDirtyRegion;
+ bool mNeedFullUpdate;
+
+ // query() must be called from dequeueBuffer() thread
+ uint32_t mWidth;
+ uint32_t mHeight;
+
+ // Inherently thread-safe
mutable Mutex mSurfaceLock;
+ mutable Mutex mApiLock;
};
}; // namespace android
diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h
index 76a3b55..777b878 100644
--- a/include/ui/SurfaceComposerClient.h
+++ b/include/ui/SurfaceComposerClient.h
@@ -20,8 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <binder/IBinder.h>
+
#include <utils/SortedVector.h>
-#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -36,8 +37,7 @@ namespace android {
class Region;
class SurfaceFlingerSynchro;
-struct per_client_cblk_t;
-struct layer_cblk_t;
+class SharedClient;
class SurfaceComposerClient : virtual public RefBase
{
@@ -62,13 +62,13 @@ public:
// surface creation / destruction
//! Create a surface
- sp<Surface> createSurface(
- int pid, //!< pid of the process the surfacec is for
- DisplayID display, //!< Display to create this surface on
- uint32_t w, //!< width in pixel
- uint32_t h, //!< height in pixel
- PixelFormat format, //!< pixel-format desired
- uint32_t flags = 0 //!< usage flags
+ sp<SurfaceControl> createSurface(
+ int pid, // pid of the process the surface is for
+ DisplayID display, // Display to create this surface on
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ uint32_t flags = 0 // usage flags
);
// ------------------------------------------------------------------------
@@ -108,54 +108,40 @@ public:
static ssize_t getDisplayHeight(DisplayID dpy);
static ssize_t getDisplayOrientation(DisplayID dpy);
+ status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie = NULL, uint32_t flags = 0);
private:
friend class Surface;
+ friend class SurfaceControl;
SurfaceComposerClient(const sp<ISurfaceComposer>& sm,
const sp<IBinder>& conn);
- status_t hide(Surface* surface);
- status_t show(Surface* surface, int32_t layer = -1);
- status_t freeze(Surface* surface);
- status_t unfreeze(Surface* surface);
- status_t setFlags(Surface* surface, uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(Surface* surface, const Region& transparent);
- status_t setLayer(Surface* surface, int32_t layer);
- status_t setAlpha(Surface* surface, float alpha=1.0f);
- status_t setFreezeTint(Surface* surface, uint32_t tint);
- status_t setMatrix(Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy);
- status_t setPosition(Surface* surface, int32_t x, int32_t y);
- status_t setSize(Surface* surface, uint32_t w, uint32_t h);
+ status_t hide(SurfaceID id);
+ status_t show(SurfaceID id, int32_t layer = -1);
+ status_t freeze(SurfaceID id);
+ status_t unfreeze(SurfaceID id);
+ status_t setFlags(SurfaceID id, uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(SurfaceID id, const Region& transparent);
+ status_t setLayer(SurfaceID id, int32_t layer);
+ status_t setAlpha(SurfaceID id, float alpha=1.0f);
+ status_t setFreezeTint(SurfaceID id, uint32_t tint);
+ status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setPosition(SurfaceID id, int32_t x, int32_t y);
+ status_t setSize(SurfaceID id, uint32_t w, uint32_t h);
- //! Unlock the surface, and specify the dirty region if any
- status_t unlockAndPostSurface(Surface* surface);
- status_t unlockSurface(Surface* surface);
-
- status_t lockSurface(Surface* surface,
- Surface::SurfaceInfo* info,
- Region* dirty,
- bool blocking = true);
-
- status_t nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info);
+ void signalServer();
status_t destroySurface(SurfaceID sid);
void _init(const sp<ISurfaceComposer>& sm,
const sp<ISurfaceFlingerClient>& conn);
- void _signal_server();
- static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
- inline layer_state_t* _get_state_l(const sp<Surface>& surface);
- layer_state_t* _lockLayerState(const sp<Surface>& surface);
+ inline layer_state_t* _get_state_l(SurfaceID id);
+ layer_state_t* _lockLayerState(SurfaceID id);
inline void _unlockLayerState();
- status_t validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface);
-
- void pinHeap(const sp<IMemoryHeap>& heap);
-
mutable Mutex mLock;
layer_state_t* mPrebuiltLayerState;
SortedVector<layer_state_t> mStates;
@@ -164,13 +150,10 @@ private:
// these don't need to be protected because they never change
// after assignment
status_t mStatus;
- per_client_cblk_t* mControl;
- sp<IMemory> mControlMemory;
+ SharedClient* mControl;
+ sp<IMemoryHeap> mControlMemory;
sp<ISurfaceFlingerClient> mClient;
- sp<IMemoryHeap> mSurfaceHeap;
- uint8_t* mSurfaceHeapBase;
- void* mGL;
- SurfaceFlingerSynchro* mSignalServer;
+ sp<ISurfaceComposer> mSignalServer;
};
}; // namespace android
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
new file mode 100644
index 0000000..9c92af8
--- /dev/null
+++ b/include/ui/android_native_buffer.h
@@ -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.
+ */
+
+#ifndef ANDROID_ANDROID_NATIVES_PRIV_H
+#define ANDROID_ANDROID_NATIVES_PRIV_H
+
+#include <ui/egl/android_natives.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+typedef struct android_native_buffer_t
+{
+#ifdef __cplusplus
+ android_native_buffer_t() {
+ common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ common.version = sizeof(android_native_buffer_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ int width;
+ int height;
+ int stride;
+ int format;
+ int usage;
+
+ void* reserved[2];
+
+ buffer_handle_t handle;
+
+ void* reserved_proc[8];
+} android_native_buffer_t;
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
new file mode 100644
index 0000000..3740db5
--- /dev/null
+++ b/include/ui/egl/android_natives.h
@@ -0,0 +1,263 @@
+/*
+ * 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_ANDROID_NATIVES_H
+#define ANDROID_ANDROID_NATIVES_H
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <hardware/gralloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+ (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
+
+#define ANDROID_NATIVE_WINDOW_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+#define ANDROID_NATIVE_BUFFER_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+// ---------------------------------------------------------------------------
+
+struct android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_base_t
+{
+ /* a magic value defined by the actual EGL native type */
+ int magic;
+
+ /* the sizeof() of the actual EGL native type */
+ int version;
+
+ void* reserved[4];
+
+ /* reference-counting interface */
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+ NATIVE_WINDOW_WIDTH = 0,
+ NATIVE_WINDOW_HEIGHT = 1,
+ NATIVE_WINDOW_FORMAT = 2,
+};
+
+/* valid operations for the (*perform)() hook */
+enum {
+ NATIVE_WINDOW_SET_USAGE = 0
+};
+
+typedef struct android_native_window_t
+{
+#ifdef __cplusplus
+ android_native_window_t()
+ : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+ {
+ common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+ common.version = sizeof(android_native_window_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ /* flags describing some attributes of this surface or its updater */
+ const uint32_t flags;
+
+ /* min swap interval supported by this updated */
+ const int minSwapInterval;
+
+ /* max swap interval supported by this updated */
+ const int maxSwapInterval;
+
+ /* horizontal and vertical resolution in DPI */
+ const float xdpi;
+ const float ydpi;
+
+ /* Some storage reserved for the OEM's driver. */
+ intptr_t oem[4];
+
+
+ /*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*setSwapInterval)(struct android_native_window_t* window,
+ int interval);
+
+ /*
+ * hook called by EGL to acquire a buffer. After this call, the buffer
+ * is not locked, so its content cannot be modified.
+ * this call may block if no buffers are available.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*dequeueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t** buffer);
+
+ /*
+ * hook called by EGL to lock a buffer. This MUST be called before modifying
+ * the content of a buffer. The buffer must have been acquired with
+ * dequeueBuffer first.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*lockBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t* buffer);
+ /*
+ * hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * Buffers MUST be queued in the same order than they were dequeued.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*queueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t* buffer);
+
+ /*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*query)(struct android_native_window_t* window,
+ int what, int* value);
+
+ /*
+ * hook used to perform various operations on the surface.
+ * (*perform)() is a generic mechanism to add functionality to
+ * android_native_window_t while keeping backward binary compatibility.
+ *
+ * This hook should not be called directly, instead use the helper functions
+ * defined below.
+ *
+ * The valid operations are:
+ * NATIVE_WINDOW_SET_USAGE
+ *
+ */
+
+ int (*perform)(struct android_native_window_t* window,
+ int operation, ... );
+
+ void* reserved_proc[3];
+} android_native_window_t;
+
+
+/*
+ * native_window_set_usage() sets the intended usage flags for the next
+ * buffers acquired with (*lockBuffer)() and on.
+ * By default (if this function is never called), a usage of
+ * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ * is assumed.
+ * Calling this function will usually cause following buffers to be
+ * reallocated.
+ */
+
+static inline int native_window_set_usage(
+ android_native_window_t* window, int usage)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+
+// ---------------------------------------------------------------------------
+
+/* FIXME: this is legacy for pixmaps */
+typedef struct egl_native_pixmap_t
+{
+ int32_t version; /* must be 32 */
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t* data;
+ uint8_t format;
+ uint8_t rfu[3];
+ union {
+ uint32_t compressedFormat;
+ int32_t vstride;
+ };
+ int32_t reserved;
+} egl_native_pixmap_t;
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/*
+ * This helper class turns an EGL android_native_xxx type into a C++
+ * reference-counted object; with proper type conversions.
+ */
+template <typename NATIVE_TYPE, typename TYPE, typename REF>
+class EGLNativeBase : public NATIVE_TYPE, public REF
+{
+protected:
+ typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE;
+ EGLNativeBase() : NATIVE_TYPE(), REF() {
+ NATIVE_TYPE::common.incRef = incRef;
+ NATIVE_TYPE::common.decRef = decRef;
+ }
+ static inline TYPE* getSelf(NATIVE_TYPE* self) {
+ return static_cast<TYPE*>(self);
+ }
+ static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
+ return static_cast<TYPE const *>(self);
+ }
+ static inline TYPE* getSelf(android_native_base_t* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));
+ }
+ static inline TYPE const * getSelf(android_native_base_t const* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));
+ }
+ static void incRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->incStrong(self);
+ }
+ static void decRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->decStrong(self);
+ }
+};
+
+} // namespace android
+#endif // __cplusplus
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_H */
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
index a662b9c..d9ed32d 100644
--- a/include/utils/Debug.h
+++ b/include/utils/Debug.h
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-//
-// Debugging tools. These should be able to be stripped
-// in release builds.
-//
#ifndef ANDROID_DEBUG_H
#define ANDROID_DEBUG_H
@@ -25,9 +21,32 @@
#include <sys/types.h>
namespace android {
+// ---------------------------------------------------------------------------
+#ifdef __cplusplus
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
+#define COMPILE_TIME_ASSERT(_exp) \
+ template class CompileTimeAssert< (_exp) >;
+#endif
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
+ CompileTimeAssert<( _exp )>();
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+template<bool C, typename LSH, typename RHS> struct CompileTimeIfElse;
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<true, LHS, RHS> { typedef LHS TYPE; };
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; };
+#endif
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
const char* stringForIndent(int32_t indentLevel);
@@ -35,11 +54,17 @@ typedef void (*debugPrintFunc)(void* cookie, const char* txt);
void printTypeCode(uint32_t typeCode,
debugPrintFunc func = 0, void* cookie = 0);
+
void printHexData(int32_t indent, const void *buf, size_t length,
size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
size_t alignment=0, bool cArrayStyle=false,
debugPrintFunc func = 0, void* cookie = 0);
+#ifdef __cplusplus
+}
+#endif
+
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_DEBUG_H
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
index 1bf9e6f..81f818b 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -63,7 +63,7 @@ enum {
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
WOULD_BLOCK = -EWOULDBLOCK,
- TIMED_OUT = -ETIME,
+ TIMED_OUT = -ETIMEDOUT,
UNKNOWN_TRANSACTION = -EBADMSG,
#else
BAD_INDEX = -E2BIG,
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index f4513ee..6bcdea4 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -164,7 +164,7 @@ ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& val
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
if (index<size()) {
- mVector.editValueAt(index).value = item;
+ mVector.editItemAt(index).value = item;
return index;
}
return BAD_INDEX;
diff --git a/include/utils/List.h b/include/utils/List.h
index 1a6be9a..403cd7f 100644
--- a/include/utils/List.h
+++ b/include/utils/List.h
@@ -22,147 +22,200 @@
// construction, so if the compiler's auto-generated versions won't work for
// you, define your own.
//
-// The only class you want to use from here is "List". Do not use classes
-// starting with "_" directly.
+// The only class you want to use from here is "List".
//
#ifndef _LIBS_UTILS_LIST_H
#define _LIBS_UTILS_LIST_H
-namespace android {
-
-/*
- * One element in the list.
- */
-template<class T> class _ListNode {
-public:
- typedef _ListNode<T> _Node;
-
- _ListNode(const T& val) : mVal(val) {}
- ~_ListNode(void) {}
-
- T& getRef(void) { return mVal; }
- void setVal(const T& val) { mVal = val; }
+#include <stddef.h>
+#include <stdint.h>
- _Node* getPrev(void) const { return mpPrev; }
- void setPrev(_Node* ptr) { mpPrev = ptr; }
- _Node* getNext(void) const { return mpNext; }
- void setNext(_Node* ptr) { mpNext = ptr; }
-
-private:
- T mVal;
- _Node* mpPrev;
- _Node* mpNext;
-};
+namespace android {
/*
- * Iterator for walking through the list.
+ * Doubly-linked list. Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
*/
-template<class T, class Tref> class _ListIterator {
-public:
- typedef _ListIterator<T,Tref> _Iter;
- typedef _ListNode<T> _Node;
-
- _ListIterator(void) {}
- _ListIterator(_Node* ptr) : mpNode(ptr) {}
- ~_ListIterator(void) {}
-
- /*
- * Dereference operator. Used to get at the juicy insides.
- */
- Tref operator*() const { return mpNode->getRef(); }
-
+template<typename T>
+class List
+{
+protected:
/*
- * Iterator comparison.
+ * One element in the list.
*/
- bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
- bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
+ class _Node {
+ public:
+ explicit _Node(const T& val) : mVal(val) {}
+ ~_Node() {}
+ inline T& getRef() { return mVal; }
+ inline const T& getRef() const { return mVal; }
+ inline _Node* getPrev() const { return mpPrev; }
+ inline _Node* getNext() const { return mpNext; }
+ inline void setVal(const T& val) { mVal = val; }
+ inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+ inline void setNext(_Node* ptr) { mpNext = ptr; }
+ private:
+ friend class List;
+ friend class _ListIterator;
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+ };
/*
- * Incr/decr, used to move through the list.
+ * Iterator for walking through the list.
*/
- _Iter& operator++(void) { // pre-increment
- mpNode = mpNode->getNext();
- return *this;
- }
- _Iter operator++(int) { // post-increment
- _Iter tmp = *this;
- ++*this;
- return tmp;
- }
- _Iter& operator--(void) { // pre-increment
- mpNode = mpNode->getPrev();
- return *this;
- }
- _Iter operator--(int) { // post-increment
- _Iter tmp = *this;
- --*this;
- return tmp;
- }
+
+ template <typename TYPE>
+ struct CONST_ITERATOR {
+ typedef _Node const * NodePtr;
+ typedef const TYPE Type;
+ };
+
+ template <typename TYPE>
+ struct NON_CONST_ITERATOR {
+ typedef _Node* NodePtr;
+ typedef TYPE Type;
+ };
+
+ template<
+ typename U,
+ template <class> class Constness
+ >
+ class _ListIterator {
+ typedef _ListIterator<U, Constness> _Iter;
+ typedef typename Constness<U>::NodePtr _NodePtr;
+ typedef typename Constness<U>::Type _Type;
+
+ explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+ public:
+ _ListIterator() {}
+ _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+ ~_ListIterator() {}
+
+ // this will handle conversions from iterator to const_iterator
+ // (and also all convertible iterators)
+ // Here, in this implementation, the iterators can be converted
+ // if the nodes can be converted
+ template<typename V> explicit
+ _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ _Type& operator*() const { return mpNode->getRef(); }
+ _Type* operator->() const { return &(mpNode->getRef()); }
+
+ /*
+ * Iterator comparison.
+ */
+ inline bool operator==(const _Iter& right) const {
+ return mpNode == right.mpNode; }
+
+ inline bool operator!=(const _Iter& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * handle comparisons between iterator and const_iterator
+ */
+ template<typename OTHER>
+ inline bool operator==(const OTHER& right) const {
+ return mpNode == right.mpNode; }
+
+ template<typename OTHER>
+ inline bool operator!=(const OTHER& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ inline _Iter& operator++() { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ const _Iter operator++(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getNext();
+ return tmp;
+ }
+ inline _Iter& operator--() { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ const _Iter operator--(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getPrev();
+ return tmp;
+ }
- _Node* getNode(void) const { return mpNode; }
+ inline _NodePtr getNode() const { return mpNode; }
-private:
- _Node* mpNode;
-};
+ _NodePtr mpNode; /* should be private, but older gcc fails */
+ private:
+ friend class List;
+ };
-
-/*
- * Doubly-linked list. Instantiate with "List<MyClass> myList".
- *
- * Objects added to the list are copied using the assignment operator,
- * so this must be defined.
- */
-template<class T> class List {
public:
- typedef _ListNode<T> _Node;
-
- List(void) {
+ List() {
prep();
}
List(const List<T>& src) { // copy-constructor
prep();
insert(begin(), src.begin(), src.end());
}
- virtual ~List(void) {
+ virtual ~List() {
clear();
delete[] (unsigned char*) mpMiddle;
}
- typedef _ListIterator<T,T&> iterator;
- typedef _ListIterator<T, const T&> const_iterator;
+ typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+ typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
List<T>& operator=(const List<T>& right);
/* returns true if the list is empty */
- bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
+ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
/* return #of elements in list */
- unsigned int size(void) const {
- return distance(begin(), end());
+ size_t size() const {
+ return size_t(distance(begin(), end()));
}
/*
* Return the first element or one past the last element. The
- * _ListNode* we're returning is converted to an "iterator" by a
+ * _Node* we're returning is converted to an "iterator" by a
* constructor in _ListIterator.
*/
- iterator begin() { return mpMiddle->getNext(); }
- const_iterator begin() const { return mpMiddle->getNext(); }
- iterator end() { return mpMiddle; }
- const_iterator end() const { return mpMiddle; }
+ inline iterator begin() {
+ return iterator(mpMiddle->getNext());
+ }
+ inline const_iterator begin() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
+ }
+ inline iterator end() {
+ return iterator(mpMiddle);
+ }
+ inline const_iterator end() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle));
+ }
/* add the object to the head or tail of the list */
void push_front(const T& val) { insert(begin(), val); }
void push_back(const T& val) { insert(end(), val); }
/* insert before the current node; returns iterator at new node */
- iterator insert(iterator posn, const T& val) {
+ iterator insert(iterator posn, const T& val)
+ {
_Node* newNode = new _Node(val); // alloc & copy-construct
newNode->setNext(posn.getNode());
newNode->setPrev(posn.getNode()->getPrev());
posn.getNode()->getPrev()->setNext(newNode);
posn.getNode()->setPrev(newNode);
- return newNode;
+ return iterator(newNode);
}
/* insert a range of elements before the current node */
@@ -178,18 +231,18 @@ public:
pPrev->setNext(pNext);
pNext->setPrev(pPrev);
delete posn.getNode();
- return pNext;
+ return iterator(pNext);
}
/* remove a range of elements */
iterator erase(iterator first, iterator last) {
while (first != last)
erase(first++); // don't erase than incr later!
- return last;
+ return iterator(last);
}
/* remove all contents of the list */
- void clear(void) {
+ void clear() {
_Node* pCurrent = mpMiddle->getNext();
_Node* pNext;
@@ -207,21 +260,20 @@ public:
* will be equal to "last". The iterators must refer to the same
* list.
*
- * (This is actually a generic iterator function. It should be part
- * of some other class, possibly an iterator base class. It needs to
- * know the difference between a list, which has to march through,
- * and a vector, which can just do pointer math.)
+ * FIXME: This is actually a generic iterator function. It should be a
+ * template function at the top-level with specializations for things like
+ * vector<>, which can just do pointer math). Here we limit it to
+ * _ListIterator of the same type but different constness.
*/
- unsigned int distance(iterator first, iterator last) {
- unsigned int count = 0;
- while (first != last) {
- ++first;
- ++count;
- }
- return count;
- }
- unsigned int distance(const_iterator first, const_iterator last) const {
- unsigned int count = 0;
+ template<
+ typename U,
+ template <class> class CL,
+ template <class> class CR
+ >
+ ptrdiff_t distance(
+ _ListIterator<U, CL> first, _ListIterator<U, CR> last) const
+ {
+ ptrdiff_t count = 0;
while (first != last) {
++first;
++count;
@@ -231,12 +283,12 @@ public:
private:
/*
- * I want a _ListNode but don't need it to hold valid data. More
+ * I want a _Node but don't need it to hold valid data. More
* to the point, I don't want T's constructor to fire, since it
* might have side-effects or require arguments. So, we do this
* slightly uncouth storage alloc.
*/
- void prep(void) {
+ void prep() {
mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
mpMiddle->setPrev(mpMiddle);
mpMiddle->setNext(mpMiddle);
diff --git a/include/utils/LogSocket.h b/include/utils/LogSocket.h
deleted file mode 100644
index 01fbfb5..0000000
--- a/include/utils/LogSocket.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* utils/LogSocket.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGSOCKET_H
-#define _UTILS_LOGSOCKET_H
-
-#define SOCKET_CLOSE_LOCAL 0
-
-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 /* _UTILS_LOGSOCKET_H */
diff --git a/include/utils/Pipe.h b/include/utils/Pipe.h
deleted file mode 100644
index 6404168..0000000
--- a/include/utils/Pipe.h
+++ /dev/null
@@ -1,108 +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.
- */
-
-//
-// FIFO I/O.
-//
-#ifndef _LIBS_UTILS_PIPE_H
-#define _LIBS_UTILS_PIPE_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-namespace android {
-
-/*
- * Simple anonymous unidirectional pipe.
- *
- * The primary goal is to create an implementation with minimal overhead
- * under Linux. Making Windows, Mac OS X, and Linux all work the same way
- * is a secondary goal. Part of this goal is to have something that can
- * be fed to a select() call, so that the application can sleep in the
- * kernel until something interesting happens.
- */
-class Pipe {
-public:
- Pipe(void);
- virtual ~Pipe(void);
-
- /* Create the pipe */
- bool create(void);
-
- /* Create a read-only pipe, using the supplied handle as read handle */
- bool createReader(unsigned long handle);
- /* Create a write-only pipe, using the supplied handle as write handle */
- bool createWriter(unsigned long handle);
-
- /* Is this object ready to go? */
- bool isCreated(void);
-
- /*
- * Read "count" bytes from the pipe. Returns the amount of data read,
- * or 0 if no data available and we're non-blocking.
- * Returns -1 on error.
- */
- int read(void* buf, int count);
-
- /*
- * Write "count" bytes into the pipe. Returns number of bytes written,
- * or 0 if there's no room for more data and we're non-blocking.
- * Returns -1 on error.
- */
- int write(const void* buf, int count);
-
- /* Returns "true" if data is available to read */
- bool readReady(void);
-
- /* Enable or disable non-blocking I/O for reads */
- bool setReadNonBlocking(bool val);
- /* Enable or disable non-blocking I/O for writes. Only works on Linux. */
- bool setWriteNonBlocking(bool val);
-
- /*
- * Get the handle. Only useful in some platform-specific situations.
- */
- unsigned long getReadHandle(void);
- unsigned long getWriteHandle(void);
-
- /*
- * Modify inheritance, i.e. whether or not a child process will get
- * copies of the descriptors. Systems with fork+exec allow us to close
- * the descriptors before launching the child process, but Win32
- * doesn't allow it.
- */
- bool disallowReadInherit(void);
- bool disallowWriteInherit(void);
-
- /*
- * Close one side or the other. Useful in the parent after launching
- * a child process.
- */
- bool closeRead(void);
- bool closeWrite(void);
-
-private:
- bool mReadNonBlocking;
- bool mWriteNonBlocking;
-
- unsigned long mReadHandle;
- unsigned long mWriteHandle;
-};
-
-}; // android
-
-#endif // _LIBS_UTILS_PIPE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbda0fd..bd7f28c 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -156,6 +156,10 @@ public:
delete static_cast<const T*>(this);
}
}
+ //! DEBUGGING ONLY: Get current strong ref count.
+ inline int32_t getStrongCount() const {
+ return mCount;
+ }
protected:
inline ~LightRefBase() { }
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index e524e2a..49145e8 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -864,6 +864,13 @@ struct ResTable_config
KEYSHIDDEN_SOFT = 0x0003,
};
+ enum {
+ MASK_NAVHIDDEN = 0x000c,
+ NAVHIDDEN_ANY = 0x0000,
+ NAVHIDDEN_NO = 0x0004,
+ NAVHIDDEN_YES = 0x0008,
+ };
+
union {
struct {
uint8_t keyboard;
@@ -1011,7 +1018,8 @@ struct ResTable_config
if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
if (density != o.density) diffs |= CONFIG_DENSITY;
if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
- if (((inputFlags^o.inputFlags)&MASK_KEYSHIDDEN) != 0) diffs |= CONFIG_KEYBOARD_HIDDEN;
+ if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
+ diffs |= CONFIG_KEYBOARD_HIDDEN;
if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
@@ -1082,6 +1090,11 @@ struct ResTable_config
if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
}
+ if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
+ if (!(inputFlags & MASK_NAVHIDDEN)) return false;
+ if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
+ }
+
if (keyboard != o.keyboard) {
if (!keyboard) return false;
if (!o.keyboard) return true;
@@ -1225,6 +1238,18 @@ struct ResTable_config
}
}
+ const int navHidden = inputFlags & MASK_NAVHIDDEN;
+ const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
+ if (navHidden != oNavHidden) {
+ const int reqNavHidden =
+ requested->inputFlags & MASK_NAVHIDDEN;
+ if (reqNavHidden) {
+
+ if (!navHidden) return false;
+ if (!oNavHidden) return true;
+ }
+ }
+
if ((keyboard != o.keyboard) && requested->keyboard) {
return (keyboard);
}
@@ -1247,7 +1272,7 @@ struct ResTable_config
if (version || o.version) {
if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
- return (sdkVersion);
+ return (sdkVersion > o.sdkVersion);
}
if ((minorVersion != o.minorVersion) &&
@@ -1332,6 +1357,12 @@ struct ResTable_config
return false;
}
}
+ const int navHidden = inputFlags&MASK_NAVHIDDEN;
+ const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
+ if (setNavHidden != 0 && navHidden != 0
+ && navHidden != setNavHidden) {
+ return false;
+ }
if (settings.keyboard != 0 && keyboard != 0
&& keyboard != settings.keyboard) {
return false;
@@ -1353,7 +1384,7 @@ struct ResTable_config
}
if (version != 0) {
if (settings.sdkVersion != 0 && sdkVersion != 0
- && sdkVersion != settings.sdkVersion) {
+ && sdkVersion > settings.sdkVersion) {
return false;
}
if (settings.minorVersion != 0 && minorVersion != 0
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
new file mode 100644
index 0000000..bc7626a
--- /dev/null
+++ b/include/utils/Singleton.h
@@ -0,0 +1,69 @@
+/*
+ * 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_UTILS_SINGLETON_H
+#define ANDROID_UTILS_SINGLETON_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <typename TYPE>
+class Singleton
+{
+public:
+ static TYPE& getInstance() {
+ Mutex::Autolock _l(sLock);
+ TYPE* instance = sInstance;
+ if (instance == 0) {
+ instance = new TYPE();
+ sInstance = instance;
+ }
+ return *instance;
+ }
+
+protected:
+ ~Singleton() { };
+ Singleton() { };
+
+private:
+ Singleton(const Singleton&);
+ Singleton& operator = (const Singleton&);
+ static Mutex sLock;
+ static TYPE* sInstance;
+};
+
+/*
+ * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
+ * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
+ * and avoid to have a copy of them in each compilation units Singleton<TYPE>
+ * is used.
+ */
+
+#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
+ template class Singleton< TYPE >; \
+ template< class TYPE > Mutex Singleton< TYPE >::sLock; \
+ template<> TYPE* Singleton< TYPE >::sInstance(0);
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UTILS_SINGLETON_H
+
diff --git a/include/utils/Socket.h b/include/utils/Socket.h
deleted file mode 100644
index 8b7f406..0000000
--- a/include/utils/Socket.h
+++ /dev/null
@@ -1,80 +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.
- */
-
-//
-// Socket class. Modeled after Java classes.
-//
-#ifndef _RUNTIME_SOCKET_H
-#define _RUNTIME_SOCKET_H
-
-#include <utils/inet_address.h>
-#include <sys/types.h>
-
-namespace android {
-
-/*
- * Basic socket class, needed to abstract away the differences between
- * BSD sockets and WinSock. This establishes a streaming network
- * connection (TCP/IP) to somebody.
- */
-class Socket {
-public:
- Socket(void);
- ~Socket(void);
-
- // Create a connection to somewhere.
- // Return 0 on success.
- int connect(const char* host, int port);
- int connect(const InetAddress* addr, int port);
-
-
- // Close the socket. Don't try to use this object again after
- // calling this. Returns false on failure.
- bool close(void);
-
- // If we created the socket without an address, we can use these
- // to finish the connection. Returns 0 on success.
- int bind(const SocketAddress& bindPoint);
- int connect(const SocketAddress& endPoint);
-
- // Here we deviate from the traditional object-oriented fanciness
- // and just provide read/write operators instead of getters for
- // objects that abstract a stream.
- //
- // Standard read/write semantics.
- int read(void* buf, ssize_t len) const;
- int write(const void* buf, ssize_t len) const;
-
- // This must be called once, at program startup.
- static bool bootInit(void);
- static void finalShutdown(void);
-
-private:
- // Internal function that establishes a connection.
- int doConnect(const InetSocketAddress& addr);
-
- unsigned long mSock; // holds SOCKET or int
-
- static bool mBootInitialized;
-};
-
-
-// debug -- unit tests
-void TestSockets(void);
-
-}; // namespace android
-
-#endif // _RUNTIME_SOCKET_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index c8a6153..8beec57 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -141,8 +141,7 @@ SortedVector<TYPE>::SortedVector()
: SortedVectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
diff --git a/include/utils/StringArray.h b/include/utils/StringArray.h
new file mode 100644
index 0000000..c244587
--- /dev/null
+++ b/include/utils/StringArray.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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+#ifndef _LIBS_UTILS_STRING_ARRAY_H
+#define _LIBS_UTILS_STRING_ARRAY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+class StringArray {
+public:
+ StringArray();
+ virtual ~StringArray();
+
+ //
+ // Add a string. A copy of the string is made.
+ //
+ bool push_back(const char* str);
+
+ //
+ // Delete an entry.
+ //
+ void erase(int idx);
+
+ //
+ // Sort the array.
+ //
+ void sort(int (*compare)(const void*, const void*));
+
+ //
+ // Pass this to the sort routine to do an ascending alphabetical sort.
+ //
+ static int cmpAscendingAlpha(const void* pstr1, const void* pstr2);
+
+ //
+ // Get the #of items in the array.
+ //
+ inline int size(void) const { return mCurrent; }
+
+ //
+ // Return entry N.
+ // [should use operator[] here]
+ //
+ const char* getEntry(int idx) const {
+ return (unsigned(idx) >= unsigned(mCurrent)) ? NULL : mArray[idx];
+ }
+
+ //
+ // Set entry N to specified string.
+ // [should use operator[] here]
+ //
+ void setEntry(int idx, const char* str);
+
+private:
+ int mMax;
+ int mCurrent;
+ char** mArray;
+};
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/TextOutput.h b/include/utils/TextOutput.h
index d8d86ba..de2fbbe 100644
--- a/include/utils/TextOutput.h
+++ b/include/utils/TextOutput.h
@@ -28,8 +28,8 @@ namespace android {
class TextOutput
{
public:
- TextOutput() { }
- virtual ~TextOutput() { }
+ TextOutput();
+ virtual ~TextOutput();
virtual status_t print(const char* txt, size_t len) = 0;
virtual void moveIndent(int delta) = 0;
diff --git a/include/utils/TimerProbe.h b/include/utils/TimerProbe.h
deleted file mode 100644
index f2e32b2..0000000
--- a/include/utils/TimerProbe.h
+++ /dev/null
@@ -1,72 +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_TIMER_PROBE_H
-#define ANDROID_TIMER_PROBE_H
-
-#if 0 && defined(HAVE_POSIX_CLOCKS)
-#define ENABLE_TIMER_PROBE 1
-#else
-#define ENABLE_TIMER_PROBE 0
-#endif
-
-#if ENABLE_TIMER_PROBE
-
-#include <time.h>
-#include <sys/time.h>
-#include <utils/Vector.h>
-
-#define TIMER_PROBE(tag) \
- static int _timer_slot_; \
- android::TimerProbe probe(tag, &_timer_slot_)
-#define TIMER_PROBE_END() probe.end()
-#else
-#define TIMER_PROBE(tag)
-#define TIMER_PROBE_END()
-#endif
-
-#if ENABLE_TIMER_PROBE
-namespace android {
-
-class TimerProbe {
-public:
- TimerProbe(const char tag[], int* slot);
- void end();
- ~TimerProbe();
-private:
- struct Bucket {
- int mStart, mReal, mProcess, mThread, mCount;
- const char* mTag;
- int* mSlotPtr;
- int mIndent;
- };
- static Vector<Bucket> gBuckets;
- static TimerProbe* gExecuteChain;
- static int gIndent;
- static timespec gRealBase;
- TimerProbe* mNext;
- static uint32_t ElapsedTime(const timespec& start, const timespec& end);
- void print(const timespec& r, const timespec& p, const timespec& t) const;
- timespec mRealStart, mPStart, mTStart;
- const char* mTag;
- int mIndent;
- int mBucket;
-};
-
-}; // namespace android
-
-#endif
-#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9610399..9a9e07c 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,9 +88,6 @@ nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
nsecs_t systemTime(int clock);
#endif // def __cplusplus
-// return the system-time according to the specified clock
-int sleepForInterval(long interval, struct timeval* pNextTick);
-
#ifdef __cplusplus
} // extern "C"
#endif
@@ -108,15 +105,15 @@ namespace android {
*/
class DurationTimer {
public:
- DurationTimer(void) {}
- ~DurationTimer(void) {}
+ DurationTimer() {}
+ ~DurationTimer() {}
// Start the timer.
- void start(void);
+ void start();
// Stop the timer.
- void stop(void);
+ void stop();
// Get the duration in microseconds.
- long long durationUsecs(void) const;
+ long long durationUsecs() const;
// Subtract two timevals. Returns the difference (ptv1-ptv2) in
// microseconds.
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index c04c37f..2ff2749 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -29,35 +29,39 @@ namespace android {
/*
* Types traits
*/
-
-template <typename T> struct trait_trivial_ctor { enum { value = false }; };
-template <typename T> struct trait_trivial_dtor { enum { value = false }; };
-template <typename T> struct trait_trivial_copy { enum { value = false }; };
-template <typename T> struct trait_trivial_assign{ enum { value = false }; };
-
-template <typename T> struct trait_pointer { enum { value = false }; };
-template <typename T> struct trait_pointer<T*> { enum { value = true }; };
-
-#define ANDROID_BASIC_TYPES_TRAITS( T ) \
- template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = true }; };
-
-#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
- template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
+
+template <typename T> struct trait_trivial_ctor { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor { enum { value = false }; };
+template <typename T> struct trait_trivial_copy { enum { value = false }; };
+template <typename T> struct trait_trivial_move { enum { value = false }; };
+template <typename T> struct trait_pointer { enum { value = false }; };
+template <typename T> struct trait_pointer<T*> { enum { value = true }; };
+
+// sp<> can be trivially moved
+template <typename T> class sp;
+template <typename T> struct trait_trivial_move< sp<T> >{
+ enum { value = true };
+};
+
+// wp<> can be trivially moved
+template <typename T> class wp;
+template <typename T> struct trait_trivial_move< wp<T> >{
+ enum { value = true };
+};
template <typename TYPE>
struct traits {
enum {
+ // whether this type is a pointer
is_pointer = trait_pointer<TYPE>::value,
+ // whether this type's constructor is a no-op
has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
+ // whether this type's destructor is a no-op
has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
+ // whether this type type can be copy-constructed with memcpy
has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
- has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
+ // whether this type can be moved with memmove
+ has_trivial_move = is_pointer || trait_trivial_move<TYPE>::value
};
};
@@ -65,37 +69,47 @@ template <typename T, typename U>
struct aggregate_traits {
enum {
is_pointer = false,
- has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
- has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
- has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
- has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
+ has_trivial_ctor =
+ traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+ has_trivial_dtor =
+ traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+ has_trivial_copy =
+ traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+ has_trivial_move =
+ traits<T>::has_trivial_move && traits<U>::has_trivial_move
};
};
+#define ANDROID_BASIC_TYPES_TRAITS( T ) \
+ template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_move< T > { enum { value = true }; };
+
// ---------------------------------------------------------------------------
/*
* basic types traits
*/
-
-ANDROID_BASIC_TYPES_TRAITS( void );
-ANDROID_BASIC_TYPES_TRAITS( bool );
-ANDROID_BASIC_TYPES_TRAITS( char );
-ANDROID_BASIC_TYPES_TRAITS( unsigned char );
-ANDROID_BASIC_TYPES_TRAITS( short );
-ANDROID_BASIC_TYPES_TRAITS( unsigned short );
-ANDROID_BASIC_TYPES_TRAITS( int );
-ANDROID_BASIC_TYPES_TRAITS( unsigned int );
-ANDROID_BASIC_TYPES_TRAITS( long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long );
-ANDROID_BASIC_TYPES_TRAITS( long long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
-ANDROID_BASIC_TYPES_TRAITS( float );
-ANDROID_BASIC_TYPES_TRAITS( double );
+
+ANDROID_BASIC_TYPES_TRAITS( void )
+ANDROID_BASIC_TYPES_TRAITS( bool )
+ANDROID_BASIC_TYPES_TRAITS( char )
+ANDROID_BASIC_TYPES_TRAITS( unsigned char )
+ANDROID_BASIC_TYPES_TRAITS( short )
+ANDROID_BASIC_TYPES_TRAITS( unsigned short )
+ANDROID_BASIC_TYPES_TRAITS( int )
+ANDROID_BASIC_TYPES_TRAITS( unsigned int )
+ANDROID_BASIC_TYPES_TRAITS( long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long )
+ANDROID_BASIC_TYPES_TRAITS( long long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
+ANDROID_BASIC_TYPES_TRAITS( float )
+ANDROID_BASIC_TYPES_TRAITS( double )
// ---------------------------------------------------------------------------
-
+
/*
* compare and order types
*/
@@ -111,9 +125,9 @@ int compare_type(const TYPE& lhs, const TYPE& rhs) {
}
/*
- * create, destroy, copy and assign types...
+ * create, destroy, copy and move types...
*/
-
+
template<typename TYPE> inline
void construct_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_ctor) {
@@ -146,17 +160,6 @@ void copy_type(TYPE* d, const TYPE* s, size_t n) {
}
template<typename TYPE> inline
-void assign_type(TYPE* d, const TYPE* s, size_t n) {
- if (!traits<TYPE>::has_trivial_assign) {
- while (n--) {
- *d++ = *s++;
- }
- } else {
- memcpy(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
void splat_type(TYPE* where, const TYPE* what, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
while (n--) {
@@ -164,15 +167,19 @@ void splat_type(TYPE* where, const TYPE* what, size_t n) {
where++;
}
} else {
- while (n--) {
- *where++ = *what;
+ while (n--) {
+ *where++ = *what;
}
}
}
template<typename TYPE> inline
void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
d += n;
s += n;
while (n--) {
@@ -180,35 +187,37 @@ void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
template<typename TYPE> inline
void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
while (n--) {
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
d++, s++;
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
+
+
// ---------------------------------------------------------------------------
/*
@@ -242,8 +251,8 @@ struct trait_trivial_copy< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
template<>
template <typename K, typename V>
-struct trait_trivial_assign< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
+struct trait_trivial_move< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_move }; };
// ---------------------------------------------------------------------------
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index be365d8..ad59fd6 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -175,8 +175,7 @@ Vector<TYPE>::Vector()
: VectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index 2525229..49b03f1 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -44,7 +44,6 @@ public:
HAS_TRIVIAL_CTOR = 0x00000001,
HAS_TRIVIAL_DTOR = 0x00000002,
HAS_TRIVIAL_COPY = 0x00000004,
- HAS_TRIVIAL_ASSIGN = 0x00000008
};
VectorImpl(size_t itemSize, uint32_t flags);
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
deleted file mode 100644
index e4698df..0000000
--- a/include/utils/ZipEntry.h
+++ /dev/null
@@ -1,345 +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.
- */
-
-//
-// Zip archive entries.
-//
-// The ZipEntry class is tightly meshed with the ZipFile class.
-//
-#ifndef __LIBS_ZIPENTRY_H
-#define __LIBS_ZIPENTRY_H
-
-#include "Errors.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-namespace android {
-
-class ZipFile;
-
-/*
- * ZipEntry objects represent a single entry in a Zip archive.
- *
- * You can use one of these to get or set information about an entry, but
- * there are no functions here for accessing the data itself. (We could
- * tuck a pointer to the ZipFile in here for convenience, but that raises
- * the likelihood of using ZipEntry objects after discarding the ZipFile.)
- *
- * File information is stored in two places: next to the file data (the Local
- * File Header, and possibly a Data Descriptor), and at the end of the file
- * (the Central Directory Entry). The two must be kept in sync.
- */
-class ZipEntry {
-public:
- friend class ZipFile;
-
- ZipEntry(void)
- : mDeleted(false), mMarked(false)
- {}
- ~ZipEntry(void) {}
-
- /*
- * Returns "true" if the data is compressed.
- */
- bool isCompressed(void) const {
- return mCDE.mCompressionMethod != kCompressStored;
- }
- int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
-
- /*
- * Return the uncompressed length.
- */
- off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
-
- /*
- * Return the compressed length. For uncompressed data, this returns
- * the same thing as getUncompresesdLen().
- */
- off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
-
- /*
- * Return the absolute file offset of the start of the compressed or
- * uncompressed data.
- */
- off_t getFileOffset(void) const {
- return mCDE.mLocalHeaderRelOffset +
- LocalFileHeader::kLFHLen +
- mLFH.mFileNameLength +
- mLFH.mExtraFieldLength;
- }
-
- /*
- * Return the data CRC.
- */
- unsigned long getCRC32(void) const { return mCDE.mCRC32; }
-
- /*
- * Return file modification time in UNIX seconds-since-epoch.
- */
- time_t getModWhen(void) const;
-
- /*
- * Return the archived file name.
- */
- const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
-
- /*
- * Application-defined "mark". Can be useful when synchronizing the
- * contents of an archive with contents on disk.
- */
- bool getMarked(void) const { return mMarked; }
- void setMarked(bool val) { mMarked = val; }
-
- /*
- * Some basic functions for raw data manipulation. "LE" means
- * Little Endian.
- */
- static inline unsigned short getShortLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8);
- }
- static inline unsigned long getLongLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
- }
- static inline void putShortLE(unsigned char* buf, short val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- }
- static inline void putLongLE(unsigned char* buf, long val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- buf[2] = (unsigned char) (val >> 16);
- buf[3] = (unsigned char) (val >> 24);
- }
-
- /* defined for Zip archives */
- enum {
- kCompressStored = 0, // no compression
- // shrunk = 1,
- // reduced 1 = 2,
- // reduced 2 = 3,
- // reduced 3 = 4,
- // reduced 4 = 5,
- // imploded = 6,
- // tokenized = 7,
- kCompressDeflated = 8, // standard deflate
- // Deflate64 = 9,
- // lib imploded = 10,
- // reserved = 11,
- // bzip2 = 12,
- };
-
- /*
- * Deletion flag. If set, the entry will be removed on the next
- * call to "flush".
- */
- bool getDeleted(void) const { return mDeleted; }
-
-protected:
- /*
- * Initialize the structure from the file, which is pointing at
- * our Central Directory entry.
- */
- status_t initFromCDE(FILE* fp);
-
- /*
- * Initialize the structure for a new file. We need the filename
- * and comment so that we can properly size the LFH area. The
- * filename is mandatory, the comment is optional.
- */
- void initNew(const char* fileName, const char* comment);
-
- /*
- * Initialize the structure with the contents of a ZipEntry from
- * another file.
- */
- status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
-
- /*
- * Add some pad bytes to the LFH. We do this by adding or resizing
- * the "extra" field.
- */
- status_t addPadding(int padding);
-
- /*
- * Set information about the data for this entry.
- */
- void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod);
-
- /*
- * Set the modification date.
- */
- void setModWhen(time_t when);
-
- /*
- * Return the offset of the local file header.
- */
- off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
-
- /*
- * Set the offset of the local file header, relative to the start of
- * the current file.
- */
- void setLFHOffset(off_t offset) {
- mCDE.mLocalHeaderRelOffset = (long) offset;
- }
-
- /* mark for deletion; used by ZipFile::remove() */
- void setDeleted(void) { mDeleted = true; }
-
-private:
- /* these are private and not defined */
- ZipEntry(const ZipEntry& src);
- ZipEntry& operator=(const ZipEntry& src);
-
- /* returns "true" if the CDE and the LFH agree */
- bool compareHeaders(void) const;
- void copyCDEtoLFH(void);
-
- bool mDeleted; // set if entry is pending deletion
- bool mMarked; // app-defined marker
-
- /*
- * Every entry in the Zip archive starts off with one of these.
- */
- class LocalFileHeader {
- public:
- LocalFileHeader(void) :
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileName(NULL),
- mExtraField(NULL)
- {}
- virtual ~LocalFileHeader(void) {
- delete[] mFileName;
- delete[] mExtraField;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned char* mFileName;
- unsigned char* mExtraField;
-
- enum {
- kSignature = 0x04034b50,
- kLFHLen = 30, // LocalFileHdr len, excl. var fields
- };
-
- void dump(void) const;
- };
-
- /*
- * Every entry in the Zip archive has one of these in the "central
- * directory" at the end of the file.
- */
- class CentralDirEntry {
- public:
- CentralDirEntry(void) :
- mVersionMadeBy(0),
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileCommentLength(0),
- mDiskNumberStart(0),
- mInternalAttrs(0),
- mExternalAttrs(0),
- mLocalHeaderRelOffset(0),
- mFileName(NULL),
- mExtraField(NULL),
- mFileComment(NULL)
- {}
- virtual ~CentralDirEntry(void) {
- delete[] mFileName;
- delete[] mExtraField;
- delete[] mFileComment;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionMadeBy;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned short mFileCommentLength;
- unsigned short mDiskNumberStart;
- unsigned short mInternalAttrs;
- unsigned long mExternalAttrs;
- unsigned long mLocalHeaderRelOffset;
- unsigned char* mFileName;
- unsigned char* mExtraField;
- unsigned char* mFileComment;
-
- void dump(void) const;
-
- enum {
- kSignature = 0x02014b50,
- kCDELen = 46, // CentralDirEnt len, excl. var fields
- };
- };
-
- enum {
- //kDataDescriptorSignature = 0x08074b50, // currently unused
- kDataDescriptorLen = 16, // four 32-bit fields
-
- kDefaultVersion = 20, // need deflate, nothing much else
- kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
- kUsesDataDescr = 0x0008, // GPBitFlag bit 3
- };
-
- LocalFileHeader mLFH;
- CentralDirEntry mCDE;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
deleted file mode 100644
index 44df5bb..0000000
--- a/include/utils/ZipFile.h
+++ /dev/null
@@ -1,269 +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.
- */
-
-//
-// General-purpose Zip archive access. This class allows both reading and
-// writing to Zip archives, including deletion of existing entries.
-//
-#ifndef __LIBS_ZIPFILE_H
-#define __LIBS_ZIPFILE_H
-
-#include "ZipEntry.h"
-#include "Vector.h"
-#include "Errors.h"
-#include <stdio.h>
-
-namespace android {
-
-/*
- * Manipulate a Zip archive.
- *
- * Some changes will not be visible in the until until "flush" is called.
- *
- * The correct way to update a file archive is to make all changes to a
- * copy of the archive in a temporary file, and then unlink/rename over
- * the original after everything completes. Because we're only interested
- * in using this for packaging, we don't worry about such things. Crashing
- * after making changes and before flush() completes could leave us with
- * an unusable Zip archive.
- */
-class ZipFile {
-public:
- ZipFile(void)
- : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
- {}
- ~ZipFile(void) {
- if (!mReadOnly)
- flush();
- if (mZipFp != NULL)
- fclose(mZipFp);
- discardEntries();
- }
-
- /*
- * Open a new or existing archive.
- */
- typedef enum {
- kOpenReadOnly = 0x01,
- kOpenReadWrite = 0x02,
- kOpenCreate = 0x04, // create if it doesn't exist
- kOpenTruncate = 0x08, // if it exists, empty it
- };
- status_t open(const char* zipFileName, int flags);
-
- /*
- * Add a file to the end of the archive. Specify whether you want the
- * library to try to store it compressed.
- *
- * If "storageName" is specified, the archive will use that instead
- * of "fileName".
- *
- * If there is already an entry with the same name, the call fails.
- * Existing entries with the same name must be removed first.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const char* fileName, int compressionMethod,
- ZipEntry** ppEntry)
- {
- return add(fileName, fileName, compressionMethod, ppEntry);
- }
- status_t add(const char* fileName, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * Add a file that is already compressed with gzip.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t addGzip(const char* fileName, const char* storageName,
- ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressDeflated,
- ZipEntry::kCompressDeflated, ppEntry);
- }
-
- /*
- * Add a file from an in-memory data buffer.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const void* data, size_t size, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(NULL, data, size, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * 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 add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry);
-
- /*
- * Mark an entry as having been removed. It is not actually deleted
- * from the archive or our internal data structures until flush() is
- * called.
- */
- status_t remove(ZipEntry* pEntry);
-
- /*
- * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
- */
- status_t flush(void);
-
- /*
- * Expand the data into the buffer provided. The buffer must hold
- * at least <uncompressed len> bytes. Variation expands directly
- * to a file.
- *
- * Returns "false" if an error was encountered in the compressed data.
- */
- //bool uncompress(const ZipEntry* pEntry, void* buf) const;
- //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
- void* uncompress(const ZipEntry* pEntry);
-
- /*
- * Get an entry, by name. Returns NULL if not found.
- *
- * Does not return entries pending deletion.
- */
- ZipEntry* getEntryByName(const char* fileName) const;
-
- /*
- * Get the Nth entry in the archive.
- *
- * This will return an entry that is pending deletion.
- */
- int getNumEntries(void) const { return mEntries.size(); }
- ZipEntry* getEntryByIndex(int idx) const;
-
-private:
- /* these are private and not defined */
- ZipFile(const ZipFile& src);
- ZipFile& operator=(const ZipFile& src);
-
- class EndOfCentralDir {
- public:
- EndOfCentralDir(void) :
- mDiskNumber(0),
- mDiskWithCentralDir(0),
- mNumEntries(0),
- mTotalNumEntries(0),
- mCentralDirSize(0),
- mCentralDirOffset(0),
- mCommentLen(0),
- mComment(NULL)
- {}
- virtual ~EndOfCentralDir(void) {
- delete[] mComment;
- }
-
- status_t readBuf(const unsigned char* buf, int len);
- status_t write(FILE* fp);
-
- //unsigned long mSignature;
- unsigned short mDiskNumber;
- unsigned short mDiskWithCentralDir;
- unsigned short mNumEntries;
- unsigned short mTotalNumEntries;
- unsigned long mCentralDirSize;
- unsigned long mCentralDirOffset; // offset from first disk
- unsigned short mCommentLen;
- unsigned char* mComment;
-
- enum {
- kSignature = 0x06054b50,
- kEOCDLen = 22, // EndOfCentralDir len, excl. comment
-
- kMaxCommentLen = 65535, // longest possible in ushort
- kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
-
- };
-
- void dump(void) const;
- };
-
-
- /* read all entries in the central dir */
- status_t readCentralDir(void);
-
- /* crunch deleted entries out */
- status_t crunchArchive(void);
-
- /* clean up mEntries */
- void discardEntries(void);
-
- /* common handler for all "add" functions */
- status_t addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry);
-
- /* copy all of "srcFp" into "dstFp" */
- status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
- /* copy all of "data" into "dstFp" */
- status_t copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32);
- /* copy some of "srcFp" into "dstFp" */
- status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32);
- /* like memmove(), but on parts of a single file */
- status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
- /* compress all of "srcFp" into "dstFp", using Deflate */
- status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
- const void* data, size_t size, unsigned long* pCRC32);
-
- /* get modification date from a file descriptor */
- time_t getModTime(int fd);
-
- /*
- * We use stdio FILE*, which gives us buffering but makes dealing
- * with files >2GB awkward. Until we support Zip64, we're fine.
- */
- FILE* mZipFp; // Zip file pointer
-
- /* one of these per file */
- EndOfCentralDir mEOCD;
-
- /* did we open this read-only? */
- bool mReadOnly;
-
- /* set this when we trash the central dir */
- bool mNeedCDRewrite;
-
- /*
- * One ZipEntry per entry in the zip file. I'm using pointers instead
- * of objects because it's easier than making operator= work for the
- * classes and sub-classes.
- */
- Vector<ZipEntry*> mEntries;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPFILE_H
diff --git a/include/utils/inet_address.h b/include/utils/inet_address.h
deleted file mode 100644
index dbd8672..0000000
--- a/include/utils/inet_address.h
+++ /dev/null
@@ -1,103 +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 classes. Modeled after Java classes.
-//
-#ifndef _RUNTIME_INET_ADDRESS_H
-#define _RUNTIME_INET_ADDRESS_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-
-namespace android {
-
-/*
- * This class holds Internet addresses. Perhaps more useful is its
- * ability to look up addresses by name.
- *
- * Invoke one of the static factory methods to create a new object.
- */
-class InetAddress {
-public:
- virtual ~InetAddress(void);
-
- // create from w.x.y.z or foo.bar.com notation
- static InetAddress* getByName(const char* host);
-
- // copy-construction
- InetAddress(const InetAddress& orig);
-
- const void* getAddress(void) const { return mAddress; }
- int getAddressLength(void) const { return mLength; }
- const char* getHostName(void) const { return mName; }
-
-private:
- InetAddress(void);
- // assignment (private)
- InetAddress& operator=(const InetAddress& addr);
-
- // use a void* here so we don't have to expose actual socket headers
- void* mAddress; // this is really a ptr to sockaddr_in
- int mLength;
- char* mName;
-};
-
-
-/*
- * Base class for socket addresses.
- */
-class SocketAddress {
-public:
- SocketAddress() {}
- virtual ~SocketAddress() {}
-};
-
-
-/*
- * Internet address class. This combines an InetAddress with a port.
- */
-class InetSocketAddress : public SocketAddress {
-public:
- InetSocketAddress() :
- mAddress(0), mPort(-1)
- {}
- ~InetSocketAddress(void) {
- delete mAddress;
- }
-
- // Create an address with a host wildcard (useful for servers).
- bool create(int port);
- // Create an address with the specified host and port.
- bool create(const InetAddress* addr, int port);
- // Create an address with the specified host and port. Does the
- // hostname lookup.
- bool create(const char* host, int port);
-
- const InetAddress* getAddress(void) const { return mAddress; }
- const int getPort(void) const { return mPort; }
- const char* getHostName(void) const { return mAddress->getHostName(); }
-
-private:
- InetAddress* mAddress;
- int mPort;
-};
-
-}; // namespace android
-
-#endif // _RUNTIME_INET_ADDRESS_H
diff --git a/include/utils/misc.h b/include/utils/misc.h
index 62e84b4..23f2a4c 100644
--- a/include/utils/misc.h
+++ b/include/utils/misc.h
@@ -21,7 +21,7 @@
#define _LIBS_UTILS_MISC_H
#include <sys/time.h>
-#include "utils/Endian.h"
+#include <utils/Endian.h>
namespace android {
diff --git a/include/utils/ported.h b/include/utils/ported.h
deleted file mode 100644
index eb3be01..0000000
--- a/include/utils/ported.h
+++ /dev/null
@@ -1,50 +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.
- */
-
-//
-// Standard functions ported to the current platform. Note these are NOT
-// in the "android" namespace.
-//
-#ifndef _LIBS_UTILS_PORTED_H
-#define _LIBS_UTILS_PORTED_H
-
-#include <sys/time.h> // for timeval
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* library replacement functions */
-#if defined(NEED_GETTIMEOFDAY)
-int gettimeofday(struct timeval* tv, struct timezone* tz);
-#endif
-#if defined(NEED_USLEEP)
-void usleep(unsigned long usec);
-#endif
-#if defined(NEED_PIPE)
-int pipe(int filedes[2]);
-#endif
-#if defined(NEED_SETENV)
-int setenv(const char* name, const char* value, int overwrite);
-void unsetenv(const char* name);
-char* getenv(const char* name);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _LIBS_UTILS_PORTED_H
diff --git a/include/utils/string_array.h b/include/utils/string_array.h
deleted file mode 100644
index 064dda2..0000000
--- a/include/utils/string_array.h
+++ /dev/null
@@ -1,135 +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.
- */
-
-//
-// Sortable array of strings. STL-ish, but STL-free.
-//
-#ifndef _LIBS_UTILS_STRING_ARRAY_H
-#define _LIBS_UTILS_STRING_ARRAY_H
-
-#include <stdlib.h>
-#include <string.h>
-
-namespace android {
-
-//
-// An expanding array of strings. Add, get, sort, delete.
-//
-class StringArray {
-public:
- StringArray()
- : mMax(0), mCurrent(0), mArray(NULL)
- {}
- virtual ~StringArray() {
- for (int i = 0; i < mCurrent; i++)
- delete[] mArray[i];
- delete[] mArray;
- }
-
- //
- // Add a string. A copy of the string is made.
- //
- bool 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 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 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.
- //
- static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
- return strcmp(*(const char**)pstr1, *(const char**)pstr2);
- }
-
- //
- // Get the #of items in the array.
- //
- inline int size(void) const { return mCurrent; }
-
- //
- // Return entry N.
- // [should use operator[] here]
- //
- const char* getEntry(int idx) const {
- if (idx < 0 || idx >= mCurrent)
- return NULL;
- return mArray[idx];
- }
-
- //
- // Set entry N to specified string.
- // [should use operator[] here]
- //
- void 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);
- }
-
-private:
- int mMax;
- int mCurrent;
- char** mArray;
-};
-
-}; // namespace android
-
-#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/threads.h b/include/utils/threads.h
index b320915..0fc533f 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -21,6 +21,10 @@
#include <sys/types.h>
#include <time.h>
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
// ------------------------------------------------------------------
// C API
@@ -176,6 +180,8 @@ inline thread_id_t getThreadId() {
return androidGetThreadId();
}
+/*****************************************************************************/
+
/*
* Simple mutex class. The implementation is system-dependent.
*
@@ -184,8 +190,14 @@ inline thread_id_t getThreadId() {
*/
class Mutex {
public:
+ enum {
+ NORMAL = 0,
+ SHARED = 1
+ };
+
Mutex();
Mutex(const char* name);
+ Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
@@ -199,11 +211,11 @@ public:
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
- inline Autolock(Mutex& mutex) : mpMutex(&mutex) { mutex.lock(); }
- inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
- inline ~Autolock() { mpMutex->unlock(); }
+ inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() { mLock.unlock(); }
private:
- Mutex* mpMutex;
+ Mutex& mLock;
};
private:
@@ -212,11 +224,49 @@ private:
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
- void _init();
+#if defined(HAVE_PTHREADS)
+ pthread_mutex_t mMutex;
+#else
+ void _init();
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Mutex::Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(const char* name) {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(int type, const char* name) {
+ if (type == SHARED) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&mMutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ } else {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+}
+inline Mutex::~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+}
+inline status_t Mutex::lock() {
+ return -pthread_mutex_lock(&mMutex);
+}
+inline void Mutex::unlock() {
+ pthread_mutex_unlock(&mMutex);
+}
+inline status_t Mutex::tryLock() {
+ return -pthread_mutex_trylock(&mMutex);
+}
+
+#endif // HAVE_PTHREADS
+
/*
* Automatic mutex. Declare one of these at the top of a function.
* When the function returns, it will go out of scope, and release the
@@ -225,6 +275,7 @@ private:
typedef Mutex::Autolock AutoMutex;
+/*****************************************************************************/
/*
* Condition variable class. The implementation is system-dependent.
@@ -240,9 +291,6 @@ public:
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
- // Wait on the condition variable until the given time. Lock the mutex
- // before calling.
- status_t wait(Mutex& mutex, nsecs_t abstime);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
@@ -251,9 +299,60 @@ public:
void broadcast();
private:
+#if defined(HAVE_PTHREADS)
+ pthread_cond_t mCond;
+#else
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Condition::Condition() {
+ pthread_cond_init(&mCond, NULL);
+}
+inline Condition::~Condition() {
+ pthread_cond_destroy(&mCond);
+}
+inline status_t Condition::wait(Mutex& mutex) {
+ return -pthread_cond_wait(&mCond, &mutex.mMutex);
+}
+inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
+ struct timespec ts;
+ ts.tv_sec = reltime/1000000000;
+ ts.tv_nsec = reltime%1000000000;
+ return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
+#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+ struct timespec ts;
+#if defined(HAVE_POSIX_CLOCKS)
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else // HAVE_POSIX_CLOCKS
+ // we don't support the clocks here.
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ ts.tv_sec = t.tv_sec;
+ ts.tv_nsec= t.tv_usec*1000;
+#endif // HAVE_POSIX_CLOCKS
+ ts.tv_sec += reltime/1000000000;
+ ts.tv_nsec+= reltime%1000000000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec += 1;
+ }
+ return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
+#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+}
+inline void Condition::signal() {
+ pthread_cond_signal(&mCond);
+}
+inline void Condition::broadcast() {
+ pthread_cond_broadcast(&mCond);
+}
+
+#endif // HAVE_PTHREADS
+
+/*****************************************************************************/
/*
* This is our spiffy thread object!
@@ -291,7 +390,7 @@ protected:
bool exitPending() const;
private:
- // Derived class must implemtent threadLoop(). The thread starts its life
+ // Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
@@ -309,6 +408,9 @@ private:
volatile bool mExitPending;
volatile bool mRunning;
sp<Thread> mHoldSelf;
+#if HAVE_ANDROID_OS
+ int mTid;
+#endif
};
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 16a4f2d..351815b 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -16,7 +16,7 @@
#include <math.h>
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "A2dpAudioInterface"
#include <utils/Log.h>
#include <utils/String8.h>
@@ -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), mSuspended(false)
{
}
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,142 @@ 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);
+ mOutput->setSuspended(mSuspended);
} else {
delete out;
}
-
+
if (status)
*status = err;
return mOutput;
}
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput == 0 || mOutput != out) {
+ mHardwareInterface->closeOutputStream(out);
+ }
+ 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);
+ }
+ key = String8("A2dpSuspended");
+ if (param.get(key, value) == NO_ERROR) {
+ mSuspended = (value == "true");
+ if (mOutput) {
+ mOutput->setSuspended(mSuspended);
+ }
+ 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);
+ key = "A2dpSuspended";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mSuspended ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
}
- return 0;
+ String8 keyValuePairs = a2dpParam.toString();
+
+ if (param.size()) {
+ keyValuePairs += ";";
+ keyValuePairs += mHardwareInterface->getParameters(param.toString());
+ }
+
+ 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 +219,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), mClosing(false), mSuspended(false)
{
// use any address by default
strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -140,27 +227,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)
@@ -170,8 +273,10 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t
size_t remaining = bytes;
status_t status = -1;
- if (!mBluetoothEnabled) {
- LOGW("A2dpAudioStreamOut::write(), but bluetooth disabled");
+ if (!mBluetoothEnabled || mClosing || mSuspended) {
+ LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
+ mBluetoothEnabled %d, mClosing %d, mSuspended %d",
+ mBluetoothEnabled, mClosing, mSuspended);
goto Error;
}
@@ -219,6 +324,11 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
{
int result = 0;
+ if (mClosing) {
+ LOGV("Ignore standby, closing");
+ return result;
+ }
+
Mutex::Autolock lock(mLock);
if (!mStandby) {
@@ -230,6 +340,64 @@ 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 = String8("closing");
+ if (param.get(key, value) == NO_ERROR) {
+ mClosing = (value == "true");
+ 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);
@@ -257,15 +425,25 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enable
return NO_ERROR;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
+{
+ LOGV("setSuspended %d", onOff);
+ mSuspended = onOff;
+ standby();
+ return NO_ERROR;
+}
+
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 +455,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..530e432 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;
@@ -92,6 +101,7 @@ private:
status_t close_l();
status_t setAddress(const char* address);
status_t setBluetoothEnabled(bool enabled);
+ status_t setSuspended(bool onOff);
private:
int mFd;
@@ -102,11 +112,21 @@ private:
void* mData;
Mutex mLock;
bool mBluetoothEnabled;
+ uint32_t mDevice;
+ bool mClosing;
+ bool mSuspended;
};
+ friend class A2dpAudioStreamOut;
+
A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
+ bool mSuspended;
};
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 50d516b..f5c03bb 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,45 @@ 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)
+ LOCAL_SHARED_LIBRARIES += liba2dp
+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..858e5aa 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,240 @@
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;
+ } else {
+ lFormat = AudioSystem::PCM_16_BIT;
+ }
+ if (channels != 0 && *channels != 0) {
+ lChannels = *channels;
+ } else {
+ lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ }
+ if (sampleRate != 0 && *sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ lRate = 44100;
+ }
+ 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;
+ }
+
+ LOGV("closeOutputStream() output %p", out);
+
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ mFirstHwOutput = true;
+ }
+
+ 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;
+ param.remove(String8("test_cmd_file_name"));
+ }
+ 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);
+ AudioParameter response;
+ String8 value;
+
+// LOGV("getParameters %s", keys.string());
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ if (mPolicyCommands.length() != 0) {
+ response = AudioParameter(mPolicyCommands);
+ response.addInt(String8("test_cmd_policy"), 1);
+ } else {
+ response.addInt(String8("test_cmd_policy"), 0);
+ }
+ param.remove(String8("test_cmd_policy"));
+// LOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ }
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ response.add(String8("test_cmd_file_name"), mFileName);
+ param.remove(String8("test_cmd_file_name"));
+ }
+
+ String8 keyValuePairs = response.toString();
+
+ if (param.size() && mFinalInterface != 0 ) {
+ keyValuePairs += ";";
+ keyValuePairs += mFinalInterface->getParameters(param.toString());
+ }
+
+ return keyValuePairs;
+}
+
// ----------------------------------------------------------------------------
-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()
{
+ LOGV("AudioStreamOutDump destructor");
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 +273,105 @@ 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 %s", keyValuePairs.string());
+
+ if (mFinalStream != 0 ) {
+ return mFinalStream->setParameters(keyValuePairs);
+ }
+
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ status_t status = NO_ERROR;
+
+ if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+ mId = valueInt;
+ }
+
+ if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+ if (mOutFile == 0) {
+ mFormat = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ }
+ if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+ if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+ mChannels = valueInt;
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+ if (valueInt > 0 && valueInt <= 48000) {
+ if (mOutFile == 0) {
+ mSampleRate = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ return status;
}
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
-void AudioStreamOutDump::Close(void)
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
{
if(mOutFile) {
fclose(mOutFile);
@@ -114,4 +379,141 @@ 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)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+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..1136ce1 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -20,35 +20,95 @@
#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; }
+ int getId() { return mId; }
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 +116,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 +138,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 da7cc8a..ebd470f 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>
@@ -62,8 +62,6 @@ static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n";
static const char* kHardwareLockedString = "Hardware lock is taken\n";
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-static const unsigned long kBufferRecoveryInUsecs = 2000;
-static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
static const float MAX_GAIN = 4096.0f;
// retry counts for buffer fill timeout
@@ -71,14 +69,10 @@ 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;
+static const nsecs_t kWarningThrottle = seconds(5);
#define AUDIOFLINGER_SECURITY_ENABLED 1
@@ -121,132 +115,41 @@ 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), mNextThreadId(0)
{
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();
+ while (!mRecordThreads.isEmpty()) {
+ // closeInput() will remove first entry from mRecordThreads
+ closeInput(mRecordThreads.keyAt(0));
}
- mHardwareMixerThread.clear();
- delete mAudioHardware;
- // deleting mA2dpAudioInterface also deletes mA2dpOutput;
-#ifdef WITH_A2DP
- mA2dpMixerThread.clear();
- delete mA2dpAudioInterface;
-#endif
-}
-
-
-#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;
-
- LOGD_IF(enable, "set output to A2DP\n");
- LOGD_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);
- mA2dpMixerThread->mOutput->standby();
+ while (!mPlaybackThreads.isEmpty()) {
+ // closeOutput() will remove first entry from mPlaybackThreads
+ closeOutput(mPlaybackThreads.keyAt(0));
}
- 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;
+ if (mAudioHardware) {
+ delete mAudioHardware;
}
}
-#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)
{
@@ -276,10 +179,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());
@@ -337,13 +237,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.valueAt(i)->dump(fd, args);
+ }
+
+ // dump record threads
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->dump(fd, args);
+ }
if (mAudioHardware) {
mAudioHardware->dumpState(fd, args);
@@ -353,6 +256,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+
// IAudioFlinger interface
@@ -365,9 +269,10 @@ sp<IAudioTrack> AudioFlinger::createTrack(
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status)
{
- sp<MixerThread::Track> track;
+ sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
@@ -381,6 +286,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);
@@ -390,20 +301,15 @@ 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);
} else {
+ // remove local strong reference to Client before deleting the Track so that the Client
+ // destructor is called by the TrackBase destructor with mLock held
+ client.clear();
track.clear();
}
@@ -416,52 +322,57 @@ Exit:
uint32_t AudioFlinger::sampleRate(int 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 %d", output);
+ return 0;
+ }
+ return thread->sampleRate();
}
int AudioFlinger::channelCount(int 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 %d", output);
+ return 0;
+ }
+ return thread->channelCount();
}
int AudioFlinger::format(int 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 %d", output);
+ return 0;
+ }
+ return thread->format();
}
size_t AudioFlinger::frameCount(int 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 %d", output);
+ return 0;
+ }
+ return thread->frameCount();
}
uint32_t AudioFlinger::latency(int 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 %d", output);
+ return 0;
+ }
+ return thread->latency();
}
status_t AudioFlinger::setMasterVolume(float value)
@@ -478,94 +389,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.valueAt(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)
@@ -586,15 +415,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
@@ -624,60 +444,55 @@ 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.valueAt(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, int 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;
}
- status_t ret = NO_ERROR;
- if (stream == AudioSystem::VOICE_CALL ||
- stream == AudioSystem::BLUETOOTH_SCO) {
- float hwValue;
- if (stream == AudioSystem::VOICE_CALL) {
- hwValue = (float)AudioSystem::logToLinear(value)/100.0f;
- // offset value to reflect actual hardware volume that never reaches 0
- // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
- value = 0.01 + 0.99 * value;
- } else { // (type == AudioSystem::BLUETOOTH_SCO)
- hwValue = 1.0f;
+ AutoMutex lock(mLock);
+ PlaybackThread *thread = NULL;
+ if (output) {
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
}
-
- AutoMutex lock(mHardwareLock);
- 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;
- return ret;
+ if (thread == NULL) {
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
+ }
+ } else {
+ thread->setStreamVolume(stream, value);
+ }
+
+ return NO_ERROR;
}
status_t AudioFlinger::setStreamMute(int stream, bool muted)
@@ -687,82 +502,115 @@ 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.valueAt(i)->setStreamMute(stream, muted);
return NO_ERROR;
}
-float AudioFlinger::streamVolume(int stream) const
+float AudioFlinger::streamVolume(int stream, int 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);
- // remove correction applied by setStreamVolume()
- if (stream == AudioSystem::VOICE_CALL) {
- volume = (volume - 0.01) / 0.99 ;
+
+ 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;
}
-
+
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.valueAt(i)->isMusicActive()) {
+ return true;
+ }
+ }
+ return false;
}
-status_t AudioFlinger::setParameter(const char* key, const char* value)
+status_t AudioFlinger::setParameters(int 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 %d, 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;
+ }
+
+ // hold a strong ref on thread in case closeOutput() or closeInput() is called
+ // and the thread is exited once the lock is released
+ sp<ThreadBase> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(ioHandle);
+ if (thread == NULL) {
+ thread = checkRecordThread_l(ioHandle);
+ }
+ }
+ if (thread != NULL) {
+ return thread->setParameters(keyValuePairs);
+ }
+ return BAD_VALUE;
+}
+
+String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
+{
+// LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
+
+ if (ioHandle == 0) {
+ return mAudioHardware->getParameters(keys);
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ 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)
@@ -770,9 +618,24 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha
return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
}
+status_t AudioFlinger::setVoiceVolume(float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+ status_t ret = mAudioHardware->setVoiceVolume(value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+
+ return ret;
+}
+
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);
@@ -781,12 +644,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.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+ }
+
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
}
}
void AudioFlinger::binderDied(const wp<IBinder>& who) {
-
+
LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
@@ -801,156 +673,242 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) {
}
}
-void AudioFlinger::removeClient(pid_t pid)
+// audioConfigChanged_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2) {
+ int ioHandle = 0;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i) == thread) {
+ ioHandle = mPlaybackThreads.keyAt(i);
+ break;
+ }
+ }
+ if (ioHandle == 0) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i) == thread) {
+ ioHandle = mRecordThreads.keyAt(i);
+ break;
+ }
+ }
+ }
+
+ if (ioHandle != 0) {
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i);
+ LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->ioConfigChanged(event, ioHandle, param2);
+ }
+ }
+}
+
+// removeClient_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::removeClient_l(pid_t pid)
{
- LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
- Mutex::Autolock _l(mLock);
+ LOGV("removeClient_l() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
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), 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;
+ mParamCond.broadcast();
+ mNewParameters.clear();
+}
+
+void AudioFlinger::ThreadBase::exit()
+{
+ // keep a strong ref on ourself so that we wont get
+ // destroyed in the middle of requestExitAndWait()
+ sp <ThreadBase> strongMe = this;
+
+ LOGV("ThreadBase::exit");
+ {
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
}
+ requestExitAndWait();
}
-#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");
- }
+uint32_t AudioFlinger::ThreadBase::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioFlinger::ThreadBase::channelCount() const
+{
+ return mChannelCount;
+}
+
+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 status;
+
+ LOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
+ Mutex::Autolock _l(mLock);
+
+ mNewParameters.add(keyValuePairs);
+ mWaitWorkCV.signal();
+ // wait condition with timeout in case the thread loop has exited
+ // before the request could be processed
+ if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+ status = mParamStatus;
+ mWaitWorkCV.signal();
+ } else {
+ status = TIMED_OUT;
}
+ return status;
}
-#endif
-// ----------------------------------------------------------------------------
+void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
+{
+ Mutex::Autolock _l(mLock);
+ sendConfigEvent_l(event, param);
+}
-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)
+// sendConfigEvent_l() must be called with ThreadBase::mLock held
+void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
+ 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();
+}
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
+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 lock AudioFlinger mLock
+ // before calling Audioflinger::audioConfigChanged_l() 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());
+status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
- // 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));
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ snprintf(buffer, SIZE, "thread %p maybe dead locked\n", this);
+ write(fd, buffer, strlen(buffer));
+ }
+
+ snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Sample rate: %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Frame count: %d\n", mFrameCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Channel Count: %d\n", mChannelCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Frame size: %d\n", mFrameSize);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "\nPending setParameters commands: \n");
+ result.append(buffer);
+ result.append(" Index Command");
+ for (size_t i = 0; i < mNewParameters.size(); ++i) {
+ snprintf(buffer, SIZE, "\n %02d ", i);
+ result.append(buffer);
+ result.append(mNewParameters[i]);
+ }
+
+ snprintf(buffer, SIZE, "\n\nPending config events: \n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Index event param\n");
+ result.append(buffer);
+ for (size_t i = 0; i < mConfigEvents.size(); i++) {
+ snprintf(buffer, SIZE, " %02d %02d %d\n", i, mConfigEvents[i]->mEvent, mConfigEvents[i]->mParam);
+ result.append(buffer);
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+
+ if (locked) {
+ mLock.unlock();
+ }
+ return NO_ERROR;
}
-AudioFlinger::MixerThread::~MixerThread()
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : ThreadBase(audioFlinger),
+ mMixBuffer(0), mSuspended(0), 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::PlaybackThread::~PlaybackThread()
{
delete [] mMixBuffer;
- delete mAudioMixer;
}
-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");
+ 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) {
sp<Track> track = mTracks[i];
if (track != 0) {
@@ -959,9 +917,9 @@ 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");
+ 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) {
wp<Track> wTrack = mActiveTracks[i];
if (wTrack != 0) {
@@ -976,15 +934,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, "\nOutput thread %p internals\n", this);
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -994,350 +950,545 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
result.append(buffer);
snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
result.append(buffer);
- snprintf(buffer, SIZE, "standby: %d\n", mStandby);
- result.append(buffer);
write(fd, result.string(), result.size());
+
+ dumpBase(fd, args);
+
return NO_ERROR;
}
// 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 || track->name() < 0) {
+ 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) on thread %p", track->name(), this);
+ } else {
+ track->mState = TrackBase::ACTIVE;
+ LOGV("? => ACTIVE (%d) on thread %p", track->name(), this);
+ }
+ // 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;
+ }
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ mAudioFlinger->audioConfigChanged_l(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;
+ uint32_t sleepTime = 1000;
+ uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
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 maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-
-#ifdef WITH_A2DP
- bool outputTrackActive = false;
-#endif
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount * mFrameSize;
+ // FIXME: Relaxed timing because of a certain device that can't meet latency
+ // Should be reduced to 2x after the vendor fixes the driver issue
+ nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 3;
+ nsecs_t lastWarning = 0;
+
+ 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;
+ // FIXME: Relaxed timing because of a certain device that can't meet latency
+ // Should be reduced to 2x after the vendor fixes the driver issue
+ maxPeriod = seconds(mFrameCount) / mSampleRate * 3;
+ maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
}
- 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);
- }
-
- // 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 (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
+ if (exitPending()) break;
- // 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);
+ // 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());
- // 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;
+ sleepTime = 1000;
+ 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);
+ sleepTime = 0;
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ } else {
+ // If no tracks are ready, sleep once for the duration of an output
+ // buffer size, then write 0s to the output
+ if (sleepTime == 0) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ } else if (mBytesWritten != 0) {
+ memset (curBuf, 0, mixBufferSize);
+ sleepTime = 0;
}
-#endif
+ }
- // output audio to hardware
+ if (mSuspended) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ }
+ // sleepTime == 0 means we must write to audio hardware
+ if (sleepTime == 0) {
mLastWriteTime = systemTime();
mInWrite = true;
- mOutput->write(curBuf, mixBufferSize);
+ 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;
+ nsecs_t now = systemTime();
+ nsecs_t delta = now - 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 ((now - lastWarning) > kWarningThrottle) {
+ LOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
+ ns2ms(delta), mNumDelayedWrites, this);
+ lastWarning = now;
}
}
-#endif
- // 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);
+ } else {
usleep(sleepTime);
- if (sleepTime < kMaxBufferRecoveryInUsecs) {
- 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();
- } 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;
+
+ 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);
+ 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;
- run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
-}
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
-// 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;
- }
+ // 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);
+ }
+ // XXX: these things DON'T need to be done each time
+ mAudioMixer->setBufferProvider(track);
+ mAudioMixer->enable(AudioMixer::MIXING);
+
+ int param = AudioMixer::VOLUME;
+ 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 if (cblk->server != 0) {
+ // If the track is stopped before the first frame was mixed,
+ // do not apply ramp
+ param = AudioMixer::RAMP_VOLUME;
+ }
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
+ 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 on thread %p", track->name(), this);
+ tracksToRemove->add(track);
+ }
+ // For tracks using static shared memory 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];
@@ -1346,219 +1497,603 @@ 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);
+ // force buffer refilling and no ramp volume when the track is mixed for the first time
+ t->mFillingUpStatus = Track::FS_FILLING;
+ }
}
}
-uint32_t AudioFlinger::MixerThread::sampleRate() const
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
{
- return mSampleRate;
+ return mAudioMixer->getTrackName();
}
-int AudioFlinger::MixerThread::channelCount() const
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
{
- return mChannelCount;
+ mAudioMixer->deleteTrackName(name);
}
-int AudioFlinger::MixerThread::format() const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameters_l()
{
- return mFormat;
-}
+ bool reconfig = false;
-size_t AudioFlinger::MixerThread::frameCount() const
-{
- return mFrameCount;
-}
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
-uint32_t AudioFlinger::MixerThread::latency() const
-{
- if (mOutput) {
- return mOutput->latency();
- }
- else {
- return 0;
+ 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(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ 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;
+ // limit track sample rate to 2 x new output sample rate
+ if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) {
+ mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
+ }
+ }
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+
+ mNewParameters.removeAt(0);
+
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
}
+ return reconfig;
}
-status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
{
- mMasterVolume = value;
- return NO_ERROR;
-}
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
-status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
-{
- mMasterMute = muted;
+ 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;
}
-float AudioFlinger::MixerThread::masterVolume() const
+uint32_t AudioFlinger::MixerThread::getMaxBufferRecoveryInUsecs()
{
- return mMasterVolume;
+ uint32_t time = ((mFrameCount * 1000) / mSampleRate) * 1000;
+ // Add some margin with regard to scheduling precision
+ if (time > 10000) {
+ time -= 10000;
+ }
+ return time;
}
-bool AudioFlinger::MixerThread::masterMute() const
+// ----------------------------------------------------------------------------
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mLeftVolume (1.0), mRightVolume(1.0)
{
- return mMasterMute;
+ mType = PlaybackThread::DIRECT;
}
-status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
- mStreamTypes[stream].volume = value;
- return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+
+bool AudioFlinger::DirectOutputThread::threadLoop()
{
- mStreamTypes[stream].mute = muted;
- return NO_ERROR;
+ uint32_t sleepTime = 1000;
+ uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
+ 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;
+ maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
+ }
+
+ // 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;
+ sleepTime = 1000;
+ 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
+ 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);
+ }
+ sleepTime = 0;
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ } else {
+ if (sleepTime == 0) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ } else if (mBytesWritten != 0 && AudioSystem::isLinearPCM(mFormat)) {
+ memset (mMixBuffer, 0, mFrameCount * mFrameSize);
+ sleepTime = 0;
+ }
+ }
+
+ if (mSuspended) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ }
+ // sleepTime == 0 means we must write to audio hardware
+ if (sleepTime == 0) {
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
+ if (bytesWritten) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ } else {
+ usleep(sleepTime);
+ }
+
+ // 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();
+ }
+
+ LOGV("DirectOutputThread %p exiting", this);
+ return false;
}
-float AudioFlinger::MixerThread::streamVolume(int stream) const
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::DirectOutputThread::getTrackName_l()
{
- return mStreamTypes[stream].volume;
+ return 0;
}
-bool AudioFlinger::MixerThread::streamMute(int stream) const
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
{
- return mStreamTypes[stream].mute;
}
-// isMusicActive_l() must be called with AudioFlinger::mLock held
-bool AudioFlinger::MixerThread::isMusicActive_l() const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
{
- 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;
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ 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(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters();
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+
+ mNewParameters.removeAt(0);
+
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
}
- return false;
+ return reconfig;
}
-// addTrack_l() must be called with AudioFlinger::mLock held
-status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+uint32_t AudioFlinger::DirectOutputThread::getMaxBufferRecoveryInUsecs()
{
- 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());
+ uint32_t time;
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ time = ((mFrameCount * 1000) / mSampleRate) * 1000;
+ // Add some margin with regard to scheduling precision
+ if (time > 10000) {
+ time -= 10000;
+ }
} 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;
+ time = 10000;
}
-
- LOGV("mWaitWorkCV.broadcast");
- mAudioFlinger->mWaitWorkCV.broadcast();
-
- return status;
+ return time;
}
-// destroyTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
+// ----------------------------------------------------------------------------
+
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
+ : MixerThread(audioFlinger, mainThread->getOutput())
{
- 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());
- }
+ mType = PlaybackThread::DUPLICATING;
+ addOutputTrack(mainThread);
}
-// addActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
+AudioFlinger::DuplicatingThread::~DuplicatingThread()
{
- mActiveTracks.add(t);
-
- // 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);
- }
- }
+ mOutputTracks.clear();
}
-// removeActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
+bool AudioFlinger::DuplicatingThread::threadLoop()
{
- mActiveTracks.remove(t);
+ uint32_t sleepTime = 1000;
+ uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
+ 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;
+ uint32_t writeFrames = 0;
+
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ enabledTracks = 0;
+ { // scope for the mLock
- // 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;
+ Mutex::Autolock _l(mLock);
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
+ }
+
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ 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++) {
+ outputTracks[i]->stop();
+ }
+ 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 = 1000;
+ continue;
+ }
+ }
+
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
}
+
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+ sleepTime = 0;
+ writeFrames = mFrameCount;
+ } else {
+ if (sleepTime == 0) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ } else if (mBytesWritten != 0) {
+ // flush remaining overflow buffers in output tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ if (outputTracks[i]->isActive()) {
+ sleepTime = 0;
+ writeFrames = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (mSuspended) {
+ sleepTime = maxBufferRecoveryInUsecs;
+ }
+ // sleepTime == 0 means we must write to audio hardware
+ if (sleepTime == 0) {
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->write(curBuf, writeFrames);
+ }
+ mStandby = false;
+ mBytesWritten += mixBufferSize;
+ } else {
+ usleep(sleepTime);
+ }
+
+ // 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();
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+ if (!mStandby) {
+ LOGV("DuplicatingThread() exiting out of standby");
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ mOutputTracks[i]->destroy();
+ }
+ }
+ }
+
+ 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);
+ if (outputTrack->cblk() != NULL) {
+ 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[i]->destroy();
+ 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,
@@ -1567,21 +2102,15 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mMixerThread(mixerThread),
+ mThread(thread),
mClient(client),
+ mCblk(0),
mFrameCount(0),
mState(IDLE),
mClientTid(-1),
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);
@@ -1635,16 +2164,22 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
}
}
-AudioFlinger::MixerThread::TrackBase::~TrackBase()
+AudioFlinger::ThreadBase::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();
+ if (mClient != NULL) {
+ Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+ mClient.clear();
+ }
}
-void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1652,7 +2187,7 @@ void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Bu
buffer->frameCount = 0;
}
-bool AudioFlinger::MixerThread::TrackBase::step() {
+bool AudioFlinger::ThreadBase::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1664,7 +2199,7 @@ bool AudioFlinger::MixerThread::TrackBase::step() {
return result;
}
-void AudioFlinger::MixerThread::TrackBase::reset() {
+void AudioFlinger::ThreadBase::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
@@ -1675,27 +2210,27 @@ void AudioFlinger::MixerThread::TrackBase::reset() {
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
+int AudioFlinger::ThreadBase::TrackBase::sampleRate() const {
return (int)mCblk->sampleRate;
}
-int AudioFlinger::MixerThread::TrackBase::channelCount() const {
+int AudioFlinger::ThreadBase::TrackBase::channelCount() const {
return (int)mCblk->channels;
}
-void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::ThreadBase::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,
@@ -1708,9 +2243,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,
@@ -1718,42 +2253,62 @@ AudioFlinger::MixerThread::Track::Track(
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
-{
- mVolume[0] = 1.0f;
- mVolume[1] = 1.0f;
- mMute = false;
- mSharedBuffer = sharedBuffer;
- mStreamType = streamType;
+ : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
+ mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
+{
+ if (mCblk != NULL) {
+ 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;
+ 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",
+ snprintf(buffer, size, " %5d %5d %3u %3u %3u %04u %1d %1d %1d %5u %5u %5u %08x %08x\n",
mName - AudioMixer::TRACK0,
(mClient == NULL) ? getpid() : mClient->pid(),
mStreamType,
@@ -1770,7 +2325,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;
@@ -1807,76 +2362,90 @@ status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Bu
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
+ LOGV("getNextBuffer() no more data for track %d on thread %p", mName, mThread.unsafe_get());
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) on thread %p", mName, playbackThread);
}
- 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) on thread %p", mName, thread.get());
+ }
}
}
-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.
@@ -1886,17 +2455,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;
@@ -1905,28 +2474,35 @@ 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)
+{
+ if (mCblk != NULL) {
+ 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;
@@ -1965,180 +2541,247 @@ getNextBuffer_exit:
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::MixerThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start()
+{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ return recordThread->start(this);
+ }
+ return NO_INIT;
+}
+
+void AudioFlinger::RecordThread::RecordTrack::stop()
{
- return mMixerThread->mAudioFlinger->startRecord(this);
+ 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;
+ }
}
-void AudioFlinger::MixerThread::RecordTrack::stop()
+void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
{
- mMixerThread->mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
+ snprintf(buffer, size, " %05d %03u %03u %04u %01d %05u %08x %08x\n",
+ (mClient == NULL) ? getpid() : mClient->pid(),
+ mFormat,
+ mCblk->channels,
+ mFrameCount,
+ mState,
+ mCblk->sampleRate,
+ mCblk->server,
+ mCblk->user);
}
// ----------------------------------------------------------------------------
-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)
{
-
- 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);
-
+
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
+ if (mCblk != NULL) {
+ mCblk->out = 1;
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mOutBuffer.frameCount = 0;
+ mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
+ playbackThread->mTracks.add(this);
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+ } else {
+ LOGW("Error creating output track on thread %p", playbackThread);
+ }
}
-AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
{
- stop();
+ clearBufferQueue();
}
-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 && frames != 0) {
+ 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() to thread %p waitTimeMs %d waitTimeLeftMs %d", mThread.unsafe_get(), 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 if (mActive) {
+ 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;
}
@@ -2156,11 +2799,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;
@@ -2180,9 +2823,10 @@ AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
+// Client destructor must be called with AudioFlinger::mLock held
AudioFlinger::Client::~Client()
{
- mAudioFlinger->removeClient(mPid);
+ mAudioFlinger->removeClient_l(mPid);
}
const sp<MemoryDealer>& AudioFlinger::Client::heap() const
@@ -2192,7 +2836,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)
{
@@ -2244,7 +2888,7 @@ status_t AudioFlinger::TrackHandle::onTransact(
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -2252,14 +2896,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()) {
@@ -2267,30 +2910,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();
@@ -2299,15 +2927,14 @@ 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) {
+ // remove local strong reference to Client before deleting the RecordTrack so that the Client
+ // destructor is called by the TrackBase destructor with mLock held
+ client.clear();
recordTrack.clear();
lStatus = NO_MEMORY;
goto Exit;
@@ -2324,22 +2951,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)
{
@@ -2371,86 +2985,164 @@ 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()
{
+ 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;
- }
- if (mStartStatus !=NO_ERROR) {
- LOGW("record start failed, status %d", mStartStatus);
- mActive = false;
- mRecordTrack.clear();
+ mStartStopCond.broadcast();
}
- 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.
@@ -2459,73 +3151,559 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
}
}
-
- if (input) {
- delete input;
+ if (!mStandby) {
+ mInput->standby();
}
- mRecordTrack.clear();
-
+ mActiveTrack.clear();
+
+ 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;
+
+ if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
- mRecordTrack = recordTrack;
+ 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());
+ snprintf(buffer, SIZE, "\nInput thread %p internals\n", this);
+ result.append(buffer);
+
+ if (mActiveTrack != 0) {
+ result.append("Active Track:\n");
+ result.append(" Clien Fmt Chn Buf S SRate Serv User\n");
+ mActiveTrack->dump(buffer, SIZE);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "In size: %d\n", mInputBytes);
result.append(buffer);
+ snprintf(buffer, SIZE, "Resampling: %d\n", (mResampler != 0));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Out channel count: %d\n", mReqChannelCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate);
+ result.append(buffer);
+
+
} else {
result.append("No record client\n");
}
write(fd, result.string(), result.size());
+
+ dumpBase(fd, args);
+
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;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ 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(keyValuePair);
+ if (status == INVALID_OPERATION) {
+ mInput->standby();
+ status = mInput->setParameters(keyValuePair);
+ }
+ 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_l(AudioSystem::INPUT_CONFIG_CHANGED);
+ }
+ }
+ }
+
+ mNewParameters.removeAt(0);
+
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ 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;
+ }
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ mAudioFlinger->audioConfigChanged_l(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;
+}
+
+// ----------------------------------------------------------------------------
+
+int 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 0;
+ }
+ 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: ID %d thread %p", (mNextThreadId + 1), thread);
+ } else {
+ thread = new MixerThread(this, output);
+ LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
+ }
+ mPlaybackThreads.add(++mNextThreadId, thread);
+
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = channels;
+ if (pLatencyMs) *pLatencyMs = thread->latency();
+ }
+
+ return mNextThreadId;
+}
+
+int AudioFlinger::openDuplicateOutput(int output1, int output2)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *thread1 = checkMixerThread_l(output1);
+ MixerThread *thread2 = checkMixerThread_l(output2);
+
+ if (thread1 == NULL || thread2 == NULL) {
+ LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
+ return 0;
+ }
+
+
+ DuplicatingThread *thread = new DuplicatingThread(this, thread1);
+ thread->addOutputTrack(thread2);
+ mPlaybackThreads.add(++mNextThreadId, thread);
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeOutput(int output)
+{
+ // keep strong reference on the playback thread so that
+ // it is not destroyed while exit() is executed
+ sp <PlaybackThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeOutput() %d", output);
+
+ if (thread->type() == PlaybackThread::MIXER) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+ DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
+ dupThread->removeOutputTrack((MixerThread *)thread.get());
+ }
+ }
+ }
+ void *param2 = 0;
+ audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
+ mPlaybackThreads.removeItem(output);
+ }
+ thread->exit();
+
+ if (thread->type() != PlaybackThread::DUPLICATING) {
+ mAudioHardware->closeOutputStream(thread->getOutput());
+ }
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::suspendOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("suspendOutput() %d", output);
+ thread->suspend();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::restoreOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("restoreOutput() %d", output);
+
+ thread->restore();
+
+ return NO_ERROR;
+}
+
+int 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 0;
+ }
+ 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(++mNextThreadId, thread);
+ LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
+ if (pSamplingRate) *pSamplingRate = reqSamplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = reqChannels;
+
+ input->standby();
+ }
+
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeInput(int input)
+{
+ // keep strong reference on the record thread so that
+ // it is not destroyed while exit() is executed
+ sp <RecordThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeInput() %d", input);
+ void *param2 = 0;
+ audioConfigChanged_l(AudioSystem::INPUT_CLOSED, thread, param2);
+ mRecordThreads.removeItem(input);
+ }
+ thread->exit();
+
+ mAudioHardware->closeInputStream(thread->getInput());
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *dstThread = checkMixerThread_l(output);
+ if (dstThread == NULL) {
+ LOGW("setStreamOutput() bad output id %d", output);
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamOutput() stream %d to output %d", stream, output);
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ if (thread != dstThread &&
+ thread->type() != PlaybackThread::DIRECT) {
+ MixerThread *srcThread = (MixerThread *)thread;
+ SortedVector < sp<MixerThread::Track> > tracks;
+ SortedVector < wp<MixerThread::Track> > activeTracks;
+ srcThread->getTracks(tracks, activeTracks, stream);
+ if (tracks.size()) {
+ dstThread->putTracks(tracks, activeTracks);
+ }
+ }
+ }
+
+ dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
+
+ return NO_ERROR;
+}
+
+// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
+{
+ PlaybackThread *thread = NULL;
+ if (mPlaybackThreads.indexOfKey(output) >= 0) {
+ thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
+ }
+ return thread;
+}
+
+// checkMixerThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int 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(int input) const
+{
+ RecordThread *thread = NULL;
+ if (mRecordThreads.indexOfKey(input) >= 0) {
+ thread = (RecordThread *)mRecordThreads.valueFor(input).get();
+ }
+ return thread;
+}
+
+// ----------------------------------------------------------------------------
+
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -2533,6 +3711,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..22d15c9 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,6 +73,7 @@ public:
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status);
virtual uint32_t sampleRate(int output) const;
@@ -87,33 +88,53 @@ 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, int output);
virtual status_t setStreamMute(int stream, bool muted);
- virtual float streamVolume(int stream) const;
+ virtual float streamVolume(int stream, int 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(int ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(int 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 int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags);
+
+ virtual int openDuplicateOutput(int output1, int output2);
+
+ virtual status_t closeOutput(int output);
+
+ virtual status_t suspendOutput(int output);
+
+ virtual status_t restoreOutput(int output);
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+
+ virtual status_t closeInput(int input);
+
+ virtual status_t setStreamOutput(uint32_t stream, int output);
+
+ virtual status_t setVoiceVolume(float volume);
+
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -139,7 +160,7 @@ public:
// record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -156,27 +177,7 @@ public:
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);
@@ -190,6 +191,8 @@ private:
virtual ~Client();
const sp<MemoryDealer>& heap() const;
pid_t pid() const { return mPid; }
+ sp<AudioFlinger> audioFlinger() { return mAudioFlinger; }
+
private:
Client(const Client&);
Client& operator = (const Client&);
@@ -201,14 +204,19 @@ 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();
+
+ status_t dumpBase(int fd, const Vector<String16>& args);
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -230,7 +238,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,
@@ -243,11 +251,15 @@ private:
virtual status_t start() = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const;
+ audio_track_cblk_t* cblk() const { return mCblk; }
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&);
@@ -255,10 +267,6 @@ private:
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
int format() const {
return mFormat;
}
@@ -269,10 +277,6 @@ private:
void* getBuffer(uint32_t offset, uint32_t frames) const;
- int name() const {
- return mName;
- }
-
bool isStopped() const {
return mState == STOPPED;
}
@@ -284,14 +288,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 +302,69 @@ 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 sendConfigEvent_l(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;
+ Vector<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 +383,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 +393,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 +425,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 +447,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 +490,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 +501,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++; }
+ void restore() { if (mSuspended) mSuspended--; }
+ 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 +520,122 @@ private:
bool mute;
};
- private:
+ protected:
+ int mType;
+ int16_t* mMixBuffer;
+ int mSuspended;
+ int mBytesWritten;
+ bool mMasterMute;
+ SortedVector< wp<Track> > mActiveTracks;
+
+ virtual int getTrackName_l() = 0;
+ virtual void deleteTrackName_l(int name) = 0;
+ virtual uint32_t getMaxBufferRecoveryInUsecs() = 0;
+ private:
friend class AudioFlinger;
+ friend class OutputTrack;
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();
- status_t dumpInternals(int fd, const Vector<String16>& args);
+ void readOutputParameters();
+
+ 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 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);
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual uint32_t getMaxBufferRecoveryInUsecs();
+
+ AudioMixer* mAudioMixer;
+ };
+
+ class DirectOutputThread : public PlaybackThread {
+ public:
+
+ DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ ~DirectOutputThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ virtual bool checkForNewParameters_l();
+
+ protected:
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual uint32_t getMaxBufferRecoveryInUsecs();
+
+ 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(int output) const;
+ MixerThread *checkMixerThread_l(int output) const;
+ RecordThread *checkRecordThread_l(int input) const;
+ float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
+ void audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2);
+
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 +647,92 @@ 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_l(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; }
+
+ void dump(char* buffer, size_t size);
+ 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();
- void removeClient(pid_t pid);
+ 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 +740,31 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::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;
+ sp<RecordThread::RecordTrack> mRecordTrack;
};
- friend class AudioRecordThread;
- friend class MixerThread;
+ friend class RecordThread;
+ friend class PlaybackThread;
- 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;
+
+
+ DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads;
+ PlaybackThread::stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ float mMasterVolume;
+ bool mMasterMute;
+
+ DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
+
+ SortedVector< sp<IBinder> > mNotificationClients;
+ int mNextThreadId;
};
// ----------------------------------------------------------------------------
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..9a4a7f9 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;
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
}
-
// 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..ae391ee 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,29 +145,31 @@ 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());
return NO_ERROR;
}
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
-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 +185,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);
@@ -187,6 +193,12 @@ status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index bf63cc5..583f852 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);
};
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);
};
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..8cfc204
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
@@ -0,0 +1,945 @@
+/*
+ * 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, channels %x, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, 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 = mTestChannels;
+ 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);
+ if (mTestOutputs[mCurOutput]) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"),mCurOutput);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+ 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 0;
+ }
+
+ return mHardwareOutput;
+}
+
+status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("startOutput() output %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("startOutput() unknow output %d", 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 %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("stopOutput() unknow output %d", 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 %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
+{
+ LOGV("releaseOutput() %d", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("releaseOutput() releasing unknown output %d", 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 0;
+ }
+ mInputs.add(input, inputDesc);
+ return input;
+}
+
+status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
+{
+ LOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("startInput() unknow input %d", 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 %d, other input %d 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 %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("stopInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ LOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ inputDesc->mRefCount = 0;
+ return NO_ERROR;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
+{
+ LOGV("releaseInput() %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("releaseInput() releasing unknown input %d", 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 %d 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;
+}
+
+status_t AudioPolicyManagerGeneric::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mOutputs.valueAt(i)->dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nInputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mInputs.valueAt(i)->dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nStreams dump:\n");
+ write(fd, buffer, strlen(buffer));
+ snprintf(buffer, SIZE, " Stream Index Min Index Max Index Cur Mute Count Can be muted\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ snprintf(buffer, SIZE, " %02d", i);
+ mStreams[i].dump(buffer + 3, SIZE);
+ write(fd, buffer, strlen(buffer));
+ }
+
+ 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
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+
+ mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ 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())
+ {
+ String8 command;
+ int valueInt;
+ String8 value;
+
+ Mutex::Autolock _l(mLock);
+ mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+ command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+ AudioParameter param = AudioParameter(command);
+
+ if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+ valueInt != 0) {
+ LOGV("Test command %s received", command.string());
+ String8 target;
+ if (param.get(String8("target"), target) != NO_ERROR) {
+ target = "Manager";
+ }
+ 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"));
+ int format = AudioSystem::INVALID_FORMAT;
+ if (value == "PCM 16 bits") {
+ format = AudioSystem::PCM_16_BIT;
+ } else if (value == "PCM 8 bits") {
+ format = AudioSystem::PCM_8_BIT;
+ } else if (value == "Compressed MP3") {
+ format = AudioSystem::MP3;
+ }
+ if (format != AudioSystem::INVALID_FORMAT) {
+ if (target == "Manager") {
+ mTestFormat = format;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("format"), format);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_channels"));
+ int channels = 0;
+
+ if (value == "Channels Stereo") {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
+ } else if (value == "Channels Mono") {
+ channels = AudioSystem::CHANNEL_OUT_MONO;
+ }
+ if (channels != 0) {
+ if (target == "Manager") {
+ mTestChannels = channels;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("channels"), channels);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_sampleRate"));
+ if (valueInt >= 0 && valueInt <= 96000) {
+ int samplingRate = valueInt;
+ if (target == "Manager") {
+ mTestSamplingRate = samplingRate;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("sampling_rate"), samplingRate);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+
+ if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_reopen"));
+
+ mpClientInterface->closeOutput(mHardwareOutput);
+ delete mOutputs.valueFor(mHardwareOutput);
+ mOutputs.removeItem(mHardwareOutput);
+
+ 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 reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+ }
+
+
+ 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 %d", 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;
+}
+
+status_t AudioPolicyManagerGeneric::AudioOutputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Stream refCount\n");
+ result.append(buffer);
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ snprintf(buffer, SIZE, " %02d %d\n", i, mRefCount[i]);
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
+{
+}
+
+status_t AudioPolicyManagerGeneric::AudioInputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- StreamDescriptor class implementation
+
+void AudioPolicyManagerGeneric::StreamDescriptor::dump(char* buffer, size_t size)
+{
+ snprintf(buffer, size, " %02d %02d %02d %02d %d\n",
+ mIndexMin,
+ mIndexMax,
+ mIndexCur,
+ mMuteCount,
+ mCanBeMuted);
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
new file mode 100644
index 0000000..4997cdf
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.h
@@ -0,0 +1,196 @@
+/*
+ * 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);
+
+ virtual status_t dump(int fd);
+
+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();
+
+ status_t dump(int fd);
+
+ 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();
+
+ status_t dump(int fd);
+
+ 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) {}
+
+ void dump(char* buffer, size_t size);
+
+ 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 mTestChannels;
+ 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..aa48019
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -0,0 +1,911 @@
+/*
+ * 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
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include <sys/time.h>
+#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 const char* kDeadlockedString = "AudioPolicyService may be deadlocked\n";
+static const char* kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n";
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+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
+ mTonePlaybackThread = 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()
+{
+ mTonePlaybackThread->exit();
+ mTonePlaybackThread.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 0;
+ }
+ 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 0;
+ }
+ 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());
+}
+
+static bool tryLock(Mutex& mutex)
+{
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
+status_t AudioPolicyService::dumpInternals(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "PolicyManager Interface: %p\n", mpPolicyManager);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Command Thread: %p\n", mAudioCommandThread.get());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Tones Thread: %p\n", mTonePlaybackThread.get());
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd);
+ } else {
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ String8 result(kDeadlockedString);
+ write(fd, result.string(), result.size());
+ }
+
+ dumpInternals(fd);
+ if (mAudioCommandThread != NULL) {
+ mAudioCommandThread->dump(fd);
+ }
+ if (mTonePlaybackThread != NULL) {
+ mTonePlaybackThread->dump(fd);
+ }
+
+ if (mpPolicyManager) {
+ mpPolicyManager->dump(fd);
+ }
+
+ if (locked) mLock.unlock();
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::dumpPermissionDenial(int fd)
+{
+ 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 0;
+ }
+
+ 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 0;
+ }
+ 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 0;
+ }
+
+ 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, int delayMs)
+{
+ return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
+}
+
+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, int delayMs)
+{
+ mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs);
+}
+
+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)
+{
+ mTonePlaybackThread->startToneCommand(tone, stream);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::stopTone()
+{
+ mTonePlaybackThread->stopToneCommand();
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setVoiceVolume(float volume, int delayMs)
+{
+ return mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
+}
+
+// ----------- 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()
+{
+ nsecs_t waitTime = INT64_MAX;
+
+ mLock.lock();
+ while (!exitPending())
+ {
+ while(!mAudioCommands.isEmpty()) {
+ nsecs_t curTime = systemTime();
+ // commands are sorted by increasing time stamp: execute them from index 0 and up
+ if (mAudioCommands[0]->mTime <= curTime) {
+ AudioCommand *command = mAudioCommands[0];
+ mAudioCommands.removeAt(0);
+ mLastCommand = *command;
+
+ 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 %d", data->mStream, data->mVolume, data->mIO);
+ command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
+ command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ case SET_VOICE_VOLUME: {
+ VoiceVolumeData *data = (VoiceVolumeData *)command->mParam;
+ LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume);
+ command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ default:
+ LOGW("AudioCommandThread() unknown command %d", command->mCommand);
+ }
+ delete command;
+ waitTime = INT64_MAX;
+ } else {
+ waitTime = mAudioCommands[0]->mTime - curTime;
+ break;
+ }
+ }
+ LOGV("AudioCommandThread() going to sleep");
+ mWaitWorkCV.waitRelative(mLock, waitTime);
+ LOGV("AudioCommandThread() waking up");
+ }
+ mLock.unlock();
+ return false;
+}
+
+status_t AudioPolicyService::AudioCommandThread::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "AudioCommandThread %p Dump\n", this);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ String8 result2(kCmdDeadlockedString);
+ write(fd, result2.string(), result2.size());
+ }
+
+ snprintf(buffer, SIZE, "- Commands:\n");
+ result = String8(buffer);
+ result.append(" Command Time Wait pParam\n");
+ for (int i = 0; i < (int)mAudioCommands.size(); i++) {
+ mAudioCommands[i]->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ result.append(" Last Command\n");
+ mLastCommand.dump(buffer, SIZE);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+
+ if (locked) mLock.unlock();
+
+ return NO_ERROR;
+}
+
+void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stream)
+{
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = START_TONE;
+ ToneData *data = new ToneData();
+ data->mType = type;
+ data->mStream = stream;
+ command->mParam = (void *)data;
+ command->mWaitStatus = false;
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command);
+ LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
+ mWaitWorkCV.signal();
+}
+
+void AudioPolicyService::AudioCommandThread::stopToneCommand()
+{
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = STOP_TONE;
+ command->mParam = NULL;
+ command->mWaitStatus = false;
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command);
+ LOGV("AudioCommandThread() adding tone stop");
+ mWaitWorkCV.signal();
+}
+
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_VOLUME;
+ VolumeData *data = new VolumeData();
+ data->mStream = stream;
+ data->mVolume = volume;
+ data->mIO = output;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_PARAMETERS;
+ ParametersData *data = new ParametersData();
+ data->mIO = ioHandle;
+ data->mKeyValuePairs = keyValuePairs;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_VOICE_VOLUME;
+ VoiceVolumeData *data = new VoiceVolumeData();
+ data->mVolume = volume;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set voice volume volume %f", volume);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+
+// insertCommand_l() must be called with mLock held
+void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
+{
+ ssize_t i;
+ Vector <AudioCommand *> removedCommands;
+
+ command->mTime = systemTime() + milliseconds(delayMs);
+
+ // check same pending commands with later time stamps and eliminate them
+ for (i = mAudioCommands.size()-1; i >= 0; i--) {
+ AudioCommand *command2 = mAudioCommands[i];
+ // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
+ if (command2->mTime <= command->mTime) break;
+ if (command2->mCommand != command->mCommand) continue;
+
+ switch (command->mCommand) {
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ ParametersData *data2 = (ParametersData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
+ AudioParameter param = AudioParameter(data->mKeyValuePairs);
+ AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
+ for (size_t j = 0; j < param.size(); j++) {
+ String8 key;
+ String8 value;
+ param.getAt(j, key, value);
+ for (size_t k = 0; k < param2.size(); k++) {
+ String8 key2;
+ String8 value2;
+ param2.getAt(k, key2, value2);
+ if (key2 == key) {
+ param2.remove(key2);
+ LOGV("Filtering out parameter %s", key2.string());
+ break;
+ }
+ }
+ }
+ // if all keys have been filtered out, remove the command.
+ // otherwise, update the key value pairs
+ if (param2.size() == 0) {
+ removedCommands.add(command2);
+ } else {
+ data2->mKeyValuePairs = param2.toString();
+ }
+ } break;
+
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ VolumeData *data2 = (VolumeData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ if (data->mStream != data2->mStream) break;
+ LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream);
+ removedCommands.add(command2);
+ } break;
+ case START_TONE:
+ case STOP_TONE:
+ default:
+ break;
+ }
+ }
+
+ // remove filtered commands
+ for (size_t j = 0; j < removedCommands.size(); j++) {
+ // removed commands always have time stamps greater than current command
+ for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
+ if (mAudioCommands[k] == removedCommands[j]) {
+ LOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
+ mAudioCommands.removeAt(k);
+ break;
+ }
+ }
+ }
+ removedCommands.clear();
+
+ // insert command at the right place according to its time stamp
+ LOGV("inserting command: %d at index %ld, num commands %d", command->mCommand, i+1, mAudioCommands.size());
+ mAudioCommands.insertAt(command, i + 1);
+}
+
+void AudioPolicyService::AudioCommandThread::exit()
+{
+ LOGV("AudioCommandThread::exit");
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+void AudioPolicyService::AudioCommandThread::AudioCommand::dump(char* buffer, size_t size)
+{
+ snprintf(buffer, size, " %02d %06d.%03d %01u %p\n",
+ mCommand,
+ (int)ns2s(mTime),
+ (int)ns2ms(mTime)%1000,
+ mWaitStatus,
+ mParam);
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
new file mode 100644
index 0000000..b9234ec
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -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.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYSERVICE_H
+#define ANDROID_AUDIOPOLICYSERVICE_H
+
+#include <media/IAudioPolicyService.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <media/ToneGenerator.h>
+#include <utils/Vector.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, int delayMs = 0);
+ virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
+ 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();
+ virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+
+private:
+ AudioPolicyService();
+ virtual ~AudioPolicyService();
+
+ status_t dumpInternals(int fd);
+
+ // 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 {
+ class AudioCommand;
+ public:
+
+ // commands for tone AudioCommand
+ enum {
+ START_TONE,
+ STOP_TONE,
+ SET_VOLUME,
+ SET_PARAMETERS,
+ SET_VOICE_VOLUME
+ };
+
+ AudioCommandThread ();
+ virtual ~AudioCommandThread();
+
+ status_t dump(int fd);
+
+ // 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, int output, int delayMs = 0);
+ status_t parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs = 0);
+ status_t voiceVolumeCommand(float volume, int delayMs = 0);
+ void insertCommand_l(AudioCommand *command, int delayMs = 0);
+
+ private:
+ // descriptor for requested tone playback event
+ class AudioCommand {
+
+ public:
+ AudioCommand()
+ : mCommand(-1) {}
+
+ void dump(char* buffer, size_t size);
+
+ int mCommand; // START_TONE, STOP_TONE ...
+ nsecs_t mTime; // time stamp
+ Condition mCond; // condition for status return
+ status_t mStatus; // command status
+ bool mWaitStatus; // true if caller is waiting for status
+ void *mParam; // command parameter (ToneData, VolumeData, ParametersData)
+ };
+
+ class ToneData {
+ public:
+ int mType; // tone type (START_TONE only)
+ int mStream; // stream type (START_TONE only)
+ };
+
+ class VolumeData {
+ public:
+ int mStream;
+ float mVolume;
+ int mIO;
+ };
+
+ class ParametersData {
+ public:
+ int mIO;
+ String8 mKeyValuePairs;
+ };
+
+ class VoiceVolumeData {
+ public:
+ float mVolume;
+ };
+
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ Vector <AudioCommand *> mAudioCommands; // list of pending commands
+ ToneGenerator *mpToneGenerator; // the tone generator
+ AudioCommand mLastCommand;
+ };
+
+ // Internal dump utilities.
+ status_t dumpPermissionDenial(int fd);
+
+
+ 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> mTonePlaybackThread; // tone playback thread
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYSERVICE_H
+
+
+
+
+
+
+
+
diff --git a/cmds/keystore/tests/Android.mk b/libs/binder/Android.mk
index 33541cc..2df6775 100644
--- a/cmds/keystore/tests/Android.mk
+++ b/libs/binder/Android.mk
@@ -11,18 +11,35 @@
# 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 the KEYSTORE_TESTS environment variable to build the test programs
-ifdef KEYSTORE_TESTS
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c
-LOCAL_SHARED_LIBRARIES := libcutils libssl
-LOCAL_MODULE:= netkeystore_test
-LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := external/openssl/include \
- frameworks/base/cmds/keystore
-EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING
-include $(BUILD_EXECUTABLE)
-endif #KEYSTORE_TESTS
+# 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..b2a7db8 100644
--- a/libs/utils/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-#include <utils/IPCThreadState.h>
+#define LOG_TAG "IPCThreadState"
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
+#include <binder/IPCThreadState.h>
+
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <cutils/sched_policy.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 +369,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()
@@ -423,9 +421,26 @@ void IPCThreadState::joinThreadPool(bool isMain)
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
+
+
result = executeCommand(cmd);
}
+ // After executing the command, ensure that the thread is returned to the
+ // default cgroup and priority before rejoining the pool. This is a failsafe
+ // in case the command implementation failed to properly restore the thread's
+ // scheduling parameters upon completion.
+ int my_id;
+#ifdef HAVE_GETTID
+ my_id = gettid();
+#else
+ my_id = getpid();
+#endif
+ if (!set_sched_policy(my_id, SP_FOREGROUND)) {
+ // success; reset the priority as well
+ setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
+ }
+
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
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..624f7eb 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>
@@ -67,7 +67,11 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(0), mNeedUnmap(false)
{
- int fd = open(device, O_RDWR);
+ int open_flags = O_RDWR;
+ if (flags & NO_CACHING)
+ open_flags |= O_SYNC;
+
+ int fd = open(device, open_flags);
LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
if (fd >= 0) {
const size_t pagesize = getpagesize();
@@ -78,13 +82,13 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
}
}
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(0), mNeedUnmap(false)
{
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- mapfd(dup(fd), size);
+ mapfd(dup(fd), size, offset);
}
status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
@@ -100,7 +104,7 @@ status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const cha
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
{
if (size == 0) {
// try to figure out the size automatically
@@ -121,7 +125,7 @@ status_t MemoryHeapBase::mapfd(int fd, size_t size)
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
void* base = (uint8_t*)mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
LOGE("mmap(fd=%d, size=%u) failed (%s)",
fd, uint32_t(size), strerror(errno));
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index eba2b30..c660947 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;
@@ -132,7 +132,7 @@ MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
char const * const device = pmemHeap->getDevice();
#if HAVE_ANDROID_OS
if (device) {
- int fd = open(device, O_RDWR);
+ int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0));
LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
if (fd >= 0) {
int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
diff --git a/libs/utils/Parcel.cpp b/libs/binder/Parcel.cpp
index b0e3750..e397bce 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 {
@@ -557,54 +562,27 @@ restart_write:
status_t Parcel::writeInt32(int32_t val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int32_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeInt64(int64_t val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int64_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeFloat(float val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<float*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeDouble(double val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<double*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
+ return writeAligned(val);
+}
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+status_t Parcel::writeIntPtr(intptr_t val)
+{
+ return writeAligned(val);
}
status_t Parcel::writeCString(const char* str)
@@ -656,7 +634,7 @@ status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
status_t Parcel::writeNativeHandle(const native_handle* handle)
{
- if (handle->version != sizeof(native_handle))
+ if (!handle || handle->version != sizeof(native_handle))
return BAD_TYPE;
status_t err;
@@ -763,103 +741,98 @@ const void* Parcel::readInplace(size_t len) const
return NULL;
}
-status_t Parcel::readInt32(int32_t *pArg) const
-{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+template<class T>
+status_t Parcel::readAligned(T *pArg) const {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(T)) <= mDataSize) {
const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- *pArg = *reinterpret_cast<const int32_t*>(data);
+ mDataPos += sizeof(T);
+ *pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
}
}
+template<class T>
+T Parcel::readAligned() const {
+ T result;
+ if (readAligned(&result) != NO_ERROR) {
+ result = 0;
+ }
+
+ return result;
+}
+
+template<class T>
+status_t Parcel::writeAligned(T val) {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<T*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::readInt32(int32_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
int32_t Parcel::readInt32() const
{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int32_t*>(data);
- }
- return 0;
+ return readAligned<int32_t>();
}
status_t Parcel::readInt64(int64_t *pArg) const
{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- *pArg = *reinterpret_cast<const int64_t*>(data);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
int64_t Parcel::readInt64() const
{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int64_t*>(data);
- }
- return 0;
+ return readAligned<int64_t>();
}
status_t Parcel::readFloat(float *pArg) const
{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const float*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
float Parcel::readFloat() const
{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const float*>(data);
- }
- return 0;
+ return readAligned<float>();
}
status_t Parcel::readDouble(double *pArg) const
{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const double*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
double Parcel::readDouble() const
{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const double*>(data);
- }
- return 0;
+ return readAligned<double>();
+}
+
+status_t Parcel::readIntPtr(intptr_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+intptr_t Parcel::readIntPtr() const
+{
+ return readAligned<intptr_t>();
}
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/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index ec5aa3f..eb51c22 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -5,44 +5,50 @@ LOCAL_SRC_FILES:= \
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- GPUHardware/GPUHardware.cpp \
BlurFilter.cpp.arm \
- CPUGauge.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
+ifeq ($(TARGET_BOARD_PLATFORM), qsd8k)
+ 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/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
index 5dc0ba0..1ffbd5b 100644
--- a/libs/surfaceflinger/BlurFilter.cpp
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -111,6 +111,50 @@ struct BlurColor565
}
};
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+ typedef uint32_t type;
+ int r, g, b;
+ inline BlurColor888X() { }
+ inline BlurColor888X(uint32_t v) {
+ v = BLUR_RGBA_TO_HOST(v);
+ r = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ b = (v >> 16) & 0xFF;
+ }
+ inline void clear() { r=g=b=0; }
+ inline uint32_t to(int shift, int last, int dither) const {
+ int R = r;
+ int G = g;
+ int B = b;
+ if (UNLIKELY(last)) {
+ if (FACTOR>0) {
+ int L = (R+G+G+B)>>2;
+ R += ((L - R) * FACTOR) >> 8;
+ G += ((L - G) * FACTOR) >> 8;
+ B += ((L - B) * FACTOR) >> 8;
+ }
+ }
+ R >>= shift;
+ G >>= shift;
+ B >>= shift;
+ return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+ }
+ inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+ r += rhs.r;
+ g += rhs.g;
+ b += rhs.b;
+ return *this;
+ }
+ inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+ r -= rhs.r;
+ g -= rhs.g;
+ b -= rhs.b;
+ return *this;
+ }
+};
+
struct BlurGray565
{
typedef uint16_t type;
@@ -316,7 +360,13 @@ status_t blurFilter(
int kernelSizeUser,
int repeat)
{
- return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+ status_t err = BAD_VALUE;
+ if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+ err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+ } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+ err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+ }
+ return err;
}
} // namespace android
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 ab02fa0..1abfd68 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,63 +21,50 @@
#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 <ui/EGLUtils.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;
-static __attribute__((noinline))
-const char *egl_strerror(EGLint err)
-{
- switch (err){
- case EGL_SUCCESS: return "EGL_SUCCESS";
- case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
- case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
- case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
- case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
- case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
- case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
- case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
- case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
- case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
- case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
- default: return "UNKNOWN";
- }
-}
static __attribute__((noinline))
void checkGLErrors()
{
- GLenum error = glGetError();
- if (error != GL_NO_ERROR)
+ do {
+ // there could be more than one error flag
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR)
+ break;
LOGE("GL error 0x%04x", int(error));
+ } while(true);
}
static __attribute__((noinline))
void checkEGLErrors(const char* token)
{
EGLint error = eglGetError();
- // GLESonGL seems to be returning 0 when there is no errors?
- if (error && error != EGL_SUCCESS)
- LOGE("%s error 0x%04x (%s)",
- token, int(error), egl_strerror(error));
+ if (error && error != EGL_SUCCESS) {
+ LOGE("%s: EGL error 0x%04x (%s)",
+ token, int(error), EGLUtils::strerror(error));
+ }
}
-
/*
* Initialize the display to the specified values.
*
@@ -108,20 +93,37 @@ PixelFormat DisplayHardware::getFormat() const { return mFormat; }
void DisplayHardware::init(uint32_t dpy)
{
+ mNativeWindow = new FramebufferNativeWindow();
+ framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+
+ mOverlayEngine = NULL;
+ hw_module_t const* module;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+
// initialize EGL
- const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 0,
+ EGLint attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE, 0,
EGL_NONE
};
+
+ // debug: disable h/w rendering
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.sf.hw", property, NULL) > 0) {
+ if (atoi(property) == 0) {
+ LOGW("H/W composition disabled");
+ attribs[2] = EGL_CONFIG_CAVEAT;
+ attribs[3] = EGL_SLOW_CONFIG;
+ }
+ }
+
EGLint w, h, dummy;
- EGLint numConfigs, n;
- EGLConfig config;
+ EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
- mFlags = 0;
+ mFlags = CACHED_BUFFERS;
// TODO: all the extensions below should be queried through
// eglGetProcAddress().
@@ -129,7 +131,17 @@ 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);
+
+ EGLConfig config;
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ display, attribs, mNativeWindow.get(), &config);
+ LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
/*
* Gather EGL extensions
@@ -144,13 +156,13 @@ void DisplayHardware::init(uint32_t dpy)
LOGI("version : %s", eglQueryString(display, EGL_VERSION));
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;
+ LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
- // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
- mFlags |= UPDATE_ON_DEMAND;
+ if (mNativeWindow->isUpdateOnDemand()) {
+ mFlags |= PARTIAL_UPDATES;
+ }
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -160,37 +172,48 @@ void DisplayHardware::init(uint32_t dpy)
* Create our main surface
*/
- mDisplaySurface = new EGLDisplaySurface();
+ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
- surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
- //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+ if (mFlags & PARTIAL_UPDATES) {
+ // if we have partial updates, we definitely don't need to
+ // preserve the backbuffer, which may be costly.
+ eglSurfaceAttrib(display, surface,
+ EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
+ }
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;
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
+ if (eglSetSwapRectangleANDROID(display, surface,
+ 0, 0, mWidth, mHeight) == EGL_TRUE) {
+ // This could fail if this extension is not supported by this
+ // specific surface (of config)
+ mFlags |= SWAP_RECTANGLE;
+ }
}
- mRefreshRate = 60.f; // TODO: get the real refresh rate
+ // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
+ // choose PARTIAL_UPDATES, which should be more efficient
+ if (mFlags & PARTIAL_UPDATES)
+ mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+ LOGI("flags : %08x", mFlags);
+
+ mDpiX = mNativeWindow->xdpi;
+ mDpiY = mNativeWindow->ydpi;
+ mRefreshRate = fbDev->fps;
- char property[PROPERTY_VALUE_MAX];
/* Read density from build-specific ro.sf.lcd_density property
- * except if it is overriden by qemu.sf.lcd_density.
+ * except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
@@ -209,11 +232,6 @@ void DisplayHardware::init(uint32_t dpy)
*/
context = eglCreateContext(display, config, NULL, NULL);
- //checkEGLErrors("eglCreateContext");
-
- eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
- eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
-
/*
* Gather OpenGL ES extensions
@@ -221,21 +239,33 @@ void DisplayHardware::init(uint32_t dpy)
eglMakeCurrent(display, surface, surface, context);
const char* const gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+ const char* const gl_renderer = (const char*)glGetString(GL_RENDERER);
LOGI("OpenGL informations:");
LOGI("vendor : %s", glGetString(GL_VENDOR));
- LOGI("renderer : %s", glGetString(GL_RENDERER));
+ LOGI("renderer : %s", gl_renderer);
LOGI("version : %s", glGetString(GL_VERSION));
LOGI("extensions: %s", gl_extensions);
+ if (strstr(gl_renderer, "PowerVR SGX 530")) {
+ LOGD("Assuming uncached graphics buffers.");
+ mFlags &= ~CACHED_BUFFERS;
+ }
if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
mFlags |= NPOT_EXTENSION;
}
if (strstr(gl_extensions, "GL_OES_draw_texture")) {
mFlags |= DRAW_TEXTURE_EXTENSION;
}
- if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+#ifdef EGL_ANDROID_image_native_buffer
+ 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;
}
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -244,19 +274,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;
}
/*
@@ -270,7 +289,6 @@ void DisplayHardware::fini()
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- copybit_close(mBlitEngine);
overlay_control_close(mOverlayEngine);
}
@@ -284,33 +302,13 @@ 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;
}
-/*
- * "Flip" the front and back buffers.
- */
+status_t DisplayHardware::compositionComplete() const {
+ return mNativeWindow->compositionComplete();
+}
void DisplayHardware::flip(const Region& dirty) const
{
@@ -319,21 +317,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 & PARTIAL_UPDATES) {
+ mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
-
+
+ mPageFlipCount++;
eglSwapBuffers(dpy, surface);
checkEGLErrors("eglSwapBuffers");
@@ -351,11 +348,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..6914d0c 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,31 +22,36 @@
#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
+ PARTIAL_UPDATES = 0x00020000, // video driver feature
SLOW_CONFIG = 0x00040000, // software
+ SWAP_RECTANGLE = 0x00080000,
+ CACHED_BUFFERS = 0x00100000
};
DisplayHardware(
@@ -73,15 +78,11 @@ 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;
-
+ status_t compositionComplete() const;
+
Rect bounds() const {
return Rect(mWidth, mHeight);
}
@@ -102,9 +103,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/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
deleted file mode 100644
index 7168bf2..0000000
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ /dev/null
@@ -1,585 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#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 <utils/StopWatch.h>
-
-#include <ui/ISurfaceComposer.h>
-
-#include "VRamHeap.h"
-#include "GPUHardware.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include "GPUHardware/GPUHardware.h"
-
-
-/*
- * Manage the GPU. This implementation is very specific to the G1.
- * There are no abstraction here.
- *
- * All this code will soon go-away and be replaced by a new architecture
- * for managing graphics accelerators.
- *
- * In the meantime, it is conceptually possible to instantiate a
- * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
- * of this file); practically... doubtful.
- *
- */
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class GPUClientHeap;
-class GPUAreaHeap;
-
-class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
-{
-public:
- static const int GPU_RESERVED_SIZE;
- static const int GPUR_SIZE;
-
- GPUHardware();
- virtual ~GPUHardware();
-
- virtual void revoke(int pid);
- virtual sp<MemoryDealer> request(int pid);
- virtual status_t request(int pid,
- const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu);
-
- virtual status_t friendlyRevoke();
- virtual void unconditionalRevoke();
-
- virtual pid_t getOwner() const { return mOwner; }
-
- // used for debugging only...
- virtual sp<SimpleBestFitAllocator> getAllocator() const;
-
-private:
-
-
- enum {
- NO_OWNER = -1,
- };
-
- struct GPUArea {
- sp<GPUAreaHeap> heap;
- sp<MemoryHeapPmem> clientHeap;
- sp<IMemory> map();
- };
-
- struct Client {
- pid_t pid;
- GPUArea smi;
- GPUArea ebi;
- GPUArea reg;
- void createClientHeaps();
- void revokeAllHeaps();
- };
-
- Client& getClientLocked(pid_t pid);
- status_t requestLocked(int pid);
- void releaseLocked();
- void takeBackGPULocked();
- void registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client);
-
- virtual void binderDied(const wp<IBinder>& who);
-
- mutable Mutex mLock;
- sp<GPUAreaHeap> mSMIHeap;
- sp<GPUAreaHeap> mEBIHeap;
- sp<GPUAreaHeap> mREGHeap;
-
- KeyedVector<pid_t, Client> mClients;
- DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
-
- pid_t mOwner;
-
- sp<MemoryDealer> mCurrentAllocator;
- sp<IGPUCallback> mCallback;
-
- sp<SimpleBestFitAllocator> mAllocator;
-
- Condition mCondition;
-};
-
-// size reserved for GPU surfaces
-// 1200 KB fits exactly:
-// - two 320*480 16-bits double-buffered surfaces
-// - one 320*480 32-bits double-buffered surface
-// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
-const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
-const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
-
-// ---------------------------------------------------------------------------
-
-/*
- * GPUHandle is a special IMemory given to the client. It represents their
- * handle to the GPU. Once they give it up, they loose GPU access, or if
- * they explicitly revoke their access through the binder code 1000.
- * In both cases, this triggers a callback to revoke()
- * first, and then actually powers down the chip.
- *
- * In the case of a misbehaving app, GPUHardware can ask for an immediate
- * release of the GPU to the target process which should answer by calling
- * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
- * be revoked from under their feet.
- *
- * We should never hold a strong reference on GPUHandle. In practice this
- * shouldn't be a big issue though because clients should use code 1000 and
- * not rely on the dtor being called.
- *
- */
-
-class GPUClientHeap : public MemoryHeapPmem
-{
-public:
- GPUClientHeap(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : MemoryHeapPmem(heap), mGPU(gpu) { }
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPUAreaHeap : public MemoryHeapBase
-{
-public:
- GPUAreaHeap(const wp<GPUHardware>& gpu,
- const char* const vram, size_t size=0, size_t reserved=0)
- : MemoryHeapBase(vram, size), mGPU(gpu) {
- if (base() != MAP_FAILED) {
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
- }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new GPUClientHeap(mGPU, parentHeap);
- }
- virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
- return mAllocator;
- }
-private:
- sp<SimpleBestFitAllocator> mAllocator;
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPURegisterHeap : public GPUAreaHeap
-{
-public:
- GPURegisterHeap(const sp<GPUHardware>& gpu)
- : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapRegs(mGPU, parentHeap);
- }
-private:
- class MemoryHeapRegs : public GPUClientHeap {
- public:
- MemoryHeapRegs(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : GPUClientHeap(gpu, heap) { }
- sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
- virtual void revoke();
- private:
- class GPUHandle : public MemoryHeapPmem::MemoryPmem {
- public:
- GPUHandle(const sp<GPUHardware>& gpu,
- const sp<MemoryHeapPmem>& heap)
- : MemoryHeapPmem::MemoryPmem(heap),
- mGPU(gpu), mOwner(gpu->getOwner()) { }
- virtual ~GPUHandle();
- virtual sp<IMemoryHeap> getMemory(
- ssize_t* offset, size_t* size) const;
- virtual void revoke() { };
- virtual status_t onTransact(
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- private:
- void revokeNotification();
- wp<GPUHardware> mGPU;
- pid_t mOwner;
- };
- };
-};
-
-GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
- //LOGD("GPUHandle %p released, revoking GPU", this);
- revokeNotification();
-}
-void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
- sp<GPUHardware> hw(mGPU.promote());
- if (hw != 0) {
- hw->revoke(mOwner);
- }
-}
-sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
- ssize_t* offset, size_t* size) const
-{
- sp<MemoryHeapPmem> heap = getHeap();
- if (offset) *offset = 0;
- if (size) *size = heap !=0 ? heap->virtualSize() : 0;
- return heap;
-}
-status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- status_t err = BnMemory::onTransact(code, data, reply, flags);
- if (err == UNKNOWN_TRANSACTION && code == 1000) {
- int callingPid = IPCThreadState::self()->getCallingPid();
- //LOGD("pid %d voluntarily revoking gpu", callingPid);
- if (callingPid == mOwner) {
- revokeNotification();
- // we've revoked the GPU, don't do it again later when we
- // are destroyed.
- mGPU.clear();
- } else {
- LOGW("%d revoking someone else's gpu? (owner=%d)",
- callingPid, mOwner);
- }
- err = NO_ERROR;
- }
- return err;
-}
-
-// ---------------------------------------------------------------------------
-
-
-sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
- size_t offset, size_t size)
-{
- sp<GPUHandle> memory;
- sp<GPUHardware> gpu = mGPU.promote();
- if (heapID()>0 && gpu!=0) {
-#if HAVE_ANDROID_OS
- /* this is where the GPU is powered on and the registers are mapped
- * in the client */
- //LOGD("ioctl(HW3D_GRANT_GPU)");
- int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
- if (err) {
- // it can happen if the master heap has been closed already
- // in which case the GPU already is revoked (app crash for
- // instance).
- LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
- memory = new GPUHandle(gpu, this);
-#endif
- }
- return memory;
-}
-
-void GPURegisterHeap::MemoryHeapRegs::revoke()
-{
- MemoryHeapPmem::revoke();
-#if HAVE_ANDROID_OS
- if (heapID() > 0) {
- //LOGD("ioctl(HW3D_REVOKE_GPU)");
- int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
- LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
-#endif
-}
-
-/*****************************************************************************/
-
-GPUHardware::GPUHardware()
- : mOwner(NO_OWNER)
-{
-}
-
-GPUHardware::~GPUHardware()
-{
-}
-
-status_t GPUHardware::requestLocked(int pid)
-{
- const int self_pid = getpid();
- if (pid == self_pid) {
- // can't use GPU from surfaceflinger's process
- return PERMISSION_DENIED;
- }
-
- if (mOwner != pid) {
- if (mREGHeap != 0) {
- if (mOwner != NO_OWNER) {
- // someone already has the gpu.
- takeBackGPULocked();
- releaseLocked();
- }
- } else {
- // first time, initialize the stuff.
- if (mSMIHeap == 0)
- mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
- if (mEBIHeap == 0)
- mEBIHeap = new GPUAreaHeap(this,
- "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
- mREGHeap = new GPURegisterHeap(this);
- mAllocator = mEBIHeap->getAllocator();
- if (mAllocator == NULL) {
- // something went terribly wrong.
- mSMIHeap.clear();
- mEBIHeap.clear();
- mREGHeap.clear();
- return INVALID_OPERATION;
- }
- }
- Client& client = getClientLocked(pid);
- mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
- mOwner = pid;
- }
- return NO_ERROR;
-}
-
-sp<MemoryDealer> GPUHardware::request(int pid)
-{
- sp<MemoryDealer> dealer;
- Mutex::Autolock _l(mLock);
- Client* client;
- LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
- if (requestLocked(pid) == NO_ERROR) {
- dealer = mCurrentAllocator;
- LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
- }
- return dealer;
-}
-
-status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu)
-{
- if (callback == 0)
- return BAD_VALUE;
-
- sp<IMemory> gpuHandle;
- LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
- Mutex::Autolock _l(mLock);
- status_t err = requestLocked(pid);
- if (err == NO_ERROR) {
- // it's guaranteed to be there, be construction
- Client& client = mClients.editValueFor(pid);
- registerCallbackLocked(callback, client);
- gpu->count = 2;
- gpu->regions[0].region = client.smi.map();
- gpu->regions[1].region = client.ebi.map();
- gpu->regs = client.reg.map();
- gpu->regions[0].reserved = 0;
- gpu->regions[1].reserved = GPU_RESERVED_SIZE;
- if (gpu->regs != 0) {
- //LOGD("gpu core granted to pid %d, handle base=%p",
- // mOwner, gpu->regs->pointer());
- }
- mCallback = callback;
- } else {
- LOGW("couldn't grant gpu core to pid %d", pid);
- }
- return err;
-}
-
-void GPUHardware::revoke(int pid)
-{
- Mutex::Autolock _l(mLock);
- if (mOwner > 0) {
- if (pid != mOwner) {
- LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
- return;
- }
- //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
- // mOwner could be <0 if the same process acquired the GPU
- // several times without releasing it first.
- mCondition.signal();
- releaseLocked();
- }
-}
-
-status_t GPUHardware::friendlyRevoke()
-{
- Mutex::Autolock _l(mLock);
- //LOGD("friendlyRevoke owner=%d", mOwner);
- takeBackGPULocked();
- releaseLocked();
- return NO_ERROR;
-}
-
-void GPUHardware::takeBackGPULocked()
-{
- sp<IGPUCallback> callback = mCallback;
- mCallback.clear();
- if (callback != 0) {
- callback->gpuLost(); // one-way
- mCondition.waitRelative(mLock, ms2ns(250));
- }
-}
-
-void GPUHardware::releaseLocked()
-{
- //LOGD("revoking gpu from pid %d", mOwner);
- if (mOwner != NO_OWNER) {
- // this may fail because the client might have died, and have
- // been removed from the list.
- ssize_t index = mClients.indexOfKey(mOwner);
- if (index >= 0) {
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps();
- }
- mOwner = NO_OWNER;
- mCurrentAllocator.clear();
- mCallback.clear();
- }
-}
-
-GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
-{
- ssize_t index = mClients.indexOfKey(pid);
- if (index < 0) {
- Client client;
- client.pid = pid;
- client.smi.heap = mSMIHeap;
- client.ebi.heap = mEBIHeap;
- client.reg.heap = mREGHeap;
- index = mClients.add(pid, client);
- }
- Client& client(mClients.editValueAt(index));
- client.createClientHeaps();
- return client;
-}
-
-// ----------------------------------------------------------------------------
-// for debugging / testing ...
-
-sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
- Mutex::Autolock _l(mLock);
- return mAllocator;
-}
-
-void GPUHardware::unconditionalRevoke()
-{
- Mutex::Autolock _l(mLock);
- releaseLocked();
-}
-
-// ---------------------------------------------------------------------------
-
-sp<IMemory> GPUHardware::GPUArea::map() {
- sp<IMemory> memory;
- if (clientHeap != 0 && heap != 0) {
- memory = clientHeap->mapMemory(0, heap->virtualSize());
- }
- return memory;
-}
-
-void GPUHardware::Client::createClientHeaps()
-{
- if (smi.clientHeap == 0)
- smi.clientHeap = smi.heap->createClientHeap();
- if (ebi.clientHeap == 0)
- ebi.clientHeap = ebi.heap->createClientHeap();
- if (reg.clientHeap == 0)
- reg.clientHeap = reg.heap->createClientHeap();
-}
-
-void GPUHardware::Client::revokeAllHeaps()
-{
- if (smi.clientHeap != 0)
- smi.clientHeap->revoke();
- if (ebi.clientHeap != 0)
- ebi.clientHeap->revoke();
- if (reg.clientHeap != 0)
- reg.clientHeap->revoke();
-}
-
-void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client)
-{
- sp<IBinder> binder = callback->asBinder();
- if (mRegisteredClients.add(binder, client.pid) >= 0) {
- binder->linkToDeath(this);
- }
-}
-
-void GPUHardware::binderDied(const wp<IBinder>& who)
-{
- Mutex::Autolock _l(mLock);
- pid_t pid = mRegisteredClients.valueFor(who);
- if (pid != 0) {
- ssize_t index = mClients.indexOfKey(pid);
- if (index >= 0) {
- //LOGD("*** removing client at %d", index);
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps(); // not really needed in theory
- mClients.removeItemsAt(index);
- if (mClients.size() == 0) {
- //LOGD("*** was last client closing everything");
- mCallback.clear();
- mAllocator.clear();
- mCurrentAllocator.clear();
- mSMIHeap.clear();
- mREGHeap.clear();
-
- // NOTE: we cannot clear the EBI heap because surfaceflinger
- // itself may be using it, since this is where surfaces
- // are allocated. if we're in the middle of compositing
- // a surface (even if its process just died), we cannot
- // rip the heap under our feet.
-
- mOwner = NO_OWNER;
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-sp<GPUHardwareInterface> GPUFactory::getGPU()
-{
- sp<GPUHardwareInterface> gpu;
- if (access("/dev/hw3d", F_OK) == 0) {
- gpu = new GPUHardware();
- }
- return gpu;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
deleted file mode 100644
index 3354528..0000000
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.h
+++ /dev/null
@@ -1,63 +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 ANDROID_GPU_HARDWARE_H
-#define ANDROID_GPU_HARDWARE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-
-#include <ui/ISurfaceComposer.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class IGPUCallback;
-
-class GPUHardwareInterface : public virtual RefBase
-{
-public:
- virtual void revoke(int pid) = 0;
- virtual sp<MemoryDealer> request(int pid) = 0;
- virtual status_t request(int pid, const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu) = 0;
-
- virtual status_t friendlyRevoke() = 0;
-
- // used for debugging only...
- virtual sp<SimpleBestFitAllocator> getAllocator() const = 0;
- virtual pid_t getOwner() const = 0;
- virtual void unconditionalRevoke() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class GPUFactory
-{
-public:
- // the gpu factory
- static sp<GPUHardwareInterface> getGPU();
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GPU_HARDWARE_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 96395a8..f5a5a0b 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/GraphicBuffer.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,292 +47,375 @@ 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),
+ mNoEGLImageForSwBuffers(false),
mNeedsBlending(true),
- mResizeTransactionDone(false),
- mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+ mNeedsDithering(false)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
+ mFrontBufferIndex = lcblk->getFrontBuffer();
}
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::initStates(uint32_t w, uint32_t h, uint32_t flags)
+void Layer::destroy()
{
- LayerBase::initStates(w,h,flags);
-
- if (flags & ISurfaceComposer::eDestroyBackbuffer)
- lcblk->flags |= eNoCopyBack;
+ for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+ if (mTextures[i].name != -1U) {
+ glDeleteTextures(1, &mTextures[i].name);
+ mTextures[i].name = -1U;
+ }
+ if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[i].image);
+ mTextures[i].image = EGL_NO_IMAGE_KHR;
+ }
+ Mutex::Autolock _l(mLock);
+ mBuffers[i].clear();
+ mWidth = mHeight = 0;
+ }
+ mSurface.clear();
}
-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)
{
+ // this surfaces pixel format
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;
-
- const uint32_t memory_flags = flags &
- (ISurfaceComposer::eGPU |
- ISurfaceComposer::eHardware |
- ISurfaceComposer::eSecure);
+ // the display's pixel format
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ PixelFormatInfo displayInfo;
+ getPixelFormatInfo(hw.getFormat(), &displayInfo);
+ const uint32_t hwFlags = hw.getFlags();
- // pixel-alignment. the final alignment may be bigger because
- // we always force a 4-byte aligned bpr.
- uint32_t alignment = 1;
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this value should come from the h/w
- alignment = 8;
- // FIXME: this is msm7201A specific, as its GPU only supports
- // BGRA_8888.
- if (format == PIXEL_FORMAT_RGBA_8888) {
- format = PIXEL_FORMAT_BGRA_8888;
- }
- }
-
+ mFormat = format;
+ mWidth = w;
+ mHeight = h;
mSecure = (flags & ISurfaceComposer::eSecure) ? 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)
- 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);
+ mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS);
+
+ // we use the red index
+ int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
+ int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
+ mNeedsDithering = layerRedsize > displayRedSize;
+ for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+ mBuffers[i] = new GraphicBuffer();
+ }
+ mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
}
void Layer::reloadTexture(const Region& dirty)
{
- 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();
+ Mutex::Autolock _l(mLock);
+ sp<GraphicBuffer> buffer(getFrontBufferLocked());
+ int index = mFrontBufferIndex;
+
+ // create the new texture name if needed
+ if (UNLIKELY(mTextures[index].name == -1U)) {
+ mTextures[index].name = createTexture();
+ mTextures[index].width = 0;
+ mTextures[index].height = 0;
}
- const GGLSurface& t(frontBuffer().surface());
- loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
-}
+#ifdef EGL_ANDROID_image_native_buffer
+ if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
+ if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
+ if (mTextures[index].dirty) {
+ initializeEglImage(buffer, &mTextures[index]);
+ }
+ } else {
+ if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
+ mHybridBuffer->height != buffer->height)) {
+ mHybridBuffer.clear();
+ mHybridBuffer = new GraphicBuffer(
+ buffer->width, buffer->height, buffer->format,
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN |
+ GraphicBuffer::USAGE_HW_TEXTURE);
+ initializeEglImage(
+ mHybridBuffer, &mTextures[0]);
+ }
+
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ Texture* const texture(&mTextures[0]);
+
+ glBindTexture(GL_TEXTURE_2D, texture->name);
+
+ sp<GraphicBuffer> buf(mHybridBuffer);
+ void* vaddr;
+ res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr);
+ if (res == NO_ERROR) {
+ int bpp = 0;
+ switch (t.format) {
+ case GGL_PIXEL_FORMAT_RGB_565:
+ case GGL_PIXEL_FORMAT_RGBA_4444:
+ bpp = 2;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_8888:
+ case GGL_PIXEL_FORMAT_RGBX_8888:
+ bpp = 4;
+ break;
+ case GGL_PIXEL_FORMAT_YCbCr_422_SP:
+ case GGL_PIXEL_FORMAT_YCbCr_420_SP:
+ // just show the Y plane of YUV buffers
+ bpp = 1;
+ break;
+ default:
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, texture->name, t.format);
+ }
+ if (bpp) {
+ const Rect bounds(dirty.getBounds());
+ size_t src_stride = t.stride;
+ size_t dst_stride = buf->stride;
+ if (src_stride == dst_stride &&
+ bounds.width() == t.width &&
+ bounds.height() == t.height)
+ {
+ memcpy(vaddr, t.data, t.height * t.stride * bpp);
+ } else {
+ GLubyte const * src = t.data +
+ (bounds.left + bounds.top * src_stride) * bpp;
+ GLubyte * dst = (GLubyte *)vaddr +
+ (bounds.left + bounds.top * dst_stride) * bpp;
+ const size_t length = bounds.width() * bpp;
+ size_t h = bounds.height();
+ src_stride *= bpp;
+ dst_stride *= bpp;
+ while (h--) {
+ memcpy(dst, src, length);
+ dst += dst_stride;
+ src += src_stride;
+ }
+ }
+ }
+ buf->unlock();
+ }
+ buffer->unlock();
+ }
+ }
+ } else
+#endif
+ {
+ for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+ mTextures[i].image = EGL_NO_IMAGE_KHR;
+ }
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ loadTexture(&mTextures[0], dirty, t);
+ buffer->unlock();
+ }
+ }
+}
void Layer::onDraw(const Region& clip) const
{
- if (UNLIKELY(mTextureName == -1LU)) {
- //LOGW("Layer %p doesn't have a texture", this);
+ int index = mFrontBufferIndex;
+ if (mTextures[index].image == EGL_NO_IMAGE_KHR)
+ index = 0;
+ GLuint textureName = mTextures[index].name;
+ if (UNLIKELY(textureName == -1LU)) {
// 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());
-
- 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);
+sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
+{
+ sp<GraphicBuffer> buffer;
+
+ // this ensures our client doesn't go away while we're accessing
+ // the shared area.
+ sp<Client> ourClient(client.promote());
+ if (ourClient == 0) {
+ // oops, the client is already gone
+ return buffer;
+ }
+
+ /*
+ * This is called from the client's Surface::dequeue(). This can happen
+ * at any time, especially while we're in the middle of using the
+ * buffer 'index' as our front buffer.
+ *
+ * Make sure the buffer we're resizing is not the front buffer and has been
+ * dequeued. Once this condition is asserted, we are guaranteed that this
+ * buffer cannot become the front buffer under our feet, since we're called
+ * from Surface::dequeue()
+ */
+ status_t err = lcblk->assertReallocate(index);
+ LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err));
+ if (err != NO_ERROR) {
+ // the surface may have died
+ return buffer;
}
- if (!can_use_copybit || err) {
- drawWithOpenGL(clip, mTextureName, t);
+ uint32_t w, h;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ w = mWidth;
+ h = mHeight;
+ buffer = mBuffers[index];
+
+ // destroy() could have been called before we get here, we log it
+ // because it's uncommon, and the code below should handle it
+ LOGW_IF(buffer==0,
+ "mBuffers[%d] is null (mWidth=%d, mHeight=%d)",
+ index, w, h);
+
+ mBuffers[index].clear();
}
-}
-status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
-{
- 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);
+ const uint32_t effectiveUsage = getEffectiveUsage(usage);
+ if (buffer!=0 && buffer->getStrongCount() == 1) {
+ err = buffer->reallocate(w, h, mFormat, effectiveUsage);
} 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?
+ // here we have to reallocate a new buffer because we could have a
+ // client in our process with a reference to it (eg: status bar),
+ // and we can't release the handle under its feet.
+ buffer.clear();
+ buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage);
+ err = buffer->initCheck();
}
- return err;
-}
-uint32_t Layer::doTransaction(uint32_t flags)
-{
- const Layer::State& front(drawingState());
- const Layer::State& temp(currentState());
+ if (err || buffer->handle == 0) {
+ LOGE_IF(err || buffer->handle == 0,
+ "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
+ this, index, w, h, strerror(-err));
+ } else {
+ LOGD_IF(DEBUG_RESIZE,
+ "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p",
+ this, index, w, h, buffer->handle);
+ }
- // the test front.{w|h} != temp.{w|h} is not enough because it is possible
- // 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.
+ if (err == NO_ERROR && buffer->handle != 0) {
+ Mutex::Autolock _l(mLock);
+ if (mWidth && mHeight) {
+ // and we have new buffer
+ mBuffers[index] = buffer;
+ // texture is now dirty...
+ mTextures[index].dirty = true;
+ } else {
+ // oops we got killed while we were allocating the buffer
+ buffer.clear();
+ }
+ }
+ return buffer;
+}
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const
+{
/*
- * Various states we could be in...
-
- resize = state & eResizeRequested;
- if (backbufferChanged) {
- if (resize == 0) {
- // ERROR, the resized buffer doesn't have its resize flag set
- } else if (resize == mask) {
- // ERROR one of the buffer has already been resized
- } else if (resize == mask ^ eResizeRequested) {
- // ERROR, the resized buffer doesn't have its resize flag set
- } else if (resize == eResizeRequested) {
- // OK, Normal case, proceed with resize
- }
- } else {
- if (resize == 0) {
- // OK, nothing special, do nothing
- } else if (resize == mask) {
- // restarted transaction, do nothing
- } else if (resize == mask ^ eResizeRequested) {
- // restarted transaction, do nothing
- } else if (resize == eResizeRequested) {
- // OK, size reset to previous value, proceed with resize
- }
- }
+ * 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
+ *
*/
- // Index of the back buffer
- const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
- const uint32_t state = lcblk->swapState;
- const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state);
- const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
- uint32_t resizeFlags = state & eResizeRequested;
-
- if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) {
- LOGE( "backbuffer size changed, but both resize flags are not set! "
- "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), "
- "index=%d, (%dx%d), (%dx%d)",
- this, state,
- 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()));
- // 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
- // client to get unblocked)
- resizeFlags = eResizeRequested;
+ if (mSecure) {
+ // secure buffer, don't store it into the GPU
+ usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+ } else {
+ // it's allowed to modify the usage flags here, but generally
+ // the requested flags should be honored.
+ if (mNoEGLImageForSwBuffers) {
+ if (usage & GraphicBuffer::USAGE_HW_MASK) {
+ // request EGLImage for h/w buffers only
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ }
+ } else {
+ // request EGLImage for all buffers
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ }
}
+ return usage;
+}
- if (resizeFlags == eResizeRequested) {
- // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex
- // here, would be wrong and misleading because by this point
- // mFrontBufferIndex has not been updated yet.
+uint32_t Layer::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+ if ((front.requested_w != temp.requested_w) ||
+ (front.requested_h != temp.requested_h)) {
+ // the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
- "resize (layer=%p), state=%08x, "
- "requested (%dx%d), "
- "drawing (%d,%d), "
- "index=%d, (%dx%d), (%dx%d)",
- this, state,
- 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()));
-
- if (state & eLocked) {
- // if the buffer is locked, we can't resize anything because
- // - the backbuffer is currently in use by the user
- // - the front buffer is being shown
- // We just act as if the transaction didn't happen and we
- // reschedule it later...
- flags |= eRestartTransaction;
- } else {
- // This buffer needs to be resized
- status_t err =
- resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
- if (err == NO_ERROR) {
- 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);
- mResizeTransactionDone = true;
-
- // we're being resized and there is a freeze display request,
- // acquire a freeze lock, so that the screen stays put
- // until we've redrawn at the new size; this is to avoid
- // glitches upon orientation changes.
- if (mFlinger->hasFreezeRequest()) {
- // if the surface is hidden, don't try to acquire the
- // freeze lock, since hidden surfaces may never redraw
- if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
- mFreezeLock = mFlinger->getFreezeLock();
- }
- }
+ "resize (layer=%p), requested (%dx%d), "
+ "drawing (%d,%d), (%dx%d), (%dx%d)",
+ this,
+ int(temp.requested_w), int(temp.requested_h),
+ int(front.requested_w), int(front.requested_h),
+ int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
+ int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
+
+ // we're being resized and there is a freeze display request,
+ // acquire a freeze lock, so that the screen stays put
+ // until we've redrawn at the new size; this is to avoid
+ // glitches upon orientation changes.
+ if (mFlinger->hasFreezeRequest()) {
+ // if the surface is hidden, don't try to acquire the
+ // freeze lock, since hidden surfaces may never redraw
+ if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+ mFreezeLock = mFlinger->getFreezeLock();
}
}
+
+ // this will make sure LayerBase::doTransaction doesn't update
+ // the drawing state's size
+ Layer::State& editDraw(mDrawingState);
+ editDraw.requested_w = temp.requested_w;
+ editDraw.requested_h = temp.requested_h;
+
+ // record the new size, form this point on, when the client request a
+ // buffer, it'll get the new size.
+ setDrawingSize(temp.requested_w, temp.requested_h);
+
+ // all buffers need reallocation
+ lcblk->reallocate();
}
-
+
if (temp.sequence != front.sequence) {
if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
// this surface is now hidden, so it shouldn't hold a freeze lock
@@ -346,54 +427,10 @@ uint32_t Layer::doTransaction(uint32_t flags)
return LayerBase::doTransaction(flags);
}
-status_t Layer::resize(
- int32_t clientBackBufferIndex,
- uint32_t width, uint32_t height,
- const char* what)
-{
- /*
- * handle resize (backbuffer and frontbuffer reallocation)
- */
-
- 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);
-
- LOGD_IF(!backbufferChanged,
- "(%s) eResizeRequested (layer=%p), but size not changed: "
- "requested (%dx%d), drawing (%d,%d), current (%d,%d),"
- "state=%08lx, index=%d, (%dx%d), (%dx%d)",
- what, this,
- int(width), int(height),
- int(drawingState().w), int(drawingState().h),
- 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()));
-
- // 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));
- }
- return err;
-}
-
-void Layer::setSizeChanged(uint32_t w, uint32_t h)
-{
- LOGD_IF(DEBUG_RESIZE,
- "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)",
- w, h, mCurrentState.w, mCurrentState.h);
- android_atomic_or(eResizeRequested, &(lcblk->swapState));
+void Layer::setDrawingSize(uint32_t w, uint32_t h) {
+ Mutex::Autolock _l(mLock);
+ mWidth = w;
+ mHeight = h;
}
// ----------------------------------------------------------------------------
@@ -402,128 +439,61 @@ void Layer::setSizeChanged(uint32_t w, uint32_t h)
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
- uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
- // preemptively block the client, because he might set
- // eFlipRequested at any time and want to use this buffer
- // for the next frame. This will be unset below if it
- // turns out we didn't need it.
-
- uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested;
- if (!(state & mask))
- return;
-
- if (UNLIKELY(state & eInvalidSurface)) {
- // if eInvalidSurface is set, this means the surface
- // became invalid during a transaction (NO_MEMORY for instance)
- mFlinger->scheduleBroadcast(client);
+ ssize_t buf = lcblk->retireAndLock();
+ if (buf < NO_ERROR) {
+ //LOGW("nothing to retire (%s)", strerror(-buf));
+ // NOTE: here the buffer is locked because we will used
+ // for composition later in the loop
return;
}
+
+ // we retired a buffer, which becomes the new front buffer
+ mFrontBufferIndex = buf;
- if (UNLIKELY(state & eFlipRequested)) {
- uint32_t oldState;
- mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions);
- if (oldState & eNextFlipPending) {
- // Process another round (we know at least a buffer
- // is ready for that client).
- mFlinger->signalEvent();
- }
- }
-}
-
-Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
-{
- // atomically swap buffers and (re)set eFlipRequested
- int32_t oldValue, newValue;
- layer_cblk_t * const lcblk = this->lcblk;
- do {
- oldValue = lcblk->swapState;
- // get the current value
-
- LOG_ASSERT(oldValue&eFlipRequested,
- "eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
- long(oldValue));
-
- newValue = (oldValue ^ eIndex);
- // swap buffers
-
- newValue &= ~(eFlipRequested | eNextFlipPending);
- // clear eFlipRequested and eNextFlipPending
-
- if (oldValue & eNextFlipPending)
- newValue |= eFlipRequested;
- // if eNextFlipPending is set (second buffer already has something
- // in it) we need to reset eFlipRequested because the client
- // might never do it
-
- } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
- *previousSate = oldValue;
-
- const int32_t index = (newValue & eIndex) ^ 1;
- mFrontBufferIndex = index;
-
- // ... post the new front-buffer
- Region dirty(lcblk->region + index);
- dirty.andSelf(frontBuffer().bounds());
-
- //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
- // oldValue, newValue, mFrontBufferIndex);
- //dirty.dump("dirty");
-
- if (UNLIKELY(oldValue & eResizeRequested)) {
+ // get the dirty region
+ sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
+ const Region dirty(lcblk->getDirtyRegion(buf));
+ mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
- LOGD_IF(DEBUG_RESIZE,
- "post (layer=%p), state=%08x, "
- "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()));
-
- // here, we just posted the surface and we have resolved
- // the front/back buffer indices. The client is blocked, so
- // it cannot start using the new backbuffer.
-
- // If the backbuffer was resized in THIS round, we actually cannot
- // resize the frontbuffer because it has *just* been drawn (and we
- // would have nothing to draw). In this case we just skip the resize
- // it'll happen after the next page flip or during the next
- // transaction.
-
- const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0;
- if (mResizeTransactionDone && (newValue & mask)) {
- // Resize the layer's second buffer only if the transaction
- // happened. It may not have happened yet if eResizeRequested
- // was set immediately after the "transactionRequested" test,
- // in which case the drawing state's size would be wrong.
- mFreezeLock.clear();
- const Layer::State& s(drawingState());
- if (resize(1-index, s.w, s.h, "post") == NO_ERROR) {
- do {
- oldValue = lcblk->swapState;
- if ((oldValue & eResizeRequested) == eResizeRequested) {
- // ugh, another resize was requested since we processed
- // the first buffer, don't free the client, and let
- // the next transaction handle everything.
- break;
- }
- newValue = oldValue & ~mask;
- } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
- }
- mResizeTransactionDone = false;
+ const Layer::State& front(drawingState());
+ if (newFrontBuffer->getWidth() == front.requested_w &&
+ newFrontBuffer->getHeight() == front.requested_h)
+ {
+ if ((front.w != front.requested_w) ||
+ (front.h != front.requested_h))
+ {
+ // Here we pretend the transaction happened by updating the
+ // current and drawing states. Drawing state is only accessed
+ // in this thread, no need to have it locked
+ Layer::State& editDraw(mDrawingState);
+ editDraw.w = editDraw.requested_w;
+ editDraw.h = editDraw.requested_h;
+
+ // We also need to update the current state so that we don't
+ // end-up doing too much work during the next transaction.
+ // NOTE: We actually don't need hold the transaction lock here
+ // because State::w and State::h are only accessed from
+ // this thread
+ Layer::State& editTemp(currentState());
+ editTemp.w = editDraw.w;
+ editTemp.h = editDraw.h;
+
+ // recompute visible region
recomputeVisibleRegions = true;
- this->contentDirty = true;
}
- }
- reloadTexture(dirty);
+ // we now have the correct size, unfreeze the screen
+ mFreezeLock.clear();
+ }
- return dirty;
-}
+ if (lcblk->getQueuedCount()) {
+ // signal an event if we have more buffers waiting
+ mFlinger->signalEvent();
+ }
-Point Layer::getPhysicalSize() const
-{
- const LayerBitmap& front(frontBuffer());
- return Point(front.width(), front.height());
+ if (!mPostedDirtyRegion.isEmpty()) {
+ reloadTexture( mPostedDirtyRegion );
+ }
}
void Layer::unlockPageFlip(
@@ -544,23 +514,42 @@ void Layer::unlockPageFlip(
// is in screen space as well).
dirtyRegion.andSelf(visibleRegionScreen);
outDirtyRegion.orSelf(dirtyRegion);
-
- // client could be blocked, so signal them so they get a
- // chance to reevaluate their condition.
- mFlinger->scheduleBroadcast(client);
}
}
void Layer::finishPageFlip()
{
- if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
- LOGE_IF(!(lcblk->swapState & eBusy),
- "layer %p wasn't locked!", this);
- android_atomic_and(~eBusy, &(lcblk->swapState));
- }
- mFlinger->scheduleBroadcast(client);
+ status_t err = lcblk->unlock( mFrontBufferIndex );
+ LOGE_IF(err!=NO_ERROR,
+ "layer %p, buffer=%d wasn't locked!",
+ this, mFrontBufferIndex);
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner)
+ : Surface(flinger, id, owner->getIdentity(), owner)
+{
+}
+
+Layer::SurfaceLayer::~SurfaceLayer()
+{
}
+sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
+{
+ sp<GraphicBuffer> buffer;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ LOGE_IF(uint32_t(index)>=NUM_BUFFERS,
+ "getBuffer() index (%d) out of range", index);
+ if (uint32_t(index) < NUM_BUFFERS) {
+ buffer = owner->requestBuffer(index, usage);
+ }
+ }
+ return buffer;
+}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 2867f2b..1310ecc 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -20,14 +20,15 @@
#include <stdint.h>
#include <sys/types.h>
+#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
-
-#include <private/ui/SharedState.h>
-#include <private/ui/LayerState.h>
-
#include <pixelflinger/pixelflinger.h>
-#include "LayerBitmap.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "LayerBase.h"
#include "Transform.h"
@@ -36,12 +37,12 @@ namespace android {
// ---------------------------------------------------------------------------
class Client;
-class LayerBitmap;
-class MemoryDealer;
class FreezeLock;
// ---------------------------------------------------------------------------
+const size_t NUM_BUFFERS = 2;
+
class Layer : public LayerBaseClient
{
public:
@@ -49,68 +50,79 @@ public:
static const char* const typeID;
virtual char const* getTypeID() const { return typeID; }
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();
- }
+ status_t setBuffers(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags=0);
- status_t setBuffers( Client* client,
- uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags=0);
+ void setDrawingSize(uint32_t w, uint32_t h);
virtual void onDraw(const Region& clip) const;
- virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
- virtual void setSizeChanged(uint32_t w, uint32_t h);
virtual uint32_t doTransaction(uint32_t transactionFlags);
- virtual Point getPhysicalSize() const;
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual void finishPageFlip();
virtual bool needsBlending() const { return mNeedsBlending; }
+ virtual bool needsDithering() const { return mNeedsDithering; }
virtual bool isSecure() const { return mSecure; }
- virtual GLuint getTextureName() const { return mTextureName; }
- virtual sp<Surface> getSurface() const;
-
- const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
- LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
-
+ virtual sp<Surface> createSurface() const;
+ virtual status_t ditch();
+
+ // only for debugging
+ inline sp<GraphicBuffer> getBuffer(int i) { return mBuffers[i]; }
// only for debugging
- const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
+ inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
+ // only for debugging
+ inline PixelFormat pixelFormat() const { return mFormat; }
private:
- inline const LayerBitmap&
- frontBuffer() const { return getBuffer(mFrontBufferIndex); }
- inline LayerBitmap&
- frontBuffer() { return getBuffer(mFrontBufferIndex); }
- inline const LayerBitmap&
- backBuffer() const { return getBuffer(1-mFrontBufferIndex); }
- inline LayerBitmap&
- backBuffer() { return getBuffer(1-mFrontBufferIndex); }
-
+ inline sp<GraphicBuffer> getFrontBufferLocked() {
+ return mBuffers[mFrontBufferIndex];
+ }
+
void reloadTexture(const Region& dirty);
- 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);
-
+ uint32_t getEffectiveUsage(uint32_t usage) const;
+
+ sp<GraphicBuffer> requestBuffer(int index, int usage);
+ void destroy();
+
+ class SurfaceLayer : public LayerBaseClient::Surface {
+ public:
+ SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner);
+ ~SurfaceLayer();
+ private:
+ virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+ sp<Layer> getOwner() const {
+ return static_cast<Layer*>(Surface::getOwner().get());
+ }
+ };
+ friend class SurfaceLayer;
+
sp<Surface> mSurface;
bool mSecure;
- LayerBitmap mBuffers[2];
+ bool mNoEGLImageForSwBuffers;
int32_t mFrontBufferIndex;
bool mNeedsBlending;
- bool mResizeTransactionDone;
+ bool mNeedsDithering;
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
+ PixelFormat mFormat;
+
+ // protected by mLock
+ sp<GraphicBuffer> mBuffers[NUM_BUFFERS];
+ Texture mTextures[NUM_BUFFERS];
+ sp<GraphicBuffer> mHybridBuffer;
+ uint32_t mWidth;
+ uint32_t mHeight;
- GLuint mTextureName;
- GLuint mTextureWidth;
- GLuint mTextureHeight;
+ mutable Mutex mLock;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 0cf53f7..8003d22 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>
@@ -30,17 +30,10 @@
#include "clz.h"
#include "LayerBase.h"
-#include "LayerBlur.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
-// We don't honor the premultiplied alpha flags, which means that
-// premultiplied surface may be composed using a non-premultiplied
-// equation. We do this because it may be a lot faster on some hardware
-// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
-#define HONOR_PREMULTIPLIED_ALPHA 0
-
namespace android {
// ---------------------------------------------------------------------------
@@ -53,19 +46,14 @@ 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),
+ mUseLinearFiltering(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());
@@ -95,26 +83,22 @@ void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
if (flags & ISurfaceComposer::eNonPremultiplied)
mPremultipliedAlpha = false;
- mCurrentState.z = 0;
- mCurrentState.w = w;
- mCurrentState.h = h;
- mCurrentState.alpha = 0xFF;
- mCurrentState.flags = layerFlags;
- mCurrentState.sequence = 0;
+ mCurrentState.z = 0;
+ mCurrentState.w = w;
+ mCurrentState.h = h;
+ mCurrentState.requested_w = w;
+ mCurrentState.requested_h = h;
+ mCurrentState.alpha = 0xFF;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.sequence = 0;
mCurrentState.transform.set(0, 0);
// drawing state & current state are identical
mDrawingState = mCurrentState;
}
-void LayerBase::commitTransaction(bool skipSize) {
- const uint32_t w = mDrawingState.w;
- const uint32_t h = mDrawingState.h;
+void LayerBase::commitTransaction() {
mDrawingState = mCurrentState;
- if (skipSize) {
- mDrawingState.w = w;
- mDrawingState.h = h;
- }
}
void LayerBase::forceVisibilityTransaction() {
// this can be called without SurfaceFlinger.mStateLock, but if we
@@ -133,9 +117,6 @@ uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
return android_atomic_or(flags, &mTransactionFlags);
}
-void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
-}
-
bool LayerBase::setPosition(int32_t x, int32_t y) {
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
return false;
@@ -153,11 +134,10 @@ bool LayerBase::setLayer(uint32_t z) {
return true;
}
bool LayerBase::setSize(uint32_t w, uint32_t h) {
- if (mCurrentState.w == w && mCurrentState.h == h)
+ if (mCurrentState.requested_w == w && mCurrentState.requested_h == h)
return false;
- setSizeChanged(w, h);
- mCurrentState.w = w;
- mCurrentState.h = h;
+ mCurrentState.requested_w = w;
+ mCurrentState.requested_h = h;
requestTransaction();
return true;
}
@@ -214,32 +194,49 @@ uint32_t LayerBase::doTransaction(uint32_t flags)
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
+ if ((front.requested_w != temp.requested_w) ||
+ (front.requested_h != temp.requested_h)) {
+ // resize the layer, set the physical size to the requested size
+ Layer::State& editTemp(currentState());
+ editTemp.w = temp.requested_w;
+ editTemp.h = temp.requested_h;
+ }
+
+ if ((front.w != temp.w) || (front.h != temp.h)) {
+ // invalidate and recompute the visible regions if needed
+ flags |= Layer::eVisibleRegion;
+ this->contentDirty = true;
+ }
+
if (temp.sequence != front.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
+
+ const bool linearFiltering = mUseLinearFiltering;
+ mUseLinearFiltering = false;
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // we may use linear filtering, if the matrix scales us
+ const uint8_t type = temp.transform.getType();
+ if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) {
+ mUseLinearFiltering = true;
+ }
+ }
}
-
+
// Commit the transaction
- commitTransaction(flags & eRestartTransaction);
+ commitTransaction();
return flags;
}
-Point LayerBase::getPhysicalSize() const
-{
- const Layer::State& front(drawingState());
- return Point(front.w, front.h);
-}
-
void LayerBase::validateVisibility(const Transform& planeTransform)
{
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
const bool transformed = tr.transformed();
- const Point size(getPhysicalSize());
- uint32_t w = size.x;
- uint32_t h = size.y;
+ uint32_t w = s.w;
+ uint32_t h = s.h;
tr.transform(mVertices[0], 0, 0);
tr.transform(mVertices[1], 0, h);
tr.transform(mVertices[2], w, h);
@@ -265,43 +262,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 +289,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 +299,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);
@@ -385,55 +347,52 @@ GLuint LayerBase::createTexture() const
glBindTexture(GL_TEXTURE_2D, textureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- if (mFlags & DisplayHardware::SLOW_CONFIG) {
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- } else {
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureName;
}
-void LayerBase::clearWithOpenGL(const Region& clip) const
+void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,
+ GLclampx green, GLclampx blue,
+ GLclampx alpha) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
- glColor4x(0,0,0,0);
+ glColor4x(red,green,blue,alpha);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
- Rect r;
- Region::iterator iterator(clip);
- if (iterator) {
- glEnable(GL_SCISSOR_TEST);
- glVertexPointer(2, GL_FIXED, 0, mVertices);
- 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);
- }
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ glEnable(GL_SCISSOR_TEST);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
-void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t, int transform) const
+void LayerBase::clearWithOpenGL(const Region& clip) const
+{
+ clearWithOpenGL(clip,0,0,0,0);
+}
+
+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...
- if (s.flags & ISurfaceComposer::eLayerDither) {
- glEnable(GL_DITHER);
- } else {
- glDisable(GL_DITHER);
- }
-
if (UNLIKELY(s.alpha < 0xFF)) {
// We have an alpha-modulation. We need to modulate all
// texture components by alpha because we're always using
@@ -468,77 +427,55 @@ void LayerBase::drawWithOpenGL(const Region& clip,
}
}
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
if (UNLIKELY(transformed()
|| !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
{
//StopWatch watch("GL transformed");
- Region::iterator iterator(clip);
- if (iterator) {
- // always use high-quality filtering with fast configurations
- bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
- if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
- const GLfixed texCoords[4][2] = {
- { 0, 0 },
- { 0, 0x10000 },
- { 0x10000, 0x10000 },
- { 0x10000, 0 }
- };
-
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
-
- if (transform == HAL_TRANSFORM_ROT_90) {
- 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;
- // 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;
- glScalef(ws, hs, 1.0f);
- }
-
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(2, GL_FIXED, 0, mVertices);
- glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+ const GLfixed texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 0x10000 },
+ { 0x10000, 0x10000 },
+ { 0x10000, 0 }
+ };
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ // 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 (texture.NPOTAdjust) {
+ glScalef(texture.wScale, texture.hScale, 1.0f);
+ }
- 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);
- }
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
- if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- Rect r;
- GLint crop[4] = { 0, t.height, t.width, -t.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)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, t.width, t.height);
- }
+ 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 + 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, width, height);
}
}
}
@@ -548,25 +485,34 @@ void LayerBase::validateTexture(GLint textureName) const
glBindTexture(GL_TEXTURE_2D, textureName);
// TODO: reload the texture if needed
// this is currently done in loadTexture() below
+ if (mUseLinearFiltering) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+
+ if (needsDithering()) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
}
-void LayerBase::loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const
+void LayerBase::loadTexture(Texture* texture,
+ const Region& dirty, const GGLSurface& t) const
{
- // TODO: defer the actual texture reload until LayerBase::validateTexture
- // is called.
-
- uint32_t flags = mFlags;
- glBindTexture(GL_TEXTURE_2D, textureName);
+ if (texture->name == -1U) {
+ // uh?
+ return;
+ }
- GLuint tw = t.width;
- GLuint th = t.height;
+ glBindTexture(GL_TEXTURE_2D, texture->name);
/*
* 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,161 +525,294 @@ 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
*/
+ if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+ texture->NPOTAdjust = true;
+ }
- GLuint texture_w = tw;
- GLuint texture_h = th;
- if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
+ if (texture->NPOTAdjust) {
// find the smallest power-of-two that will accommodate our surface
- texture_w = 1 << (31 - clz(t.width));
- 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;
- }
+ texture->potWidth = 1 << (31 - clz(t.width));
+ texture->potHeight = 1 << (31 - clz(t.height));
+ if (texture->potWidth < t.width) texture->potWidth <<= 1;
+ if (texture->potHeight < t.height) texture->potHeight <<= 1;
+ texture->wScale = float(t.width) / texture->potWidth;
+ texture->hScale = float(t.height) / texture->potHeight;
+ } else {
+ texture->potWidth = t.width;
+ texture->potHeight = t.height;
}
- if (flags & DisplayHardware::DIRECT_TEXTURE) {
- // here we're guaranteed that texture_{w|h} == t{w|h}
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture->width != t.width || texture->height != t.height) {
+ texture->width = t.width;
+ texture->height = t.height;
+
+ // texture size changed, we need to create a new one
+ bounds.set(Rect(t.width, t.height));
+ if (t.width == texture->potWidth &&
+ t.height == texture->potHeight) {
+ // we can do it one pass
+ data = t.data;
+ }
+
if (t.format == 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);
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture->potWidth, texture->potHeight, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
} else if (t.format == 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
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture->potWidth, texture->potHeight, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 ||
+ t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture->potWidth, texture->potHeight, 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->potWidth, texture->potHeight, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
} else {
- // oops, we don't handle this format, try the regular path
- goto regular;
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, texture->name, t.format);
}
- 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
- 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;
- }
- 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 (!data) {
+ 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 ||
+ t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride*4);
+ } else if ( 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
+status_t LayerBase::initializeEglImage(
+ const sp<GraphicBuffer>& buffer, Texture* texture)
{
- return mCanUseCopyBit;
+ status_t err = NO_ERROR;
+
+ // we need to recreate the texture
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+ // free the previous image
+ if (texture->image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, texture->image);
+ texture->image = EGL_NO_IMAGE_KHR;
+ }
+
+ // construct an EGL_NATIVE_BUFFER_ANDROID
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ // create the new EGLImageKHR
+ const EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE, EGL_NONE
+ };
+ texture->image = eglCreateImageKHR(
+ dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)clientBuf, attrs);
+
+ LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
+ "eglCreateImageKHR() failed. err=0x%4x",
+ eglGetError());
+
+ if (texture->image != EGL_NO_IMAGE_KHR) {
+ glBindTexture(GL_TEXTURE_2D, texture->name);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+ (GLeglImageOES)texture->image);
+ GLint error = glGetError();
+ if (UNLIKELY(error != GL_NO_ERROR)) {
+ // this failed, for instance, because we don't support NPOT.
+ // FIXME: do something!
+ LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
+ "failed err=0x%04x",
+ this, texture->image, error);
+ mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+ err = INVALID_OPERATION;
+ } else {
+ // Everything went okay!
+ texture->NPOTAdjust = false;
+ texture->dirty = false;
+ texture->width = clientBuf->width;
+ texture->height = clientBuf->height;
+ }
+ } else {
+ err = INVALID_OPERATION;
+ }
+ return err;
}
+
// ---------------------------------------------------------------------------
+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)
-{
- if (client) {
- client->bindLayer(this, i);
-
- // Initialize this layer's control block
- memset(this->lcblk, 0, sizeof(layer_cblk_t));
- this->lcblk->identity = mIdentity;
- Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
- Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
+ const sp<Client>& client, int32_t i)
+ : LayerBase(flinger, display), lcblk(NULL), client(client),
+ mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
+{
+ lcblk = new SharedBufferServer(
+ client->ctrlblk, i, NUM_BUFFERS,
+ mIdentity);
+}
+
+void LayerBaseClient::onFirstRef()
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
+ client->bindLayer(this, mIndex);
}
}
LayerBaseClient::~LayerBaseClient()
{
- if (client) {
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
client->free(mIndex);
}
+ delete lcblk;
}
-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()
{
- return new Surface(clientIndex(), mIdentity);
+ 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));
+}
+
+// called with SurfaceFlinger::mStateLock as soon as the layer is entered
+// in the purgatory list
+void LayerBaseClient::onRemoved()
+{
+ // wake up the condition
+ lcblk->setStatus(NO_INIT);
+}
+
+// ---------------------------------------------------------------------------
+
+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;
+}
+
+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<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)
+{
+ 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..ed07b3f 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -20,8 +20,14 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
+#include <utils/RefBase.h>
+
#include <ui/Region.h>
#include <ui/Overlay.h>
@@ -33,14 +39,15 @@ namespace android {
// ---------------------------------------------------------------------------
-class SurfaceFlinger;
class DisplayHardware;
-class GraphicPlane;
class Client;
+class GraphicBuffer;
+class GraphicPlane;
+class SurfaceFlinger;
// ---------------------------------------------------------------------------
-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;
@@ -83,6 +87,8 @@ public:
struct State {
uint32_t w;
uint32_t h;
+ uint32_t requested_w;
+ uint32_t requested_h;
uint32_t z;
uint8_t alpha;
uint8_t flags;
@@ -102,7 +108,7 @@ public:
bool setTransparentRegionHint(const Region& opaque);
bool setFlags(uint8_t flags, uint8_t mask);
- void commitTransaction(bool skipSize);
+ void commitTransaction();
bool requestTransaction();
void forceVisibilityTransaction();
@@ -133,11 +139,6 @@ public:
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
/**
- * setSizeChanged - called when the *current* state's size is changed.
- */
- virtual void setSizeChanged(uint32_t w, uint32_t h);
-
- /**
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
@@ -157,13 +158,6 @@ public:
virtual void setCoveredRegion(const Region& coveredRegion);
/**
- * getPhysicalSize - returns the physical size of the drawing state of
- * the surface. If the surface is backed by a bitmap, this is the size of
- * the bitmap (as opposed to the size of the drawing state).
- */
- virtual Point getPhysicalSize() const;
-
- /**
* validateVisibility - cache a bunch of things
*/
virtual void validateVisibility(const Transform& globalTransform);
@@ -195,27 +189,42 @@ public:
virtual bool needsBlending() const { return false; }
/**
+ * needsDithering - true if this surface needs dithering
+ */
+ virtual bool needsDithering() const { return false; }
+
+ /**
* transformed -- true is this surface needs a to be transformed
*/
virtual bool transformed() const { return mTransformed; }
/**
* 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
- };
+ /** Called from the main thread, when the surface is removed from the
+ * draw list */
+ virtual status_t ditch() { return NO_ERROR; }
+
+ /** called with the state lock when the surface is removed from the
+ * current list */
+ virtual void onRemoved() { };
+
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ };
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,28 +238,42 @@ 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),
+ NPOTAdjust(false), dirty(true) { }
+ GLuint name;
+ GLuint width;
+ GLuint height;
+ GLuint potWidth;
+ GLuint potHeight;
+ GLfloat wScale;
+ GLfloat hScale;
+ EGLImageKHR image;
+ uint32_t transform;
+ bool NPOTAdjust;
+ bool dirty;
+ };
+
+ void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g,
+ GLclampx b, GLclampx alpha) const;
void clearWithOpenGL(const Region& clip) const;
+ void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ void loadTexture(Texture* texture,
+ const Region& dirty, const GGLSurface& t) const;
+ status_t initializeEglImage(
+ const sp<GraphicBuffer>& buffer, Texture* texture);
- 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()
bool mTransformed;
+ bool mUseLinearFiltering;
int32_t mOrientation;
GLfixed mVertices[4][2];
Rect mTransformedBounds;
- bool mCanUseCopyBit;
int mLeft;
int mTop;
@@ -262,16 +285,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;
};
@@ -286,67 +309,67 @@ public:
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
+ // lcblk is (almost) only accessed from the main SF thread, in the places
+ // where it's not, a reference to Client must be held
+ SharedBufferServer* lcblk;
+
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBaseClient();
+ virtual void onFirstRef();
+ const wp<Client> client;
- Client* const 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;
+
+ virtual void onRemoved();
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;
- };
+ int32_t getToken() const { return mToken; }
+ int32_t getIdentity() const { return mIdentity; }
+
+ 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<GraphicBuffer> requestBuffer(int index, int usage);
+ 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
deleted file mode 100644
index 397ddc8..0000000
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ /dev/null
@@ -1,187 +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 <cutils/memory.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/IMemory.h>
-#include <ui/PixelFormat.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include "LayerBitmap.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-LayerBitmap::LayerBitmap()
- : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
-{
- memset(&mSurface, 0, sizeof(mSurface));
-}
-
-LayerBitmap::~LayerBitmap()
-{
- mSurface.data = 0;
-}
-
-status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
-{
- if (mAllocator != NULL)
- return BAD_VALUE;
- mAllocator = allocator;
- return NO_ERROR;
-}
-
-status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags)
-{
- 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);
- }
-
- /* 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)
- */
- 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;
- } 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 (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;
- }
- return NO_ERROR;
-}
-
-void LayerBitmap::clear()
-{
- // 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);
- //}
- }
-}
-
-status_t LayerBitmap::getInfo(surface_info_t* info) const
-{
- 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);
- return NO_ERROR;
-}
-
-status_t LayerBitmap::resize(uint32_t w, uint32_t h)
-{
- int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
- return err;
-}
-
-size_t LayerBitmap::size() const
-{
- return mSize;
-}
-
-void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
-{
- 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();
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
deleted file mode 100644
index 9ad64c4..0000000
--- a/libs/surfaceflinger/LayerBitmap.h
+++ /dev/null
@@ -1,84 +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_LAYER_BITMAP_H
-#define ANDROID_LAYER_BITMAP_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Atomic.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
-#include <pixelflinger/pixelflinger.h>
-
-class copybit_image_t;
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class IMemory;
-class MemoryDealer;
-class LayerBitmap;
-
-// ---------------------------------------------------------------------------
-
-class LayerBitmap
-{
-public:
-
- enum {
- // erase memory to ensure security when necessary
- SECURE_BITS = 0x00000001
- };
-
- LayerBitmap();
- ~LayerBitmap();
- status_t init(const sp<MemoryDealer>& allocator);
-
- status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags = 0);
- void clear();
-
- status_t getInfo(surface_info_t* info) const;
- status_t resize(uint32_t w, uint32_t h);
-
- 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;
-
-private:
- sp<MemoryDealer> mAllocator;
- sp<IMemory> mBitsMemory;
- uint32_t mAllocFlags;
- ssize_t mOffset;
- GGLSurface mSurface;
- size_t mSize;
- uint32_t mAlignment;
-};
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_BITMAP_H
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index d3e456f..5fd7904 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>
@@ -26,6 +24,7 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include "clz.h"
#include "BlurFilter.h"
#include "LayerBlur.h"
#include "SurfaceFlinger.h"
@@ -40,17 +39,18 @@ const char* const LayerBlur::typeID = "LayerBlur";
// ---------------------------------------------------------------------------
LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
- : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
- mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
+ const sp<Client>& client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+ mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
+ mWidthScale(1.0f), mHeightScale(1.0f),
+ mBlurFormat(GGL_PIXEL_FORMAT_RGB_565)
{
}
LayerBlur::~LayerBlur()
{
if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ glDeleteTextures(1, &mTextureName);
}
}
@@ -137,44 +137,73 @@ void LayerBlur::onDraw(const Region& clip) const
// create the texture name the first time
// can't do that in the ctor, because it runs in another thread.
glGenTextures(1, &mTextureName);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+ if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+ mReadFormat = GL_RGBA;
+ mReadType = GL_UNSIGNED_BYTE;
+ mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+ }
}
- 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);
-
+
if (mRefreshCache) {
mRefreshCache = false;
mAutoRefreshPending = false;
-
- // allocate enough memory for 4-bytes (2 pixels) aligned data
- const int32_t s = (w + 1) & ~1;
- uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+ int32_t pixelSize = 4;
+ int32_t s = w;
+ if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+ // allocate enough memory for 4-bytes (2 pixels) aligned data
+ s = (w + 1) & ~1;
+ pixelSize = 2;
+ }
+
+ uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
// This reads the frame-buffer, so a h/w GL would have to
// finish() its rendering first. we don't want to do that
// too often. Read data is 4-bytes aligned.
- glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
-
+ glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
// blur that texture.
GGLSurface bl;
bl.version = sizeof(GGLSurface);
bl.width = w;
bl.height = h;
bl.stride = s;
- bl.format = GGL_PIXEL_FORMAT_RGB_565;
+ bl.format = mBlurFormat;
bl.data = (GGLubyte*)pixels;
blurFilter(&bl, 8, 2);
-
- // NOTE: this works only because we have POT. we'd have to round the
- // texture size up, otherwise.
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+ if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+ mReadFormat, mReadType, pixels);
+ mWidthScale = 1.0f / w;
+ mHeightScale =-1.0f / h;
+ mYOffset = 0;
+ } else {
+ GLuint tw = 1 << (31 - clz(w));
+ GLuint th = 1 << (31 - clz(h));
+ if (tw < GLuint(w)) tw <<= 1;
+ if (th < GLuint(h)) th <<= 1;
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+ mReadFormat, mReadType, NULL);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
+ mReadFormat, mReadType, pixels);
+ mWidthScale = 1.0f / tw;
+ mHeightScale =-1.0f / th;
+ mYOffset = th-h;
+ }
free((void*)pixels);
}
-
+
const State& s = drawingState();
if (UNLIKELY(s.alpha < 0xFF)) {
const GGLfixed alpha = (s.alpha << 16)/255;
@@ -186,7 +215,12 @@ void LayerBlur::onDraw(const Region& clip) const
glDisable(GL_BLEND);
}
- glDisable(GL_DITHER);
+ if (mFlags & DisplayHardware::SLOW_CONFIG) {
+ glDisable(GL_DITHER);
+ } else {
+ glEnable(GL_DITHER);
+ }
+
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -196,37 +230,34 @@ void LayerBlur::onDraw(const Region& clip) const
// This is a very rare scenario.
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
- glScalef(1.0f/w, -1.0f/h, 1);
- glTranslatef(-x, -y, 0);
+ glScalef(mWidthScale, mHeightScale, 1);
+ glTranslatef(-x, mYOffset - y, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, mVertices);
- 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);
}
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} 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);
}
}
}
-
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 24b1156..2e9d7c6 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;
@@ -56,6 +56,12 @@ private:
mutable bool mAutoRefreshPending;
nsecs_t mCacheAge;
mutable GLuint mTextureName;
+ mutable GLfloat mWidthScale;
+ mutable GLfloat mHeightScale;
+ mutable GLfloat mYOffset;
+ mutable GLint mReadFormat;
+ mutable GLint mReadType;
+ mutable uint32_t mBlurFormat;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 00fab70..a36304c 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,29 +23,28 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-
+#include <ui/GraphicBuffer.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"
-
namespace android {
// ---------------------------------------------------------------------------
const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
const char* const LayerBuffer::typeID = "LayerBuffer";
+gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
// ---------------------------------------------------------------------------
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,34 @@ LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
LayerBuffer::~LayerBuffer()
{
- sp<SurfaceBuffer> s(getClientSurface());
- if (s != 0) {
- s->disown();
- mClientSurface.clear();
+}
+
+void LayerBuffer::onFirstRef()
+{
+ LayerBaseClient::onFirstRef();
+ mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
+ const_cast<LayerBuffer *>(this));
+
+ hw_module_t const* module = (hw_module_t const*)sGrallocModule;
+ if (!module) {
+ // NOTE: technically there is a race here, but it shouldn't
+ // cause any problem since hw_get_module() always returns
+ // the same value.
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ sGrallocModule = (gralloc_module_t const *)module;
+ }
}
}
-sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
{
- Mutex::Autolock _l(mLock);
- return mClientSurface.promote();
+ return mSurface;
}
-sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+status_t LayerBuffer::ditch()
{
- 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;
+ mSurface.clear();
+ return NO_ERROR;
}
bool LayerBuffer::needsBlending() const {
@@ -140,6 +141,14 @@ bool LayerBuffer::transformed() const
return false;
}
+void LayerBuffer::serverDestroy()
+{
+ sp<Source> source(clearSource());
+ if (source != 0) {
+ source->destroy();
+ }
+}
+
/**
* This creates a "buffer" source for this surface
*/
@@ -189,85 +198,52 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() {
}
// ============================================================================
-// LayerBuffer::SurfaceBuffer
+// LayerBuffer::SurfaceLayerBuffer
// ============================================================================
-LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
-: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner)
+ : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
{
}
-LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
+LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
{
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::SurfaceLayerBuffer::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)
+void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->postBuffer(offset);
}
-void LayerBuffer::SurfaceBuffer::unregisterBuffers()
+void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->unregisterBuffers();
}
-sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
+sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::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 +252,36 @@ 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.handle = 0;
+
+ gralloc_module_t const * module = LayerBuffer::getGrallocModule();
+ if (module && module->perform) {
+ int err = module->perform(module,
+ GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
+ buffers.heap->heapID(), buffers.heap->getSize(),
+ offset, buffers.heap->base(),
+ &src.img.handle);
+
+ if (err == NO_ERROR) {
+ 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.base = (void*)(intptr_t(buffers.heap->base()) + offset);
+ }
+ }
}
LayerBuffer::Buffer::~Buffer()
{
+ NativeBuffer& src(mNativeBuffer);
+ if (src.img.handle) {
+ native_handle_delete(src.img.handle);
+ }
}
// ============================================================================
@@ -323,8 +315,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 +354,16 @@ 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();
-
}
LayerBuffer::BufferSource::~BufferSource()
{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
+ if (mTexture.name != -1U) {
+ glDeleteTextures(1, &mTexture.name);
+ }
+ if (mTexture.image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTexture.image);
}
}
@@ -377,7 +371,7 @@ void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
ISurface::BufferHeap buffers;
{ // scope for the lock
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mBufferSourceLock);
buffers = mBufferHeap;
if (buffers.heap != 0) {
const size_t memorySize = buffers.heap->getSize();
@@ -402,7 +396,7 @@ void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
void LayerBuffer::BufferSource::unregisterBuffers()
{
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mBufferSourceLock);
mBufferHeap.heap.clear();
mBuffer.clear();
mLayer.invalidate();
@@ -410,13 +404,13 @@ void LayerBuffer::BufferSource::unregisterBuffers()
sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
{
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mBufferSourceLock);
return mBuffer;
}
void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
{
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mBufferSourceLock);
mBuffer = buffer;
}
@@ -427,113 +421,40 @@ 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());
- const Rect& transformedBounds = mLayer.getTransformedBounds();
- const int can_use_copybit = mLayer.canUseCopybit();
-
- if (can_use_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();
- int H = transformedBounds.height();
- if (mLayer.getOrientation() & Transform::ROT_90) {
- int t(W); W=H; H=t;
- }
+ NativeBuffer src(ourBuffer->getBuffer());
+ const Rect transformedBounds(mLayer.getTransformedBounds());
- /* 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);
- }
+ if (UNLIKELY(mTexture.name == -1LU)) {
+ mTexture.name = mLayer.createTexture();
+ }
- 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;
- }
- }
+#if defined(EGL_ANDROID_image_native_buffer)
+ if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
+ // NOTE: Assume the buffer is allocated with the proper USAGE flags
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ src.crop.r, src.crop.b, src.img.format,
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ src.img.w, src.img.handle, false);
- 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));
- }
+ graphicBuffer->setVerticalStride(src.img.h);
+
+ err = mLayer.initializeEglImage(graphicBuffer, &mTexture);
+ }
+#endif
+ else {
+ err = INVALID_OPERATION;
}
- if (!can_use_copybit || err) {
- if (UNLIKELY(mTextureName == -1LU)) {
- mTextureName = mLayer.createTexture();
- }
- GLuint w = 0;
- GLuint h = 0;
+ if (err != NO_ERROR) {
+ // slower fallback
GGLSurface t;
t.version = sizeof(GGLSurface);
t.width = src.crop.r;
@@ -541,13 +462,14 @@ 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, dirty, t);
}
-}
+ mTexture.transform = mBufferHeap.transform;
+ mLayer.drawWithOpenGL(clip, mTexture);
+}
// ---------------------------------------------------------------------------
@@ -580,15 +502,15 @@ LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
mFormat = overlay->format;
mWidthStride = overlay->w_stride;
mHeightStride = overlay->h_stride;
+ mInitialized = false;
mOverlayHandle = overlay->getHandleRef(overlay);
- // NOTE: here it's okay to acquire a reference to "this"m as long as
- // the reference is not released before we leave the ctor.
- sp<OverlayChannel> channel = new OverlayChannel(this);
+ sp<OverlayChannel> channel = new OverlayChannel( &layer );
*overlayRef = new OverlayRef(mOverlayHandle, channel,
mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+ mLayer.mFlinger->signalEvent();
}
LayerBuffer::OverlaySource::~OverlaySource()
@@ -599,6 +521,15 @@ LayerBuffer::OverlaySource::~OverlaySource()
}
}
+void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
+{
+ // this would be where the color-key would be set, should we need it.
+ GLclampx red = 0;
+ GLclampx green = 0;
+ GLclampx blue = 0;
+ mLayer.clearWithOpenGL(clip, red, green, blue, 0);
+}
+
void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
{
const Layer::State& front(mLayer.drawingState());
@@ -614,37 +545,33 @@ 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;
- const Rect& bounds = mLayer.getTransformedBounds();
+ mInitialized = true;
+ const Rect bounds(mLayer.getTransformedBounds());
int x = bounds.left;
int y = bounds.top;
int w = bounds.width();
int h = bounds.height();
// we need a lock here to protect "destroy"
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mOverlaySourceLock);
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);
}
}
}
}
-void LayerBuffer::OverlaySource::serverDestroy()
-{
- mLayer.clearSource();
- destroyOverlay();
-}
-
-void LayerBuffer::OverlaySource::destroyOverlay()
+void LayerBuffer::OverlaySource::destroy()
{
// we need a lock here to protect "onVisibilityResolved"
- Mutex::Autolock _l(mLock);
- if (mOverlay) {
+ Mutex::Autolock _l(mOverlaySourceLock);
+ if (mOverlay && mOverlayDevice) {
overlay_control_device_t* overlay_dev = mOverlayDevice;
overlay_dev->destroyOverlay(overlay_dev, mOverlay);
mOverlay = 0;
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2dc77f1..47482f4 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -20,21 +20,20 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/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 Buffer;
class Region;
class OverlayRef;
+// ---------------------------------------------------------------------------
+
class LayerBuffer : public LayerBaseClient
{
class Source : public LightRefBase<Source> {
@@ -47,11 +46,11 @@ class LayerBuffer : public LayerBaseClient
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
virtual bool transformed() const;
+ virtual void destroy() { }
protected:
LayerBuffer& mLayer;
};
-
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -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);
@@ -78,16 +79,23 @@ public:
sp<Source> getSource() const;
sp<Source> clearSource();
void setNeedsBlending(bool blending);
- const Rect& getTransformedBounds() const {
+ Rect getTransformedBounds() const {
return mTransformedBounds;
}
+ void serverDestroy();
+
private:
struct NativeBuffer {
copybit_image_t img;
copybit_rect_t crop;
};
+ static gralloc_module_t const* sGrallocModule;
+ static gralloc_module_t const* getGrallocModule() {
+ return sGrallocModule;
+ }
+
class Buffer : public LightRefBase<Buffer> {
public:
Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
@@ -120,15 +128,15 @@ private:
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
virtual bool transformed() const;
+ virtual void destroy() { }
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 mBufferSourceLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable sp<GraphicBuffer> mTempBitmap;
+ mutable LayerBase::Texture mTexture;
};
class OverlaySource : public Source {
@@ -137,30 +145,26 @@ 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);
+ virtual void destroy();
private:
- void serverDestroy();
- void destroyOverlay();
+
class OverlayChannel : public BnOverlay {
- mutable Mutex mLock;
- sp<OverlaySource> mSource;
+ wp<LayerBuffer> mLayer;
virtual void destroy() {
- sp<OverlaySource> source;
- { // scope for the lock;
- Mutex::Autolock _l(mLock);
- source = mSource;
- mSource.clear();
- }
- if (source != 0) {
- source->serverDestroy();
+ sp<LayerBuffer> layer(mLayer.promote());
+ if (layer != 0) {
+ layer->serverDestroy();
}
}
public:
- OverlayChannel(const sp<OverlaySource>& source)
- : mSource(source) {
+ OverlayChannel(const sp<LayerBuffer>& layer)
+ : mLayer(layer) {
}
};
+
friend class OverlayChannel;
bool mVisibilityChanged;
@@ -172,41 +176,35 @@ private:
int32_t mFormat;
int32_t mWidthStride;
int32_t mHeightStride;
- mutable Mutex mLock;
+ mutable Mutex mOverlaySourceLock;
+ bool mInitialized;
};
- class SurfaceBuffer : public LayerBaseClient::Surface
+ class SurfaceLayerBuffer : public LayerBaseClient::Surface
{
public:
- SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
- virtual ~SurfaceBuffer();
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner);
+ virtual ~SurfaceLayerBuffer();
+
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..fd61e30 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>
@@ -23,9 +21,10 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <ui/GraphicBuffer.h>
+
#include "LayerDim.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
@@ -33,27 +32,76 @@ 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;
+
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
+
+#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)) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN |
+ GraphicBuffer::USAGE_HW_TEXTURE);
+
+ 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_WRITE_OFTEN);
+ memset(t.data, 0, t.stride * t.height * 2);
+ buffer->unlock();
+ sUseTexture = true;
}
+#endif
}
LayerDim::~LayerDim()
@@ -63,49 +111,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);
+
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
+ 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..d4672a1 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -20,15 +20,22 @@
#include <stdint.h>
#include <sys/types.h>
-#include "LayerBase.h"
-#include "LayerBitmap.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
-namespace android {
+#include "LayerBase.h"
// ---------------------------------------------------------------------------
+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 +43,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 +51,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/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
deleted file mode 100644
index 12b6f1c..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ /dev/null
@@ -1,80 +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_LAYER_ORIENTATION_ANIM_H
-#define ANDROID_LAYER_ORIENTATION_ANIM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/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 LayerBitmap& bitmapIn,
- const LayerBitmap& 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:
- OrientationAnimation* mAnim;
- LayerBitmap mBitmapIn;
- LayerBitmap mBitmapOut;
- bool mOrientationCompleted;
- mutable GLuint mTextureName;
- mutable GLuint mTextureNameIn;
- mutable bool mNeedsBlending;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
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/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
deleted file mode 100644
index 12c0eef..0000000
--- a/libs/surfaceflinger/OrientationAnimation.cpp
+++ /dev/null
@@ -1,155 +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 <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#include "DisplayHardware/DisplayHardware.h"
-
-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()
-{
-}
-
-void OrientationAnimation::onOrientationChanged(uint32_t type)
-{
- if (mState == DONE) {
- mType = type;
- if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
- mState = PREPARE;
- }
- }
-}
-
-void OrientationAnimation::onAnimationFinished()
-{
- if (mState != DONE)
- mState = FINISH;
-}
-
-bool OrientationAnimation::run_impl()
-{
- bool skip_frame;
- switch (mState) {
- default:
- case DONE:
- skip_frame = done();
- break;
- case PREPARE:
- skip_frame = prepare();
- break;
- case PHASE1:
- skip_frame = phase1();
- break;
- case PHASE2:
- skip_frame = phase2();
- break;
- case FINISH:
- skip_frame = finished();
- break;
- }
- return skip_frame;
-}
-
-bool OrientationAnimation::done()
-{
- return done_impl();
-}
-
-bool OrientationAnimation::prepare()
-{
- mState = PHASE1;
-
- const GraphicPlane& plane(mFlinger->graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- 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());
-
- copybit_image_t front;
- bitmap.getBitmapSurface(&front);
- hw.copyFrontToImage(front);
-
- LayerOrientationAnimBase* l;
-
- l = new LayerOrientationAnim(
- mFlinger.get(), 0, this, bitmap, bitmapIn);
-
- l->initStates(w, h, 0);
- l->setLayer(INT_MAX-1);
- mFlinger->addLayer(l);
- mLayerOrientationAnim = l;
- return true;
-}
-
-bool OrientationAnimation::phase1()
-{
- if (mFlinger->isFrozen() == false) {
- // start phase 2
- mState = PHASE2;
- mLayerOrientationAnim->onOrientationCompleted();
- mLayerOrientationAnim->invalidate();
- return true;
-
- }
- //mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::phase2()
-{
- // do the 2nd phase of the animation
- mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::finished()
-{
- mState = DONE;
- mFlinger->removeLayer(mLayerOrientationAnim);
- mLayerOrientationAnim = NULL;
- return true;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
deleted file mode 100644
index cafa38d..0000000
--- a/libs/surfaceflinger/OrientationAnimation.h
+++ /dev/null
@@ -1,85 +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_ORIENTATION_ANIMATION_H
-#define ANDROID_ORIENTATION_ANIMATION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class SurfaceFlinger;
-class MemoryDealer;
-class LayerOrientationAnim;
-
-class OrientationAnimation
-{
-public:
- OrientationAnimation(const sp<SurfaceFlinger>& flinger);
- virtual ~OrientationAnimation();
-
- void onOrientationChanged(uint32_t type);
- void onAnimationFinished();
- inline bool run() {
- if (LIKELY(mState == DONE))
- return done_impl();
- return run_impl();
- }
-
-private:
- enum {
- DONE = 0,
- PREPARE,
- PHASE1,
- PHASE2,
- FINISH
- };
-
- bool run_impl();
- inline bool done_impl() {
- if (mFlinger->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 true;
- }
- return false;
- }
-
- bool done();
- bool prepare();
- bool phase1();
- bool phase2();
- bool finished();
-
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mTemporaryDealer;
- LayerOrientationAnimBase* mLayerOrientationAnim;
- int mState;
- uint32_t mType;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 97dfecc..9694cf1 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,29 @@
#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/GraphicBufferAllocator.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 "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 +85,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 +131,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 +153,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,19 +172,24 @@ SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
mTransactionCount(0),
+ mResizeTransationPending(false),
+ mLayersRemoved(false),
mBootTime(systemTime()),
- mLastScheduledBroadcast(NULL),
+ mHardwareTest("android.permission.HARDWARE_TEST"),
+ mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
+ mDump("android.permission.DUMP"),
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
- mDebugCpu(0),
- mDebugFps(0),
mDebugBackground(0),
- mSyncObject(),
- mDeplayedTransactionPending(0),
+ mDebugInSwapBuffers(0),
+ mLastSwapBufferTime(0),
+ mDebugInTransaction(0),
+ mLastTransactionTime(0),
+ mBootFinished(false),
mConsoleSignals(0),
mSecureFrameBuffer(0)
{
@@ -207,28 +204,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 +221,9 @@ overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
return graphicPlane(0).displayHardware().getOverlayEngine();
}
-sp<IMemory> 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()
+sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- return mGPU->friendlyRevoke();
+ return mServerHeap;
}
sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
@@ -266,33 +231,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
@@ -328,6 +294,7 @@ void SurfaceFlinger::bootFinished()
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ mBootFinished = true;
property_set("ctl.stop", "bootanim");
}
@@ -339,41 +306,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 +325,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 +401,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 +415,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);
}
// ----------------------------------------------------------------------------
@@ -540,24 +492,20 @@ bool SurfaceFlinger::threadLoop()
handlePageFlip();
const DisplayHardware& hw(graphicPlane(0).displayHardware());
- if (LIKELY(hw.canDraw())) {
+ if (LIKELY(hw.canDraw() && !isFrozen())) {
// repaint the framebuffer (if needed)
handleRepaint();
+ // inform the h/w that we're done compositing
+ hw.compositionComplete();
+
// release the clients before we flip ('cause flip might block)
unlockClients();
- executeScheduledBroadcasts();
-
- // sample the cpu gauge
- if (UNLIKELY(mDebugCpu)) {
- handleDebugCpu();
- }
postFramebuffer();
} else {
// pretend we did the post
unlockClients();
- executeScheduledBroadcasts();
usleep(16667); // 60 fps period
}
return true;
@@ -565,28 +513,14 @@ bool SurfaceFlinger::threadLoop()
void SurfaceFlinger::postFramebuffer()
{
- const bool skip = mOrientationAnimation->run();
- if (UNLIKELY(skip)) {
- return;
- }
-
if (!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
+ const nsecs_t now = systemTime();
+ mDebugInSwapBuffers = now;
hw.flip(mInvalidRegion);
-
+ mLastSwapBufferTime = systemTime() - now;
+ mDebugInSwapBuffers = 0;
mInvalidRegion.clear();
-
- if (Layer::deletedTextures.size()) {
- glDeleteTextures(
- Layer::deletedTextures.size(),
- Layer::deletedTextures.array());
- Layer::deletedTextures.clear();
- }
}
}
@@ -601,15 +535,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 +553,31 @@ void SurfaceFlinger::handleConsoleEvents()
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
- Mutex::Autolock _l(mStateLock);
+ Vector< sp<LayerBase> > ditchedLayers;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
+ }
+
+ // do this without lock held
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (ditchedLayers[i] != 0) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+ }
+}
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
/*
@@ -634,19 +588,13 @@ 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;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
-
- if (flags & Layer::eRestartTransaction) {
- // restart the transaction, but back-off a little
- layer->setTransactionFlags(eTransactionNeeded);
- setTransactionFlags(eTraversalNeeded, ms2ns(8));
- }
}
}
@@ -681,7 +629,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
mFreezeDisplayTime = 0;
- mOrientationAnimation->onOrientationChanged(type);
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
@@ -689,22 +636,26 @@ 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.
- const SortedVector<LayerBase*>& removedLayers(mRemovedLayers);
- size_t c = removedLayers.size();
- if (c) {
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
mVisibleRegionsDirty = true;
- while (c--) {
- mDirtyRegionRemovedLayer.orSelf(
- removedLayers[c]->visibleRegionScreen);
- }
}
- 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) {
+ mLayersRemoved = false;
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);
+ mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
+ }
+ }
}
// get rid of all resources we don't need anymore
@@ -734,7 +685,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
@@ -785,7 +736,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);
@@ -811,7 +762,8 @@ void SurfaceFlinger::computeVisibleRegions(
void SurfaceFlinger::commitTransaction()
{
mDrawingState = mCurrentState;
- mTransactionCV.signal();
+ mResizeTransationPending = false;
+ mTransactionCV.broadcast();
}
void SurfaceFlinger::handlePageFlip()
@@ -837,9 +789,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;
@@ -850,37 +802,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
+ if (flags & DisplayHardware::PARTIAL_UPDATES) {
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because PARTIAL_UPDATES 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;
}
@@ -903,9 +876,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));
@@ -920,67 +893,42 @@ 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)
-{
- if (mLastScheduledBroadcast != client) {
- mLastScheduledBroadcast = client;
- mScheduledBroadcasts.add(client);
- }
-}
-
-void SurfaceFlinger::executeScheduledBroadcasts()
-{
- SortedVector<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));
- }
- }
- 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::PARTIAL_UPDATES) ?
+ 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 },
@@ -990,10 +938,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);
@@ -1017,9 +967,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);
@@ -1037,9 +988,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);
@@ -1065,7 +1017,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);
@@ -1073,91 +1025,77 @@ 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)
{
+ if (layer == 0)
+ return BAD_VALUE;
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);
+
+ layerBase->onRemoved();
+
// 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();
-
// free resources associated with disconnected clients
- SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
- Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
const size_t count = disconnectedClients.size();
for (size_t i=0 ; i<count ; i++) {
- 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).
- int32_t index = scheduledBroadcasts.indexOf(client);
- if (index >= 0) {
- scheduledBroadcasts.removeItemsAt(index);
- }
+ sp<Client> client = disconnectedClients[i];
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;
@@ -1185,6 +1123,20 @@ void SurfaceFlinger::closeGlobalTransaction()
{
if (android_atomic_dec(&mTransactionCount) == 1) {
signalEvent();
+
+ // if there is a transaction with a resize, wait for it to
+ // take effect before returning.
+ Mutex::Autolock _l(mStateLock);
+ while (mResizeTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mResizeTransationPending = false;
+ break;
+ }
+ }
}
}
@@ -1198,7 +1150,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;
}
@@ -1212,7 +1164,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;
}
@@ -1241,7 +1193,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) {
@@ -1251,14 +1203,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;
@@ -1267,32 +1219,40 @@ 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, flags, format);
}
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)
- surfaceHandle->getSurfaceData(params);
+ if (surfaceHandle != 0) {
+ params->token = surfaceHandle->getToken();
+ params->identity = surfaceHandle->getIdentity();
+ params->width = w;
+ params->height = h;
+ params->format = format;
+ }
}
return surfaceHandle;
}
-LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
- Client* client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format)
{
// initialize the surfaces
switch (format) { // TODO: take h/w into account
@@ -1305,57 +1265,102 @@ 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).
+ */
+
+ status_t err = NAME_NOT_FOUND;
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);
+ if (layer != 0) {
+ 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;
}
@@ -1369,18 +1374,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;
@@ -1395,8 +1391,10 @@ status_t SurfaceFlinger::setClientState(
}
}
if (what & eSizeChanged) {
- if (layer->setSize(s.w, s.h))
+ if (layer->setSize(s.w, s.h)) {
flags |= eTraversalNeeded;
+ mResizeTransationPending = true;
+ }
}
if (what & eAlphaChanged) {
if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
@@ -1422,9 +1420,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)
@@ -1446,20 +1445,40 @@ 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(),
IPCThreadState::self()->getCallingUid());
result.append(buffer);
} else {
- Mutex::Autolock _l(mStateLock);
+
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ // Try to get the main lock, but don't insist if we can't
+ // (this would indicate SF is stuck, but we want to be able to
+ // print something in dumpsys).
+ int retry = 3;
+ while (mStateLock.tryLock()<0 && --retry>=0) {
+ usleep(1000000);
+ }
+ const bool locked(retry >= 0);
+ if (!locked) {
+ snprintf(buffer, SIZE,
+ "SurfaceFlinger appears to be unresponsive, "
+ "dumping anyways (no locks held)\n");
+ result.append(buffer);
+ }
+
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);
}
@@ -1467,51 +1486,66 @@ 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"
" "
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
- "needsBlending=%1d, invalidate=%1d, "
+ "needsBlending=%1d, needsDithering=%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,
+ layer->needsBlending(), layer->needsDithering(),
+ layer->contentDirty,
s.alpha, s.flags,
s.transform[0], s.transform[1],
s.transform[2], s.transform[3]);
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;
}
- result.append(buffer);
- buffer[0] = 0;
/*** Layer ***/
- Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
- if (l) {
- const LayerBitmap& buf0(l->getBuffer(0));
- const LayerBitmap& buf1(l->getBuffer(1));
+ sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
+ if (l != 0) {
+ SharedBufferStack::Statistics stats = l->lcblk->getStats();
+ result.append( l->lcblk->dump(" ") );
+ sp<const GraphicBuffer> buf0(l->getBuffer(0));
+ sp<const GraphicBuffer> buf1(l->getBuffer(1));
+ uint32_t w0=0, h0=0, s0=0;
+ uint32_t w1=0, h1=0, s1=0;
+ if (buf0 != 0) {
+ w0 = buf0->getWidth();
+ h0 = buf0->getHeight();
+ s0 = buf0->getStride();
+ }
+ if (buf1 != 0) {
+ w1 = buf1->getWidth();
+ h1 = buf1->getHeight();
+ s1 = buf1->getStride();
+ }
snprintf(buffer, SIZE,
" "
- "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
- " freezeLock=%p, swapState=0x%08x\n",
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
+ " freezeLock=%p, dq-q-time=%u us\n",
l->pixelFormat(),
- buf0.width(), buf0.height(), buf0.stride(),
- buf1.width(), buf1.height(), buf1.stride(),
- l->getTextureName(), l->getFreezeLock().get(),
- l->lcblk->swapState);
+ w0, h0, s0, w1, h1, s1,
+ l->getFreezeLock().get(), stats.totalTime);
+ result.append(buffer);
+ buffer[0] = 0;
}
- result.append(buffer);
- buffer[0] = 0;
s.transparentRegion.dump(result, "transparentRegion");
layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
@@ -1523,19 +1557,28 @@ 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());
+ snprintf(buffer, SIZE,
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n",
+ mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
+ result.append(buffer);
+ if (inSwapBuffersDuration || !locked) {
+ snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+ result.append(buffer);
+ }
+ if (inTransactionDuration || !locked) {
+ snprintf(buffer, SIZE, " transaction time: %f us\n",
+ inTransactionDuration/1000.0);
result.append(buffer);
- 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 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.dump(result);
+
+ if (locked) {
+ mStateLock.unlock();
}
}
write(fd, result.string(), result.size());
@@ -1553,57 +1596,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();
@@ -1618,23 +1638,17 @@ status_t SurfaceFlinger::onTransact(
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
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();
- }
+ }
+ case 1005:{ // force transaction
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
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);
@@ -1658,30 +1672,24 @@ 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(SharedClient)+(pgsize-1))&~(pgsize-1));
+
+ mCblkHeap = new MemoryHeapBase(cblksize, 0,
+ "SurfaceFlinger Client control-block");
+
+ ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) SharedClient;
}
}
Client::~Client() {
if (ctrlblk) {
- const int pgsize = getpagesize();
- ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
+ ctrlblk->~SharedClient(); // destroy our shared-structure.
}
}
-const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
- return mFlinger->getSurfaceHeapManager();
-}
-
int32_t Client::generateId(int pid)
{
const uint32_t i = clz( ~mBitmap );
@@ -1693,13 +1701,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));
@@ -1709,27 +1719,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)
@@ -1741,7 +1742,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)
{
}
@@ -1751,8 +1752,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(
@@ -1766,7 +1767,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)
@@ -1866,6 +1867,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 0d63e1d..f9bfe6c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -25,21 +25,24 @@
#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>
#include <ui/ISurfaceFlingerClient.h>
-#include <private/ui/SharedState.h>
+#include <private/ui/SharedBufferStack.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,35 +72,34 @@ 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;
+ SharedClient* ctrlblk;
ClientID cid;
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, uint32_t flags,
+ PixelFormat& format);
- 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,38 +242,26 @@ 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();
+public: // hack to work around gcc 4.0.3 bug
const GraphicPlane& graphicPlane(int dpy) const;
GraphicPlane& graphicPlane(int dpy);
+private:
void waitForEvent();
+public: // hack to work around gcc 4.0.3 bug
void signalEvent();
+private:
void signalDelayedEvent(nsecs_t delay);
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(
+ uint32_t transactionFlags,
+ Vector< sp<LayerBase> >& ditchedLayers);
void computeVisibleRegions(
LayerVector& currentLayers,
@@ -289,19 +272,16 @@ private:
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRepaint();
- void handleDebugCpu();
- void scheduleBroadcast(Client* client);
- void executeScheduledBroadcasts();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
void unlockClients();
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);
@@ -315,7 +295,7 @@ private:
inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
inline bool hasFreezeRequest() const { return mFreezeDisplay; }
inline bool isFrozen() const {
- return mFreezeDisplay || mFreezeCount>0;
+ return (mFreezeDisplay || mFreezeCount>0) && mBootFinished;
}
@@ -323,6 +303,11 @@ private:
void debugShowFPS() const;
void drawWormhole() const;
+
+ mutable MessageQueue mEventQueue;
+
+
+
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState;
@@ -330,23 +315,24 @@ private:
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
-
+ bool mResizeTransationPending;
+
// 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
@@ -354,30 +340,23 @@ private:
Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
Region mWormholeRegion;
- Client* mLastScheduledBroadcast;
- SortedVector<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;
+ volatile nsecs_t mDebugInSwapBuffers;
+ nsecs_t mLastSwapBufferTime;
+ volatile nsecs_t mDebugInTransaction;
+ nsecs_t mLastTransactionTime;
+ bool mBootFinished;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
- mutable SurfaceFlingerSynchro mSyncObject;
- volatile int32_t mDeplayedTransactionPending;
// atomic variables
enum {
@@ -410,11 +389,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,
@@ -427,7 +406,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/Transform.h b/libs/surfaceflinger/Transform.h
index 4c4528e..78f5c19 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -50,6 +50,14 @@ public:
ROT_INVALID = 0x80000000
};
+ enum type_mask {
+ IDENTITY = 0,
+ TRANSLATE = 0x1,
+ SCALE = 0x2,
+ AFFINE = 0x4,
+ PERSPECTIVE = 0x8
+ };
+
bool transformed() const;
int32_t getOrientation() const;
bool preserveRects() const;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
deleted file mode 100644
index 5f633bd..0000000
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ /dev/null
@@ -1,178 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-
-#include <EGL/eglnatives.h>
-
-#include "GPUHardware/GPUHardware.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-/*
- * Amount of memory we reserve for surface, per client in PMEM
- * (PMEM is used for 2D acceleration)
- * 8 MB of address space per client should be enough.
- */
-static const int PMEM_SIZE = int(8 * 1024 * 1024);
-
-int SurfaceHeapManager::global_pmem_heap = 0;
-
-// ---------------------------------------------------------------------------
-
-SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
- size_t clientHeapSize)
- : mFlinger(flinger), mClientHeapSize(clientHeapSize)
-{
- SurfaceHeapManager::global_pmem_heap = 1;
-}
-
-SurfaceHeapManager::~SurfaceHeapManager()
-{
-}
-
-void SurfaceHeapManager::onFirstRef()
-{
- if (global_pmem_heap) {
- const char* device = "/dev/pmem";
- mPMemHeap = new PMemHeap(device, PMEM_SIZE);
- if (mPMemHeap->base() == MAP_FAILED) {
- mPMemHeap.clear();
- global_pmem_heap = 0;
- }
- }
-}
-
-sp<MemoryDealer> SurfaceHeapManager::createHeap(
- uint32_t flags,
- pid_t client_pid,
- const sp<MemoryDealer>& defaultAllocator)
-{
- sp<MemoryDealer> dealer;
-
- if (flags & ISurfaceComposer::eGPU) {
- // don't grant GPU memory if GPU is disabled
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) == 0) {
- flags &= ~ISurfaceComposer::eGPU;
- }
- }
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
- if (!(flags & ISurfaceComposer::eSecure)) {
- // if GPU doesn't work, we try eHardware
- flags |= ISurfaceComposer::eHardware;
- // asked for GPU memory, try that first
- dealer = mFlinger->getGPU()->request(client_pid);
- }
- }
-
- if (dealer == NULL) {
- if (defaultAllocator != NULL)
- // if a default allocator is given, use that
- dealer = defaultAllocator;
- }
-
- if (dealer == NULL) {
- // always try h/w accelerated memory first
- if (global_pmem_heap) {
- const sp<PMemHeap>& heap(mPMemHeap);
- if (dealer == NULL && heap != NULL) {
- dealer = new MemoryDealer(
- heap->createClientHeap(),
- heap->getAllocator());
- }
- }
- }
-
- if (dealer == NULL) {
- // return the ashmem allocator (software rendering)
- dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
- }
- return dealer;
-}
-
-sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
-{
- Mutex::Autolock _l(mLock);
- sp<SimpleBestFitAllocator> allocator;
-
- // this is only used for debugging
- switch (type) {
- case NATIVE_MEMORY_TYPE_PMEM:
- if (mPMemHeap != 0) {
- allocator = mPMemHeap->getAllocator();
- }
- break;
- }
- return allocator;
-}
-
-// ---------------------------------------------------------------------------
-
-PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
- : MemoryHeapBase(device, size)
-{
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
- if (base() != MAP_FAILED) {
- //LOGD("%s, %u bytes", device, virtualSize());
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
-}
-
-PMemHeap::~PMemHeap() {
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
-}
-
-sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapPmem(parentHeap);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
deleted file mode 100644
index 9140167..0000000
--- a/libs/surfaceflinger/VRamHeap.h
+++ /dev/null
@@ -1,78 +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 ANDROID_VRAM_HEAP_H
-#define ANDROID_VRAM_HEAP_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/MemoryDealer.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class PMemHeap;
-class MemoryHeapPmem;
-class SurfaceFlinger;
-
-// ---------------------------------------------------------------------------
-
-class SurfaceHeapManager : public RefBase
-{
-public:
- SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
- virtual ~SurfaceHeapManager();
- virtual void onFirstRef();
- /* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
- sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
- const sp<MemoryDealer>& defaultAllocator = 0);
-
- // used for debugging only...
- sp<SimpleBestFitAllocator> getAllocator(int type) const;
-
-private:
- sp<PMemHeap> getHeap(int type) const;
-
- sp<SurfaceFlinger> mFlinger;
- mutable Mutex mLock;
- size_t mClientHeapSize;
- sp<PMemHeap> mPMemHeap;
- static int global_pmem_heap;
-};
-
-// ---------------------------------------------------------------------------
-
-class PMemHeap : public MemoryHeapBase
-{
-public:
- PMemHeap(const char* const vram,
- size_t size=0, size_t reserved=0);
- virtual ~PMemHeap();
-
- virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
- return mAllocator;
- }
- virtual sp<MemoryHeapPmem> createClientHeap();
-
-private:
- sp<SimpleBestFitAllocator> mAllocator;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_VRAM_HEAP_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..84aec61 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -4,10 +4,13 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
Camera.cpp \
CameraParameters.cpp \
- EGLDisplaySurface.cpp \
- EGLNativeWindowSurface.cpp \
+ EGLUtils.cpp \
EventHub.cpp \
EventRecurrence.cpp \
+ FramebufferNativeWindow.cpp \
+ GraphicBuffer.cpp \
+ GraphicBufferAllocator.cpp \
+ GraphicBufferMapper.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
ICamera.cpp \
@@ -22,18 +25,23 @@ LOCAL_SRC_FILES:= \
PixelFormat.cpp \
Rect.cpp \
Region.cpp \
+ SharedBufferStack.cpp \
Surface.cpp \
- SurfaceComposerClient.cpp \
- SurfaceFlingerSynchro.cpp
+ SurfaceComposerClient.cpp
LOCAL_SHARED_LIBRARIES := \
- libcorecg \
libcutils \
libutils \
+ libEGL \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
LOCAL_MODULE:= libui
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 5015379..09a36f1 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>
@@ -242,6 +242,14 @@ status_t Camera::autoFocus()
return c->autoFocus();
}
+status_t Camera::cancelAutoFocus()
+{
+ LOGV("cancelAutoFocus");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->cancelAutoFocus();
+}
+
// take a picture
status_t Camera::takePicture()
{
@@ -270,6 +278,15 @@ String8 Camera::getParameters() const
return params;
}
+// send command to camera driver
+status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+{
+ LOGD("sendCommand");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->sendCommand(cmd, arg1, arg2);
+}
+
void Camera::setListener(const sp<CameraListener>& listener)
{
Mutex::Autolock _l(mLock);
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 6c25836..8f1749d 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -2,16 +2,16 @@
**
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -23,6 +23,103 @@
#include <ui/CameraParameters.h>
namespace android {
+// Parameter keys to communicate between camera application and driver.
+const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
+const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
+const char CameraParameters::KEY_SUPPORTED_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
+const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
+const char CameraParameters::KEY_ROTATION[] = "rotation";
+const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
+const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
+const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
+const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
+const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
+const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
+const char CameraParameters::KEY_EFFECT[] = "effect";
+const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
+const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
+const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
+const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
+const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
+const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
+const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
+
+// Values for white balance settings.
+const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
+const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
+const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
+const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
+const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
+const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
+const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
+const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
+
+// Values for effect settings.
+const char CameraParameters::EFFECT_NONE[] = "none";
+const char CameraParameters::EFFECT_MONO[] = "mono";
+const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
+const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
+const char CameraParameters::EFFECT_SEPIA[] = "sepia";
+const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
+const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
+const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
+const char CameraParameters::EFFECT_AQUA[] = "aqua";
+
+// Values for antibanding settings.
+const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
+const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
+const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
+const char CameraParameters::ANTIBANDING_OFF[] = "off";
+
+// Values for flash mode settings.
+const char CameraParameters::FLASH_MODE_OFF[] = "off";
+const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
+const char CameraParameters::FLASH_MODE_ON[] = "on";
+const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
+const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
+
+// Values for scene mode settings.
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_ACTION[] = "action";
+const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
+const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
+const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
+const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
+const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
+const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
+const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
+const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
+const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
+const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
+const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
+const char CameraParameters::SCENE_MODE_PARTY[] = "party";
+const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+
+// Formats for setPreviewFormat and setPictureFormat.
+const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
+const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
+const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+
+// Values for focus mode settings.
+const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
+const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
+const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
+const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
static const char* portrait = "portrait";
static const char* landscape = "landscape";
@@ -91,7 +188,7 @@ void CameraParameters::unflatten(const String8 &params)
void CameraParameters::set(const char *key, const char *value)
{
- // XXX i think i can do this with strspn()
+ // XXX i think i can do this with strspn()
if (strchr(key, '=') || strchr(key, ';')) {
//XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key);
return;
@@ -150,7 +247,7 @@ void CameraParameters::setPreviewSize(int width, int height)
{
char str[32];
sprintf(str, "%dx%d", width, height);
- set("preview-size", str);
+ set(KEY_PREVIEW_SIZE, str);
}
void CameraParameters::getPreviewSize(int *width, int *height) const
@@ -159,7 +256,7 @@ void CameraParameters::getPreviewSize(int *width, int *height) const
*height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get("preview-size");
+ const char *p = get(KEY_PREVIEW_SIZE);
if (p == 0)
return;
@@ -172,17 +269,17 @@ void CameraParameters::getPreviewSize(int *width, int *height) const
void CameraParameters::setPreviewFrameRate(int fps)
{
- set("preview-frame-rate", fps);
+ set(KEY_PREVIEW_FRAME_RATE, fps);
}
int CameraParameters::getPreviewFrameRate() const
{
- return getInt("preview-frame-rate");
+ return getInt(KEY_PREVIEW_FRAME_RATE);
}
void CameraParameters::setPreviewFormat(const char *format)
{
- set("preview-format", format);
+ set(KEY_PREVIEW_FORMAT, format);
}
int CameraParameters::getOrientation() const
@@ -196,22 +293,22 @@ int CameraParameters::getOrientation() const
void CameraParameters::setOrientation(int orientation)
{
if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
- set("preview-format", portrait);
+ set("orientation", portrait);
} else {
- set("preview-format", landscape);
+ set("orientation", landscape);
}
}
const char *CameraParameters::getPreviewFormat() const
{
- return get("preview-format");
+ return get(KEY_PREVIEW_FORMAT);
}
void CameraParameters::setPictureSize(int width, int height)
{
char str[32];
sprintf(str, "%dx%d", width, height);
- set("picture-size", str);
+ set(KEY_PICTURE_SIZE, str);
}
void CameraParameters::getPictureSize(int *width, int *height) const
@@ -220,7 +317,7 @@ void CameraParameters::getPictureSize(int *width, int *height) const
*height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get("picture-size");
+ const char *p = get(KEY_PICTURE_SIZE);
if (p == 0)
return;
@@ -233,12 +330,12 @@ void CameraParameters::getPictureSize(int *width, int *height) const
void CameraParameters::setPictureFormat(const char *format)
{
- set("picture-format", format);
+ set(KEY_PICTURE_FORMAT, format);
}
const char *CameraParameters::getPictureFormat() const
{
- return get("picture-format");
+ return get(KEY_PICTURE_FORMAT);
}
void CameraParameters::dump() const
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/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
new file mode 100644
index 0000000..1663313
--- /dev/null
+++ b/libs/ui/EGLUtils.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "EGLUtils"
+
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+#include <ui/EGLUtils.h>
+
+#include <EGL/egl.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const char *EGLUtils::strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+status_t EGLUtils::selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig)
+{
+ EGLint numConfigs = -1, n=0;
+
+ if (!attrs)
+ return BAD_VALUE;
+
+ if (outConfig == NULL)
+ return BAD_VALUE;
+
+ int err;
+ PixelFormatInfo fbFormatInfo;
+ if ((err = getPixelFormatInfo(PixelFormat(format), &fbFormatInfo)) < 0) {
+ return err;
+ }
+
+ // Get all the "potential match" configs...
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ return BAD_VALUE;
+
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+ const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+ const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+ const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint r,g,b,a;
+ EGLConfig curr = configs[i];
+ eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);
+ if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) {
+ config = curr;
+ break;
+ }
+ }
+
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+status_t EGLUtils::selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig)
+{
+ int err;
+ int format;
+
+ if (!window)
+ return BAD_VALUE;
+
+ if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
+ return err;
+ }
+
+ return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..e39a357 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -16,13 +16,14 @@
//#define LOG_NDEBUG 0
#include <ui/EventHub.h>
+#include <ui/KeycodeLabels.h>
#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>
@@ -58,6 +59,18 @@
#define SEQ_SHIFT 16
#define id_to_index(id) ((id&ID_MASK)+1)
+#ifndef ABS_MT_TOUCH_MAJOR
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#endif
+
+#ifndef ABS_MT_POSITION_X
+#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
+#endif
+
+#ifndef ABS_MT_POSITION_Y
+#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
+#endif
+
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
@@ -69,8 +82,8 @@ static inline int max(int v1, int v2)
return (v1 > v2) ? v1 : v2;
}
-EventHub::device_t::device_t(int32_t _id, const char* _path)
- : id(_id), path(_path), classes(0)
+EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
+ : id(_id), path(_path), name(name), classes(0)
, keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
@@ -83,7 +96,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 +113,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 +247,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 +319,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 +522,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';
@@ -531,7 +593,7 @@ int EventHub::open_device(const char *deviceName)
version >> 16, (version >> 8) & 0xff, version & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+ device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
if (device == NULL) {
LOGE("out of memory");
return -1;
@@ -541,6 +603,8 @@ int EventHub::open_device(const char *deviceName)
mFDs[mFDCount].events = POLLIN;
// figure out the kinds of events the device reports
+
+ // See if this is a keyboard, and classify it.
uint8_t key_bitmask[(KEY_MAX+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
@@ -552,15 +616,11 @@ int EventHub::open_device(const char *deviceName)
for (int i=0; i<((BTN_MISC+7)/8); i++) {
if (key_bitmask[i] != 0) {
device->classes |= CLASS_KEYBOARD;
- // 'Q' key support = cheap test of whether this is an alpha-capable kbd
- if (test_bit(KEY_Q, key_bitmask)) {
- device->classes |= CLASS_ALPHAKEY;
- }
break;
}
}
if ((device->classes & CLASS_KEYBOARD) != 0) {
- device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
if (device->keyBitmask != NULL) {
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
} else {
@@ -570,6 +630,8 @@ int EventHub::open_device(const char *deviceName)
}
}
}
+
+ // See if this is a trackball.
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
memset(rel_bitmask, 0, sizeof(rel_bitmask));
@@ -581,16 +643,22 @@ int EventHub::open_device(const char *deviceName)
}
}
}
- if (test_bit(BTN_TOUCH, key_bitmask)) {
- uint8_t abs_bitmask[(ABS_MAX+1)/8];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
- {
- if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
- device->classes |= CLASS_TOUCHSCREEN;
- }
- }
+
+ uint8_t abs_bitmask[(ABS_MAX+1)/8];
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ LOGV("Getting absolute controllers...");
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+
+ // Is this a new modern multi-touch driver?
+ if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
+
+ // Is this an old style single-touch driver?
+ } else if (test_bit(BTN_TOUCH, key_bitmask)
+ && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN;
}
#ifdef EV_SW
@@ -609,21 +677,15 @@ int EventHub::open_device(const char *deviceName)
}
#endif
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
if ((device->classes&CLASS_KEYBOARD) != 0) {
- char devname[101];
- char tmpfn[101];
+ char tmpfn[sizeof(name)];
char keylayoutFilename[300];
// a more descriptive name
- ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
- devname[sizeof(devname)-1] = 0;
- device->name = devname;
+ device->name = name;
// replace all the spaces with underscores
- strcpy(tmpfn, devname);
+ strcpy(tmpfn, name);
for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
*p = '_';
@@ -656,12 +718,29 @@ int EventHub::open_device(const char *deviceName)
}
char propName[100];
sprintf(propName, "hw.keyboards.%u.devname", publicID);
- property_set(propName, devname);
+ property_set(propName, name);
- LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
- publicID, device->id, devname, propName, keylayoutFilename);
+ // 'Q' key support = cheap test of whether this is an alpha-capable kbd
+ if (hasKeycode(device, kKeyCodeQ)) {
+ device->classes |= CLASS_ALPHAKEY;
+ }
+
+ // See if this has a DPAD.
+ if (hasKeycode(device, kKeyCodeDpadUp) &&
+ hasKeycode(device, kKeyCodeDpadDown) &&
+ hasKeycode(device, kKeyCodeDpadLeft) &&
+ hasKeycode(device, kKeyCodeDpadRight) &&
+ hasKeycode(device, kKeyCodeDpadCenter)) {
+ device->classes |= CLASS_DPAD;
+ }
+
+ LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
+ publicID, device->id, name, propName, keylayoutFilename);
}
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
deviceName, device, mFDCount, devid, device->classes);
@@ -674,6 +753,25 @@ int EventHub::open_device(const char *deviceName)
return 0;
}
+bool EventHub::hasKeycode(device_t* device, int keycode) const
+{
+ if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+ return false;
+ }
+
+ Vector<int32_t> scanCodes;
+ device->layoutMap->findScancodes(keycode, &scanCodes);
+ const size_t N = scanCodes.size();
+ for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+ int32_t sc = scanCodes.itemAt(i);
+ if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
int EventHub::close_device(const char *deviceName)
{
AutoMutex _l(mLock);
@@ -683,11 +781,21 @@ int EventHub::close_device(const char *deviceName)
if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
//LOGD("remove device %d: %s\n", i, deviceName);
device_t* device = mDevices[i];
- int count = mFDCount - i - 1;
+
+ LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ device->path.string(), device->name.string(), device->id,
+ mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
+
+ // Clear this device's entry.
int index = (device->id&ID_MASK);
mDevicesById[index].device = NULL;
+
+ // Close the file descriptor and compact the fd array.
+ close(mFDs[i].fd);
+ int count = mFDCount - i - 1;
memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
+ mFDCount--;
#ifdef EV_SW
for (int j=0; j<EV_SW; j++) {
@@ -700,8 +808,6 @@ int EventHub::close_device(const char *deviceName)
device->next = mClosingDevices;
mClosingDevices = device;
- mFDCount--;
-
uint32_t publicID;
if (device->id == mFirstKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
@@ -718,7 +824,7 @@ int EventHub::close_device(const char *deviceName)
return 0;
}
}
- LOGE("remote device: %s not found\n", deviceName);
+ LOGE("remove device: %s not found\n", deviceName);
return -1;
}
@@ -733,6 +839,7 @@ int EventHub::read_notify(int nfd)
int event_pos = 0;
struct inotify_event *event;
+ LOGV("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..0efba9c
--- /dev/null
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -0,0 +1,279 @@
+/*
+**
+** 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 <utils/RefBase.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;
+ int err;
+ err = framebuffer_open(module, &fbDev);
+ LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+
+ err = gralloc_open(module, &grDev);
+ LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
+
+ // bail out if we can't initialize the modules
+ if (!fbDev || !grDev)
+ return;
+
+ 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));
+
+ LOGE("xDpi %d", fbDev->xdpi);
+ LOGE("yDpi %d", fbDev->ydpi);
+ 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;
+ } else {
+ LOGE("Couldn't get gralloc module");
+ }
+
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+}
+
+FramebufferNativeWindow::~FramebufferNativeWindow()
+{
+ if (grDev) {
+ if (buffers[0] != NULL)
+ grDev->free(grDev, buffers[0]->handle);
+ if (buffers[1] != NULL)
+ grDev->free(grDev, buffers[1]->handle);
+ gralloc_close(grDev);
+ }
+
+ if (fbDev) {
+ 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());
+}
+
+status_t FramebufferNativeWindow::compositionComplete()
+{
+ if (fbDev->compositionComplete) {
+ return fbDev->compositionComplete(fbDev);
+ }
+ return INVALID_OPERATION;
+}
+
+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;
+}
+
+int FramebufferNativeWindow::query(android_native_window_t* window,
+ int what, int* value)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = fb->format;
+ return NO_ERROR;
+ }
+ *value = 0;
+ return BAD_VALUE;
+}
+
+int FramebufferNativeWindow::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLNativeWindowType android_createDisplaySurface(void)
+{
+ FramebufferNativeWindow* w;
+ w = new FramebufferNativeWindow();
+ if (w->getDevice() == NULL) {
+ // get a ref so it can be destroyed when we exit this block
+ sp<FramebufferNativeWindow> ref(w);
+ return NULL;
+ }
+ return (EGLNativeWindowType)w;
+}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
new file mode 100644
index 0000000..6a5c8a9
--- /dev/null
+++ b/libs/ui/GraphicBuffer.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+#include <ui/PixelFormat.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
+
+GraphicBuffer::GraphicBuffer()
+ : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
+}
+
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat reqFormat, uint32_t reqUsage)
+ : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
+ mInitCheck = initSize(w, h, reqFormat, reqUsage);
+}
+
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat inFormat, uint32_t inUsage,
+ uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width = w;
+ height = h;
+ stride = inStride;
+ format = inFormat;
+ usage = inUsage;
+ handle = inHandle;
+}
+
+GraphicBuffer::GraphicBuffer(const Parcel& data)
+ : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ // we own the handle in this case
+ width = data.readInt32();
+ if (width < 0) {
+ width = height = stride = format = usage = 0;
+ handle = 0;
+ } else {
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
+ }
+}
+
+GraphicBuffer::~GraphicBuffer()
+{
+ if (handle) {
+ if (mOwner == ownHandle) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
+ } else if (mOwner == ownData) {
+ GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+ allocator.free(handle);
+ }
+ }
+}
+
+status_t GraphicBuffer::initCheck() const {
+ return mInitCheck;
+}
+
+android_native_buffer_t* GraphicBuffer::getNativeBuffer() const
+{
+ return static_cast<android_native_buffer_t*>(
+ const_cast<GraphicBuffer*>(this));
+}
+
+status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
+ uint32_t reqUsage)
+{
+ if (mOwner != ownData)
+ return INVALID_OPERATION;
+
+ if (handle) {
+ GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+ allocator.free(handle);
+ handle = 0;
+ }
+ return initSize(w, h, f, reqUsage);
+}
+
+status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage)
+{
+ if (format == PIXEL_FORMAT_RGBX_8888)
+ format = PIXEL_FORMAT_RGBA_8888;
+
+ GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
+ status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
+ if (err == NO_ERROR) {
+ this->width = w;
+ this->height = h;
+ this->format = format;
+ this->usage = reqUsage;
+ mVStride = 0;
+ }
+ return err;
+}
+
+status_t GraphicBuffer::lock(uint32_t usage, void** vaddr)
+{
+ const Rect lockBounds(width, height);
+ status_t res = lock(usage, lockBounds, vaddr);
+ return res;
+}
+
+status_t GraphicBuffer::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 GraphicBuffer::unlock()
+{
+ status_t res = getBufferMapper().unlock(handle);
+ return res;
+}
+
+status_t GraphicBuffer::lock(GGLSurface* sur, uint32_t usage)
+{
+ void* vaddr;
+ status_t res = GraphicBuffer::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 GraphicBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
+{
+ if (buffer == NULL)
+ return BAD_VALUE;
+
+ if (buffer->width < 0 || buffer->height < 0)
+ return BAD_VALUE;
+
+ status_t err = NO_ERROR;
+ if (buffer->handle == NULL) {
+ // this buffer doesn't have a handle
+ reply->writeInt32(NO_MEMORY);
+ } else {
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ err = reply->writeNativeHandle(buffer->handle);
+ }
+ return err;
+}
+
+
+void GraphicBuffer::setIndex(int index) {
+ mIndex = index;
+}
+
+int GraphicBuffer::getIndex() const {
+ return mIndex;
+}
+
+void GraphicBuffer::setVerticalStride(uint32_t vstride) {
+ mVStride = vstride;
+}
+
+uint32_t GraphicBuffer::getVerticalStride() const {
+ return mVStride;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
new file mode 100644
index 0000000..57d5fc3
--- /dev/null
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -0,0 +1,141 @@
+/*
+**
+** 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 <cutils/log.h>
+
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <ui/GraphicBufferAllocator.h>
+
+#include <private/ui/sw_gralloc_handle.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
+
+Mutex GraphicBufferAllocator::sLock;
+KeyedVector<buffer_handle_t,
+ GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
+
+GraphicBufferAllocator::GraphicBufferAllocator()
+ : 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);
+ }
+}
+
+GraphicBufferAllocator::~GraphicBufferAllocator()
+{
+ gralloc_close(mAllocDev);
+}
+
+void GraphicBufferAllocator::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);
+}
+
+static inline uint32_t clamp(uint32_t c) {
+ return c>0 ? c : 1;
+}
+
+status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
+ int usage, buffer_handle_t* handle, int32_t* stride)
+{
+ Mutex::Autolock _l(mLock);
+
+ // make sure to not allocate a 0 x 0 buffer
+ w = clamp(w);
+ h = clamp(h);
+
+ // we have a h/w allocator and h/w buffer is requested
+ status_t err;
+
+ if (usage & GRALLOC_USAGE_HW_MASK) {
+ err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ } else {
+ err = sw_gralloc_handle_t::alloc(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);
+ } else {
+ String8 s;
+ dump(s);
+ LOGD("%s", s.string());
+ }
+
+ return err;
+}
+
+status_t GraphicBufferAllocator::free(buffer_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocDev->free(mAllocDev, handle);
+ } else {
+ err = sw_gralloc_handle_t::free((sw_gralloc_handle_t*)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/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
new file mode 100644
index 0000000..ce2acd0
--- /dev/null
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 "GraphicBufferMapper"
+
+#include <stdint.h>
+#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
+# include <asm/page.h>
+#else
+# include <sys/user.h>
+#endif
+#include <errno.h>
+#include <sys/mman.h>
+
+#include <cutils/ashmem.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
+
+#include <hardware/gralloc.h>
+
+#include <private/ui/sw_gralloc_handle.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
+
+GraphicBufferMapper::GraphicBufferMapper()
+ : 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 GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->registerBuffer(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::unregisterBuffer((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(),
+ vaddr);
+ } else {
+ err = sw_gralloc_handle_t::lock((sw_gralloc_handle_t*)handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(),
+ vaddr);
+ }
+ LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->unlock(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::unlock((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t sw_gralloc_handle_t::alloc(uint32_t w, uint32_t h, int format,
+ int usage, buffer_handle_t* pHandle, int32_t* pStride)
+{
+ int align = 4;
+ int bpp = 0;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ bpp = 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ bpp = 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ bpp = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ size_t bpr = (w*bpp + (align-1)) & ~(align-1);
+ size_t size = bpr * h;
+ size_t stride = bpr / bpp;
+ size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+
+ int fd = ashmem_create_region("sw-gralloc-buffer", size);
+ if (fd < 0) {
+ LOGE("ashmem_create_region(size=%d) failed (%s)",
+ size, strerror(-errno));
+ return -errno;
+ }
+
+ int prot = PROT_READ;
+ if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
+ prot |= PROT_WRITE;
+
+ if (ashmem_set_prot_region(fd, prot) < 0) {
+ LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
+ fd, prot, strerror(-errno));
+ close(fd);
+ return -errno;
+ }
+
+ void* base = mmap(0, size, prot, MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
+ fd, size, prot, strerror(-errno));
+ close(fd);
+ return -errno;
+ }
+
+ sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();
+ hnd->fd = fd;
+ hnd->size = size;
+ hnd->base = intptr_t(base);
+ hnd->prot = prot;
+ *pStride = stride;
+ *pHandle = hnd;
+
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::free(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->base) {
+ munmap((void*)hnd->base, hnd->size);
+ }
+ if (hnd->fd >= 0) {
+ close(hnd->fd);
+ }
+ delete hnd;
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->pid != getpid()) {
+ void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("registerBuffer mmap(fd=%d, size=%d, prot=%x) failed (%s)",
+ hnd->fd, hnd->size, hnd->prot, strerror(-errno));
+ return -errno;
+ }
+ hnd->base = intptr_t(base);
+ }
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::unregisterBuffer(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->pid != getpid()) {
+ if (hnd->base) {
+ munmap((void*)hnd->base, hnd->size);
+ }
+ hnd->base = 0;
+ }
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::lock(sw_gralloc_handle_t* hnd, int usage,
+ int l, int t, int w, int h, void** vaddr)
+{
+ *vaddr = (void*)hnd->base;
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)
+{
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index ab0fef1..e1b3ec7 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 {
@@ -32,9 +32,11 @@ enum {
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
+ CANCEL_AUTO_FOCUS,
TAKE_PICTURE,
SET_PARAMETERS,
GET_PARAMETERS,
+ SEND_COMMAND,
CONNECT,
LOCK,
UNLOCK,
@@ -162,6 +164,17 @@ public:
return ret;
}
+ // cancel focus
+ status_t cancelAutoFocus()
+ {
+ LOGV("cancelAutoFocus");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(CANCEL_AUTO_FOCUS, data, &reply);
+ status_t ret = reply.readInt32();
+ return ret;
+ }
+
// take a picture - returns an IMemory (ref-counted mmap)
status_t takePicture()
{
@@ -193,6 +206,17 @@ public:
remote()->transact(GET_PARAMETERS, data, &reply);
return reply.readString8();
}
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+ {
+ LOGD("sendCommand");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeInt32(cmd);
+ data.writeInt32(arg1);
+ data.writeInt32(arg2);
+ remote()->transact(SEND_COMMAND, data, &reply);
+ return reply.readInt32();
+ }
virtual status_t connect(const sp<ICameraClient>& cameraClient)
{
Parcel data, reply;
@@ -221,12 +245,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)
{
@@ -300,6 +318,12 @@ status_t BnCamera::onTransact(
reply->writeInt32(autoFocus());
return NO_ERROR;
} break;
+ case CANCEL_AUTO_FOCUS: {
+ LOGV("CANCEL_AUTO_FOCUS");
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(cancelAutoFocus());
+ return NO_ERROR;
+ } break;
case TAKE_PICTURE: {
LOGV("TAKE_PICTURE");
CHECK_INTERFACE(ICamera, data, reply);
@@ -319,6 +343,15 @@ status_t BnCamera::onTransact(
reply->writeString8(getParameters());
return NO_ERROR;
} break;
+ case SEND_COMMAND: {
+ LOGD("SEND_COMMAND");
+ CHECK_INTERFACE(ICamera, data, reply);
+ int command = data.readInt32();
+ int arg1 = data.readInt32();
+ int arg2 = data.readInt32();
+ reply->writeInt32(sendCommand(command, arg1, arg2));
+ return NO_ERROR;
+ } break;
case CONNECT: {
CHECK_INTERFACE(ICamera, data, reply);
sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
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..4fb38ed 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 <ui/GraphicBuffer.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,17 @@ public:
{
}
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(bufferIdx);
+ data.writeInt32(usage);
+ remote()->transact(REQUEST_BUFFER, data, &reply);
+ sp<GraphicBuffer> buffer = new GraphicBuffer(reply);
+ return buffer;
+ }
+
virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
@@ -112,16 +131,17 @@ 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 REQUEST_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int bufferIdx = data.readInt32();
+ int usage = data.readInt32();
+ sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
+ return GraphicBuffer::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..4a6a1d7 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;
@@ -196,10 +189,11 @@ status_t BnSurfaceFlingerClient::onTransact(
status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
{
- token = parcel.readInt32();
- identity = parcel.readInt32();
- heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
- heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ width = parcel.readInt32();
+ height = parcel.readInt32();
+ format = parcel.readInt32();
return NO_ERROR;
}
@@ -207,8 +201,9 @@ 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);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
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..3aa8950 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,30 @@ status_t Overlay::queueBuffer(overlay_buffer_t buffer)
return mOverlayData->queueBuffer(mOverlayData, buffer);
}
+status_t Overlay::resizeInput(uint32_t width, uint32_t height)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->resizeInput(mOverlayData, width, height);
+}
+
+status_t Overlay::setParameter(int param, int value)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setParameter(mOverlayData, param, value);
+}
+
+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 +97,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/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
new file mode 100644
index 0000000..46b6766
--- /dev/null
+++ b/libs/ui/SharedBufferStack.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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 "SharedBufferStack"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <private/ui/SharedBufferStack.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#define DEBUG_ATOMICS 0
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+SharedClient::SharedClient()
+ : lock(Mutex::SHARED)
+{
+}
+
+SharedClient::~SharedClient() {
+}
+
+
+// these functions are used by the clients
+status_t SharedClient::validate(size_t i) const {
+ if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
+ return BAD_INDEX;
+ return surfaces[i].status;
+}
+
+uint32_t SharedClient::getIdentity(size_t token) const {
+ return uint32_t(surfaces[token].identity);
+}
+
+// ----------------------------------------------------------------------------
+
+
+SharedBufferStack::SharedBufferStack()
+{
+}
+
+void SharedBufferStack::init(int32_t i)
+{
+ inUse = -1;
+ status = NO_ERROR;
+ identity = i;
+}
+
+status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+
+ // in the current implementation we only send a single rectangle
+ const Rect bounds(dirty.getBounds());
+ FlatRegion& reg(dirtyRegion[buffer]);
+ reg.count = 1;
+ reg.rects[0] = uint16_t(bounds.left);
+ reg.rects[1] = uint16_t(bounds.top);
+ reg.rects[2] = uint16_t(bounds.right);
+ reg.rects[3] = uint16_t(bounds.bottom);
+ return NO_ERROR;
+}
+
+Region SharedBufferStack::getDirtyRegion(int buffer) const
+{
+ Region res;
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+
+ const FlatRegion& reg(dirtyRegion[buffer]);
+ res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : mSharedClient(sharedClient),
+ mSharedStack(sharedClient->surfaces + surface),
+ mNumBuffers(num), mIdentity(identity)
+{
+}
+
+SharedBufferBase::~SharedBufferBase()
+{
+}
+
+uint32_t SharedBufferBase::getIdentity()
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.identity;
+}
+
+status_t SharedBufferBase::getStatus() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.status;
+}
+
+size_t SharedBufferBase::getFrontBuffer() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return size_t( stack.head );
+}
+
+String8 SharedBufferBase::dump(char const* prefix) const
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ SharedBufferStack& stack( *mSharedStack );
+ snprintf(buffer, SIZE,
+ "%s[ head=%2d, available=%2d, queued=%2d ] "
+ "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
+ prefix, stack.head, stack.available, stack.queued,
+ stack.reallocMask, stack.inUse, stack.identity, stack.status);
+ result.append(buffer);
+ return result;
+}
+
+// ============================================================================
+// conditions and updates
+// ============================================================================
+
+SharedBufferClient::DequeueCondition::DequeueCondition(
+ SharedBufferClient* sbc) : ConditionBase(sbc) {
+}
+bool SharedBufferClient::DequeueCondition::operator()() {
+ return stack.available > 0;
+}
+
+SharedBufferClient::LockCondition::LockCondition(
+ SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
+}
+bool SharedBufferClient::LockCondition::operator()() {
+ return (buf != stack.head ||
+ (stack.queued > 0 && stack.inUse != buf));
+}
+
+SharedBufferServer::ReallocateCondition::ReallocateCondition(
+ SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {
+}
+bool SharedBufferServer::ReallocateCondition::operator()() {
+ // TODO: we should also check that buf has been dequeued
+ return (buf != stack.head);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::QueueUpdate::operator()() {
+ android_atomic_inc(&stack.queued);
+ return NO_ERROR;
+}
+
+SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() {
+ android_atomic_inc(&stack.available);
+ return NO_ERROR;
+}
+
+SharedBufferServer::UnlockUpdate::UnlockUpdate(
+ SharedBufferBase* sbb, int lockedBuffer)
+ : UpdateBase(sbb), lockedBuffer(lockedBuffer) {
+}
+ssize_t SharedBufferServer::UnlockUpdate::operator()() {
+ if (stack.inUse != lockedBuffer) {
+ LOGE("unlocking %d, but currently locked buffer is %d",
+ lockedBuffer, stack.inUse);
+ return BAD_VALUE;
+ }
+ android_atomic_write(-1, &stack.inUse);
+ return NO_ERROR;
+}
+
+SharedBufferServer::RetireUpdate::RetireUpdate(
+ SharedBufferBase* sbb, int numBuffers)
+ : UpdateBase(sbb), numBuffers(numBuffers) {
+}
+ssize_t SharedBufferServer::RetireUpdate::operator()() {
+ // head is only written in this function, which is single-thread.
+ int32_t head = stack.head;
+
+ // Preventively lock the current buffer before updating queued.
+ android_atomic_write(head, &stack.inUse);
+
+ // Decrement the number of queued buffers
+ int32_t queued;
+ do {
+ queued = stack.queued;
+ if (queued == 0) {
+ return NOT_ENOUGH_DATA;
+ }
+ } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
+
+ // update the head pointer
+ head = ((head+1 >= numBuffers) ? 0 : head+1);
+
+ // lock the buffer before advancing head, which automatically unlocks
+ // the buffer we preventively locked upon entering this function
+ android_atomic_write(head, &stack.inUse);
+
+ // advance head
+ android_atomic_write(head, &stack.head);
+
+ // now that head has moved, we can increment the number of available buffers
+ android_atomic_inc(&stack.available);
+ return head;
+}
+
+SharedBufferServer::StatusUpdate::StatusUpdate(
+ SharedBufferBase* sbb, status_t status)
+ : UpdateBase(sbb), status(status) {
+}
+
+ssize_t SharedBufferServer::StatusUpdate::operator()() {
+ android_atomic_write(status, &stack.status);
+ return NO_ERROR;
+}
+
+// ============================================================================
+
+SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, num, identity), tail(0)
+{
+ tail = computeTail();
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ // we need to make sure we read available and head coherently,
+ // w.r.t RetireUpdate.
+ int32_t newTail;
+ int32_t avail;
+ int32_t head;
+ do {
+ avail = stack.available;
+ head = stack.head;
+ } while (stack.available != avail);
+ newTail = head - avail + 1;
+ if (newTail < 0) {
+ newTail += mNumBuffers;
+ }
+ return newTail;
+}
+
+ssize_t SharedBufferClient::dequeue()
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ if (stack.head == tail && stack.available == 2) {
+ LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
+ tail, stack.head, stack.available, stack.queued);
+ }
+
+ const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
+
+ //LOGD("[%d] about to dequeue a buffer",
+ // mSharedStack->identity);
+ DequeueCondition condition(this);
+ status_t err = waitForCondition(condition);
+ if (err != NO_ERROR)
+ return ssize_t(err);
+
+ // NOTE: 'stack.available' is part of the conditions, however
+ // decrementing it, never changes any conditions, so we don't need
+ // to do this as part of an update.
+ if (android_atomic_dec(&stack.available) == 0) {
+ LOGW("dequeue probably called from multiple threads!");
+ }
+
+ int dequeued = tail;
+ tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
+ LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
+ dequeued, tail, dump("").string());
+
+ mDequeueTime[dequeued] = dequeueTime;
+
+ return dequeued;
+}
+
+status_t SharedBufferClient::undoDequeue(int buf)
+{
+ UndoDequeueUpdate update(this);
+ status_t err = updateCondition( update );
+ if (err == NO_ERROR) {
+ tail = computeTail();
+ }
+ return err;
+}
+
+status_t SharedBufferClient::lock(int buf)
+{
+ LockCondition condition(this, buf);
+ status_t err = waitForCondition(condition);
+ return err;
+}
+
+status_t SharedBufferClient::queue(int buf)
+{
+ QueueUpdate update(this);
+ status_t err = updateCondition( update );
+ LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+ SharedBufferStack& stack( *mSharedStack );
+ const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+ stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
+ return err;
+}
+
+bool SharedBufferClient::needNewBuffer(int buffer) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ const uint32_t mask = 1<<buffer;
+ return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
+}
+
+status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setDirtyRegion(buffer, reg);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, num, identity)
+{
+ mSharedStack->init(identity);
+ mSharedStack->head = num-1;
+ mSharedStack->available = num;
+ mSharedStack->queued = 0;
+ mSharedStack->reallocMask = 0;
+ memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
+}
+
+ssize_t SharedBufferServer::retireAndLock()
+{
+ RetireUpdate update(this, mNumBuffers);
+ ssize_t buf = updateCondition( update );
+ LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
+ return buf;
+}
+
+status_t SharedBufferServer::unlock(int buffer)
+{
+ UnlockUpdate update(this, buffer);
+ status_t err = updateCondition( update );
+ return err;
+}
+
+void SharedBufferServer::setStatus(status_t status)
+{
+ if (status < NO_ERROR) {
+ StatusUpdate update(this, status);
+ updateCondition( update );
+ }
+}
+
+status_t SharedBufferServer::reallocate()
+{
+ SharedBufferStack& stack( *mSharedStack );
+ uint32_t mask = (1<<mNumBuffers)-1;
+ android_atomic_or(mask, &stack.reallocMask);
+ return NO_ERROR;
+}
+
+int32_t SharedBufferServer::getQueuedCount() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.queued;
+}
+
+status_t SharedBufferServer::assertReallocate(int buffer)
+{
+ ReallocateCondition condition(this, buffer);
+ status_t err = waitForCondition(condition);
+ return err;
+}
+
+Region SharedBufferServer::getDirtyRegion(int buffer) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getDirtyRegion(buffer);
+}
+
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.stats;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..f51ca7a 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,233 +23,734 @@
#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 <utils/CallStack.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
namespace android {
-// ---------------------------------------------------------------------------
+// ----------------------------------------------------------------------
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& 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;
+}
+
+// ============================================================================
+// SurfaceControl
+// ============================================================================
-Surface::Surface(const sp<SurfaceComposerClient>& client,
+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,
- bool owner)
+ 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), mOwner(owner)
+ mWidth(data.width), mHeight(data.height), mFormat(data.format),
+ mFlags(flags)
{
- 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)
+
+SurfaceControl::~SurfaceControl()
{
- 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();
+ destroy();
}
-Surface::~Surface()
+void SurfaceControl::destroy()
{
- if (mOwner && mToken>=0 && mClient!=0) {
+ 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();
- mHeap[0].clear();
- mHeap[1].clear();
IPCThreadState::self()->flushCommands();
}
-sp<Surface> Surface::dup() const
+void SurfaceControl::clear()
{
- 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);
- }
- return const_cast<Surface*>(r);
+ // 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::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
+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::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
+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 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 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 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 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 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 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);
+}
+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);
+}
+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);
+}
+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);
+}
+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);
}
-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 SurfaceControl::validate(SharedClient 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;
+ }
+ uint32_t identity = cblk->getIdentity(mToken);
+ if (mIdentity != identity) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
}
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
+{
+ uint32_t flags = 0;
+ uint32_t format = 0;
+ SurfaceID token = -1;
+ uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ sp<SurfaceComposerClient> client;
+ sp<ISurface> sur;
+ if (SurfaceControl::isValid(control)) {
+ token = control->mToken;
+ identity = control->mIdentity;
+ client = control->mClient;
+ sur = control->mSurface;
+ width = control->mWidth;
+ height = control->mHeight;
+ format = control->mFormat;
+ flags = control->mFlags;
+ }
+ parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ 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);
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
}
-status_t Surface::setLayer(int32_t layer) {
- return mClient->setLayer(this, layer);
+// ============================================================================
+// 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(GraphicBufferMapper::get()), mSharedBufferClient(NULL),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
+{
+ mSharedBufferClient = new SharedBufferClient(
+ mClient->mControl, mToken, 2, mIdentity);
+
+ init();
}
-status_t Surface::setPosition(int32_t x, int32_t y) {
- return mClient->setPosition(this, x, y);
+
+Surface::Surface(const Parcel& parcel)
+ : mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL)
+{
+ sp<IBinder> clientBinder = parcel.readStrongBinder();
+ mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
+ mToken = parcel.readInt32();
+ mIdentity = parcel.readInt32();
+ mWidth = parcel.readInt32();
+ mHeight = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+
+ // FIXME: what does that mean if clientBinder is NULL here?
+ if (clientBinder != NULL) {
+ mClient = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ mSharedBufferClient = new SharedBufferClient(
+ mClient->mControl, mToken, 2, mIdentity);
+ }
+
+ init();
}
-status_t Surface::setSize(uint32_t w, uint32_t h) {
- return mClient->setSize(this, w, h);
+
+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;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+ mSwapRectangle.makeInvalid();
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ 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;
+ // be default we request a hardware surface
+ mUsage = GRALLOC_USAGE_HW_RENDER;
+ mNeedFullUpdate = false;
}
-status_t Surface::hide() {
- return mClient->hide(this);
+
+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 && mBuffers[i]->handle != 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();
+ delete mSharedBufferClient;
+ IPCThreadState::self()->flushCommands();
}
-status_t Surface::show(int32_t layer) {
- return mClient->show(this, layer);
+
+sp<SurfaceComposerClient> Surface::getClient() const {
+ return mClient;
}
-status_t Surface::freeze() {
- return mClient->freeze(this);
+
+sp<ISurface> Surface::getISurface() const {
+ return mSurface;
}
-status_t Surface::unfreeze() {
- return mClient->unfreeze(this);
+
+bool Surface::isValid() {
+ return mToken>=0 && mClient!=0;
}
-status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
- return mClient->setFlags(this, flags, mask);
+
+status_t Surface::validate(SharedClient const* cblk) const
+{
+ sp<SurfaceComposerClient> client(getClient());
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, client.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ uint32_t identity = cblk->getIdentity(mToken);
+ if (mIdentity != identity) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
}
-status_t Surface::setTransparentRegionHint(const Region& transparent) {
- return mClient->setTransparentRegionHint(this, transparent);
+
+
+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();
}
-status_t Surface::setAlpha(float alpha) {
- return mClient->setAlpha(this, alpha);
+
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval) {
+ return 0;
}
-status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer) {
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
}
-status_t Surface::setFreezeTint(uint32_t tint) {
- return mClient->setFreezeTint(this, tint);
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
}
-Region Surface::dirtyRegion() const {
- return mDirtyRegion;
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
}
-void Surface::setDirtyRegion(const Region& region) const {
- mDirtyRegion = region;
+
+int Surface::query(android_native_window_t* window,
+ int what, int* value) {
+ Surface* self = getSelf(window);
+ return self->query(what, value);
}
-const Rect& Surface::swapRectangle() const {
- return mSwapRectangle;
+
+int Surface::perform(android_native_window_t* window,
+ int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ Surface* self = getSelf(window);
+ int res = self->perform(operation, args);
+ va_end(args);
+ return res;
}
-void Surface::setSwapRectangle(const Rect& r) {
- mSwapRectangle = r;
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer) {
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ if (err == NO_ERROR) {
+ *buffer = GraphicBuffer::getSelf(out);
+ }
+ return err;
}
-sp<Surface> Surface::readFromParcel(Parcel* parcel)
+// ----------------------------------------------------------------------------
+
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
{
- 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();
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
- if (clientBinder != NULL)
- client = SurfaceComposerClient::clientForConnection(clientBinder);
+ ssize_t bufIdx = mSharedBufferClient->dequeue();
+ if (bufIdx < 0) {
+ LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
+ return bufIdx;
+ }
+
+ // below we make sure we AT LEAST have the usage flags we want
+ const uint32_t usage(getUsage());
+ const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
+ if (backBuffer == 0 ||
+ ((uint32_t(backBuffer->usage) & usage) != usage) ||
+ mSharedBufferClient->needNewBuffer(bufIdx))
+ {
+ err = getBufferLocked(bufIdx, usage);
+ LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
+ bufIdx, usage, strerror(-err));
+ if (err == NO_ERROR) {
+ // reset the width/height with the what we get from the buffer
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ }
+ }
+
+ // if we still don't have a buffer here, we probably ran out of memory
+ if (!err && backBuffer==0) {
+ err = NO_MEMORY;
+ }
- return new Surface(client, surface, data, 0, 0, format, flags, false);
+ if (err == NO_ERROR) {
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ } else {
+ mSharedBufferClient->undoDequeue(bufIdx);
+ }
+
+ return err;
}
-status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+int Surface::lockBuffer(android_native_buffer_t* buffer)
{
- 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;
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
+
+ int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+ err = mSharedBufferClient->lock(bufIdx);
+ LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
+ return err;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
}
- 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);
- parcel->writeInt32(flags);
- return NO_ERROR;
+
+ int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+ mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
+ err = mSharedBufferClient->queue(bufIdx);
+ LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // FIXME: can we avoid this IPC if we know there is one pending?
+ client->signalServer();
+ }
+ return err;
}
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+int Surface::query(int what, int* value)
{
- if (lhs == 0 || rhs == 0)
- return false;
- return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = int(mWidth);
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = int(mHeight);
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = int(mFormat);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+int Surface::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ setUsage( va_arg(args, int) );
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
+
+void Surface::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mUsage = reqUsage;
+}
+
+uint32_t Surface::getUsage() const
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ return mUsage;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ if (mApiLock.tryLock() != NO_ERROR) {
+ LOGE("calling Surface::lock() from different threads!");
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface::lock called from different threads");
+ return WOULD_BLOCK;
+ }
+
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ sp<GraphicBuffer> backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
+ backBuffer->getIndex(), strerror(-err));
+ if (err == NO_ERROR) {
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region scratch(bounds);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+
+ if (mNeedFullUpdate) {
+ // reset newDirtyRegion to bounds when a buffer is reallocated
+ // it would be better if this information was associated with
+ // the buffer and made available to outside of Surface.
+ // This will do for now though.
+ mNeedFullUpdate = false;
+ newDirtyRegion.set(bounds);
+ } else {
+ newDirtyRegion.andSelf(bounds);
+ }
+
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ if (frontBuffer !=0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ !(mFlags & ISurfaceComposer::eDestroyBackbuffer))
+ {
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer, copyback);
+ }
+ }
+
+ 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 (handle = %p)",
+ 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;
+ }
+ }
+ mApiLock.unlock();
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("unlockAndPost failed, no locked buffer");
+ return BAD_VALUE;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
+ mLockedBuffer->getIndex(), strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
}
-void* Surface::heapBase(int i) const
+void Surface::setSwapRectangle(const Rect& r) {
+ Mutex::Autolock _l(mSurfaceLock);
+ mSwapRectangle = r;
+}
+
+status_t Surface::getBufferLocked(int index, int usage)
{
- 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());
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
+ status_t err = NO_MEMORY;
+
+ // free the current buffer
+ sp<GraphicBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ getBufferMapper().unregisterBuffer(currentBuffer->handle);
+ currentBuffer.clear();
+ }
+
+ sp<GraphicBuffer> buffer = s->requestBuffer(index, usage);
+ LOGE_IF(buffer==0,
+ "ISurface::getBuffer(%d, %08x) returned NULL",
+ index, usage);
+ if (buffer != 0) { // this should never happen by construction
+ LOGE_IF(buffer->handle == NULL,
+ "Surface (identity=%d) requestBuffer(%d, %08x) returned"
+ "a buffer with a null handle", mIdentity, index, usage);
+ err = mSharedBufferClient->getStatus();
+ LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
+ if (!err && buffer->handle != NULL) {
+ err = getBufferMapper().registerBuffer(buffer->handle);
+ LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
+ err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
+ currentBuffer->setIndex(index);
+ mNeedFullUpdate = true;
}
- mSurfaceHeapBase[i] = heapBase;
+ } else {
+ err = err<0 ? err : NO_MEMORY;
}
}
- return heapBase;
+ return err;
}
}; // namespace android
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..eda84ef 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,26 +29,19 @@
#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>
+#include <private/ui/SharedBufferStack.h>
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
@@ -65,42 +58,50 @@ 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()
+static sp<ISurfaceComposer> getComposerService()
{
+ sp<ISurfaceComposer> sc;
+ Mutex::Autolock _l(gLock);
if (gSurfaceManager != 0) {
- return gSurfaceManager;
- }
+ sc = gSurfaceManager;
+ } else {
+ // release the lock while we're waiting...
+ gLock.unlock();
+
+ sp<IBinder> binder;
+ sp<IServiceManager> sm = defaultServiceManager();
+ do {
+ binder = sm->getService(String16("SurfaceFlinger"));
+ if (binder == 0) {
+ LOGW("SurfaceFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ }
+ } while(binder == 0);
- sp<IBinder> binder;
- sp<IServiceManager> sm = defaultServiceManager();
- do {
- binder = sm->getService(String16("SurfaceFlinger"));
- if (binder == 0) {
- LOGW("SurfaceFlinger not published, waiting...");
- usleep(500000); // 0.5 s
+ // grab the lock again for updating gSurfaceManager
+ gLock.lock();
+ if (gSurfaceManager == 0) {
+ sc = interface_cast<ISurfaceComposer>(binder);
+ gSurfaceManager = sc;
+ } else {
+ sc = gSurfaceManager;
}
- } while(binder == 0);
- sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder));
-
- Mutex::Autolock _l(gLock);
- if (gSurfaceManager == 0) {
- gSurfaceManager = sc;
}
- return gSurfaceManager;
+ return sc;
}
static volatile surface_flinger_cblk_t const * get_cblk()
{
if (gServerCblk == 0) {
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
Mutex::Autolock _l(gLock);
if (gServerCblk == 0) {
gServerCblkMemory = sm->getCblk();
LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
- gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
LOGE_IF(gServerCblk==0, "Can't get server control block address");
}
}
@@ -109,210 +110,6 @@ 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 {
- if (uint32_t(i) >= NUM_LAYERS_MAX)
- return BAD_INDEX;
- if (layers[i].swapState & eInvalidSurface)
- return NO_MEMORY;
- return NO_ERROR;
-}
-
-int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
-{
- int32_t index;
- uint32_t state;
- int timeout = 0;
- status_t result;
- layer_cblk_t * const layer = layers + i;
- const bool blocking = flags & BLOCKING;
- const bool inspect = flags & INSPECT;
-
- do {
- state = layer->swapState;
-
- if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) {
- LOGE("eNextFlipPending set but eFlipRequested not set, "
- "layer=%d (lcblk=%p), state=%08x",
- int(i), layer, int(state));
- return INVALID_OPERATION;
- }
-
- if (UNLIKELY(state&eLocked)) {
- LOGE("eLocked set when entering lock_layer(), "
- "layer=%d (lcblk=%p), state=%08x",
- int(i), layer, int(state));
- return WOULD_BLOCK;
- }
-
-
- if (state & (eFlipRequested | eNextFlipPending | eResizeRequested
- | eInvalidSurface))
- {
- int32_t resizeIndex;
- Mutex::Autolock _l(lock);
- // might block for a very short amount of time
- // will never cause the server to block (trylock())
-
- goto start_loop_here;
-
- // We block the client if:
- // eNextFlipPending: we've used both buffers already, so we need to
- // wait for one to become availlable.
- // eResizeRequested: the buffer we're going to acquire is being
- // resized. Block until it is done.
- // eFlipRequested && eBusy: the buffer we're going to acquire is
- // currently in use by the server.
- // eInvalidSurface: this is a special case, we don't block in this
- // case, we just return an error.
-
- while((state & (eNextFlipPending|eInvalidSurface)) ||
- (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) ||
- ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) )
- {
- if (state & eInvalidSurface)
- return NO_MEMORY;
-
- if (!blocking)
- return WOULD_BLOCK;
-
- timeout = 0;
- result = cv.waitRelative(lock, seconds(1));
- if (__builtin_expect(result!=NO_ERROR, false)) {
- const int newState = layer->swapState;
- LOGW( "lock_layer timed out (is the CPU pegged?) "
- "layer=%d, lcblk=%p, state=%08x (was %08x)",
- int(i), layer, newState, int(state));
- timeout = newState != int(state);
- }
-
- start_loop_here:
- state = layer->swapState;
- resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1);
- }
-
- LOGW_IF(timeout,
- "lock_layer() timed out but didn't appear to need "
- "to be locked and we recovered "
- "(layer=%d, lcblk=%p, state=%08x)",
- int(i), layer, int(state));
- }
-
- // eFlipRequested is not set and cannot be set by another thread: it's
- // safe to use the first buffer without synchronization.
-
- // Choose the index depending on eFlipRequested.
- // When it's set, choose the 'other' buffer.
- 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);
- }
-
- if (inspect) {
- // we just want to inspect this layer. don't lock it.
- goto done;
- }
-
- // last thing before we're done, we need to atomically lock the state
- } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState)));
-
- VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x",
- int(i), layer, int(index), int(state));
-
- // store the index of the locked buffer (for client use only)
- layer->flags &= ~eBufferIndex;
- layer->flags |= ((index << eBufferIndexShift) & eBufferIndex);
-
-done:
- return index;
-}
-
-uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
-{
- // atomically set eFlipRequested and clear eLocked and optionnaly
- // set eNextFlipPending if eFlipRequested was already set
-
- layer_cblk_t * const layer = layers + i;
- int32_t oldvalue, newvalue;
- do {
- oldvalue = layer->swapState;
- // get current value
-
- newvalue = oldvalue & ~eLocked;
- // clear eLocked
-
- newvalue |= eFlipRequested;
- // set eFlipRequested
-
- if (oldvalue & eFlipRequested)
- newvalue |= eNextFlipPending;
- // if eFlipRequested was alread set, set eNextFlipPending
-
- } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
-
- VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x",
- int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
- int(newvalue));
-
- // from this point, the server can kick in at anytime 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).
-
- return newvalue;
-}
-
-void per_client_cblk_t::unlock_layer(size_t i)
-{
- layer_cblk_t * const layer = layers + i;
- android_atomic_and(~eLocked, &layer->swapState);
-}
-
-// ---------------------------------------------------------------------------
-
static inline int compare_type( const layer_state_t& lhs,
const layer_state_t& rhs) {
if (lhs.surface < rhs.surface) return -1;
@@ -322,7 +119,7 @@ static inline int compare_type( const layer_state_t& lhs,
SurfaceComposerClient::SurfaceComposerClient()
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
if (sm == 0) {
_init(0, 0);
return;
@@ -343,12 +140,20 @@ SurfaceComposerClient::SurfaceComposerClient(
_init(sm, interface_cast<ISurfaceFlingerClient>(conn));
}
+
+status_t SurfaceComposerClient::linkToComposerDeath(
+ const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->asBinder()->linkToDeath(recipient, cookie, flags);
+}
+
void SurfaceComposerClient::_init(
const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
{
VERBOSE("Creating client %p, conn %p", this, conn.get());
- mSignalServer = 0;
mPrebuiltLayerState = 0;
mTransactionOpen = 0;
mStatus = NO_ERROR;
@@ -360,9 +165,9 @@ void SurfaceComposerClient::_init(
return;
}
- mClient->getControlBlocks(&mControlMemory);
- mSignalServer = new SurfaceFlingerSynchro(sm);
- mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+ mControlMemory = mClient->getControlBlock();
+ mSignalServer = sm;
+ mControl = static_cast<SharedClient *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@@ -376,32 +181,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;
@@ -419,7 +198,7 @@ SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn)
if (client == 0) {
// Need to make a new client.
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
client = new SurfaceComposerClient(sm, conn);
if (client != 0 && client->initCheck() == NO_ERROR) {
Mutex::Autolock _l(gLock);
@@ -437,15 +216,13 @@ 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);
Mutex::Autolock _lm(mLock);
- delete mSignalServer;
mSignalServer = 0;
if (mClient != 0) {
@@ -462,9 +239,7 @@ void SurfaceComposerClient::dispose()
delete mPrebuiltLayerState;
mPrebuiltLayerState = 0;
controlMemory = mControlMemory;
- surfaceHeap = mSurfaceHeap;
mControlMemory.clear();
- mSurfaceHeap.clear();
mControl = 0;
mStatus = NO_INIT;
}
@@ -528,7 +303,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 +317,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 +349,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);
@@ -789,34 +390,33 @@ void SurfaceComposerClient::closeGlobalTransaction()
const size_t N = clients.size();
VERBOSE("closeGlobalTransaction (%ld clients)", N);
- if (N == 1) {
- clients[0]->closeTransaction();
- } else {
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
- sm->openGlobalTransaction();
- for (size_t i=0; i<N; i++) {
- clients[i]->closeTransaction();
- }
- sm->closeGlobalTransaction();
+
+ sp<ISurfaceComposer> sm(getComposerService());
+ sm->openGlobalTransaction();
+ for (size_t i=0; i<N; i++) {
+ clients[i]->closeTransaction();
}
+ sm->closeGlobalTransaction();
+
}
+
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->freezeDisplay(dpy, flags);
}
status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->unfreezeDisplay(dpy, flags);
}
int SurfaceComposerClient::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->setOrientation(dpy, orientation, flags);
}
@@ -866,14 +466,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 +486,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 +500,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 +511,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 +522,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 +532,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 +567,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 +578,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 +589,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 +606,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
deleted file mode 100644
index 5cd9755..0000000
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ /dev/null
@@ -1,123 +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.
- */
-
-#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>
-
-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()
-{
-}
-
-status_t SurfaceFlingerSynchro::signal()
-{
- mSurfaceComposer->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..ef15de9
--- /dev/null
+++ b/libs/ui/tests/region.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.
+ */
+
+#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 empty;
+ Region reg0( Rect( 0, 0, 100, 100 ) );
+ Region reg1 = reg0;
+ Region reg2, reg3;
+
+ Region reg4 = empty | reg1;
+ Region reg5 = reg1 | empty;
+
+ reg4.dump("reg4");
+ reg5.dump("reg5");
+
+ 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..adb3174 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -107,7 +107,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
} else {
k = key;
}
- if (true) {
+ if (false) {
LOGD("Writing entity: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), key.string(),
dataSize);
}
@@ -193,8 +193,11 @@ BackupDataReader::Status()
if ((actual) != (expected)) { \
if ((actual) == 0) { \
m_status = EIO; \
+ m_done = true; \
} else { \
m_status = errno; \
+ LOGD("CHECK_SIZE(a=%ld e=%ld) failed at line %d m_status='%s'", \
+ long(actual), long(expected), __LINE__, strerror(m_status)); \
} \
return m_status; \
} \
@@ -203,6 +206,7 @@ BackupDataReader::Status()
do { \
status_t err = skip_padding(); \
if (err != NO_ERROR) { \
+ LOGD("SKIP_PADDING FAILED at line %d", __LINE__); \
m_status = err; \
return err; \
} \
@@ -218,10 +222,19 @@ BackupDataReader::ReadNextHeader(bool* done, int* type)
int amt;
- // No error checking here, in case we're at the end of the stream. Just let read() fail.
- skip_padding();
+ amt = skip_padding();
+ if (amt == EIO) {
+ *done = m_done = true;
+ return NO_ERROR;
+ }
+ else if (amt != NO_ERROR) {
+ return amt;
+ }
amt = read(m_fd, &m_header, sizeof(m_header));
*done = m_done = (amt == 0);
+ if (*done) {
+ return NO_ERROR;
+ }
CHECK_SIZE(amt, sizeof(m_header));
m_pos += sizeof(m_header);
if (type) {
@@ -298,10 +311,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
@@ -325,6 +340,10 @@ BackupDataReader::ReadEntityData(void* data, size_t size)
m_status = errno;
return -1;
}
+ if (amt == 0) {
+ m_status = EIO;
+ m_done = true;
+ }
m_pos += amt;
return amt;
}
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/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 0831f4a..872b2bc 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1740,7 +1740,11 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
const int e = Res_GETENTRY(resID);
if (p < 0) {
- LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+ if (Res_GETPACKAGE(resID)+1 == 0) {
+ LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+ } else {
+ LOGW("Resources don't contain package for resource number 0x%08x", resID);
+ }
return false;
}
if (t < 0) {
@@ -1786,7 +1790,11 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
const int e = Res_GETENTRY(resID);
if (p < 0) {
- LOGW("No package identifier when getting value for resource number 0x%08x", resID);
+ if (Res_GETPACKAGE(resID)+1 == 0) {
+ LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+ } else {
+ LOGW("Resources don't contain package for resource number 0x%08x", resID);
+ }
return BAD_INDEX;
}
if (t < 0) {
@@ -3284,7 +3292,16 @@ bool ResTable::collectString(String16* outString,
break;
}
if (c == '\'' && (quoted == 0 || quoted == '\'')) {
- break;
+ /*
+ * In practice, when people write ' instead of \'
+ * in a string, they are doing it by accident
+ * instead of really meaning to use ' as a quoting
+ * character. Warn them so they don't lose it.
+ */
+ if (outErrorMsg) {
+ *outErrorMsg = "Apostrophe not preceded by \\";
+ }
+ return false;
}
}
p++;
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..ec3db09 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,112 +277,23 @@ namespace android {
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Mutex
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-/*
- * Simple pthread wrapper.
- */
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
+#elif defined(HAVE_WIN32_THREADS)
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
+ HANDLE hMutex;
-#define STATE ((futex_mutex_t*) (&mState))
+ assert(sizeof(hMutex) == sizeof(mState));
-Mutex::Mutex()
-{
- _init();
+ hMutex = CreateMutex(NULL, FALSE, NULL);
+ mState = (void*) hMutex;
}
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
-
-#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
-
-Mutex::Mutex()
-{
+ // XXX: name not used for now
HANDLE hMutex;
assert(sizeof(hMutex) == sizeof(mState));
@@ -408,11 +302,13 @@ Mutex::Mutex()
mState = (void*) hMutex;
}
-Mutex::Mutex(const char* name)
+Mutex::Mutex(int type, const char* name)
{
- // XXX: name not used for now
+ // XXX: type and name not used for now
HANDLE hMutex;
+ assert(sizeof(hMutex) == sizeof(mState));
+
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
@@ -456,161 +352,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,17 +497,13 @@ status_t Condition::wait(Mutex& mutex)
return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
}
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
{
WinCondition* condState = (WinCondition*) mState;
HANDLE hMutex = (HANDLE) mutex.mState;
+ nsecs_t absTime = systemTime()+reltime;
- return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
+ return ((WinCondition*)mState)->wait(condState, hMutex, &absTime);
}
/*
@@ -841,11 +581,6 @@ void Condition::broadcast()
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Thread::Thread
-#endif
-
/*
* This is our thread object!
*/
@@ -920,6 +655,11 @@ int Thread::_threadLoop(void* user)
wp<Thread> weak(strong);
self->mHoldSelf.clear();
+#if HAVE_ANDROID_OS
+ // this is very useful for debugging with gdb
+ self->mTid = gettid();
+#endif
+
bool first = true;
do {
@@ -950,7 +690,7 @@ int Thread::_threadLoop(void* user)
self->mExitPending = true;
self->mLock.lock();
self->mRunning = false;
- self->mThreadExitedCondition.signal();
+ self->mThreadExitedCondition.broadcast();
self->mLock.unlock();
break;
}
@@ -958,7 +698,7 @@ int Thread::_threadLoop(void* user)
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
strong.clear();
- // And immediately, reacquire a strong reference for the next loop
+ // And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
} while(strong != 0);
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
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 25cfcb8..545fd0e 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -131,6 +131,30 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGL
/* Interfaces defined by EGL_KHR_image above */
#endif
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+struct android_native_buffer_t;
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_ANDROID_get_render_buffer
+#define EGL_ANDROID_get_render_buffer 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw);
+#endif
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw);
+#endif
+
+#ifndef EGL_ANDROID_swap_rectangle
+#define EGL_ANDROID_swap_rectangle 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif
+
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/include/EGL/eglnatives.h b/opengl/include/EGL/eglnatives.h
deleted file mode 100644
index 21622dc..0000000
--- a/opengl/include/EGL/eglnatives.h
+++ /dev/null
@@ -1,271 +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_EGLNATIVES_H
-#define ANDROID_EGLNATIVES_H
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-/* flags returned from swapBuffer */
-#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001
-
-/* surface flags */
-#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001
-
-enum native_pixel_format_t
-{
- NATIVE_PIXEL_FORMAT_RGBA_8888 = 1,
- NATIVE_PIXEL_FORMAT_RGB_565 = 4,
- NATIVE_PIXEL_FORMAT_BGRA_8888 = 5,
- NATIVE_PIXEL_FORMAT_RGBA_5551 = 6,
- NATIVE_PIXEL_FORMAT_RGBA_4444 = 7,
- NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
- NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
-};
-
-enum native_memory_type_t
-{
- NATIVE_MEMORY_TYPE_PMEM = 0,
- NATIVE_MEMORY_TYPE_GPU = 1,
- NATIVE_MEMORY_TYPE_FB = 2,
- NATIVE_MEMORY_TYPE_HEAP = 128
-};
-
-
-struct egl_native_window_t
-{
- /*
- * magic must be set to 0x600913
- */
- uint32_t magic;
-
- /*
- * must be sizeof(egl_native_window_t)
- */
- uint32_t version;
-
- /*
- * ident is reserved for the Android platform
- */
- uint32_t ident;
-
- /*
- * width, height and stride of the window in pixels
- * Any of these value can be nul in which case GL commands are
- * accepted and processed as usual, but not rendering occurs.
- */
- int width; // w=h=0 is legal
- int height;
- int stride;
-
- /*
- * format of the native window (see ui/PixelFormat.h)
- */
- int format;
-
- /*
- * Offset of the bits in the VRAM
- */
- intptr_t offset;
-
- /*
- * flags describing some attributes of this surface
- * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after
- * eglSwapBuffers
- */
- uint32_t flags;
-
- /*
- * horizontal and vertical resolution in DPI
- */
- float xdpi;
- float ydpi;
-
- /*
- * refresh rate in frames per second (Hz)
- */
- float fps;
-
-
- /*
- * Base memory virtual address of the surface in the CPU side
- */
- intptr_t base;
-
- /*
- * Heap the offset above is based from
- */
- int fd;
-
- /*
- * Memory type the surface resides into
- */
- uint8_t memory_type;
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- uint8_t reserved_pad[3];
- int reserved[8];
-
- /*
- * Vertical stride (only relevant with planar formats)
- */
-
- int vstride;
-
- /*
- * Hook called by EGL to hold a reference on this structure
- */
- void (*incRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to release a reference on this structure
- */
- void (*decRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to perform a page flip. This function
- * may update the size attributes above, in which case it returns
- * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
- */
- uint32_t (*swapBuffers)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_0)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_1)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_2)(void);
-
-
- /*
- * Hook called by EGL when the native surface is associated to EGL
- * (eglCreateWindowSurface). Can be NULL.
- */
- void (*connect)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL when eglDestroySurface is called. Can be NULL.
- */
- void (*disconnect)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc[11])(void);
-
- /*
- * Some storage reserved for the oem driver.
- */
- intptr_t oem[4];
-};
-
-
-struct egl_native_pixmap_t
-{
- int32_t version; /* must be 32 */
- int32_t width;
- int32_t height;
- int32_t stride;
- uint8_t* data;
- uint8_t format;
- uint8_t rfu[3];
- union {
- uint32_t compressedFormat;
- int32_t vstride;
- };
- int32_t reserved;
-};
-
-/*****************************************************************************/
-
-/*
- * This a convenience function to create a NativeWindowType surface
- * that maps to the whole screen
- * This function is actually implemented in libui.so
- */
-
-struct egl_native_window_t* android_createDisplaySurface();
-
-/*****************************************************************************/
-
-
-/*
- * OEM's egl's library (libhgl.so) must imlement these hooks to allocate
- * the GPU memory they need
- */
-
-
-typedef struct
-{
- // for internal use
- void* user;
- // virtual address of this area
- void* base;
- // size of this area in bytes
- size_t size;
- // physical address of this area
- void* phys;
- // offset in this area available to the GPU
- size_t offset;
- // fd of this area
- int fd;
-} gpu_area_t;
-
-typedef struct
-{
- // area where GPU registers are mapped
- gpu_area_t regs;
- // number of extra areas (currently limited to 2)
- int32_t count;
- // extra GPU areas (currently limited to 2)
- gpu_area_t gpu[2];
-} request_gpu_t;
-
-
-typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user);
-typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle);
-typedef void (*register_gpu_t)
- (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t);
-
-void oem_register_gpu(
- void* user,
- OEM_EGL_acquire_gpu_t acquire,
- OEM_EGL_release_gpu_t release);
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_EGLNATIVES_H */
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index ac00901..53e9e61 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -89,9 +89,10 @@ typedef Window EGLNativeWindowType;
#elif defined(ANDROID)
-#include <EGL/eglnatives.h>
+struct android_native_window_t;
+struct egl_native_pixmap_t;
-typedef struct egl_native_window_t* EGLNativeWindowType;
+typedef struct android_native_window_t* EGLNativeWindowType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
index 0924cae..198e679 100644
--- a/opengl/include/GLES/glplatform.h
+++ b/opengl/include/GLES/glplatform.h
@@ -28,12 +28,6 @@
#define GL_APIENTRY KHRONOS_APIENTRY
-// XXX: this should probably not be here
-#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
-
-// XXX: not sure how this is intended to be used
-#define GL_GLEXT_PROTOTYPES
-
#endif
#endif /* __glplatform_h_ */
diff --git a/opengl/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h
new file mode 100644
index 0000000..0182a67
--- /dev/null
+++ b/opengl/include/GLES2/gl2.h
@@ -0,0 +1,620 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
new file mode 100644
index 0000000..72f1ae7
--- /dev/null
+++ b/opengl/include/GLES2/gl2ext.h
@@ -0,0 +1,518 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 8271 $ on $Date:: 2009-05-21 09:33:40 -0700 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture3D */
+#ifndef GL_OES_texture3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA 0x80E1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint fence);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/opengl/include/GLES2/gl2platform.h b/opengl/include/GLES2/gl2platform.h
new file mode 100644
index 0000000..3e9036c
--- /dev/null
+++ b/opengl/include/GLES2/gl2platform.h
@@ -0,0 +1,29 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+#endif /* __gl2platform_h_ */
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 3ce0414..9837845 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -6,6 +6,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+# Set to 1 to use gralloc and copybits
+LIBAGL_USE_GRALLOC_COPYBITS := 1
+
LOCAL_SRC_FILES:= \
egl.cpp \
state.cpp \
@@ -22,6 +25,13 @@ LOCAL_SRC_FILES:= \
primitives.cpp.arm \
vertex.cpp.arm
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += fixed_asm.S iterators.S
LOCAL_CFLAGS += -fstrict-aliasing
@@ -29,13 +39,17 @@ endif
ifneq ($(TARGET_SIMULATOR),true)
# we need to access the private Bionic header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
-LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
-LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
+ LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
+ LOCAL_SRC_FILES += copybit.cpp
+ LOCAL_SHARED_LIBRARIES += libui
+endif
-LOCAL_LDLIBS := -lpthread -ldl
-LOCAL_MODULE:= libagl
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
+LOCAL_MODULE:= libGLES_android
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index ce31854..255ccac 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -1,16 +1,16 @@
/*
** Copyright 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
+ ** 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
+ ** 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
+ ** 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.
*/
@@ -19,11 +19,13 @@
#include "context.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
namespace android {
// ----------------------------------------------------------------------------
EGLTextureObject::EGLTextureObject()
- : mCount(0), mSize(0)
+ : mSize(0)
{
init();
}
@@ -53,6 +55,10 @@ void EGLTextureObject::init()
memset(crop_rect, 0, sizeof(crop_rect));
generate_mipmap = GL_FALSE;
direct = GL_FALSE;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ try_copybit = false;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ buffer = 0;
}
void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
@@ -123,6 +129,7 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s)
}
surface = *s;
internalformat = 0;
+ buffer = 0;
// we should keep the crop_rect, but it's delicate because
// the new size of the surface could make it invalid.
@@ -141,12 +148,26 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s)
return NO_ERROR;
}
+status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+{
+ GGLSurface sur;
+ sur.version = sizeof(GGLSurface);
+ sur.width = native_buffer->width;
+ sur.height= native_buffer->height;
+ sur.stride= native_buffer->stride;
+ sur.format= native_buffer->format;
+ sur.data = 0;
+ setSurface(&sur);
+ buffer = native_buffer;
+ return NO_ERROR;
+}
+
status_t EGLTextureObject::reallocate(
GLint level, int w, int h, int s,
int format, int compressedFormat, int bpr)
{
const size_t size = h * bpr;
- if (level == 0)
+ if (level == 0)
{
if (size!=mSize || !surface.data) {
if (mSize && surface.data) {
@@ -177,9 +198,9 @@ status_t EGLTextureObject::reallocate(
return NO_MEMORY;
}
- LOGW_IF(level-1 >= mNumExtraLod,
+ LOGW_IF(level-1 >= mNumExtraLod,
"specifying mipmap level %d, but # of level is %d",
- level, mNumExtraLod+1);
+ level, mNumExtraLod+1);
GGLSurface& mipmap = editMip(level);
if (mipmap.data)
@@ -224,7 +245,7 @@ status_t EGLTextureObject::reallocate(
// ----------------------------------------------------------------------------
EGLSurfaceManager::EGLSurfaceManager()
- : TokenManager(), mCount(0)
+ : TokenManager()
{
}
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 74ed1a4..279e040 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -1,16 +1,16 @@
/*
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -30,6 +30,8 @@
#include <private/pixelflinger/ggl_context.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include "Tokenizer.h"
#include "TokenManager.h"
@@ -39,22 +41,20 @@ namespace android {
// ----------------------------------------------------------------------------
-class EGLTextureObject
+class EGLTextureObject : public LightRefBase<EGLTextureObject>
{
public:
EGLTextureObject();
~EGLTextureObject();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- inline uint32_t getStrongCount() const;
+ status_t setSurface(GGLSurface const* s);
+ status_t setImage(android_native_buffer_t* buffer);
+ void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
- status_t setSurface(GGLSurface const* s);
status_t reallocate(GLint level,
int w, int h, int s,
int format, int compressedFormat, int bpr);
- inline size_t size() const;
+ inline size_t size() const { return mSize; }
const GGLSurface& mip(int lod) const;
GGLSurface& editMip(int lod);
bool hasMipmaps() const { return mMipmaps!=0; }
@@ -65,7 +65,6 @@ private:
status_t allocateMipmaps();
void freeMipmaps();
void init();
- mutable int32_t mCount;
size_t mSize;
GGLSurface *mMipmaps;
int mNumExtraLod;
@@ -81,36 +80,22 @@ public:
GLint crop_rect[4];
GLint generate_mipmap;
GLint direct;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ bool try_copybit;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ android_native_buffer_t* buffer;
};
-void EGLTextureObject::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLTextureObject::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-uint32_t EGLTextureObject::getStrongCount() const {
- return mCount;
-}
-size_t EGLTextureObject::size() const {
- return mSize;
-}
-
// ----------------------------------------------------------------------------
-class EGLSurfaceManager : public TokenManager
+class EGLSurfaceManager :
+ public LightRefBase<EGLSurfaceManager>,
+ public TokenManager
{
public:
EGLSurfaceManager();
~EGLSurfaceManager();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- typedef void weakref_type;
-
sp<EGLTextureObject> createTexture(GLuint name);
sp<EGLTextureObject> removeTexture(GLuint name);
sp<EGLTextureObject> replaceTexture(GLuint name);
@@ -118,21 +103,10 @@ public:
sp<EGLTextureObject> texture(GLuint name);
private:
- mutable int32_t mCount;
mutable Mutex mLock;
KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
};
-void EGLSurfaceManager::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLSurfaceManager::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 3e9c6a5..4878722 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -1,16 +1,16 @@
-/*
+/*
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -26,6 +26,9 @@
#include "primitives.h"
#include "texture.h"
#include "BufferObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
// ----------------------------------------------------------------------------
@@ -250,7 +253,7 @@ static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
v[2] = GGL_S_TO_X(p[2]);
}
-typedef array_t::fetcher_t fn_t;
+typedef array_t::fetcher_t fn_t;
static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
{ 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
@@ -334,7 +337,7 @@ void array_t::init(
this->bounds = count;
}
-inline void array_t::resolve()
+inline void array_t::resolve()
{
physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
}
@@ -465,7 +468,7 @@ vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
// We compute directly the index of a "free" entry from the locked
// state of v[2] and v[3].
v = c->vc.vBuffer + 2;
- v += v[0].locked | (v[1].locked<<1);
+ v += v[0].locked | (v[1].locked<<1);
}
// note: compileElement clears v->flags
c->arrays.compileElement(c, v, index);
@@ -480,7 +483,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
- vertex_t* const v = c->vc.vCache +
+ vertex_t* const v = c->vc.vCache +
(index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
if (ggl_likely(v->index == index)) {
@@ -491,7 +494,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
- vertex_t* v = c->vc.vCache +
+ vertex_t* v = c->vc.vCache +
(index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
// always record LRU in v[0]
@@ -532,12 +535,12 @@ void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE);
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -569,13 +572,13 @@ void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
count -= 1;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 1);
do {
- v0 = c->vc.vBuffer + 0;
+ v0 = c->vc.vBuffer + 0;
v = c->vc.vBuffer + 1;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -602,7 +605,7 @@ void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
return;
drawPrimitivesLineStrip(c, first, count);
if (ggl_likely(count >= 3)) {
- vertex_t* v0 = c->vc.vBuffer;
+ vertex_t* v0 = c->vc.vBuffer;
vertex_t* v1 = c->vc.vBuffer + 1;
c->arrays.compileElement(c, v1, first);
const uint32_t cc = v0->flags & v1->flags;
@@ -617,12 +620,12 @@ void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 2
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -662,14 +665,14 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
// because it allows us to preserve the same winding when the whole
// batch is culled. We also need 2 extra vertices in the array, because
// we always keep the two first ones.
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
do {
- v0 = c->vc.vBuffer + 0;
- v1 = c->vc.vBuffer + 1;
+ v0 = c->vc.vBuffer + 0;
+ v1 = c->vc.vBuffer + 1;
v = c->vc.vBuffer + 2;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -697,13 +700,19 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
} while (count > 0);
}
-void drawPrimitivesTriangleStrip(ogles_context_t* c,
+void drawPrimitivesTriangleStrip(ogles_context_t* c,
GLint first, GLsizei count) {
drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
}
void drawPrimitivesTriangleFan(ogles_context_t* c,
GLint first, GLsizei count) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTriangleFanWithCopybit(c, first, count)) {
+ return;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
}
@@ -713,12 +722,12 @@ void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 3
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -779,11 +788,11 @@ void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
{
if (ggl_unlikely(count < 2))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -806,11 +815,11 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
drawIndexedPrimitivesLines(c, count, indices);
return;
}
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -825,7 +834,7 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
} while (count);
v1->locked = 0;
- v1 = c->vc.vBuffer;
+ v1 = c->vc.vBuffer;
const uint32_t cc = v0->flags & v1->flags;
if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
c->prims.renderLine(c, v0, v1);
@@ -861,7 +870,7 @@ static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
if (ggl_unlikely(count < 3))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1 = v+1;
@@ -985,17 +994,17 @@ void compileElements__3x_full(ogles_context_t* c,
const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
const size_t stride = c->arrays.vertex.stride / 4;
// const GLfixed* const& m = c->transforms.mvp.matrix.m;
-
+
GLfixed m[16];
memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
-
+
do {
const GLfixed rx = vp[0];
const GLfixed ry = vp[1];
const GLfixed rz = vp[2];
vp += stride;
v->index = first++;
- v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
@@ -1023,7 +1032,7 @@ void compileElements__3x_full(ogles_context_t* c,
#pragma mark clippers
#endif
-static void clipVec4(vec4_t& nv,
+static void clipVec4(vec4_t& nv,
GLfixed t, const vec4_t& s, const vec4_t& p)
{
for (int i=0; i<4 ; i++)
@@ -1086,10 +1095,10 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
// automatically turn it off (in fact we could when the 4th coordinate
// is not spcified in the vertex array).
// W interpolation is never needed for points.
- GLboolean perspective =
+ GLboolean perspective =
c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
-
+
// set anti-aliasing
GLboolean smooth = GL_FALSE;
switch (mode) {
@@ -1120,7 +1129,7 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
want |= transform_state_t::TEXTURE;
}
- if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
+ if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
want |= transform_state_t::MODELVIEW; // needs eye coords
}
ogles_validate_transform(c, want);
@@ -1139,18 +1148,18 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
c->arrays.mv_transform =
c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
-
+
/*
* ***********************************************************************
* pick fetchers
* ***********************************************************************
*/
-
+
array_machine_t& am = c->arrays;
am.vertex.fetch = fetchNop;
am.normal.fetch = currentNormal;
am.color.fetch = currentColor;
-
+
if (am.vertex.enable) {
am.vertex.resolve();
if (am.vertex.bo || am.vertex.pointer) {
@@ -1257,9 +1266,7 @@ void glColorPointer(
GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
ogles_context_t* c = ogles_context_t::get();
- // in theory ogles doesn't allow color arrays of size 3
- // but it is very useful to 'visualize' the normal array.
- if (size<3 || size>4 || stride<0) {
+ if (size!=4 || stride<0) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
@@ -1366,9 +1373,18 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count)
if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
return; // all triangles are culled
+
validate_arrays(c, mode);
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+
drawArraysPrims[mode](c, first, count);
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1413,15 +1429,23 @@ void glDrawElements(
// clear the vertex-cache
c->vc.clear();
validate_arrays(c, mode);
-
+
// if indices are in a buffer object, the pointer is treated as an
// offset in that buffer.
if (c->arrays.element_array_buffer) {
indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
}
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+
drawElementsPrims[mode](c, count, indices);
+
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1448,7 +1472,7 @@ void glBindBuffer(GLenum target, GLuint buffer)
return;
}
}
- ((target == GL_ARRAY_BUFFER) ?
+ ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
}
@@ -1467,7 +1491,7 @@ void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usa
ogles_error(c, GL_INVALID_ENUM);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1497,7 +1521,7 @@ void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvo
ogles_error(c, GL_INVALID_VALUE);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1545,7 +1569,7 @@ void glDeleteBuffers(GLsizei n, const GLuint* buffers)
}
}
}
- }
+ }
c->bufferObjectManager->deleteBuffers(n, buffers);
c->bufferObjectManager->recycleTokens(n, buffers);
}
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
new file mode 100644
index 0000000..a68750e
--- /dev/null
+++ b/opengl/libagl/copybit.cpp
@@ -0,0 +1,631 @@
+/*
+**
+** 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 <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "primitives.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+#include <hardware/gralloc.h>
+#include <hardware/copybit.h>
+#include <private/ui/android_natives_priv.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
+
+#define DEBUG_COPYBIT true
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void textureToCopyBitImage(
+ const GGLSurface* surface, int32_t opFormat,
+ android_native_buffer_t* buffer, copybit_image_t* img)
+{
+ uint32_t vstride = 0;
+ if (opFormat == COPYBIT_FORMAT_YCbCr_422_SP ||
+ opFormat == COPYBIT_FORMAT_YCbCr_420_SP) {
+ // NOTE: this static_cast is really not safe b/c we can't know for
+ // sure the buffer passed is of the right type.
+ // However, since we do this only for YUV formats, we should be safe
+ // since only SurfaceFlinger makes use of them.
+ GraphicBuffer* graphicBuffer = static_cast<GraphicBuffer*>(buffer);
+ vstride = graphicBuffer->getVerticalStride();
+ }
+
+ img->w = surface->stride;
+ img->h = vstride ? vstride : surface->height;
+ img->format = opFormat;
+ img->base = surface->data;
+ img->handle = (native_handle_t *)buffer->handle;
+}
+
+struct clipRectRegion : public copybit_region_t {
+ clipRectRegion(ogles_context_t* c)
+ {
+ scissor_t const* scissor = &c->rasterizer.state.scissor;
+ r.l = scissor->left;
+ r.t = scissor->top;
+ r.r = scissor->right;
+ r.b = scissor->bottom;
+ next = iterate;
+ }
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ *rect = static_cast<clipRectRegion const*>(self)->r;
+ const_cast<copybit_region_t *>(self)->next = iterate_done;
+ return 1;
+ }
+ static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
+ return 0;
+ }
+public:
+ copybit_rect_t r;
+};
+
+static bool supportedCopybitsFormat(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_RGBX_8888:
+ case COPYBIT_FORMAT_RGB_888:
+ case COPYBIT_FORMAT_RGB_565:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ case COPYBIT_FORMAT_YCbCr_422_SP:
+ case COPYBIT_FORMAT_YCbCr_420_SP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool hasAlpha(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int fixedToByte(GGLfixed val) {
+ return (val - (val >> 8)) >> 8;
+}
+
+/**
+ * Performs a quick check of the rendering state. If this function returns
+ * false we cannot use the copybit driver.
+ */
+
+static bool checkContext(ogles_context_t* c) {
+
+ // By convention copybitQuickCheckContext() has already returned true.
+ // avoid checking the same information again.
+
+ if (c->copybits.blitEngine == NULL) {
+ LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
+ return false;
+ }
+
+ if (c->rasterizer.state.enables
+ & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
+ return false;
+ }
+
+ // Note: The drawSurfaceBuffer is only set for destination
+ // surfaces types that are supported by the hardware and
+ // do not have an alpha channel. So we don't have to re-check that here.
+
+ static const int tmu = 0;
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ EGLTextureObject* textureObject = u.texture;
+
+ if (!supportedCopybitsFormat(textureObject->surface.format)) {
+ LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
+ return false;
+ }
+ return true;
+}
+
+
+static bool copybit(GLint x, GLint y,
+ GLint w, GLint h,
+ EGLTextureObject* textureObject,
+ const GLint* crop_rect,
+ int transform,
+ ogles_context_t* c)
+{
+ status_t err = NO_ERROR;
+
+ // We assume checkContext has already been called and has already
+ // returned true.
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+
+ y = cbSurface.height - (y + h);
+
+ const GLint Ucr = crop_rect[0];
+ const GLint Vcr = crop_rect[1];
+ const GLint Wcr = crop_rect[2];
+ const GLint Hcr = crop_rect[3];
+
+ GLint screen_w = w;
+ GLint screen_h = h;
+ int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt
+ int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht
+ if (transform & COPYBIT_TRANSFORM_ROT_90) {
+ swap(screen_w, screen_h);
+ }
+ if (dsdx!=screen_w || dtdy!=screen_h) {
+ // in most cases the divide is not needed
+ dsdx /= screen_w;
+ dtdy /= screen_h;
+ }
+ dtdy = -dtdy; // see equation of dtdy above
+
+ // copybit doesn't say anything about filtering, so we can't
+ // discriminate. On msm7k, copybit will always filter.
+ // the code below handles min/mag filters, we keep it as a reference.
+
+#ifdef MIN_MAG_FILTER
+ int32_t texelArea = gglMulx(dtdy, dsdx);
+ if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
+ // Non-linear filtering on a texture enlargement.
+ LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
+ return false;
+ }
+ if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
+ // Non-linear filtering on an texture shrink.
+ LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
+ return false;
+ }
+#endif
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ int planeAlpha = 255;
+ bool alphaPlaneWorkaround = false;
+ static const int tmu = 0;
+ texture_t& tev(c->rasterizer.state.texture[tmu]);
+ int32_t opFormat = textureObject->surface.format;
+ const bool srcTextureHasAlpha = hasAlpha(opFormat);
+ if (!srcTextureHasAlpha) {
+ planeAlpha = fixedToByte(c->currentColorClamped.a);
+ }
+
+ const bool cbHasAlpha = hasAlpha(cbSurface.format);
+ bool blending = false;
+ if ((enables & GGL_ENABLE_BLENDING)
+ && !(c->rasterizer.state.blend.src == GL_ONE
+ && c->rasterizer.state.blend.dst == GL_ZERO)) {
+ // Blending is OK if it is
+ // the exact kind of blending that the copybits hardware supports.
+ // Note: The hardware only supports
+ // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
+ // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
+ // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
+ // because the performance is worth it, even if the results are
+ // not correct.
+ if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
+ || c->rasterizer.state.blend.src == GL_ONE)
+ && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
+ && c->rasterizer.state.blend.alpha_separate == 0)) {
+ // Incompatible blend mode.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
+ return false;
+ }
+ blending = true;
+ } else {
+ if (cbHasAlpha) {
+ // NOTE: the result will be slightly wrong in this case because
+ // the destination alpha channel will be set to 1.0 instead of
+ // the iterated alpha value. *shrug*.
+ }
+ // disable plane blending and src blending for supported formats
+ planeAlpha = 255;
+ if (opFormat == COPYBIT_FORMAT_RGBA_8888) {
+ opFormat = COPYBIT_FORMAT_RGBX_8888;
+ } else {
+ if (srcTextureHasAlpha) {
+ LOGD_IF(DEBUG_COPYBIT, "texture format requires blending");
+ return false;
+ }
+ }
+ }
+
+ switch (tev.env) {
+ case GGL_REPLACE:
+ break;
+ case GGL_MODULATE:
+ // only cases allowed is:
+ // RGB source, color={1,1,1,a} -> can be done with GL_REPLACE
+ // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE
+ if (blending) {
+ if (c->currentColorClamped.r == c->currentColorClamped.a &&
+ c->currentColorClamped.g == c->currentColorClamped.a &&
+ c->currentColorClamped.b == c->currentColorClamped.a) {
+ // TODO: RGBA source, color={1,1,1,a} / regular-blending
+ // is equivalent
+ alphaPlaneWorkaround = true;
+ break;
+ }
+ }
+ LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE");
+ return false;
+ default:
+ // Incompatible texture environment.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
+ return false;
+ }
+
+ copybit_device_t* copybit = c->copybits.blitEngine;
+ copybit_image_t src;
+ textureToCopyBitImage(&textureObject->surface, opFormat,
+ textureObject->buffer, &src);
+ copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+ /*
+ * Below we perform extra passes needed to emulate things the h/w
+ * cannot do.
+ */
+
+ const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
+ const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
+
+ sp<GraphicBuffer> tempBitmap;
+
+ if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+ dtdy < maxScaleInv || dtdy > minScaleInv)
+ {
+ // The requested scale is out of the range the hardware
+ // can support.
+ LOGD_IF(DEBUG_COPYBIT,
+ "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+ "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+ dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+
+ int32_t xscale=0x10000, yscale=0x10000;
+ if (dsdx > minScaleInv) xscale = c->copybits.minScale;
+ else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale;
+ if (dtdy > minScaleInv) yscale = c->copybits.minScale;
+ else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale;
+ dsdx = gglMulx(dsdx, xscale);
+ dtdy = gglMulx(dtdy, yscale);
+
+ /* we handle only one step of resizing below. Handling an arbitrary
+ * number is relatively easy (replace "if" above by "while"), but requires
+ * two intermediate buffers and so far we never had the need.
+ */
+
+ if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+ dtdy < maxScaleInv || dtdy > minScaleInv) {
+ LOGD_IF(DEBUG_COPYBIT,
+ "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+ "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+ dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+ return false;
+ }
+
+ const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
+ const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
+
+ LOGD_IF(DEBUG_COPYBIT,
+ "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
+ xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
+
+ tempBitmap = new GraphicBuffer(
+ tmp_w, tmp_h, src.format,
+ GraphicBuffer::USAGE_HW_2D);
+
+ err = tempBitmap->initCheck();
+ if (err == NO_ERROR) {
+ copybit_image_t tmp_dst;
+ copybit_rect_t tmp_rect;
+ tmp_dst.w = tmp_w;
+ tmp_dst.h = tmp_h;
+ tmp_dst.format = tempBitmap->format;
+ tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
+ tmp_rect.l = 0;
+ tmp_rect.t = 0;
+ tmp_rect.r = tmp_dst.w;
+ tmp_rect.b = tmp_dst.h;
+ region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.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_dst, &src, &tmp_rect, &srect, &tmp_it);
+ src = tmp_dst;
+ srect = tmp_rect;
+ }
+ }
+
+ copybit_image_t dst;
+ textureToCopyBitImage(&cbSurface, cbSurface.format,
+ c->copybits.drawSurfaceBuffer, &dst);
+ copybit_rect_t drect = {x, y, x+w, y+h};
+
+
+ /* and now the alpha-plane hack. This handles the "Fade" case of a
+ * texture with an alpha channel.
+ */
+ if (alphaPlaneWorkaround) {
+ sp<GraphicBuffer> tempCb = new GraphicBuffer(
+ w, h, COPYBIT_FORMAT_RGB_565,
+ GraphicBuffer::USAGE_HW_2D);
+
+ err = tempCb->initCheck();
+
+ copybit_image_t tmpCbImg;
+ copybit_rect_t tmpCbRect;
+ copybit_rect_t tmpdrect = drect;
+ tmpCbImg.w = w;
+ tmpCbImg.h = h;
+ tmpCbImg.format = tempCb->format;
+ tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle;
+ tmpCbRect.l = 0;
+ tmpCbRect.t = 0;
+
+ if (drect.l < 0) {
+ tmpCbRect.l = -tmpdrect.l;
+ tmpdrect.l = 0;
+ }
+ if (drect.t < 0) {
+ tmpCbRect.t = -tmpdrect.t;
+ tmpdrect.t = 0;
+ }
+ if (drect.l + tmpCbImg.w > dst.w) {
+ tmpCbImg.w = dst.w - drect.l;
+ tmpdrect.r = dst.w;
+ }
+ if (drect.t + tmpCbImg.h > dst.h) {
+ tmpCbImg.h = dst.h - drect.t;
+ tmpdrect.b = dst.h;
+ }
+
+ tmpCbRect.r = tmpCbImg.w;
+ tmpCbRect.b = tmpCbImg.h;
+
+ if (!err) {
+ // first make a copy of the destination buffer
+ region_iterator tmp_it(Region(Rect(w, h)));
+ 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,
+ &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it);
+ }
+ if (!err) {
+ // then proceed as usual, but without the alpha plane
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (enables & GGL_ENABLE_DITHER) ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ clipRectRegion it(c);
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+ if (!err) {
+ // finally copy back the destination on top with 1-alphaplane
+ int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a);
+ clipRectRegion it(c);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ err = copybit->stretch(copybit,
+ &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it);
+ }
+ } else {
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (enables & GGL_ENABLE_DITHER) ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ clipRectRegion it(c);
+
+ LOGD_IF(0,
+ "dst={%d, %d, %d, %p, %p}, "
+ "src={%d, %d, %d, %p, %p}, "
+ "drect={%d,%d,%d,%d}, "
+ "srect={%d,%d,%d,%d}, "
+ "it={%d,%d,%d,%d}, " ,
+ dst.w, dst.h, dst.format, dst.base, dst.handle,
+ src.w, src.h, src.format, src.base, src.handle,
+ drect.l, drect.t, drect.r, drect.b,
+ srect.l, srect.t, srect.r, srect.b,
+ it.r.l, it.r.t, it.r.r, it.r.b
+ );
+
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+ if (err != NO_ERROR) {
+ c->textures.tmu[0].texture->try_copybit = false;
+ }
+ return err == NO_ERROR ? true : false;
+}
+
+/*
+ * Try to draw a triangle fan with copybit, return false if we fail.
+ */
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (!checkContext(c)) {
+ return false;
+ }
+
+ // FIXME: we should handle culling here
+ c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
+
+ // we detect if we're dealing with a rectangle, by comparing the
+ // rectangles {v0,v2} and {v1,v3} which should be identical.
+
+ // NOTE: we should check that the rectangle is window aligned, however
+ // if we do that, the optimization won't be taken in a lot of cases.
+ // Since this code is intended to be used with SurfaceFlinger only,
+ // so it's okay...
+
+ const vec4_t& v0 = c->vc.vBuffer[0].window;
+ const vec4_t& v1 = c->vc.vBuffer[1].window;
+ const vec4_t& v2 = c->vc.vBuffer[2].window;
+ const vec4_t& v3 = c->vc.vBuffer[3].window;
+ int l = min(v0.x, v2.x);
+ int b = min(v0.y, v2.y);
+ int r = max(v0.x, v2.x);
+ int t = max(v0.y, v2.y);
+ if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
+ (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
+ return false;
+ }
+
+ // fetch and transform texture coordinates
+ // NOTE: maybe it would be better to have a "compileElementsAll" method
+ // that would ensure all vertex data are fetched and transformed
+ const transform_t& tr = c->transforms.texture[0].transform;
+ for (size_t i=0 ; i<4 ; i++) {
+ const GLubyte* tp = c->arrays.texture[0].element(i);
+ vertex_t* const v = &c->vc.vBuffer[i];
+ c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
+ // FIXME: we should bail if q!=1
+ c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
+ }
+
+ const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
+ const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
+ const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
+ const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
+ int txl = min(t0.x, t2.x);
+ int txb = min(t0.y, t2.y);
+ int txr = max(t0.x, t2.x);
+ int txt = max(t0.y, t2.y);
+ if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
+ (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
+ return false;
+ }
+ if ((txl != 0) || (txb != 0) ||
+ (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
+ // we could probably handle this case, if we wanted to
+ LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
+ txl, txb, txr, txt);
+ return false;
+ }
+
+ // at this point, we know we are dealing with a rectangle, so we
+ // only need to consider 3 vertices for computing the jacobians
+
+ const int dx01 = v1.x - v0.x;
+ const int dx02 = v2.x - v0.x;
+ const int dy01 = v1.y - v0.y;
+ const int dy02 = v2.y - v0.y;
+ const int ds01 = t1.S - t0.S;
+ const int ds02 = t2.S - t0.S;
+ const int dt01 = t1.T - t0.T;
+ const int dt02 = t2.T - t0.T;
+ const int area = dx01*dy02 - dy01*dx02;
+ int dsdx, dsdy, dtdx, dtdy;
+ if (area >= 0) {
+ dsdx = ds01*dy02 - ds02*dy01;
+ dtdx = dt01*dy02 - dt02*dy01;
+ dsdy = ds02*dx01 - ds01*dx02;
+ dtdy = dt02*dx01 - dt01*dx02;
+ } else {
+ dsdx = ds02*dy01 - ds01*dy02;
+ dtdx = dt02*dy01 - dt01*dy02;
+ dsdy = ds01*dx02 - ds02*dx01;
+ dtdy = dt01*dx02 - dt02*dx01;
+ }
+
+ // here we rely on the fact that we know the transform is
+ // a rigid-body transform AND that it can only rotate in 90 degrees
+ // increments
+
+ int transform = 0;
+ if (dsdx == 0) {
+ // 90 deg rotation case
+ // [ 0 dtdx ]
+ // [ dsdx 0 ]
+ transform |= COPYBIT_TRANSFORM_ROT_90;
+ // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
+ if (dtdx > 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dsdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ } else {
+ // [ dsdx 0 ]
+ // [ 0 dtdy ]
+ if (dsdx < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dtdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ }
+
+ //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
+ //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
+ // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
+
+ int x = l >> 4;
+ int y = b >> 4;
+ int w = (r-l) >> 4;
+ int h = (t-b) >> 4;
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ GLint tWidth = textureObject->surface.width;
+ GLint tHeight = textureObject->surface.height;
+ GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + h);
+ return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
+}
+
+/*
+ * Try to drawTexiOESWithCopybit, return false if we fail.
+ */
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c)
+{
+ // quickly process empty rects
+ if ((w|h) <= 0) {
+ return true;
+ }
+ if (!checkContext(c)) {
+ return false;
+ }
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
+}
+
+} // namespace android
+
diff --git a/opengl/libagl/copybit.h b/opengl/libagl/copybit.h
new file mode 100644
index 0000000..b8b5afd
--- /dev/null
+++ b/opengl/libagl/copybit.h
@@ -0,0 +1,75 @@
+/*
+**
+** 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_OPENGLES_COPYBIT_H
+#define ANDROID_OPENGLES_COPYBIT_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+#include "TextureObjectManager.h"
+namespace android {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c);
+
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first,
+ GLsizei count);
+
+inline bool copybitQuickCheckContext(ogles_context_t* c) {
+ return c->copybits.drawSurfaceBuffer != 0
+ && c->rasterizer.state.enabled_tmu == 1
+ && c->textures.tmu[0].texture->try_copybit;
+}
+
+/*
+ * Tries to draw a drawTexiOES using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c) {
+ if (!copybitQuickCheckContext(c)) {
+ return false;
+ }
+
+ return drawTexiOESWithCopybit_impl(x, y, z, w, h, c);
+}
+
+/*
+ * Tries to draw a triangle fan using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first,
+ GLsizei count) {
+ /*
+ * We are looking for the glDrawArrays call made by SurfaceFlinger.
+ */
+
+ if ((count!=4) || first || !copybitQuickCheckContext(c))
+ return false;
+
+ return drawTriangleFanWithCopybit_impl(c, first, count);
+}
+
+
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_COPYBIT_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 4461567..673c174 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -15,8 +15,6 @@
** limitations under the License.
*/
-#define LOG_TAG "EGL"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
@@ -41,6 +39,11 @@
#include <pixelflinger/format.h>
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/android_natives_priv.h>
+#include <private/ui/sw_gralloc_handle.h>
+
+#include <hardware/copybit.h>
+
#include "context.h"
#include "state.h"
#include "texture.h"
@@ -89,9 +92,9 @@ static GLint getError() {
struct egl_display_t
{
egl_display_t() : type(0), initialized(0) { }
-
+
static egl_display_t& get_display(EGLDisplay dpy);
-
+
static EGLBoolean is_valid(EGLDisplay dpy) {
return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
}
@@ -139,19 +142,23 @@ struct egl_surface_t
egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
virtual ~egl_surface_t();
- virtual bool isValid() const = 0;
-
+ bool isValid() const;
+ virtual bool initCheck() const = 0;
+
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
+ virtual EGLBoolean connect() { return EGL_TRUE; }
+ virtual void disconnect() {}
virtual EGLint getWidth() const = 0;
virtual EGLint getHeight() const = 0;
- virtual void* getBits() const = 0;
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
protected:
GGLSurface depth;
};
@@ -170,6 +177,11 @@ egl_surface_t::~egl_surface_t()
magic = 0;
free(depth.data);
}
+bool egl_surface_t::isValid() const {
+ LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
+ return magic == MAGIC;
+}
+
EGLBoolean egl_surface_t::swapBuffers() {
return EGL_FALSE;
}
@@ -185,119 +197,519 @@ EGLint egl_surface_t::getRefreshRate() const {
EGLint egl_surface_t::getSwapBehavior() const {
return EGL_BUFFER_PRESERVED;
}
+EGLBoolean egl_surface_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ return EGL_FALSE;
+}
+EGLClientBuffer egl_surface_t::getRenderBuffer() const {
+ return 0;
+}
// ----------------------------------------------------------------------------
-struct egl_window_surface_t : public egl_surface_t
+struct egl_window_surface_v2_t : public egl_surface_t
{
- egl_window_surface_t(
+ egl_window_surface_v2_t(
EGLDisplay dpy, EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window);
+ android_native_window_t* window);
- ~egl_window_surface_t();
+ ~egl_window_surface_v2_t();
- virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
+ virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails
virtual EGLBoolean swapBuffers();
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLint getWidth() const { return nativeWindow->width; }
- virtual EGLint getHeight() const { return nativeWindow->height; }
- virtual void* getBits() const;
+ virtual EGLBoolean connect();
+ virtual void disconnect();
+ virtual EGLint getWidth() const { return width; }
+ virtual EGLint getHeight() const { return height; }
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
+
private:
- egl_native_window_t* nativeWindow;
+ status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
+ status_t unlock(android_native_buffer_t* buf);
+ android_native_window_t* nativeWindow;
+ android_native_buffer_t* buffer;
+ android_native_buffer_t* previousBuffer;
+ gralloc_module_t const* module;
+ copybit_device_t* blitengine;
+ int width;
+ int height;
+ void* bits;
+ GGLFormat const* pixelFormatTable;
+
+ struct Rect {
+ inline Rect() { };
+ inline Rect(int32_t w, int32_t h)
+ : left(0), top(0), right(w), bottom(h) { }
+ inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
+ : left(l), top(t), right(r), bottom(b) { }
+ Rect& andSelf(const Rect& r) {
+ left = max(left, r.left);
+ top = max(top, r.top);
+ right = min(right, r.right);
+ bottom = min(bottom, r.bottom);
+ return *this;
+ }
+ bool isEmpty() const {
+ return (left>=right || top>=bottom);
+ }
+ void dump(char const* what) {
+ LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
+ what, left, top, right-left, bottom-top);
+ }
+
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
+
+ struct Region {
+ inline Region() : count(0) { }
+ typedef Rect const* const_iterator;
+ const_iterator begin() const { return storage; }
+ const_iterator end() const { return storage+count; }
+ static Region subtract(const Rect& lhs, const Rect& rhs) {
+ Region reg;
+ Rect* storage = reg.storage;
+ if (!lhs.isEmpty()) {
+ if (lhs.top < rhs.top) { // top rect
+ storage->left = lhs.left;
+ storage->top = lhs.top;
+ storage->right = lhs.right;
+ storage->bottom = rhs.top;
+ storage++;
+ }
+ const int32_t top = max(lhs.top, rhs.top);
+ const int32_t bot = min(lhs.bottom, rhs.bottom);
+ if (top < bot) {
+ if (lhs.left < rhs.left) { // left-side rect
+ storage->left = lhs.left;
+ storage->top = top;
+ storage->right = rhs.left;
+ storage->bottom = bot;
+ storage++;
+ }
+ if (lhs.right > rhs.right) { // right-side rect
+ storage->left = rhs.right;
+ storage->top = top;
+ storage->right = lhs.right;
+ storage->bottom = bot;
+ storage++;
+ }
+ }
+ if (lhs.bottom > rhs.bottom) { // bottom rect
+ storage->left = lhs.left;
+ storage->top = rhs.bottom;
+ storage->right = lhs.right;
+ storage->bottom = lhs.bottom;
+ storage++;
+ }
+ reg.count = storage - reg.storage;
+ }
+ return reg;
+ }
+ bool isEmpty() const {
+ return count<=0;
+ }
+ private:
+ Rect storage[4];
+ ssize_t count;
+ };
+
+ struct region_iterator : public copybit_region_t {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
+ this->next = iterate;
+ }
+ private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
+ }
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
+ };
+
+ void copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip);
+
+ Rect dirtyRegion;
+ Rect oldDirtyRegion;
};
-egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window)
- : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+ android_native_window_t* window)
+ : egl_surface_t(dpy, config, depthFormat),
+ nativeWindow(window), buffer(0), previousBuffer(0), module(0),
+ blitengine(0), bits(NULL)
{
- if (depthFormat) {
- depth.width = window->width;
- depth.height = window->height;
+ hw_module_t const* pModule;
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
+ module = reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
+ copybit_open(pModule, &blitengine);
+ }
+
+ pixelFormatTable = gglGetPixelFormatTable();
+
+ // keep a reference on the window
+ nativeWindow->common.incRef(&nativeWindow->common);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
+}
+
+egl_window_surface_v2_t::~egl_window_surface_v2_t() {
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ }
+ nativeWindow->common.decRef(&nativeWindow->common);
+ if (blitengine) {
+ copybit_close(blitengine);
+ }
+}
+
+EGLBoolean egl_window_surface_v2_t::connect()
+{
+ // we're intending to do software rendering
+ native_window_set_usage(nativeWindow,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ // dequeue a buffer
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ // allocate a corresponding depth-buffer
+ width = buffer->width;
+ height = buffer->height;
+ if (depth.format) {
+ depth.width = width;
+ depth.height = height;
depth.stride = depth.width; // use the width here
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
}
}
- nativeWindow->incRef(nativeWindow);
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // Lock the buffer
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+ // pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("connect() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+ return EGL_TRUE;
}
-egl_window_surface_t::~egl_window_surface_t() {
- nativeWindow->decRef(nativeWindow);
+
+void egl_window_surface_v2_t::disconnect()
+{
+ if (buffer && bits) {
+ bits = NULL;
+ unlock(buffer);
+ }
+ // enqueue the last frame
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ buffer = 0;
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+}
+
+status_t egl_window_surface_v2_t::lock(
+ android_native_buffer_t* buf, int usage, void** vaddr)
+{
+ int err;
+ if (sw_gralloc_handle_t::validate(buf->handle) < 0) {
+ err = module->lock(module, buf->handle,
+ usage, 0, 0, buf->width, buf->height, vaddr);
+ } else {
+ sw_gralloc_handle_t const* hnd =
+ reinterpret_cast<sw_gralloc_handle_t const*>(buf->handle);
+ *vaddr = (void*)hnd->base;
+ err = NO_ERROR;
+ }
+ return err;
+}
+
+status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+{
+ if (!buf) return BAD_VALUE;
+ int err = NO_ERROR;
+ if (sw_gralloc_handle_t::validate(buf->handle) < 0) {
+ err = module->unlock(module, buf->handle);
+ }
+ return err;
+}
+
+void egl_window_surface_v2_t::copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip)
+{
+ // FIXME: use copybit if possible
+ // NOTE: dst and src must be the same format
+
+ status_t err = NO_ERROR;
+ copybit_device_t* const copybit = blitengine;
+ if (copybit) {
+ copybit_image_t simg;
+ simg.w = src->width;
+ simg.h = src->height;
+ simg.format = src->format;
+ simg.handle = const_cast<native_handle_t*>(src->handle);
+
+ copybit_image_t dimg;
+ dimg.w = dst->width;
+ dimg.h = dst->height;
+ dimg.format = dst->format;
+ dimg.handle = const_cast<native_handle_t*>(dst->handle);
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ region_iterator it(clip);
+ err = copybit->blit(copybit, &dimg, &simg, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
+ }
+
+ if (!copybit || err) {
+ Region::const_iterator cur = clip.begin();
+ Region::const_iterator end = clip.end();
+
+ const size_t bpp = pixelFormatTable[src->format].size;
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+ uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
+
+ while (cur != end) {
+ const Rect& r(*cur++);
+ ssize_t w = r.right - r.left;
+ ssize_t h = r.bottom - r.top;
+ if (w <= 0 || h<=0) continue;
+ size_t size = w * 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);
+ }
+ }
}
-EGLBoolean egl_window_surface_t::swapBuffers()
+EGLBoolean egl_window_surface_v2_t::swapBuffers()
{
- uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
- if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+ if (!buffer) {
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+
+ /*
+ * Handle eglSetSwapRectangleANDROID()
+ * We copyback from the front buffer
+ */
+ if (!dirtyRegion.isEmpty()) {
+ dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
+ if (previousBuffer) {
+ const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ if (!copyBack.isEmpty()) {
+ void* prevBits;
+ if (lock(previousBuffer,
+ GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
+ // copy from previousBuffer to buffer
+ copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
+ unlock(previousBuffer);
+ }
+ }
+ }
+ oldDirtyRegion = dirtyRegion;
+ }
+
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+
+ unlock(buffer);
+ previousBuffer = buffer;
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ buffer = 0;
+
+ // dequeue a new buffer
+ nativeWindow->dequeueBuffer(nativeWindow, &buffer);
+
+ // TODO: lockBuffer should rather be executed when the very first
+ // direct rendering occurs.
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+
+ // reallocate the depth-buffer if needed
+ if ((width != buffer->width) || (height != buffer->height)) {
// TODO: we probably should reset the swap rect here
// if the window size has changed
+ width = buffer->width;
+ height = buffer->height;
if (depth.data) {
free(depth.data);
- depth.width = nativeWindow->width;
- depth.height = nativeWindow->height;
- depth.stride = nativeWindow->stride;
+ depth.width = width;
+ depth.height = height;
+ depth.stride = buffer->stride;
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ setError(EGL_BAD_ALLOC, EGL_FALSE);
return EGL_FALSE;
}
}
}
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // finally pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+
+ return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ dirtyRegion = Rect(l, t, l+w, t+h);
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
+{
+ return buffer;
+}
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+static bool supportedCopybitsDestinationFormat(int format) {
+ // Hardware supported
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+ }
+ return false;
+}
+#endif
+
+EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits;
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ gl->copybits.drawSurfaceBuffer = 0;
+ if (gl->copybits.blitEngine != NULL) {
+ if (supportedCopybitsDestinationFormat(buffer.format)) {
+ buffer_handle_t handle = this->buffer->handle;
+ if (handle != NULL) {
+ gl->copybits.drawSurfaceBuffer = this->buffer;
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.readBuffer(gl, &buffer);
return EGL_TRUE;
}
-void* egl_window_surface_t::getBits() const {
- return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
-}
-EGLint egl_window_surface_t::getHorizontalResolution() const {
+EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getVerticalResolution() const {
+EGLint egl_window_surface_v2_t::getVerticalResolution() const {
return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getRefreshRate() const {
- return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+EGLint egl_window_surface_v2_t::getRefreshRate() const {
+ return (60 * EGL_DISPLAY_SCALING); // FIXME
}
-EGLint egl_window_surface_t::getSwapBehavior() const {
- uint32_t flags = nativeWindow->flags;
- if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
- return EGL_BUFFER_DESTROYED;
- return EGL_BUFFER_PRESERVED;
+EGLint egl_window_surface_v2_t::getSwapBehavior() const
+{
+ /*
+ * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
+ * the content of the swapped buffer.
+ *
+ * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
+ *
+ * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
+ * only applies to the area specified by eglSetSwapRectangleANDROID(), that
+ * is, everything outside of this area is preserved.
+ *
+ * This implementation of EGL assumes the later case.
+ *
+ */
+
+ return EGL_BUFFER_DESTROYED;
}
// ----------------------------------------------------------------------------
@@ -311,12 +723,11 @@ struct egl_pixmap_surface_t : public egl_surface_t
virtual ~egl_pixmap_surface_t() { }
- virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual bool initCheck() const { return !depth.format || depth.data!=0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return nativePixmap.width; }
virtual EGLint getHeight() const { return nativePixmap.height; }
- virtual void* getBits() const { return nativePixmap.data; }
private:
egl_native_pixmap_t nativePixmap;
};
@@ -334,7 +745,6 @@ egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
}
}
}
@@ -347,7 +757,7 @@ EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
buffer.stride = nativePixmap.stride;
buffer.data = nativePixmap.data;
buffer.format = nativePixmap.format;
-
+
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
@@ -376,12 +786,11 @@ struct egl_pbuffer_surface_t : public egl_surface_t
virtual ~egl_pbuffer_surface_t();
- virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual bool initCheck() const { return pbuffer.data != 0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return pbuffer.width; }
virtual EGLint getHeight() const { return pbuffer.height; }
- virtual void* getBits() const { return pbuffer.data; }
private:
GGLSurface pbuffer;
};
@@ -396,6 +805,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
+ case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
default:
LOGE("incompatible pixel format for pbuffer (format=%d)", f);
pbuffer.data = 0;
@@ -407,7 +817,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
pbuffer.stride = w;
pbuffer.data = (GGLubyte*)malloc(size);
pbuffer.format = f;
-
+
if (depthFormat) {
depth.width = pbuffer.width;
depth.height = pbuffer.height;
@@ -468,7 +878,13 @@ struct config_management_t {
static char const * const gVendorString = "Google Inc.";
static char const * const gVersionString = "1.2 Android Driver";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionsString = "";
+static char const * const gExtensionsString =
+ "EGL_KHR_image_base "
+ // "KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
// ----------------------------------------------------------------------------
@@ -496,6 +912,10 @@ static const extention_map_t gExtentionMap[] = {
(__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
{ "glQueryMatrixxOES",
(__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+ { "glEGLImageTargetTexture2DOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
+ { "glEGLImageTargetRenderbufferStorageOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
{ "glClipPlanef",
(__eglMustCastToProperFunctionPointerType)&glClipPlanef },
{ "glClipPlanex",
@@ -510,9 +930,17 @@ static const extention_map_t gExtentionMap[] = {
(__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
{ "glGenBuffers",
(__eglMustCastToProperFunctionPointerType)&glGenBuffers },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
-/*
+/*
* In the lists below, attributes names MUST be sorted.
* Additionally, all configs must be sorted according to
* the EGL specification.
@@ -523,7 +951,7 @@ static config_pair_t const config_base_attribute_list[] = {
{ EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
{ EGL_LEVEL, 0 },
{ EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_PIXELS,
+ { EGL_MAX_PBUFFER_PIXELS,
GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
{ EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
{ EGL_NATIVE_RENDERABLE, EGL_TRUE },
@@ -538,12 +966,18 @@ static config_pair_t const config_base_attribute_list[] = {
{ EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
{ EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
{ EGL_MIN_SWAP_INTERVAL, 1 },
- { EGL_MAX_SWAP_INTERVAL, 4 },
+ { EGL_MAX_SWAP_INTERVAL, 1 },
+ { EGL_LUMINANCE_SIZE, 0 },
+ { EGL_ALPHA_MASK_SIZE, 0 },
+ { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER },
+ { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT },
+ { EGL_CONFORMANT, 0 }
};
// These configs can override the base attribute list
// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
+// 565 configs
static config_pair_t const config_0_attribute_list[] = {
{ EGL_BUFFER_SIZE, 16 },
{ EGL_ALPHA_SIZE, 0 },
@@ -566,8 +1000,32 @@ static config_pair_t const config_1_attribute_list[] = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
+// RGB 888 configs
static config_pair_t const config_2_attribute_list[] = {
{ EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 6 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_3_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 7 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+// 8888 configs
+static config_pair_t const config_4_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
{ EGL_ALPHA_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
{ EGL_GREEN_SIZE, 8 },
@@ -577,7 +1035,7 @@ static config_pair_t const config_2_attribute_list[] = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
-static config_pair_t const config_3_attribute_list[] = {
+static config_pair_t const config_5_attribute_list[] = {
{ EGL_BUFFER_SIZE, 32 },
{ EGL_ALPHA_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
@@ -588,7 +1046,8 @@ static config_pair_t const config_3_attribute_list[] = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
-static config_pair_t const config_4_attribute_list[] = {
+// A8 configs
+static config_pair_t const config_6_attribute_list[] = {
{ EGL_BUFFER_SIZE, 8 },
{ EGL_ALPHA_SIZE, 8 },
{ EGL_BLUE_SIZE, 0 },
@@ -599,7 +1058,7 @@ static config_pair_t const config_4_attribute_list[] = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
-static config_pair_t const config_5_attribute_list[] = {
+static config_pair_t const config_7_attribute_list[] = {
{ EGL_BUFFER_SIZE, 8 },
{ EGL_ALPHA_SIZE, 8 },
{ EGL_BLUE_SIZE, 0 },
@@ -617,6 +1076,8 @@ static configs_t const gConfigs[] = {
{ config_3_attribute_list, NELEM(config_3_attribute_list) },
{ config_4_attribute_list, NELEM(config_4_attribute_list) },
{ config_5_attribute_list, NELEM(config_5_attribute_list) },
+ { config_6_attribute_list, NELEM(config_6_attribute_list) },
+ { config_7_attribute_list, NELEM(config_7_attribute_list) },
};
static config_management_t const gConfigManagement[] = {
@@ -647,22 +1108,74 @@ static config_management_t const gConfigManagement[] = {
{ EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
{ EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
{ EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
+ { EGL_LUMINANCE_SIZE, config_management_t::atLeast },
+ { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast },
+ { EGL_COLOR_BUFFER_TYPE, config_management_t::exact },
+ { EGL_RENDERABLE_TYPE, config_management_t::mask },
+ { EGL_CONFORMANT, config_management_t::mask }
};
+
static config_pair_t const config_defaults[] = {
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
+ // attributes that are not specified are simply ignored, if a particular
+ // one needs not be ignored, it must be specified here, eg:
+ // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
};
// ----------------------------------------------------------------------------
+static status_t getConfigFormatInfo(EGLint configID,
+ int32_t& pixelFormat, int32_t& depthFormat)
+{
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 4:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 5:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 6:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = 0;
+ break;
+ case 7:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
template<typename T>
static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
{
while (first <= last) {
int mid = (first + last) / 2;
- if (key > sortedArray[mid].key) {
+ if (key > sortedArray[mid].key) {
first = mid + 1;
- } else if (key < sortedArray[mid].key) {
+ } else if (key < sortedArray[mid].key) {
last = mid - 1;
} else {
return mid;
@@ -674,13 +1187,13 @@ static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
static int isAttributeMatching(int i, EGLint attr, EGLint val)
{
// look for the attribute in all of our configs
- config_pair_t const* configFound = gConfigs[i].array;
+ config_pair_t const* configFound = gConfigs[i].array;
int index = binarySearch<config_pair_t>(
gConfigs[i].array,
0, gConfigs[i].size-1,
attr);
if (index < 0) {
- configFound = config_base_attribute_list;
+ configFound = config_base_attribute_list;
index = binarySearch<config_pair_t>(
config_base_attribute_list,
0, NELEM(config_base_attribute_list)-1,
@@ -787,38 +1300,18 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
if (!(surfaceType & EGL_WINDOW_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<android_native_window_t*>(window)->common.magic !=
+ ANDROID_NATIVE_WINDOW_MAGIC) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
int32_t depthFormat;
int32_t pixelFormat;
- switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = 0;
- break;
- case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = 0;
- break;
- case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- default:
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
@@ -828,11 +1321,11 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
//if (EGLint(info.format) != pixelFormat)
// return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- egl_surface_t* surface =
- new egl_window_surface_t(dpy, config, depthFormat,
- static_cast<egl_native_window_t*>(window));
+ egl_surface_t* surface;
+ surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
+ static_cast<android_native_window_t*>(window));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -856,38 +1349,18 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
if (!(surfaceType & EGL_PIXMAP_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
+ sizeof(egl_native_pixmap_t)) {
+ return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
int32_t depthFormat;
int32_t pixelFormat;
- switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = 0;
- break;
- case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = 0;
- break;
- case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- default:
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
@@ -898,7 +1371,7 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
new egl_pixmap_surface_t(dpy, config, depthFormat,
static_cast<egl_native_pixmap_t*>(pixmap));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -916,42 +1389,17 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
EGLint surfaceType;
if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
return EGL_FALSE;
-
+
if (!(surfaceType & EGL_PBUFFER_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
int32_t depthFormat;
int32_t pixelFormat;
- switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = 0;
- break;
- case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = 0;
- break;
- case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- default:
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
@@ -966,7 +1414,7 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
egl_surface_t* surface =
new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -1001,7 +1449,7 @@ EGLDisplay eglGetDisplay(NativeDisplayType display)
egl_display_t& d = egl_display_t::get_display(dpy);
d.type = display;
return dpy;
- }
+ }
return EGL_NO_DISPLAY;
}
@@ -1009,10 +1457,10 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
EGLBoolean res = EGL_TRUE;
egl_display_t& d = egl_display_t::get_display(dpy);
-
+
if (android_atomic_inc(&d.initialized) == 0) {
// initialize stuff here if needed
//pthread_mutex_lock(&gInitMutex);
@@ -1080,7 +1528,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
*num_config = 0;
return EGL_TRUE;
}
-
+
int numAttributes = 0;
int numConfigs = NELEM(gConfigs);
uint32_t possibleMatch = (1<<numConfigs)-1;
@@ -1088,7 +1536,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
numAttributes++;
EGLint attr = *attrib_list++;
EGLint val = *attrib_list++;
- for (int i=0 ; i<numConfigs ; i++) {
+ for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
if (!(possibleMatch & (1<<i)))
continue;
if (isAttributeMatching(i, attr, val) == 0) {
@@ -1098,15 +1546,15 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
}
// now, handle the attributes which have a useful default value
- for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
- // see if this attribute was specified, if not apply its
+ for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
+ // see if this attribute was specified, if not, apply its
// default value
if (binarySearch<config_pair_t>(
(config_pair_t const*)attrib_list,
0, numAttributes-1,
config_defaults[j].key) < 0)
{
- for (int i=0 ; i<numConfigs ; i++) {
+ for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
if (!(possibleMatch & (1<<i)))
continue;
if (isAttributeMatching(i,
@@ -1161,7 +1609,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
{
return createWindowSurface(dpy, config, window, attrib_list);
}
-
+
EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
NativePixmapType pixmap,
const EGLint *attrib_list)
@@ -1174,17 +1622,22 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
{
return createPbufferSurface(dpy, config, attrib_list);
}
-
+
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (eglSurface != EGL_NO_SURFACE) {
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
- if (surface->magic != egl_surface_t::MAGIC)
+ if (!surface->isValid())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (surface->ctx) {
+ // FIXME: this surface is current check what the spec says
+ surface->disconnect();
+ surface->ctx = 0;
+ }
delete surface;
}
return EGL_TRUE;
@@ -1196,6 +1649,8 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (!surface->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1244,7 +1699,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
*value = (wr * EGL_DISPLAY_SCALING) / hr;
} break;
case EGL_SWAP_BEHAVIOR:
- *value = surface->getSwapBehavior();
+ *value = surface->getSwapBehavior();
break;
default:
ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
@@ -1288,13 +1743,23 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (draw) {
egl_surface_t* s = (egl_surface_t*)draw;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (s->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that draw and read are compatible with the context
+ // TODO: check that draw is compatible with the context
+ }
+ if (read && read!=draw) {
+ egl_surface_t* s = (egl_surface_t*)read;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that read is compatible with the context
}
EGLContext current_ctx = EGL_NO_CONTEXT;
-
+
if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
return setError(EGL_BAD_MATCH, EGL_FALSE);
@@ -1310,21 +1775,29 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
egl_surface_t* r = (egl_surface_t*)read;
if ((d && d->ctx && d->ctx != ctx) ||
(r && r->ctx && r->ctx != ctx)) {
- // once of the surface is bound to a context in another thread
+ // one of the surface is bound to a context in another thread
return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
}
- // TODO: call connect / disconnect on the surface
-
ogles_context_t* gl = (ogles_context_t*)ctx;
if (makeCurrent(gl) == 0) {
if (ctx) {
egl_context_t* c = egl_context_t::context(ctx);
egl_surface_t* d = (egl_surface_t*)draw;
egl_surface_t* r = (egl_surface_t*)read;
- c->read = read;
+
+ if (c->draw) {
+ egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
+ s->disconnect();
+ }
+ if (c->read) {
+ // FIXME: unlock/disconnect the read surface too
+ }
+
c->draw = draw;
+ c->read = read;
+
if (c->flags & egl_context_t::NEVER_CURRENT) {
c->flags &= ~egl_context_t::NEVER_CURRENT;
GLint w = 0;
@@ -1338,10 +1811,14 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
ogles_scissor(gl, 0, 0, w, h);
}
if (d) {
+ if (d->connect() == EGL_FALSE) {
+ return EGL_FALSE;
+ }
d->ctx = ctx;
d->bindDrawSurface(gl);
}
if (r) {
+ // FIXME: lock/connect the read surface too
r->ctx = ctx;
r->bindReadSurface(gl);
}
@@ -1352,8 +1829,16 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
egl_context_t* c = egl_context_t::context(current_ctx);
egl_surface_t* d = (egl_surface_t*)c->draw;
egl_surface_t* r = (egl_surface_t*)c->read;
- if (d) d->ctx = EGL_NO_CONTEXT;
- if (r) r->ctx = EGL_NO_CONTEXT;
+ if (d) {
+ c->draw = 0;
+ d->ctx = EGL_NO_CONTEXT;
+ d->disconnect();
+ }
+ if (r) {
+ c->read = 0;
+ r->ctx = EGL_NO_CONTEXT;
+ // FIXME: unlock/disconnect the read surface too
+ }
}
}
return EGL_TRUE;
@@ -1425,8 +1910,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1558,7 +2045,7 @@ EGLSurface eglCreatePbufferFromClientBuffer(
}
// ----------------------------------------------------------------------------
-// Android extensions
+// EGL_EGLEXT_VERSION 3
// ----------------------------------------------------------------------------
void (*eglGetProcAddress (const char *procname))()
@@ -1571,3 +2058,97 @@ void (*eglGetProcAddress (const char *procname))()
}
return NULL;
}
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ if (ctx != EGL_NO_CONTEXT) {
+ return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ }
+ if (target != EGL_NATIVE_BUFFER_ANDROID) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ native_buffer->common.incRef(&native_buffer->common);
+ return (EGLImageKHR)native_buffer;
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ native_buffer->common.decRef(&native_buffer->common);
+
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // post the surface
+ d->setSwapRectangle(left, top, width, height);
+
+ return EGL_TRUE;
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ // post the surface
+ return d->getRenderBuffer();
+}
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index 8ae32cc..f211bca 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -216,6 +216,8 @@ static inline void light_picker(ogles_context_t* c)
static inline void validate_light_mvi(ogles_context_t* c)
{
uint32_t en = c->lighting.enabledLights;
+ // Vector from object to viewer, in eye coordinates
+ const vec4_t eyeViewer = { 0, 0, 0x1000, 0 };
while (en) {
const int i = 31 - gglClz(en);
en &= ~(1<<i);
@@ -223,6 +225,9 @@ static inline void validate_light_mvi(ogles_context_t* c)
c->transforms.mvui.point4(&c->transforms.mvui,
&l.objPosition, &l.position);
vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+ c->transforms.mvui.point4(&c->transforms.mvui,
+ &l.objViewer, &eyeViewer);
+ vnorm3(l.objViewer.v, l.objViewer.v);
}
}
@@ -379,9 +384,9 @@ void lightVertex(ogles_context_t* c, vertex_t* v)
// specular
if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
vec4_t h;
- h.x = d.x;
- h.y = d.y;
- h.z = d.z + 0x10000;
+ h.x = d.x + l.objViewer.x;
+ h.y = d.y + l.objViewer.y;
+ h.z = d.z + l.objViewer.z;
vnorm3(h.v, h.v);
s = dot3(n.v, h.v);
s = (s<0) ? (twoSide?(-s):0) : s;
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index 0b68dc0..3c50977 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -696,6 +696,8 @@ void ogles_viewport(ogles_context_t* c,
f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
c->transforms.dirty |= transform_state_t::VIEWPORT;
+ if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)
+ c->transforms.dirty |= transform_state_t::MVP;
}
// ----------------------------------------------------------------------------
@@ -739,20 +741,19 @@ void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
// this used for transforming light positions back to object space.
- // Lights have 3 components positions, so w is always 1.
- // however, it is used as a switch for directional lights, so we need
+ // w is used as a switch for directional lights, so we need
// to preserve it.
const GLfixed* const m = mx->matrix.m;
const GLfixed rx = rhs->x;
const GLfixed ry = rhs->y;
const GLfixed rz = rhs->z;
- lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
- lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
- lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
- lhs->w = rhs->w;
+ const GLfixed rw = rhs->w;
+ lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);
+ lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
+ lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
+ lhs->w = rw;
}
-
void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
lhs->z = 0;
lhs->w = 0x10000;
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index f164c02..769ec40 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -369,7 +369,7 @@ void compute_iterators_t::iterators0032(int32_t* it,
int32_t c0, int32_t c1, int32_t c2) const
{
int64_t it64[3];
- iterators0032(it, c0, c1, c2);
+ iterators0032(it64, c0, c1, c2);
it[0] = it64[0];
it[1] = it64[1];
it[2] = it64[2];
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 5cbabea..a59b3b0 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -2,16 +2,16 @@
**
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -28,12 +28,16 @@
#include "BufferObjectManager.h"
#include "TextureObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include <hardware/copybit.h>
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
static char const * const gVendorString = "Android";
-static char const * const gRendererString = "Android PixelFlinger 1.0";
+static char const * const gRendererString = "Android PixelFlinger 1.1";
static char const * const gVersionString = "OpenGL ES-CM 1.0";
static char const * const gExtensionsString =
"GL_OES_byte_coordinates " // OK
@@ -46,9 +50,9 @@ static char const * const gExtensionsString =
"GL_OES_query_matrix " // OK
// "GL_OES_point_size_array " // TODO
// "GL_OES_point_sprite " // TODO
+ "GL_OES_EGL_image " // OK
"GL_ARB_texture_compression " // OK
"GL_ARB_texture_non_power_of_two " // OK
- "GL_ANDROID_direct_texture " // OK
"GL_ANDROID_user_clip_plane " // OK
"GL_ANDROID_vertex_buffer_object " // OK
"GL_ANDROID_generate_mipmap " // OK
@@ -62,13 +66,13 @@ static char const * const gExtensionsString =
ogles_context_t *ogles_init(size_t extra)
{
void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
- if (!base) return 0;
+ if (!base) return 0;
ogles_context_t *c =
(ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
memset(c, 0, sizeof(ogles_context_t));
ggl_init_context(&(c->rasterizer));
-
+
// XXX: this should be passed as an argument
sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
c->surfaceManager = smgr.get();
@@ -87,13 +91,42 @@ ogles_context_t *ogles_init(size_t extra)
c->rasterizer.base = base;
c->point.size = TRI_ONE;
c->line.width = TRI_ONE;
-
+
// in OpenGL, writing to the depth buffer is enabled by default.
c->rasterizer.procs.depthMask(c, 1);
-
+
// OpenGL enables dithering by default
c->rasterizer.procs.enable(c, GL_DITHER);
+ c->copybits.blitEngine = NULL;
+ c->copybits.minScale = 0;
+ c->copybits.maxScale = 0;
+ c->copybits.drawSurfaceBuffer = 0;
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ hw_module_t const* module;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ struct copybit_device_t* copyBits;
+ if (copybit_open(module, &copyBits) == 0) {
+ c->copybits.blitEngine = copyBits;
+ {
+ int minLim = copyBits->get(copyBits,
+ COPYBIT_MINIFICATION_LIMIT);
+ if (minLim != -EINVAL && minLim > 0) {
+ c->copybits.minScale = (1 << 16) / minLim;
+ }
+ }
+ {
+ int magLim = copyBits->get(copyBits,
+ COPYBIT_MAGNIFICATION_LIMIT);
+ if (magLim != -EINVAL && magLim > 0) {
+ c->copybits.maxScale = min(32*1024-1, magLim) << 16;
+ }
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return c;
}
@@ -107,7 +140,12 @@ void ogles_uninit(ogles_context_t* c)
c->surfaceManager->decStrong(c);
c->bufferObjectManager->decStrong(c);
ggl_uninit_context(&(c->rasterizer));
- free(c->rasterizer.base);
+ free(c->rasterizer.base);
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (c->copybits.blitEngine != NULL) {
+ copybit_close((struct copybit_device_t*) c->copybits.blitEngine);
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
}
void _ogles_error(ogles_context_t* c, GLenum error)
@@ -188,7 +226,7 @@ static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
// these need to fall through into the rasterizer
c->rasterizer.procs.enableDisable(c, cap, enabled);
break;
-
+
case GL_MULTISAMPLE:
case GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL_SAMPLE_ALPHA_TO_ONE:
@@ -281,7 +319,7 @@ void glHint(GLenum target, GLenum mode)
case GL_LINE_SMOOTH_HINT:
break;
case GL_POINT_SMOOTH_HINT:
- c->rasterizer.procs.enableDisable(c,
+ c->rasterizer.procs.enableDisable(c,
GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
break;
case GL_PERSPECTIVE_CORRECTION_HINT:
@@ -323,7 +361,7 @@ GLenum glGetError()
c->error = 0;
return ret;
}
-
+
if (c->rasterizer.error) {
const GLenum ret(c->rasterizer.error);
c->rasterizer.error = 0;
@@ -362,25 +400,25 @@ void glGetIntegerv(GLenum pname, GLint *params)
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].ah - formats[index].al;
- break;
+ break;
}
case GL_RED_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].rh - formats[index].rl;
- break;
+ break;
}
case GL_GREEN_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].gh - formats[index].gl;
- break;
+ break;
}
case GL_BLUE_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].bh - formats[index].bl;
- break;
+ break;
}
case GL_COMPRESSED_TEXTURE_FORMATS:
params[ 0] = GL_PALETTE4_RGB8_OES;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 14a910c..13d078e 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -2,16 +2,16 @@
**
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -23,6 +23,12 @@
#include "texture.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
@@ -48,7 +54,7 @@ void ogles_init_texture(ogles_context_t* c)
// each context has a default named (0) texture (not shared)
c->textures.defaultTexture = new EGLTextureObject();
c->textures.defaultTexture->incStrong(c);
-
+
// bind the default texture to each texture unit
for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
bindTextureTmu(c, i, 0, c->textures.defaultTexture);
@@ -96,7 +102,7 @@ void validate_tmu(ogles_context_t* c, int i)
}
}
-void ogles_validate_texture_impl(ogles_context_t* c)
+void ogles_validate_texture(ogles_context_t* c)
{
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable)
@@ -110,6 +116,66 @@ void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
c->textures.tmu[tmu].dirty = flags;
}
+/*
+ * If the active textures are EGLImage, they need to be locked before
+ * they can be used.
+ *
+ * FIXME: code below is far from being optimal
+ *
+ */
+
+void ogles_lock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ void* vaddr;
+ int err = module->lock(module, native_buffer->handle,
+ GRALLOC_USAGE_SW_READ_OFTEN,
+ 0, 0, native_buffer->width, native_buffer->height,
+ &vaddr);
+
+ u.texture->setImageBits(vaddr);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+}
+
+void ogles_unlock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ module->unlock(module, native_buffer->handle);
+ u.texture->setImageBits(NULL);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
@@ -255,7 +321,7 @@ sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
u.texture->decStrong(c);
if (name == 0) {
- // 0 is our local texture object, not shared with anyone.
+ // 0 is our local texture object, not shared with anyone.
// But it affects all bound TMUs immediately.
// (we need to invalidate all units bound to this texture object)
tex = c->textures.defaultTexture;
@@ -273,7 +339,7 @@ sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
u.texture = tex.get();
u.texture->incStrong(c);
u.name = name;
- invalidate_texture(c, active);
+ invalidate_texture(c, active);
return tex;
}
@@ -282,7 +348,7 @@ void bindTextureTmu(
{
if (tex.get() == c->textures.tmu[tmu].texture)
return;
-
+
// free the reference to the previously bound object
texture_unit_t& u(c->textures.tmu[tmu]);
if (u.texture)
@@ -310,7 +376,7 @@ int createTextureSurface(ogles_context_t* c,
if (formatIdx == 0) { // we don't know what to do with this
return GL_INVALID_OPERATION;
}
-
+
// figure out the size we need as well as the stride
const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
const int32_t align = c->textures.unpackAlignment-1;
@@ -343,6 +409,49 @@ int createTextureSurface(ogles_context_t* c,
return 0;
}
+static size_t dataSizePalette4(int numLevels, int width, int height, int format)
+{
+ int indexBits = 8;
+ int entrySize = 0;
+ switch (format) {
+ case GL_PALETTE4_RGB8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGB8_OES:
+ entrySize = 3;
+ break;
+
+ case GL_PALETTE4_RGBA8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGBA8_OES:
+ entrySize = 4;
+ break;
+
+ case GL_PALETTE4_R5_G6_B5_OES:
+ case GL_PALETTE4_RGBA4_OES:
+ case GL_PALETTE4_RGB5_A1_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_R5_G6_B5_OES:
+ case GL_PALETTE8_RGBA4_OES:
+ case GL_PALETTE8_RGB5_A1_OES:
+ entrySize = 2;
+ break;
+ }
+
+ size_t size = (1 << indexBits) * entrySize; // palette size
+
+ for (int i=0 ; i< numLevels ; i++) {
+ int w = (width >> i) ? : 1;
+ int h = (height >> i) ? : 1;
+ int levelSize = h * ((w * indexBits) / 8) ? : 1;
+ size += levelSize;
+ }
+
+ return size;
+}
+
static void decodePalette4(const GLvoid *data, int level, int width, int height,
void *surface, int stride, int format)
@@ -377,6 +486,7 @@ static void decodePalette4(const GLvoid *data, int level, int width, int height,
}
const int paletteSize = (1 << indexBits) * entrySize;
+
uint8_t const* pixels = (uint8_t *)data + paletteSize;
for (int i=0 ; i<level ; i++) {
int w = (width >> i) ? : 1;
@@ -530,8 +640,8 @@ static void texParameterx(
ogles_error(c, GL_INVALID_ENUM);
return;
}
-
- EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
switch (pname) {
case GL_TEXTURE_WRAP_S:
if ((param == GL_REPEAT) ||
@@ -581,12 +691,11 @@ invalid_enum:
}
-static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+
+static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
ogles_context_t* c)
{
- // quickly reject empty rects
- if ((w|h) <= 0)
- return;
+ ogles_lock_textures(c);
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = gglIntToFixed(cbSurface.height) - (y + h);
@@ -610,7 +719,7 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
u.dirty = 0xFF; // XXX: should be more subtle
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Ucr = textureObject->crop_rect[0] << 16;
const GLint Vcr = textureObject->crop_rect[1] << 16;
const GLint Wcr = textureObject->crop_rect[2] << 16;
@@ -641,11 +750,30 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
c->rasterizer.procs.disable(c, GGL_W_LERP);
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
- c->rasterizer.procs.recti(c,
+ c->rasterizer.procs.recti(c,
gglFixedToIntRound(x),
gglFixedToIntRound(y),
gglFixedToIntRound(x)+w,
gglFixedToIntRound(y)+h);
+
+ ogles_unlock_textures(c);
+}
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+ ogles_context_t* c)
+{
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
+ gglFixedToIntRound(y), gglFixedToIntRound(z),
+ gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
+ return;
+ }
+#else
+ // quickly reject empty rects
+ if ((w|h) <= 0)
+ return;
+#endif
+ drawTexxOESImp(x, y, z, w, h, c);
}
static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
@@ -656,14 +784,21 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
// which is a lot faster.
if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
+ return;
+ }
+#endif
const int tmu = 0;
texture_unit_t& u(c->textures.tmu[tmu]);
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Wcr = textureObject->crop_rect[2];
const GLint Hcr = textureObject->crop_rect[3];
if ((w == Wcr) && (h == -Hcr)) {
+#ifndef LIBAGL_USE_GRALLOC_COPYBITS
if ((w|h) <= 0) return; // quickly reject empty rects
+#endif
if (u.dirty) {
c->rasterizer.procs.activeTexture(c, tmu);
@@ -679,14 +814,14 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
u.dirty = 0xFF; // XXX: should be more subtle
c->rasterizer.procs.activeTexture(c, c->textures.active);
-
+
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = cbSurface.height - (y + h);
const GLint Ucr = textureObject->crop_rect[0];
const GLint Vcr = textureObject->crop_rect[1];
const GLint s0 = Ucr - x;
const GLint t0 = (Vcr + Hcr) - y;
-
+
const GLuint tw = textureObject->surface.width;
const GLuint th = textureObject->surface.height;
if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
@@ -694,7 +829,9 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
// in this case, so we just use the slow case, which
// at least won't crash
goto slow_case;
- }
+ }
+
+ ogles_lock_textures(c);
c->rasterizer.procs.texCoord2i(c, s0, t0);
const uint32_t enables = c->rasterizer.state.enables;
@@ -706,12 +843,15 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+
+ ogles_unlock_textures(c);
+
return;
}
}
slow_case:
- drawTexxOES(
+ drawTexxOESImp(
gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
gglIntToFixed(w), gglIntToFixed(h),
c);
@@ -749,7 +889,7 @@ void glBindTexture(GLenum target, GLuint texture)
}
// Bind or create a texture
- sp<EGLTextureObject> tex;
+ sp<EGLTextureObject> tex;
if (texture == 0) {
// 0 is our local texture object
tex = c->textures.defaultTexture;
@@ -837,7 +977,7 @@ void glPixelStorei(GLenum pname, GLint param)
if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
ogles_error(c, GL_INVALID_ENUM);
return;
- }
+ }
if ((param<=0 || param>8) || (param & (param-1))) {
ogles_error(c, GL_INVALID_VALUE);
return;
@@ -952,7 +1092,7 @@ void glCompressedTexImage2D(
}
// "uncompress" the texture since pixelflinger doesn't support
- // any compressed texture format natively.
+ // any compressed texture format natively.
GLenum format;
GLenum type;
switch (internalformat) {
@@ -995,6 +1135,12 @@ void glCompressedTexImage2D(
GGLSurface* surface;
// all mipmap levels are specified at once.
const int numLevels = level<0 ? -level : 1;
+
+ if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
for (int i=0 ; i<numLevels ; i++) {
int lod_w = (width >> i) ? : 1;
int lod_h = (height >> i) ? : 1;
@@ -1016,7 +1162,7 @@ void glTexImage2D(
GLenum format, GLenum type, const GLvoid *pixels)
{
ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ if (target != GL_TEXTURE_2D) {
ogles_error(c, GL_INVALID_ENUM);
return;
}
@@ -1024,7 +1170,7 @@ void glTexImage2D(
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (format != internalformat) {
+ if (format != (GLenum)internalformat) {
ogles_error(c, GL_INVALID_OPERATION);
return;
}
@@ -1034,16 +1180,10 @@ void glTexImage2D(
int32_t size = 0;
GGLSurface* surface = 0;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
- } else if (pixels == 0 || level != 0) {
- // pixel can't be null for direct texture
- ogles_error(c, GL_INVALID_OPERATION);
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
return;
}
@@ -1064,18 +1204,12 @@ void glTexImage2D(
userSurface.compressedFormat = 0;
userSurface.data = (GLubyte*)pixels;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
- generateMipmap(c, level);
- } else {
- // bind it to the texture unit
- sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
- tex->setSurface(&userSurface);
+ int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
}
+ generateMipmap(c, level);
}
}
@@ -1118,6 +1252,11 @@ void glTexSubImage2D(
ogles_error(c, GL_INVALID_OPERATION);
return;
}
+
+ if (format != tex->internalformat) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
if ((xoffset + width > GLsizei(surface.width)) ||
(yoffset + height > GLsizei(surface.height))) {
ogles_error(c, GL_INVALID_VALUE);
@@ -1150,7 +1289,7 @@ void glTexSubImage2D(
int err = copyPixels(c,
surface, xoffset, yoffset,
- userSurface, 0, 0, width, height);
+ userSurface, 0, 0, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1203,7 +1342,7 @@ void glCopyTexImage2D(
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE:
type = GL_UNSIGNED_BYTE;
- break;
+ break;
}
// figure out the format to use for the new texture
@@ -1213,7 +1352,7 @@ void glCopyTexImage2D(
case GGL_PIXEL_FORMAT_RGBA_5551:
case GGL_PIXEL_FORMAT_RGBA_4444:
format = internalformat;
- break;
+ break;
case GGL_PIXEL_FORMAT_RGBX_8888:
case GGL_PIXEL_FORMAT_RGB_888:
case GGL_PIXEL_FORMAT_RGB_565:
@@ -1222,7 +1361,7 @@ void glCopyTexImage2D(
case GL_LUMINANCE:
case GL_RGB:
format = internalformat;
- break;
+ break;
}
break;
}
@@ -1242,7 +1381,7 @@ void glCopyTexImage2D(
ogles_error(c, error);
return;
}
-
+
// The bottom row is stored first in textures
GGLSurface txSurface(*surface);
txSurface.stride = -txSurface.stride;
@@ -1252,7 +1391,7 @@ void glCopyTexImage2D(
int err = copyPixels(c,
txSurface, 0, 0,
- cbSurface, x, y, cbSurface.width, cbSurface.height);
+ cbSurface, x, y, cbSurface.width, cbSurface.height);
if (err) {
ogles_error(c, err);
}
@@ -1302,7 +1441,7 @@ void glCopyTexSubImage2D(
int err = copyPixels(c,
surface, xoffset, yoffset,
- cbSurface, x, y, width, height);
+ cbSurface, x, y, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1372,7 +1511,7 @@ void glReadPixels(
return;
}
- ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
+ ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
ggl->bindTexture(ggl, &readSurface); // source is read-buffer
ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
ggl->recti(ggl, 0, 0, width, height);
@@ -1426,3 +1565,43 @@ void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
ogles_context_t* c = ogles_context_t::get();
drawTexxOES(x, y, z, w, h, c);
}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark EGL Image Extension
+#endif
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // bind it to the texture unit
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ tex->setImage(native_buffer);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ tex->try_copybit = false;
+ if (c->copybits.blitEngine != NULL) {
+ tex->try_copybit = true;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
index 5c57948..98f7550 100644
--- a/opengl/libagl/texture.h
+++ b/opengl/libagl/texture.h
@@ -32,13 +32,9 @@ namespace android {
void ogles_init_texture(ogles_context_t* c);
void ogles_uninit_texture(ogles_context_t* c);
-void ogles_validate_texture_impl(ogles_context_t* c);
-
-inline void ogles_validate_texture(ogles_context_t* c) {
- if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
- ogles_validate_texture_impl(c);
-}
-
+void ogles_validate_texture(ogles_context_t* c);
+void ogles_lock_textures(ogles_context_t* c);
+void ogles_unlock_textures(ogles_context_t* c);
}; // namespace android
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 23304d5..6d20e80 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -1,17 +1,18 @@
LOCAL_PATH:= $(call my-dir)
-#
+###############################################################################
# Build META EGL library
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- EGL/egl.cpp \
- EGL/gpu.cpp \
+ EGL/egl.cpp \
+ EGL/hooks.cpp \
+ EGL/Loader.cpp \
#
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_SHARED_LIBRARIES += libcutils libutils
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
@@ -19,24 +20,50 @@ LOCAL_MODULE:= libEGL
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
+LOCAL_CFLAGS += -DADRENO130=1
+endif
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
include $(BUILD_SHARED_LIBRARY)
+installed_libEGL := $(LOCAL_INSTALLED_MODULE)
+# OpenGL drivers config file
+ifneq ($(BOARD_EGL_CFG),)
-#
-# Build the wrapper OpenGL ES library
+include $(CLEAR_VARS)
+LOCAL_MODULE := egl.cfg
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
+LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
+include $(BUILD_PREBUILT)
+
+# make sure we depend on egl.cfg, so it gets installed
+$(installed_libEGL): | egl.cfg
+
+endif
+
+###############################################################################
+# Build the wrapper OpenGL ES 1.x library
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- GLES_CM/gl.cpp.arm \
+LOCAL_SRC_FILES:= \
+ GLES_CM/gl.cpp.arm \
#
LOCAL_SHARED_LIBRARIES += libcutils libEGL
@@ -47,10 +74,49 @@ LOCAL_MODULE:= libGLESv1_CM
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+###############################################################################
+# Build the wrapper OpenGL ES 2.x library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ GLES2/gl2.cpp.arm \
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libEGL
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLESv2
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
new file mode 100644
index 0000000..5d6ac26
--- /dev/null
+++ b/opengl/libs/EGL/Loader.cpp
@@ -0,0 +1,287 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+#include "Loader.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * EGL drivers are called
+ *
+ * /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so
+ *
+ */
+
+ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+
+// ----------------------------------------------------------------------------
+
+Loader::driver_t::driver_t(void* gles)
+{
+ dso[0] = gles;
+ for (size_t i=1 ; i<NELEM(dso) ; i++)
+ dso[i] = 0;
+}
+
+Loader::driver_t::~driver_t()
+{
+ for (size_t i=0 ; i<NELEM(dso) ; i++) {
+ if (dso[i]) {
+ dlclose(dso[i]);
+ dso[i] = 0;
+ }
+ }
+}
+
+status_t Loader::driver_t::set(void* hnd, int32_t api)
+{
+ switch (api) {
+ case EGL:
+ dso[0] = hnd;
+ break;
+ case GLESv1_CM:
+ dso[1] = hnd;
+ break;
+ case GLESv2:
+ dso[2] = hnd;
+ break;
+ default:
+ return BAD_INDEX;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
+ : dpy(dpy), impl(impl), tag(tag) {
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::Loader()
+{
+ char line[256];
+ char tag[256];
+ FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
+ if (cfg == NULL) {
+ // default config
+ LOGD("egl.cfg not found, using default config");
+ gConfig.add( entry_t(0, 0, "android") );
+ } else {
+ while (fgets(line, 256, cfg)) {
+ int dpy;
+ int impl;
+ if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
+ //LOGD(">>> %u %u %s", dpy, impl, tag);
+ gConfig.add( entry_t(dpy, impl, tag) );
+ }
+ }
+ fclose(cfg);
+ }
+}
+
+Loader::~Loader()
+{
+}
+
+const char* Loader::getTag(int dpy, int impl)
+{
+ const Vector<entry_t>& cfgs(gConfig);
+ const size_t c = cfgs.size();
+ for (size_t i=0 ; i<c ; i++) {
+ if (dpy == cfgs[i].dpy)
+ if (impl == cfgs[i].impl)
+ return cfgs[i].tag.string();
+ }
+ return 0;
+}
+
+void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx)
+{
+ /*
+ * TODO: if we don't find display/0, then use 0/0
+ * (0/0 should always work)
+ */
+
+ void* dso;
+ char path[PATH_MAX];
+ int index = int(display);
+ driver_t* hnd = 0;
+ const char* const format = "/system/lib/egl/lib%s_%s.so";
+
+ char const* tag = getTag(index, impl);
+ if (tag) {
+ snprintf(path, PATH_MAX, format, "GLES", tag);
+ dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
+ if (dso) {
+ hnd = new driver_t(dso);
+ } else {
+ // Always load EGL first
+ snprintf(path, PATH_MAX, format, "EGL", tag);
+ dso = load_driver(path, cnx, EGL);
+ if (dso) {
+ hnd = new driver_t(dso);
+
+ // TODO: make this more automated
+ snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
+ hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM );
+
+ snprintf(path, PATH_MAX, format, "GLESv2", tag);
+ hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
+ }
+ }
+ }
+
+ LOG_FATAL_IF(!index && !impl && !hnd,
+ "couldn't find the default OpenGL ES implementation "
+ "for default display");
+
+ return (void*)hnd;
+}
+
+status_t Loader::close(void* driver)
+{
+ driver_t* hnd = (driver_t*)driver;
+ delete hnd;
+ return NO_ERROR;
+}
+
+void Loader::init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress)
+{
+ char scrap[256];
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ }
+ if (f == NULL) {
+ // Try without the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ // Try with the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ strcat(scrap, "OES");
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ //LOGD("%s", name);
+ f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+ }
+ *curr++ = f;
+ api++;
+ }
+}
+
+void *Loader::load_driver(const char* driver_absolute_path,
+ egl_connection_t* cnx, uint32_t mask)
+{
+ if (access(driver_absolute_path, R_OK)) {
+ // this happens often, we don't want to log an error
+ return 0;
+ }
+
+ void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
+ if (dso == 0) {
+ const char* err = dlerror();
+ LOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+ return 0;
+ }
+
+ LOGD("loaded %s", driver_absolute_path);
+
+ if (mask & EGL) {
+ getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+
+ LOGE_IF(!getProcAddress,
+ "can't find eglGetProcAddress() in %s", driver_absolute_path);
+
+ egl_t* egl = &cnx->egl;
+ __eglMustCastToProperFunctionPointerType* curr =
+ (__eglMustCastToProperFunctionPointerType*)egl;
+ char const * const * api = egl_names;
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ if (f == NULL) {
+ f = (__eglMustCastToProperFunctionPointerType)0;
+ }
+ }
+ *curr++ = f;
+ api++;
+ }
+ }
+
+ if (mask & GLESv1_CM) {
+ init_api(dso, gl_names,
+ (__eglMustCastToProperFunctionPointerType*)
+ &cnx->hooks[GLESv1_INDEX]->gl,
+ getProcAddress);
+ }
+
+ if (mask & GLESv2) {
+ init_api(dso, gl_names,
+ (__eglMustCastToProperFunctionPointerType*)
+ &cnx->hooks[GLESv2_INDEX]->gl,
+ getProcAddress);
+ }
+
+ return dso;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
new file mode 100644
index 0000000..8659b0b
--- /dev/null
+++ b/opengl/libs/EGL/Loader.h
@@ -0,0 +1,90 @@
+/*
+ ** 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_EGL_LOADER_H
+#define ANDROID_EGL_LOADER_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct egl_connection_t;
+
+class Loader : public Singleton<Loader>
+{
+ friend class Singleton<Loader>;
+
+ typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
+ const char*);
+
+ enum {
+ EGL = 0x01,
+ GLESv1_CM = 0x02,
+ GLESv2 = 0x04
+ };
+ struct driver_t {
+ driver_t(void* gles);
+ ~driver_t();
+ status_t set(void* hnd, int32_t api);
+ void* dso[3];
+ };
+
+ struct entry_t {
+ entry_t() { }
+ entry_t(int dpy, int impl, const char* tag);
+ int dpy;
+ int impl;
+ String8 tag;
+ };
+
+ Vector<entry_t> gConfig;
+ getProcAddressType getProcAddress;
+
+ const char* getTag(int dpy, int impl);
+
+public:
+ ~Loader();
+
+ void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx);
+ status_t close(void* driver);
+
+private:
+ Loader();
+ void *load_driver(const char* driver, egl_connection_t* cnx, uint32_t mask);
+
+ static __attribute__((noinline))
+ void init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_LOADER_H */
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index c6e0f50..c22c21b 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -14,9 +14,8 @@
** limitations under the License.
*/
-#define LOG_TAG "libEGL"
-
#include <ctype.h>
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
@@ -37,11 +36,11 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
-#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
#include "hooks.h"
#include "egl_impl.h"
-
+#include "Loader.h"
#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -53,64 +52,152 @@ namespace android {
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
static char const * const gVendorString = "Android";
-static char const * const gVersionString = "1.31 Android META-EGL";
+static char const * const gVersionString = "1.4 Android META-EGL";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionString = "";
+static char const * const gExtensionString =
+ "EGL_KHR_image "
+ "EGL_KHR_image_base "
+ "EGL_KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
+
+// ----------------------------------------------------------------------------
+
+class egl_object_t {
+ static SortedVector<egl_object_t*> sObjects;
+ static Mutex sLock;
+
+ volatile int32_t terminated;
+ mutable volatile int32_t count;
+
+public:
+ egl_object_t() : terminated(0), count(1) {
+ Mutex::Autolock _l(sLock);
+ sObjects.add(this);
+ }
+
+ inline bool isAlive() const { return !terminated; }
-template <int MAGIC>
-struct egl_object_t
-{
- egl_object_t() : magic(MAGIC) { }
- ~egl_object_t() { magic = 0; }
- bool isValid() const { return magic == MAGIC; }
private:
- uint32_t magic;
+ bool get() {
+ Mutex::Autolock _l(sLock);
+ if (egl_object_t::sObjects.indexOf(this) >= 0) {
+ android_atomic_inc(&count);
+ return true;
+ }
+ return false;
+ }
+
+ bool put() {
+ Mutex::Autolock _l(sLock);
+ if (android_atomic_dec(&count) == 1) {
+ sObjects.remove(this);
+ return true;
+ }
+ return false;
+ }
+
+public:
+ template <typename N, typename T>
+ struct LocalRef {
+ N* ref;
+ LocalRef(T o) : ref(0) {
+ N* native = reinterpret_cast<N*>(o);
+ if (o && native->get()) {
+ ref = native;
+ }
+ }
+ ~LocalRef() {
+ if (ref && ref->put()) {
+ delete ref;
+ }
+ }
+ inline N* get() {
+ return ref;
+ }
+ void acquire() const {
+ if (ref) {
+ android_atomic_inc(&ref->count);
+ }
+ }
+ void release() const {
+ if (ref) {
+ int32_t c = android_atomic_dec(&ref->count);
+ // ref->count cannot be 1 prior atomic_dec because we have
+ // a reference, and if we have one, it means there was
+ // already one before us.
+ LOGE_IF(c==1, "refcount is now 0 in release()");
+ }
+ }
+ void terminate() {
+ if (ref) {
+ ref->terminated = 1;
+ release();
+ }
+ }
+ };
};
-struct egl_display_t : public egl_object_t<'_dpy'>
-{
- EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- char const* extensionsString;
- volatile int32_t refs;
+SortedVector<egl_object_t*> egl_object_t::sObjects;
+Mutex egl_object_t::sLock;
+
+struct egl_display_t {
+ enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
+
struct strings_t {
char const * vendor;
char const * version;
char const * clientApi;
char const * extensions;
};
- strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+
+ struct DisplayImpl {
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+ state(NOT_INITIALIZED), numConfigs(0) { }
+ EGLDisplay dpy;
+ EGLConfig* config;
+ EGLint state;
+ EGLint numConfigs;
+ strings_t queryString;
+ };
+
+ uint32_t magic;
+ DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
+ EGLint numTotalConfigs;
+ volatile int32_t refs;
+
+ egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
+ ~egl_display_t() { magic = 0; }
+ inline bool isValid() const { return magic == '_dpy'; }
+ inline bool isAlive() const { return isValid(); }
};
-struct egl_surface_t : public egl_object_t<'_srf'>
+struct egl_surface_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
+
egl_surface_t(EGLDisplay dpy, EGLSurface surface,
- NativeWindowType window, int impl, egl_connection_t const* cnx)
- : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
- {
- // NOTE: window must be incRef'ed and connected already
+ int impl, egl_connection_t const* cnx)
+ : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
}
~egl_surface_t() {
- if (window) {
- if (window->disconnect)
- window->disconnect(window);
- window->decRef(window);
- }
}
EGLDisplay dpy;
EGLSurface surface;
- NativeWindowType window;
int impl;
egl_connection_t const* cnx;
};
-struct egl_context_t : public egl_object_t<'_ctx'>
+struct egl_context_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
+
egl_context_t(EGLDisplay dpy, EGLContext context,
- int impl, egl_connection_t const* cnx)
- : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
+ int impl, egl_connection_t const* cnx, int version)
+ : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
+ version(version)
{
}
EGLDisplay dpy;
@@ -119,52 +206,47 @@ struct egl_context_t : public egl_object_t<'_ctx'>
EGLSurface draw;
int impl;
egl_connection_t const* cnx;
+ int version;
};
-struct tls_t
+struct egl_image_t : public egl_object_t
{
- tls_t() : error(EGL_SUCCESS), ctx(0) { }
- EGLint error;
- EGLContext ctx;
-};
-
-static void gl_unimplemented() {
- LOGE("called unimplemented OpenGL ES API");
-}
+ typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-static char const * const gl_names[] = {
- #include "gl_entries.in"
- #include "glext_entries.in"
- NULL
+ egl_image_t(EGLDisplay dpy, EGLContext context)
+ : dpy(dpy), context(context)
+ {
+ memset(images, 0, sizeof(images));
+ }
+ EGLDisplay dpy;
+ EGLConfig context;
+ EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
};
-static char const * const egl_names[] = {
- #include "egl_entries.in"
- NULL
+typedef egl_surface_t::Ref SurfaceRef;
+typedef egl_context_t::Ref ContextRef;
+typedef egl_image_t::Ref ImageRef;
+
+struct tls_t
+{
+ tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
+ EGLint error;
+ EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
};
-#undef GL_ENTRY
-#undef EGL_ENTRY
// ----------------------------------------------------------------------------
-egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
static egl_display_t gDisplay[NUM_DISPLAYS];
static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t gEGLThreadLocalStorageKey = -1;
// ----------------------------------------------------------------------------
-EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+EGLAPI gl_hooks_t gHooksNoContext;
EGLAPI pthread_key_t gGLWrapperKey = -1;
// ----------------------------------------------------------------------------
@@ -262,110 +344,8 @@ EGLContext getContext() {
return tls->ctx;
}
-
/*****************************************************************************/
-class ISurfaceComposer;
-const sp<ISurfaceComposer>& getSurfaceFlinger();
-request_gpu_t* gpu_acquire(void* user);
-int gpu_release(void*, request_gpu_t* gpu);
-
-static __attribute__((noinline))
-void *load_driver(const char* driver, gl_hooks_t* hooks)
-{
- //LOGD("%s", driver);
- char scrap[256];
- void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
- LOGE_IF(!dso,
- "couldn't load <%s> library (%s)",
- driver, dlerror());
-
- if (dso) {
- // first find the symbol for eglGetProcAddress
-
- typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
- const char*);
-
- getProcAddressType getProcAddress =
- (getProcAddressType)dlsym(dso, "eglGetProcAddress");
-
- LOGE_IF(!getProcAddress,
- "can't find eglGetProcAddress() in %s", driver);
-
- __eglMustCastToProperFunctionPointerType* curr;
- char const * const * api;
-
- gl_hooks_t::egl_t* egl = &hooks->egl;
- curr = (__eglMustCastToProperFunctionPointerType*)egl;
- api = egl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- if (f == NULL) {
- f = (__eglMustCastToProperFunctionPointerType)0;
- }
- }
- *curr++ = f;
- api++;
- }
-
- gl_hooks_t::gl_t* gl = &hooks->gl;
- curr = (__eglMustCastToProperFunctionPointerType*)gl;
- api = gl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- }
- if (f == NULL) {
- // Try without the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- // Try with the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- strcat(scrap, "OES");
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- //LOGD("%s", name);
- f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
- }
- *curr++ = f;
- api++;
- }
-
- // hook this driver up with surfaceflinger if needed
- register_gpu_t register_gpu =
- (register_gpu_t)dlsym(dso, "oem_register_gpu");
-
- if (register_gpu != NULL) {
- if (getSurfaceFlinger() != 0) {
- register_gpu(dso, gpu_acquire, gpu_release);
- }
- }
- }
- return dso;
-}
-
template<typename T>
static __attribute__((noinline))
int binarySearch(
@@ -387,14 +367,14 @@ int binarySearch(
static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- return (i>0 ? dp->numConfigs[0] : 0) + index;
+ return (i>0 ? dp->disp[0].numConfigs : 0) + index;
}
static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
int& i, int& index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- size_t numConfigs = dp->numConfigs[0];
+ size_t numConfigs = dp->disp[0].numConfigs;
i = configId / numConfigs;
index = configId % numConfigs;
}
@@ -412,6 +392,18 @@ struct extention_map_t {
};
static const extention_map_t gExtentionMap[] = {
+ { "eglLockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
+ { "eglUnlockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -429,29 +421,15 @@ static void(*findProcAddress(const char* name,
// ----------------------------------------------------------------------------
-static int gl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return 0;
-}
-static int egl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
- usleep(100000); // don't use all the CPU
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static GLint egl_context_lost_get_error() {
- return EGL_CONTEXT_LOST;
-}
-static int ext_context_lost() {
- return 0;
-}
-
static void gl_no_context() {
- LOGE("call to OpenGL ES API with no current context");
+ tls_t* tls = getTLS();
+ if (tls->logCallWithNoContext == EGL_TRUE) {
+ tls->logCallWithNoContext = EGL_FALSE;
+ LOGE("call to OpenGL ES API with no current context "
+ "(logged once per thread)");
+ }
}
+
static void early_egl_init(void)
{
#if !USE_FAST_TLS_KEY
@@ -459,10 +437,10 @@ static void early_egl_init(void)
#endif
uint32_t addr = (uint32_t)((void*)gl_no_context);
android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
+ (uint32_t*)(void*)&gHooksNoContext,
addr,
- sizeof(gHooks[IMPL_NO_CONTEXT]));
- setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+ sizeof(gHooksNoContext));
+ setGlThreadSpecific(&gHooksNoContext);
}
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
@@ -491,6 +469,11 @@ egl_context_t* get_context(EGLContext context) {
return egl_to_native_cast<egl_context_t>(context);
}
+static inline
+egl_image_t* get_image(EGLImageKHR image) {
+ return egl_to_native_cast<egl_image_t>(image);
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp, int& impl, int& index)
@@ -499,11 +482,11 @@ static egl_connection_t* validate_display_config(
if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
impl = uintptr_t(config)>>24;
- if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
+ if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
index = uintptr_t(config) & 0xFFFFFF;
- if (index >= dp->numConfigs[impl]) {
+ if (index >= dp->disp[impl].numConfigs) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
egl_connection_t* const cnx = &gEGLImpl[impl];
@@ -517,11 +500,9 @@ static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!ctx) // TODO: make sure context is a valid object
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!get_context(ctx)->isValid())
+ if (!get_context(ctx)->isAlive())
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
return EGL_TRUE;
}
@@ -530,92 +511,108 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!surface) // TODO: make sure surface is a valid object
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (!get_surface(surface)->isValid())
+ if (!get_surface(surface)->isAlive())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
return EGL_TRUE;
}
+EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
+{
+ ImageRef _i(image);
+ if (!_i.get()) return EGL_NO_IMAGE_KHR;
+
+ EGLContext context = getContext();
+ if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
+ return EGL_NO_IMAGE_KHR;
+
+ egl_context_t const * const c = get_context(context);
+ if (!c->isAlive())
+ return EGL_NO_IMAGE_KHR;
+
+ egl_image_t const * const i = get_image(image);
+ return i->images[c->impl];
+}
+
+// ----------------------------------------------------------------------------
-EGLDisplay egl_init_displays(NativeDisplayType display)
+// this mutex protects:
+// d->disp[]
+// egl_init_drivers_locked()
+//
+static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
+
+EGLBoolean egl_init_drivers_locked()
{
if (sEarlyInitState) {
- return EGL_NO_DISPLAY;
+ // initialized by static ctor. should be set here.
+ return EGL_FALSE;
}
- uint32_t index = uint32_t(display);
- if (index >= NUM_DISPLAYS) {
- return EGL_NO_DISPLAY;
- }
+ // get our driver loader
+ Loader& loader(Loader::getInstance());
- EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
- egl_display_t* d = &gDisplay[index];
-
- // dynamically load all our EGL implementations for that display
- // and call into the real eglGetGisplay()
- egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+ // dynamically load all our EGL implementations for all displays
+ // and retrieve the corresponding EGLDisplay
+ // if that fails, don't use this driver.
+ // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
+ egl_connection_t* cnx;
+ egl_display_t* d = &gDisplay[0];
+
+ cnx = &gEGLImpl[IMPL_SOFTWARE];
if (cnx->dso == 0) {
- cnx->hooks = &gHooks[IMPL_SOFTWARE];
- cnx->dso = load_driver("libagl.so", cnx->hooks);
- }
- if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
- d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
- LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
- "No EGLDisplay for software EGL!");
+ cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
+ cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
+ d->disp[IMPL_SOFTWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
}
cnx = &gEGLImpl[IMPL_HARDWARE];
- if (cnx->dso == 0 && cnx->unavailable == 0) {
+ if (cnx->dso == 0) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.hw", value, "1");
if (atoi(value) != 0) {
- cnx->hooks = &gHooks[IMPL_HARDWARE];
- cnx->dso = load_driver("libhgl.so", cnx->hooks);
+ cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
+ cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
+ d->disp[IMPL_HARDWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
} else {
LOGD("3D hardware acceleration is disabled");
}
}
- if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
- (uint32_t)((void*)gl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
- (uint32_t)((void*)egl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
- (uint32_t)((void*)ext_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
- egl_context_lost_swap_buffers;
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
- egl_context_lost_get_error;
- gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
- gHooks[IMPL_HARDWARE].egl.eglTerminate;
-
- d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
- if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
- LOGE("h/w accelerated eglGetDisplay() failed (%s)",
- egl_strerror(cnx->hooks->egl.eglGetError()));
- dlclose((void*)cnx->dso);
- cnx->dso = 0;
- // in case of failure, we want to make sure we don't try again
- // as it's expensive.
- cnx->unavailable = 1;
- }
+ if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
+ return EGL_FALSE;
}
- return dpy;
+ return EGL_TRUE;
}
+EGLBoolean egl_init_drivers()
+{
+ EGLBoolean res;
+ pthread_mutex_lock(&gInitDriverMutex);
+ res = egl_init_drivers_locked();
+ pthread_mutex_unlock(&gInitDriverMutex);
+ return res;
+}
// ----------------------------------------------------------------------------
}; // namespace android
@@ -625,7 +622,17 @@ using namespace android;
EGLDisplay eglGetDisplay(NativeDisplayType display)
{
- return egl_init_displays(display);
+ uint32_t index = uint32_t(display);
+ if (index >= NUM_DISPLAYS) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+ return dpy;
}
// ----------------------------------------------------------------------------
@@ -643,55 +650,73 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
return EGL_TRUE;
}
- setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+ setGlThreadSpecific(&gHooksNoContext);
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- dp->extensionsString = strdup(gExtensionString);
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
cnx->major = -1;
cnx->minor = -1;
if (!cnx->dso)
continue;
- if (cnx->hooks->egl.eglInitialize(
- dp->dpys[i], &cnx->major, &cnx->minor)) {
+#if defined(ADRENO130)
+#warning "Adreno-130 eglInitialize() workaround"
+ /*
+ * The ADRENO 130 driver returns a different EGLDisplay each time
+ * eglGetDisplay() is called, but also makes the EGLDisplay invalid
+ * after eglTerminate() has been called, so that eglInitialize()
+ * cannot be called again. Therefore, we need to make sure to call
+ * eglGetDisplay() before calling eglInitialize();
+ */
+ if (i == IMPL_HARDWARE) {
+ dp->disp[i].dpy =
+ cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+#endif
+
+ EGLDisplay idpy = dp->disp[i].dpy;
+ if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
//LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+ // i, idpy, cnx->major, cnx->minor, cnx);
+
+ // display is now initialized
+ dp->disp[i].state = egl_display_t::INITIALIZED;
// get the query-strings for this display for each implementation
- dp->queryString[i].vendor =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
- dp->queryString[i].version =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
- dp->queryString[i].extensions = strdup(
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
- dp->queryString[i].clientApi =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+ dp->disp[i].queryString.vendor =
+ cnx->egl.eglQueryString(idpy, EGL_VENDOR);
+ dp->disp[i].queryString.version =
+ cnx->egl.eglQueryString(idpy, EGL_VERSION);
+ dp->disp[i].queryString.extensions =
+ cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
+ dp->disp[i].queryString.clientApi =
+ cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
} else {
- LOGD("%d: eglInitialize() failed (%s)",
- i, egl_strerror(cnx->hooks->egl.eglGetError()));
+ LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ egl_strerror(cnx->egl.eglGetError()));
}
}
EGLBoolean res = EGL_FALSE;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
EGLint n;
- if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
- dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
- if (dp->configs[i]) {
- if (cnx->hooks->egl.eglGetConfigs(
- dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+ if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
+ dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+ if (dp->disp[i].config) {
+ if (cnx->egl.eglGetConfigs(
+ dp->disp[i].dpy, dp->disp[i].config, n,
+ &dp->disp[i].numConfigs))
{
// sort the configurations so we can do binary searches
- qsort( dp->configs[i],
- dp->numConfigs[i],
+ qsort( dp->disp[i].config,
+ dp->disp[i].numConfigs,
sizeof(EGLConfig), cmp_configs);
dp->numTotalConfigs += n;
@@ -712,33 +737,36 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
EGLBoolean eglTerminate(EGLDisplay dpy)
{
+ // NOTE: don't unload the drivers b/c some APIs can be called
+ // after eglTerminate() has been called. eglTerminate() only
+ // terminates an EGLDisplay, not a EGL itself.
+
egl_display_t* const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (android_atomic_dec(&dp->refs) != 1)
return EGL_TRUE;
-
+
EGLBoolean res = EGL_FALSE;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- cnx->hooks->egl.eglTerminate(dp->dpys[i]);
-
- /* REVISIT: it's unclear what to do if eglTerminate() fails,
- * on one end we shouldn't care, on the other end if it fails
- * it might not be safe to call dlclose() (there could be some
- * threads around). */
-
- free(dp->configs[i]);
- free((void*)dp->queryString[i].extensions);
- dp->numConfigs[i] = 0;
- dp->dpys[i] = EGL_NO_DISPLAY;
- dlclose((void*)cnx->dso);
- cnx->dso = 0;
+ if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
+ if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
+ LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
+ egl_strerror(cnx->egl.eglGetError()));
+ }
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ free(dp->disp[i].config);
+
+ dp->disp[i].numConfigs = 0;
+ dp->disp[i].config = 0;
+ dp->disp[i].state = egl_display_t::TERMINATED;
+
res = EGL_TRUE;
}
}
- free((void*)dp->extensionsString);
- dp->extensionsString = 0;
+
+ // TODO: all egl_object_t should be marked for termination
+
dp->numTotalConfigs = 0;
clearTLS();
return res;
@@ -761,8 +789,8 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy,
return EGL_TRUE;
}
GLint n = 0;
- for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
- for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+ for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
+ for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
*configs++ = MAKE_CONFIG(j, i);
config_size--;
n++;
@@ -818,8 +846,8 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index],
+ cnx->egl.eglGetConfigAttrib(
+ dp->disp[i].dpy, dp->disp[i].config[index],
EGL_CONFIG_ID, &configId);
// and switch to the new list
@@ -828,13 +856,13 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
// At this point, the only configuration that can match is
// dp->configs[i][index], however, we don't know if it would be
// rejected because of the other attributes, so we do have to call
- // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
+ // cnx->egl.eglChooseConfig() -- but we don't have to loop
// through all the EGLimpl[].
// We also know we can only get a single config back, and we know
// which one.
- res = cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n);
+ res = cnx->egl.eglChooseConfig(
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n);
if (res && n>0) {
// n has to be 0 or 1, by construction, and we already know
// which config it will return (since there can be only one).
@@ -849,17 +877,18 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
return res;
}
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n)) {
+ if (cnx->egl.eglChooseConfig(
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
if (configs) {
// now we need to convert these client EGLConfig to our
// internal EGLConfig format. This is done in O(n log n).
for (int j=0 ; j<n ; j++) {
int index = binarySearch<EGLConfig>(
- dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+ dp->disp[i].config, 0,
+ dp->disp[i].numConfigs-1, configs[j]);
if (index >= 0) {
if (configs) {
configs[j] = MAKE_CONFIG(i, index);
@@ -893,8 +922,8 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
*value = configToUniqueId(dp, i, index);
return EGL_TRUE;
}
- return cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index], attribute, value);
+ return cnx->egl.eglGetConfigAttrib(
+ dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
}
// ----------------------------------------------------------------------------
@@ -909,26 +938,12 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- // window must be connected upon calling underlying
- // eglCreateWindowSurface
- if (window) {
- window->incRef(window);
- if (window->connect)
- window->connect(window);
- }
-
- EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
- dp->dpys[i], dp->configs[i][index], window, attrib_list);
+ EGLSurface surface = cnx->egl.eglCreateWindowSurface(
+ dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
-
- // something went wrong, disconnect and free window
- // (will disconnect() automatically)
- if (window) {
- window->decRef(window);
- }
}
return EGL_NO_SURFACE;
}
@@ -941,10 +956,10 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
- dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+ EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
+ dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -958,10 +973,10 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
- dp->dpys[i], dp->configs[i][index], attrib_list);
+ EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
+ dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -970,28 +985,35 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
- egl_surface_t const * const s = get_surface(surface);
- EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
- dp->dpys[s->impl], s->surface);
-
- delete s;
+ egl_surface_t * const s = get_surface(surface);
+ EGLBoolean result = s->cnx->egl.eglDestroySurface(
+ dp->disp[s->impl].dpy, s->surface);
+ if (result == EGL_TRUE) {
+ _s.terminate();
+ }
return result;
}
EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
EGLint attribute, EGLint *value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
- return s->cnx->hooks->egl.eglQuerySurface(
- dp->dpys[s->impl], s->surface, attribute, value);
+ return s->cnx->egl.eglQuerySurface(
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -1005,10 +1027,26 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- EGLContext context = cnx->hooks->egl.eglCreateContext(
- dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+ EGLContext context = cnx->egl.eglCreateContext(
+ dp->disp[i].dpy, dp->disp[i].config[index],
+ share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
- egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
+ // figure out if it's a GLESv1 or GLESv2
+ int version = 0;
+ if (attrib_list) {
+ while (*attrib_list != EGL_NONE) {
+ GLint attr = *attrib_list++;
+ GLint value = *attrib_list++;
+ if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+ if (value == 1) {
+ version = GLESv1_INDEX;
+ } else if (value == 2) {
+ version = GLESv2_INDEX;
+ }
+ }
+ };
+ }
+ egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
return c;
}
}
@@ -1017,66 +1055,125 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
- EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
- dp->dpys[c->impl], c->context);
- delete c;
+ EGLBoolean result = c->cnx->egl.eglDestroyContext(
+ dp->disp[c->impl].dpy, c->context);
+ if (result == EGL_TRUE) {
+ _c.terminate();
+ }
return result;
}
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
+ // get a reference to the object passed in
+ ContextRef _c(ctx);
+ SurfaceRef _d(draw);
+ SurfaceRef _r(read);
+
+ // validate the display and the context (if not EGL_NO_CONTEXT)
egl_display_t const * const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
+ // EGL_NO_CONTEXT is valid
+ return EGL_FALSE;
+ }
- if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
- ctx == EGL_NO_CONTEXT)
- {
- EGLBoolean result = EGL_TRUE;
- ctx = getContext();
- if (ctx) {
- egl_context_t * const c = get_context(ctx);
- result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
- if (result == EGL_TRUE) {
- setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
- setContext(EGL_NO_CONTEXT);
+ // these are the underlying implementation's object
+ EGLContext impl_ctx = EGL_NO_CONTEXT;
+ EGLSurface impl_draw = EGL_NO_SURFACE;
+ EGLSurface impl_read = EGL_NO_SURFACE;
+
+ // these are our objects structs passed in
+ egl_context_t * c = NULL;
+ egl_surface_t const * d = NULL;
+ egl_surface_t const * r = NULL;
+
+ // these are the current objects structs
+ egl_context_t * cur_c = get_context(getContext());
+ egl_surface_t * cur_r = NULL;
+ egl_surface_t * cur_d = NULL;
+
+ if (ctx != EGL_NO_CONTEXT) {
+ c = get_context(ctx);
+ cur_r = get_surface(c->read);
+ cur_d = get_surface(c->draw);
+ impl_ctx = c->context;
+ } else {
+ // no context given, use the implementation of the current context
+ if (cur_c == NULL) {
+ // no current context
+ if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+ // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
+ // not an error, there is just not current context.
+ return EGL_TRUE;
}
- return result;
}
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- EGLSurface impl_draw = EGL_NO_SURFACE;
- EGLSurface impl_read = EGL_NO_SURFACE;
- egl_context_t * const c = get_context(ctx);
+ // retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
- egl_surface_t const * d = get_surface(draw);
- if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->impl != c->impl)
+ d = get_surface(draw);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && d->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_draw = d->surface;
}
+
+ // retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
- egl_surface_t const * r = get_surface(read);
- if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (r->impl != c->impl)
+ r = get_surface(read);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && r->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_read = r->surface;
}
- EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
- dp->dpys[c->impl], impl_draw, impl_read, c->context);
+
+ EGLBoolean result;
+
+ if (c) {
+ result = c->cnx->egl.eglMakeCurrent(
+ dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ } else {
+ result = cur_c->cnx->egl.eglMakeCurrent(
+ dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ }
if (result == EGL_TRUE) {
- setGlThreadSpecific(c->cnx->hooks);
- setContext(ctx);
- c->read = read;
- c->draw = draw;
+ // by construction, these are either 0 or valid (possibly terminated)
+ // it should be impossible for these to be invalid
+ ContextRef _cur_c(cur_c);
+ SurfaceRef _cur_r(cur_r);
+ SurfaceRef _cur_d(cur_d);
+
+ // cur_c has to be valid here (but could be terminated)
+ if (ctx != EGL_NO_CONTEXT) {
+ setGlThreadSpecific(c->cnx->hooks[c->version]);
+ setContext(ctx);
+ _c.acquire();
+ } else {
+ setGlThreadSpecific(&gHooksNoContext);
+ setContext(EGL_NO_CONTEXT);
+ }
+ _cur_c.release();
+
+ _r.acquire();
+ _cur_r.release();
+ if (c) c->read = read;
+
+ _d.acquire();
+ _cur_d.release();
+ if (c) c->draw = draw;
}
return result;
}
@@ -1085,24 +1182,33 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
EGLint attribute, EGLint *value)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
- return c->cnx->hooks->egl.eglQueryContext(
- dp->dpys[c->impl], c->context, attribute, value);
+ return c->cnx->egl.eglQueryContext(
+ dp->disp[c->impl].dpy, c->context, attribute, value);
}
EGLContext eglGetCurrentContext(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_CONTEXT.
+
EGLContext ctx = getContext();
return ctx;
}
EGLSurface eglGetCurrentSurface(EGLint readdraw)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_SURFACE.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1118,6 +1224,9 @@ EGLSurface eglGetCurrentSurface(EGLint readdraw)
EGLDisplay eglGetCurrentDisplay(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_DISPLAY.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1129,6 +1238,9 @@ EGLDisplay eglGetCurrentDisplay(void)
EGLBoolean eglWaitGL(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1139,13 +1251,16 @@ EGLBoolean eglWaitGL(void)
egl_connection_t* const cnx = &gEGLImpl[c->impl];
if (!cnx->dso)
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->hooks->egl.eglWaitGL();
+ res = cnx->egl.eglWaitGL();
}
return res;
}
EGLBoolean eglWaitNative(EGLint engine)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1156,7 +1271,7 @@ EGLBoolean eglWaitNative(EGLint engine)
egl_connection_t* const cnx = &gEGLImpl[c->impl];
if (!cnx->dso)
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->hooks->egl.eglWaitNative(engine);
+ res = cnx->egl.eglWaitNative(engine);
}
return res;
}
@@ -1164,11 +1279,11 @@ EGLBoolean eglWaitNative(EGLint engine)
EGLint eglGetError(void)
{
EGLint result = EGL_SUCCESS;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
EGLint err = EGL_SUCCESS;
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso)
- err = cnx->hooks->egl.eglGetError();
+ err = cnx->egl.eglGetError();
if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
result = err;
}
@@ -1182,9 +1297,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
// eglGetProcAddress() could be the very first function called
// in which case we must make sure we've initialized ourselves, this
// happens the first time egl_get_display() is called.
-
- if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
- return NULL;
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ setError(EGL_BAD_PARAMETER, NULL);
+ return NULL;
+ }
__eglMustCastToProperFunctionPointerType addr;
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
@@ -1197,11 +1314,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
addr = 0;
int slot = -1;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglGetProcAddress) {
- addr = cnx->hooks->egl.eglGetProcAddress(procname);
+ if (cnx->egl.eglGetProcAddress) {
+ addr = cnx->egl.eglGetProcAddress(procname);
if (addr) {
if (slot == -1) {
slot = 0; // XXX: find free slot
@@ -1210,7 +1327,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
break;
}
}
- cnx->hooks->ext.extensions[slot] = addr;
+ //cnx->hooks->ext.extensions[slot] = addr;
}
}
}
@@ -1243,22 +1360,28 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
- return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+ return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
NativePixmapType target)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
- return s->cnx->hooks->egl.eglCopyBuffers(
- dp->dpys[s->impl], s->surface, target);
+ return s->cnx->egl.eglCopyBuffers(
+ dp->disp[s->impl].dpy, s->surface, target);
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -1285,13 +1408,16 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name)
EGLBoolean eglSurfaceAttrib(
EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->hooks->egl.eglSurfaceAttrib) {
- return s->cnx->hooks->egl.eglSurfaceAttrib(
- dp->dpys[s->impl], s->surface, attribute, value);
+ if (s->cnx->egl.eglSurfaceAttrib) {
+ return s->cnx->egl.eglSurfaceAttrib(
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1299,13 +1425,16 @@ EGLBoolean eglSurfaceAttrib(
EGLBoolean eglBindTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->hooks->egl.eglBindTexImage) {
- return s->cnx->hooks->egl.eglBindTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ if (s->cnx->egl.eglBindTexImage) {
+ return s->cnx->egl.eglBindTexImage(
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1313,13 +1442,16 @@ EGLBoolean eglBindTexImage(
EGLBoolean eglReleaseTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->hooks->egl.eglReleaseTexImage) {
- return s->cnx->hooks->egl.eglReleaseTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ if (s->cnx->egl.eglReleaseTexImage) {
+ return s->cnx->egl.eglReleaseTexImage(
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1330,11 +1462,12 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglSwapInterval) {
- if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+ if (cnx->egl.eglSwapInterval) {
+ if (cnx->egl.eglSwapInterval(
+ dp->disp[i].dpy, interval) == EGL_FALSE) {
res = EGL_FALSE;
}
}
@@ -1350,6 +1483,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
EGLBoolean eglWaitClient(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1360,10 +1495,10 @@ EGLBoolean eglWaitClient(void)
egl_connection_t* const cnx = &gEGLImpl[c->impl];
if (!cnx->dso)
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (cnx->hooks->egl.eglWaitClient) {
- res = cnx->hooks->egl.eglWaitClient();
+ if (cnx->egl.eglWaitClient) {
+ res = cnx->egl.eglWaitClient();
} else {
- res = cnx->hooks->egl.eglWaitGL();
+ res = cnx->egl.eglWaitGL();
}
}
return res;
@@ -1371,13 +1506,17 @@ EGLBoolean eglWaitClient(void)
EGLBoolean eglBindAPI(EGLenum api)
{
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
// bind this API on all EGLs
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglBindAPI) {
- if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
+ if (cnx->egl.eglBindAPI) {
+ if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
res = EGL_FALSE;
}
}
@@ -1388,13 +1527,17 @@ EGLBoolean eglBindAPI(EGLenum api)
EGLenum eglQueryAPI(void)
{
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglQueryAPI) {
+ if (cnx->egl.eglQueryAPI) {
// the first one we find is okay, because they all
// should be the same
- return cnx->hooks->egl.eglQueryAPI();
+ return cnx->egl.eglQueryAPI();
}
}
}
@@ -1404,11 +1547,11 @@ EGLenum eglQueryAPI(void)
EGLBoolean eglReleaseThread(void)
{
- for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
- if (cnx->hooks->egl.eglReleaseThread) {
- cnx->hooks->egl.eglReleaseThread();
+ if (cnx->egl.eglReleaseThread) {
+ cnx->egl.eglReleaseThread();
}
}
}
@@ -1424,9 +1567,194 @@ EGLSurface eglCreatePbufferFromClientBuffer(
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (!cnx) return EGL_FALSE;
- if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
- return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
- dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+ if (cnx->egl.eglCreatePbufferFromClientBuffer) {
+ return cnx->egl.eglCreatePbufferFromClientBuffer(
+ dp->disp[i].dpy, buftype, buffer,
+ dp->disp[i].config[index], attrib_list);
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (s->cnx->egl.eglLockSurfaceKHR) {
+ return s->cnx->egl.eglLockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface, attrib_list);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (s->cnx->egl.eglUnlockSurfaceKHR) {
+ return s->cnx->egl.eglUnlockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (ctx != EGL_NO_CONTEXT) {
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_NO_IMAGE_KHR;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+ // since we have an EGLContext, we know which implementation to use
+ EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
+ dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+ if (image == EGL_NO_IMAGE_KHR)
+ return image;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ result->images[c->impl] = image;
+ return (EGLImageKHR)result;
+ } else {
+ // EGL_NO_CONTEXT is a valid parameter
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+
+ /* Since we don't have a way to know which implementation to call,
+ * we're calling all of them. If at least one of the implementation
+ * succeeded, this is a success.
+ */
+
+ EGLint currentError = eglGetError();
+
+ EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ implImages[i] = EGL_NO_IMAGE_KHR;
+ if (cnx->dso) {
+ if (cnx->egl.eglCreateImageKHR) {
+ implImages[i] = cnx->egl.eglCreateImageKHR(
+ dp->disp[i].dpy, ctx, target, buffer, attrib_list);
+ if (implImages[i] != EGL_NO_IMAGE_KHR) {
+ success = true;
+ }
+ }
+ }
+ }
+
+ if (!success) {
+ // failure, if there was an error when we entered this function,
+ // the error flag must not be updated.
+ // Otherwise, the error is whatever happened in the implementation
+ // that faulted.
+ if (currentError != EGL_SUCCESS) {
+ setError(currentError, EGL_NO_IMAGE_KHR);
+ }
+ return EGL_NO_IMAGE_KHR;
+ } else {
+ // In case of success, we need to clear all error flags
+ // (especially those caused by the implementation that didn't
+ // succeed). TODO: we could avoid this if we knew this was
+ // a "full" success (all implementation succeeded).
+ eglGetError();
+ }
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ memcpy(result->images, implImages, sizeof(implImages));
+ return (EGLImageKHR)result;
+ }
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ ImageRef _i(img);
+ if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl_image_t* image = get_image(img);
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (image->images[i] != EGL_NO_IMAGE_KHR) {
+ if (cnx->dso) {
+ if (cnx->egl.eglCreateImageKHR) {
+ if (cnx->egl.eglDestroyImageKHR(
+ dp->disp[i].dpy, image->images[i])) {
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_FALSE;
+
+ _i.terminate();
+
+ return EGL_TRUE;
+}
+
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, draw))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->egl.eglSetSwapRectangleANDROID) {
+ return s->cnx->egl.eglSetSwapRectangleANDROID(
+ dp->disp[s->impl].dpy, s->surface, left, top, width, height);
+ }
+ return setError(EGL_BAD_DISPLAY, NULL);
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
+
+ if (!validate_display_surface(dpy, draw))
+ return 0;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->egl.eglGetRenderBufferANDROID) {
+ return s->cnx->egl.eglGetRenderBufferANDROID(
+ dp->disp[s->impl].dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
+}
diff --git a/opengl/libs/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 3b4551b..5d89287 100644
--- a/opengl/libs/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -50,3 +50,8 @@ EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint
EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+
+/* ANDROID extensions */
+
+EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
+EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
deleted file mode 100644
index 4c902c8..0000000
--- a/opengl/libs/EGL/gpu.cpp
+++ /dev/null
@@ -1,217 +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 "EGL"
-
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
-
-#include <ui/EGLDisplaySurface.h>
-#include <ui/ISurfaceComposer.h>
-
-#include "hooks.h"
-#include "egl_impl.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-/*
- * we provide our own allocators for the GPU regions, these
- * allocators go through surfaceflinger
- */
-
-static Mutex gRegionsLock;
-static request_gpu_t gRegions;
-static sp<ISurfaceComposer> gSurfaceManager;
-GL_API ISurfaceComposer* GLES_localSurfaceManager = 0;
-
-extern egl_connection_t gEGLImpl[2];
-
-const sp<ISurfaceComposer>& getSurfaceFlinger()
-{
- Mutex::Autolock _l(gRegionsLock);
-
- /*
- * There is a little bit of voodoo magic here. We want to access
- * surfaceflinger for allocating GPU regions, however, when we are
- * running as part of surfaceflinger, we want to bypass the
- * service manager because surfaceflinger might not be registered yet.
- * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
- * own address, so we can just use that.
- */
- if (gSurfaceManager == 0) {
- if (GLES_localSurfaceManager) {
- // we're running in SurfaceFlinger's context
- gSurfaceManager = GLES_localSurfaceManager;
- } else {
- // we're a remote process or not part of surfaceflinger,
- // go through the service manager
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
- gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
- }
- }
- }
- return gSurfaceManager;
-}
-
-class GPURevokeRequester : public BnGPUCallback
-{
-public:
- virtual void gpuLost() {
- LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
- gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
- }
-};
-
-static sp<GPURevokeRequester> gRevokerCallback;
-
-
-request_gpu_t* gpu_acquire(void* user)
-{
- sp<ISurfaceComposer> server( getSurfaceFlinger() );
-
- Mutex::Autolock _l(gRegionsLock);
- if (server == NULL) {
- return 0;
- }
-
- ISurfaceComposer::gpu_info_t info;
-
- if (gRevokerCallback == 0)
- gRevokerCallback = new GPURevokeRequester();
-
- status_t err = server->requestGPU(gRevokerCallback, &info);
- if (err != NO_ERROR) {
- LOGD("requestGPU returned %d", err);
- return 0;
- }
-
- if (info.regs == 0) {
- LOGD("requestGPU() failed");
- return 0;
- }
-
- bool failed = false;
- request_gpu_t* gpu = &gRegions;
- memset(gpu, 0, sizeof(*gpu));
-
- if (info.regs != 0) {
- sp<IMemoryHeap> heap(info.regs->getMemory());
- if (heap != 0) {
- int fd = heap->heapID();
- gpu->regs.fd = fd;
- gpu->regs.base = info.regs->pointer();
- gpu->regs.size = info.regs->size();
- gpu->regs.user = info.regs.get();
-#if HAVE_ANDROID_OS
- struct pmem_region region;
- if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
- gpu->regs.phys = (void*)region.offset;
-#endif
- info.regs->incStrong(gpu);
- } else {
- LOGE("GPU register handle %p is invalid!", info.regs.get());
- failed = true;
- }
- }
-
- for (size_t i=0 ; i<info.count && !failed ; i++) {
- sp<IMemory>& region(info.regions[i].region);
- if (region != 0) {
- sp<IMemoryHeap> heap(region->getMemory());
- if (heap != 0) {
- const int fd = heap->heapID();
- gpu->gpu[i].fd = fd;
- gpu->gpu[i].base = region->pointer();
- gpu->gpu[i].size = region->size();
- gpu->gpu[i].user = region.get();
- gpu->gpu[i].offset = info.regions[i].reserved;
-#if HAVE_ANDROID_OS
- struct pmem_region reg;
- if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
- gpu->gpu[i].phys = (void*)reg.offset;
-#endif
- region->incStrong(gpu);
- } else {
- LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
- failed = true;
- }
- }
- }
-
- if (failed) {
- // something went wrong, clean up everything!
- if (gpu->regs.user) {
- static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
- for (size_t i=0 ; i<info.count ; i++) {
- if (gpu->gpu[i].user) {
- static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
- }
- }
- }
- }
-
- gpu->count = info.count;
- return gpu;
-}
-
-int gpu_release(void*, request_gpu_t* gpu)
-{
- sp<IMemory> regs;
-
- { // scope for lock
- Mutex::Autolock _l(gRegionsLock);
- regs = static_cast<IMemory*>(gpu->regs.user);
- gpu->regs.user = 0;
- if (regs != 0) regs->decStrong(gpu);
-
- for (int i=0 ; i<gpu->count ; i++) {
- sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
- gpu->gpu[i].user = 0;
- if (r != 0) r->decStrong(gpu);
- }
- }
-
- // there is a special transaction to relinquish the GPU
- // (it will happen automatically anyway if we don't do this)
- Parcel data, reply;
- // NOTE: this transaction does not require an interface token
- regs->asBinder()->transact(1000, data, &reply);
- return 1;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
new file mode 100644
index 0000000..72ad6b3
--- /dev/null
+++ b/opengl/libs/EGL/hooks.cpp
@@ -0,0 +1,60 @@
+/*
+ ** 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 <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+ #include "entries.in"
+ NULL
+};
+
+char const * const egl_names[] = {
+ #include "egl_entries.in"
+ NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
new file mode 100644
index 0000000..b8e3283
--- /dev/null
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -0,0 +1,119 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Actual GL entry-points
+// ----------------------------------------------------------------------------
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+#if USE_FAST_TLS_KEY
+
+ #ifdef HAVE_ARM_TLS_REGISTER
+ #define GET_TLS(reg) \
+ "mrc p15, 0, " #reg ", c13, c0, 3 \n"
+ #else
+ #define GET_TLS(reg) \
+ "mov " #reg ", #0xFFFF0FFF \n" \
+ "ldr " #reg ", [" #reg ", #-15] \n"
+ #endif
+
+ #define API_ENTRY(_api) __attribute__((naked)) _api
+
+ #define CALL_GL_API(_api, ...) \
+ asm volatile( \
+ GET_TLS(r12) \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ "bx lr \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : \
+ );
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API(_api, __VA_ARGS__) \
+ return 0; // placate gcc's warnings. never reached.
+
+#else
+
+ #define API_ENTRY(_api) _api
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ _c->_api(__VA_ARGS__)
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ return _c->_api(__VA_ARGS__)
+
+#endif
+
+
+extern "C" {
+#include "gl2_api.in"
+#include "gl2ext_api.in"
+}
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+
+/*
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
+ */
+
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
+}
+
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
new file mode 100644
index 0000000..9c2e69a
--- /dev/null
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -0,0 +1,426 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+ CALL_GL_API(glActiveTexture, texture);
+}
+void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glAttachShader, program, shader);
+}
+void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const char* name) {
+ CALL_GL_API(glBindAttribLocation, program, index, name);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+ CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
+ CALL_GL_API(glBindFramebuffer, target, framebuffer);
+}
+void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
+ CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
+}
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+ CALL_GL_API(glBindTexture, target, texture);
+}
+void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glBlendColor, red, green, blue, alpha);
+}
+void API_ENTRY(glBlendEquation)( GLenum mode ) {
+ CALL_GL_API(glBlendEquation, mode);
+}
+void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
+ CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
+}
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+ CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
+ CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
+}
+void API_ENTRY(glClear)(GLbitfield mask) {
+ CALL_GL_API(glClear, mask);
+}
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+ CALL_GL_API(glClearDepthf, depth);
+}
+void API_ENTRY(glClearStencil)(GLint s) {
+ CALL_GL_API(glClearStencil, s);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glCompileShader)(GLuint shader) {
+ CALL_GL_API(glCompileShader, shader);
+}
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+ CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
+}
+void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
+}
+GLuint API_ENTRY(glCreateProgram)(void) {
+ CALL_GL_API_RETURN(glCreateProgram);
+}
+GLuint API_ENTRY(glCreateShader)(GLenum type) {
+ CALL_GL_API_RETURN(glCreateShader, type);
+}
+void API_ENTRY(glCullFace)(GLenum mode) {
+ CALL_GL_API(glCullFace, mode);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+ CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers) {
+ CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glDeleteProgram)(GLuint program) {
+ CALL_GL_API(glDeleteProgram, program);
+}
+void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers) {
+ CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glDeleteShader)(GLuint shader) {
+ CALL_GL_API(glDeleteShader, shader);
+}
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint* textures) {
+ CALL_GL_API(glDeleteTextures, n, textures);
+}
+void API_ENTRY(glDepthFunc)(GLenum func) {
+ CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+ CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+ CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glDetachShader, program, shader);
+}
+void API_ENTRY(glDisable)(GLenum cap) {
+ CALL_GL_API(glDisable, cap);
+}
+void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glDisableVertexAttribArray, index);
+}
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+ CALL_GL_API(glDrawArrays, mode, first, count);
+}
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+void API_ENTRY(glEnable)(GLenum cap) {
+ CALL_GL_API(glEnable, cap);
+}
+void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glEnableVertexAttribArray, index);
+}
+void API_ENTRY(glFinish)(void) {
+ CALL_GL_API(glFinish);
+}
+void API_ENTRY(glFlush)(void) {
+ CALL_GL_API(glFlush);
+}
+void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
+ CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
+ CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
+}
+void API_ENTRY(glFrontFace)(GLenum mode) {
+ CALL_GL_API(glFrontFace, mode);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+ CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGenerateMipmap)(GLenum target) {
+ CALL_GL_API(glGenerateMipmap, target);
+}
+void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers) {
+ CALL_GL_API(glGenFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) {
+ CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint* textures) {
+ CALL_GL_API(glGenTextures, n, textures);
+}
+void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
+}
+int API_ENTRY(glGetAttribLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetAttribLocation, program, name);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
+ CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+GLenum API_ENTRY(glGetError)(void) {
+ CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
+ CALL_GL_API(glGetIntegerv, pname, params);
+}
+void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetProgramiv, program, pname, params);
+}
+void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
+}
+void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetShaderiv, shader, pname, params);
+}
+void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
+}
+void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
+}
+void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
+}
+const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+ CALL_GL_API_RETURN(glGetString, name);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
+ CALL_GL_API(glGetUniformfv, program, location, params);
+}
+void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
+ CALL_GL_API(glGetUniformiv, program, location, params);
+}
+int API_ENTRY(glGetUniformLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetUniformLocation, program, name);
+}
+void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetVertexAttribfv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetVertexAttribiv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer) {
+ CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
+}
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+ CALL_GL_API(glHint, target, mode);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+ CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+ CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
+ CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
+}
+GLboolean API_ENTRY(glIsProgram)(GLuint program) {
+ CALL_GL_API_RETURN(glIsProgram, program);
+}
+GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
+ CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
+}
+GLboolean API_ENTRY(glIsShader)(GLuint shader) {
+ CALL_GL_API_RETURN(glIsShader, shader);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+ CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glLineWidth)(GLfloat width) {
+ CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glLinkProgram)(GLuint program) {
+ CALL_GL_API(glLinkProgram, program);
+}
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+ CALL_GL_API(glPixelStorei, pname, param);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+ CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
+ CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glReleaseShaderCompiler)(void) {
+ CALL_GL_API(glReleaseShaderCompiler);
+}
+void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+ CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glScissor, x, y, width, height);
+}
+void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) {
+ CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
+}
+void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length) {
+ CALL_GL_API(glShaderSource, shader, count, string, length);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask) {
+ CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
+ CALL_GL_API(glStencilMaskSeparate, face, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
+}
+void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
+ CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
+}
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexParameterf, target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
+ CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
+ CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
+ CALL_GL_API(glUniform1f, location, x);
+}
+void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform1fv, location, count, v);
+}
+void API_ENTRY(glUniform1i)(GLint location, GLint x) {
+ CALL_GL_API(glUniform1i, location, x);
+}
+void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform1iv, location, count, v);
+}
+void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
+ CALL_GL_API(glUniform2f, location, x, y);
+}
+void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform2fv, location, count, v);
+}
+void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
+ CALL_GL_API(glUniform2i, location, x, y);
+}
+void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform2iv, location, count, v);
+}
+void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glUniform3f, location, x, y, z);
+}
+void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform3fv, location, count, v);
+}
+void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
+ CALL_GL_API(glUniform3i, location, x, y, z);
+}
+void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform3iv, location, count, v);
+}
+void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glUniform4f, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform4fv, location, count, v);
+}
+void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
+ CALL_GL_API(glUniform4i, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform4iv, location, count, v);
+}
+void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
+}
+void API_ENTRY(glUseProgram)(GLuint program) {
+ CALL_GL_API(glUseProgram, program);
+}
+void API_ENTRY(glValidateProgram)(GLuint program) {
+ CALL_GL_API(glValidateProgram, program);
+}
+void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
+ CALL_GL_API(glVertexAttrib1f, indx, x);
+}
+void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib1fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
+ CALL_GL_API(glVertexAttrib2f, indx, x, y);
+}
+void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib2fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
+}
+void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib3fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
+}
+void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib4fv, indx, values);
+}
+void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) {
+ CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
+}
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glViewport, x, y, width, height);
+}
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
new file mode 100644
index 0000000..6eeecb3
--- /dev/null
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -0,0 +1,105 @@
+void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
+}
+void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
+}
+void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) {
+ CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary);
+}
+void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) {
+ CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length);
+}
+void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {
+ CALL_GL_API_RETURN(glMapBufferOES, target, access);
+}
+GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {
+ CALL_GL_API_RETURN(glUnmapBufferOES, target);
+}
+void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) {
+ CALL_GL_API(glGetBufferPointervOES, target, pname, params);
+}
+void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels);
+}
+void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+}
+void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height);
+}
+void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+}
+void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {
+ CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset);
+}
+void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) {
+ CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups);
+}
+void API_ENTRY(glGetPerfMonitorCountersAMD)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) {
+ CALL_GL_API(glGetPerfMonitorCountersAMD, group, numCounters, maxActiveCounters, counterSize, counters);
+}
+void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, char *groupString) {
+ CALL_GL_API(glGetPerfMonitorGroupStringAMD, group, bufSize, length, groupString);
+}
+void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString) {
+ CALL_GL_API(glGetPerfMonitorCounterStringAMD, group, counter, bufSize, length, counterString);
+}
+void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, void *data) {
+ CALL_GL_API(glGetPerfMonitorCounterInfoAMD, group, counter, pname, data);
+}
+void API_ENTRY(glGenPerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glGenPerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glDeletePerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glDeletePerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glSelectPerfMonitorCountersAMD)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList) {
+ CALL_GL_API(glSelectPerfMonitorCountersAMD, monitor, enable, group, numCounters, countersList);
+}
+void API_ENTRY(glBeginPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glBeginPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glEndPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glEndPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {
+ CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);
+}
+void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
+ CALL_GL_API(glDeleteFencesNV, n, fences);
+}
+void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) {
+ CALL_GL_API(glGenFencesNV, n, fences);
+}
+GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glIsFenceNV, fence);
+}
+GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glTestFenceNV, fence);
+}
+void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetFenceivNV, fence, pname, params);
+}
+void API_ENTRY(glFinishFenceNV)(GLuint fence) {
+ CALL_GL_API(glFinishFenceNV, fence);
+}
+void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {
+ CALL_GL_API(glSetFenceNV, fence, condition);
+}
+void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {
+ CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);
+}
+void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString) {
+ CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString);
+}
+void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glEnableDriverControlQCOM, driverControl);
+}
+void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glDisableDriverControlQCOM, driverControl);
+}
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 384b59a..0c9352e 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -14,8 +14,6 @@
** limitations under the License.
*/
-#define LOG_TAG "GLES_CM"
-
#include <ctype.h>
#include <string.h>
#include <errno.h>
@@ -33,6 +31,9 @@
using namespace android;
+// set this to 1 for crude GL debugging
+#define CHECK_FOR_GL_ERRORS 0
+
// ----------------------------------------------------------------------------
// extensions for the framework
// ----------------------------------------------------------------------------
@@ -73,14 +74,22 @@ void glVertexPointerBounds(GLint size, GLenum type,
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-#if USE_FAST_TLS_KEY
+#if USE_FAST_TLS_KEY && !CHECK_FOR_GL_ERRORS
+
+ #ifdef HAVE_ARM_TLS_REGISTER
+ #define GET_TLS(reg) \
+ "mrc p15, 0, " #reg ", c13, c0, 3 \n"
+ #else
+ #define GET_TLS(reg) \
+ "mov " #reg ", #0xFFFF0FFF \n" \
+ "ldr " #reg ", [" #reg ", #-15] \n"
+ #endif
#define API_ENTRY(_api) __attribute__((naked)) _api
#define CALL_GL_API(_api, ...) \
asm volatile( \
- "mov r12, #0xFFFF0FFF \n" \
- "ldr r12, [r12, #-15] \n" \
+ GET_TLS(r12) \
"ldr r12, [r12, %[tls]] \n" \
"cmp r12, #0 \n" \
"ldrne pc, [r12, %[api]] \n" \
@@ -90,19 +99,34 @@ void glVertexPointerBounds(GLint size, GLenum type,
[api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
: \
);
-
+
#define CALL_GL_API_RETURN(_api, ...) \
CALL_GL_API(_api, __VA_ARGS__) \
return 0; // placate gcc's warnings. never reached.
#else
+ #if CHECK_FOR_GL_ERRORS
+
+ #define CHECK_GL_ERRORS(_api) \
+ do { GLint err = glGetError(); \
+ LOGE_IF(err != GL_NO_ERROR, "%s failed (0x%04X)", #_api, err); \
+ } while(false);
+
+ #else
+
+ #define CHECK_GL_ERRORS(_api) do { } while(false);
+
+ #endif
+
+
#define API_ENTRY(_api) _api
#define CALL_GL_API(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- _c->_api(__VA_ARGS__)
-
+ _c->_api(__VA_ARGS__); \
+ CHECK_GL_ERRORS(_api)
+
#define CALL_GL_API_RETURN(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
return _c->_api(__VA_ARGS__)
@@ -121,16 +145,25 @@ extern "C" {
/*
- * These GL calls are special because they need to call into EGL to retrieve
- * some informations before they can execute.
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
*/
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
}
void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
}
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 312b176..1fba209 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -23,21 +23,23 @@
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
+#include "hooks.h"
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-struct gl_hooks_t;
-
struct egl_connection_t
{
- void volatile * dso;
- gl_hooks_t * hooks;
+ void * dso;
+ gl_hooks_t * hooks[2];
EGLint major;
EGLint minor;
- int unavailable;
+ egl_t egl;
};
+EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/entries.in b/opengl/libs/entries.in
new file mode 100644
index 0000000..bbe3e23
--- /dev/null
+++ b/opengl/libs/entries.in
@@ -0,0 +1,349 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const char* name)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glBlendEquation, GLenum mode )
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
+GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLclampx depth)
+GL_ENTRY(void, glClearDepthxOES, GLclampx depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glCompileShader, GLuint shader)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(GLuint, glCreateProgram, void)
+GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteShader, GLuint shader)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(void, glGenerateMipmap, GLenum target)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+GL_ENTRY(int, glGetAttribLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params)
+GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
+GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, void *data)
+GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString)
+GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
+GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, char *groupString)
+GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
+GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
+GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
+GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(int, glGetUniformLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)
+GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params)
+GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer)
+GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsShader, GLuint shader)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLinkProgram, GLuint program)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glReleaseShaderCompiler, void)
+GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const char** string, const GLint* length)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glUniform1f, GLint location, GLfloat x)
+GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform1i, GLint location, GLint x)
+GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
+GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
+GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
diff --git a/opengl/libs/gl_entries.in b/opengl/libs/gl_entries.in
deleted file mode 100644
index d7cc5da..0000000
--- a/opengl/libs/gl_entries.in
+++ /dev/null
@@ -1,145 +0,0 @@
-GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
-GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-GL_ENTRY(void, glClearDepthf, GLclampf depth)
-GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation)
-GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
-GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
-GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
-GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
-GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4])
-GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
-GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
-GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glLineWidth, GLfloat width)
-GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
-GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
-GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
-GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
-GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
-GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
-GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
-GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glPointSize, GLfloat size)
-GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
-GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
-GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
-GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
-GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
-GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
-GL_ENTRY(void, glActiveTexture, GLenum texture)
-GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
-GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
-GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
-GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
-GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
-GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
-GL_ENTRY(void, glClear, GLbitfield mask)
-GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
-GL_ENTRY(void, glClearDepthx, GLclampx depth)
-GL_ENTRY(void, glClearStencil, GLint s)
-GL_ENTRY(void, glClientActiveTexture, GLenum texture)
-GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
-GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
-GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
-GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
-GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
-GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-GL_ENTRY(void, glCullFace, GLenum mode)
-GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
-GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
-GL_ENTRY(void, glDepthFunc, GLenum func)
-GL_ENTRY(void, glDepthMask, GLboolean flag)
-GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
-GL_ENTRY(void, glDisable, GLenum cap)
-GL_ENTRY(void, glDisableClientState, GLenum array)
-GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
-GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
-GL_ENTRY(void, glEnable, GLenum cap)
-GL_ENTRY(void, glEnableClientState, GLenum array)
-GL_ENTRY(void, glFinish, void)
-GL_ENTRY(void, glFlush, void)
-GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
-GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glFrontFace, GLenum mode)
-GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
-GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)
-GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
-GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4])
-GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
-GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
-GL_ENTRY(GLenum, glGetError, void)
-GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
-GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
-GL_ENTRY(const GLubyte *, glGetString, GLenum name)
-GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params)
-GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
-GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glHint, GLenum target, GLenum mode)
-GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
-GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
-GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
-GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
-GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
-GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glLineWidthx, GLfixed width)
-GL_ENTRY(void, glLoadIdentity, void)
-GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
-GL_ENTRY(void, glLogicOp, GLenum opcode)
-GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
-GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glMatrixMode, GLenum mode)
-GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
-GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
-GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
-GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
-GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
-GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
-GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glPointSizex, GLfixed size)
-GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
-GL_ENTRY(void, glPopMatrix, void)
-GL_ENTRY(void, glPushMatrix, void)
-GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
-GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
-GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
-GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
-GL_ENTRY(void, glShadeModel, GLenum mode)
-GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
-GL_ENTRY(void, glStencilMask, GLuint mask)
-GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
-GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
-GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
-GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
-GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
-GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
-GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
-GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
-GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
-GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
-GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer)
diff --git a/opengl/libs/gl_enums.in b/opengl/libs/gl_enums.in
deleted file mode 100644
index ffc2fad..0000000
--- a/opengl/libs/gl_enums.in
+++ /dev/null
@@ -1,261 +0,0 @@
-GLENUM(GL_POINTS, 0x0000)
-GLENUM(GL_LINES, 0x0001)
-GLENUM(GL_LINE_LOOP, 0x0002)
-GLENUM(GL_LINE_STRIP, 0x0003)
-GLENUM(GL_TRIANGLES, 0x0004)
-GLENUM(GL_TRIANGLE_STRIP, 0x0005)
-GLENUM(GL_TRIANGLE_FAN, 0x0006)
-GLENUM(GL_ADD, 0x0104)
-GLENUM(GL_NEVER, 0x0200)
-GLENUM(GL_LESS, 0x0201)
-GLENUM(GL_EQUAL, 0x0202)
-GLENUM(GL_LEQUAL, 0x0203)
-GLENUM(GL_GREATER, 0x0204)
-GLENUM(GL_NOTEQUAL, 0x0205)
-GLENUM(GL_GEQUAL, 0x0206)
-GLENUM(GL_ALWAYS, 0x0207)
-GLENUM(GL_SRC_COLOR, 0x0300)
-GLENUM(GL_ONE_MINUS_SRC_COLOR, 0x0301)
-GLENUM(GL_SRC_ALPHA, 0x0302)
-GLENUM(GL_ONE_MINUS_SRC_ALPHA, 0x0303)
-GLENUM(GL_DST_ALPHA, 0x0304)
-GLENUM(GL_ONE_MINUS_DST_ALPHA, 0x0305)
-GLENUM(GL_DST_COLOR, 0x0306)
-GLENUM(GL_ONE_MINUS_DST_COLOR, 0x0307)
-GLENUM(GL_SRC_ALPHA_SATURATE, 0x0308)
-GLENUM(GL_FRONT, 0x0404)
-GLENUM(GL_BACK, 0x0405)
-GLENUM(GL_FRONT_AND_BACK, 0x0408)
-GLENUM(GL_INVALID_ENUM, 0x0500)
-GLENUM(GL_INVALID_VALUE, 0x0501)
-GLENUM(GL_INVALID_OPERATION, 0x0502)
-GLENUM(GL_STACK_OVERFLOW, 0x0503)
-GLENUM(GL_STACK_UNDERFLOW, 0x0504)
-GLENUM(GL_OUT_OF_MEMORY, 0x0505)
-GLENUM(GL_EXP, 0x0800)
-GLENUM(GL_EXP2, 0x0801)
-GLENUM(GL_CW, 0x0900)
-GLENUM(GL_CCW, 0x0901)
-GLENUM(GL_POINT_SMOOTH, 0x0B10)
-GLENUM(GL_SMOOTH_POINT_SIZE_RANGE, 0x0B12)
-GLENUM(GL_LINE_SMOOTH, 0x0B20)
-GLENUM(GL_SMOOTH_LINE_WIDTH_RANGE, 0x0B22)
-GLENUM(GL_CULL_FACE, 0x0B44)
-GLENUM(GL_LIGHTING, 0x0B50)
-GLENUM(GL_LIGHT_MODEL_TWO_SIDE, 0x0B52)
-GLENUM(GL_LIGHT_MODEL_AMBIENT, 0x0B53)
-GLENUM(GL_COLOR_MATERIAL, 0x0B57)
-GLENUM(GL_FOG, 0x0B60)
-GLENUM(GL_FOG_DENSITY, 0x0B62)
-GLENUM(GL_FOG_START, 0x0B63)
-GLENUM(GL_FOG_END, 0x0B64)
-GLENUM(GL_FOG_MODE, 0x0B65)
-GLENUM(GL_FOG_COLOR, 0x0B66)
-GLENUM(GL_DEPTH_TEST, 0x0B71)
-GLENUM(GL_STENCIL_TEST, 0x0B90)
-GLENUM(GL_NORMALIZE, 0x0BA1)
-GLENUM(GL_ALPHA_TEST, 0x0BC0)
-GLENUM(GL_DITHER, 0x0BD0)
-GLENUM(GL_BLEND, 0x0BE2)
-GLENUM(GL_COLOR_LOGIC_OP, 0x0BF2)
-GLENUM(GL_SCISSOR_TEST, 0x0C11)
-GLENUM(GL_PERSPECTIVE_CORRECTION_HINT, 0x0C50)
-GLENUM(GL_POINT_SMOOTH_HINT, 0x0C51)
-GLENUM(GL_LINE_SMOOTH_HINT, 0x0C52)
-GLENUM(GL_POLYGON_SMOOTH_HINT, 0x0C53)
-GLENUM(GL_FOG_HINT, 0x0C54)
-GLENUM(GL_UNPACK_ALIGNMENT, 0x0CF5)
-GLENUM(GL_PACK_ALIGNMENT, 0x0D05)
-GLENUM(GL_MAX_LIGHTS, 0x0D31)
-GLENUM(GL_MAX_CLIP_PLANES, 0x0D32)
-GLENUM(GL_MAX_TEXTURE_SIZE, 0x0D33)
-GLENUM(GL_MAX_MODELVIEW_STACK_DEPTH, 0x0D36)
-GLENUM(GL_MAX_PROJECTION_STACK_DEPTH, 0x0D38)
-GLENUM(GL_MAX_TEXTURE_STACK_DEPTH, 0x0D39)
-GLENUM(GL_MAX_VIEWPORT_DIMS, 0x0D3A)
-GLENUM(GL_RED_BITS, 0x0D52)
-GLENUM(GL_GREEN_BITS, 0x0D53)
-GLENUM(GL_BLUE_BITS, 0x0D54)
-GLENUM(GL_ALPHA_BITS, 0x0D55)
-GLENUM(GL_DEPTH_BITS, 0x0D56)
-GLENUM(GL_STENCIL_BITS, 0x0D57)
-GLENUM(GL_TEXTURE_2D, 0x0DE1)
-GLENUM(GL_DONT_CARE, 0x1100)
-GLENUM(GL_FASTEST, 0x1101)
-GLENUM(GL_NICEST, 0x1102)
-GLENUM(GL_AMBIENT, 0x1200)
-GLENUM(GL_DIFFUSE, 0x1201)
-GLENUM(GL_SPECULAR, 0x1202)
-GLENUM(GL_POSITION, 0x1203)
-GLENUM(GL_SPOT_DIRECTION, 0x1204)
-GLENUM(GL_SPOT_EXPONENT, 0x1205)
-GLENUM(GL_SPOT_CUTOFF, 0x1206)
-GLENUM(GL_CONSTANT_ATTENUATION, 0x1207)
-GLENUM(GL_LINEAR_ATTENUATION, 0x1208)
-GLENUM(GL_QUADRATIC_ATTENUATION, 0x1209)
-GLENUM(GL_BYTE, 0x1400)
-GLENUM(GL_UNSIGNED_BYTE, 0x1401)
-GLENUM(GL_SHORT, 0x1402)
-GLENUM(GL_UNSIGNED_SHORT, 0x1403)
-GLENUM(GL_FLOAT, 0x1406)
-GLENUM(GL_FIXED, 0x140C)
-GLENUM(GL_CLEAR, 0x1500)
-GLENUM(GL_AND, 0x1501)
-GLENUM(GL_AND_REVERSE, 0x1502)
-GLENUM(GL_COPY, 0x1503)
-GLENUM(GL_AND_INVERTED, 0x1504)
-GLENUM(GL_NOOP, 0x1505)
-GLENUM(GL_XOR, 0x1506)
-GLENUM(GL_OR, 0x1507)
-GLENUM(GL_NOR, 0x1508)
-GLENUM(GL_EQUIV, 0x1509)
-GLENUM(GL_INVERT, 0x150A)
-GLENUM(GL_OR_REVERSE, 0x150B)
-GLENUM(GL_COPY_INVERTED, 0x150C)
-GLENUM(GL_OR_INVERTED, 0x150D)
-GLENUM(GL_NAND, 0x150E)
-GLENUM(GL_SET, 0x150F)
-GLENUM(GL_EMISSION, 0x1600)
-GLENUM(GL_SHININESS, 0x1601)
-GLENUM(GL_AMBIENT_AND_DIFFUSE, 0x1602)
-GLENUM(GL_MODELVIEW, 0x1700)
-GLENUM(GL_PROJECTION, 0x1701)
-GLENUM(GL_TEXTURE, 0x1702)
-GLENUM(GL_ALPHA, 0x1906)
-GLENUM(GL_RGB, 0x1907)
-GLENUM(GL_RGBA, 0x1908)
-GLENUM(GL_LUMINANCE, 0x1909)
-GLENUM(GL_LUMINANCE_ALPHA, 0x190A)
-GLENUM(GL_FLAT, 0x1D00)
-GLENUM(GL_SMOOTH, 0x1D01)
-GLENUM(GL_KEEP, 0x1E00)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_INCR, 0x1E02)
-GLENUM(GL_DECR, 0x1E03)
-GLENUM(GL_VENDOR, 0x1F00)
-GLENUM(GL_RENDERER, 0x1F01)
-GLENUM(GL_VERSION, 0x1F02)
-GLENUM(GL_EXTENSIONS, 0x1F03)
-GLENUM(GL_MODULATE, 0x2100)
-GLENUM(GL_DECAL, 0x2101)
-GLENUM(GL_TEXTURE_ENV_MODE, 0x2200)
-GLENUM(GL_TEXTURE_ENV_COLOR, 0x2201)
-GLENUM(GL_TEXTURE_ENV, 0x2300)
-GLENUM(GL_NEAREST, 0x2600)
-GLENUM(GL_LINEAR, 0x2601)
-GLENUM(GL_NEAREST_MIPMAP_NEAREST, 0x2700)
-GLENUM(GL_LINEAR_MIPMAP_NEAREST, 0x2701)
-GLENUM(GL_NEAREST_MIPMAP_LINEAR, 0x2702)
-GLENUM(GL_LINEAR_MIPMAP_LINEAR, 0x2703)
-GLENUM(GL_TEXTURE_MAG_FILTER, 0x2800)
-GLENUM(GL_TEXTURE_MIN_FILTER, 0x2801)
-GLENUM(GL_TEXTURE_WRAP_S, 0x2802)
-GLENUM(GL_TEXTURE_WRAP_T, 0x2803)
-GLENUM(GL_CLAMP, 0x2900)
-GLENUM(GL_REPEAT, 0x2901)
-GLENUM(GL_CLIP_PLANE0, 0x3000)
-GLENUM(GL_CLIP_PLANE1, 0x3001)
-GLENUM(GL_CLIP_PLANE2, 0x3002)
-GLENUM(GL_CLIP_PLANE3, 0x3003)
-GLENUM(GL_CLIP_PLANE4, 0x3004)
-GLENUM(GL_CLIP_PLANE5, 0x3005)
-GLENUM(GL_LIGHT0, 0x4000)
-GLENUM(GL_LIGHT1, 0x4001)
-GLENUM(GL_LIGHT2, 0x4002)
-GLENUM(GL_LIGHT3, 0x4003)
-GLENUM(GL_LIGHT4, 0x4004)
-GLENUM(GL_LIGHT5, 0x4005)
-GLENUM(GL_LIGHT6, 0x4006)
-GLENUM(GL_LIGHT7, 0x4007)
-GLENUM(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0x7E80)
-GLENUM(GL_UNSIGNED_SHORT_4_4_4_4, 0x8033)
-GLENUM(GL_UNSIGNED_SHORT_5_5_5_1, 0x8034)
-GLENUM(GL_POLYGON_OFFSET_FILL, 0x8037)
-GLENUM(GL_RESCALE_NORMAL, 0x803A)
-GLENUM(GL_VERTEX_ARRAY, 0x8074)
-GLENUM(GL_NORMAL_ARRAY, 0x8075)
-GLENUM(GL_COLOR_ARRAY, 0x8076)
-GLENUM(GL_TEXTURE_COORD_ARRAY, 0x8078)
-GLENUM(GL_MULTISAMPLE, 0x809D)
-GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE, 0x809E)
-GLENUM(GL_SAMPLE_ALPHA_TO_ONE, 0x809F)
-GLENUM(GL_SAMPLE_COVERAGE, 0x80A0)
-GLENUM(GL_MAX_ELEMENTS_VERTICES, 0x80E8)
-GLENUM(GL_MAX_ELEMENTS_INDICES, 0x80E9)
-GLENUM(GL_CLAMP_TO_EDGE, 0x812F)
-GLENUM(GL_GENERATE_MIPMAP, 0x8191)
-GLENUM(GL_GENERATE_MIPMAP_HINT, 0x8192)
-GLENUM(GL_UNSIGNED_SHORT_5_6_5, 0x8363)
-GLENUM(GL_ALIASED_POINT_SIZE_RANGE, 0x846D)
-GLENUM(GL_ALIASED_LINE_WIDTH_RANGE, 0x846E)
-GLENUM(GL_TEXTURE0, 0x84C0)
-GLENUM(GL_TEXTURE1, 0x84C1)
-GLENUM(GL_TEXTURE2, 0x84C2)
-GLENUM(GL_TEXTURE3, 0x84C3)
-GLENUM(GL_TEXTURE4, 0x84C4)
-GLENUM(GL_TEXTURE5, 0x84C5)
-GLENUM(GL_TEXTURE6, 0x84C6)
-GLENUM(GL_TEXTURE7, 0x84C7)
-GLENUM(GL_TEXTURE8, 0x84C8)
-GLENUM(GL_TEXTURE9, 0x84C9)
-GLENUM(GL_TEXTURE10, 0x84CA)
-GLENUM(GL_TEXTURE11, 0x84CB)
-GLENUM(GL_TEXTURE12, 0x84CC)
-GLENUM(GL_TEXTURE13, 0x84CD)
-GLENUM(GL_TEXTURE14, 0x84CE)
-GLENUM(GL_TEXTURE15, 0x84CF)
-GLENUM(GL_TEXTURE16, 0x84D0)
-GLENUM(GL_TEXTURE17, 0x84D1)
-GLENUM(GL_TEXTURE18, 0x84D2)
-GLENUM(GL_TEXTURE19, 0x84D3)
-GLENUM(GL_TEXTURE20, 0x84D4)
-GLENUM(GL_TEXTURE21, 0x84D5)
-GLENUM(GL_TEXTURE22, 0x84D6)
-GLENUM(GL_TEXTURE23, 0x84D7)
-GLENUM(GL_TEXTURE24, 0x84D8)
-GLENUM(GL_TEXTURE25, 0x84D9)
-GLENUM(GL_TEXTURE26, 0x84DA)
-GLENUM(GL_TEXTURE27, 0x84DB)
-GLENUM(GL_TEXTURE28, 0x84DC)
-GLENUM(GL_TEXTURE29, 0x84DD)
-GLENUM(GL_TEXTURE30, 0x84DE)
-GLENUM(GL_TEXTURE31, 0x84DF)
-GLENUM(GL_MAX_TEXTURE_UNITS, 0x84E2)
-GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 0x86A2)
-GLENUM(GL_COMPRESSED_TEXTURE_FORMATS, 0x86A3)
-GLENUM(GL_BUFFER_SIZE, 0x8764)
-GLENUM(GL_BUFFER_USAGE, 0x8765)
-GLENUM(GL_POINT_SPRITE_OES, 0x8861)
-GLENUM(GL_COORD_REPLACE_OES, 0x8862)
-GLENUM(GL_ARRAY_BUFFER, 0x8892)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER, 0x8893)
-GLENUM(GL_ARRAY_BUFFER_BINDING, 0x8894)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0x8895)
-GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING, 0x8896)
-GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING, 0x8897)
-GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING, 0x8898)
-GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, 0x889A)
-GLENUM(GL_STATIC_DRAW, 0x88E4)
-GLENUM(GL_DYNAMIC_DRAW, 0x88E8)
-GLENUM(GL_POINT_SIZE_ARRAY_TYPE_OES, 0x898A)
-GLENUM(GL_POINT_SIZE_ARRAY_STRIDE_OES, 0x898B)
-GLENUM(GL_POINT_SIZE_ARRAY_POINTER_OES, 0x898C)
-GLENUM(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898D)
-GLENUM(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898E)
-GLENUM(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898F)
-GLENUM(GL_PALETTE4_RGB8_OES, 0x8B90)
-GLENUM(GL_PALETTE4_RGBA8_OES, 0x8B91)
-GLENUM(GL_PALETTE4_R5_G6_B5_OES, 0x8B92)
-GLENUM(GL_PALETTE4_RGBA4_OES, 0x8B93)
-GLENUM(GL_PALETTE4_RGB5_A1_OES, 0x8B94)
-GLENUM(GL_PALETTE8_RGB8_OES, 0x8B95)
-GLENUM(GL_PALETTE8_RGBA8_OES, 0x8B96)
-GLENUM(GL_PALETTE8_R5_G6_B5_OES, 0x8B97)
-GLENUM(GL_PALETTE8_RGBA4_OES, 0x8B98)
-GLENUM(GL_PALETTE8_RGB5_A1_OES, 0x8B99)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, 0x8B9A)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, 0x8B9B)
-GLENUM(GL_POINT_SIZE_ARRAY_OES, 0x8B9C)
-GLENUM(GL_TEXTURE_CROP_RECT_OES, 0x8B9D)
-GLENUM(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, 0x8B9F)
diff --git a/opengl/libs/glext_entries.in b/opengl/libs/glext_entries.in
deleted file mode 100644
index dd09c71..0000000
--- a/opengl/libs/glext_entries.in
+++ /dev/null
@@ -1,90 +0,0 @@
-GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
-GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-GL_ENTRY(void, glBlendEquationOES, GLenum mode)
-GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
-GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
-GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
-GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
-GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
-GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
-GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
-GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
-GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
-GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
-GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
-GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
-GL_ENTRY(void, glClearDepthxOES, GLclampx depth)
-GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
-GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
-GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar)
-GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
-GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
-GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4])
-GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
-GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
-GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
-GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glLineWidthxOES, GLfixed width)
-GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
-GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
-GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
-GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
-GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
-GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
-GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
-GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glPointSizexOES, GLfixed size)
-GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
-GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
-GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
-GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
-GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
-GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
-GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
-GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
-GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
-GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
-GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
-GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
-GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
-GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
-GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
-GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
-GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
-GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
-GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
-GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params)
-GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
-GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
-GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
-GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar)
-GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
-GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
-GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
-GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4])
-GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
-GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
-GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
-GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
-GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
-GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
-GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
-GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
-GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
-GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index fd97254..f47f093 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -21,10 +21,14 @@
#include <string.h>
#include <errno.h>
+#include <pthread.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#if !defined(__arm__)
#define USE_SLOW_BINDING 1
@@ -56,15 +60,14 @@ const unsigned int NUM_DISPLAYS = 1;
enum {
IMPL_HARDWARE = 0,
IMPL_SOFTWARE,
-
- IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
-
- IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
- IMPL_NO_CONTEXT,
-
IMPL_NUM_IMPLEMENTATIONS
};
+enum {
+ GLESv1_INDEX = 0,
+ GLESv2_INDEX = 1,
+};
+
// ----------------------------------------------------------------------------
// GL / EGL hooks
@@ -74,14 +77,14 @@ enum {
#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
#define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+struct egl_t {
+ #include "EGL/egl_entries.in"
+};
+
struct gl_hooks_t {
struct gl_t {
- #include "gl_entries.in"
- #include "glext_entries.in"
+ #include "entries.in"
} gl;
- struct egl_t {
- #include "egl_entries.in"
- } egl;
struct gl_ext_t {
void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
} ext;
@@ -92,8 +95,15 @@ struct gl_hooks_t {
// ----------------------------------------------------------------------------
-extern gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooksNoContext;
extern pthread_key_t gGLWrapperKey;
+extern "C" void gl_unimplemented();
+
+extern char const * const gl_names[];
+extern char const * const egl_names[];
+
+// ----------------------------------------------------------------------------
#if USE_FAST_TLS_KEY
@@ -114,7 +124,7 @@ static gl_hooks_t const* getGlThreadSpecific() {
gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
if (hooks) return hooks;
- return &gHooks[IMPL_NO_CONTEXT];
+ return &gHooksNoContext;
}
#else
@@ -126,7 +136,7 @@ static inline void setGlThreadSpecific(gl_hooks_t const *value) {
static gl_hooks_t const* getGlThreadSpecific() {
gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
if (hooks) return hooks;
- return &gHooks[IMPL_NO_CONTEXT];
+ return &gHooksNoContext;
}
#endif
diff --git a/opengl/libs/tools/enumextract.sh b/opengl/libs/tools/enumextract.sh
deleted file mode 100644
index 5707302..0000000
--- a/opengl/libs/tools/enumextract.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-awk '
-/^#define GL_/ {
- names[count] = $2;
- values[count] = $3;
- sort[count] = $3 + 0;
- count++;
-}
-END {
- for (i = 1; i < count; i++) {
- for (j = 0; j < i; j++) {
- if (sort[i] < sort[j]) {
- tn = names[i];
- tv = values[i];
- ts = sort[i];
- names[i] = names[j];
- values[i] = values[j];
- sort[i] = sort[j];
- names[j] = tn;
- values[j] = tv;
- sort[j] = ts;
- }
- }
- }
-
- for (i = 0; i < count; i++) {
- printf("GLENUM(%s, %s)\n", names[i], values[i]);
- }
-}
-' < $1
-
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
index 107768b..120cb4b 100755
--- a/opengl/libs/tools/genfiles
+++ b/opengl/libs/tools/genfiles
@@ -14,7 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in
-./glentrygen ../../include/GLES/gl.h > ../gl_entries.in
-./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in
-./glentrygen ../../include/GLES/glext.h > ../glext_entries.in
+./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in
+./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in
+./glapigen ../../include/GLES2/gl2.h > ../GLES2/gl2_api.in
+./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in
+
+./glentrygen ../../include/GLES/gl.h > /tmp/gl_entries.in
+./glentrygen ../../include/GLES/glext.h > /tmp/glext_entries.in
+./glentrygen ../../include/GLES2/gl2.h > /tmp/gl2_entries.in
+./glentrygen ../../include/GLES2/gl2ext.h > /tmp/gl2ext_entries.in
+
+cat /tmp/gl_entries.in \
+ /tmp/glext_entries.in \
+ /tmp/gl2_entries.in \
+ /tmp/gl2ext_entries.in \
+ | sort -t, -k2 \
+ | awk -F, '!_[$2]++' \
+ > ../entries.in
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index a2c3a7b..bd8dda3 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
#printf("%s", $line);
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
index 5e0f7b6..170f041 100755
--- a/opengl/libs/tools/glentrygen
+++ b/opengl/libs/tools/glentrygen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
}
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index e193483..d0c3221 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -2,7 +2,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.c demo.c.arm
+LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
LOCAL_MODULE:= angeles
LOCAL_MODULE_TAGS := optional
diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.cpp
index 7d0d320..06fa0c2 100644
--- a/opengl/tests/angeles/app-linux.c
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -52,6 +52,11 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
#include "app.h"
@@ -115,48 +120,33 @@ static void checkEGLErrors()
static int initGraphics()
{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- #if 1
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, 0,
- #else
- EGL_ALPHA_SIZE, EGL_DONT_CARE,
- EGL_DEPTH_SIZE, EGL_DONT_CARE,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_SURFACE_TYPE, EGL_DONT_CARE,
- #endif
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 16,
EGL_NONE
};
- EGLint numConfigs = -1;
EGLint majorVersion;
EGLint minorVersion;
- EGLConfig config;
EGLContext context;
+ EGLConfig config;
EGLSurface surface;
-
+ EGLint w, h;
EGLDisplay dpy;
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- egl_error("eglGetDisplay");
- fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy);
+ EGLNativeWindowType window = android_createDisplaySurface();
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(dpy, &majorVersion, &minorVersion);
- egl_error("eglInitialize");
-
- eglGetConfigs(dpy, NULL, 0, &numConfigs);
- egl_error("eglGetConfigs");
- fprintf(stderr,"num configs %d\n", numConfigs);
-
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- egl_error("eglChooseConfig");
-
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- egl_error("eglMapWindowSurface");
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ egl_error("eglCreateWindowSurface");
fprintf(stderr,"surface = %p\n", surface);
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
new file mode 100644
index 0000000..a7d30c2
--- /dev/null
+++ b/opengl/tests/fillrate/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ fillrate.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-fillrate
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
new file mode 100644
index 0000000..911d354
--- /dev/null
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -0,0 +1,161 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ uint32_t* t32 = (uint32_t*)malloc(512*512*4);
+ for (int y=0 ; y<512 ; y++) {
+ for (int x=0 ; x<512 ; x++) {
+ int u = x-256;
+ int v = y-256;
+ if (u*u+v*v < 256*256) {
+ t32[x+y*512] = 0x10FFFFFF;
+ } else {
+ t32[x+y*512] = 0x20FF0000;
+ }
+ }
+ }
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ eglSwapBuffers(dpy, surface);
+
+
+ nsecs_t times[32];
+
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ // for (int c=31 ; c>=1 ; c--) {
+ int j=0;
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ nsecs_t now = systemTime();
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ nsecs_t t = systemTime() - now;
+ times[j++] = t;
+ }
+
+ for (int c=1, j=0 ; c<32 ; c++, j++) {
+ nsecs_t t = times[j];
+ printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+ }
+
+
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index 31b7d9a..a254127 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- filter.c
+ filter.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-filter
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.cpp
index de97119..2351909 100644
--- a/opengl/tests/filter/filter.c
+++ b/opengl/tests/filter/filter.cpp
@@ -5,6 +5,13 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+#define USE_DRAW_TEXTURE 1
+
int main(int argc, char** argv)
{
if (argc!=2 && argc!=3) {
@@ -32,14 +39,20 @@ int main(int argc, char** argv)
EGLDisplay dpy;
+ EGLNativeWindowType window = 0;
+ if (!usePbuffer) {
+ window = android_createDisplaySurface();
+ }
+
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
if (!usePbuffer) {
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
+ EGLUtils::selectConfigForNativeWindow(
+ dpy, s_configAttribs, window, &config);
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
} else {
printf("using pbuffer\n");
+ eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
surface = eglCreatePbufferSurface(dpy, config, attribs);
if (surface == EGL_NO_SURFACE) {
@@ -52,6 +65,12 @@ int main(int argc, char** argv)
eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
GLint dim = w<h ? w : h;
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
GLint crop[4] = { 0, 4, 4, -4 };
@@ -117,14 +136,55 @@ int main(int argc, char** argv)
break;
}
- glDrawTexiOES(0, 0, 0, dim, dim);
+ //glDrawTexiOES(0, 0, 0, dim, dim);
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, dim },
+ { dim, dim },
+ { dim, 0 }
+ };
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
if (!usePbuffer) {
eglSwapBuffers(dpy, surface);
- } else {
- glFinish();
}
+ glMatrixMode(GL_MODELVIEW);
+ glScissor(0,dim,dim,h-dim);
+ glDisable(GL_SCISSOR_TEST);
+
+ for (int y=0 ; y<dim ; y++) {
+ //glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ //glEnable(GL_SCISSOR_TEST);
+
+#if USE_DRAW_TEXTURE && GL_OES_draw_texture
+ glDrawTexiOES(0, y, 1, dim, dim);
+#else
+ glLoadIdentity();
+ glTranslatef(0, y, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#endif
+
+ if (!usePbuffer) {
+ eglSwapBuffers(dpy, surface);
+ } else {
+ glFinish();
+ }
+ }
+
eglTerminate(dpy);
return 0;
}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 8b46cd7..5620814 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- finish.c
+ finish.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-finish
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.cpp
index 45fc758..91f5c45 100644
--- a/opengl/tests/finish/finish.c
+++ b/opengl/tests/finish/finish.cpp
@@ -24,39 +24,41 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <utils/Timers.h>
-long long systemTime()
-{
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
int main(int argc, char** argv)
{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
EGL_NONE
};
- EGLint numConfigs = -1;
EGLint majorVersion;
EGLint minorVersion;
- EGLConfig config;
EGLContext context;
+ EGLConfig config;
EGLSurface surface;
EGLint w, h;
-
EGLDisplay dpy;
+ EGLNativeWindowType window = android_createDisplaySurface();
+
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
context = eglCreateContext(dpy, config, NULL, NULL);
eglMakeCurrent(dpy, surface, surface, context);
eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
@@ -75,13 +77,13 @@ int main(int argc, char** argv)
long long now, t;
int i;
- char* texels = malloc(512*512*2);
+ char* texels = (char*)malloc(512*512*2);
memset(texels,0xFF,512*512*2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
- char* dst = malloc(320*480*2);
+ char* dst = (char*)malloc(320*480*2);
memset(dst, 0, 320*480*2);
printf("307200 bytes memcpy\n");
for (i=0 ; i<4 ; i++) {
diff --git a/opengl/tests/gl2_basic/Android.mk b/opengl/tests/gl2_basic/Android.mk
new file mode 100644
index 0000000..a642eaf
--- /dev/null
+++ b/opengl/tests/gl2_basic/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl2_basic.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl2_basic
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
new file mode 100644
index 0000000..2361db5
--- /dev/null
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+static void printGLString(const char *name, GLenum s) {
+ // fprintf(stderr, "printGLString %s, %d\n", name, s);
+ const char *v = (const char *) glGetString(s);
+ // int error = glGetError();
+ // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+ // (unsigned int) v);
+ // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+ // fprintf(stderr, "GL %s = %s\n", name, v);
+ // else
+ // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+ fprintf(stderr, "GL %s = %s\n", name, v);
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+ "void main() {\n"
+ " gl_Position = vPosition;\n"
+ "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ fprintf(stderr, "Could not compile shader %d:\n%s\n",
+ shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ fprintf(stderr, "Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+}
+
+GLuint gProgram;
+GLuint gvPositionHandle;
+
+bool setupGraphics(int w, int h) {
+ gProgram = createProgram(gVertexShader, gFragmentShader);
+ if (!gProgram) {
+ return false;
+ }
+ gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+ checkGlError("glGetAttribLocation");
+ fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n",
+ gvPositionHandle);
+
+ glViewport(0, 0, w, h);
+ checkGlError("glViewport");
+ return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f };
+
+void renderFrame() {
+ glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ checkGlError("glClearColor");
+ glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ glUseProgram(gProgram);
+ checkGlError("glUseProgram");
+
+ glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+ checkGlError("glVertexAttribPointer");
+ glEnableVertexAttribArray(gvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ checkGlError("glDrawArrays");
+}
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_PRESERVED_RESOURCES),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ printf(" %s: ", names[j].name);
+ printf("%d (0x%x)", value, value);
+ }
+ }
+ printf("\n");
+}
+
+int printEGLConfigurations(EGLDisplay dpy) {
+ EGLint numConfig = 0;
+ EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ return false;
+ }
+
+ printf("Number of EGL configuration: %d\n", numConfig);
+
+ EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig);
+ if (! configs) {
+ printf("Could not allocate configs.\n");
+ return false;
+ }
+
+ returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ free(configs);
+ return false;
+ }
+
+ for(int i = 0; i < numConfig; i++) {
+ printf("Configuration %d\n", i);
+ printEGLConfiguration(dpy, configs[i]);
+ }
+
+ free(configs);
+ return true;
+}
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ if (!printEGLConfigurations(dpy)) {
+ printf("printEGLConfigurations failed\n");
+ return 0;
+ }
+
+ checkEglError("printEGLConfigurations");
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+ if (returnValue) {
+ printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+ return 0;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ printf("Chose this configuration:\n");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 0;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 0;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if(!setupGraphics(w, h)) {
+ fprintf(stderr, "Could not set up graphics.\n");
+ return 0;
+ }
+
+ for (;;) {
+ renderFrame();
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
new file mode 100644
index 0000000..81247df
--- /dev/null
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -0,0 +1,51 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GL2JNI
+
+LOCAL_JNI_SHARED_LIBRARIES := libgl2jni
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+# Optional tag would mean it doesn't get installed by default
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+ gl_code.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libEGL \
+ libGLESv2
+
+LOCAL_MODULE := libgl2jni
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl2_jni/AndroidManifest.xml b/opengl/tests/gl2_jni/AndroidManifest.xml
new file mode 100644
index 0000000..a72a6a5
--- /dev/null
+++ b/opengl/tests/gl2_jni/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.gl2jni">
+ <application
+ android:label="@string/gl2jni_activity">
+ <activity android:name="GL2JNIActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp
new file mode 100644
index 0000000..c2fabe6
--- /dev/null
+++ b/opengl/tests/gl2_jni/jni/gl_code.cpp
@@ -0,0 +1,165 @@
+// OpenGL ES 2.0 code
+
+#include <nativehelper/jni.h>
+#define LOG_TAG "GL2JNI gl_code.cpp"
+#include <utils/Log.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+static void printGLString(const char *name, GLenum s) {
+ const char *v = (const char *) glGetString(s);
+ LOGI("GL %s = %s\n", name, v);
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ LOGI("after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+ "void main() {\n"
+ " gl_Position = vPosition;\n"
+ "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ LOGE("Could not compile shader %d:\n%s\n",
+ shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ LOGE("Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+}
+
+GLuint gProgram;
+GLuint gvPositionHandle;
+
+bool setupGraphics(int w, int h) {
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ LOGI("setupGraphics(%d, %d)", w, h);
+ gProgram = createProgram(gVertexShader, gFragmentShader);
+ if (!gProgram) {
+ LOGE("Could not create program.");
+ return false;
+ }
+ gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+ checkGlError("glGetAttribLocation");
+ LOGI("glGetAttribLocation(\"vPosition\") = %d\n",
+ gvPositionHandle);
+
+ glViewport(0, 0, w, h);
+ checkGlError("glViewport");
+ return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f };
+
+void renderFrame() {
+ static float grey;
+ grey += 0.01f;
+ if (grey > 1.0f) {
+ grey = 0.0f;
+ }
+ glClearColor(grey, grey, grey, 1.0f);
+ checkGlError("glClearColor");
+ glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ glUseProgram(gProgram);
+ checkGlError("glUseProgram");
+
+ glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+ checkGlError("glVertexAttribPointer");
+ glEnableVertexAttribArray(gvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ checkGlError("glDrawArrays");
+}
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
+};
+
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ setupGraphics(width, height);
+}
+
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
+{
+ renderFrame();
+}
+
diff --git a/opengl/tests/gl2_jni/res/values/strings.xml b/opengl/tests/gl2_jni/res/values/strings.xml
new file mode 100644
index 0000000..e3f7331
--- /dev/null
+++ b/opengl/tests/gl2_jni/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="gl2jni_activity">GL2JNI</string>
+
+</resources>
+
diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java
new file mode 100644
index 0000000..c366a2c
--- /dev/null
+++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.gl2jni;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class GL2JNIActivity extends Activity {
+
+ GL2JNIView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new GL2JNIView(getApplication());
+ setContentView(mView);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/libs/utils/executablepath_linux.cpp b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java
index b8d2a3d..040a984 100644
--- a/libs/utils/executablepath_linux.cpp
+++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
+package com.android.gl2jni;
-void executablepath(char exe[PATH_MAX])
-{
- char proc[100];
- sprintf(proc, "/proc/%d/exe", getpid());
-
- int err = readlink(proc, exe, PATH_MAX);
-}
+// Wrapper for native library
+
+public class GL2JNILib {
+ static {
+ System.loadLibrary("gl2jni");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+ public static native void init(int width, int height);
+ public static native void step();
+}
diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
new file mode 100644
index 0000000..2dae090
--- /dev/null
+++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
@@ -0,0 +1,139 @@
+/*
+ * 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.gl2jni;
+/*
+ * 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.
+ */
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GL2JNIView extends GLSurfaceView {
+ private static String TAG = "GL2JNIView";
+ GL2JNIView(Context context) {
+ super(context);
+ init();
+ }
+
+ public GL2JNIView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setEGLContextFactory(new ContextFactory());
+ setEGLConfigChooser(new ConfigChooser());
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ Log.w(TAG, String.format("Found %d configurations", numConfigs));
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+ return configs[0];
+ }
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+ public void onDrawFrame(GL10 gl) {
+ GL2JNILib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GL2JNILib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+}
+
diff --git a/opengl/tests/gl_basic/Android.mk b/opengl/tests/gl_basic/Android.mk
new file mode 100644
index 0000000..6b6341f
--- /dev/null
+++ b/opengl/tests/gl_basic/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl_basic.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl_basic
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
new file mode 100644
index 0000000..7dc2378
--- /dev/null
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -0,0 +1,357 @@
+// Simple OpenGL ES 1.x application showing how to initialize and draw something.
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+using namespace android;
+
+EGLDisplay eglDisplay;
+EGLSurface eglSurface;
+EGLContext eglContext;
+GLuint texture;
+
+#define FIXED_ONE 0x10000
+#define ITERATIONS 50
+
+int init_gl_surface(void);
+void free_gl_surface(void);
+void init_scene(void);
+void render();
+void create_texture(void);
+int readTimer(void);
+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ, float upX, float upY,
+ float upZ)
+{
+ // See the OpenGL GLUT documentation for gluLookAt for a description
+ // of the algorithm. We implement it in a straightforward way:
+
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // Normalize up
+ float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+ upX *= rlup;
+ upY *= rlup;
+ upZ *= rlup;
+
+ // compute s = f x up (x means "cross product")
+
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ float m[16] ;
+ m[0] = sx;
+ m[1] = ux;
+ m[2] = -fx;
+ m[3] = 0.0f;
+
+ m[4] = sy;
+ m[5] = uy;
+ m[6] = -fy;
+ m[7] = 0.0f;
+
+ m[8] = sz;
+ m[9] = uz;
+ m[10] = -fz;
+ m[11] = 0.0f;
+
+ m[12] = 0.0f;
+ m[13] = 0.0f;
+ m[14] = 0.0f;
+ m[15] = 1.0f;
+
+ glMultMatrixf(m);
+ glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_PRESERVED_RESOURCES),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ printf(" %s: ", names[j].name);
+ printf("%d (0x%x)", value, value);
+ }
+ }
+ printf("\n");
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+int printEGLConfigurations(EGLDisplay dpy) {
+ EGLint numConfig = 0;
+ EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ return false;
+ }
+
+ printf("Number of EGL configurations: %d\n", numConfig);
+
+ EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig);
+ if (! configs) {
+ printf("Could not allocate configs.\n");
+ return false;
+ }
+
+ returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ free(configs);
+ return false;
+ }
+
+ for(int i = 0; i < numConfig; i++) {
+ printf("Configuration %d\n", i);
+ printEGLConfiguration(dpy, configs[i]);
+ }
+
+ free(configs);
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ int q;
+ int start, end;
+
+ printf("Initializing EGL...\n");
+
+ if(!init_gl_surface())
+ {
+ printf("GL initialisation failed - exiting\n");
+ return 0;
+ }
+
+ init_scene();
+
+ create_texture();
+
+ printf("Running...\n");
+
+ while(true) {
+ render();
+ }
+
+ free_gl_surface();
+
+ return 0;
+}
+
+int init_gl_surface(void)
+{
+ EGLint numConfigs = 1;
+ EGLConfig myConfig = {0};
+ EGLint attrib[] =
+ {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
+ {
+ printf("eglGetDisplay failed\n");
+ return 0;
+ }
+
+ if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )
+ {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ if (! printEGLConfigurations(eglDisplay)) {
+ printf("printEGLConfigurations failed.\n");
+ return 0;
+ }
+ EGLNativeWindowType window = android_createDisplaySurface();
+ EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);
+
+ if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
+ window, 0)) == EGL_NO_SURFACE )
+ {
+ printf("eglCreateWindowSurface failed\n");
+ return 0;
+ }
+
+ if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
+ {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+
+ if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )
+ {
+ printf("eglMakeCurrent failed\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+void free_gl_surface(void)
+{
+ if (eglDisplay != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT );
+ eglDestroyContext( eglDisplay, eglContext );
+ eglDestroySurface( eglDisplay, eglSurface );
+ eglTerminate( eglDisplay );
+ eglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void init_scene(void)
+{
+ glDisable(GL_DITHER);
+ glEnable(GL_CULL_FACE);
+
+ float ratio = 320.0f / 480.0f;
+ glViewport(0, 0, 320, 480);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ gluLookAt(
+ 0, 0, 3, // eye
+ 0, 0, 0, // center
+ 0, 1, 0); // up
+
+ glEnable(GL_TEXTURE_2D);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void create_texture(void)
+{
+ const unsigned int on = 0xff0000ff;
+ const unsigned int off = 0xffffffff;
+ const unsigned int pixels[] =
+ {
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ };
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+void render()
+{
+ int i, j;
+ int quads = 1;
+
+ const GLfloat vertices[] = {
+ -1, -1, 0,
+ 1, -1, 0,
+ 1, 1, 0,
+ -1, 1, 0
+ };
+
+ const GLfixed texCoords[] = {
+ 0, 0,
+ FIXED_ONE, 0,
+ FIXED_ONE, FIXED_ONE,
+ 0, FIXED_ONE
+ };
+
+ const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ glVertexPointer(3, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ glClearColor(1.0, 1.0, 1.0, 1.0);
+
+ int nelem = sizeof(indices)/sizeof(indices[0]);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices);
+ eglSwapBuffers(eglDisplay, eglSurface);
+}
+
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
new file mode 100644
index 0000000..4029fa1
--- /dev/null
+++ b/opengl/tests/gl_jni/Android.mk
@@ -0,0 +1,53 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GLJNI
+
+LOCAL_JNI_SHARED_LIBRARIES := libgljni
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+# Optional tag would mean it doesn't get installed by default
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+ gl_code.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libEGL \
+ libGLESv1_CM
+
+LOCAL_MODULE := libgljni
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl_jni/AndroidManifest.xml b/opengl/tests/gl_jni/AndroidManifest.xml
new file mode 100644
index 0000000..64bd6bf
--- /dev/null
+++ b/opengl/tests/gl_jni/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.gljni">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/gljni_activity">
+ <activity android:name="GLJNIActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
new file mode 100644
index 0000000..33b25ab
--- /dev/null
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -0,0 +1,183 @@
+// OpenGL ES 1.0 code
+
+#include <nativehelper/jni.h>
+#define LOG_TAG "GLJNI gl_code.cpp"
+#include <utils/Log.h>
+
+#include <GLES/gl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+GLuint texture;
+GLfloat background;
+
+#define FIXED_ONE 0x10000
+
+static void printGLString(const char *name, GLenum s) {
+ const char *v = (const char *) glGetString(s);
+ LOGI("GL %s = %s\n", name, v);
+}
+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ, float upX, float upY,
+ float upZ)
+{
+ // See the OpenGL GLUT documentation for gluLookAt for a description
+ // of the algorithm. We implement it in a straightforward way:
+
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // Normalize up
+ float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+ upX *= rlup;
+ upY *= rlup;
+ upZ *= rlup;
+
+ // compute s = f x up (x means "cross product")
+
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ float m[16] ;
+ m[0] = sx;
+ m[1] = ux;
+ m[2] = -fx;
+ m[3] = 0.0f;
+
+ m[4] = sy;
+ m[5] = uy;
+ m[6] = -fy;
+ m[7] = 0.0f;
+
+ m[8] = sz;
+ m[9] = uz;
+ m[10] = -fz;
+ m[11] = 0.0f;
+
+ m[12] = 0.0f;
+ m[13] = 0.0f;
+ m[14] = 0.0f;
+ m[15] = 1.0f;
+
+ glMultMatrixf(m);
+ glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+
+void init_scene(int width, int height)
+{
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ glDisable(GL_DITHER);
+ glEnable(GL_CULL_FACE);
+
+ float ratio = width / height;
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+ gluLookAt(
+ 0, 0, 3, // eye
+ 0, 0, 0, // center
+ 0, 1, 0); // up
+
+ glEnable(GL_TEXTURE_2D);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void create_texture()
+{
+ const unsigned int on = 0xff0000ff;
+ const unsigned int off = 0xffffffff;
+ const unsigned int pixels[] =
+ {
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ on, off, on, off, on, off, on, off,
+ off, on, off, on, off, on, off, on,
+ };
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj);
+};
+
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ init_scene(width, height);
+ create_texture();
+}
+
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
+{
+ const GLfloat vertices[] = {
+ -1, -1, 0,
+ 1, -1, 0,
+ 1, 1, 0,
+ -1, 1, 0
+ };
+
+ const GLfixed texCoords[] = {
+ 0, 0,
+ FIXED_ONE, 0,
+ FIXED_ONE, FIXED_ONE,
+ 0, FIXED_ONE
+ };
+
+ const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 };
+ glVertexPointer(3, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ int nelem = sizeof(quadIndices)/sizeof(quadIndices[0]);
+ static float grey;
+ grey += 0.01f;
+ if (grey > 1.0f) {
+ grey = 0.0f;
+ }
+ glClearColor(background, grey, grey, 1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices);
+}
+
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj)
+{
+ background = 1.0f - background;
+} \ No newline at end of file
diff --git a/opengl/tests/gl_jni/res/values/strings.xml b/opengl/tests/gl_jni/res/values/strings.xml
new file mode 100644
index 0000000..880f5c9
--- /dev/null
+++ b/opengl/tests/gl_jni/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="gljni_activity">GLJNI</string>
+
+</resources>
+
diff --git a/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java
new file mode 100644
index 0000000..c6f5313
--- /dev/null
+++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package com.android.gljni;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class GLJNIActivity extends Activity {
+
+ GLJNIView mView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new GLJNIView(getApplication());
+ mView.setFocusableInTouchMode(true);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/include/utils.h b/opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java
index 30648b1..f56d2af 100644
--- a/include/utils.h
+++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 The Android Open Source Project
+ * 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.
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-//
-// Handy utility functions and portability code. This file includes all
-// of the generally-useful headers in the "utils" directory.
-//
-#ifndef _LIBS_UTILS_H
-#define _LIBS_UTILS_H
+package com.android.gljni;
-#include <utils/ported.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/List.h>
-#include <utils/string_array.h>
-#include <utils/misc.h>
-#include <utils/Errors.h>
+// Wrapper for native library
-#endif // _LIBS_UTILS_H
+public class GLJNILib {
+
+ static {
+ System.loadLibrary("gljni");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+ public static native void init(int width, int height);
+ public static native void step();
+ public static native void changeBackground();
+}
diff --git a/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java
new file mode 100644
index 0000000..9a2c8c4
--- /dev/null
+++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.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.gljni;
+/*
+ * 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.
+ */
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GLJNIView extends GLSurfaceView {
+ GLJNIView(Context context) {
+ super(context);
+ init();
+ }
+
+ public GLJNIView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setRenderer(new Renderer());
+ }
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private static final String TAG = "Renderer";
+ public void onDrawFrame(GL10 gl) {
+ GLJNILib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLJNILib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ GLJNILib.changeBackground();
+ return true;
+ }
+}
+
diff --git a/opengl/tests/gralloc/Android.mk b/opengl/tests/gralloc/Android.mk
new file mode 100644
index 0000000..d43c39a
--- /dev/null
+++ b/opengl/tests/gralloc/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gralloc.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-opengl-gralloc
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gralloc/gralloc.cpp b/opengl/tests/gralloc/gralloc.cpp
new file mode 100644
index 0000000..8987040
--- /dev/null
+++ b/opengl/tests/gralloc/gralloc.cpp
@@ -0,0 +1,110 @@
+/*
+ **
+ ** 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.
+ */
+
+#define LOG_TAG "StopWatch"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <utils/StopWatch.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+
+using namespace android;
+
+void* lamecpy(void* d, void const* s, size_t size) {
+ char* dst = (char*)d;
+ char const* src = (char const*)s;
+ while (size) {
+ *dst++ = *src++;
+ size--;
+ }
+ return d;
+}
+
+int main(int argc, char** argv)
+{
+ size_t size = 128*256*4;
+ void* temp = malloc(size);
+ void* temp2 = malloc(size);
+ memset(temp, 0, size);
+ memset(temp2, 0, size);
+
+
+ sp<GraphicBuffer> buffer = new GraphicBuffer(128, 256, HAL_PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ status_t err = buffer->initCheck();
+ if (err != NO_ERROR) {
+ printf("%s\n", strerror(-err));
+ return 0;
+ }
+
+ void* vaddr;
+ buffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &vaddr);
+
+ {
+ StopWatch watch("memset");
+ for (int i=0 ; i<10 ; i++)
+ memset(vaddr, 0, size);
+ }
+
+ {
+ StopWatch watch("memcpy baseline");
+ for (int i=0 ; i<10 ; i++)
+ memcpy(temp, temp2, size);
+ }
+
+ {
+ StopWatch watch("memcpy from gralloc");
+ for (int i=0 ; i<10 ; i++)
+ memcpy(temp, vaddr, size);
+ }
+
+ {
+ StopWatch watch("memcpy into gralloc");
+ for (int i=0 ; i<10 ; i++)
+ memcpy(vaddr, temp, size);
+ }
+
+
+ {
+ StopWatch watch("lamecpy baseline");
+ for (int i=0 ; i<10 ; i++)
+ lamecpy(temp, temp2, size);
+ }
+
+ {
+ StopWatch watch("lamecpy from gralloc");
+ for (int i=0 ; i<10 ; i++)
+ lamecpy(temp, vaddr, size);
+ }
+
+ {
+ StopWatch watch("lamecpy into gralloc");
+ for (int i=0 ; i<10 ; i++)
+ lamecpy(vaddr, temp, size);
+ }
+
+ buffer->unlock();
+
+ return 0;
+}
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
new file mode 100644
index 0000000..6ff248d
--- /dev/null
+++ b/opengl/tests/linetex/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ linetex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-linetex
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
new file mode 100644
index 0000000..6842940
--- /dev/null
+++ b/opengl/tests/linetex/linetex.cpp
@@ -0,0 +1,116 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glDisable(GL_DITHER);
+ glDisable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+
+ // default pack-alignment is 4
+ const uint16_t t16[64] = { 0xFFFF, 0, 0xF800, 0, 0x07E0, 0, 0x001F, 0 };
+
+ const GLfloat vertices[4][2] = {
+ { w/2, 0 },
+ { w/2, h }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 1, 1 }
+ };
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_LINES, 0, 2);
+ eglSwapBuffers(dpy, surface);
+
+ usleep(5*1000000);
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
new file mode 100644
index 0000000..619447c
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ swapinterval.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-swapinterval
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
new file mode 100644
index 0000000..df53b62
--- /dev/null
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -0,0 +1,121 @@
+/*
+ **
+ ** Copyright 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 <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLint numConfigs=0;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+ eglGetConfigs(dpy, NULL, 0, &numConfigs);
+ printf("# configs = %d\n", numConfigs);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ if (surface == EGL_NO_SURFACE) {
+ EGLint err = eglGetError();
+ fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
+ EGLUtils::strerror(err), config, r,g,b,a);
+ return 0;
+ } else {
+ printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+ }
+
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+
+ glViewport(0, 0, w, h);
+ glOrthof(0, w, 0, h, 0, 1);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+
+
+ int time = 10;
+ printf("screen should flash red/green quickly for %d s...\n", time);
+
+ int c = 0;
+ nsecs_t start = systemTime();
+ nsecs_t t;
+ do {
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ glClearColor(0,1,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ t = systemTime() - start;
+ c += 2;
+ } while (int(ns2s(t))<=time);
+
+ double p = (double(t) / c) / 1000000000.0;
+ printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0);
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index 8d5f56d..b2fa185 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- textures.c
+ textures.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-textures
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.cpp
index 214291b..cbe8ffd 100644
--- a/opengl/tests/textures/textures.c
+++ b/opengl/tests/textures/textures.cpp
@@ -22,30 +22,39 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
int main(int argc, char** argv)
{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
EGL_NONE
};
- EGLint numConfigs = -1;
EGLint majorVersion;
EGLint minorVersion;
- EGLConfig config;
EGLContext context;
+ EGLConfig config;
EGLSurface surface;
EGLint w, h;
-
EGLDisplay dpy;
+ EGLNativeWindowType window = android_createDisplaySurface();
+
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
context = eglCreateContext(dpy, config, NULL, NULL);
eglMakeCurrent(dpy, surface, surface, context);
eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 76fd8dd..6db3f49 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- tritex.c
+ tritex.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/opengl/tests/tritex/tritex.c b/opengl/tests/tritex/tritex.cpp
index 60a7feb..3365ab4 100644
--- a/opengl/tests/tritex/tritex.c
+++ b/opengl/tests/tritex/tritex.cpp
@@ -6,10 +6,16 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
+
+using namespace android;
EGLDisplay eglDisplay;
EGLSurface eglSurface;
@@ -117,6 +123,7 @@ int init_gl_surface(void)
EGLConfig myConfig = {0};
EGLint attrib[] =
{
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, 16,
EGL_NONE
};
@@ -132,15 +139,12 @@ int init_gl_surface(void)
printf("eglInitialize failed\n");
return 0;
}
-
- if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE )
- {
- printf("eglChooseConfig failed\n");
- return 0;
- }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);
if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
- android_createDisplaySurface(), 0)) == EGL_NO_SURFACE )
+ window, 0)) == EGL_NO_SURFACE )
{
printf("eglCreateWindowSurface failed\n");
return 0;
@@ -239,12 +243,12 @@ void render(int quads)
0, FIXED_ONE
};
- const GLushort template[] = { 0, 1, 2, 0, 2, 3 };
+ const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 };
- GLushort* indices = (GLushort*)malloc(quads*sizeof(template));
+ GLushort* indices = (GLushort*)malloc(quads*sizeof(quadIndices));
for (i=0 ; i<quads ; i++)
- memcpy(indices+(sizeof(template)/sizeof(indices[0]))*i, template, sizeof(template));
+ memcpy(indices+(sizeof(quadIndices)/sizeof(indices[0]))*i, quadIndices, sizeof(quadIndices));
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
@@ -262,7 +266,7 @@ void render(int quads)
for (j=0 ; j<10 ; j++) {
printf("loop %d / 10 (%d quads / loop)\n", j, quads);
- int nelem = sizeof(template)/sizeof(template[0]);
+ int nelem = sizeof(quadIndices)/sizeof(quadIndices[0]);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, nelem*quads, GL_UNSIGNED_SHORT, indices);
eglSwapBuffers(eglDisplay, eglSurface);
diff --git a/opengl/tools/glgen/specs/gles11/checks.spec b/opengl/tools/glgen/specs/gles11/checks.spec
index e31a2ce..1468ab9 100644
--- a/opengl/tools/glgen/specs/gles11/checks.spec
+++ b/opengl/tools/glgen/specs/gles11/checks.spec
@@ -1,61 +1,62 @@
-glClipPlanef check eqn 4
-glClipPlanex check eqn 4
-glGetClipPlanefOES check eqn 4
-glGetClipPlanexOES check eqn 4
-glDeleteBuffers check buffers n
-glDeleteTextures check textures n
-glDrawElements check_AIOOBE indices count
-glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR
-glGenBuffers check buffers n
-glGenTextures check textures n
-glGetClipPlane check eqn 4
-glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS
-glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
-glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
-glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
-glGetTexParameter check params 1
-glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT
-glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
-glLoadMatrix check m 16
-glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
-glMultMatrix check m 16
-glPointParameter check params 1
-glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
-glTexImage2D nullAllowed
-glTexSubImage2D nullAllowed
-glBufferData nullAllowed
-glTexParameter check params 1
-glQueryMatrixxOES check mantissa 16 check exponent 16 return -1
-glDrawTexfvOES check coords 5
-glDrawTexivOES check coords 5
-glDrawTexsvOES check coords 5
-glDrawTexxvOES check coords 5
-glBindFramebufferOES unsupported
-glBindRenderbufferOES unsupported
-glBlendEquation unsupported
-glBlendEquationSeparate unsupported
-glBlendFuncSeparate unsupported
-glCheckFramebufferStatusOES unsupported return 0
-glCurrentPaletteMatrixOES unsupported
-glDeleteFramebuffersOES unsupported
-glDeleteRenderbuffersOES unsupported
-glFramebufferRenderbufferOES unsupported
-glFramebufferStorageOES unsupported
-glFramebufferTexture2DOES unsupported
-glGenFramebuffersOES unsupported
-glGenRenderbuffersOES unsupported
-glGenerateMipmapOES unsupported
-glGetBufferParameter unsupported
-glGetFramebufferAttachmentParameterivOES unsupported
-glGetRenderbufferParameterivOES unsupported
-glGetTexGen unsupported
-glIsFramebufferOES unsupported return JNI_FALSE
-glIsRenderbufferOES unsupported return JNI_FALSE
-glLoadPaletteFromModelViewMatrixOES unsupported
-glMatrixIndexPointerOES unsupported
-glRenderbufferStorageOES unsupported return false
-glTexGen unsupported
-glTexGenf unsupported
-glTexGeni unsupported
-glTexGenx unsupported
-glWeightPointerOES unsupported
+glClipPlanef check eqn 4
+glClipPlanex check eqn 4
+glGetClipPlanefOES check eqn 4
+glGetClipPlanexOES check eqn 4
+glDeleteBuffers check buffers n
+glDeleteTextures check textures n
+glDrawElements check_AIOOBE indices count
+glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR
+glGenBuffers check buffers n
+glGenTextures check textures n
+glGetClipPlane check eqn 4
+glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS
+glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
+glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
+glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
+glGetTexParameter check params 1
+glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT
+glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
+glLoadMatrix check m 16
+glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
+glMultMatrix check m 16
+glPointParameter check params 1
+glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
+glTexImage2D nullAllowed
+glTexSubImage2D nullAllowed
+glBufferData nullAllowed check data size
+glBufferSubData check data size
+glTexParameter check params 1
+glQueryMatrixxOES check mantissa 16 check exponent 16 return -1
+glDrawTexfvOES check coords 5
+glDrawTexivOES check coords 5
+glDrawTexsvOES check coords 5
+glDrawTexxvOES check coords 5
+glBindFramebufferOES unsupported
+glBindRenderbufferOES unsupported
+glBlendEquation unsupported
+glBlendEquationSeparate unsupported
+glBlendFuncSeparate unsupported
+glCheckFramebufferStatusOES unsupported return 0
+glCurrentPaletteMatrixOES unsupported
+glDeleteFramebuffersOES unsupported
+glDeleteRenderbuffersOES unsupported
+glFramebufferRenderbufferOES unsupported
+glFramebufferStorageOES unsupported
+glFramebufferTexture2DOES unsupported
+glGenFramebuffersOES unsupported
+glGenRenderbuffersOES unsupported
+glGenerateMipmapOES unsupported
+glGetBufferParameter unsupported
+glGetFramebufferAttachmentParameterivOES unsupported
+glGetRenderbufferParameterivOES unsupported
+glGetTexGen unsupported
+glIsFramebufferOES unsupported return JNI_FALSE
+glIsRenderbufferOES unsupported return JNI_FALSE
+glLoadPaletteFromModelViewMatrixOES unsupported
+glMatrixIndexPointerOES unsupported
+glRenderbufferStorageOES unsupported return false
+glTexGen unsupported
+glTexGenf unsupported
+glTexGeni unsupported
+glTexGenx unsupported
+glWeightPointerOES unsupported
diff --git a/opengl/tools/glgen/specs/jsr239/glspec-checks b/opengl/tools/glgen/specs/jsr239/glspec-checks
index 55840fa..063cdc7 100644
--- a/opengl/tools/glgen/specs/jsr239/glspec-checks
+++ b/opengl/tools/glgen/specs/jsr239/glspec-checks
@@ -1,59 +1,60 @@
-glClipPlanef check equation 4
-glClipPlanex check equation 4
-glDeleteBuffers check buffers n
-glDeleteTextures check textures n
-glDrawElements check_AIOOBE indices count
-glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR
-glGenBuffers check buffers n
-glGenTextures check textures n
-glGetClipPlane check eqn 4
-glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS
-glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
-glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
-glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
-glGetTexParameter check params 1
-glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT
-glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
-glLoadMatrix check m 16
-glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
-glMultMatrix check m 16
-glPointParameter check params 1
-glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
-glTexImage2D nullAllowed
-glTexSubImage2D nullAllowed
-glBufferData nullAllowed
-glTexParameter check params 1
-glQueryMatrixxOES check mantissa 16 check exponent 16 return -1
-glDrawTexfvOES check coords 5
-glDrawTexivOES check coords 5
-glDrawTexsvOES check coords 5
-glDrawTexxvOES check coords 5
-glBindFramebufferOES unsupported
-glBindRenderbufferOES unsupported
-glBlendEquation unsupported
-glBlendEquationSeparate unsupported
-glBlendFuncSeparate unsupported
-glCheckFramebufferStatusOES unsupported return 0
-glCurrentPaletteMatrixOES unsupported
-glDeleteFramebuffersOES unsupported
-glDeleteRenderbuffersOES unsupported
-glFramebufferRenderbufferOES unsupported
-glFramebufferStorageOES unsupported
-glFramebufferTexture2DOES unsupported
-glGenFramebuffersOES unsupported
-glGenRenderbuffersOES unsupported
-glGenerateMipmapOES unsupported
-glGetBufferParameter unsupported
-glGetFramebufferAttachmentParameterivOES unsupported
-glGetRenderbufferParameterivOES unsupported
-glGetTexGen unsupported
-glIsFramebufferOES unsupported return JNI_FALSE
-glIsRenderbufferOES unsupported return JNI_FALSE
-glLoadPaletteFromModelViewMatrixOES unsupported
-glMatrixIndexPointerOES unsupported
-glRenderbufferStorageOES unsupported return false
-glTexGen unsupported
-glTexGenf unsupported
-glTexGeni unsupported
-glTexGenx unsupported
-glWeightPointerOES unsupported
+glClipPlanef check equation 4
+glClipPlanex check equation 4
+glDeleteBuffers check buffers n
+glDeleteTextures check textures n
+glDrawElements check_AIOOBE indices count
+glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR
+glGenBuffers check buffers n
+glGenTextures check textures n
+glGetClipPlane check eqn 4
+glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS
+glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
+glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
+glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
+glGetTexParameter check params 1
+glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT
+glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION
+glLoadMatrix check m 16
+glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE
+glMultMatrix check m 16
+glPointParameter check params 1
+glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR
+glTexImage2D nullAllowed
+glTexSubImage2D nullAllowed
+glBufferData nullAllowed check data size
+glBufferSubData check data size
+glTexParameter check params 1
+glQueryMatrixxOES check mantissa 16 check exponent 16 return -1
+glDrawTexfvOES check coords 5
+glDrawTexivOES check coords 5
+glDrawTexsvOES check coords 5
+glDrawTexxvOES check coords 5
+glBindFramebufferOES unsupported
+glBindRenderbufferOES unsupported
+glBlendEquation unsupported
+glBlendEquationSeparate unsupported
+glBlendFuncSeparate unsupported
+glCheckFramebufferStatusOES unsupported return 0
+glCurrentPaletteMatrixOES unsupported
+glDeleteFramebuffersOES unsupported
+glDeleteRenderbuffersOES unsupported
+glFramebufferRenderbufferOES unsupported
+glFramebufferStorageOES unsupported
+glFramebufferTexture2DOES unsupported
+glGenFramebuffersOES unsupported
+glGenRenderbuffersOES unsupported
+glGenerateMipmapOES unsupported
+glGetBufferParameter unsupported
+glGetFramebufferAttachmentParameterivOES unsupported
+glGetRenderbufferParameterivOES unsupported
+glGetTexGen unsupported
+glIsFramebufferOES unsupported return JNI_FALSE
+glIsRenderbufferOES unsupported return JNI_FALSE
+glLoadPaletteFromModelViewMatrixOES unsupported
+glMatrixIndexPointerOES unsupported
+glRenderbufferStorageOES unsupported return false
+glTexGen unsupported
+glTexGenf unsupported
+glTexGeni unsupported
+glTexGenx unsupported
+glWeightPointerOES unsupported
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 7340357..2cdb244 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -893,7 +893,7 @@ public class JniCodeEmitter {
") getDirectBufferPointer(_env, " +
cname + "_buf);");
String iii = " ";
- out.println(iii + indent + "if ( ! " + cname + " ) {");
+ out.println(iii + indent + "if ( ! " + cname + " ) {");
out.println(iii + iii + indent + "return;");
out.println(iii + indent + "}");
} else {
@@ -907,13 +907,13 @@ public class JniCodeEmitter {
");");
}
+ emitNativeBoundsChecks(cfunc, cname, out, true,
+ emitExceptionCheck,
+ offset, remaining, nullAllowed ? " " : " ");
+
if (nullAllowed) {
out.println(indent + "}");
}
-
- emitNativeBoundsChecks(cfunc, cname, out, true,
- emitExceptionCheck,
- offset, remaining, " ");
}
}
}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index f71bbea..6df612e 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -45,18 +45,25 @@ public class VpnManager {
/** Key to the error code of a connectivity broadcast event. */
public static final String BROADCAST_ERROR_CODE = "err";
/** Error code to indicate an error from authentication. */
- public static final int VPN_ERROR_AUTH = 1;
+ public static final int VPN_ERROR_AUTH = 51;
/** Error code to indicate the connection attempt failed. */
- public static final int VPN_ERROR_CONNECTION_FAILED = 2;
+ public static final int VPN_ERROR_CONNECTION_FAILED = 101;
/** Error code to indicate the server is not known. */
- public static final int VPN_ERROR_UNKNOWN_SERVER = 3;
+ public static final int VPN_ERROR_UNKNOWN_SERVER = 102;
/** Error code to indicate an error from challenge response. */
- public static final int VPN_ERROR_CHALLENGE = 4;
+ public static final int VPN_ERROR_CHALLENGE = 5;
/** Error code to indicate an error of remote server hanging up. */
- public static final int VPN_ERROR_REMOTE_HUNG_UP = 5;
+ public static final int VPN_ERROR_REMOTE_HUNG_UP = 7;
+ /** Error code to indicate an error of remote PPP server hanging up. */
+ public static final int VPN_ERROR_REMOTE_PPP_HUNG_UP = 48;
+ /** Error code to indicate a PPP negotiation error. */
+ public static final int VPN_ERROR_PPP_NEGOTIATION_FAILED = 42;
/** Error code to indicate an error of losing connectivity. */
- public static final int VPN_ERROR_CONNECTION_LOST = 6;
- private static final int VPN_ERROR_NO_ERROR = 0;
+ public static final int VPN_ERROR_CONNECTION_LOST = 103;
+ /** Largest error code used by VPN. */
+ public static final int VPN_ERROR_LARGEST = 200;
+ /** Error code to indicate a successful connection. */
+ public static final int VPN_ERROR_NO_ERROR = 0;
public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index c7df943..356f8b1 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -16,26 +16,28 @@
package android.net.vpn;
+import com.android.internal.R;
+
/**
* Enumeration of all supported VPN types.
* {@hide}
*/
public enum VpnType {
- PPTP("PPTP", "", PptpProfile.class),
- L2TP("L2TP", "", L2tpProfile.class),
- L2TP_IPSEC_PSK("L2TP/IPSec PSK", "Pre-shared key based L2TP/IPSec VPN",
+ PPTP("PPTP", R.string.pptp_vpn_description, PptpProfile.class),
+ L2TP("L2TP", R.string.l2tp_vpn_description, L2tpProfile.class),
+ L2TP_IPSEC_PSK("L2TP/IPSec PSK", R.string.l2tp_ipsec_psk_vpn_description,
L2tpIpsecPskProfile.class),
- L2TP_IPSEC("L2TP/IPSec CRT", "Certificate based L2TP/IPSec VPN",
+ L2TP_IPSEC("L2TP/IPSec CRT", R.string.l2tp_ipsec_crt_vpn_description,
L2tpIpsecProfile.class);
private String mDisplayName;
- private String mDescription;
+ private int mDescriptionId;
private Class<? extends VpnProfile> mClass;
- VpnType(String displayName, String description,
+ VpnType(String displayName, int descriptionId,
Class<? extends VpnProfile> klass) {
mDisplayName = displayName;
- mDescription = description;
+ mDescriptionId = descriptionId;
mClass = klass;
}
@@ -43,8 +45,8 @@ public enum VpnType {
return mDisplayName;
}
- public String getDescription() {
- return mDescription;
+ public int getDescriptionId() {
+ return mDescriptionId;
}
public Class<? extends VpnProfile> getProfileClass() {