diff options
Diffstat (limited to 'libs')
138 files changed, 6667 insertions, 15534 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index f329ac4642c9..d57f2c9fdcec 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -619,7 +619,10 @@ status_t Parcel::writeCString(const char* str) status_t Parcel::writeString8(const String8& str) { status_t err = writeInt32(str.bytes()); - if (err == NO_ERROR) { + // only write string if its length is more than zero characters, + // as readString8 will only read if the length field is non-zero. + // this is slightly different from how writeString16 works. + if (str.bytes() > 0 && err == NO_ERROR) { err = write(str.string(), str.bytes()+1); } return err; diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk index 03ff229dacdf..2f16923de473 100644 --- a/libs/camera/Android.mk +++ b/libs/camera/Android.mk @@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libhardware \ libsurfaceflinger_client \ - libui + libui \ + libgui LOCAL_MODULE:= libcamera_client diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index 450971d39dba..907f119b8174 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -80,8 +80,9 @@ sp<Camera> Camera::create(const sp<ICamera>& camera) c->mStatus = NO_ERROR; c->mCamera = camera; camera->asBinder()->linkToDeath(c); + return c; } - return c; + return 0; } void Camera::init() @@ -181,6 +182,20 @@ status_t Camera::setPreviewDisplay(const sp<Surface>& surface) } } +// pass the buffered ISurfaceTexture to the camera service +status_t Camera::setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) +{ + LOGV("setPreviewTexture(%p)", surfaceTexture.get()); + sp <ICamera> c = mCamera; + if (c == 0) return NO_INIT; + if (surfaceTexture != 0) { + return c->setPreviewTexture(surfaceTexture); + } else { + LOGD("app passed NULL surface"); + return c->setPreviewTexture(0); + } +} + // start preview mode status_t Camera::startPreview() { diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp index 7ba8d120bea9..0881d65ae3d2 100644 --- a/libs/camera/ICamera.cpp +++ b/libs/camera/ICamera.cpp @@ -28,6 +28,7 @@ namespace android { enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, SET_PREVIEW_DISPLAY, + SET_PREVIEW_TEXTURE, SET_PREVIEW_CALLBACK_FLAG, START_PREVIEW, STOP_PREVIEW, @@ -78,6 +79,18 @@ public: return reply.readInt32(); } + // pass the buffered SurfaceTexture to the camera service + status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) + { + LOGV("setPreviewTexture"); + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + sp<IBinder> b(surfaceTexture->asBinder()); + data.writeStrongBinder(b); + remote()->transact(SET_PREVIEW_TEXTURE, data, &reply); + return reply.readInt32(); + } + // set the preview callback flag to affect how the received frames from // preview are handled. See Camera.h for details. void setPreviewCallbackFlag(int flag) @@ -296,6 +309,13 @@ status_t BnCamera::onTransact( reply->writeInt32(setPreviewDisplay(surface)); return NO_ERROR; } break; + case SET_PREVIEW_TEXTURE: { + LOGV("SET_PREVIEW_TEXTURE"); + CHECK_INTERFACE(ICamera, data, reply); + sp<ISurfaceTexture> st = interface_cast<ISurfaceTexture>(data.readStrongBinder()); + reply->writeInt32(setPreviewTexture(st)); + return NO_ERROR; + } break; case SET_PREVIEW_CALLBACK_FLAG: { LOGV("SET_PREVIEW_CALLBACK_TYPE"); CHECK_INTERFACE(ICamera, data, reply); diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index 249558ac8601..d1a6af1dc11b 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -4,17 +4,25 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ISensorEventConnection.cpp \ ISensorServer.cpp \ + ISurfaceTexture.cpp \ Sensor.cpp \ SensorChannel.cpp \ SensorEventQueue.cpp \ - SensorManager.cpp + SensorManager.cpp \ + SurfaceTexture.cpp \ + SurfaceTextureClient.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder \ libhardware \ - libhardware_legacy + libhardware_legacy \ + libui \ + libEGL \ + libGLESv2 \ + libsurfaceflinger_client + LOCAL_MODULE:= libgui diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp new file mode 100644 index 000000000000..d661fd57914e --- /dev/null +++ b/libs/gui/ISurfaceTexture.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Vector.h> +#include <utils/Timers.h> + +#include <binder/Parcel.h> +#include <binder/IInterface.h> + +#include <gui/ISurfaceTexture.h> + +namespace android { +// ---------------------------------------------------------------------------- + +enum { + REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + SET_BUFFER_COUNT, + DEQUEUE_BUFFER, + QUEUE_BUFFER, + CANCEL_BUFFER, + SET_CROP, + SET_TRANSFORM, + GET_ALLOCATOR, +}; + + +class BpSurfaceTexture : public BpInterface<ISurfaceTexture> +{ +public: + BpSurfaceTexture(const sp<IBinder>& impl) + : BpInterface<ISurfaceTexture>(impl) + { + } + + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(bufferIdx); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); + data.writeInt32(usage); + remote()->transact(REQUEST_BUFFER, data, &reply); + sp<GraphicBuffer> buffer; + bool nonNull = reply.readInt32(); + if (nonNull) { + buffer = new GraphicBuffer(); + reply.read(*buffer); + } + return buffer; + } + + virtual status_t setBufferCount(int bufferCount) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + remote()->transact(SET_BUFFER_COUNT, data, &reply); + status_t err = reply.readInt32(); + return err; + } + + virtual status_t dequeueBuffer(int *buf) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + remote()->transact(DEQUEUE_BUFFER, data, &reply); + *buf = reply.readInt32(); + int result = reply.readInt32(); + return result; + } + + virtual status_t queueBuffer(int buf) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(buf); + remote()->transact(QUEUE_BUFFER, data, &reply); + status_t result = reply.readInt32(); + return result; + } + + virtual void cancelBuffer(int buf) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(buf); + remote()->transact(CANCEL_BUFFER, data, &reply); + } + + virtual status_t setCrop(const Rect& reg) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeFloat(reg.left); + data.writeFloat(reg.top); + data.writeFloat(reg.right); + data.writeFloat(reg.bottom); + remote()->transact(SET_CROP, data, &reply); + status_t result = reply.readInt32(); + return result; + } + + virtual status_t setTransform(uint32_t transform) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(transform); + remote()->transact(SET_TRANSFORM, data, &reply); + status_t result = reply.readInt32(); + return result; + } + + virtual sp<IBinder> getAllocator() { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + remote()->transact(GET_ALLOCATOR, data, &reply); + return reply.readStrongBinder(); + } +}; + +IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture"); + +// ---------------------------------------------------------------------- + +status_t BnSurfaceTexture::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case REQUEST_BUFFER: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int bufferIdx = data.readInt32(); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + uint32_t format = data.readInt32(); + uint32_t usage = data.readInt32(); + sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, + usage)); + reply->writeInt32(buffer != 0); + if (buffer != 0) { + reply->write(*buffer); + } + return NO_ERROR; + } break; + case SET_BUFFER_COUNT: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int bufferCount = data.readInt32(); + int result = setBufferCount(bufferCount); + reply->writeInt32(result); + return NO_ERROR; + } break; + case DEQUEUE_BUFFER: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int buf; + int result = dequeueBuffer(&buf); + reply->writeInt32(buf); + reply->writeInt32(result); + return NO_ERROR; + } break; + case QUEUE_BUFFER: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int buf = data.readInt32(); + status_t result = queueBuffer(buf); + reply->writeInt32(result); + return NO_ERROR; + } break; + case CANCEL_BUFFER: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int buf = data.readInt32(); + cancelBuffer(buf); + return NO_ERROR; + } break; + case SET_CROP: { + Rect reg; + CHECK_INTERFACE(ISurfaceTexture, data, reply); + reg.left = data.readFloat(); + reg.top = data.readFloat(); + reg.right = data.readFloat(); + reg.bottom = data.readFloat(); + status_t result = setCrop(reg); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_TRANSFORM: { + Rect reg; + CHECK_INTERFACE(ISurfaceTexture, data, reply); + uint32_t transform = data.readInt32(); + status_t result = setTransform(transform); + reply->writeInt32(result); + return NO_ERROR; + } break; + case GET_ALLOCATOR: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + sp<IBinder> result = getAllocator(); + reply->writeStrongBinder(result); + return NO_ERROR; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp new file mode 100644 index 000000000000..223cf091e7bd --- /dev/null +++ b/libs/gui/SurfaceTexture.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceTexture" +//#define LOG_NDEBUG 0 + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <gui/SurfaceTexture.h> + +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/SurfaceComposerClient.h> +#include <surfaceflinger/IGraphicBufferAlloc.h> + +#include <utils/Log.h> + +namespace android { + +// Transform matrices +static float mtxIdentity[16] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, +}; +static float mtxFlipH[16] = { + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1, +}; +static float mtxFlipV[16] = { + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1, +}; +static float mtxRot90[16] = { + 0, 1, 0, 0, + -1, 0, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1, +}; +static float mtxRot180[16] = { + -1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 1, 1, 0, 1, +}; +static float mtxRot270[16] = { + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1, +}; + +static void mtxMul(float out[16], const float a[16], const float b[16]); + +SurfaceTexture::SurfaceTexture(GLuint tex) : + mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), + mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT), + mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) { + LOGV("SurfaceTexture::SurfaceTexture"); + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[i].mEglDisplay = EGL_NO_DISPLAY; + mSlots[i].mOwnedByClient = false; + } + sp<ISurfaceComposer> composer(ComposerService::getComposerService()); + mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); +} + +SurfaceTexture::~SurfaceTexture() { + LOGV("SurfaceTexture::~SurfaceTexture"); + freeAllBuffers(); +} + +status_t SurfaceTexture::setBufferCount(int bufferCount) { + LOGV("SurfaceTexture::setBufferCount"); + Mutex::Autolock lock(mMutex); + freeAllBuffers(); + mBufferCount = bufferCount; + mCurrentTexture = INVALID_BUFFER_SLOT; + mLastQueued = INVALID_BUFFER_SLOT; + return OK; +} + +sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + LOGV("SurfaceTexture::requestBuffer"); + Mutex::Autolock lock(mMutex); + if (buf < 0 || mBufferCount <= buf) { + LOGE("requestBuffer: slot index out of range [0, %d]: %d", + mBufferCount, buf); + return 0; + } + usage |= GraphicBuffer::USAGE_HW_TEXTURE; + sp<GraphicBuffer> graphicBuffer( + mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); + if (graphicBuffer == 0) { + LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); + } else { + mSlots[buf].mGraphicBuffer = graphicBuffer; + if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); + mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; + } + mAllocdBuffers.add(graphicBuffer); + } + return graphicBuffer; +} + +status_t SurfaceTexture::dequeueBuffer(int *buf) { + LOGV("SurfaceTexture::dequeueBuffer"); + Mutex::Autolock lock(mMutex); + int found = INVALID_BUFFER_SLOT; + for (int i = 0; i < mBufferCount; i++) { + if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) { + mSlots[i].mOwnedByClient = true; + found = i; + break; + } + } + if (found == INVALID_BUFFER_SLOT) { + return -EBUSY; + } + *buf = found; + return OK; +} + +status_t SurfaceTexture::queueBuffer(int buf) { + LOGV("SurfaceTexture::queueBuffer"); + Mutex::Autolock lock(mMutex); + if (buf < 0 || mBufferCount <= buf) { + LOGE("queueBuffer: slot index out of range [0, %d]: %d", + mBufferCount, buf); + return -EINVAL; + } else if (!mSlots[buf].mOwnedByClient) { + LOGE("queueBuffer: slot %d is not owned by the client", buf); + return -EINVAL; + } else if (mSlots[buf].mGraphicBuffer == 0) { + LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", + buf); + return -EINVAL; + } + mSlots[buf].mOwnedByClient = false; + mLastQueued = buf; + mLastQueuedCrop = mNextCrop; + mLastQueuedTransform = mNextTransform; + if (mFrameAvailableListener != 0) { + mFrameAvailableListener->onFrameAvailable(); + } + return OK; +} + +void SurfaceTexture::cancelBuffer(int buf) { + LOGV("SurfaceTexture::cancelBuffer"); + Mutex::Autolock lock(mMutex); + if (buf < 0 || mBufferCount <= buf) { + LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, + buf); + return; + } else if (!mSlots[buf].mOwnedByClient) { + LOGE("cancelBuffer: slot %d is not owned by the client", buf); + return; + } + mSlots[buf].mOwnedByClient = false; +} + +status_t SurfaceTexture::setCrop(const Rect& crop) { + LOGV("SurfaceTexture::setCrop"); + Mutex::Autolock lock(mMutex); + mNextCrop = crop; + return OK; +} + +status_t SurfaceTexture::setTransform(uint32_t transform) { + LOGV("SurfaceTexture::setTransform"); + Mutex::Autolock lock(mMutex); + mNextTransform = transform; + return OK; +} + +status_t SurfaceTexture::updateTexImage() { + LOGV("SurfaceTexture::updateTexImage"); + Mutex::Autolock lock(mMutex); + + // We always bind the texture even if we don't update its contents. + glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); + + // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT, + // so this check will fail until a buffer gets queued. + if (mCurrentTexture != mLastQueued) { + // Update the GL texture object. + EGLImageKHR image = mSlots[mLastQueued].mEglImage; + if (image == EGL_NO_IMAGE_KHR) { + EGLDisplay dpy = eglGetCurrentDisplay(); + sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer; + image = createImage(dpy, graphicBuffer); + mSlots[mLastQueued].mEglImage = image; + mSlots[mLastQueued].mEglDisplay = dpy; + } + + GLint error; + while ((error = glGetError()) != GL_NO_ERROR) { + LOGE("GL error cleared before updating SurfaceTexture: %#04x", error); + } + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); + bool failed = false; + while ((error = glGetError()) != GL_NO_ERROR) { + LOGE("error binding external texture image %p (slot %d): %#04x", + image, mLastQueued, error); + failed = true; + } + if (failed) { + return -EINVAL; + } + + // Update the SurfaceTexture state. + mCurrentTexture = mLastQueued; + mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; + mCurrentCrop = mLastQueuedCrop; + mCurrentTransform = mLastQueuedTransform; + } + return OK; +} + +void SurfaceTexture::getTransformMatrix(float mtx[16]) { + LOGV("SurfaceTexture::updateTexImage"); + Mutex::Autolock lock(mMutex); + + float xform[16]; + for (int i = 0; i < 16; i++) { + xform[i] = mtxIdentity[i]; + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + float result[16]; + mtxMul(result, xform, mtxFlipH); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + float result[16]; + mtxMul(result, xform, mtxFlipV); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + float result[16]; + mtxMul(result, xform, mtxRot90); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } + } + + sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer); + float tx, ty, sx, sy; + if (!mCurrentCrop.isEmpty()) { + tx = float(mCurrentCrop.left) / float(buf->getWidth()); + ty = float(buf->getHeight() - mCurrentCrop.bottom) / + float(buf->getHeight()); + sx = float(mCurrentCrop.width()) / float(buf->getWidth()); + sy = float(mCurrentCrop.height()) / float(buf->getHeight()); + } else { + tx = 0.0f; + ty = 0.0f; + sx = 1.0f; + sy = 1.0f; + } + float crop[16] = { + sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, 1, 0, + sx*tx, sy*ty, 0, 1, + }; + + float mtxBeforeFlipV[16]; + mtxMul(mtxBeforeFlipV, crop, xform); + + // SurfaceFlinger expects the top of its window textures to be at a Y + // coordinate of 0, so SurfaceTexture must behave the same way. We don't + // want to expose this to applications, however, so we must add an + // additional vertical flip to the transform after all the other transforms. + mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); +} + +void SurfaceTexture::setFrameAvailableListener( + const sp<FrameAvailableListener>& l) { + LOGV("SurfaceTexture::setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = l; +} + +sp<IBinder> SurfaceTexture::getAllocator() { + LOGV("SurfaceTexture::getAllocator"); + return mGraphicBufferAlloc->asBinder(); +} + +void SurfaceTexture::freeAllBuffers() { + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + mSlots[i].mGraphicBuffer = 0; + mSlots[i].mOwnedByClient = false; + if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); + mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[i].mEglDisplay = EGL_NO_DISPLAY; + } + } + + int exceptBuf = -1; + for (size_t i = 0; i < mAllocdBuffers.size(); i++) { + if (mAllocdBuffers[i] == mCurrentTextureBuf) { + exceptBuf = i; + break; + } + } + mAllocdBuffers.clear(); + if (exceptBuf >= 0) { + mAllocdBuffers.add(mCurrentTextureBuf); + } + mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf); +} + +EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, + const sp<GraphicBuffer>& graphicBuffer) { + EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); + EGLint attrs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE, + }; + EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); + EGLint error = eglGetError(); + if (error != EGL_SUCCESS) { + LOGE("error creating EGLImage: %#x", error); + } else if (image == EGL_NO_IMAGE_KHR) { + LOGE("no error reported, but no image was returned by " + "eglCreateImageKHR"); + } + return image; +} + +static void mtxMul(float out[16], const float a[16], const float b[16]) { + out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; + out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; + out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; + out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; + + out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; + out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; + out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; + out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; + + out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; + out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; + out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; + out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; + + out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; + out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; + out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; + out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; +} + +}; // namespace android diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp new file mode 100644 index 000000000000..ee14ac9006a4 --- /dev/null +++ b/libs/gui/SurfaceTextureClient.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceTextureClient" +//#define LOG_NDEBUG 0 + +#include <gui/SurfaceTextureClient.h> + +#include <utils/Log.h> + +namespace android { + +SurfaceTextureClient::SurfaceTextureClient( + const sp<ISurfaceTexture>& surfaceTexture): + mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1), + mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() { + // Initialize the ANativeWindow function pointers. + ANativeWindow::setSwapInterval = setSwapInterval; + ANativeWindow::dequeueBuffer = dequeueBuffer; + ANativeWindow::cancelBuffer = cancelBuffer; + ANativeWindow::lockBuffer = lockBuffer; + ANativeWindow::queueBuffer = queueBuffer; + ANativeWindow::query = query; + ANativeWindow::perform = perform; + + // Get a reference to the allocator. + mAllocator = mSurfaceTexture->getAllocator(); +} + +int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) { + SurfaceTextureClient* c = getSelf(window); + return c->setSwapInterval(interval); +} + +int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window, + android_native_buffer_t** buffer) { + SurfaceTextureClient* c = getSelf(window); + return c->dequeueBuffer(buffer); +} + +int SurfaceTextureClient::cancelBuffer(ANativeWindow* window, + android_native_buffer_t* buffer) { + SurfaceTextureClient* c = getSelf(window); + return c->cancelBuffer(buffer); +} + +int SurfaceTextureClient::lockBuffer(ANativeWindow* window, + android_native_buffer_t* buffer) { + SurfaceTextureClient* c = getSelf(window); + return c->lockBuffer(buffer); +} + +int SurfaceTextureClient::queueBuffer(ANativeWindow* window, + android_native_buffer_t* buffer) { + SurfaceTextureClient* c = getSelf(window); + return c->queueBuffer(buffer); +} + +int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) { + SurfaceTextureClient* c = getSelf(window); + return c->query(what, value); +} + +int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) { + va_list args; + va_start(args, operation); + SurfaceTextureClient* c = getSelf(window); + return c->perform(operation, args); +} + +int SurfaceTextureClient::setSwapInterval(int interval) { + return INVALID_OPERATION; +} + +int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { + LOGV("SurfaceTextureClient::dequeueBuffer"); + Mutex::Autolock lock(mMutex); + int buf = -1; + status_t err = mSurfaceTexture->dequeueBuffer(&buf); + if (err < 0) { + LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer failed: %d", err); + return err; + } + sp<GraphicBuffer>& gbuf(mSlots[buf]); + if (gbuf == 0 || gbuf->getWidth() != mReqWidth || + gbuf->getHeight() != mReqHeight || + uint32_t(gbuf->getPixelFormat()) != mReqFormat || + (gbuf->getUsage() & mReqUsage) != mReqUsage) { + gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight, + mReqFormat, mReqUsage); + if (gbuf == 0) { + LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed"); + return NO_MEMORY; + } + } + *buffer = gbuf.get(); + return OK; +} + +int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) { + LOGV("SurfaceTextureClient::cancelBuffer"); + Mutex::Autolock lock(mMutex); + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + if (mSlots[i]->handle == buffer->handle) { + mSurfaceTexture->cancelBuffer(i); + return OK; + } + } + return BAD_VALUE; +} + +int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) { + LOGV("SurfaceTextureClient::lockBuffer"); + Mutex::Autolock lock(mMutex); + return OK; +} + +int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { + LOGV("SurfaceTextureClient::queueBuffer"); + Mutex::Autolock lock(mMutex); + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + if (mSlots[i]->handle == buffer->handle) { + return mSurfaceTexture->queueBuffer(i); + } + } + LOGE("queueBuffer: unknown buffer queued"); + return BAD_VALUE; +} + +int SurfaceTextureClient::query(int what, int* value) { + LOGV("SurfaceTextureClient::query"); + Mutex::Autolock lock(mMutex); + // XXX: Implement this! + return INVALID_OPERATION; +} + +int SurfaceTextureClient::perform(int operation, va_list args) +{ + int res = NO_ERROR; + switch (operation) { + case NATIVE_WINDOW_CONNECT: + res = dispatchConnect(args); + break; + case NATIVE_WINDOW_DISCONNECT: + res = dispatchDisconnect(args); + break; + case NATIVE_WINDOW_SET_USAGE: + res = dispatchSetUsage(args); + break; + case NATIVE_WINDOW_SET_CROP: + res = dispatchSetCrop(args); + break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + res = dispatchSetBufferCount(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + res = dispatchSetBuffersGeometry(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: + res = dispatchSetBuffersTransform(args); + break; + default: + res = NAME_NOT_FOUND; + break; + } + return res; +} + +int SurfaceTextureClient::dispatchConnect(va_list args) { + int api = va_arg(args, int); + return connect(api); +} + +int SurfaceTextureClient::dispatchDisconnect(va_list args) { + int api = va_arg(args, int); + return disconnect(api); +} + +int SurfaceTextureClient::dispatchSetUsage(va_list args) { + int usage = va_arg(args, int); + return setUsage(usage); +} + +int SurfaceTextureClient::dispatchSetCrop(va_list args) { + android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); + return setCrop(reinterpret_cast<Rect const*>(rect)); +} + +int SurfaceTextureClient::dispatchSetBufferCount(va_list args) { + size_t bufferCount = va_arg(args, size_t); + return setBufferCount(bufferCount); +} + +int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + return setBuffersGeometry(w, h, f); +} + +int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { + int transform = va_arg(args, int); + return setBuffersTransform(transform); +} + +int SurfaceTextureClient::connect(int api) { + LOGV("SurfaceTextureClient::connect"); + // XXX: Implement this! + return INVALID_OPERATION; +} + +int SurfaceTextureClient::disconnect(int api) { + LOGV("SurfaceTextureClient::disconnect"); + // XXX: Implement this! + return INVALID_OPERATION; +} + +int SurfaceTextureClient::setUsage(uint32_t reqUsage) +{ + LOGV("SurfaceTextureClient::setUsage"); + Mutex::Autolock lock(mMutex); + mReqUsage = reqUsage; + return OK; +} + +int SurfaceTextureClient::setCrop(Rect const* rect) +{ + LOGV("SurfaceTextureClient::setCrop"); + Mutex::Autolock lock(mMutex); + + Rect realRect; + if (rect == NULL || rect->isEmpty()) { + realRect = Rect(0, 0); + } else { + realRect = *rect; + } + + status_t err = mSurfaceTexture->setCrop(*rect); + LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err)); + + return err; +} + +int SurfaceTextureClient::setBufferCount(int bufferCount) +{ + LOGV("SurfaceTextureClient::setBufferCount"); + Mutex::Autolock lock(mMutex); + + status_t err = mSurfaceTexture->setBufferCount(bufferCount); + LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); + + if (err == NO_ERROR) { + freeAllBuffers(); + } + + return err; +} + +int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format) +{ + LOGV("SurfaceTextureClient::setBuffersGeometry"); + Mutex::Autolock lock(mMutex); + + if (w<0 || h<0 || format<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + mReqWidth = w; + mReqHeight = h; + mReqFormat = format; + + status_t err = mSurfaceTexture->setCrop(Rect(0, 0)); + LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err)); + + return err; +} + +int SurfaceTextureClient::setBuffersTransform(int transform) +{ + LOGV("SurfaceTextureClient::setBuffersTransform"); + Mutex::Autolock lock(mMutex); + status_t err = mSurfaceTexture->setTransform(transform); + return err; +} + +void SurfaceTextureClient::freeAllBuffers() { + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + mSlots[i] = 0; + } +} + +}; // namespace android diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 29158e512692..38e0848d5b54 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -13,6 +13,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) FboCache.cpp \ GradientCache.cpp \ LayerCache.cpp \ + LayerRenderer.cpp \ Matrix.cpp \ OpenGLDebugRenderer.cpp \ OpenGLRenderer.cpp \ @@ -22,6 +23,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) Program.cpp \ ProgramCache.cpp \ ResourceCache.cpp \ + ShapeCache.cpp \ SkiaColorFilter.cpp \ SkiaShader.cpp \ TextureCache.cpp \ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 40dd11770f3a..4f5edd575926 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -20,6 +20,7 @@ #include "Caches.h" #include "Properties.h" +#include "LayerRenderer.h" namespace android { @@ -53,6 +54,10 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), mDebugLevel = readDebugLevel(); LOGD("Enabling debug mode %d", mDebugLevel); + +#if RENDER_LAYERS_AS_REGIONS + LOGD("Layers will be composited as regions"); +#endif } Caches::~Caches() { @@ -69,6 +74,16 @@ void Caches::dumpMemoryUsage() { LOGD(" LayerCache %8d / %8d", layerCache.getSize(), layerCache.getMaxSize()); LOGD(" GradientCache %8d / %8d", gradientCache.getSize(), gradientCache.getMaxSize()); LOGD(" PathCache %8d / %8d", pathCache.getSize(), pathCache.getMaxSize()); + LOGD(" CircleShapeCache %8d / %8d", + circleShapeCache.getSize(), circleShapeCache.getMaxSize()); + LOGD(" OvalShapeCache %8d / %8d", + ovalShapeCache.getSize(), ovalShapeCache.getMaxSize()); + LOGD(" RoundRectShapeCache %8d / %8d", + roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize()); + LOGD(" RectShapeCache %8d / %8d", + rectShapeCache.getSize(), rectShapeCache.getMaxSize()); + LOGD(" ArcShapeCache %8d / %8d", + arcShapeCache.getSize(), arcShapeCache.getMaxSize()); LOGD(" TextDropShadowCache %8d / %8d", dropShadowCache.getSize(), dropShadowCache.getMaxSize()); for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { @@ -85,6 +100,11 @@ void Caches::dumpMemoryUsage() { total += gradientCache.getSize(); total += pathCache.getSize(); total += dropShadowCache.getSize(); + total += roundRectShapeCache.getSize(); + total += circleShapeCache.getSize(); + total += ovalShapeCache.getSize(); + total += rectShapeCache.getSize(); + total += arcShapeCache.getSize(); for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { total += fontRenderer.getFontRendererSize(i); } @@ -102,6 +122,20 @@ void Caches::clearGarbage() { textureCache.clearGarbage(); gradientCache.clearGarbage(); pathCache.clearGarbage(); + + Mutex::Autolock _l(mGarbageLock); + + size_t count = mLayerGarbage.size(); + for (size_t i = 0; i < count; i++) { + Layer* layer = mLayerGarbage.itemAt(i); + LayerRenderer::destroyLayer(layer); + } + mLayerGarbage.clear(); +} + +void Caches::deleteLayerDeferred(Layer* layer) { + Mutex::Autolock _l(mGarbageLock); + mLayerGarbage.push(layer); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 318c12045fca..0a9335f23288 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -31,6 +31,7 @@ #include "GradientCache.h" #include "PatchCache.h" #include "ProgramCache.h" +#include "ShapeCache.h" #include "PathCache.h" #include "TextDropShadowCache.h" #include "FboCache.h" @@ -68,7 +69,7 @@ static const GLsizei gMeshCount = 4; struct CacheLogger { CacheLogger() { - LOGD("Creating caches"); + LOGD("Creating OpenGL renderer caches"); } }; // struct CacheLogger @@ -90,6 +91,9 @@ class Caches: public Singleton<Caches> { TextureVertex* mRegionMesh; GLuint mRegionMeshIndices; + mutable Mutex mGarbageLock; + Vector<Layer*> mLayerGarbage; + public: /** * Indicates whether the renderer is in debug mode. @@ -106,6 +110,11 @@ public: void clearGarbage(); /** + * Can be used to delete a layer from a non EGL thread. + */ + void deleteLayerDeferred(Layer* layer); + + /** * Binds the VBO used to render simple textured quads. */ void bindMeshBuffer(); @@ -151,6 +160,11 @@ public: GradientCache gradientCache; ProgramCache programCache; PathCache pathCache; + RoundRectShapeCache roundRectShapeCache; + CircleShapeCache circleShapeCache; + OvalShapeCache ovalShapeCache; + RectShapeCache rectShapeCache; + ArcShapeCache arcShapeCache; PatchCache patchCache; TextDropShadowCache dropShadowCache; FboCache fboCache; diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index ddbfa5e3ddb0..14471bc7b717 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -20,6 +20,9 @@ // Turn on to check for OpenGL errors on each frame #define DEBUG_OPENGL 1 +// Turn on to enable initialization information +#define DEBUG_INIT 0 + // Turn on to enable memory usage summary on each frame #define DEBUG_MEMORY_USAGE 0 @@ -37,11 +40,27 @@ // Turn on to display vertex and tex coords data about 9patch objects // This flag requires DEBUG_PATCHES to be turned on #define DEBUG_PATCHES_VERTICES 0 +// Turn on to display vertex and tex coords data used by empty quads +// in 9patch objects +// This flag requires DEBUG_PATCHES to be turned on +#define DEBUG_PATCHES_EMPTY_VERTICES 0 -// Turn on to display debug info about paths -#define DEBUG_PATHS 0 +// Turn on to display debug info about shapes +#define DEBUG_SHAPES 0 // Turn on to display debug info about textures #define DEBUG_TEXTURES 0 +// Turn on to display debug info about the layer renderer +#define DEBUG_LAYER_RENDERER 0 + +// Turn on to dump display list state +#define DEBUG_DISPLAY_LIST 0 + +#if DEBUG_INIT + #define INIT_LOGD(...) LOGD(__VA_ARGS__) +#else + #define INIT_LOGD(...) +#endif + #endif // ANDROID_HWUI_DEBUG_H diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 77d628a4ecd2..d5d2ba07154c 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -22,66 +22,91 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Defines +// Display list /////////////////////////////////////////////////////////////////////////////// -#define PATH_HEAP_SIZE 64 +const char* DisplayList::OP_NAMES[] = { + "Save", + "Restore", + "RestoreToCount", + "SaveLayer", + "SaveLayerAlpha", + "Translate", + "Rotate", + "Scale", + "Skew", + "SetMatrix", + "ConcatMatrix", + "ClipRect", + "DrawDisplayList", + "DrawLayer", + "DrawBitmap", + "DrawBitmapMatrix", + "DrawBitmapRect", + "DrawBitmapMesh", + "DrawPatch", + "DrawColor", + "DrawRect", + "DrawRoundRect", + "DrawCircle", + "DrawOval", + "DrawArc", + "DrawPath", + "DrawLines", + "DrawText", + "ResetShader", + "SetupShader", + "ResetColorFilter", + "SetupColorFilter", + "ResetShadow", + "SetupShadow", + "DrawGLFunction" +}; -/////////////////////////////////////////////////////////////////////////////// -// Helpers -/////////////////////////////////////////////////////////////////////////////// +DisplayList::DisplayList(const DisplayListRenderer& recorder) { + initFromDisplayListRenderer(recorder); +} -PathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { +DisplayList::~DisplayList() { + clearResources(); } -PathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { - int count = buffer.readS32(); +void DisplayList::clearResources() { + sk_free((void*) mReader.base()); - mPaths.setCount(count); - SkPath** ptr = mPaths.begin(); - SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath)); + Caches& caches = Caches::getInstance(); - for (int i = 0; i < count; i++) { - new (p) SkPath; - p->unflatten(buffer); - *ptr++ = p; - p++; + for (size_t i = 0; i < mBitmapResources.size(); i++) { + caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i)); } -} + mBitmapResources.clear(); -PathHeap::~PathHeap() { - SkPath** iter = mPaths.begin(); - SkPath** stop = mPaths.end(); - while (iter < stop) { - (*iter)->~SkPath(); - iter++; + for (size_t i = 0; i < mShaders.size(); i++) { + caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); } -} + mShaders.clear(); -int PathHeap::append(const SkPath& path) { - SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath)); - new (p) SkPath(path); - *mPaths.append() = p; - return mPaths.count(); -} + for (size_t i = 0; i < mPaints.size(); i++) { + delete mPaints.itemAt(i); + } + mPaints.clear(); -void PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const { - int count = mPaths.count(); + for (size_t i = 0; i < mPaths.size(); i++) { + delete mPaths.itemAt(i); + } + mPaths.clear(); + for (size_t i = 0; i < mOriginalPaths.size(); i++) { + caches.resourceCache.decrementRefcount(mOriginalPaths.itemAt(i)); + } + mOriginalPaths.clear(); - buffer.write32(count); - SkPath** iter = mPaths.begin(); - SkPath** stop = mPaths.end(); - while (iter < stop) { - (*iter)->flatten(buffer); - iter++; + for (size_t i = 0; i < mMatrices.size(); i++) { + delete mMatrices.itemAt(i); } + mMatrices.clear(); } -/////////////////////////////////////////////////////////////////////////////// -// Display list -/////////////////////////////////////////////////////////////////////////////// - -DisplayList::DisplayList(const DisplayListRenderer& recorder) { +void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) { const SkWriter32& writer = recorder.writeStream(); init(); @@ -89,17 +114,16 @@ DisplayList::DisplayList(const DisplayListRenderer& recorder) { return; } + if (reusing) { + // re-using display list - clear out previous allocations + clearResources(); + } + size_t size = writer.size(); void* buffer = sk_malloc_throw(size); writer.flatten(buffer); mReader.setMemory(buffer, size); - mRCPlayback.reset(&recorder.mRCRecorder); - mRCPlayback.setupBuffer(mReader); - - mTFPlayback.reset(&recorder.mTFRecorder); - mTFPlayback.setupBuffer(mReader); - Caches& caches = Caches::getInstance(); const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources(); @@ -109,11 +133,11 @@ DisplayList::DisplayList(const DisplayListRenderer& recorder) { caches.resourceCache.incrementRefcount(resource); } - const Vector<SkiaShader*> &shaderResources = recorder.getShaderResources(); - for (size_t i = 0; i < shaderResources.size(); i++) { - SkiaShader* resource = shaderResources.itemAt(i); - mShaderResources.add(resource); - caches.resourceCache.incrementRefcount(resource); + const Vector<SkiaShader*> &shaders = recorder.getShaders(); + for (size_t i = 0; i < shaders.size(); i++) { + SkiaShader* shader = shaders.itemAt(i); + mShaders.add(shader); + caches.resourceCache.incrementRefcount(shader); } const Vector<SkPaint*> &paints = recorder.getPaints(); @@ -121,133 +145,209 @@ DisplayList::DisplayList(const DisplayListRenderer& recorder) { mPaints.add(paints.itemAt(i)); } - const Vector<SkMatrix*> &matrices = recorder.getMatrices(); - for (size_t i = 0; i < matrices.size(); i++) { - mMatrices.add(matrices.itemAt(i)); + const Vector<SkPath*> &paths = recorder.getPaths(); + for (size_t i = 0; i < paths.size(); i++) { + mPaths.add(paths.itemAt(i)); } - mPathHeap = recorder.mPathHeap; - if (mPathHeap) { - mPathHeap->safeRef(); + const Vector<SkPath*> &originalPaths = recorder.getOriginalPaths(); + for (size_t i = 0; i < originalPaths.size(); i++) { + SkPath* path = originalPaths.itemAt(i); + mOriginalPaths.add(path); + caches.resourceCache.incrementRefcount(path); } -} - -DisplayList::~DisplayList() { - sk_free((void*) mReader.base()); - - Caches& caches = Caches::getInstance(); - for (size_t i = 0; i < mBitmapResources.size(); i++) { - caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i)); - } - mBitmapResources.clear(); - - for (size_t i = 0; i < mShaderResources.size(); i++) { - caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i)); - } - mShaderResources.clear(); - - for (size_t i = 0; i < mPaints.size(); i++) { - delete mPaints.itemAt(i); - } - mPaints.clear(); - - for (size_t i = 0; i < mMatrices.size(); i++) { - delete mMatrices.itemAt(i); - } - mMatrices.clear(); - - if (mPathHeap) { - for (int i = 0; i < mPathHeap->count(); i++) { - caches.pathCache.removeDeferred(&(*mPathHeap)[i]); - } - mPathHeap->safeUnref(); + const Vector<SkMatrix*> &matrices = recorder.getMatrices(); + for (size_t i = 0; i < matrices.size(); i++) { + mMatrices.add(matrices.itemAt(i)); } } void DisplayList::init() { - mPathHeap = NULL; } -void DisplayList::replay(OpenGLRenderer& renderer) { +bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { + bool needsInvalidate = false; TextContainer text; mReader.rewind(); - int saveCount = renderer.getSaveCount() - 1; +#if DEBUG_DISPLAY_LIST + uint32_t count = (level + 1) * 2; + char indent[count + 1]; + for (uint32_t i = 0; i < count; i++) { + indent[i] = ' '; + } + indent[count] = '\0'; + DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this); +#endif + int saveCount = renderer.getSaveCount() - 1; while (!mReader.eof()) { int op = mReader.readInt(); + switch (op) { - case AcquireContext: { - renderer.acquireContext(); - } - break; - case ReleaseContext: { - renderer.releaseContext(); + case DrawGLFunction: { + Functor *functor = (Functor *) getInt(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); + needsInvalidate |= renderer.callDrawGLFunction(functor); } break; case Save: { - renderer.save(getInt()); + int rendererNum = getInt(); + DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); + renderer.save(rendererNum); } break; case Restore: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.restore(); } break; case RestoreToCount: { - renderer.restoreToCount(saveCount + getInt()); + int restoreCount = saveCount + getInt(); + DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); + renderer.restoreToCount(restoreCount); } break; case SaveLayer: { - renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(), - getPaint(), getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + int flags = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, paint, flags); + renderer.saveLayer(f1, f2, f3, f4, paint, flags); } break; case SaveLayerAlpha: { - renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(), - getInt(), getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int alpha = getInt(); + int flags = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, alpha, flags); + renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags); } break; case Translate: { - renderer.translate(getFloat(), getFloat()); + float f1 = getFloat(); + float f2 = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2); + renderer.translate(f1, f2); } break; case Rotate: { - renderer.rotate(getFloat()); + float rotation = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation); + renderer.rotate(rotation); } break; case Scale: { - renderer.scale(getFloat(), getFloat()); + float sx = getFloat(); + float sy = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + renderer.scale(sx, sy); + } + break; + case Skew: { + float sx = getFloat(); + float sy = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + renderer.skew(sx, sy); } break; case SetMatrix: { - renderer.setMatrix(getMatrix()); + SkMatrix* matrix = getMatrix(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + renderer.setMatrix(matrix); } break; case ConcatMatrix: { - renderer.concatMatrix(getMatrix()); + SkMatrix* matrix = getMatrix(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + renderer.concatMatrix(matrix); } break; case ClipRect: { - renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(), - (SkRegion::Op) getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int regionOp = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, regionOp); + renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp); } break; case DrawDisplayList: { - renderer.drawDisplayList(getDisplayList()); + DisplayList* displayList = getDisplayList(); + DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op], + displayList, level + 1); + needsInvalidate |= renderer.drawDisplayList(displayList, level + 1); + } + break; + case DrawLayer: { + Layer* layer = (Layer*) getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + layer, x, y, paint); + renderer.drawLayer(layer, x, y, paint); } break; case DrawBitmap: { - renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint()); + SkBitmap* bitmap = getBitmap(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + bitmap, x, y, paint); + renderer.drawBitmap(bitmap, x, y, paint); } break; case DrawBitmapMatrix: { - renderer.drawBitmap(getBitmap(), getMatrix(), getPaint()); + SkBitmap* bitmap = getBitmap(); + SkMatrix* matrix = getMatrix(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op], + bitmap, matrix, paint); + renderer.drawBitmap(bitmap, matrix, paint); } break; case DrawBitmapRect: { - renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(), - getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + SkBitmap* bitmap = getBitmap(); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + float f7 = getFloat(); + float f8 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); + renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); + } + break; + case DrawBitmapMesh: { + int verticesCount = 0; + uint32_t colorsCount = 0; + + SkBitmap* bitmap = getBitmap(); + uint32_t meshWidth = getInt(); + uint32_t meshHeight = getInt(); + float* vertices = getFloats(verticesCount); + bool hasColors = getInt(); + int* colors = hasColors ? getInts(colorsCount) : NULL; + + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); + renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, getPaint()); } break; case DrawPatch: { @@ -264,69 +364,156 @@ void DisplayList::replay(OpenGLRenderer& renderer) { yDivs = getInts(yDivsCount); colors = getUInts(numColors); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); } break; case DrawColor: { - renderer.drawColor(getInt(), (SkXfermode::Mode) getInt()); + int color = getInt(); + int xferMode = getInt(); + DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); + renderer.drawColor(color, (SkXfermode::Mode) xferMode); } break; case DrawRect: { - renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, paint); + renderer.drawRect(f1, f2, f3, f4, paint); + } + break; + case DrawRoundRect: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint); + renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint); + } + break; + case DrawCircle: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, paint); + renderer.drawCircle(f1, f2, f3, paint); + } + break; + case DrawOval: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); + renderer.drawOval(f1, f2, f3, f4, paint); + } + break; + case DrawArc: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + int i1 = getInt(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); + renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint); } break; case DrawPath: { - renderer.drawPath(getPath(), getPaint()); + SkPath* path = getPath(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint); + renderer.drawPath(path, paint); } break; case DrawLines: { int count = 0; float* points = getFloats(count); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawLines(points, count, getPaint()); } break; case DrawText: { getText(&text); - renderer.drawText(text.text(), text.length(), getInt(), - getFloat(), getFloat(), getPaint()); + int count = getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + text.text(), text.length(), count, x, y, paint); + renderer.drawText(text.text(), text.length(), count, x, y, paint); } break; case ResetShader: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShader(); } break; case SetupShader: { - renderer.setupShader(getShader()); + SkiaShader* shader = getShader(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader); + renderer.setupShader(shader); } break; case ResetColorFilter: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetColorFilter(); } break; case SetupColorFilter: { - renderer.setupColorFilter(getColorFilter()); + SkiaColorFilter *colorFilter = getColorFilter(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter); + renderer.setupColorFilter(colorFilter); } break; case ResetShadow: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShadow(); } break; case SetupShadow: { - renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt()); + float radius = getFloat(); + float dx = getFloat(); + float dy = getFloat(); + int color = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], + radius, dx, dy, color); + renderer.setupShadow(radius, dx, dy, color); } break; + default: + DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s", + (char*) indent, OP_NAMES[op]); + break; } } + + DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate); + return needsInvalidate; } /////////////////////////////////////////////////////////////////////////////// // Base structure /////////////////////////////////////////////////////////////////////////////// -DisplayListRenderer::DisplayListRenderer(): - mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) { - mPathHeap = NULL; +DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE) { + mDisplayList = NULL; } DisplayListRenderer::~DisplayListRenderer() { @@ -334,16 +521,7 @@ DisplayListRenderer::~DisplayListRenderer() { } void DisplayListRenderer::reset() { - if (mPathHeap) { - mPathHeap->unref(); - mPathHeap = NULL; - } - mWriter.reset(); - mHeap.reset(); - - mRCRecorder.reset(); - mTFRecorder.reset(); Caches& caches = Caches::getInstance(); for (size_t i = 0; i < mBitmapResources.size(); i++) { @@ -352,14 +530,22 @@ void DisplayListRenderer::reset() { } mBitmapResources.clear(); - for (size_t i = 0; i < mShaderResources.size(); i++) { - SkiaShader* resource = mShaderResources.itemAt(i); + for (size_t i = 0; i < mOriginalPaths.size(); i++) { + SkPath* resource = mOriginalPaths.itemAt(i); caches.resourceCache.decrementRefcount(resource); } - mShaderResources.clear(); + mOriginalPaths.clear(); + + for (size_t i = 0; i < mShaders.size(); i++) { + caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); + } + mShaders.clear(); + mShaderMap.clear(); mPaints.clear(); mPaintMap.clear(); + mPaths.clear(); + mPathMap.clear(); mMatrices.clear(); } @@ -367,6 +553,15 @@ void DisplayListRenderer::reset() { // Operations /////////////////////////////////////////////////////////////////////////////// +DisplayList* DisplayListRenderer::getDisplayList() { + if (mDisplayList == NULL) { + mDisplayList = new DisplayList(*this); + } else { + mDisplayList->initFromDisplayListRenderer(*this, true); + } + return mDisplayList; +} + void DisplayListRenderer::setViewport(int width, int height) { mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); @@ -374,21 +569,30 @@ void DisplayListRenderer::setViewport(int width, int height) { mHeight = height; } -void DisplayListRenderer::prepare(bool opaque) { +void DisplayListRenderer::prepareDirty(float left, float top, + float right, float bottom, bool opaque) { mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSaveCount = 1; mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); + mRestoreSaveCount = -1; +} + +void DisplayListRenderer::finish() { + insertRestoreToCount(); + OpenGLRenderer::finish(); } -void DisplayListRenderer::acquireContext() { - addOp(DisplayList::AcquireContext); - OpenGLRenderer::acquireContext(); +void DisplayListRenderer::interrupt() { } -void DisplayListRenderer::releaseContext() { - addOp(DisplayList::ReleaseContext); - OpenGLRenderer::releaseContext(); +void DisplayListRenderer::resume() { +} + +bool DisplayListRenderer::callDrawGLFunction(Functor *functor) { + addOp(DisplayList::DrawGLFunction); + addInt((int) functor); + return false; // No invalidate needed at record-time } int DisplayListRenderer::save(int flags) { @@ -403,8 +607,7 @@ void DisplayListRenderer::restore() { } void DisplayListRenderer::restoreToCount(int saveCount) { - addOp(DisplayList::RestoreToCount); - addInt(saveCount); + mRestoreSaveCount = saveCount; OpenGLRenderer::restoreToCount(saveCount); } @@ -444,6 +647,12 @@ void DisplayListRenderer::scale(float sx, float sy) { OpenGLRenderer::scale(sx, sy); } +void DisplayListRenderer::skew(float sx, float sy) { + addOp(DisplayList::Skew); + addPoint(sx, sy); + OpenGLRenderer::skew(sx, sy); +} + void DisplayListRenderer::setMatrix(SkMatrix* matrix) { addOp(DisplayList::SetMatrix); addMatrix(matrix); @@ -464,9 +673,17 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot return OpenGLRenderer::clipRect(left, top, right, bottom, op); } -void DisplayListRenderer::drawDisplayList(DisplayList* displayList) { +bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { addOp(DisplayList::DrawDisplayList); addDisplayList(displayList); + return false; +} + +void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { + addOp(DisplayList::DrawLayer); + addInt((int) layer); + addPoint(x, y); + addPaint(paint); } void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, @@ -495,6 +712,22 @@ void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcT addPaint(paint); } +void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, + float* vertices, int* colors, SkPaint* paint) { + addOp(DisplayList::DrawBitmapMesh); + addBitmap(bitmap); + addInt(meshWidth); + addInt(meshHeight); + addFloats(vertices, (meshWidth + 1) * (meshHeight + 1) * 2); + if (colors) { + addInt(1); + addInts(colors, (meshWidth + 1) * (meshHeight + 1)); + } else { + addInt(0); + } + addPaint(paint); +} + void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) { @@ -520,6 +753,37 @@ void DisplayListRenderer::drawRect(float left, float top, float right, float bot addPaint(paint); } +void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint) { + addOp(DisplayList::DrawRoundRect); + addBounds(left, top, right, bottom); + addPoint(rx, ry); + addPaint(paint); +} + +void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { + addOp(DisplayList::DrawCircle); + addPoint(x, y); + addFloat(radius); + addPaint(paint); +} + +void DisplayListRenderer::drawOval(float left, float top, float right, float bottom, + SkPaint* paint) { + addOp(DisplayList::DrawOval); + addBounds(left, top, right, bottom); + addPaint(paint); +} + +void DisplayListRenderer::drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { + addOp(DisplayList::DrawArc); + addBounds(left, top, right, bottom); + addPoint(startAngle, sweepAngle); + addInt(useCenter ? 1 : 0); + addPaint(paint); +} + void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) { addOp(DisplayList::DrawPath); addPath(path); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index b608381cef9f..f39f37f860eb 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -28,6 +28,7 @@ #include <SkTSearch.h> #include "OpenGLRenderer.h" +#include "utils/Functor.h" namespace android { namespace uirenderer { @@ -37,32 +38,13 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// #define MIN_WRITER_SIZE 16384 -#define HEAP_BLOCK_SIZE 4096 -/////////////////////////////////////////////////////////////////////////////// -// Helpers -/////////////////////////////////////////////////////////////////////////////// - -class PathHeap: public SkRefCnt { -public: - PathHeap(); - PathHeap(SkFlattenableReadBuffer& buffer); - ~PathHeap(); - - int append(const SkPath& path); - - int count() const { return mPaths.count(); } - - SkPath& operator[](int index) const { - return *mPaths[index]; - } - - void flatten(SkFlattenableWriteBuffer& buffer) const; - -private: - SkChunkAlloc mHeap; - SkTDArray<SkPath*> mPaths; -}; +// Debug +#if DEBUG_DISPLAY_LIST + #define DISPLAY_LIST_LOGD(...) LOGD(__VA_ARGS__) +#else + #define DISPLAY_LIST_LOGD(...) +#endif /////////////////////////////////////////////////////////////////////////////// // Display list @@ -78,10 +60,10 @@ public: DisplayList(const DisplayListRenderer& recorder); ~DisplayList(); + // IMPORTANT: Update the intialization of OP_NAMES in the .cpp file + // when modifying this file enum Op { - AcquireContext, - ReleaseContext, - Save, + Save = 0, Restore, RestoreToCount, SaveLayer, @@ -89,16 +71,23 @@ public: Translate, Rotate, Scale, + Skew, SetMatrix, ConcatMatrix, ClipRect, DrawDisplayList, + DrawLayer, DrawBitmap, DrawBitmapMatrix, DrawBitmapRect, + DrawBitmapMesh, DrawPatch, DrawColor, DrawRect, + DrawRoundRect, + DrawCircle, + DrawOval, + DrawArc, DrawPath, DrawLines, DrawText, @@ -107,14 +96,21 @@ public: ResetColorFilter, SetupColorFilter, ResetShadow, - SetupShadow + SetupShadow, + DrawGLFunction, }; - void replay(OpenGLRenderer& renderer); + static const char* OP_NAMES[]; + + void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false); + + bool replay(OpenGLRenderer& renderer, uint32_t level = 0); private: void init(); + void clearResources(); + class TextContainer { public: size_t length() const { @@ -154,7 +150,7 @@ private: } SkPath* getPath() { - return &(*mPathHeap)[getInt() - 1]; + return (SkPath*) getInt(); } SkPaint* getPaint() { @@ -189,19 +185,16 @@ private: text->mText = (const char*) mReader.skip(length); } - PathHeap* mPathHeap; - Vector<SkBitmap*> mBitmapResources; - Vector<SkiaShader*> mShaderResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; + Vector<SkPath*> mPaths; + Vector<SkPath*> mOriginalPaths; Vector<SkMatrix*> mMatrices; + Vector<SkiaShader*> mShaders; mutable SkFlattenableReadBuffer mReader; - - SkRefCntPlayback mRCPlayback; - SkTypefacePlayback mTFPlayback; }; /////////////////////////////////////////////////////////////////////////////// @@ -216,11 +209,16 @@ public: DisplayListRenderer(); ~DisplayListRenderer(); + DisplayList* getDisplayList(); + void setViewport(int width, int height); - void prepare(bool opaque); + void prepareDirty(float left, float top, float right, float bottom, bool opaque); + void finish(); - void acquireContext(); - void releaseContext(); + bool callDrawGLFunction(Functor *functor); + + void interrupt(); + void resume(); int save(int flags); void restore(); @@ -234,23 +232,33 @@ public: void translate(float dx, float dy); void rotate(float degrees); void scale(float sx, float sy); + void skew(float sx, float sy); void setMatrix(SkMatrix* matrix); void concatMatrix(SkMatrix* matrix); bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - void drawDisplayList(DisplayList* displayList); + bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); + void drawLayer(Layer* layer, float x, float y, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint); + void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, + float* vertices, int* colors, SkPaint* paint); void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint); void drawColor(int color, SkXfermode::Mode mode); void drawRect(float left, float top, float right, float bottom, SkPaint* paint); + void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint); + void drawCircle(float x, float y, float radius, SkPaint* paint); + void drawOval(float left, float top, float right, float bottom, SkPaint* paint); + void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); void drawPath(SkPath* path, SkPaint* paint); void drawLines(float* points, int count, SkPaint* paint); void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); @@ -266,10 +274,6 @@ public: void reset(); - DisplayList* getDisplayList() const { - return new DisplayList(*this); - } - const SkWriter32& writeStream() const { return mWriter; } @@ -278,14 +282,22 @@ public: return mBitmapResources; } - const Vector<SkiaShader*>& getShaderResources() const { - return mShaderResources; + const Vector<SkiaShader*>& getShaders() const { + return mShaders; } const Vector<SkPaint*>& getPaints() const { return mPaints; } + const Vector<SkPath*>& getPaths() const { + return mPaths; + } + + const Vector<SkPath*>& getOriginalPaths() const { + return mOriginalPaths; + } + const Vector<SkMatrix*>& getMatrices() const { return mMatrices; } @@ -295,7 +307,16 @@ public: } private: + void insertRestoreToCount() { + if (mRestoreSaveCount >= 0) { + mWriter.writeInt(DisplayList::RestoreToCount); + addInt(mRestoreSaveCount); + mRestoreSaveCount = -1; + } + } + inline void addOp(DisplayList::Op drawOp) { + insertRestoreToCount(); mWriter.writeInt(drawOp); } @@ -345,20 +366,36 @@ private: mWriter.writePad(text, byteLength); } - inline void addPath(const SkPath* path) { - if (mPathHeap == NULL) { - mPathHeap = new PathHeap(); + inline void addPath(SkPath* path) { + if (!path) { + addInt((int) NULL); + return; + } + + SkPath* pathCopy = mPathMap.valueFor(path); + if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) { + if (pathCopy == NULL) { + pathCopy = path; + mOriginalPaths.add(path); + Caches& caches = Caches::getInstance(); + caches.resourceCache.incrementRefcount(path); + } else { + pathCopy = new SkPath(*path); + mPaths.add(pathCopy); + } + mPathMap.add(path, pathCopy); } - addInt(mPathHeap->append(*path)); + + addInt((int) pathCopy); } inline void addPaint(SkPaint* paint) { - if (paint == NULL) { + if (!paint) { addInt((int) NULL); return; } - SkPaint *paintCopy = mPaintMap.valueFor(paint); + SkPaint* paintCopy = mPaintMap.valueFor(paint); if (paintCopy == NULL || paintCopy->getGenerationID() != paint->getGenerationID()) { paintCopy = new SkPaint(*paint); mPaintMap.add(paint, paintCopy); @@ -393,10 +430,21 @@ private: } inline void addShader(SkiaShader* shader) { - addInt((int) shader); - mShaderResources.add(shader); - Caches& caches = Caches::getInstance(); - caches.resourceCache.incrementRefcount(shader); + if (!shader) { + addInt((int) NULL); + return; + } + + SkiaShader* shaderCopy = mShaderMap.valueFor(shader); + // TODO: We also need to handle generation ID changes in compose shaders + if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) { + shaderCopy = shader->copy(); + mShaderMap.add(shader, shaderCopy); + mShaders.add(shaderCopy); + Caches::getInstance().resourceCache.incrementRefcount(shaderCopy); + } + + addInt((int) shaderCopy); } inline void addColorFilter(SkiaColorFilter* colorFilter) { @@ -406,21 +454,26 @@ private: caches.resourceCache.incrementRefcount(colorFilter); } - SkChunkAlloc mHeap; - Vector<SkBitmap*> mBitmapResources; - Vector<SkiaShader*> mShaderResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap; + + Vector<SkPath*> mOriginalPaths; + Vector<SkPath*> mPaths; + DefaultKeyedVector<SkPath*, SkPath*> mPathMap; + + Vector<SkiaShader*> mShaders; + DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap; + Vector<SkMatrix*> mMatrices; - PathHeap* mPathHeap; SkWriter32 mWriter; - SkRefCntRecorder mRCRecorder; - SkRefCntRecorder mTFRecorder; + DisplayList *mDisplayList; + + int mRestoreSaveCount; friend class DisplayList; diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp index 2ef71c245305..beef7bea258d 100644 --- a/libs/hwui/FboCache.cpp +++ b/libs/hwui/FboCache.cpp @@ -18,6 +18,7 @@ #include <stdlib.h> +#include "Debug.h" #include "FboCache.h" #include "Properties.h" @@ -31,10 +32,10 @@ namespace uirenderer { FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_FBO_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting fbo cache size to %s", property); + INIT_LOGD(" Setting fbo cache size to %s", property); mMaxSize = atoi(property); } else { - LOGD(" Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE); + INIT_LOGD(" Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE); } } diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 5224689b3ce7..0042f496fac4 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -22,6 +22,7 @@ #include <utils/Log.h> +#include "Debug.h" #include "FontRenderer.h" namespace android { @@ -38,8 +39,10 @@ namespace uirenderer { // Font /////////////////////////////////////////////////////////////////////////////// -Font::Font(FontRenderer* state, uint32_t fontId, float fontSize) : - mState(state), mFontId(fontId), mFontSize(fontSize) { +Font::Font(FontRenderer* state, uint32_t fontId, float fontSize, + int flags, uint32_t italicStyle) : + mState(state), mFontId(fontId), mFontSize(fontSize), + mFlags(flags), mItalicStyle(italicStyle) { } @@ -275,17 +278,19 @@ Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { return newGlyph; } -Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) { +Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, + int flags, uint32_t italicStyle) { Vector<Font*> &activeFonts = state->mActiveFonts; for (uint32_t i = 0; i < activeFonts.size(); i++) { Font* font = activeFonts[i]; - if (font->mFontId == fontId && font->mFontSize == fontSize) { + if (font->mFontId == fontId && font->mFontSize == fontSize && + font->mFlags == flags && font->mItalicStyle == italicStyle) { return font; } } - Font* newFont = new Font(state, fontId, fontSize); + Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle); activeFonts.push(newFont); return newFont; } @@ -294,8 +299,12 @@ Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) { // FontRenderer /////////////////////////////////////////////////////////////////////////////// +static bool sLogFontRendererCreate = true; + FontRenderer::FontRenderer() { - LOGD("Creating FontRenderer"); + if (sLogFontRendererCreate) { + INIT_LOGD("Creating FontRenderer"); + } mGammaTable = NULL; mInitialized = false; @@ -313,18 +322,28 @@ FontRenderer::FontRenderer() { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { - LOGD(" Setting text cache width to %s pixels", property); + if (sLogFontRendererCreate) { + INIT_LOGD(" Setting text cache width to %s pixels", property); + } mCacheWidth = atoi(property); } else { - LOGD(" Using default text cache width of %i pixels", mCacheWidth); + if (sLogFontRendererCreate) { + INIT_LOGD(" Using default text cache width of %i pixels", mCacheWidth); + } } if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { - LOGD(" Setting text cache width to %s pixels", property); + if (sLogFontRendererCreate) { + INIT_LOGD(" Setting text cache width to %s pixels", property); + } mCacheHeight = atoi(property); } else { - LOGD(" Using default text cache height of %i pixels", mCacheHeight); + if (sLogFontRendererCreate) { + INIT_LOGD(" Using default text cache height of %i pixels", mCacheHeight); + } } + + sLogFontRendererCreate = false; } FontRenderer::~FontRenderer() { @@ -634,7 +653,14 @@ void FontRenderer::precacheLatin(SkPaint* paint) { void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { uint32_t currentNumFonts = mActiveFonts.size(); - mCurrentFont = Font::create(this, fontId, fontSize); + int flags = 0; + if (paint->isFakeBoldText()) { + flags |= Font::kFakeBold; + } + + const float skewX = paint->getTextSkewX(); + uint32_t italicStyle = *(uint32_t*) &skewX; + mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle); const float maxPrecacheFontSize = 40.0f; bool isNewFont = currentNumFonts != mActiveFonts.size(); @@ -720,7 +746,7 @@ void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { // The larger the radius gets, the more our gaussian blur // will resemble a box blur since with large sigma // the gaussian curve begins to lose its shape - float sigma = 0.3f * (float)radius + 0.6f; + float sigma = 0.3f * (float) radius + 0.6f; // Now compute the coefficints // We will store some redundant values to save some math during @@ -730,7 +756,7 @@ void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { float coeff2 = - 1.0f / (2.0f * sigma * sigma); float normalizeFactor = 0.0f; - for(int32_t r = -radius; r <= radius; r ++) { + for (int32_t r = -radius; r <= radius; r ++) { float floatR = (float) r; weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); normalizeFactor += weights[r + radius]; @@ -738,7 +764,7 @@ void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { //Now we need to normalize the weights because all our coefficients need to add up to one normalizeFactor = 1.0f / normalizeFactor; - for(int32_t r = -radius; r <= radius; r ++) { + for (int32_t r = -radius; r <= radius; r ++) { weights[r + radius] *= normalizeFactor; } } @@ -748,35 +774,35 @@ void FontRenderer::horizontalBlur(float* weights, int32_t radius, float blurredPixel = 0.0f; float currentPixel = 0.0f; - for(int32_t y = 0; y < height; y ++) { + for (int32_t y = 0; y < height; y ++) { const uint8_t* input = source + y * width; uint8_t* output = dest + y * width; - for(int32_t x = 0; x < width; x ++) { + for (int32_t x = 0; x < width; x ++) { blurredPixel = 0.0f; const float* gPtr = weights; // Optimization for non-border pixels - if ((x > radius) && (x < (width - radius))) { + if (x > radius && x < (width - radius)) { const uint8_t *i = input + (x - radius); - for(int r = -radius; r <= radius; r ++) { + for (int r = -radius; r <= radius; r ++) { currentPixel = (float) (*i); blurredPixel += currentPixel * gPtr[0]; gPtr++; i++; } } else { - for(int32_t r = -radius; r <= radius; r ++) { + for (int32_t r = -radius; r <= radius; r ++) { // Stepping left and right away from the pixel int validW = x + r; - if(validW < 0) { + if (validW < 0) { validW = 0; } - if(validW > width - 1) { + if (validW > width - 1) { validW = width - 1; } - currentPixel = (float)(input[validW]); + currentPixel = (float) input[validW]; blurredPixel += currentPixel * gPtr[0]; gPtr++; } @@ -792,41 +818,41 @@ void FontRenderer::verticalBlur(float* weights, int32_t radius, float blurredPixel = 0.0f; float currentPixel = 0.0f; - for(int32_t y = 0; y < height; y ++) { + for (int32_t y = 0; y < height; y ++) { uint8_t* output = dest + y * width; - for(int32_t x = 0; x < width; x ++) { + for (int32_t x = 0; x < width; x ++) { blurredPixel = 0.0f; const float* gPtr = weights; const uint8_t* input = source + x; // Optimization for non-border pixels - if ((y > radius) && (y < (height - radius))) { + if (y > radius && y < (height - radius)) { const uint8_t *i = input + ((y - radius) * width); - for(int32_t r = -radius; r <= radius; r ++) { + for (int32_t r = -radius; r <= radius; r ++) { currentPixel = (float)(*i); blurredPixel += currentPixel * gPtr[0]; gPtr++; i += width; } } else { - for(int32_t r = -radius; r <= radius; r ++) { + for (int32_t r = -radius; r <= radius; r ++) { int validH = y + r; // Clamp to zero and width - if(validH < 0) { + if (validH < 0) { validH = 0; } - if(validH > height - 1) { + if (validH > height - 1) { validH = height - 1; } const uint8_t *i = input + validH * width; - currentPixel = (float)(*i); + currentPixel = (float) (*i); blurredPixel += currentPixel * gPtr[0]; gPtr++; } } - *output = (uint8_t)blurredPixel; + *output = (uint8_t) blurredPixel; output ++; } } diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 7e749ca58d3f..10058125a8e1 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -41,6 +41,10 @@ class FontRenderer; */ class Font { public: + enum Style { + kFakeBold + }; + ~Font(); /** @@ -53,7 +57,8 @@ public: /** * Creates a new font associated with the specified font state. */ - static Font* create(FontRenderer* state, uint32_t fontId, float fontSize); + static Font* create(FontRenderer* state, uint32_t fontId, float fontSize, + int flags, uint32_t italicStyle); protected: friend class FontRenderer; @@ -99,7 +104,7 @@ protected: SkFixed mRsbDelta; }; - Font(FontRenderer* state, uint32_t fontId, float fontSize); + Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle); DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs; @@ -117,6 +122,8 @@ protected: FontRenderer* mState; uint32_t mFontId; float mFontSize; + int mFlags; + uint32_t mItalicStyle; }; class FontRenderer { diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp index 6d087e3baaae..e8362dcd45d2 100644 --- a/libs/hwui/GammaFontRenderer.cpp +++ b/libs/hwui/GammaFontRenderer.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "OpenGLRenderer" +#include "Debug.h" #include "GammaFontRenderer.h" #include "Properties.h" @@ -27,7 +28,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// GammaFontRenderer::GammaFontRenderer() { - LOGD("Creating gamma font renderer"); + INIT_LOGD("Creating gamma font renderer"); // Get the renderer properties char property[PROPERTY_VALUE_MAX]; @@ -35,29 +36,29 @@ GammaFontRenderer::GammaFontRenderer() { // Get the gamma float gamma = DEFAULT_TEXT_GAMMA; if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { - LOGD(" Setting text gamma to %s", property); + INIT_LOGD(" Setting text gamma to %s", property); gamma = atof(property); } else { - LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); + INIT_LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); } // Get the black gamma threshold mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { - LOGD(" Setting text black gamma threshold to %s", property); + INIT_LOGD(" Setting text black gamma threshold to %s", property); mBlackThreshold = atoi(property); } else { - LOGD(" Using default text black gamma threshold of %d", + INIT_LOGD(" Using default text black gamma threshold of %d", DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); } // Get the white gamma threshold mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { - LOGD(" Setting text white gamma threshold to %s", property); + INIT_LOGD(" Setting text white gamma threshold to %s", property); mWhiteThreshold = atoi(property); } else { - LOGD(" Using default white black gamma threshold of %d", + INIT_LOGD(" Using default white black gamma threshold of %d", DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index a37964eae4cd..4a40a63485ac 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -23,6 +23,7 @@ #include <utils/threads.h> +#include "Debug.h" #include "GradientCache.h" #include "Properties.h" @@ -38,10 +39,10 @@ GradientCache::GradientCache(): mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting gradient cache size to %sMB", property); + INIT_LOGD(" Setting gradient cache size to %sMB", property); setMaxSize(MB(atof(property))); } else { - LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); + INIT_LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); } mCache.setOnEntryRemovedListener(this); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index a780183a1c33..bb2843790ed7 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -26,6 +26,8 @@ #include <SkXfermode.h> #include "Rect.h" +#include "SkiaColorFilter.h" +#include "Vertex.h" namespace android { namespace uirenderer { @@ -40,6 +42,14 @@ namespace uirenderer { struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight): width(layerWidth), height(layerHeight) { + mesh = NULL; + meshIndices = NULL; + meshElementCount = 0; + } + + ~Layer() { + if (mesh) delete mesh; + if (meshIndices) delete meshIndices; } /** @@ -93,6 +103,18 @@ struct Layer { * have been drawn. */ Region region; + + /** + * Color filter used to draw this layer. Optional. + */ + SkiaColorFilter* colorFilter; + + /** + * If the layer can be rendered as a mesh, this is non-null. + */ + TextureVertex* mesh; + uint16_t* meshIndices; + GLsizei meshElementCount; }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index 9ce0359140bb..a9710ad6adbf 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -20,6 +20,7 @@ #include <utils/Log.h> +#include "Debug.h" #include "LayerCache.h" #include "Properties.h" @@ -33,10 +34,10 @@ namespace uirenderer { LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting layer cache size to %sMB", property); + INIT_LOGD(" Setting layer cache size to %sMB", property); setMaxSize(MB(atof(property))); } else { - LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); + INIT_LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); } } @@ -102,6 +103,7 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { layer->blend = true; layer->empty = true; layer->fbo = 0; + layer->colorFilter = NULL; glGenTextures(1, &layer->texture); glBindTexture(GL_TEXTURE_2D, layer->texture); @@ -126,6 +128,31 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { return layer; } +bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t height) { + // TODO: We should be smarter and see if we have a texture of the appropriate + // size already in the cache, and reuse it instead of creating a new one + + LayerEntry entry(width, height); + if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) { + return true; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, layer->texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + if (glGetError() != GL_NO_ERROR) { + return false; + } + + layer->width = entry.mWidth; + layer->height = entry.mHeight; + + return true; +} + bool LayerCache::put(Layer* layer) { const uint32_t size = layer->width * layer->height * 4; // Don't even try to cache a layer that's bigger than the cache diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h index 1333a73feea7..d2d5f3960568 100644 --- a/libs/hwui/LayerCache.h +++ b/libs/hwui/LayerCache.h @@ -76,6 +76,17 @@ public: * Clears the cache. This causes all layers to be deleted. */ void clear(); + /** + * Resize the specified layer if needed. + * + * @param layer The layer to resize + * @param width The new width of the layer + * @param height The new height of the layer + * + * @return True if the layer was resized or nothing happened, false if + * a failure occurred during the resizing operation + */ + bool resize(Layer* layer, const uint32_t width, const uint32_t height); /** * Sets the maximum size of the cache in bytes. diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp new file mode 100644 index 000000000000..24f9739715ee --- /dev/null +++ b/libs/hwui/LayerRenderer.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2011 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 "OpenGLRenderer" + +#include <ui/Rect.h> + +#include "LayerCache.h" +#include "LayerRenderer.h" +#include "Properties.h" +#include "Rect.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Rendering +/////////////////////////////////////////////////////////////////////////////// + +void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { + LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo); + + glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); + + const float width = mLayer->layer.getWidth(); + const float height = mLayer->layer.getHeight(); + +#if RENDER_LAYERS_AS_REGIONS + Rect dirty(left, top, right, bottom); + if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && + dirty.right >= width && dirty.bottom >= height)) { + mLayer->region.clear(); + dirty.set(0.0f, 0.0f, width, height); + } else { + dirty.intersect(0.0f, 0.0f, width, height); + android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom); + mLayer->region.subtractSelf(r); + } + + OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); +#else + OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque); +#endif +} + +void LayerRenderer::finish() { + OpenGLRenderer::finish(); + + generateMesh(); + + LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->fbo); + + // No need to unbind our FBO, this will be taken care of by the caller + // who will invoke OpenGLRenderer::resume() +} + +GLint LayerRenderer::getTargetFbo() { + return mLayer->fbo; +} + +/////////////////////////////////////////////////////////////////////////////// +// Dirty region tracking +/////////////////////////////////////////////////////////////////////////////// + +bool LayerRenderer::hasLayer() { + return true; +} + +Region* LayerRenderer::getRegion() { +#if RENDER_LAYERS_AS_REGIONS + if (getSnapshot()->flags & Snapshot::kFlagFboTarget) { + return OpenGLRenderer::getRegion(); + } + return &mLayer->region; +#else + return OpenGLRenderer::getRegion(); +#endif +} + +void LayerRenderer::generateMesh() { +#if RENDER_LAYERS_AS_REGIONS + if (mLayer->region.isRect() || mLayer->region.isEmpty()) { + if (mLayer->mesh) { + delete mLayer->mesh; + delete mLayer->meshIndices; + + mLayer->mesh = NULL; + mLayer->meshIndices = NULL; + mLayer->meshElementCount = 0; + } + return; + } + + size_t count; + const android::Rect* rects = mLayer->region.getArray(&count); + + GLsizei elementCount = count * 6; + + if (mLayer->mesh && mLayer->meshElementCount < elementCount) { + delete mLayer->mesh; + delete mLayer->meshIndices; + + mLayer->mesh = NULL; + mLayer->meshIndices = NULL; + } + + bool rebuildIndices = false; + if (!mLayer->mesh) { + mLayer->mesh = new TextureVertex[count * 4]; + mLayer->meshIndices = new uint16_t[elementCount]; + rebuildIndices = true; + } + mLayer->meshElementCount = elementCount; + + const float texX = 1.0f / float(mLayer->width); + const float texY = 1.0f / float(mLayer->height); + const float height = mLayer->layer.getHeight(); + + TextureVertex* mesh = mLayer->mesh; + uint16_t* indices = mLayer->meshIndices; + + for (size_t i = 0; i < count; i++) { + const android::Rect* r = &rects[i]; + + const float u1 = r->left * texX; + const float v1 = (height - r->top) * texY; + const float u2 = r->right * texX; + const float v2 = (height - r->bottom) * texY; + + TextureVertex::set(mesh++, r->left, r->top, u1, v1); + TextureVertex::set(mesh++, r->right, r->top, u2, v1); + TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); + TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); + + if (rebuildIndices) { + uint16_t quad = i * 4; + int index = i * 6; + indices[index ] = quad; // top-left + indices[index + 1] = quad + 1; // top-right + indices[index + 2] = quad + 2; // bottom-left + indices[index + 3] = quad + 2; // bottom-left + indices[index + 4] = quad + 1; // top-right + indices[index + 5] = quad + 3; // bottom-right + } + } +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// Layers management +/////////////////////////////////////////////////////////////////////////////// + +Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { + LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); + + GLuint fbo = Caches::getInstance().fboCache.get(); + if (!fbo) { + LOGW("Could not obtain an FBO"); + return NULL; + } + + glActiveTexture(GL_TEXTURE0); + Layer* layer = Caches::getInstance().layerCache.get(width, height); + if (!layer) { + LOGW("Could not obtain a layer"); + return NULL; + } + + layer->fbo = fbo; + layer->layer.set(0.0f, 0.0f, width, height); + layer->texCoords.set(0.0f, height / float(layer->height), + width / float(layer->width), 0.0f); + layer->alpha = 255; + layer->mode = SkXfermode::kSrcOver_Mode; + layer->blend = !isOpaque; + layer->colorFilter = NULL; + layer->region.clear(); + + GLuint previousFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); + + glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); + glBindTexture(GL_TEXTURE_2D, layer->texture); + + // Initialize the texture if needed + if (layer->empty) { + layer->empty = false; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + if (glGetError() != GL_NO_ERROR) { + LOGD("Could not allocate texture"); + glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); + glDeleteTextures(1, &layer->texture); + Caches::getInstance().fboCache.put(fbo); + delete layer; + return NULL; + } + } + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + layer->texture, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); + + return layer; +} + +bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { + if (layer) { + LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height); + + if (Caches::getInstance().layerCache.resize(layer, width, height)) { + layer->layer.set(0.0f, 0.0f, width, height); + layer->texCoords.set(0.0f, height / float(layer->height), + width / float(layer->width), 0.0f); + } else { + if (layer->texture) glDeleteTextures(1, &layer->texture); + delete layer; + return false; + } + } + + return true; +} + +void LayerRenderer::destroyLayer(Layer* layer) { + if (layer) { + LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); + + if (layer->fbo) { + Caches::getInstance().fboCache.put(layer->fbo); + } + + if (!Caches::getInstance().layerCache.put(layer)) { + if (layer->texture) glDeleteTextures(1, &layer->texture); + delete layer; + } else { + layer->region.clear(); + } + } +} + +void LayerRenderer::destroyLayerDeferred(Layer* layer) { + if (layer) { + LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo); + + Caches::getInstance().deleteLayerDeferred(layer); + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h new file mode 100644 index 000000000000..d2f565e4f307 --- /dev/null +++ b/libs/hwui/LayerRenderer.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 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_HWUI_LAYER_RENDERER_H +#define ANDROID_HWUI_LAYER_RENDERER_H + +#include "OpenGLRenderer.h" +#include "Layer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#if DEBUG_LAYER_RENDERER + #define LAYER_RENDERER_LOGD(...) LOGD(__VA_ARGS__) +#else + #define LAYER_RENDERER_LOGD(...) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////// + +class LayerRenderer: public OpenGLRenderer { +public: + LayerRenderer(Layer* layer): mLayer(layer) { + } + + ~LayerRenderer() { + } + + void prepareDirty(float left, float top, float right, float bottom, bool opaque); + void finish(); + + bool hasLayer(); + Region* getRegion(); + GLint getTargetFbo(); + + static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); + static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); + static void destroyLayer(Layer* layer); + static void destroyLayerDeferred(Layer* layer); + +private: + void generateMesh(); + + Layer* mLayer; +}; // class LayerRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_LAYER_RENDERER_H diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index fe7f8834a8b2..e7c0fe35194a 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -178,6 +178,24 @@ void Matrix4::loadScale(float sx, float sy, float sz) { data[kScaleZ] = sz; } +void Matrix4::loadSkew(float sx, float sy) { + loadIdentity(); + + data[kScaleX] = 1.0f; + data[kSkewX] = sx; + data[kTranslateX] = 0.0f; + + data[kSkewY] = sy; + data[kScaleY] = 1.0f; + data[kTranslateY] = 0.0f; + + data[kPerspective0] = 0.0f; + data[kPerspective1] = 0.0f; + data[kPerspective2] = 1.0f; + + mSimpleMatrix = false; +} + void Matrix4::loadRotate(float angle, float x, float y, float z) { data[kPerspective0] = 0.0f; data[kPerspective1] = 0.0f; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 23fc6c375150..08f5d776d5f5 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -72,6 +72,7 @@ public: void loadTranslate(float x, float y, float z); void loadScale(float sx, float sy, float sz); + void loadSkew(float sx, float sy); void loadRotate(float angle, float x, float y, float z); void loadMultiply(const Matrix4& u, const Matrix4& v); @@ -97,6 +98,12 @@ public: multiply(u); } + void skew(float sx, float sy) { + Matrix4 u; + u.loadSkew(sx, sy); + multiply(u); + } + void rotate(float angle, float x, float y, float z) { Matrix4 u; u.loadRotate(angle, x, y, z); diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp index 1cf3d20c8be1..05870bb2e07e 100644 --- a/libs/hwui/OpenGLDebugRenderer.cpp +++ b/libs/hwui/OpenGLDebugRenderer.cpp @@ -23,10 +23,11 @@ namespace android { namespace uirenderer { -void OpenGLDebugRenderer::prepare(bool opaque) { +void OpenGLDebugRenderer::prepareDirty(float left, float top, + float right, float bottom, bool opaque) { mPrimitivesCount = 0; LOGD("========= Frame start ========="); - OpenGLRenderer::prepare(opaque); + OpenGLRenderer::prepareDirty(left, top, right, bottom, opaque); } void OpenGLDebugRenderer::finish() { @@ -48,10 +49,16 @@ int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bot return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags); } -void OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList) { +bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { mPrimitivesCount++; StopWatch w("drawDisplayList"); - OpenGLRenderer::drawDisplayList(displayList); + return OpenGLRenderer::drawDisplayList(displayList); +} + +void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawLayer"); + OpenGLRenderer::drawLayer(layer, x, y, paint); } void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, @@ -99,6 +106,33 @@ void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bot OpenGLRenderer::drawRect(left, top, right, bottom, paint); } +void OpenGLDebugRenderer::drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawRoundRect"); + OpenGLRenderer::drawRoundRect(left, top, right, bottom, rx, ry, paint); +} + +void OpenGLDebugRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawCircle"); + OpenGLRenderer::drawCircle(x, y, radius, paint); +} + +void OpenGLDebugRenderer::drawOval(float left, float top, float right, float bottom, + SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawOval"); + OpenGLRenderer::drawOval(left, top, right, bottom, paint); +} + +void OpenGLDebugRenderer::drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawArc"); + OpenGLRenderer::drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint); +} + void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) { mPrimitivesCount++; StopWatch w("drawPath"); diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h index ee34d736d700..1a18a6727f9f 100644 --- a/libs/hwui/OpenGLDebugRenderer.h +++ b/libs/hwui/OpenGLDebugRenderer.h @@ -34,13 +34,14 @@ public: ~OpenGLDebugRenderer() { } - void prepare(bool opaque); + void prepareDirty(float left, float top, float right, float bottom, bool opaque); void finish(); int saveLayer(float left, float top, float right, float bottom, SkPaint* p, int flags); - void drawDisplayList(DisplayList* displayList); + bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); + void drawLayer(Layer* layer, float x, float y, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, @@ -51,6 +52,12 @@ public: float left, float top, float right, float bottom, SkPaint* paint); void drawColor(int color, SkXfermode::Mode mode); void drawRect(float left, float top, float right, float bottom, SkPaint* paint); + void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint); + void drawCircle(float x, float y, float radius, SkPaint* paint); + void drawOval(float left, float top, float right, float bottom, SkPaint* paint); + void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); void drawPath(SkPath* path, SkPaint* paint); void drawLines(float* points, int count, SkPaint* paint); void drawText(const char* text, int bytesCount, int count, float x, float y, diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index eec8d8c73fee..8ee7ec3f60cd 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -136,6 +136,10 @@ void OpenGLRenderer::setViewport(int width, int height) { } void OpenGLRenderer::prepare(bool opaque) { + prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); +} + +void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { mCaches.clearGarbage(); mSnapshot = new Snapshot(mFirstSnapshot, @@ -146,15 +150,14 @@ void OpenGLRenderer::prepare(bool opaque) { glDisable(GL_DITHER); + glEnable(GL_SCISSOR_TEST); + glScissor(left, mSnapshot->height - bottom, right - left, bottom - top); + mSnapshot->setClip(left, top, right, bottom); + if (!opaque) { - glDisable(GL_SCISSOR_TEST); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); } - - glEnable(GL_SCISSOR_TEST); - glScissor(0, 0, mWidth, mHeight); - mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); } void OpenGLRenderer::finish() { @@ -162,6 +165,11 @@ void OpenGLRenderer::finish() { GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { LOGD("GL error from OpenGLRenderer: 0x%x", status); + switch (status) { + case GL_OUT_OF_MEMORY: + LOGE(" OpenGLRenderer is out of memory!"); + break; + } } #endif #if DEBUG_MEMORY_USAGE @@ -173,7 +181,7 @@ void OpenGLRenderer::finish() { #endif } -void OpenGLRenderer::acquireContext() { +void OpenGLRenderer::interrupt() { if (mCaches.currentProgram) { if (mCaches.currentProgram->isInUse()) { mCaches.currentProgram->remove(); @@ -183,7 +191,7 @@ void OpenGLRenderer::acquireContext() { mCaches.unbindMeshBuffer(); } -void OpenGLRenderer::releaseContext() { +void OpenGLRenderer::resume() { glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); glEnable(GL_SCISSOR_TEST); @@ -191,7 +199,7 @@ void OpenGLRenderer::releaseContext() { glDisable(GL_DITHER); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); mCaches.blend = true; @@ -200,6 +208,16 @@ void OpenGLRenderer::releaseContext() { glBlendEquation(GL_FUNC_ADD); } +bool OpenGLRenderer::callDrawGLFunction(Functor *functor) { + interrupt(); + if (mDirtyClip) { + setScissorFromClip(); + } + status_t result = (*functor)(); + resume(); + return (result == 0) ? false : true; +} + /////////////////////////////////////////////////////////////////////////////// // State management /////////////////////////////////////////////////////////////////////////////// @@ -406,6 +424,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, layer->layer.set(bounds); layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height), bounds.getWidth() / float(layer->width), 0.0f); + layer->colorFilter = mColorFilter; // Save the layer in the snapshot snapshot->flags |= Snapshot::kFlagIsLayer; @@ -416,18 +435,18 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, } else { // Copy the framebuffer into the layer glBindTexture(GL_TEXTURE_2D, layer->texture); - - if (layer->empty) { - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, - snapshot->height - bounds.bottom, layer->width, layer->height, 0); - layer->empty = false; - } else { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, - snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); + if (!bounds.isEmpty()) { + if (layer->empty) { + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, + snapshot->height - bounds.bottom, layer->width, layer->height, 0); + layer->empty = false; + } else { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, + snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); + } + // Enqueue the buffer coordinates to clear the corresponding region later + mLayers.push(new Rect(bounds)); } - - // Enqueue the buffer coordinates to clear the corresponding region later - mLayers.push(new Rect(bounds)); } return true; @@ -459,7 +478,6 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna snapshot->flags |= Snapshot::kFlagIsFboLayer; snapshot->fbo = layer->fbo; snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); - //snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); snapshot->height = bounds.getHeight(); @@ -544,10 +562,18 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { // drawing only the dirty region if (fboLayer) { dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); + if (layer->colorFilter) { + setupColorFilter(layer->colorFilter); + } composeLayerRegion(layer, rect); + if (layer->colorFilter) { + resetColorFilter(); + } } else { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); - composeLayerRect(layer, rect, true); + if (!rect.isEmpty()) { + dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); + composeLayerRect(layer, rect, true); + } } if (fboLayer) { @@ -593,51 +619,34 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { size_t count; const android::Rect* rects = layer->region.getArray(&count); - setupDraw(); - - ProgramDescription description; - description.hasTexture = true; - const float alpha = layer->alpha / 255.0f; - const bool setColor = description.setColor(alpha, alpha, alpha, alpha); - chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false); - - useProgram(mCaches.programCache.get(description)); - - // Texture - bindTexture(layer->texture); - glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); - - // Always premultiplied - if (setColor) { - mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); - } - - // Mesh - int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); - glEnableVertexAttribArray(texCoordsSlot); - - mModelView.loadIdentity(); - mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); - const float texX = 1.0f / float(layer->width); const float texY = 1.0f / float(layer->height); + const float height = rect.getHeight(); TextureVertex* mesh = mCaches.getRegionMesh(); GLsizei numQuads = 0; - glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, - gMeshStride, &mesh[0].position[0]); - glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, - gMeshStride, &mesh[0].texture[0]); + setupDraw(); + setupDrawWithTexture(); + setupDrawColor(alpha, alpha, alpha, alpha); + setupDrawColorFilter(); + setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); + setupDrawProgram(); + setupDrawDirtyRegionsDisabled(); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawTexture(layer->texture); + setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); + setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]); for (size_t i = 0; i < count; i++) { const android::Rect* r = &rects[i]; const float u1 = r->left * texX; - const float v1 = (rect.getHeight() - r->top) * texY; + const float v1 = (height - r->top) * texY; const float u2 = r->right * texX; - const float v2 = (rect.getHeight() - r->bottom) * texY; + const float v2 = (height - r->bottom) * texY; // TODO: Reject quads outside of the clip TextureVertex::set(mesh++, r->left, r->top, u1, v1); @@ -659,28 +668,10 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableVertexAttribArray(texCoordsSlot); + finishDrawTexture(); #if DEBUG_LAYERS_AS_REGIONS - uint32_t colors[] = { - 0x7fff0000, 0x7f00ff00, - 0x7f0000ff, 0x7fff00ff, - }; - - int offset = 0; - int32_t top = rects[0].top; - int i = 0; - - for (size_t i = 0; i < count; i++) { - if (top != rects[i].top) { - offset ^= 0x2; - top = rects[i].top; - } - - Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); - drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)], - SkXfermode::kSrcOver_Mode); - } + drawRegionRects(layer->region); #endif layer->region.clear(); @@ -690,19 +681,39 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { #endif } +void OpenGLRenderer::drawRegionRects(const Region& region) { +#if DEBUG_LAYERS_AS_REGIONS + size_t count; + const android::Rect* rects = region.getArray(&count); + + uint32_t colors[] = { + 0x7fff0000, 0x7f00ff00, + 0x7f0000ff, 0x7fff00ff, + }; + + int offset = 0; + int32_t top = rects[0].top; + + for (size_t i = 0; i < count; i++) { + if (top != rects[i].top) { + offset ^= 0x2; + top = rects[i].top; + } + + Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); + drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)], + SkXfermode::kSrcOver_Mode); + } +#endif +} + void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform) { #if RENDER_LAYERS_AS_REGIONS - if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { + if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); - bounds.intersect(*mSnapshot->clipRect); - bounds.snapToPixelBoundaries(); - - android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); - if (!dirty.isEmpty()) { - mSnapshot->region->orSelf(dirty); - } + dirtyLayerUnchecked(bounds, getRegion()); } #endif } @@ -710,14 +721,20 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top, void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom) { #if RENDER_LAYERS_AS_REGIONS - if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { + if (hasLayer()) { Rect bounds(left, top, right, bottom); - bounds.intersect(*mSnapshot->clipRect); - bounds.snapToPixelBoundaries(); + dirtyLayerUnchecked(bounds, getRegion()); + } +#endif +} +void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { +#if RENDER_LAYERS_AS_REGIONS + if (bounds.intersect(*mSnapshot->clipRect)) { + bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); if (!dirty.isEmpty()) { - mSnapshot->region->orSelf(dirty); + region->orSelf(dirty); } } #endif @@ -764,6 +781,10 @@ void OpenGLRenderer::scale(float sx, float sy) { mSnapshot->transform->scale(sx, sy, 1.0f); } +void OpenGLRenderer::skew(float sx, float sy) { + mSnapshot->transform->skew(sx, sy); +} + void OpenGLRenderer::setMatrix(SkMatrix* matrix) { mSnapshot->transform->load(*matrix); } @@ -1023,12 +1044,13 @@ void OpenGLRenderer::finishDrawTexture() { // Drawing /////////////////////////////////////////////////////////////////////////////// -void OpenGLRenderer::drawDisplayList(DisplayList* displayList) { +bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList) { - displayList->replay(*this); + return displayList->replay(*this, level); } + return false; } void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { @@ -1069,6 +1091,61 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* pai restore(); } +void OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, + float* vertices, int* colors, SkPaint* paint) { + // TODO: Do a quickReject + if (!vertices || mSnapshot->isIgnored()) { + return; + } + + glActiveTexture(gTextureUnits[0]); + Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + const uint32_t count = meshWidth * meshHeight * 6; + + // TODO: Support the colors array + TextureVertex mesh[count]; + TextureVertex* vertex = mesh; + for (int32_t y = 0; y < meshHeight; y++) { + for (int32_t x = 0; x < meshWidth; x++) { + uint32_t i = (y * (meshWidth + 1) + x) * 2; + + float u1 = float(x) / meshWidth; + float u2 = float(x + 1) / meshWidth; + float v1 = float(y) / meshHeight; + float v2 = float(y + 1) / meshHeight; + + int ax = i + (meshWidth + 1) * 2; + int ay = ax + 1; + int bx = i; + int by = bx + 1; + int cx = i + 2; + int cy = cx + 1; + int dx = i + (meshWidth + 1) * 2 + 2; + int dy = dx + 1; + + TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); + TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1); + TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); + + TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); + TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); + TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2); + } + } + + drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f, + mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0], + GL_TRIANGLES, count); +} + void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, @@ -1139,19 +1216,19 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int const bool pureTranslate = mSnapshot->transform->isPureTranslate(); #if RENDER_LAYERS_AS_REGIONS // Mark the current layer dirty where we are going to draw the patch - if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && - mSnapshot->region && mesh->hasEmptyQuads) { + if (hasLayer() && mesh->hasEmptyQuads) { + const float offsetX = left + mSnapshot->transform->getTranslateX(); + const float offsetY = top + mSnapshot->transform->getTranslateY(); const size_t count = mesh->quads.size(); for (size_t i = 0; i < count; i++) { const Rect& bounds = mesh->quads.itemAt(i); if (pureTranslate) { - const float x = (int) floorf(bounds.left + 0.5f); - const float y = (int) floorf(bounds.top + 0.5f); - dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight(), - *mSnapshot->transform); + const float x = (int) floorf(bounds.left + offsetX + 0.5f); + const float y = (int) floorf(bounds.top + offsetY + 0.5f); + dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); } else { - dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, - *mSnapshot->transform); + dirtyLayer(left + bounds.left, top + bounds.top, + left + bounds.right, top + bounds.bottom, *mSnapshot->transform); } } } @@ -1175,7 +1252,6 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { - // TODO: Should do quickReject for each line if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); @@ -1189,6 +1265,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { getAlphaAndMode(paint, &alpha, &mode); int verticesCount = count >> 2; + int generatedVerticesCount = 0; if (!isHairLine) { // TODO: AA needs more vertices verticesCount *= 6; @@ -1235,31 +1312,55 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { vec2 p3 = b + n; vec2 p4 = b - n; - // Draw the line as 2 triangles, could be optimized - // by using only 4 vertices and the correct indices - // Also we should probably used non textured vertices - // when line AA is disabled to save on bandwidth - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); - - // TODO: Mark the dirty regions when RENDER_LAYERS_AS_REGIONS is set + const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); + const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); + const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); + const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); + + if (!quickReject(left, top, right, bottom)) { + // Draw the line as 2 triangles, could be optimized + // by using only 4 vertices and the correct indices + // Also we should probably used non textured vertices + // when line AA is disabled to save on bandwidth + TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); + + generatedVerticesCount += 6; + + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + } } - // GL_LINE does not give the result we want to match Skia - glDrawArrays(GL_TRIANGLES, 0, verticesCount); + if (generatedVerticesCount > 0) { + // GL_LINE does not give the result we want to match Skia + glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount); + } } else { // TODO: Handle the AA case for (int i = 0; i < count; i += 4) { - TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); - TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + const float left = fmin(points[i], points[i + 1]); + const float right = fmax(points[i], points[i + 1]); + const float top = fmin(points[i + 2], points[i + 3]); + const float bottom = fmax(points[i + 2], points[i + 3]); + + if (!quickReject(left, top, right, bottom)) { + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + + generatedVerticesCount += 2; + + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + } } - glLineWidth(1.0f); - glDrawArrays(GL_LINES, 0, verticesCount); + if (generatedVerticesCount > 0) { + glLineWidth(1.0f); + glDrawArrays(GL_LINES, 0, generatedVerticesCount); + } } } @@ -1273,7 +1374,72 @@ void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); } +void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, SkPaint* paint) { + if (!texture) return; + const AutoTexture autoCleanup(texture); + + const float x = left + texture->left - texture->offset; + const float y = top + texture->top - texture->offset; + + drawPathTexture(texture, x, y, paint); +} + +void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + glActiveTexture(gTextureUnits[0]); + const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect( + right - left, bottom - top, rx, ry, paint); + drawShape(left, top, texture, paint); +} + +void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + glActiveTexture(gTextureUnits[0]); + const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint); + drawShape(x - radius, y - radius, texture, paint); +} + +void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + glActiveTexture(gTextureUnits[0]); + const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint); + drawShape(left, top, texture, paint); +} + +void OpenGLRenderer::drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + if (fabs(sweepAngle) >= 360.0f) { + drawOval(left, top, right, bottom, paint); + return; + } + + glActiveTexture(gTextureUnits[0]); + const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top, + startAngle, sweepAngle, useCenter, paint); + drawShape(left, top, texture, paint); +} + +void OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom, + SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + glActiveTexture(gTextureUnits[0]); + const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint); + drawShape(left, top, texture, paint); +} + void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { + if (p->getStyle() != SkPaint::kFill_Style) { + drawRectAsShape(left, top, right, bottom, p); + return; + } + if (quickReject(left, top, right, bottom)) { return; } @@ -1289,13 +1455,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, mode = getXfermode(p->getXfermode()); } - // Skia draws using the color's alpha channel if < 255 - // Otherwise, it uses the paint's alpha int color = p->getColor(); - if (((color >> 24) & 0xff) == 255) { - color |= p->getAlpha() << 24; - } - drawColorRect(left, top, right, bottom, color, mode); } @@ -1394,24 +1554,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS - bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; + bool hasActiveLayer = hasLayer(); #else - bool hasLayer = false; + bool hasActiveLayer = false; #endif mCaches.unbindMeshBuffer(); if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, - hasLayer ? &bounds : NULL)) { + hasActiveLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS - if (hasLayer) { + if (hasActiveLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } - bounds.intersect(*mSnapshot->clipRect); - bounds.snapToPixelBoundaries(); - - android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); - mSnapshot->region->orSelf(dirty); + dirtyLayerUnchecked(bounds, getRegion()); } #endif } @@ -1425,8 +1581,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { if (mSnapshot->isIgnored()) return; - GLuint textureUnit = 0; - glActiveTexture(gTextureUnits[textureUnit]); + glActiveTexture(gTextureUnits[0]); const PathTexture* texture = mCaches.pathCache.get(path, paint); if (!texture) return; @@ -1435,31 +1590,61 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { const float x = texture->left - texture->offset; const float y = texture->top - texture->offset; - if (quickReject(x, y, x + texture->width, y + texture->height)) { + drawPathTexture(texture, x, y, paint); +} + +void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { + if (!layer || quickReject(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight())) { return; } + glActiveTexture(gTextureUnits[0]); + int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - setupDraw(); - setupDrawWithTexture(true); - setupDrawAlpha8Color(paint->getColor(), alpha); - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelView(x, y, x + texture->width, y + texture->height); - setupDrawTexture(texture->id); - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + layer->alpha = alpha; + layer->mode = mode; - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); +#if RENDER_LAYERS_AS_REGIONS + if (!layer->region.isEmpty()) { + if (layer->region.isRect()) { + const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); + composeLayerRect(layer, r); + } else if (layer->mesh) { + const float a = alpha / 255.0f; + const Rect& rect = layer->layer; + + setupDraw(); + setupDrawWithTexture(); + setupDrawColor(a, a, a, a); + setupDrawColorFilter(); + setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); + setupDrawProgram(); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawTexture(layer->texture); + // TODO: The current layer, if any, will be dirtied with the bounding box + // of the layer we are drawing. Since the layer we are drawing has + // a mesh, we know the dirty region, we should use it instead + setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); + setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); + + glDrawElements(GL_TRIANGLES, layer->meshElementCount, + GL_UNSIGNED_SHORT, layer->meshIndices); + + finishDrawTexture(); - finishDrawTexture(); +#if DEBUG_LAYERS_AS_REGIONS + drawRegionRects(layer->region); +#endif + } + } +#else + const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); + composeLayerRect(layer, r); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1509,6 +1694,35 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { // Drawing implementation /////////////////////////////////////////////////////////////////////////////// +void OpenGLRenderer::drawPathTexture(const PathTexture* texture, + float x, float y, SkPaint* paint) { + if (quickReject(x, y, x + texture->width, y + texture->height)) { + return; + } + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + setupDraw(); + setupDrawWithTexture(true); + setupDrawAlpha8Color(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(x, y, x + texture->width, y + texture->height); + setupDrawTexture(texture->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + + finishDrawTexture(); +} + // Same values used by Skia #define kStdStrikeThru_Offset (-6.0f / 21.0f) #define kStdUnderline_Offset (1.0f / 9.0f) @@ -1539,12 +1753,17 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float if (underlineWidth > 0.0f) { const float textSize = paint->getTextSize(); - const float strokeWidth = textSize * kStdUnderline_Thickness; + // TODO: Support stroke width < 1.0f when we have AA lines + const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); const float left = x - offsetX; float top = 0.0f; - const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1); + int linesCount = 0; + if (flags & SkPaint::kUnderlineText_Flag) linesCount++; + if (flags & SkPaint::kStrikeThruText_Flag) linesCount++; + + const int pointsCount = 4 * linesCount; float points[pointsCount]; int currentPoint = 0; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 8f93f5bc60f5..7bbf034c8497 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -27,6 +27,7 @@ #include <SkShader.h> #include <SkXfermode.h> +#include <utils/Functor.h> #include <utils/RefBase.h> #include <utils/Vector.h> @@ -61,11 +62,15 @@ public: virtual void setViewport(int width, int height); - virtual void prepare(bool opaque); + void prepare(bool opaque); + virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); - virtual void acquireContext(); - virtual void releaseContext(); + // These two calls must not be recorded in display lists + virtual void interrupt(); + virtual void resume(); + + virtual bool callDrawGLFunction(Functor *functor); int getSaveCount() const; virtual int save(int flags); @@ -80,6 +85,7 @@ public: virtual void translate(float dx, float dy); virtual void rotate(float degrees); virtual void scale(float sx, float sy); + virtual void skew(float sx, float sy); const float* getMatrix() const; void getMatrix(SkMatrix* matrix); @@ -90,17 +96,26 @@ public: bool quickReject(float left, float top, float right, float bottom); virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - virtual void drawDisplayList(DisplayList* displayList); + virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); + virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint); + virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, + float* vertices, int* colors, SkPaint* paint); virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint); virtual void drawColor(int color, SkXfermode::Mode mode); virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint); + virtual void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, SkPaint* paint); + virtual void drawCircle(float x, float y, float radius, SkPaint* paint); + virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint); + virtual void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); virtual void drawPath(SkPath* path, SkPaint* paint); virtual void drawLines(float* points, int count, SkPaint* paint); virtual void drawText(const char* text, int bytesCount, int count, float x, float y, @@ -127,6 +142,39 @@ protected: */ virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); + /** + * Marks the specified region as dirty at the specified bounds. + */ + void dirtyLayerUnchecked(Rect& bounds, Region* region); + + /** + * Returns the current snapshot. + */ + sp<Snapshot> getSnapshot() { + return mSnapshot; + } + + /** + * Returns the region of the current layer. + */ + virtual Region* getRegion() { + return mSnapshot->region; + } + + /** + * Indicates whether rendering is currently targeted at a layer. + */ + virtual bool hasLayer() { + return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; + } + + /** + * Returns the name of the FBO this renderer is rendering into. + */ + virtual GLint getTargetFbo() { + return 0; + } + private: /** * Saves the current state of the renderer as a new snapshot. @@ -205,6 +253,19 @@ private: void clearLayerRegions(); /** + * Mark the layer as dirty at the specified coordinates. The coordinates + * are transformed with the supplied matrix. + */ + void dirtyLayer(const float left, const float top, + const float right, const float bottom, const mat4 transform); + + /** + * Mark the layer as dirty at the specified coordinates. + */ + void dirtyLayer(const float left, const float top, + const float right, const float bottom); + + /** * Draws a colored rectangle with the specified color. The specified coordinates * are transformed by the current snapshot's transform matrix. * @@ -220,6 +281,9 @@ private: void drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform = false); + void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint); + void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p); + /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. @@ -291,6 +355,8 @@ private: void drawTextDecorations(const char* text, int bytesCount, float length, float x, float y, SkPaint* paint); + void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint); + /** * Resets the texture coordinates stored in mMeshVertices. Setting the values * back to default is achieved by calling: @@ -389,6 +455,8 @@ private: void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void finishDrawTexture(); + void drawRegionRects(const Region& region); + /** * Should be invoked every time the glScissor is modified. */ @@ -396,18 +464,6 @@ private: mDirtyClip = true; } - /** - * Mark the layer as dirty at the specified coordinates. The coordinates - * are transformed with the supplied matrix. - */ - void dirtyLayer(const float left, const float top, const float right, const float bottom, - const mat4 transform); - - /** - * Mark the layer as dirty at the specified coordinates. - */ - void dirtyLayer(const float left, const float top, const float right, const float bottom); - // Dimensions of the drawing surface int mWidth, mHeight; diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index e5cb67b81be3..11eb953907ca 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -166,7 +166,10 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, } float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight; - generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount); + if (stepY > 0.0f) { + generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, + bitmapWidth, quadCount); + } y1 = y2; v1 = (stepY + 0.5f) / bitmapHeight; @@ -174,8 +177,10 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, previousStepY = stepY; } - generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left, - bitmapWidth, quadCount); + if (previousStepY != bitmapHeight) { + generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left, + bitmapWidth, quadCount); + } if (verticesCount > 0) { Caches::getInstance().bindMeshBuffer(meshBuffer); @@ -212,7 +217,9 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl } float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth; - generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); + if (stepX > 0.0f) { + generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); + } x1 = x2; u1 = (stepX + 0.5f) / bitmapWidth; @@ -220,19 +227,23 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl previousStepX = stepX; } - generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount); + if (previousStepX != bitmapWidth) { + generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount); + } } void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, uint32_t& quadCount) { const uint32_t oldQuadCount = quadCount; - const bool valid = x2 - x1 > 0.9999f && y2 - y1 > 0.9999f; - if (valid) { - quadCount++; - } + quadCount++; // Skip degenerate and transparent (empty) quads - if (!valid || ((mColorKey >> oldQuadCount) & 0x1) == 1) { + if ((mColorKey >> oldQuadCount) & 0x1) { +#if DEBUG_PATCHES_EMPTY_VERTICES + PATCH_LOGD(" quad %d (empty)", oldQuadCount); + PATCH_LOGD(" left, top = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1); + PATCH_LOGD(" right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2); +#endif return; } diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 8740a64601ae..0f22bea48009 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -16,11 +16,6 @@ #define LOG_TAG "OpenGLRenderer" -#include <GLES2/gl2.h> - -#include <SkCanvas.h> -#include <SkRect.h> - #include <utils/threads.h> #include "PathCache.h" @@ -30,87 +25,11 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -PathCache::PathCache(): - mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), - mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting path cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); - } - init(); -} - -PathCache::PathCache(uint32_t maxByteSize): - mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), - mSize(0), mMaxSize(maxByteSize) { - init(); -} - -PathCache::~PathCache() { - mCache.clear(); -} - -void PathCache::init() { - mCache.setOnEntryRemovedListener(this); - - GLint maxTextureSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - mMaxTextureSize = maxTextureSize; - - mDebugEnabled = readDebugLevel() & kDebugCaches; -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management +// Path cache /////////////////////////////////////////////////////////////////////////////// -uint32_t PathCache::getSize() { - return mSize; -} - -uint32_t PathCache::getMaxSize() { - return mMaxSize; -} - -void PathCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Callbacks -/////////////////////////////////////////////////////////////////////////////// - -void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) { - removeTexture(texture); -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -void PathCache::removeTexture(PathTexture* texture) { - if (texture) { - const uint32_t size = texture->width * texture->height; - mSize -= size; - - PATH_LOGD("PathCache::callback: delete path: name, size, mSize = %d, %d, %d", - texture->id, size, mSize); - if (mDebugEnabled) { - LOGD("Path deleted, size = %d", size); - } - - glDeleteTextures(1, &texture->id); - delete texture; - } +PathCache::PathCache(): ShapeCache<PathCacheEntry>("path", + PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) { } void PathCache::remove(SkPath* path) { @@ -146,7 +65,6 @@ void PathCache::clearGarbage() { PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { PathCacheEntry entry(path, paint); - PathTexture* texture = mCache.get(entry); if (!texture) { @@ -159,97 +77,5 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { return texture; } -PathTexture* PathCache::addTexture(const PathCacheEntry& entry, - const SkPath *path, const SkPaint* paint) { - const SkRect& bounds = path->getBounds(); - - const float pathWidth = fmax(bounds.width(), 1.0f); - const float pathHeight = fmax(bounds.height(), 1.0f); - - if (pathWidth > mMaxTextureSize || pathHeight > mMaxTextureSize) { - LOGW("Path too large to be rendered into a texture"); - return NULL; - } - - const float offset = entry.strokeWidth * 1.5f; - const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5); - const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5); - - const uint32_t size = width * height; - // Don't even try to cache a bitmap that's bigger than the cache - if (size < mMaxSize) { - while (mSize + size > mMaxSize) { - mCache.removeOldest(); - } - } - - PathTexture* texture = new PathTexture; - texture->left = bounds.fLeft; - texture->top = bounds.fTop; - texture->offset = offset; - texture->width = width; - texture->height = height; - texture->generation = path->getGenerationID(); - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kA8_Config, width, height); - bitmap.allocPixels(); - bitmap.eraseColor(0); - - SkPaint pathPaint(*paint); - if (!pathPaint.getXfermode()) { - SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode); - pathPaint.setXfermode(mode)->safeUnref(); - } - - SkCanvas canvas(bitmap); - canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset); - canvas.drawPath(*path, pathPaint); - - generateTexture(bitmap, texture); - - if (size < mMaxSize) { - mSize += size; - PATH_LOGD("PathCache::get: create path: name, size, mSize = %d, %d, %d", - texture->id, size, mSize); - if (mDebugEnabled) { - LOGD("Path created, size = %d", size); - } - mCache.put(entry, texture); - } else { - texture->cleanup = true; - } - - return texture; -} - -void PathCache::clear() { - mCache.clear(); -} - -void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) { - SkAutoLockPixels alp(bitmap); - if (!bitmap.readyToDraw()) { - LOGE("Cannot generate texture from bitmap"); - return; - } - - glGenTextures(1, &texture->id); - - glBindTexture(GL_TEXTURE_2D, texture->id); - // Textures are Alpha8 - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - texture->blend = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, - GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels()); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index ae2e55dfbe2a..dc67e160fabf 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -17,123 +17,54 @@ #ifndef ANDROID_HWUI_PATH_CACHE_H #define ANDROID_HWUI_PATH_CACHE_H -#include <SkBitmap.h> -#include <SkPaint.h> -#include <SkPath.h> - #include <utils/Vector.h> #include "Debug.h" -#include "Texture.h" +#include "ShapeCache.h" + #include "utils/Compare.h" -#include "utils/GenerationCache.h" namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_PATHS - #define PATH_LOGD(...) LOGD(__VA_ARGS__) -#else - #define PATH_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// // Classes /////////////////////////////////////////////////////////////////////////////// -/** - * Describe a path in the path cache. - */ -struct PathCacheEntry { - PathCacheEntry() { - path = NULL; - join = SkPaint::kDefault_Join; - cap = SkPaint::kDefault_Cap; - style = SkPaint::kFill_Style; - miter = 4.0f; - strokeWidth = 1.0f; +struct PathCacheEntry: public ShapeCacheEntry { + PathCacheEntry(SkPath* path, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapePath, paint) { + this->path = path; } - PathCacheEntry(const PathCacheEntry& entry): - path(entry.path), join(entry.join), cap(entry.cap), - style(entry.style), miter(entry.miter), - strokeWidth(entry.strokeWidth) { + PathCacheEntry(): ShapeCacheEntry() { + path = NULL; } - PathCacheEntry(SkPath* path, SkPaint* paint) { - this->path = path; - join = paint->getStrokeJoin(); - cap = paint->getStrokeCap(); - miter = paint->getStrokeMiter(); - strokeWidth = paint->getStrokeWidth(); - style = paint->getStyle(); + PathCacheEntry(const PathCacheEntry& entry): + ShapeCacheEntry(entry) { + path = entry.path; } - SkPath* path; - SkPaint::Join join; - SkPaint::Cap cap; - SkPaint::Style style; - float miter; - float strokeWidth; - - bool operator<(const PathCacheEntry& rhs) const { + bool lessThan(const ShapeCacheEntry& r) const { + const PathCacheEntry& rhs = (const PathCacheEntry&) r; LTE_INT(path) { - LTE_INT(join) { - LTE_INT(cap) { - LTE_INT(style) { - LTE_FLOAT(miter) { - LTE_FLOAT(strokeWidth) return false; - } - } - } - } + return false; } return false; } -}; // struct PathCacheEntry - -/** - * Alpha texture used to represent a path. - */ -struct PathTexture: public Texture { - PathTexture(): Texture() { - } - /** - * Left coordinate of the path bounds. - */ - float left; - /** - * Top coordinate of the path bounds. - */ - float top; - /** - * Offset to draw the path at the correct origin. - */ - float offset; -}; // struct PathTexture + SkPath* path; +}; // PathCacheEntry /** * A simple LRU path cache. The cache has a maximum size expressed in bytes. * Any texture added to the cache causing the cache to grow beyond the maximum * allowed size will also cause the oldest texture to be kicked out. */ -class PathCache: public OnEntryRemoved<PathCacheEntry, PathTexture*> { +class PathCache: public ShapeCache<PathCacheEntry> { public: PathCache(); - PathCache(uint32_t maxByteSize); - ~PathCache(); - - /** - * Used as a callback when an entry is removed from the cache. - * Do not invoke directly. - */ - void operator()(PathCacheEntry& path, PathTexture*& texture); /** * Returns the texture associated with the specified path. If the texture @@ -141,10 +72,6 @@ public: */ PathTexture* get(SkPath* path, SkPaint* paint); /** - * Clears the cache. This causes all textures to be deleted. - */ - void clear(); - /** * Removes an entry. */ void remove(SkPath* path); @@ -158,39 +85,7 @@ public: */ void clearGarbage(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - private: - /** - * Generates the texture from a bitmap into the specified texture structure. - */ - void generateTexture(SkBitmap& bitmap, Texture* texture); - - void removeTexture(PathTexture* texture); - - PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint); - - void init(); - - GenerationCache<PathCacheEntry, PathTexture*> mCache; - - uint32_t mSize; - uint32_t mMaxSize; - GLuint mMaxTextureSize; - - bool mDebugEnabled; - Vector<SkPath*> mGarbage; mutable Mutex mLock; }; // class PathCache diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index c4749363711e..2d8b6f3950f6 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -26,7 +26,7 @@ */ // If turned on, layers drawn inside FBOs are optimized with regions -#define RENDER_LAYERS_AS_REGIONS 0 +#define RENDER_LAYERS_AS_REGIONS 1 /** * Debug level for app developers. @@ -48,6 +48,7 @@ enum DebugLevel { #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size" #define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size" #define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size" +#define PROPERTY_SHAPE_CACHE_SIZE "ro.hwui.shape_cache_size" #define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size" #define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size" @@ -63,13 +64,14 @@ enum DebugLevel { // Converts a number of mega-bytes into bytes #define MB(s) s * 1024 * 1024 -#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f -#define DEFAULT_LAYER_CACHE_SIZE 8.0f +#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f +#define DEFAULT_LAYER_CACHE_SIZE 24.0f #define DEFAULT_PATH_CACHE_SIZE 4.0f +#define DEFAULT_SHAPE_CACHE_SIZE 1.0f #define DEFAULT_PATCH_CACHE_SIZE 512 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f -#define DEFAULT_FBO_CACHE_SIZE 12 +#define DEFAULT_FBO_CACHE_SIZE 16 #define DEFAULT_TEXT_GAMMA 1.4f #define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64 diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 1c93ea644ef4..87fdfb5212a1 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -60,21 +60,23 @@ void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) } void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { - SkPixelRef* pixref = bitmapResource->pixelRef(); - if (pixref) pixref->globalRef(); - + bitmapResource->pixelRef()->safeRef(); bitmapResource->getColorTable()->safeRef(); incrementRefcount((void*)bitmapResource, kBitmap); } +void ResourceCache::incrementRefcount(SkPath* pathResource) { + incrementRefcount((void*)pathResource, kPath); +} + void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { shaderResource->getSkShader()->safeRef(); - incrementRefcount((void*)shaderResource, kShader); + incrementRefcount((void*) shaderResource, kShader); } void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { filterResource->getSkColorFilter()->safeRef(); - incrementRefcount((void*)filterResource, kColorFilter); + incrementRefcount((void*) filterResource, kColorFilter); } void ResourceCache::decrementRefcount(void* resource) { @@ -91,21 +93,23 @@ void ResourceCache::decrementRefcount(void* resource) { } void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { - SkPixelRef* pixref = bitmapResource->pixelRef(); - if (pixref) pixref->globalUnref(); - + bitmapResource->pixelRef()->safeUnref(); bitmapResource->getColorTable()->safeUnref(); - decrementRefcount((void*)bitmapResource); + decrementRefcount((void*) bitmapResource); +} + +void ResourceCache::decrementRefcount(SkPath* pathResource) { + decrementRefcount((void*) pathResource); } void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { shaderResource->getSkShader()->safeUnref(); - decrementRefcount((void*)shaderResource); + decrementRefcount((void*) shaderResource); } void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { filterResource->getSkColorFilter()->safeUnref(); - decrementRefcount((void*)filterResource); + decrementRefcount((void*) filterResource); } void ResourceCache::recycle(SkBitmap* resource) { @@ -126,6 +130,24 @@ void ResourceCache::recycle(SkBitmap* resource) { } } +void ResourceCache::destructor(SkPath* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // If we're not tracking this resource, just delete it + if (Caches::hasInstance()) { + Caches::getInstance().pathCache.removeDeferred(resource); + } + delete resource; + return; + } + ref->destroyed = true; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + return; + } +} + void ResourceCache::destructor(SkBitmap* resource) { Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; @@ -196,6 +218,15 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r delete bitmap; } break; + case kPath: + { + SkPath* path = (SkPath*)resource; + if (Caches::hasInstance()) { + Caches::getInstance().pathCache.removeDeferred(path); + } + delete path; + } + break; case kShader: { SkiaShader* shader = (SkiaShader*)resource; diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h index 1bb4390f82d9..2a38910951c4 100644 --- a/libs/hwui/ResourceCache.h +++ b/libs/hwui/ResourceCache.h @@ -32,6 +32,7 @@ enum ResourceType { kBitmap, kShader, kColorFilter, + kPath, }; class ResourceReference { @@ -53,15 +54,18 @@ class ResourceCache { public: ResourceCache(); ~ResourceCache(); + void incrementRefcount(SkPath* resource); void incrementRefcount(SkBitmap* resource); void incrementRefcount(SkiaShader* resource); void incrementRefcount(SkiaColorFilter* resource); void incrementRefcount(const void* resource, ResourceType resourceType); void decrementRefcount(void* resource); void decrementRefcount(SkBitmap* resource); + void decrementRefcount(SkPath* resource); void decrementRefcount(SkiaShader* resource); void decrementRefcount(SkiaColorFilter* resource); void recycle(SkBitmap* resource); + void destructor(SkPath* resource); void destructor(SkBitmap* resource); void destructor(SkiaShader* resource); void destructor(SkiaColorFilter* resource); diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp new file mode 100644 index 000000000000..0d7cd9cb9a72 --- /dev/null +++ b/libs/hwui/ShapeCache.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2011 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 "OpenGLRenderer" + +#include "ShapeCache.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Rounded rects +/////////////////////////////////////////////////////////////////////////////// + +RoundRectShapeCache::RoundRectShapeCache(): ShapeCache<RoundRectShapeCacheEntry>( + "round rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) { +} + +PathTexture* RoundRectShapeCache::getRoundRect(float width, float height, + float rx, float ry, SkPaint* paint) { + RoundRectShapeCacheEntry entry(width, height, rx, ry, paint); + PathTexture* texture = get(entry); + + if (!texture) { + SkPath path; + SkRect r; + r.set(0.0f, 0.0f, width, height); + path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); + + texture = addTexture(entry, &path, paint); + } + + return texture; +} + +/////////////////////////////////////////////////////////////////////////////// +// Circles +/////////////////////////////////////////////////////////////////////////////// + +CircleShapeCache::CircleShapeCache(): ShapeCache<CircleShapeCacheEntry>( + "circle", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) { +} + +PathTexture* CircleShapeCache::getCircle(float radius, SkPaint* paint) { + CircleShapeCacheEntry entry(radius, paint); + PathTexture* texture = get(entry); + + if (!texture) { + SkPath path; + path.addCircle(radius, radius, radius, SkPath::kCW_Direction); + + texture = addTexture(entry, &path, paint); + } + + return texture; +} + +/////////////////////////////////////////////////////////////////////////////// +// Ovals +/////////////////////////////////////////////////////////////////////////////// + +OvalShapeCache::OvalShapeCache(): ShapeCache<OvalShapeCacheEntry>( + "oval", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) { +} + +PathTexture* OvalShapeCache::getOval(float width, float height, SkPaint* paint) { + OvalShapeCacheEntry entry(width, height, paint); + PathTexture* texture = get(entry); + + if (!texture) { + SkPath path; + SkRect r; + r.set(0.0f, 0.0f, width, height); + path.addOval(r, SkPath::kCW_Direction); + + texture = addTexture(entry, &path, paint); + } + + return texture; +} + +/////////////////////////////////////////////////////////////////////////////// +// Rects +/////////////////////////////////////////////////////////////////////////////// + +RectShapeCache::RectShapeCache(): ShapeCache<RectShapeCacheEntry>( + "rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) { +} + +PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) { + RectShapeCacheEntry entry(width, height, paint); + PathTexture* texture = get(entry); + + if (!texture) { + SkPath path; + path.addRect(0.0f, 0.0f, width, height, SkPath::kCW_Direction); + + texture = addTexture(entry, &path, paint); + } + + return texture; +} + +/////////////////////////////////////////////////////////////////////////////// +// Arcs +/////////////////////////////////////////////////////////////////////////////// + +ArcShapeCache::ArcShapeCache(): ShapeCache<ArcShapeCacheEntry>( + "arc", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) { +} + +PathTexture* ArcShapeCache::getArc(float width, float height, + float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { + ArcShapeCacheEntry entry(width, height, startAngle, sweepAngle, useCenter, paint); + PathTexture* texture = get(entry); + + if (!texture) { + SkPath path; + SkRect r; + r.set(0.0f, 0.0f, width, height); + if (useCenter) { + path.moveTo(r.centerX(), r.centerY()); + } + path.arcTo(r, startAngle, sweepAngle, !useCenter); + if (useCenter) { + path.close(); + } + + texture = addTexture(entry, &path, paint); + } + + return texture; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h new file mode 100644 index 000000000000..e53546605f13 --- /dev/null +++ b/libs/hwui/ShapeCache.h @@ -0,0 +1,630 @@ +/* + * Copyright (C) 2011 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_HWUI_SHAPE_CACHE_H +#define ANDROID_HWUI_SHAPE_CACHE_H + +#include <GLES2/gl2.h> + +#include <SkBitmap.h> +#include <SkCanvas.h> +#include <SkPaint.h> +#include <SkPath.h> +#include <SkRect.h> + +#include "Debug.h" +#include "Properties.h" +#include "Texture.h" +#include "utils/Compare.h" +#include "utils/GenerationCache.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#if DEBUG_SHAPES + #define SHAPE_LOGD(...) LOGD(__VA_ARGS__) +#else + #define SHAPE_LOGD(...) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Classes +/////////////////////////////////////////////////////////////////////////////// + +/** + * Alpha texture used to represent a path. + */ +struct PathTexture: public Texture { + PathTexture(): Texture() { + } + + /** + * Left coordinate of the path bounds. + */ + float left; + /** + * Top coordinate of the path bounds. + */ + float top; + /** + * Offset to draw the path at the correct origin. + */ + float offset; +}; // struct PathTexture + +/** + * Describe a shape in the shape cache. + */ +struct ShapeCacheEntry { + enum ShapeType { + kShapeNone, + kShapeRect, + kShapeRoundRect, + kShapeCircle, + kShapeOval, + kShapeArc, + kShapePath + }; + + ShapeCacheEntry() { + shapeType = kShapeNone; + join = SkPaint::kDefault_Join; + cap = SkPaint::kDefault_Cap; + style = SkPaint::kFill_Style; + miter = 4.0f; + strokeWidth = 1.0f; + } + + ShapeCacheEntry(const ShapeCacheEntry& entry): + shapeType(entry.shapeType), join(entry.join), cap(entry.cap), + style(entry.style), miter(entry.miter), + strokeWidth(entry.strokeWidth) { + } + + ShapeCacheEntry(ShapeType type, SkPaint* paint) { + shapeType = type; + join = paint->getStrokeJoin(); + cap = paint->getStrokeCap(); + float v = paint->getStrokeMiter(); + miter = *(uint32_t*) &v; + v = paint->getStrokeWidth(); + strokeWidth = *(uint32_t*) &v; + style = paint->getStyle(); + } + + virtual ~ShapeCacheEntry() { + } + + // shapeType must be checked in subclasses operator< + ShapeType shapeType; + SkPaint::Join join; + SkPaint::Cap cap; + SkPaint::Style style; + uint32_t miter; + uint32_t strokeWidth; + + bool operator<(const ShapeCacheEntry& rhs) const { + LTE_INT(shapeType) { + LTE_INT(join) { + LTE_INT(cap) { + LTE_INT(style) { + LTE_INT(miter) { + LTE_INT(strokeWidth) { + return lessThan(rhs); + } + } + } + } + } + } + return false; + } + +protected: + virtual bool lessThan(const ShapeCacheEntry& rhs) const { + return false; + } +}; // struct ShapeCacheEntry + + +struct RoundRectShapeCacheEntry: public ShapeCacheEntry { + RoundRectShapeCacheEntry(float width, float height, float rx, float ry, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapeRoundRect, paint) { + mWidth = *(uint32_t*) &width; + mHeight = *(uint32_t*) &height; + mRx = *(uint32_t*) ℞ + mRy = *(uint32_t*) &ry; + } + + RoundRectShapeCacheEntry(): ShapeCacheEntry() { + mWidth = 0; + mHeight = 0; + mRx = 0; + mRy = 0; + } + + RoundRectShapeCacheEntry(const RoundRectShapeCacheEntry& entry): + ShapeCacheEntry(entry) { + mWidth = entry.mWidth; + mHeight = entry.mHeight; + mRx = entry.mRx; + mRy = entry.mRy; + } + + bool lessThan(const ShapeCacheEntry& r) const { + const RoundRectShapeCacheEntry& rhs = (const RoundRectShapeCacheEntry&) r; + LTE_INT(mWidth) { + LTE_INT(mHeight) { + LTE_INT(mRx) { + LTE_INT(mRy) { + return false; + } + } + } + } + return false; + } + +private: + uint32_t mWidth; + uint32_t mHeight; + uint32_t mRx; + uint32_t mRy; +}; // RoundRectShapeCacheEntry + +struct CircleShapeCacheEntry: public ShapeCacheEntry { + CircleShapeCacheEntry(float radius, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) { + mRadius = *(uint32_t*) &radius; + } + + CircleShapeCacheEntry(): ShapeCacheEntry() { + mRadius = 0; + } + + CircleShapeCacheEntry(const CircleShapeCacheEntry& entry): + ShapeCacheEntry(entry) { + mRadius = entry.mRadius; + } + + bool lessThan(const ShapeCacheEntry& r) const { + const CircleShapeCacheEntry& rhs = (const CircleShapeCacheEntry&) r; + LTE_INT(mRadius) { + return false; + } + return false; + } + +private: + uint32_t mRadius; +}; // CircleShapeCacheEntry + +struct OvalShapeCacheEntry: public ShapeCacheEntry { + OvalShapeCacheEntry(float width, float height, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) { + mWidth = *(uint32_t*) &width; + mHeight = *(uint32_t*) &height; + } + + OvalShapeCacheEntry(): ShapeCacheEntry() { + mWidth = mHeight = 0; + } + + OvalShapeCacheEntry(const OvalShapeCacheEntry& entry): + ShapeCacheEntry(entry) { + mWidth = entry.mWidth; + mHeight = entry.mHeight; + } + + bool lessThan(const ShapeCacheEntry& r) const { + const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r; + LTE_INT(mWidth) { + LTE_INT(mHeight) { + return false; + } + } + return false; + } + +private: + uint32_t mWidth; + uint32_t mHeight; +}; // OvalShapeCacheEntry + +struct RectShapeCacheEntry: public ShapeCacheEntry { + RectShapeCacheEntry(float width, float height, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) { + mWidth = *(uint32_t*) &width; + mHeight = *(uint32_t*) &height; + } + + RectShapeCacheEntry(): ShapeCacheEntry() { + mWidth = mHeight = 0; + } + + RectShapeCacheEntry(const RectShapeCacheEntry& entry): + ShapeCacheEntry(entry) { + mWidth = entry.mWidth; + mHeight = entry.mHeight; + } + + bool lessThan(const ShapeCacheEntry& r) const { + const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r; + LTE_INT(mWidth) { + LTE_INT(mHeight) { + return false; + } + } + return false; + } + +private: + uint32_t mWidth; + uint32_t mHeight; +}; // RectShapeCacheEntry + +struct ArcShapeCacheEntry: public ShapeCacheEntry { + ArcShapeCacheEntry(float width, float height, float startAngle, float sweepAngle, + bool useCenter, SkPaint* paint): + ShapeCacheEntry(ShapeCacheEntry::kShapeArc, paint) { + mWidth = *(uint32_t*) &width; + mHeight = *(uint32_t*) &height; + mStartAngle = *(uint32_t*) &startAngle; + mSweepAngle = *(uint32_t*) &sweepAngle; + mUseCenter = useCenter ? 1 : 0; + } + + ArcShapeCacheEntry(): ShapeCacheEntry() { + mWidth = 0; + mHeight = 0; + mStartAngle = 0; + mSweepAngle = 0; + mUseCenter = 0; + } + + ArcShapeCacheEntry(const ArcShapeCacheEntry& entry): + ShapeCacheEntry(entry) { + mWidth = entry.mWidth; + mHeight = entry.mHeight; + mStartAngle = entry.mStartAngle; + mSweepAngle = entry.mSweepAngle; + mUseCenter = entry.mUseCenter; + } + + bool lessThan(const ShapeCacheEntry& r) const { + const ArcShapeCacheEntry& rhs = (const ArcShapeCacheEntry&) r; + LTE_INT(mWidth) { + LTE_INT(mHeight) { + LTE_INT(mStartAngle) { + LTE_INT(mSweepAngle) { + LTE_INT(mUseCenter) { + return false; + } + } + } + } + } + return false; + } + +private: + uint32_t mWidth; + uint32_t mHeight; + uint32_t mStartAngle; + uint32_t mSweepAngle; + uint32_t mUseCenter; +}; // ArcShapeCacheEntry + +/** + * A simple LRU shape cache. The cache has a maximum size expressed in bytes. + * Any texture added to the cache causing the cache to grow beyond the maximum + * allowed size will also cause the oldest texture to be kicked out. + */ +template<typename Entry> +class ShapeCache: public OnEntryRemoved<Entry, PathTexture*> { +public: + ShapeCache(const char* name, const char* propertyName, float defaultSize); + ~ShapeCache(); + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(Entry& path, PathTexture*& texture); + + /** + * Clears the cache. This causes all textures to be deleted. + */ + void clear(); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +protected: + PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint); + + PathTexture* get(Entry entry) { + return mCache.get(entry); + } + + void removeTexture(PathTexture* texture); + + GenerationCache<Entry, PathTexture*> mCache; + uint32_t mSize; + uint32_t mMaxSize; + GLuint mMaxTextureSize; + + char* mName; + bool mDebugEnabled; + +private: + /** + * Generates the texture from a bitmap into the specified texture structure. + */ + void generateTexture(SkBitmap& bitmap, Texture* texture); + + void init(); +}; // class ShapeCache + +class RoundRectShapeCache: public ShapeCache<RoundRectShapeCacheEntry> { +public: + RoundRectShapeCache(); + + PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint); +}; // class RoundRectShapeCache + +class CircleShapeCache: public ShapeCache<CircleShapeCacheEntry> { +public: + CircleShapeCache(); + + PathTexture* getCircle(float radius, SkPaint* paint); +}; // class CircleShapeCache + +class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> { +public: + OvalShapeCache(); + + PathTexture* getOval(float width, float height, SkPaint* paint); +}; // class OvalShapeCache + +class RectShapeCache: public ShapeCache<RectShapeCacheEntry> { +public: + RectShapeCache(); + + PathTexture* getRect(float width, float height, SkPaint* paint); +}; // class RectShapeCache + +class ArcShapeCache: public ShapeCache<ArcShapeCacheEntry> { +public: + ArcShapeCache(); + + PathTexture* getArc(float width, float height, float startAngle, float sweepAngle, + bool useCenter, SkPaint* paint); +}; // class ArcShapeCache + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +template<class Entry> +ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize): + mCache(GenerationCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(defaultSize)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(propertyName, property, NULL) > 0) { + INIT_LOGD(" Setting %s cache size to %sMB", name, property); + setMaxSize(MB(atof(property))); + } else { + INIT_LOGD(" Using default %s cache size of %.2fMB", name, defaultSize); + } + + size_t len = strlen(name); + mName = new char[len + 1]; + strcpy(mName, name); + mName[len] = '\0'; + + init(); +} + +template<class Entry> +ShapeCache<Entry>::~ShapeCache() { + mCache.clear(); + delete[] mName; +} + +template<class Entry> +void ShapeCache<Entry>::init() { + mCache.setOnEntryRemovedListener(this); + + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + mMaxTextureSize = maxTextureSize; + + mDebugEnabled = readDebugLevel() & kDebugCaches; +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +template<class Entry> +uint32_t ShapeCache<Entry>::getSize() { + return mSize; +} + +template<class Entry> +uint32_t ShapeCache<Entry>::getMaxSize() { + return mMaxSize; +} + +template<class Entry> +void ShapeCache<Entry>::setMaxSize(uint32_t maxSize) { + mMaxSize = maxSize; + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +/////////////////////////////////////////////////////////////////////////////// + +template<class Entry> +void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) { + removeTexture(texture); +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +template<class Entry> +void ShapeCache<Entry>::removeTexture(PathTexture* texture) { + if (texture) { + const uint32_t size = texture->width * texture->height; + mSize -= size; + + SHAPE_LOGD("ShapeCache::callback: delete %s: name, size, mSize = %d, %d, %d", + mName, texture->id, size, mSize); + if (mDebugEnabled) { + LOGD("Shape %s deleted, size = %d", mName, size); + } + + glDeleteTextures(1, &texture->id); + delete texture; + } +} + +template<class Entry> +PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path, + const SkPaint* paint) { + const SkRect& bounds = path->getBounds(); + + const float pathWidth = fmax(bounds.width(), 1.0f); + const float pathHeight = fmax(bounds.height(), 1.0f); + + if (pathWidth > mMaxTextureSize || pathHeight > mMaxTextureSize) { + LOGW("Shape %s too large to be rendered into a texture", mName); + return NULL; + } + + const float offset = paint->getStrokeWidth() * 1.5f; + const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5); + const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5); + + const uint32_t size = width * height; + // Don't even try to cache a bitmap that's bigger than the cache + if (size < mMaxSize) { + while (mSize + size > mMaxSize) { + mCache.removeOldest(); + } + } + + PathTexture* texture = new PathTexture; + texture->left = bounds.fLeft; + texture->top = bounds.fTop; + texture->offset = offset; + texture->width = width; + texture->height = height; + texture->generation = path->getGenerationID(); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kA8_Config, width, height); + bitmap.allocPixels(); + bitmap.eraseColor(0); + + SkPaint pathPaint(*paint); + + // Make sure the paint is opaque, color, alpha, filter, etc. + // will be applied later when compositing the alpha8 texture + pathPaint.setColor(0xff000000); + pathPaint.setAlpha(255); + pathPaint.setColorFilter(NULL); + pathPaint.setMaskFilter(NULL); + pathPaint.setShader(NULL); + SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode); + pathPaint.setXfermode(mode)->safeUnref(); + + SkCanvas canvas(bitmap); + canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset); + canvas.drawPath(*path, pathPaint); + + generateTexture(bitmap, texture); + + if (size < mMaxSize) { + mSize += size; + SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d", + mName, texture->id, size, mSize); + if (mDebugEnabled) { + LOGD("Shape %s created, size = %d", mName, size); + } + mCache.put(entry, texture); + } else { + texture->cleanup = true; + } + + return texture; +} + +template<class Entry> +void ShapeCache<Entry>::clear() { + mCache.clear(); +} + +template<class Entry> +void ShapeCache<Entry>::generateTexture(SkBitmap& bitmap, Texture* texture) { + SkAutoLockPixels alp(bitmap); + if (!bitmap.readyToDraw()) { + LOGE("Cannot generate texture from bitmap"); + return; + } + + glGenTextures(1, &texture->id); + + glBindTexture(GL_TEXTURE_2D, texture->id); + // Textures are Alpha8 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + texture->blend = true; + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels()); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_SHAPE_CACHE_H diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 590a9d7c41b8..8878c709809e 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -47,10 +47,22 @@ static const GLint gTileModes[] = { // Base shader /////////////////////////////////////////////////////////////////////////////// +void SkiaShader::copyFrom(const SkiaShader& shader) { + mType = shader.mType; + mKey = shader.mKey; + mTileX = shader.mTileX; + mTileY = shader.mTileY; + mBlend = shader.mBlend; + mUnitMatrix = shader.mUnitMatrix; + mShaderMatrix = shader.mShaderMatrix; + mGenerationId = shader.mGenerationId; +} + SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool blend): mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) { setMatrix(matrix); + mGenerationId = 0; } SkiaShader::~SkiaShader() { @@ -90,6 +102,13 @@ SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::Ti updateLocalMatrix(matrix); } +SkiaShader* SkiaBitmapShader::copy() { + SkiaBitmapShader* copy = new SkiaBitmapShader(); + copy->copyFrom(*this); + copy->mBitmap = mBitmap; + return copy; +} + void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { Texture* texture = mTextureCache->get(mBitmap); if (!texture) return; @@ -183,6 +202,19 @@ SkiaLinearGradientShader::~SkiaLinearGradientShader() { delete[] mPositions; } +SkiaShader* SkiaLinearGradientShader::copy() { + SkiaLinearGradientShader* copy = new SkiaLinearGradientShader(); + copy->copyFrom(*this); + copy->mBounds = new float[4]; + memcpy(copy->mBounds, mBounds, sizeof(float) * 4); + copy->mColors = new uint32_t[mCount]; + memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); + copy->mPositions = new float[mCount]; + memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); + copy->mCount = mCount; + return copy; +} + void SkiaLinearGradientShader::describe(ProgramDescription& description, const Extensions& extensions) { description.hasGradient = true; @@ -238,6 +270,17 @@ SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float r updateLocalMatrix(matrix); } +SkiaShader* SkiaCircularGradientShader::copy() { + SkiaCircularGradientShader* copy = new SkiaCircularGradientShader(); + copy->copyFrom(*this); + copy->mColors = new uint32_t[mCount]; + memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); + copy->mPositions = new float[mCount]; + memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); + copy->mCount = mCount; + return copy; +} + void SkiaCircularGradientShader::describe(ProgramDescription& description, const Extensions& extensions) { description.hasGradient = true; @@ -276,6 +319,17 @@ SkiaSweepGradientShader::~SkiaSweepGradientShader() { delete[] mPositions; } +SkiaShader* SkiaSweepGradientShader::copy() { + SkiaSweepGradientShader* copy = new SkiaSweepGradientShader(); + copy->copyFrom(*this); + copy->mColors = new uint32_t[mCount]; + memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); + copy->mPositions = new float[mCount]; + memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); + copy->mCount = mCount; + return copy; +} + void SkiaSweepGradientShader::describe(ProgramDescription& description, const Extensions& extensions) { description.hasGradient = true; @@ -315,7 +369,25 @@ void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& mod SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key): SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) { + NULL, first->blend() || second->blend()), + mFirst(first), mSecond(second), mMode(mode), mCleanup(false) { +} + +SkiaComposeShader::~SkiaComposeShader() { + if (mCleanup) { + delete mFirst; + delete mSecond; + } +} + +SkiaShader* SkiaComposeShader::copy() { + SkiaComposeShader* copy = new SkiaComposeShader(); + copy->copyFrom(*this); + copy->mFirst = mFirst->copy(); + copy->mSecond = mSecond->copy(); + copy->mMode = mMode; + copy->cleanup(); + return copy; } void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) { diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h index 6702129ad297..89dd131f8ab2 100644 --- a/libs/hwui/SkiaShader.h +++ b/libs/hwui/SkiaShader.h @@ -56,6 +56,9 @@ struct SkiaShader { SkMatrix* matrix, bool blend); virtual ~SkiaShader(); + virtual SkiaShader* copy() = 0; + void copyFrom(const SkiaShader& shader); + virtual void describe(ProgramDescription& description, const Extensions& extensions); virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, GLuint* textureUnit); @@ -81,8 +84,13 @@ struct SkiaShader { const Snapshot& snapshot) { } + uint32_t getGenerationId() { + return mGenerationId; + } + void setMatrix(SkMatrix* matrix) { updateLocalMatrix(matrix); + mGenerationId++; } void updateLocalMatrix(const SkMatrix* matrix) { @@ -97,6 +105,9 @@ struct SkiaShader { void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView); protected: + SkiaShader() { + } + /** * The appropriate texture unit must have been activated prior to invoking * this method. @@ -114,6 +125,9 @@ protected: mat4 mUnitMatrix; mat4 mShaderMatrix; + +private: + uint32_t mGenerationId; }; // struct SkiaShader @@ -127,6 +141,7 @@ protected: struct SkiaBitmapShader: public SkiaShader { SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool blend); + SkiaShader* copy(); void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, @@ -134,6 +149,9 @@ struct SkiaBitmapShader: public SkiaShader { void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); private: + SkiaBitmapShader() { + } + /** * This method does not work for n == 0. */ @@ -154,6 +172,7 @@ struct SkiaLinearGradientShader: public SkiaShader { SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); ~SkiaLinearGradientShader(); + SkiaShader* copy(); void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, @@ -161,6 +180,9 @@ struct SkiaLinearGradientShader: public SkiaShader { void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); private: + SkiaLinearGradientShader() { + } + float* mBounds; uint32_t* mColors; float* mPositions; @@ -174,6 +196,7 @@ struct SkiaSweepGradientShader: public SkiaShader { SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend); ~SkiaSweepGradientShader(); + SkiaShader* copy(); virtual void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, @@ -183,6 +206,8 @@ struct SkiaSweepGradientShader: public SkiaShader { protected: SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + SkiaSweepGradientShader() { + } uint32_t* mColors; float* mPositions; @@ -195,8 +220,13 @@ protected: struct SkiaCircularGradientShader: public SkiaSweepGradientShader { SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions, int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + SkiaShader* copy(); void describe(ProgramDescription& description, const Extensions& extensions); + +private: + SkiaCircularGradientShader() { + } }; // struct SkiaCircularGradientShader /** @@ -204,6 +234,8 @@ struct SkiaCircularGradientShader: public SkiaSweepGradientShader { */ struct SkiaComposeShader: public SkiaShader { SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key); + ~SkiaComposeShader(); + SkiaShader* copy(); void set(TextureCache* textureCache, GradientCache* gradientCache); @@ -212,9 +244,18 @@ struct SkiaComposeShader: public SkiaShader { GLuint* textureUnit); private: + SkiaComposeShader(): mCleanup(false) { + } + + void cleanup() { + mCleanup = true; + } + SkiaShader* mFirst; SkiaShader* mSecond; SkXfermode::Mode mMode; + + bool mCleanup; }; // struct SkiaComposeShader }; // namespace uirenderer diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 9898df491eba..bd7031927b5e 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -150,6 +150,10 @@ public: break; case SkRegion::kIntersect_Op: clipped = clipRect->intersect(r); + if (!clipped) { + clipRect->setEmpty(); + clipped = true; + } break; case SkRegion::kUnion_Op: clipped = clipRect->unionWith(r); @@ -268,7 +272,7 @@ public: Rect* clipRect; /** - * The ancestor layer's dirty region.. + * The ancestor layer's dirty region. */ Region* region; diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index d96a7f516022..32567904161c 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "OpenGLRenderer" +#include "Debug.h" #include "TextDropShadowCache.h" #include "Properties.h" @@ -31,10 +32,11 @@ TextDropShadowCache::TextDropShadowCache(): mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting drop shadow cache size to %sMB", property); + INIT_LOGD(" Setting drop shadow cache size to %sMB", property); setMaxSize(MB(atof(property))); } else { - LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE); + INIT_LOGD(" Using default drop shadow cache size of %.2fMB", + DEFAULT_DROP_SHADOW_CACHE_SIZE); } init(); diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index 8cefc8c6d541..ffccfa257324 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -32,7 +32,7 @@ namespace android { namespace uirenderer { struct ShadowText { - ShadowText(): radius(0), len(0), hash(0), textSize(0.0f), typeface(NULL) { + ShadowText(): radius(0), len(0), textSize(0.0f), typeface(NULL) { } ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText): @@ -42,20 +42,11 @@ struct ShadowText { textSize = paint->getTextSize(); typeface = paint->getTypeface(); - - hash = 0; - uint32_t multiplier = 1; - const char* text = str.string(); - for (uint32_t i = 0; i < len; i++) { - hash += text[i] * multiplier; - uint32_t shifted = multiplier << 5; - multiplier = shifted - multiplier; - } } ShadowText(const ShadowText& shadow): - radius(shadow.radius), len(shadow.len), hash(shadow.hash), - textSize(shadow.textSize), typeface(shadow.typeface), str(shadow.str) { + radius(shadow.radius), len(shadow.len), textSize(shadow.textSize), + typeface(shadow.typeface), str(shadow.str) { } ~ShadowText() { @@ -63,20 +54,17 @@ struct ShadowText { uint32_t radius; uint32_t len; - uint32_t hash; float textSize; SkTypeface* typeface; String8 str; bool operator<(const ShadowText& rhs) const { - LTE_INT(hash) { - LTE_INT(len) { - LTE_INT(radius) { - LTE_FLOAT(textSize) { - if (typeface < rhs.typeface) return true; - else if (typeface == rhs.typeface) { - return str.compare(rhs.str) < 0; - } + LTE_INT(len) { + LTE_INT(radius) { + LTE_FLOAT(textSize) { + if (typeface < rhs.typeface) return true; + else if (typeface == rhs.typeface) { + return str.compare(rhs.str) < 0; } } } diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index ebecebec9db7..e560b8f154f7 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -37,10 +37,10 @@ TextureCache::TextureCache(): mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting texture cache size to %sMB", property); + INIT_LOGD(" Setting texture cache size to %sMB", property); setMaxSize(MB(atof(property))); } else { - LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); + INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); } init(); @@ -60,7 +60,7 @@ void TextureCache::init() { mCache.setOnEntryRemovedListener(this); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); + INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); mDebugEnabled = readDebugLevel() & kDebugCaches; } diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 2ec003f989ea..25c8beb3b2f5 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -23,13 +23,17 @@ include $(BUILD_HOST_EXECUTABLE) # TODO: This should go into build/core/config.mk RSG_GENERATOR:=$(LOCAL_BUILT_MODULE) -include $(CLEAR_VARS) -input_data_file := $(LOCAL_PATH)/rslib.bc -slangdata_output_var_name := rs_runtime_lib_bc -LOCAL_MODULE := librslib_rt -LOCAL_MODULE_TAGS := optional -include frameworks/compile/slang/SlangData.mk -include $(BUILD_STATIC_LIBRARY) +# include $(CLEAR_VARS) +# input_data_file := $(LOCAL_PATH)/rslib.bc +# slangdata_output_var_name := rs_runtime_lib_bc +# LOCAL_MODULE := librslib_rt + +# LOCAL_PRELINK_MODULE := false +# LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +# LOCAL_MODULE_TAGS := optional +# include frameworks/compile/slang/SlangData.mk +# include $(BUILD_STATIC_LIBRARY) # Build render script lib ==================== @@ -113,11 +117,12 @@ LOCAL_SRC_FILES:= \ rsVertexArray.cpp -LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc +LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc -LOCAL_STATIC_LIBRARIES := libft2 librslib_rt +LOCAL_STATIC_LIBRARIES := libdex libft2 -LOCAL_C_INCLUDES += external/freetype/include +LOCAL_C_INCLUDES += external/freetype/include external/zlib dalvik +LOCAL_C_INCLUDES += frameworks/compile/libbcc/include LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libRS @@ -125,6 +130,28 @@ LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) +# Now build a host version for serialization +include $(CLEAR_VARS) +LOCAL_CFLAGS += -DANDROID_RS_SERIALIZE + +LOCAL_SRC_FILES:= \ + rsAllocation.cpp \ + rsComponent.cpp \ + rsElement.cpp \ + rsFileA3D.cpp \ + rsObjectBase.cpp \ + rsMesh.cpp \ + rsStream.cpp \ + rsType.cpp + +LOCAL_STATIC_LIBRARIES := libcutils libutils + +LOCAL_LDLIBS := -lpthread +LOCAL_MODULE:= libRSserialize +LOCAL_MODULE_TAGS := optional + +include $(BUILD_HOST_STATIC_LIBRARY) + # include the java examples include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk,\ java \ diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index 3ad453f4fa4f..bb5e4aa29015 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -111,6 +111,15 @@ enum RsAllocationMipmapControl { RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2 }; +enum RsAllocationCubemapFace { + RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5 +}; + enum RsDataType { RS_TYPE_NONE, RS_TYPE_FLOAT_16, @@ -325,7 +334,9 @@ typedef struct { // A3D loading and object update code. // Should only be called at object creation, not thread safe RsObjectBase rsaFileA3DGetEntryByIndex(RsContext, uint32_t idx, RsFile); -RsFile rsaFileA3DCreateFromAssetStream(RsContext, const void *data, uint32_t len); +RsFile rsaFileA3DCreateFromMemory(RsContext, const void *data, uint32_t len); +RsFile rsaFileA3DCreateFromAsset(RsContext, void *asset); +RsFile rsaFileA3DCreateFromFile(RsContext, const char *path); void rsaFileA3DGetNumIndexEntries(RsContext, int32_t *numEntries, RsFile); void rsaFileA3DGetIndexEntries(RsContext, RsFileIndexEntry *fileEntries,uint32_t numEntries, RsFile); void rsaGetName(RsContext, void * obj, const char **name); @@ -354,6 +365,9 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, RsAllocationMipmapControl mips, const void *data, uint32_t usages); +#ifdef ANDROID_RS_SERIALIZE +#define NO_RS_FUNCS +#endif #ifndef NO_RS_FUNCS #include "rsgApiFuncDecl.h" diff --git a/libs/rs/java/Balls/AndroidManifest.xml b/libs/rs/java/Balls/AndroidManifest.xml index 2fffc5f556a6..f3384ece05ee 100644 --- a/libs/rs/java/Balls/AndroidManifest.xml +++ b/libs/rs/java/Balls/AndroidManifest.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.balls"> + <uses-sdk android:minSdkVersion="11" /> <application android:label="Balls" android:icon="@drawable/test_pattern"> diff --git a/libs/rs/java/Balls/src/com/android/balls/BallsRS.java b/libs/rs/java/Balls/src/com/android/balls/BallsRS.java index 0a0639467262..50ee9212ae0f 100644 --- a/libs/rs/java/Balls/src/com/android/balls/BallsRS.java +++ b/libs/rs/java/Balls/src/com/android/balls/BallsRS.java @@ -50,7 +50,7 @@ public class BallsRS { private void createProgramVertex() { updateProjectionMatrices(); - ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS); + ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS); String t = "varying vec4 varColor;\n" + "void main() {\n" + " vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" + @@ -75,18 +75,27 @@ public class BallsRS { return allocation; } + ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + return builder.create(); + } + public void init(RenderScriptGL rs, Resources res, int width, int height) { mRS = rs; mRes = res; - ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs); + ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs); pfb.setPointSpriteTexCoordinateReplacement(true); - pfb.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, - ProgramFragment.Builder.Format.RGBA, 0); + pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); pfb.setVaryingColor(true); mPFPoints = pfb.create(); - pfb = new ProgramFragment.Builder(rs); + pfb = new ProgramFragmentFixedFunction.Builder(rs); pfb.setVaryingColor(true); mPFLines = pfb.create(); @@ -97,7 +106,7 @@ public class BallsRS { Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); smb.addVertexAllocation(mPoints.getAllocation()); - smb.addIndexType(Primitive.POINT); + smb.addIndexSetType(Mesh.Primitive.POINT); Mesh smP = smb.create(); mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics); @@ -113,7 +122,7 @@ public class BallsRS { mScript.set_gPFPoints(mPFPoints); createProgramVertex(); - mRS.bindProgramStore(ProgramStore.BLEND_ADD_DEPTH_NO_DEPTH(mRS)); + mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS)); mPhysicsScript.set_gMinPos(new Float2(5, 5)); mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5)); diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml index 951c45139269..5126e5c20815 100644 --- a/libs/rs/java/Fountain/AndroidManifest.xml +++ b/libs/rs/java/Fountain/AndroidManifest.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.fountain"> + <uses-sdk android:minSdkVersion="11" /> <application android:label="Fountain" android:icon="@drawable/test_pattern"> diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java index a5d06e98d81c..be2f9caefa03 100644 --- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java +++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java @@ -34,7 +34,7 @@ public class FountainRS { mRS = rs; mRes = res; - ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs); + ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs); pfb.setVaryingColor(true); rs.bindProgramFragment(pfb.create()); @@ -43,7 +43,7 @@ public class FountainRS { Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); smb.addVertexAllocation(points.getAllocation()); - smb.addIndexType(Primitive.POINT); + smb.addIndexSetType(Mesh.Primitive.POINT); Mesh sm = smb.create(); mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain); diff --git a/libs/rs/java/ImageProcessing/AndroidManifest.xml b/libs/rs/java/ImageProcessing/AndroidManifest.xml index d6a2db4a46ef..0fcbf1e70ae5 100644 --- a/libs/rs/java/ImageProcessing/AndroidManifest.xml +++ b/libs/rs/java/ImageProcessing/AndroidManifest.xml @@ -3,8 +3,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.rs.image"> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-sdk android:minSdkVersion="11" /> <application android:label="Image Processing"> <activity android:name="ImageProcessingActivity" android:screenOrientation="portrait"> diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs index e5900fd4938c..bd4ae4eca3b7 100644 --- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs @@ -55,6 +55,9 @@ void setGamma(float g) { gamma = (float3)g; } +//sliao +extern uchar3 __attribute__((overloadable)) convert2uchar3(float3 xyz); + void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { uchar4 *output = (uchar4 *)v_out; const FilterStruct *fs = (const FilterStruct *)usrData; diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java index 6cb50b8122fd..f91f31ee35e7 100644 --- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java @@ -23,6 +23,7 @@ import java.util.Vector; import android.content.res.Resources; import android.renderscript.*; import android.renderscript.Element.Builder; +import android.renderscript.Font.Style; import android.renderscript.ProgramStore.DepthFunc; import android.util.Log; @@ -53,7 +54,7 @@ public class SceneGraphRS { private ProgramStore mPSBackground; private ProgramFragment mPFBackground; private ProgramVertex mPVBackground; - private ProgramVertex.MatrixAllocation mPVA; + private ProgramVertexFixedFunction.Constants mPVA; private Allocation mGridImage; private Allocation mAllocPV; @@ -93,8 +94,8 @@ public class SceneGraphRS { ProgramStore.Builder b = new ProgramStore.Builder(mRS); b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnable(false); - b.setDepthMask(true); + b.setDitherEnabled(false); + b.setDepthMaskEnabled(true); mPSBackground = b.create(); mScript.set_gPFSBackground(mPSBackground); @@ -102,15 +103,15 @@ public class SceneGraphRS { private void initPF() { Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.CLAMP); bs.setWrapT(Sampler.Value.CLAMP); mSampler = bs.create(); - ProgramFragment.Builder b = new ProgramFragment.Builder(mRS); - b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, - ProgramFragment.Builder.Format.RGBA, 0); + ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); + b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mPFBackground = b.create(); mPFBackground.bindSampler(mSampler, 0); @@ -118,11 +119,11 @@ public class SceneGraphRS { } private void initPV() { - ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); mPVBackground = pvb.create(); - mPVA = new ProgramVertex.MatrixAllocation(mRS); - mPVBackground.bindAllocation(mPVA); + mPVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); mScript.set_gPVBackground(mPVBackground); } @@ -186,22 +187,20 @@ public class SceneGraphRS { FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { Log.e("rs", "could not load model"); } else { mMesh = (Mesh)entry.getObject(); mScript.set_gTestMesh(mMesh); } - mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8); + mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); mScript.set_gItalic(mItalic); initTextAllocation(); initTransformHierarchy(); - Log.v("========SceneGraph========", "transform hierarchy initialized"); - mScript.bind_gRootNode(mRootTransform.getField()); mScript.bind_gGroup(mGroup1.mParent.mChildField); diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java index 747463a051d6..b18a327b1832 100644 --- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java @@ -50,7 +50,7 @@ public class SimpleModelRS { private ProgramStore mPSBackground; private ProgramFragment mPFBackground; private ProgramVertex mPVBackground; - private ProgramVertex.MatrixAllocation mPVA; + private ProgramVertexFixedFunction.Constants mPVA; private Allocation mGridImage; private Allocation mAllocPV; @@ -89,8 +89,8 @@ public class SimpleModelRS { ProgramStore.Builder b = new ProgramStore.Builder(mRS); b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnable(false); - b.setDepthMask(true); + b.setDitherEnabled(false); + b.setDepthMaskEnabled(true); mPSBackground = b.create(); mScript.set_gPFSBackground(mPSBackground); @@ -98,15 +98,15 @@ public class SimpleModelRS { private void initPF() { Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.CLAMP); bs.setWrapT(Sampler.Value.CLAMP); mSampler = bs.create(); - ProgramFragment.Builder b = new ProgramFragment.Builder(mRS); - b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, - ProgramFragment.Builder.Format.RGBA, 0); + ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); + b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mPFBackground = b.create(); mPFBackground.bindSampler(mSampler, 0); @@ -114,11 +114,11 @@ public class SimpleModelRS { } private void initPV() { - ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); mPVBackground = pvb.create(); - mPVA = new ProgramVertex.MatrixAllocation(mRS); - mPVBackground.bindAllocation(mPVA); + mPVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); mScript.set_gPVBackground(mPVBackground); } @@ -148,14 +148,14 @@ public class SimpleModelRS { FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { Log.e("rs", "could not load model"); } else { mMesh = (Mesh)entry.getObject(); mScript.set_gTestMesh(mMesh); } - mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8); + mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); mScript.set_gItalic(mItalic); initTextAllocation(); diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs index 3bee8d6d167f..36790686feca 100644 --- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs @@ -81,7 +81,7 @@ int root(int launchID) { rsgProgramVertexLoadModelMatrix(&robot2Ptr->globalMat); rsgDrawMesh(gTestMesh); - color(0.3f, 0.3f, 0.3f, 1.0f); + //color(0.3f, 0.3f, 0.3f, 1.0f); rsgDrawText("Renderscript transform test", 30, 695); rsgBindFont(gItalic); diff --git a/libs/rs/java/Samples/AndroidManifest.xml b/libs/rs/java/Samples/AndroidManifest.xml index 9646a77790fe..8dad1612e163 100644 --- a/libs/rs/java/Samples/AndroidManifest.xml +++ b/libs/rs/java/Samples/AndroidManifest.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.samples"> + <uses-sdk android:minSdkVersion="11" /> <application android:label="Samples" android:icon="@drawable/test_pattern"> <activity android:name="RsList" diff --git a/libs/rs/java/Samples/res/drawable/cubemap_test.png b/libs/rs/java/Samples/res/drawable/cubemap_test.png Binary files differindex 75ad0a421775..baf35d0acbe9 100644 --- a/libs/rs/java/Samples/res/drawable/cubemap_test.png +++ b/libs/rs/java/Samples/res/drawable/cubemap_test.png diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java index ddb05b38b1c5..1afcee335a50 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java @@ -22,10 +22,11 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; -import android.renderscript.Allocation.CubemapLayout; import android.renderscript.Allocation.MipmapControl; import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; +import android.renderscript.ProgramStore.BlendSrcFunc; +import android.renderscript.ProgramStore.BlendDstFunc; import android.renderscript.Sampler.Value; import android.util.Log; @@ -69,7 +70,7 @@ public class RsBenchRS { private ProgramFragment mProgFragmentColor; private ProgramVertex mProgVertex; - private ProgramVertex.MatrixAllocation mPVA; + private ProgramVertexFixedFunction.Constants mPVA; // Custom shaders private ProgramVertex mProgVertexCustom; @@ -122,6 +123,15 @@ public class RsBenchRS { mScript.set_gDisplayMode(mMode); } + ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + return builder.create(); + } + private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, @@ -155,18 +165,18 @@ public class RsBenchRS { private void initProgramStore() { // Use stock the stock program store object mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS); - mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NO_DEPTH(mRS); + mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS); // Create a custom program store ProgramStore.Builder builder = new ProgramStore.Builder(mRS); builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); - builder.setDitherEnable(false); - builder.setDepthMask(false); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); mProgStoreBlendAlpha = builder.create(); - mProgStoreBlendAdd = ProgramStore.BLEND_ADD_DEPTH_NO_DEPTH(mRS); + mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS); mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); mScript.set_gProgStoreBlendNone(mProgStoreBlendNone); @@ -176,13 +186,13 @@ public class RsBenchRS { private void initProgramFragment() { - ProgramFragment.Builder texBuilder = new ProgramFragment.Builder(mRS); - texBuilder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, - ProgramFragment.Builder.Format.RGBA, 0); + ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mProgFragmentTexture = texBuilder.create(); mProgFragmentTexture.bindSampler(mLinearClamp, 0); - ProgramFragment.Builder colBuilder = new ProgramFragment.Builder(mRS); + ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); colBuilder.setVaryingColor(false); mProgFragmentColor = colBuilder.create(); @@ -191,12 +201,14 @@ public class RsBenchRS { } private void initProgramVertex() { - ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); mProgVertex = pvb.create(); - mPVA = new ProgramVertex.MatrixAllocation(mRS); - mProgVertex.bindAllocation(mPVA); - mPVA.setupOrthoWindow(mWidth, mHeight); + mPVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(mWidth, mHeight); + mPVA.setProjection(proj); mScript.set_gProgVertex(mProgVertex); } @@ -213,7 +225,7 @@ public class RsBenchRS { mScript.bind_gFSConstPixel(mFSConstPixel); // Initialize the shader builder - ProgramVertex.ShaderBuilder pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); // Specify the resource that contains the shader string pvbCustom.setShader(mRes, R.raw.shaderv); // Use a script field to specify the input layout @@ -224,7 +236,7 @@ public class RsBenchRS { // Bind the source of constant data mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); - ProgramFragment.ShaderBuilder pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); // Specify the resource that contains the shader string pfbCustom.setShader(mRes, R.raw.shaderf); // Tell the builder how many textures we have @@ -236,42 +248,44 @@ public class RsBenchRS { mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); // Cubemap test shaders - pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom = new ProgramVertex.Builder(mRS); pvbCustom.setShader(mRes, R.raw.shadercubev); pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); pvbCustom.addConstant(mVSConst.getAllocation().getType()); mProgVertexCube = pvbCustom.create(); mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.shadercubef); pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE); mProgFragmentCube = pfbCustom.create(); - pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom = new ProgramVertex.Builder(mRS); pvbCustom.setShader(mRes, R.raw.shader2v); pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); mProgVertexPixelLight = pvbCustom.create(); mProgVertexPixelLight.bindConstants(mVSConstPixel.getAllocation(), 0); - pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom = new ProgramVertex.Builder(mRS); pvbCustom.setShader(mRes, R.raw.shader2movev); pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); mProgVertexPixelLightMove = pvbCustom.create(); mProgVertexPixelLightMove.bindConstants(mVSConstPixel.getAllocation(), 0); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.shader2f); pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); pfbCustom.addConstant(mFSConstPixel.getAllocation().getType()); mProgFragmentPixelLight = pfbCustom.create(); mProgFragmentPixelLight.bindConstants(mFSConstPixel.getAllocation(), 0); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.multitexf); - pfbCustom.setTextureCount(3); + for (int texCount = 0; texCount < 3; texCount ++) { + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + } mProgFragmentMultitex = pfbCustom.create(); mScript.set_gProgVertexCustom(mProgVertexCustom); @@ -303,8 +317,7 @@ public class RsBenchRS { mTexTransparent = loadTextureARGB(R.drawable.leaf); mTexChecker = loadTextureRGB(R.drawable.checker); Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); - mTexCube = Allocation.createCubemapFromBitmap(mRS, b, - Allocation.CubemapLayout.VERTICAL_FACE_LIST); + mTexCube = Allocation.createCubemapFromBitmap(mRS, b); mScript.set_gTexTorus(mTexTorus); mScript.set_gTexOpaque(mTexOpaque); @@ -315,22 +328,15 @@ public class RsBenchRS { private void initFonts() { // Sans font by family name - mFontSans = Font.createFromFamily(mRS, mRes, "sans-serif", - Font.Style.NORMAL, 8); - // Create font by file name - mFontSerif = Font.create(mRS, mRes, "DroidSerif-Regular.ttf", 8); + mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); + mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8); // Create fonts by family and style - mFontSerifBold = Font.createFromFamily(mRS, mRes, "serif", - Font.Style.BOLD, 8); - mFontSerifItalic = Font.createFromFamily(mRS, mRes, "serif", - Font.Style.ITALIC, 8); - mFontSerifBoldItalic = Font.createFromFamily(mRS, mRes, "serif", - Font.Style.BOLD_ITALIC, 8); - mFontMono = Font.createFromFamily(mRS, mRes, "mono", - Font.Style.NORMAL, 8); - - mTextAlloc = Allocation.createFromString(mRS, "String from allocation", - Allocation.USAGE_SCRIPT); + mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8); + mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); + mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); + mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8); + + mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT); mScript.set_gFontSans(mFontSans); mScript.set_gFontSerif(mFontSerif); @@ -351,7 +357,7 @@ public class RsBenchRS { FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { Log.e("rs", "could not load model"); } else { mTorus = (Mesh)entry.getObject(); @@ -361,8 +367,8 @@ public class RsBenchRS { private void initSamplers() { Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.WRAP); bs.setWrapT(Sampler.Value.WRAP); mLinearWrap = bs.create(); @@ -372,8 +378,8 @@ public class RsBenchRS { mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS); bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR_MIP_LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.WRAP); bs.setWrapT(Sampler.Value.WRAP); bs.setAnisotropy(8.0f); diff --git a/libs/rs/java/Samples/src/com/android/samples/RsListRS.java b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java index 223f5528e908..8e2d51f0dbe9 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsListRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java @@ -134,7 +134,7 @@ public class RsListRS { mScript.bind_gList(mListAllocs); - mItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); + mItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); mScript.set_gItalic(mItalic); mRS.bindRootScript(mScript); diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java index 75e8d998d60f..87840a765d03 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java @@ -22,9 +22,11 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; -import android.renderscript.Allocation.CubemapLayout; +import android.renderscript.Font.Style; import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; +import android.renderscript.ProgramStore.BlendSrcFunc; +import android.renderscript.ProgramStore.BlendDstFunc; import android.renderscript.Sampler.Value; import android.util.Log; @@ -68,7 +70,7 @@ public class RsRenderStatesRS { private ProgramFragment mProgFragmentColor; private ProgramVertex mProgVertex; - private ProgramVertex.MatrixAllocation mPVA; + private ProgramVertexFixedFunction.Constants mPVA; // Custom shaders private ProgramVertex mProgVertexCustom; @@ -119,6 +121,15 @@ public class RsRenderStatesRS { mScript.set_gDisplayMode(mMode); } + ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + return builder.create(); + } + private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, @@ -152,18 +163,18 @@ public class RsRenderStatesRS { private void initProgramStore() { // Use stock the stock program store object mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS); - mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NO_DEPTH(mRS); + mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS); // Create a custom program store ProgramStore.Builder builder = new ProgramStore.Builder(mRS); builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); - builder.setDitherEnable(false); - builder.setDepthMask(false); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); mProgStoreBlendAlpha = builder.create(); - mProgStoreBlendAdd = ProgramStore.BLEND_ADD_DEPTH_NO_DEPTH(mRS); + mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS); mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); mScript.set_gProgStoreBlendNone(mProgStoreBlendNone); @@ -173,13 +184,13 @@ public class RsRenderStatesRS { private void initProgramFragment() { - ProgramFragment.Builder texBuilder = new ProgramFragment.Builder(mRS); - texBuilder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, - ProgramFragment.Builder.Format.RGBA, 0); + ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mProgFragmentTexture = texBuilder.create(); mProgFragmentTexture.bindSampler(mLinearClamp, 0); - ProgramFragment.Builder colBuilder = new ProgramFragment.Builder(mRS); + ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); colBuilder.setVaryingColor(false); mProgFragmentColor = colBuilder.create(); @@ -188,12 +199,14 @@ public class RsRenderStatesRS { } private void initProgramVertex() { - ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); mProgVertex = pvb.create(); - mPVA = new ProgramVertex.MatrixAllocation(mRS); - mProgVertex.bindAllocation(mPVA); - mPVA.setupOrthoWindow(mWidth, mHeight); + mPVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(mWidth, mHeight); + mPVA.setProjection(proj); mScript.set_gProgVertex(mProgVertex); } @@ -210,7 +223,7 @@ public class RsRenderStatesRS { mScript.bind_gFSConstants2(mFSConst2); // Initialize the shader builder - ProgramVertex.ShaderBuilder pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); // Specify the resource that contains the shader string pvbCustom.setShader(mRes, R.raw.shaderv); // Use a script field to spcify the input layout @@ -221,47 +234,49 @@ public class RsRenderStatesRS { // Bind the source of constant data mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); - ProgramFragment.ShaderBuilder pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); // Specify the resource that contains the shader string pfbCustom.setShader(mRes, R.raw.shaderf); //Tell the builder how many textures we have - pfbCustom.setTextureCount(1); + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); // Define the constant input layout pfbCustom.addConstant(mFSConst.getAllocation().getType()); mProgFragmentCustom = pfbCustom.create(); // Bind the source of constant data mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); - pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom = new ProgramVertex.Builder(mRS); pvbCustom.setShader(mRes, R.raw.shaderarrayv); pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); pvbCustom.addConstant(mVSConst2.getAllocation().getType()); mProgVertexCustom2 = pvbCustom.create(); mProgVertexCustom2.bindConstants(mVSConst2.getAllocation(), 0); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.shaderarrayf); - pfbCustom.setTextureCount(1); + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); pfbCustom.addConstant(mFSConst2.getAllocation().getType()); mProgFragmentCustom2 = pfbCustom.create(); mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0); // Cubemap test shaders - pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom = new ProgramVertex.Builder(mRS); pvbCustom.setShader(mRes, R.raw.shadercubev); pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); pvbCustom.addConstant(mVSConst.getAllocation().getType()); mProgVertexCube = pvbCustom.create(); mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.shadercubef); pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE); mProgFragmentCube = pfbCustom.create(); - pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom = new ProgramFragment.Builder(mRS); pfbCustom.setShader(mRes, R.raw.multitexf); - pfbCustom.setTextureCount(3); + for (int texCount = 0; texCount < 3; texCount ++) { + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + } mProgFragmentMultitex = pfbCustom.create(); mScript.set_gProgVertexCustom(mProgVertexCustom); @@ -292,8 +307,7 @@ public class RsRenderStatesRS { mTexTransparent = loadTextureARGB(R.drawable.leaf); mTexChecker = loadTextureRGB(R.drawable.checker); Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); - mTexCube = Allocation.createCubemapFromBitmap(mRS, b, - Allocation.CubemapLayout.VERTICAL_FACE_LIST); + mTexCube = Allocation.createCubemapFromBitmap(mRS, b); mScript.set_gTexTorus(mTexTorus); mScript.set_gTexOpaque(mTexOpaque); @@ -304,14 +318,13 @@ public class RsRenderStatesRS { private void initFonts() { // Sans font by family name - mFontSans = Font.createFromFamily(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); - // Create font by file name - mFontSerif = Font.create(mRS, mRes, "DroidSerif-Regular.ttf", 8); + mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); + mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8); // Create fonts by family and style - mFontSerifBold = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD, 8); - mFontSerifItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mFontSerifBoldItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); - mFontMono = Font.createFromFamily(mRS, mRes, "mono", Font.Style.NORMAL, 8); + mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8); + mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); + mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); + mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8); mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT); @@ -330,7 +343,7 @@ public class RsRenderStatesRS { FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { Log.e("rs", "could not load model"); } else { mTorus = (Mesh)entry.getObject(); @@ -340,8 +353,8 @@ public class RsRenderStatesRS { private void initSamplers() { Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.WRAP); bs.setWrapT(Sampler.Value.WRAP); mLinearWrap = bs.create(); @@ -351,8 +364,8 @@ public class RsRenderStatesRS { mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS); bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR_MIP_LINEAR); - bs.setMag(Sampler.Value.LINEAR); + bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); bs.setWrapS(Sampler.Value.WRAP); bs.setWrapT(Sampler.Value.WRAP); bs.setAnisotropy(8.0f); diff --git a/libs/rs/java/Samples/src/com/android/samples/rsbench.rs b/libs/rs/java/Samples/src/com/android/samples/rsbench.rs index 905f34b8a24a..a1368e68fc10 100644 --- a/libs/rs/java/Samples/src/com/android/samples/rsbench.rs +++ b/libs/rs/java/Samples/src/com/android/samples/rsbench.rs @@ -297,7 +297,7 @@ static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) { if (buffer == 0) { rsgProgramVertexLoadModelMatrix(matrix); } else { - rsAllocationMarkDirty(rsGetAllocation(buffer)); + rsgAllocationSyncAll(rsGetAllocation(buffer)); } } @@ -409,7 +409,7 @@ static void setupCustomShaderLights() { gVSConstants->light1_Diffuse = 1.0f; gVSConstants->light1_Specular = 0.7f; gVSConstants->light1_CosinePower = 25.0f; - rsAllocationMarkDirty(rsGetAllocation(gVSConstants)); + rsgAllocationSyncAll(rsGetAllocation(gVSConstants)); // Update fragment shader constants // Set light 0 colors @@ -418,7 +418,7 @@ static void setupCustomShaderLights() { // Set light 1 colors gFSConstants->light1_DiffuseColor = light1DiffCol; gFSConstants->light1_SpecularColor = light1SpecCol; - rsAllocationMarkDirty(rsGetAllocation(gFSConstants)); + rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); // Set light 0 properties for per pixel lighting gFSConstPixel->light0_Posision = light0Pos; @@ -434,7 +434,7 @@ static void setupCustomShaderLights() { gFSConstPixel->light1_CosinePower = 25.0f; gFSConstPixel->light1_DiffuseColor = light1DiffCol; gFSConstPixel->light1_SpecularColor = light1SpecCol; - rsAllocationMarkDirty(rsGetAllocation(gFSConstPixel)); + rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel)); } static void displayCustomShaderSamples(int numMeshes) { diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs index 0baccb8ae412..b79f4fcf6637 100644 --- a/libs/rs/java/Samples/src/com/android/samples/rslist.rs +++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs @@ -44,7 +44,6 @@ int root(int launchID) { rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); rsgBindFont(gItalic); - color(0.2, 0.2, 0.2, 0); rs_allocation listAlloc; rsSetObject(&listAlloc, rsGetAllocation(gList)); diff --git a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs index a973167ed845..9019533c8d9b 100644 --- a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs +++ b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs @@ -407,7 +407,7 @@ static void setupCustomShaderLights() { gVSConstants->light1_Diffuse = 1.0f; gVSConstants->light1_Specular = 0.7f; gVSConstants->light1_CosinePower = 25.0f; - rsAllocationMarkDirty(rsGetAllocation(gVSConstants)); + rsgAllocationSyncAll(rsGetAllocation(gVSConstants)); gVSConstants2->light_Posision[0] = light0Pos; gVSConstants2->light_Diffuse[0] = 1.0f; @@ -417,7 +417,7 @@ static void setupCustomShaderLights() { gVSConstants2->light_Diffuse[1] = 1.0f; gVSConstants2->light_Specular[1] = 0.7f; gVSConstants2->light_CosinePower[1] = 25.0f; - rsAllocationMarkDirty(rsGetAllocation(gVSConstants2)); + rsgAllocationSyncAll(rsGetAllocation(gVSConstants2)); // Update fragmetn shader constants // Set light 0 colors @@ -426,14 +426,14 @@ static void setupCustomShaderLights() { // Set light 1 colors gFSConstants->light1_DiffuseColor = light1DiffCol; gFSConstants->light1_SpecularColor = light1SpecCol; - rsAllocationMarkDirty(rsGetAllocation(gFSConstants)); + rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); gFSConstants2->light_DiffuseColor[0] = light0DiffCol; gFSConstants2->light_SpecularColor[0] = light0SpecCol; // Set light 1 colors gFSConstants2->light_DiffuseColor[1] = light1DiffCol; gFSConstants2->light_SpecularColor[1] = light1SpecCol; - rsAllocationMarkDirty(rsGetAllocation(gFSConstants2)); + rsgAllocationSyncAll(rsGetAllocation(gFSConstants2)); } static void displayCustomShaderSamples() { @@ -526,7 +526,7 @@ static void displayCubemapShaderSample() { // Setup the projectioni matrix float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); - rsAllocationMarkDirty(rsGetAllocation(gFSConstants)); + rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); rsgBindProgramVertex(gProgVertexCube); diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java index 265e1d6af299..541bf2234f76 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java @@ -66,7 +66,9 @@ public class RSTestCore { unitTests.add(new UT_primitives(this, mRes, mCtx)); unitTests.add(new UT_rsdebug(this, mRes, mCtx)); + unitTests.add(new UT_rstime(this, mRes, mCtx)); unitTests.add(new UT_rstypes(this, mRes, mCtx)); + unitTests.add(new UT_math(this, mRes, mCtx)); unitTests.add(new UT_fp_mad(this, mRes, mCtx)); /* unitTests.add(new UnitTest(null, "<Pass>", 1)); @@ -94,7 +96,7 @@ public class RSTestCore { mScript.bind_gList(mListAllocs); - mFont = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD, 8); + mFont = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8); mScript.set_gFont(mFont); mRS.bindRootScript(mScript); diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_math.java b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java new file mode 100644 index 000000000000..bf133be07619 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_math extends UnitTest { + private Resources mRes; + + protected UT_math(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Math", ctx); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math); + pRS.setMessageHandler(mRsMessage); + s.invoke_math_test(0, 0); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java new file mode 100644 index 000000000000..f302e1a3f0e3 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_rstime extends UnitTest { + private Resources mRes; + + protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "rsTime", ctx); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime); + pRS.setMessageHandler(mRsMessage); + s.invoke_test_rstime(0, 0); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs index 4133fdaed64a..b6f2b2a60371 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs @@ -113,7 +113,7 @@ static void test_clamp(uint32_t index) { start(); // Do ~100 M ops - for (ct=0; ct < 1000 * 100; ct++) { + for (int ct=0; ct < 1000 * 100; ct++) { for (int i=0; i < (1000); i++) { if (data_f1[i] < -1.f) data_f1[i] = -1.f; if (data_f1[i] > -1.f) data_f1[i] = 1.f; @@ -140,7 +140,8 @@ static void test_clamp4(uint32_t index) { } void fp_mad_test(uint32_t index, int test_num) { - for (int x=0; x < 1025; x++) { + int x; + for (x=0; x < 1025; x++) { data_f1[x] = (x & 0xf) * 0.1f; data_f4[x].x = (x & 0xf) * 0.1f; data_f4[x].y = (x & 0xf0) * 0.1f; diff --git a/libs/rs/java/tests/src/com/android/rs/test/math.rs b/libs/rs/java/tests/src/com/android/rs/test/math.rs new file mode 100644 index 000000000000..8cad82bfd569 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/math.rs @@ -0,0 +1,322 @@ +#include "shared.rsh" + +// Testing math library + +volatile float f1; +volatile float2 f2; +volatile float3 f3; +volatile float4 f4; + +volatile int i1; +volatile int2 i2; +volatile int3 i3; +volatile int4 i4; + +volatile uint ui1; +volatile uint2 ui2; +volatile uint3 ui3; +volatile uint4 ui4; + +volatile short s1; +volatile short2 s2; +volatile short3 s3; +volatile short4 s4; + +volatile ushort us1; +volatile ushort2 us2; +volatile ushort3 us3; +volatile ushort4 us4; + +volatile char c1; +volatile char2 c2; +volatile char3 c3; +volatile char4 c4; + +volatile uchar uc1; +volatile uchar2 uc2; +volatile uchar3 uc3; +volatile uchar4 uc4; + +#define TEST_FN_FUNC_FN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1); \ + f2 = fnc(f2); \ + f3 = fnc(f3); \ + f4 = fnc(f4); + +#define TEST_FN_FUNC_FN_PFN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, (float*) &f1); \ + f2 = fnc(f2, (float2*) &f2); \ + f3 = fnc(f3, (float3*) &f3); \ + f4 = fnc(f4, (float4*) &f4); + +#define TEST_FN_FUNC_FN_FN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, f1); \ + f2 = fnc(f2, f2); \ + f3 = fnc(f3, f3); \ + f4 = fnc(f4, f4); + +#define TEST_FN_FUNC_FN_F(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, f1); \ + f2 = fnc(f2, f1); \ + f3 = fnc(f3, f1); \ + f4 = fnc(f4, f1); + +#define TEST_FN_FUNC_FN_IN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, i1); \ + f2 = fnc(f2, i2); \ + f3 = fnc(f3, i3); \ + f4 = fnc(f4, i4); + +#define TEST_FN_FUNC_FN_I(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, i1); \ + f2 = fnc(f2, i1); \ + f3 = fnc(f3, i1); \ + f4 = fnc(f4, i1); + +#define TEST_FN_FUNC_FN_FN_FN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, f1, f1); \ + f2 = fnc(f2, f2, f2); \ + f3 = fnc(f3, f3, f3); \ + f4 = fnc(f4, f4, f4); + +#define TEST_FN_FUNC_FN_PIN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, (int*) &i1); \ + f2 = fnc(f2, (int2*) &i2); \ + f3 = fnc(f3, (int3*) &i3); \ + f4 = fnc(f4, (int4*) &i4); + +#define TEST_FN_FUNC_FN_FN_PIN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + f1 = fnc(f1, f1, (int*) &i1); \ + f2 = fnc(f2, f2, (int2*) &i2); \ + f3 = fnc(f3, f3, (int3*) &i3); \ + f4 = fnc(f4, f4, (int4*) &i4); + +#define TEST_IN_FUNC_FN(fnc) \ + rsDebug("Testing " #fnc, 0); \ + i1 = fnc(f1); \ + i2 = fnc(f2); \ + i3 = fnc(f3); \ + i4 = fnc(f4); + + +static bool test_fp_math(uint32_t index) { + bool failed = false; + start(); + + TEST_FN_FUNC_FN(acos); + TEST_FN_FUNC_FN(acosh); + TEST_FN_FUNC_FN(acospi); + TEST_FN_FUNC_FN(asin); + TEST_FN_FUNC_FN(asinh); + TEST_FN_FUNC_FN(asinpi); + TEST_FN_FUNC_FN(atan); + TEST_FN_FUNC_FN_FN(atan2); + TEST_FN_FUNC_FN(atanh); + TEST_FN_FUNC_FN(atanpi); + TEST_FN_FUNC_FN_FN(atan2pi); + TEST_FN_FUNC_FN(cbrt); + TEST_FN_FUNC_FN(ceil); + TEST_FN_FUNC_FN_FN(copysign); + TEST_FN_FUNC_FN(cos); + TEST_FN_FUNC_FN(cosh); + TEST_FN_FUNC_FN(cospi); + TEST_FN_FUNC_FN(erfc); + TEST_FN_FUNC_FN(erf); + TEST_FN_FUNC_FN(exp); + TEST_FN_FUNC_FN(exp2); + TEST_FN_FUNC_FN(exp10); + TEST_FN_FUNC_FN(expm1); + TEST_FN_FUNC_FN(fabs); + TEST_FN_FUNC_FN_FN(fdim); + TEST_FN_FUNC_FN(floor); + TEST_FN_FUNC_FN_FN_FN(fma); + TEST_FN_FUNC_FN_FN(fmax); + TEST_FN_FUNC_FN_F(fmax); + TEST_FN_FUNC_FN_FN(fmin); + TEST_FN_FUNC_FN_F(fmin); + TEST_FN_FUNC_FN_FN(fmod); + TEST_FN_FUNC_FN_PFN(fract); + TEST_FN_FUNC_FN_PIN(frexp); + TEST_FN_FUNC_FN_FN(hypot); + TEST_IN_FUNC_FN(ilogb); + TEST_FN_FUNC_FN_IN(ldexp); + TEST_FN_FUNC_FN_I(ldexp); + TEST_FN_FUNC_FN(lgamma); + TEST_FN_FUNC_FN_PIN(lgamma); + TEST_FN_FUNC_FN(log); + TEST_FN_FUNC_FN(log2); + TEST_FN_FUNC_FN(log10); + TEST_FN_FUNC_FN(log1p); + TEST_FN_FUNC_FN(logb); + TEST_FN_FUNC_FN_FN_FN(mad); + TEST_FN_FUNC_FN_PFN(modf); + // nan + TEST_FN_FUNC_FN_FN(nextafter); + TEST_FN_FUNC_FN_FN(pow); + TEST_FN_FUNC_FN_IN(pown); + TEST_FN_FUNC_FN_FN(powr); + TEST_FN_FUNC_FN_FN(remainder); + TEST_FN_FUNC_FN_FN_PIN(remquo); + TEST_FN_FUNC_FN(rint); + TEST_FN_FUNC_FN_IN(rootn); + TEST_FN_FUNC_FN(round); + TEST_FN_FUNC_FN(rsqrt); + TEST_FN_FUNC_FN(sin); + TEST_FN_FUNC_FN_PFN(sincos); + TEST_FN_FUNC_FN(sinh); + TEST_FN_FUNC_FN(sinpi); + TEST_FN_FUNC_FN(sqrt); + TEST_FN_FUNC_FN(tan); + TEST_FN_FUNC_FN(tanh); + TEST_FN_FUNC_FN(tanpi); + TEST_FN_FUNC_FN(tgamma); + TEST_FN_FUNC_FN(trunc); + + float time = end(index); + + if (failed) { + rsDebug("test_fp_math FAILED", time); + } + else { + rsDebug("test_fp_math PASSED", time); + } + + return failed; +} + +#define DECL_INT(prefix) \ +volatile char prefix##_c_1 = 1; \ +volatile char2 prefix##_c_2 = 1; \ +volatile char3 prefix##_c_3 = 1; \ +volatile char4 prefix##_c_4 = 1; \ +volatile uchar prefix##_uc_1 = 1; \ +volatile uchar2 prefix##_uc_2 = 1; \ +volatile uchar3 prefix##_uc_3 = 1; \ +volatile uchar4 prefix##_uc_4 = 1; \ +volatile short prefix##_s_1 = 1; \ +volatile short2 prefix##_s_2 = 1; \ +volatile short3 prefix##_s_3 = 1; \ +volatile short4 prefix##_s_4 = 1; \ +volatile ushort prefix##_us_1 = 1; \ +volatile ushort2 prefix##_us_2 = 1; \ +volatile ushort3 prefix##_us_3 = 1; \ +volatile ushort4 prefix##_us_4 = 1; \ +volatile int prefix##_i_1 = 1; \ +volatile int2 prefix##_i_2 = 1; \ +volatile int3 prefix##_i_3 = 1; \ +volatile int4 prefix##_i_4 = 1; \ +volatile uint prefix##_ui_1 = 1; \ +volatile uint2 prefix##_ui_2 = 1; \ +volatile uint3 prefix##_ui_3 = 1; \ +volatile uint4 prefix##_ui_4 = 1; \ +volatile long prefix##_l_1 = 1; \ +volatile ulong prefix##_ul_1 = 1; + +#define TEST_INT_OP_TYPE(op, type) \ +rsDebug("Testing " #op " for " #type "1", i++); \ +res_##type##_1 = src1_##type##_1 op src2_##type##_1; \ +rsDebug("Testing " #op " for " #type "2", i++); \ +res_##type##_2 = src1_##type##_2 op src2_##type##_2; \ +rsDebug("Testing " #op " for " #type "3", i++); \ +res_##type##_3 = src1_##type##_3 op src2_##type##_3; \ +rsDebug("Testing " #op " for " #type "4", i++); \ +res_##type##_4 = src1_##type##_4 op src2_##type##_4; + +#define TEST_INT_OP(op) \ +TEST_INT_OP_TYPE(op, c) \ +TEST_INT_OP_TYPE(op, uc) \ +TEST_INT_OP_TYPE(op, s) \ +TEST_INT_OP_TYPE(op, us) \ +TEST_INT_OP_TYPE(op, i) \ +TEST_INT_OP_TYPE(op, ui) \ +rsDebug("Testing " #op " for l1", i++); \ +res_l_1 = src1_l_1 op src2_l_1; \ +rsDebug("Testing " #op " for ul1", i++); \ +res_ul_1 = src1_ul_1 op src2_ul_1; + +DECL_INT(res) +DECL_INT(src1) +DECL_INT(src2) + +static bool test_basic_operators() { + bool failed = false; + int i = 0; + + TEST_INT_OP(+); + TEST_INT_OP(-); + TEST_INT_OP(*); + TEST_INT_OP(/); + TEST_INT_OP(%); + TEST_INT_OP(<<); + TEST_INT_OP(>>); + + if (failed) { + rsDebug("test_basic_operators FAILED", 0); + } + else { + rsDebug("test_basic_operators PASSED", 0); + } + + return failed; +} + +#define TEST_CVT(to, from, type) \ +rsDebug("Testing convert from " #from " to " #to, 0); \ +to##1 = from##1; \ +to##2 = convert_##type##2(from##2); \ +to##3 = convert_##type##3(from##3); \ +to##4 = convert_##type##4(from##4); + +#define TEST_CVT_MATRIX(to, type) \ +TEST_CVT(to, c, type); \ +TEST_CVT(to, uc, type); \ +TEST_CVT(to, s, type); \ +TEST_CVT(to, us, type); \ +TEST_CVT(to, i, type); \ +TEST_CVT(to, ui, type); \ +TEST_CVT(to, f, type); \ + +static bool test_convert() { + bool failed = false; + + TEST_CVT_MATRIX(c, char); + TEST_CVT_MATRIX(uc, uchar); + TEST_CVT_MATRIX(s, short); + TEST_CVT_MATRIX(us, ushort); + TEST_CVT_MATRIX(i, int); + TEST_CVT_MATRIX(ui, uint); + TEST_CVT_MATRIX(f, float); + + if (failed) { + rsDebug("test_convert FAILED", 0); + } + else { + rsDebug("test_convert PASSED", 0); + } + + return failed; +} + +void math_test(uint32_t index, int test_num) { + bool failed = false; + failed |= test_convert(); + failed |= test_fp_math(index); + failed |= test_basic_operators(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs index f354a72a21ea..67c2b8623c61 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs @@ -45,7 +45,6 @@ int root(int launchID) { rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); rsgBindFont(gFont); - color(0.2, 0.2, 0.2, 0); rs_allocation listAlloc; rsSetObject(&listAlloc, rsGetAllocation(gList)); diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstime.rs b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs new file mode 100644 index 000000000000..5e3e07816f9c --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs @@ -0,0 +1,52 @@ +#include "shared.rsh" + +static bool basic_test(uint32_t index) { + bool failed = false; + + rs_time_t curTime = rsTime(0); + rs_tm tm; + rsDebug("curTime", curTime); + + rsLocaltime(&tm, &curTime); + + rsDebug("tm.tm_sec", tm.tm_sec); + rsDebug("tm.tm_min", tm.tm_min); + rsDebug("tm.tm_hour", tm.tm_hour); + rsDebug("tm.tm_mday", tm.tm_mday); + rsDebug("tm.tm_mon", tm.tm_mon); + rsDebug("tm.tm_year", tm.tm_year); + rsDebug("tm.tm_wday", tm.tm_wday); + rsDebug("tm.tm_yday", tm.tm_yday); + rsDebug("tm.tm_isdst", tm.tm_isdst); + + // Test a specific time (only valid for PST localtime) + curTime = 1294438893; + rsLocaltime(&tm, &curTime); + + _RS_ASSERT(tm.tm_sec == 33); + _RS_ASSERT(tm.tm_min == 21); + _RS_ASSERT(tm.tm_hour == 14); + _RS_ASSERT(tm.tm_mday == 7); + _RS_ASSERT(tm.tm_mon == 0); + _RS_ASSERT(tm.tm_year == 111); + _RS_ASSERT(tm.tm_wday == 5); + _RS_ASSERT(tm.tm_yday == 6); + _RS_ASSERT(tm.tm_isdst == 0); + + return failed; +} + +void test_rstime(uint32_t index, int test_num) { + bool failed = false; + failed |= basic_test(index); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + rsDebug("rstime_test FAILED", -1); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + rsDebug("rstime_test PASSED", 0); + } +} + diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 5daba089bb7d..7e23cec90805 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -47,7 +47,7 @@ ContextSetPriority { param int32_t priority } -ContextDestroy { +ContextDestroyWorker { } AssignName { @@ -77,40 +77,17 @@ ElementCreate2 { ret RsElement } -AllocationCopyFromBitmap { - param RsAllocation alloc - param const void * data - param size_t dataLen - } - AllocationCopyToBitmap { param RsAllocation alloc param void * data param size_t dataLen } -AllocationUploadToTexture { - param RsAllocation alloc - param bool genMipMaps - param uint32_t baseMipLevel - } -AllocationUploadToBufferObject { - param RsAllocation alloc - } - - -AllocationData { - param RsAllocation va - param const void * data - param uint32_t bytes - handcodeApi - togglePlay - } - -Allocation1DSubData { +Allocation1DData { param RsAllocation va param uint32_t xoff + param uint32_t lod param uint32_t count param const void *data param uint32_t bytes @@ -118,9 +95,10 @@ Allocation1DSubData { togglePlay } -Allocation1DSubElementData { +Allocation1DElementData { param RsAllocation va param uint32_t x + param uint32_t lod param const void *data param uint32_t comp_offset param uint32_t bytes @@ -128,25 +106,33 @@ Allocation1DSubElementData { togglePlay } -Allocation2DSubData { +Allocation2DData { param RsAllocation va param uint32_t xoff param uint32_t yoff + param uint32_t lod + param RsAllocationCubemapFace face param uint32_t w param uint32_t h param const void *data param uint32_t bytes } -Allocation2DSubElementData { +Allocation2DElementData { param RsAllocation va param uint32_t x param uint32_t y + param uint32_t lod + param RsAllocationCubemapFace face param const void *data param uint32_t element_offset param uint32_t bytes } +AllocationGenerateMipmaps { + param RsAllocation va +} + AllocationRead { param RsAllocation va param void * data @@ -157,61 +143,6 @@ AllocationSyncAll { param RsAllocationUsageType src } -Adapter1DCreate { - ret RsAdapter1D - } - -Adapter1DBindAllocation { - param RsAdapter1D adapt - param RsAllocation alloc - } - -Adapter1DSetConstraint { - param RsAdapter1D adapter - param RsDimension dim - param uint32_t value - } - -Adapter1DData { - param RsAdapter1D adapter - param const void * data - } - -Adapter1DSubData { - param RsAdapter1D adapter - param uint32_t xoff - param uint32_t count - param const void *data - } - -Adapter2DCreate { - ret RsAdapter2D - } - -Adapter2DBindAllocation { - param RsAdapter2D adapt - param RsAllocation alloc - } - -Adapter2DSetConstraint { - param RsAdapter2D adapter - param RsDimension dim - param uint32_t value - } - -Adapter2DData { - param RsAdapter2D adapter - param const void *data - } - -Adapter2DSubData { - param RsAdapter2D adapter - param uint32_t xoff - param uint32_t yoff - param uint32_t w - param uint32_t h - param const void *data - } AllocationResize1D { param RsAllocation va @@ -321,6 +252,7 @@ ScriptCSetText { } ScriptCCreate { + param const char * packageName param const char * resName param const char * cacheDir ret RsScript @@ -412,16 +344,19 @@ ProgramVertexCreate { ret RsProgramVertex } -FileOpen { - ret RsFile +FontCreateFromFile { param const char *name - param size_t len + param float fontSize + param uint32_t dpi + ret RsFont } -FontCreateFromFile { +FontCreateFromMemory { param const char *name - param uint32_t fontSize + param float fontSize param uint32_t dpi + param const void *data + param uint32_t dataLen ret RsFont } diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp index 8d363fde19e1..6e8ca705110e 100644 --- a/libs/rs/rsAdapter.cpp +++ b/libs/rs/rsAdapter.cpp @@ -15,11 +15,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif using namespace android; using namespace android::renderscript; diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 77e80320b372..54dcbcbefc30 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -13,20 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST -#include "rsContext.h" +#include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES2/gl2.h> #include <GLES/glext.h> -#else -#include "rsContextHostStub.h" - -#include <OpenGL/gl.h> -#include <OpenGl/glext.h> -#endif +#endif //ANDROID_RS_SERIALIZE -#include "utils/StopWatch.h" +static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va); using namespace android; using namespace android::renderscript; @@ -81,7 +76,7 @@ Allocation::~Allocation() { mPtr = NULL; } freeScriptMemory(); - +#ifndef ANDROID_RS_SERIALIZE if (mBufferID) { // Causes a SW crash.... //LOGV(" mBufferID %i", mBufferID); @@ -92,6 +87,7 @@ Allocation::~Allocation() { glDeleteTextures(1, &mTextureID); mTextureID = 0; } +#endif //ANDROID_RS_SERIALIZE } void Allocation::setCpuWritable(bool) { @@ -116,6 +112,7 @@ void Allocation::deferedUploadToTexture(const Context *rsc) { } uint32_t Allocation::getGLTarget() const { +#ifndef ANDROID_RS_SERIALIZE if (getIsTexture()) { if (mType->getDimFaces()) { return GL_TEXTURE_CUBE_MAP; @@ -126,6 +123,7 @@ uint32_t Allocation::getGLTarget() const { if (getIsBufferObject()) { return GL_ARRAY_BUFFER; } +#endif //ANDROID_RS_SERIALIZE return 0; } @@ -135,7 +133,6 @@ void Allocation::allocScriptMemory() { } void Allocation::freeScriptMemory() { - rsAssert(!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)); if (mPtr) { free(mPtr); mPtr = NULL; @@ -157,7 +154,7 @@ void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) { } void Allocation::uploadToTexture(const Context *rsc) { - +#ifndef ANDROID_RS_SERIALIZE mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; GLenum type = mType->getElement()->getComponent().getGLType(); GLenum format = mType->getElement()->getComponent().getGLFormat(); @@ -187,51 +184,47 @@ void Allocation::uploadToTexture(const Context *rsc) { isFirstUpload = true; } - GLenum target = (GLenum)getGLTarget(); - if (target == GL_TEXTURE_2D) { - upload2DTexture(isFirstUpload, mPtr); - } else if (target == GL_TEXTURE_CUBE_MAP) { - uploadCubeTexture(isFirstUpload); - } + upload2DTexture(isFirstUpload); if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { freeScriptMemory(); } rsc->checkError("Allocation::uploadToTexture"); -} - -void Allocation::upload2DTexture(bool isFirstUpload, const void *ptr) { +#endif //ANDROID_RS_SERIALIZE +} + +#ifndef ANDROID_RS_SERIALIZE +const static GLenum gFaceOrder[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; +#endif //ANDROID_RS_SERIALIZE + +void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h) { +#ifndef ANDROID_RS_SERIALIZE GLenum type = mType->getElement()->getComponent().getGLType(); GLenum format = mType->getElement()->getComponent().getGLFormat(); - GLenum target = (GLenum)getGLTarget(); + rsAssert(mTextureID); glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) { - const uint8_t *p = (const uint8_t *)ptr; - p += mType->getLODOffset(lod); - - if (isFirstUpload) { - glTexImage2D(GL_TEXTURE_2D, lod, format, - mType->getLODDimX(lod), mType->getLODDimY(lod), - 0, format, type, p); - } else { - glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, - mType->getLODDimX(lod), mType->getLODDimY(lod), - format, type, p); - } - } - - if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { -#ifndef ANDROID_RS_BUILD_FOR_HOST - glGenerateMipmap(target); -#endif //ANDROID_RS_BUILD_FOR_HOST + GLenum t = GL_TEXTURE_2D; + if (mType->getDimFaces()) { + t = gFaceOrder[face]; } + glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr); +#endif //ANDROID_RS_SERIALIZE } -void Allocation::uploadCubeTexture(bool isFirstUpload) { +void Allocation::upload2DTexture(bool isFirstUpload) { +#ifndef ANDROID_RS_SERIALIZE GLenum type = mType->getElement()->getComponent().getGLType(); GLenum format = mType->getElement()->getComponent().getGLFormat(); @@ -239,41 +232,37 @@ void Allocation::uploadCubeTexture(bool isFirstUpload) { glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - GLenum faceOrder[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - }; - - Adapter2D adapt(getContext(), this); - for (uint32_t face = 0; face < 6; face ++) { - adapt.setFace(face); + uint32_t faceCount = 1; + if (mType->getDimFaces()) { + faceCount = 6; + } + for (uint32_t face = 0; face < faceCount; face ++) { for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) { - adapt.setLOD(lod); + const uint8_t *p = (const uint8_t *)mPtr; + p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); - uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0)); + GLenum t = GL_TEXTURE_2D; + if (mType->getDimFaces()) { + t = gFaceOrder[face]; + } if (isFirstUpload) { - glTexImage2D(faceOrder[face], lod, format, - adapt.getDimX(), adapt.getDimY(), - 0, format, type, ptr); + glTexImage2D(t, lod, format, + mType->getLODDimX(lod), mType->getLODDimY(lod), + 0, format, type, p); } else { - glTexSubImage2D(faceOrder[face], lod, 0, 0, - adapt.getDimX(), adapt.getDimY(), - format, type, ptr); + glTexSubImage2D(t, lod, 0, 0, + mType->getLODDimX(lod), mType->getLODDimY(lod), + format, type, p); } } } if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { -#ifndef ANDROID_RS_BUILD_FOR_HOST glGenerateMipmap(target); -#endif //ANDROID_RS_BUILD_FOR_HOST } +#endif //ANDROID_RS_SERIALIZE } void Allocation::deferedUploadToBufferObject(const Context *rsc) { @@ -282,6 +271,7 @@ void Allocation::deferedUploadToBufferObject(const Context *rsc) { } void Allocation::uploadToBufferObject(const Context *rsc) { +#ifndef ANDROID_RS_SERIALIZE rsAssert(!mType->getDimY()); rsAssert(!mType->getDimZ()); @@ -300,6 +290,7 @@ void Allocation::uploadToBufferObject(const Context *rsc) { glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); glBindBuffer(target, 0); rsc->checkError("Allocation::uploadToBufferObject"); +#endif //ANDROID_RS_SERIALIZE } void Allocation::uploadCheck(Context *rsc) { @@ -308,29 +299,12 @@ void Allocation::uploadCheck(Context *rsc) { } } - -void Allocation::data(Context *rsc, const void *data, uint32_t sizeBytes) { - uint32_t size = mType->getSizeBytes(); - if (size != sizeBytes) { - LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes); - return; - } - - if (mType->getElement()->getHasReferences()) { - incRefs(data, sizeBytes / mType->getElement()->getSizeBytes()); - decRefs(mPtr, sizeBytes / mType->getElement()->getSizeBytes()); - } - - memcpy(mPtr, data, size); - sendDirty(); - mUploadDefered = true; -} - void Allocation::read(void *data) { memcpy(data, mPtr, mType->getSizeBytes()); } -void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) { +void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod, + uint32_t count, const void *data, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); uint8_t * ptr = static_cast<uint8_t *>(mPtr); ptr += eSize * xoff; @@ -352,39 +326,48 @@ void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t count, const void mUploadDefered = true; } -void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, +void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); uint32_t lineSize = eSize * w; uint32_t destW = mType->getDimX(); - const uint8_t *src = static_cast<const uint8_t *>(data); - uint8_t *dst = static_cast<uint8_t *>(mPtr); - dst += eSize * (xoff + yoff * destW); + //LOGE("data2d %p, %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes); - if ((lineSize * eSize * h) != sizeBytes) { + if ((lineSize * h) != sizeBytes) { + LOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes); rsAssert(!"Allocation::subData called with mismatched size"); return; } - for (uint32_t line=yoff; line < (yoff+h); line++) { - if (mType->getElement()->getHasReferences()) { - incRefs(src, w); - decRefs(dst, w); + if (mPtr) { + const uint8_t *src = static_cast<const uint8_t *>(data); + uint8_t *dst = static_cast<uint8_t *>(mPtr); + dst += mType->getLODFaceOffset(lod, face, xoff, yoff); + + //LOGE(" %p %p %i ", dst, src, eSize); + for (uint32_t line=yoff; line < (yoff+h); line++) { + if (mType->getElement()->getHasReferences()) { + incRefs(src, w); + decRefs(dst, w); + } + memcpy(dst, src, lineSize); + src += lineSize; + dst += destW * eSize; } - memcpy(dst, src, lineSize); - src += lineSize; - dst += destW * eSize; + sendDirty(); + mUploadDefered = true; + } else { + update2DTexture(data, xoff, yoff, lod, face, w, h); } - sendDirty(); - mUploadDefered = true; } -void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, - uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { +void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { } -void Allocation::subElementData(Context *rsc, uint32_t x, const void *data, +void Allocation::elementData(Context *rsc, uint32_t x, const void *data, uint32_t cIdx, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); uint8_t * ptr = static_cast<uint8_t *>(mPtr); @@ -406,7 +389,7 @@ void Allocation::subElementData(Context *rsc, uint32_t x, const void *data, ptr += mType->getElement()->getFieldOffsetBytes(cIdx); if (sizeBytes != e->getSizeBytes()) { - LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes()); + LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size."); return; } @@ -421,7 +404,7 @@ void Allocation::subElementData(Context *rsc, uint32_t x, const void *data, mUploadDefered = true; } -void Allocation::subElementData(Context *rsc, uint32_t x, uint32_t y, +void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, const void *data, uint32_t cIdx, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); uint8_t * ptr = static_cast<uint8_t *>(mPtr); @@ -449,7 +432,7 @@ void Allocation::subElementData(Context *rsc, uint32_t x, uint32_t y, ptr += mType->getElement()->getFieldOffsetBytes(cIdx); if (sizeBytes != e->getSizeBytes()) { - LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes()); + LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size."); return; } @@ -465,10 +448,13 @@ void Allocation::subElementData(Context *rsc, uint32_t x, uint32_t y, } void Allocation::addProgramToDirty(const Program *p) { +#ifndef ANDROID_RS_SERIALIZE mToDirtyList.push(p); +#endif //ANDROID_RS_SERIALIZE } void Allocation::removeProgramToDirty(const Program *p) { +#ifndef ANDROID_RS_SERIALIZE for (size_t ct=0; ct < mToDirtyList.size(); ct++) { if (mToDirtyList[ct] == p) { mToDirtyList.removeAt(ct); @@ -476,6 +462,7 @@ void Allocation::removeProgramToDirty(const Program *p) { } } rsAssert(0); +#endif //ANDROID_RS_SERIALIZE } void Allocation::dumpLOGV(const char *prefix) const { @@ -540,17 +527,21 @@ Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { Allocation *alloc = new Allocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT); alloc->setName(name.string(), name.size()); + uint32_t count = dataSize / type->getElementSizeBytes(); + // Read in all of our allocation data - alloc->data(rsc, stream->getPtr() + stream->getPos(), dataSize); + alloc->data(rsc, 0, 0, count, stream->getPtr() + stream->getPos(), dataSize); stream->reset(stream->getPos() + dataSize); return alloc; } void Allocation::sendDirty() const { +#ifndef ANDROID_RS_SERIALIZE for (size_t ct=0; ct < mToDirtyList.size(); ct++) { mToDirtyList[ct]->forceDirty(); } +#endif //ANDROID_RS_SERIALIZE } void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const { @@ -609,7 +600,7 @@ void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { ///////////////// // - +#ifndef ANDROID_RS_SERIALIZE namespace android { namespace renderscript { @@ -692,41 +683,15 @@ static void mip(const Adapter2D &out, const Adapter2D &in) { } } -#ifndef ANDROID_RS_BUILD_FOR_HOST - void rsi_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType src) { Allocation *a = static_cast<Allocation *>(va); a->syncAll(rsc, src); + a->sendDirty(); } -void rsi_AllocationCopyFromBitmap(Context *rsc, RsAllocation va, const void *data, size_t dataLen) { +void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) { Allocation *texAlloc = static_cast<Allocation *>(va); - const Type * t = texAlloc->getType(); - - uint32_t w = t->getDimX(); - uint32_t h = t->getDimY(); - bool genMips = t->getDimLOD(); - size_t s = w * h * t->getElementSizeBytes(); - if (s != dataLen) { - rsc->setError(RS_ERROR_BAD_VALUE, "Bitmap size didn't match allocation size"); - return; - } - - if (texAlloc->getIsScript()) { - memcpy(texAlloc->getPtr(), data, s); - if (genMips) { - Adapter2D adapt(rsc, texAlloc); - Adapter2D adapt2(rsc, texAlloc); - for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { - adapt.setLOD(lod); - adapt2.setLOD(lod + 1); - mip(adapt2, adapt); - } - } - } else { - texAlloc->upload2DTexture(false, data); - } - + rsaAllocationGenerateScriptMips(rsc, texAlloc); } void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) { @@ -742,29 +707,28 @@ void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_ memcpy(data, texAlloc->getPtr(), s); } -void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes) { - Allocation *a = static_cast<Allocation *>(va); - a->data(rsc, data, sizeBytes); -} - -void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) { +void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod, + uint32_t count, const void *data, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subData(rsc, xoff, count, data, sizeBytes); + a->data(rsc, xoff, lod, count, data, sizeBytes); } -void rsi_Allocation2DSubElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, const void *data, uint32_t eoff, uint32_t sizeBytes) { +void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face, + const void *data, uint32_t eoff, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subElementData(rsc, x, y, data, eoff, sizeBytes); + a->elementData(rsc, x, y, data, eoff, sizeBytes); } -void rsi_Allocation1DSubElementData(Context *rsc, RsAllocation va, uint32_t x, const void *data, uint32_t eoff, uint32_t sizeBytes) { +void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod, + const void *data, uint32_t eoff, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subElementData(rsc, x, data, eoff, sizeBytes); + a->elementData(rsc, x, data, eoff, sizeBytes); } -void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { +void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subData(rsc, xoff, yoff, w, h, data, sizeBytes); + a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes); } void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) { @@ -782,11 +746,26 @@ void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32 a->resize2D(rsc, dimX, dimY); } -#endif //ANDROID_RS_BUILD_FOR_HOST - } } +static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) { + Context *rsc = static_cast<Context *>(con); + Allocation *texAlloc = static_cast<Allocation *>(va); + uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1; + for (uint32_t face = 0; face < numFaces; face ++) { + Adapter2D adapt(rsc, texAlloc); + Adapter2D adapt2(rsc, texAlloc); + adapt.setFace(face); + adapt2.setFace(face); + for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { + adapt.setLOD(lod); + adapt2.setLOD(lod + 1); + mip(adapt2, adapt); + } + } +} + const void * rsaAllocationGetType(RsContext con, RsAllocation va) { Allocation *a = static_cast<Allocation *>(va); a->getType()->incUserRef(); @@ -819,13 +798,7 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes()); if (mips == RS_ALLOCATION_MIPMAP_FULL) { - Adapter2D adapt(rsc, texAlloc); - Adapter2D adapt2(rsc, texAlloc); - for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { - adapt.setLOD(lod); - adapt2.setLOD(lod + 1); - mip(adapt2, adapt); - } + rsaAllocationGenerateScriptMips(rsc, texAlloc); } texAlloc->deferedUploadToTexture(rsc); @@ -848,30 +821,29 @@ RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, return NULL; } + uint32_t faceSize = t->getDimX(); + uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes(); + uint32_t copySize = faceSize * t->getElementSizeBytes(); + uint8_t *sourcePtr = (uint8_t*)data; for (uint32_t face = 0; face < 6; face ++) { Adapter2D faceAdapter(rsc, texAlloc); faceAdapter.setFace(face); - size_t cpySize = t->getDimX() * t->getDimX() * t->getElementSizeBytes(); - memcpy(faceAdapter.getElement(0, 0), sourcePtr, cpySize); + for (uint32_t dI = 0; dI < faceSize; dI ++) { + memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize); + } // Move the data pointer to the next cube face - sourcePtr += cpySize; - - if (mips == RS_ALLOCATION_MIPMAP_FULL) { - Adapter2D adapt(rsc, texAlloc); - Adapter2D adapt2(rsc, texAlloc); - adapt.setFace(face); - adapt2.setFace(face); - for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { - adapt.setLOD(lod); - adapt2.setLOD(lod + 1); - mip(adapt2, adapt); - } - } + sourcePtr += copySize; + } + + if (mips == RS_ALLOCATION_MIPMAP_FULL) { + rsaAllocationGenerateScriptMips(rsc, texAlloc); } texAlloc->deferedUploadToTexture(rsc); return texAlloc; } + +#endif //ANDROID_RS_SERIALIZE diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index 44dce0dcb1c3..4f5d5a8e351f 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -61,16 +61,15 @@ public: void resize1D(Context *rsc, uint32_t dimX); void resize2D(Context *rsc, uint32_t dimX, uint32_t dimY); - void data(Context *rsc, const void *data, uint32_t sizeBytes); - void subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes); - void subData(Context *rsc, uint32_t xoff, uint32_t yoff, + void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes); + void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes); - void subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, + void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); - void subElementData(Context *rsc, uint32_t x, + void elementData(Context *rsc, uint32_t x, const void *data, uint32_t elementOff, uint32_t sizeBytes); - void subElementData(Context *rsc, uint32_t x, uint32_t y, + void elementData(Context *rsc, uint32_t x, uint32_t y, const void *data, uint32_t elementOff, uint32_t sizeBytes); void read(void *data); @@ -106,7 +105,6 @@ public: return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE; } - void upload2DTexture(bool isFirstUpload, const void *ptr); protected: ObjectBaseRef<const Type> mType; @@ -148,7 +146,9 @@ protected: private: void init(Context *rsc, const Type *); - void uploadCubeTexture(bool isFirstUpload); + void upload2DTexture(bool isFirstUpload); + void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, + uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h); void allocScriptMemory(); void freeScriptMemory(); diff --git a/libs/rs/rsAnimation.cpp b/libs/rs/rsAnimation.cpp index 6abda3c0cd14..48b4f029c6d0 100644 --- a/libs/rs/rsAnimation.cpp +++ b/libs/rs/rsAnimation.cpp @@ -14,12 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif //ANDROID_RS_BUILD_FOR_HOST - #include "rsAnimation.h" diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 81ade5d4f60f..4c4987aaf7a4 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -16,10 +16,8 @@ #include "rsComponent.h" -#ifndef ANDROID_RS_BUILD_FOR_HOST +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> -#else -#include <OpenGL/gl.h> #endif using namespace android; @@ -183,6 +181,7 @@ bool Component::isReference() const { } uint32_t Component::getGLType() const { +#ifndef ANDROID_RS_SERIALIZE switch (mType) { case RS_TYPE_UNSIGNED_5_6_5: return GL_UNSIGNED_SHORT_5_6_5; case RS_TYPE_UNSIGNED_5_5_5_1: return GL_UNSIGNED_SHORT_5_5_5_1; @@ -196,11 +195,12 @@ uint32_t Component::getGLType() const { case RS_TYPE_SIGNED_16: return GL_SHORT; default: break; } - +#endif //ANDROID_RS_SERIALIZE return 0; } uint32_t Component::getGLFormat() const { +#ifndef ANDROID_RS_SERIALIZE switch (mKind) { case RS_KIND_PIXEL_L: return GL_LUMINANCE; case RS_KIND_PIXEL_A: return GL_ALPHA; @@ -209,6 +209,7 @@ uint32_t Component::getGLFormat() const { case RS_KIND_PIXEL_RGBA: return GL_RGBA; default: break; } +#endif //ANDROID_RS_SERIALIZE return 0; } diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 2988950d532a..1dfedb3bd53c 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -44,6 +44,7 @@ pthread_key_t Context::gThreadTLSKey = 0; uint32_t Context::gThreadTLSKeyCount = 0; uint32_t Context::gGLContextCount = 0; pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER; static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { @@ -200,9 +201,9 @@ bool Context::initGLThread() { mGL.mExtensions = glGetString(GL_EXTENSIONS); //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); - LOGV("GL Version %s", mGL.mVersion); + //LOGV("GL Version %s", mGL.mVersion); //LOGV("GL Vendor %s", mGL.mVendor); - LOGV("GL Renderer %s", mGL.mRenderer); + //LOGV("GL Renderer %s", mGL.mRenderer); //LOGV("GL Extensions %s", mGL.mExtensions); const char *verptr = NULL; @@ -235,6 +236,7 @@ bool Context::initGLThread() { glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGL.mMaxFragmentUniformVectors); mGL.OES_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_OES_texture_npot"); + mGL.GL_IMG_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_IMG_texture_npot"); mGL.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)mGL.mExtensions, "GL_NV_texture_npot_2D_mipmap"); mGL.EXT_texture_max_aniso = 1.0f; bool hasAniso = NULL != strstr((const char *)mGL.mExtensions, "GL_EXT_texture_filter_anisotropic"); @@ -251,7 +253,11 @@ void Context::deinitEGL() { LOGV("%p, deinitEGL", this); if (mEGL.mContext != EGL_NO_CONTEXT) { - eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEGL.mContext); + eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(mEGL.mDisplay, mEGL.mSurfaceDefault); + if (mEGL.mSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEGL.mDisplay, mEGL.mSurface); + } eglDestroyContext(mEGL.mDisplay, mEGL.mContext); checkEglError("eglDestroyContext"); } @@ -462,7 +468,6 @@ void * Context::threadProc(void *vrsc) { return NULL; } - rsc->mScriptC.init(rsc); if (rsc->mIsGraphicsContext) { rsc->mStateRaster.init(rsc); rsc->setProgramRaster(NULL); @@ -509,20 +514,6 @@ void * Context::threadProc(void *vrsc) { } LOGV("%p, RS Thread exiting", rsc); - if (rsc->mIsGraphicsContext) { - rsc->mRaster.clear(); - rsc->mFragment.clear(); - rsc->mVertex.clear(); - rsc->mFragmentStore.clear(); - rsc->mFont.clear(); - rsc->mRootScript.clear(); - rsc->mStateRaster.deinit(rsc); - rsc->mStateVertex.deinit(rsc); - rsc->mStateFragment.deinit(rsc); - rsc->mStateFragmentStore.deinit(rsc); - rsc->mStateFont.deinit(rsc); - } - ObjectBase::zeroAllUserRef(rsc); if (rsc->mIsGraphicsContext) { pthread_mutex_lock(&gInitMutex); @@ -535,11 +526,32 @@ void * Context::threadProc(void *vrsc) { return NULL; } +void Context::destroyWorkerThreadResources() { + //LOGV("destroyWorkerThreadResources 1"); + ObjectBase::zeroAllUserRef(this); + if (mIsGraphicsContext) { + mRaster.clear(); + mFragment.clear(); + mVertex.clear(); + mFragmentStore.clear(); + mFont.clear(); + mRootScript.clear(); + mStateRaster.deinit(this); + mStateVertex.deinit(this); + mStateFragment.deinit(this); + mStateFragmentStore.deinit(this); + mStateFont.deinit(this); + mShaderCache.cleanupAll(); + } + //LOGV("destroyWorkerThreadResources 2"); + mExit = true; +} + void * Context::helperThreadProc(void *vrsc) { Context *rsc = static_cast<Context *>(vrsc); uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount); - LOGV("RS helperThread starting %p idx=%i", rsc, idx); + //LOGV("RS helperThread starting %p idx=%i", rsc, idx); rsc->mWorkers.mLaunchSignals[idx].init(); rsc->mWorkers.mNativeThreadId[idx] = gettid(); @@ -560,7 +572,7 @@ void * Context::helperThreadProc(void *vrsc) { LOGE("pthread_setspecific %i", status); } - while (rsc->mRunning) { + while (!rsc->mExit) { rsc->mWorkers.mLaunchSignals[idx].wait(); if (rsc->mWorkers.mLaunchCallback) { rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx); @@ -569,7 +581,7 @@ void * Context::helperThreadProc(void *vrsc) { rsc->mWorkers.mCompleteSignal.set(); } - LOGV("RS helperThread exiting %p idx=%i", rsc, idx); + //LOGV("RS helperThread exited %p idx=%i", rsc, idx); return NULL; } @@ -707,6 +719,9 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { Context::~Context() { LOGV("Context::~Context"); + + mIO.mToCore.flush(); + rsAssert(mExit); mExit = true; mPaused = false; void *res; @@ -714,6 +729,18 @@ Context::~Context() { mIO.shutdown(); int status = pthread_join(mThreadId, &res); + // Cleanup compute threads. + mWorkers.mLaunchData = NULL; + mWorkers.mLaunchCallback = NULL; + mWorkers.mRunningCount = (int)mWorkers.mCount; + for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { + mWorkers.mLaunchSignals[ct].set(); + } + for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { + int status = pthread_join(mWorkers.mThreadId[ct], &res); + } + rsAssert(!mWorkers.mRunningCount); + // Global structure cleanup. pthread_mutex_lock(&gInitMutex); if (mDev) { @@ -725,13 +752,16 @@ Context::~Context() { mDev = NULL; } pthread_mutex_unlock(&gInitMutex); + LOGV("Context::~Context done"); } void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) { rsAssert(mIsGraphicsContext); EGLBoolean ret; - if (mEGL.mSurface != NULL) { + // WAR: Some drivers fail to handle 0 size surfaces correcntly. + // Use the pbuffer to avoid this pitfall. + if ((mEGL.mSurface != NULL) || (w == 0) || (h == 0)) { ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext); checkEglError("eglMakeCurrent", ret); @@ -1019,13 +1049,20 @@ void rsi_ContextDump(Context *rsc, int32_t bits) { ObjectBase::dumpAll(rsc); } -void rsi_ContextDestroy(Context *rsc) { - delete rsc; +void rsi_ContextDestroyWorker(Context *rsc) { + rsc->destroyWorkerThreadResources();; } } } +void rsContextDestroy(RsContext vcon) { + LOGV("rsContextDestroy %p", vcon); + Context *rsc = static_cast<Context *>(vcon); + rsContextDestroyWorker(rsc); + delete rsc; + LOGV("rsContextDestroy 2 %p", vcon); +} RsContext rsContextCreate(RsDevice vdev, uint32_t version) { LOGV("rsContextCreate %p", vdev); diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 49ee676b8442..c5e32a67dd13 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -18,16 +18,16 @@ #define ANDROID_RS_CONTEXT_H #include "rsUtils.h" -#include "rsMutex.h" - -#include "rsThreadIO.h" #include "rsType.h" -#include "rsMatrix.h" #include "rsAllocation.h" #include "rsMesh.h" + +#ifndef ANDROID_RS_SERIALIZE +#include "rsMutex.h" +#include "rsThreadIO.h" +#include "rsMatrix.h" #include "rsDevice.h" #include "rsScriptC.h" -#include "rsAllocation.h" #include "rsAdapter.h" #include "rsSampler.h" #include "rsFont.h" @@ -42,6 +42,7 @@ #include "rsLocklessFifo.h" #include <ui/egl/android_natives.h> +#endif // ANDROID_RS_SERIALIZE // --------------------------------------------------------------------------- namespace android { @@ -66,6 +67,8 @@ namespace renderscript { #define CHECK_OBJ_OR_NULL(o) #endif +#ifndef ANDROID_RS_SERIALIZE + class Context { public: static Context * createContext(Device *, const RsSurfaceConfig *sc); @@ -75,6 +78,8 @@ public: static uint32_t gThreadTLSKeyCount; static uint32_t gGLContextCount; static pthread_mutex_t gInitMutex; + // Library mutex (for providing thread-safe calls from the runtime) + static pthread_mutex_t gLibMutex; struct ScriptTLSStruct { Context * mContext; @@ -137,6 +142,7 @@ public: void resume(); void setSurface(uint32_t w, uint32_t h, ANativeWindow *sur); void setPriority(int32_t p); + void destroyWorkerThreadResources(); void assignName(ObjectBase *obj, const char *name, uint32_t len); void removeName(ObjectBase *obj); @@ -202,6 +208,7 @@ public: mutable const ObjectBase * mObjHead; bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;} + bool ext_GL_IMG_texture_npot() const {return mGL.GL_IMG_texture_npot;} bool ext_GL_NV_texture_npot_2D_mipmap() const {return mGL.GL_NV_texture_npot_2D_mipmap;} float ext_texture_max_aniso() const {return mGL.EXT_texture_max_aniso; } uint32_t getMaxFragmentTextures() const {return mGL.mMaxFragmentTextureImageUnits;} @@ -246,6 +253,7 @@ protected: int32_t mMaxVertexTextureUnits; bool OES_texture_npot; + bool GL_IMG_texture_npot; bool GL_NV_texture_npot_2D_mipmap; float EXT_texture_max_aniso; } mGL; @@ -316,6 +324,39 @@ private: uint32_t mAverageFPS; }; -} -} +#else + +class Context { +public: + Context() { + mObjHead = NULL; + } + ~Context() { + ObjectBase::zeroAllUserRef(this); + } + + ElementState mStateElement; + TypeState mStateType; + + struct { + bool mLogTimes; + bool mLogScripts; + bool mLogObjects; + bool mLogShaders; + bool mLogShadersAttr; + bool mLogShadersUniforms; + bool mLogVisual; + } props; + + void setError(RsError e, const char *msg = NULL) { } + + mutable const ObjectBase * mObjHead; + +protected: + +}; +#endif //ANDROID_RS_SERIALIZE + +} // renderscript +} // android #endif diff --git a/libs/rs/rsContextHostStub.h b/libs/rs/rsContextHostStub.h deleted file mode 100644 index c22647f87cc8..000000000000 --- a/libs/rs/rsContextHostStub.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_RS_CONTEXT_HOST_STUB_H -#define ANDROID_RS_CONTEXT_HOST_STUB_H - -#include "rsUtils.h" -//#include "rsMutex.h" - -//#include "rsThreadIO.h" -#include "rsType.h" -#include "rsMatrix.h" -#include "rsAllocation.h" -#include "rsMesh.h" -//#include "rsDevice.h" -#include "rsScriptC.h" -#include "rsAllocation.h" -#include "rsAdapter.h" -#include "rsSampler.h" -#include "rsProgramFragment.h" -#include "rsProgramStore.h" -#include "rsProgramRaster.h" -#include "rsProgramVertex.h" -#include "rsShaderCache.h" -#include "rsVertexArray.h" - -//#include "rsgApiStructs.h" -//#include "rsLocklessFifo.h" - -//#include <ui/egl/android_natives.h> - -// --------------------------------------------------------------------------- -namespace android { -namespace renderscript { - -class Device; - -class Context { -public: - Context(Device *, bool isGraphics, bool useDepth) { - mObjHead = NULL; - } - ~Context() { - } - - - //StructuredAllocationContext mStateAllocation; - ElementState mStateElement; - TypeState mStateType; - SamplerState mStateSampler; - //ProgramFragmentState mStateFragment; - ProgramStoreState mStateFragmentStore; - //ProgramRasterState mStateRaster; - //ProgramVertexState mStateVertex; - VertexArrayState mStateVertexArray; - - //ScriptCState mScriptC; - ShaderCache mShaderCache; - - RsSurfaceConfig mUserSurfaceConfig; - - //bool setupCheck(); - - ProgramFragment * getDefaultProgramFragment() const { - return NULL; - } - ProgramVertex * getDefaultProgramVertex() const { - return NULL; - } - ProgramStore * getDefaultProgramStore() const { - return NULL; - } - ProgramRaster * getDefaultProgramRaster() const { - return NULL; - } - - uint32_t getWidth() const {return 0;} - uint32_t getHeight() const {return 0;} - - // Timers - enum Timers { - RS_TIMER_IDLE, - RS_TIMER_INTERNAL, - RS_TIMER_SCRIPT, - RS_TIMER_CLEAR_SWAP, - _RS_TIMER_TOTAL - }; - - bool checkVersion1_1() const {return false; } - bool checkVersion2_0() const {return false; } - - struct { - bool mLogTimes; - bool mLogScripts; - bool mLogObjects; - bool mLogShaders; - bool mLogShadersAttr; - bool mLogShadersUniforms; - bool mLogVisual; - } props; - - void dumpDebug() const { } - void checkError(const char *) const { }; - void setError(RsError e, const char *msg = NULL) { } - - mutable const ObjectBase * mObjHead; - - bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;} - bool ext_GL_NV_texture_npot_2D_mipmap() const {return false;} - float ext_texture_max_aniso() const {return 1.0f;} - uint32_t getMaxFragmentTextures() const {return mGL.mMaxFragmentTextureImageUnits;} - uint32_t getMaxFragmentUniformVectors() const {return mGL.mMaxFragmentUniformVectors;} - uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;} - -protected: - - struct { - const uint8_t * mVendor; - const uint8_t * mRenderer; - const uint8_t * mVersion; - const uint8_t * mExtensions; - - uint32_t mMajorVersion; - uint32_t mMinorVersion; - - int32_t mMaxVaryingVectors; - int32_t mMaxTextureImageUnits; - - int32_t mMaxFragmentTextureImageUnits; - int32_t mMaxFragmentUniformVectors; - - int32_t mMaxVertexAttribs; - int32_t mMaxVertexUniformVectors; - int32_t mMaxVertexTextureUnits; - - bool OES_texture_npot; - } mGL; - -}; - -} -} -#endif diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp index dd964452e5b5..d7d03f6a283d 100644 --- a/libs/rs/rsDevice.cpp +++ b/libs/rs/rsDevice.cpp @@ -15,11 +15,7 @@ */ #include "rsDevice.h" -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif using namespace android; using namespace android::renderscript; diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp index 6ae8bb8f640e..477cb6166b21 100644 --- a/libs/rs/rsElement.cpp +++ b/libs/rs/rsElement.cpp @@ -15,13 +15,7 @@ */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include <GLES/gl.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#endif using namespace android; using namespace android::renderscript; @@ -65,7 +59,7 @@ size_t Element::getSizeBits() const { void Element::dumpLOGV(const char *prefix) const { ObjectBase::dumpLOGV(prefix); - LOGV("%s Element: fieldCount: %i, size bytes: %i", prefix, mFieldCount, getSizeBytes()); + LOGV("%s Element: fieldCount: %zu, size bytes: %zu", prefix, mFieldCount, getSizeBytes()); for (uint32_t ct = 0; ct < mFieldCount; ct++) { LOGV("%s Element field index: %u ------------------", prefix, ct); LOGV("%s name: %s, offsetBits: %u, arraySize: %u", diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp index 0c8692d3f489..cd02c24b981f 100644 --- a/libs/rs/rsFileA3D.cpp +++ b/libs/rs/rsFileA3D.cpp @@ -15,12 +15,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif - #include "rsFileA3D.h" #include "rsMesh.h" @@ -35,6 +30,7 @@ FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) { mData = NULL; mWriteStream = NULL; mReadStream = NULL; + mAsset = NULL; mMajorVersion = 0; mMinorVersion = 1; @@ -57,6 +53,9 @@ FileA3D::~FileA3D() { if (mAlloc) { free(mAlloc); } + if (mAsset) { + delete mAsset; + } } void FileA3D::parseHeader(IStream *headerStream) { @@ -83,6 +82,11 @@ void FileA3D::parseHeader(IStream *headerStream) { } } +bool FileA3D::load(Asset *asset) { + mAsset = asset; + return load(asset->getBuffer(false), asset->getLength()); +} + bool FileA3D::load(const void *data, size_t length) { const uint8_t *localData = (const uint8_t *)data; @@ -240,31 +244,31 @@ ObjectBase *FileA3D::initializeFromEntry(size_t index) { entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_PROGRAM_VERTEX: - entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream); + //entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_PROGRAM_RASTER: - entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream); + //entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT: - entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream); + //entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_PROGRAM_STORE: - entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream); + //entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_SAMPLER: - entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream); + //entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_ANIMATION: - entry->mRsObj = Animation::createFromStream(mRSC, mReadStream); + //entry->mRsObj = Animation::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_ADAPTER_1D: - entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream); + //entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_ADAPTER_2D: - entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream); + //entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream); break; case RS_A3D_CLASS_ID_SCRIPT_C: - return NULL; + break; } if (entry->mRsObj) { entry->mRsObj->incUserRef(); @@ -357,26 +361,6 @@ void FileA3D::appendToFile(ObjectBase *obj) { mWriteStream->align(4); } -namespace android { -namespace renderscript { - -RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len) { - FileA3D *fa3d = new FileA3D(rsc); - - FILE *f = fopen("/sdcard/test.a3d", "rb"); - if (f) { - fa3d->load(f); - fclose(f); - fa3d->incUserRef(); - return fa3d; - } - delete fa3d; - return NULL; -} - -} -} - RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) { FileA3D *fa3d = static_cast<FileA3D *>(file); if (!fa3d) { @@ -422,7 +406,7 @@ void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uin } } -RsFile rsaFileA3DCreateFromAssetStream(RsContext con, const void *data, uint32_t len) { +RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) { if (data == NULL) { LOGE("File load failed. Asset stream is NULL"); return NULL; @@ -435,3 +419,35 @@ RsFile rsaFileA3DCreateFromAssetStream(RsContext con, const void *data, uint32_t fa3d->load(data, len); return fa3d; } + +RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) { + Context *rsc = static_cast<Context *>(con); + Asset *asset = static_cast<Asset *>(_asset); + FileA3D *fa3d = new FileA3D(rsc); + fa3d->incUserRef(); + + fa3d->load(asset); + return fa3d; +} + +RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) { + if (path == NULL) { + LOGE("File load failed. Path is NULL"); + return NULL; + } + + Context *rsc = static_cast<Context *>(con); + FileA3D *fa3d = NULL; + + FILE *f = fopen(path, "rb"); + if (f) { + fa3d = new FileA3D(rsc); + fa3d->incUserRef(); + fa3d->load(f); + fclose(f); + } else { + LOGE("Could not open file %s", path); + } + + return fa3d; +} diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h index 3ece4c94efc8..056b5af4c1d5 100644 --- a/libs/rs/rsFileA3D.h +++ b/libs/rs/rsFileA3D.h @@ -21,6 +21,7 @@ #include "rsMesh.h" #include <utils/String8.h> +#include <utils/Asset.h> #include "rsStream.h" #include <stdio.h> @@ -59,6 +60,7 @@ public: }; bool load(FILE *f); + bool load(Asset *asset); bool load(const void *data, size_t length); size_t getNumIndexEntries() const; @@ -83,6 +85,7 @@ protected: const uint8_t * mData; void * mAlloc; uint64_t mDataSize; + Asset *mAsset; OStream *mWriteStream; Vector<A3DIndexEntry*> mWriteIndex; diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index 2fa1f0aabf9f..8a5ab99e8bad 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -15,11 +15,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif #include "rsFont.h" #include "rsProgramFragment.h" @@ -40,20 +36,21 @@ Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) { mFace = NULL; } -bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) { +bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) { if (mInitialized) { LOGE("Reinitialization of fonts not supported"); return false; } - String8 fontsDir("/fonts/"); - String8 fullPath(getenv("ANDROID_ROOT")); - fullPath += fontsDir; - fullPath += name; + FT_Error error = 0; + if (data != NULL && dataLen > 0) { + error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace); + } else { + error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace); + } - FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace); if (error) { - LOGE("Unable to initialize font %s", fullPath.string()); + LOGE("Unable to initialize font %s", name); return false; } @@ -61,9 +58,9 @@ bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) { mFontSize = fontSize; mDpi = dpi; - error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0); + error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0); if (error) { - LOGE("Unable to set font size on %s", fullPath.string()); + LOGE("Unable to set font size on %s", name); return false; } @@ -73,6 +70,15 @@ bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) { return true; } +void Font::preDestroy() const { + for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { + if (mRSC->mStateFont.mActiveFonts[ct] == this) { + mRSC->mStateFont.mActiveFonts.removeAt(ct); + break; + } + } +} + void Font::invalidateTextureCache() { for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { mCachedGlyphs.valueAt(i)->mIsValid = false; @@ -132,7 +138,8 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect int32_t width = (int32_t) glyph->mBitmapWidth; int32_t height = (int32_t) glyph->mBitmapHeight; - if (bounds->bottom > nPenY) { + // 0, 0 is top left, so bottom is a positive number + if (bounds->bottom < nPenY) { bounds->bottom = nPenY; } if (bounds->left > nPenX) { @@ -141,8 +148,8 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect if (bounds->right < nPenX + width) { bounds->right = nPenX + width; } - if (bounds->top < nPenY + height) { - bounds->top = nPenY + height; + if (bounds->top > nPenY - height) { + bounds->top = nPenY - height; } } @@ -160,7 +167,7 @@ void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y, return; } // Reset min and max of the bounding box to something large - bounds->set(1e6, -1e6, -1e6, 1e6); + bounds->set(1e6, -1e6, 1e6, -1e6); } int32_t penX = x, penY = y; @@ -278,7 +285,8 @@ Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) { return newGlyph; } -Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) { +Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi, + const void *data, uint32_t dataLen) { rsc->mStateFont.checkInit(); Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; @@ -290,7 +298,7 @@ Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t } Font *newFont = new Font(rsc); - bool isInitialized = newFont->init(name, fontSize, dpi); + bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen); if (isInitialized) { activeFonts.push(newFont); rsc->mStateFont.precacheLatin(newFont); @@ -306,13 +314,6 @@ Font::~Font() { FT_Done_Face(mFace); } - for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { - if (mRSC->mStateFont.mActiveFonts[ct] == this) { - mRSC->mStateFont.mActiveFonts.removeAt(ct); - break; - } - } - for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); delete glyph; @@ -332,31 +333,20 @@ FontState::FontState() { // Get the gamma float gamma = DEFAULT_TEXT_GAMMA; if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { - LOGD(" Setting text gamma to %s", property); gamma = atof(property); - } else { - LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); } // Get the black gamma threshold int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { - LOGD(" Setting text black gamma threshold to %s", property); blackThreshold = atoi(property); - } else { - LOGD(" Using default text black gamma threshold of %d", - DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); } mBlackThreshold = (float)(blackThreshold) / 255.0f; // Get the white gamma threshold int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { - LOGD(" Setting text white gamma threshold to %s", property); whiteThreshold = atoi(property); - } else { - LOGD(" Using default white black gamma threshold of %d", - DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); } mWhiteThreshold = (float)(whiteThreshold) / 255.0f; @@ -622,7 +612,7 @@ void FontState::issueDrawCommand() { mRSC->setProgramStore(mFontProgramStore.get()); if (mConstantsDirty) { - mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants)); + mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants)); mConstantsDirty = false; } @@ -735,7 +725,11 @@ void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y, Font *currentFont = mRSC->getFont(); if (!currentFont) { if (!mDefault.get()) { - mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); + String8 fontsDir("/fonts/DroidSans.ttf"); + String8 fullPath(getenv("ANDROID_ROOT")); + fullPath += fontsDir; + + mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96)); } currentFont = mDefault.get(); } @@ -755,6 +749,8 @@ void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y, void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) { renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds); + bounds->bottom = - bounds->bottom; + bounds->top = - bounds->top; } void FontState::setFontColor(float r, float g, float b, float a) { @@ -801,11 +797,6 @@ void FontState::deinit(Context *rsc) { mDefault.clear(); - Vector<Font*> fontsToDereference = mActiveFonts; - for (uint32_t i = 0; i < fontsToDereference.size(); i ++) { - fontsToDereference[i]->zeroUserRef(); - } - if (mLibrary) { FT_Done_FreeType( mLibrary ); mLibrary = NULL; @@ -815,7 +806,7 @@ void FontState::deinit(Context *rsc) { namespace android { namespace renderscript { -RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) { +RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) { Font *newFont = Font::create(rsc, name, fontSize, dpi); if (newFont) { newFont->incUserRef(); @@ -823,5 +814,13 @@ RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, return newFont; } +RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) { + Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen); + if (newFont) { + newFont->incUserRef(); + } + return newFont; +} + } // renderscript } // android diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h index 0f6815d218db..48209992e9b1 100644 --- a/libs/rs/rsFont.h +++ b/libs/rs/rsFont.h @@ -73,7 +73,8 @@ public: return RS_A3D_CLASS_ID_UNKNOWN; } - static Font * create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi); + static Font * create(Context *rsc, const char *name, float fontSize, uint32_t dpi, + const void *data = NULL, uint32_t dataLen = 0); protected: @@ -112,12 +113,13 @@ protected: }; String8 mFontName; - uint32_t mFontSize; + float mFontSize; uint32_t mDpi; Font(Context *rsc); - bool init(const char *name, uint32_t fontSize, uint32_t dpi); + bool init(const char *name, float fontSize, uint32_t dpi, const void *data = NULL, uint32_t dataLen = 0); + virtual void preDestroy() const; FT_Face mFace; bool mInitialized; bool mHasKerning; diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h index 122a9ed08c95..6f21a35c5505 100644 --- a/libs/rs/rsHandcode.h +++ b/libs/rs/rsHandcode.h @@ -49,64 +49,49 @@ static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t s } } -static inline void rsHCAPI_AllocationData (RsContext rsc, RsAllocation va, const void * data, uint32_t sizeBytes) { +static inline void rsHCAPI_Allocation1DData (RsContext rsc, RsAllocation va, uint32_t xoff, uint32_t lod, + uint32_t count, const void * data, uint32_t sizeBytes) { ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_AllocationData); + uint32_t size = sizeof(RS_CMD_Allocation1DData); if (sizeBytes < DATA_SYNC_SIZE) { size += (sizeBytes + 3) & ~3; } - RS_CMD_AllocationData *cmd = static_cast<RS_CMD_AllocationData *>(io->mToCore.reserve(size)); - cmd->va = va; - cmd->bytes = sizeBytes; - cmd->data = data; - if (sizeBytes < DATA_SYNC_SIZE) { - cmd->data = (void *)(cmd+1); - memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_AllocationData, size); - } else { - io->mToCore.commitSync(RS_CMD_ID_AllocationData, size); - } -} - -static inline void rsHCAPI_Allocation1DSubData (RsContext rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void * data, uint32_t sizeBytes) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_Allocation1DSubData); - if (sizeBytes < DATA_SYNC_SIZE) { - size += (sizeBytes + 3) & ~3; - } - RS_CMD_Allocation1DSubData *cmd = static_cast<RS_CMD_Allocation1DSubData *>(io->mToCore.reserve(size)); + RS_CMD_Allocation1DData *cmd = static_cast<RS_CMD_Allocation1DData *>(io->mToCore.reserve(size)); cmd->va = va; cmd->xoff = xoff; + cmd->lod = lod; cmd->count = count; cmd->data = data; cmd->bytes = sizeBytes; if (sizeBytes < DATA_SYNC_SIZE) { cmd->data = (void *)(cmd+1); memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_Allocation1DSubData, size); + io->mToCore.commit(RS_CMD_ID_Allocation1DData, size); } else { - io->mToCore.commitSync(RS_CMD_ID_Allocation1DSubData, size); + io->mToCore.commitSync(RS_CMD_ID_Allocation1DData, size); } } -static inline void rsHCAPI_Allocation1DSubElementData (RsContext rsc, RsAllocation va, uint32_t x, const void * data, uint32_t comp_offset, uint32_t sizeBytes) { +static inline void rsHCAPI_Allocation1DElementData (RsContext rsc, RsAllocation va, uint32_t x, uint32_t lod, + const void * data, uint32_t comp_offset, uint32_t sizeBytes) { ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_Allocation1DSubElementData); + uint32_t size = sizeof(RS_CMD_Allocation1DElementData); if (sizeBytes < DATA_SYNC_SIZE) { size += (sizeBytes + 3) & ~3; } - RS_CMD_Allocation1DSubElementData *cmd = static_cast<RS_CMD_Allocation1DSubElementData *>(io->mToCore.reserve(size)); + RS_CMD_Allocation1DElementData *cmd = static_cast<RS_CMD_Allocation1DElementData *>(io->mToCore.reserve(size)); cmd->va = va; cmd->x = x; + cmd->lod = lod; cmd->data = data; cmd->comp_offset = comp_offset; cmd->bytes = sizeBytes; if (sizeBytes < DATA_SYNC_SIZE) { cmd->data = (void *)(cmd+1); memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_Allocation1DSubElementData, size); + io->mToCore.commit(RS_CMD_ID_Allocation1DElementData, size); } else { - io->mToCore.commitSync(RS_CMD_ID_Allocation1DSubElementData, size); + io->mToCore.commitSync(RS_CMD_ID_Allocation1DElementData, size); } } diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp index 804c76726743..70b72783863e 100644 --- a/libs/rs/rsLocklessFifo.cpp +++ b/libs/rs/rsLocklessFifo.cpp @@ -76,7 +76,8 @@ uint32_t LocklessCommandFifo::getFreeSpace() const { } bool LocklessCommandFifo::isEmpty() const { - return mPut == mGet; + uint32_t p = android_atomic_acquire_load((int32_t *)&mPut); + return ((uint8_t *)p) == mGet; } @@ -99,7 +100,9 @@ void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes) { //dumpState("commit 1"); reinterpret_cast<uint16_t *>(mPut)[0] = command; reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes; - mPut += ((sizeInBytes + 3) & ~3) + 4; + + int32_t s = ((sizeInBytes + 3) & ~3) + 4; + android_atomic_add(s, (int32_t *)&mPut); //dumpState("commit 2"); mSignalToWorker.set(); } @@ -155,7 +158,9 @@ const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData) { void LocklessCommandFifo::next() { uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1]; - mGet += ((bytes + 3) & ~3) + 4; + + android_atomic_add(((bytes + 3) & ~3) + 4, (int32_t *)&mGet); + //mGet += ((bytes + 3) & ~3) + 4; if (isEmpty()) { mSignalToControl.set(); } @@ -210,3 +215,19 @@ void LocklessCommandFifo::makeSpace(uint32_t bytes) { void LocklessCommandFifo::dumpState(const char *s) const { LOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd); } + +void LocklessCommandFifo::printDebugData() const { + dumpState("printing fifo debug"); + const uint32_t *pptr = (const uint32_t *)mGet; + pptr -= 8 * 4; + if (mGet < mBuffer) { + pptr = (const uint32_t *)mBuffer; + } + + + for (int ct=0; ct < 16; ct++) { + LOGV("fifo %p = 0x%08x 0x%08x 0x%08x 0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]); + pptr += 4; + } + +} diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h index c96396399e32..eabdc3e97f05 100644 --- a/libs/rs/rsLocklessFifo.h +++ b/libs/rs/rsLocklessFifo.h @@ -35,6 +35,8 @@ public: bool init(uint32_t size); void shutdown(); + void printDebugData() const; + LocklessCommandFifo(); ~LocklessCommandFifo(); diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index baf4c5319074..76fe62da8830 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -14,17 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" - +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES2/gl2.h> #include <GLES/glext.h> -#else -#include "rsContextHostStub.h" - -#include <OpenGL/gl.h> -#include <OpenGl/glext.h> #endif using namespace android; @@ -35,10 +29,13 @@ Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { mPrimitivesCount = 0; mVertexBuffers = NULL; mVertexBufferCount = 0; + +#ifndef ANDROID_RS_SERIALIZE mAttribs = NULL; mAttribAllocationIndex = NULL; mAttribCount = 0; +#endif } Mesh::~Mesh() { @@ -53,12 +50,97 @@ Mesh::~Mesh() { delete[] mPrimitives; } +#ifndef ANDROID_RS_SERIALIZE if (mAttribs) { delete[] mAttribs; delete[] mAttribAllocationIndex; } +#endif +} + +void Mesh::serialize(OStream *stream) const { + // Need to identify ourselves + stream->addU32((uint32_t)getClassId()); + + String8 name(getName()); + stream->addString(&name); + + // Store number of vertex streams + stream->addU32(mVertexBufferCount); + for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) { + mVertexBuffers[vCount]->serialize(stream); + } + + stream->addU32(mPrimitivesCount); + // Store the primitives + for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) { + Primitive_t * prim = mPrimitives[pCount]; + + stream->addU8((uint8_t)prim->mPrimitive); + + if (prim->mIndexBuffer.get()) { + stream->addU32(1); + prim->mIndexBuffer->serialize(stream); + } else { + stream->addU32(0); + } + } } +Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { + // First make sure we are reading the correct object + RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); + if (classID != RS_A3D_CLASS_ID_MESH) { + LOGE("mesh loading skipped due to invalid class id"); + return NULL; + } + + Mesh * mesh = new Mesh(rsc); + + String8 name; + stream->loadString(&name); + mesh->setName(name.string(), name.size()); + + mesh->mVertexBufferCount = stream->loadU32(); + if (mesh->mVertexBufferCount) { + mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount]; + + for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) { + Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); + mesh->mVertexBuffers[vCount].set(vertexAlloc); + } + } + + mesh->mPrimitivesCount = stream->loadU32(); + if (mesh->mPrimitivesCount) { + mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount]; + + // load all primitives + for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) { + Primitive_t * prim = new Primitive_t; + mesh->mPrimitives[pCount] = prim; + + prim->mPrimitive = (RsPrimitive)stream->loadU8(); + + // Check to see if the index buffer was stored + uint32_t isIndexPresent = stream->loadU32(); + if (isIndexPresent) { + Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); + prim->mIndexBuffer.set(indexAlloc); + } + } + } + +#ifndef ANDROID_RS_SERIALIZE + mesh->updateGLPrimitives(); + mesh->initVertexAttribs(); + mesh->uploadAll(rsc); +#endif + return mesh; +} + +#ifndef ANDROID_RS_SERIALIZE + bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { // Do not create attribs for padding if (elem->getFieldName(fieldIdx)[0] == '#') { @@ -224,86 +306,6 @@ void Mesh::updateGLPrimitives() { } } -void Mesh::serialize(OStream *stream) const { - // Need to identify ourselves - stream->addU32((uint32_t)getClassId()); - - String8 name(getName()); - stream->addString(&name); - - // Store number of vertex streams - stream->addU32(mVertexBufferCount); - for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) { - mVertexBuffers[vCount]->serialize(stream); - } - - stream->addU32(mPrimitivesCount); - // Store the primitives - for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) { - Primitive_t * prim = mPrimitives[pCount]; - - stream->addU8((uint8_t)prim->mPrimitive); - - if (prim->mIndexBuffer.get()) { - stream->addU32(1); - prim->mIndexBuffer->serialize(stream); - } else { - stream->addU32(0); - } - } -} - -Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { - // First make sure we are reading the correct object - RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); - if (classID != RS_A3D_CLASS_ID_MESH) { - LOGE("mesh loading skipped due to invalid class id"); - return NULL; - } - - Mesh * mesh = new Mesh(rsc); - - String8 name; - stream->loadString(&name); - mesh->setName(name.string(), name.size()); - - mesh->mVertexBufferCount = stream->loadU32(); - if (mesh->mVertexBufferCount) { - mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount]; - - for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) { - Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); - mesh->mVertexBuffers[vCount].set(vertexAlloc); - } - } - - mesh->mPrimitivesCount = stream->loadU32(); - if (mesh->mPrimitivesCount) { - mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount]; - - // load all primitives - for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) { - Primitive_t * prim = new Primitive_t; - mesh->mPrimitives[pCount] = prim; - - prim->mPrimitive = (RsPrimitive)stream->loadU8(); - - // Check to see if the index buffer was stored - uint32_t isIndexPresent = stream->loadU32(); - if (isIndexPresent) { - Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); - prim->mIndexBuffer.set(indexAlloc); - } - } - } - - mesh->updateGLPrimitives(); - mesh->initVertexAttribs(); - mesh->uploadAll(rsc); - - return mesh; -} - void Mesh::computeBBox() { float *posPtr = NULL; uint32_t vectorSize = 0; @@ -347,13 +349,6 @@ void Mesh::computeBBox() { } } - -MeshContext::MeshContext() { -} - -MeshContext::~MeshContext() { -} - namespace android { namespace renderscript { @@ -428,3 +423,5 @@ void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *pri } } } + +#endif diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h index 410b70bc5632..3e080e2aabb9 100644 --- a/libs/rs/rsMesh.h +++ b/libs/rs/rsMesh.h @@ -50,15 +50,18 @@ public: Primitive_t ** mPrimitives; uint32_t mPrimitivesCount; + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } + static Mesh *createFromStream(Context *rsc, IStream *stream); + +#ifndef ANDROID_RS_SERIALIZE void render(Context *) const; void renderPrimitive(Context *, uint32_t primIndex) const; void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; void uploadAll(Context *); void updateGLPrimitives(); - virtual void serialize(OStream *stream) const; - virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } - static Mesh *createFromStream(Context *rsc, IStream *stream); + // Bounding volumes float mBBoxMin[3]; @@ -76,12 +79,15 @@ protected: // buffer, it lets us properly map it uint32_t *mAttribAllocationIndex; uint32_t mAttribCount; +#endif }; class MeshContext { public: - MeshContext(); - ~MeshContext(); + MeshContext() { + } + ~MeshContext() { + } }; } diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp index aec2f6794de5..f428f9486d8d 100644 --- a/libs/rs/rsObjectBase.cpp +++ b/libs/rs/rsObjectBase.cpp @@ -15,13 +15,7 @@ */ #include "rsObjectBase.h" - -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif - using namespace android; using namespace android::renderscript; diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 39b85e39ed3f..4ef05bf4372f 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -14,15 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGL/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsProgram.h" diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 22cd5d39a69e..ff314b7f6429 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -14,17 +14,13 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGL/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsProgramFragment.h" diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp index f2b5b9af7d4b..ace1572f4010 100644 --- a/libs/rs/rsProgramRaster.cpp +++ b/libs/rs/rsProgramRaster.cpp @@ -14,15 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES/glext.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGl/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsProgramRaster.h" diff --git a/libs/rs/rsProgramStore.cpp b/libs/rs/rsProgramStore.cpp index 72ac574af2fe..09b759d9a340 100644 --- a/libs/rs/rsProgramStore.cpp +++ b/libs/rs/rsProgramStore.cpp @@ -14,15 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES/glext.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGl/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsProgramStore.h" diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index ad2beafbf9d2..403c2a6e356b 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -14,17 +14,13 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGL/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsProgramVertex.h" diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp index e2757df10831..db2383aca7eb 100644 --- a/libs/rs/rsSampler.cpp +++ b/libs/rs/rsSampler.cpp @@ -14,15 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES/glext.h> -#include "rsContext.h" -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#include <OpenGL/glext.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE #include "rsSampler.h" @@ -77,8 +73,20 @@ void Sampler::setupGL(const Context *rsc, const Allocation *tex) { GLenum target = (GLenum)tex->getGLTarget(); if (!rsc->ext_OES_texture_npot() && tex->getType()->getIsNp2()) { - if (tex->getHasGraphicsMipmaps() && rsc->ext_GL_NV_texture_npot_2D_mipmap()) { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + if (tex->getHasGraphicsMipmaps() && + (rsc->ext_GL_NV_texture_npot_2D_mipmap() || rsc->ext_GL_IMG_texture_npot())) { + if (rsc->ext_GL_NV_texture_npot_2D_mipmap()) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + } else { + switch (trans[mMinFilter]) { + case GL_LINEAR_MIPMAP_LINEAR: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + break; + default: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + break; + } + } } else { glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); } diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index efdc626071f8..9ada9c299ac4 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -78,8 +78,6 @@ void Script::setVarObj(uint32_t slot, ObjectBase *val) { (*destPtr)->decSysRef(); } *destPtr = val; - } else { - LOGV("Calling setVarObj on slot = %i which is null. This is dangerous because the script will not hold a ref count on the object.", slot); } } diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 507430dfabc9..445a4e4edeee 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -17,9 +17,11 @@ #include "rsContext.h" #include "rsScriptC.h" #include "rsMatrix.h" -#include "../../compile/libbcc/include/bcc/bcc.h" #include "utils/Timers.h" #include "utils/StopWatch.h" +extern "C" { +#include "libdex/ZipArchive.h" +} #include <GLES/gl.h> #include <GLES/glext.h> @@ -32,6 +34,64 @@ using namespace android::renderscript; Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript +// Input: cacheDir +// Input: resName +// Input: extName +// +// Note: cacheFile = resName + extName +// +// Output: Returns cachePath == cacheDir + cacheFile +char *genCacheFileName(const char *cacheDir, + const char *resName, + const char *extName) { + char cachePath[512]; + char cacheFile[sizeof(cachePath)]; + const size_t kBufLen = sizeof(cachePath) - 1; + + cacheFile[0] = '\0'; + // Note: resName today is usually something like + // "/com.android.fountain:raw/fountain" + if (resName[0] != '/') { + // Get the absolute path of the raw/***.bc file. + + // Generate the absolute path. This doesn't do everything it + // should, e.g. if resName is "./out/whatever" it doesn't crunch + // the leading "./" out because this if-block is not triggered, + // but it'll make do. + // + if (getcwd(cacheFile, kBufLen) == NULL) { + LOGE("Can't get CWD while opening raw/***.bc file\n"); + return NULL; + } + // Append "/" at the end of cacheFile so far. + strncat(cacheFile, "/", kBufLen); + } + + // cacheFile = resName + extName + // + strncat(cacheFile, resName, kBufLen); + if (extName != NULL) { + // TODO(srhines): strncat() is a bit dangerous + strncat(cacheFile, extName, kBufLen); + } + + // Turn the path into a flat filename by replacing + // any slashes after the first one with '@' characters. + char *cp = cacheFile + 1; + while (*cp != '\0') { + if (*cp == '/') { + *cp = '@'; + } + cp++; + } + + // Tack on the file name for the actual cache file path. + strncpy(cachePath, cacheDir, kBufLen); + strncat(cachePath, cacheFile, kBufLen); + + LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); + return strdup(cachePath); +} ScriptC::ScriptC(Context *rsc) : Script(rsc) { mBccScript = NULL; @@ -40,7 +100,18 @@ ScriptC::ScriptC(Context *rsc) : Script(rsc) { ScriptC::~ScriptC() { if (mBccScript) { - bccDeleteScript(mBccScript); + if (mProgram.mObjectSlotList) { + for (size_t ct=0; ct < mProgram.mObjectSlotCount; ct++) { + setVarObj(mProgram.mObjectSlotList[ct], NULL); + } + delete [] mProgram.mObjectSlotList; + mProgram.mObjectSlotList = NULL; + mProgram.mObjectSlotCount = 0; + } + + + LOGD(">>>> ~ScriptC bccDisposeScript(%p)", mBccScript); + bccDisposeScript(mBccScript); } free(mEnviroment.mScriptText); mEnviroment.mScriptText = NULL; @@ -358,28 +429,16 @@ void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len } ScriptCState::ScriptCState() { - mScript.clear(); } ScriptCState::~ScriptCState() { - mScript.clear(); -} - -void ScriptCState::init(Context *rsc) { - clear(rsc); -} - -void ScriptCState::clear(Context *rsc) { - rsAssert(rsc); - mScript.clear(); - mScript.set(new ScriptC(rsc)); } -static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) { +static void* symbolLookup(void* pContext, char const* name) { const ScriptCState::SymbolTable_t *sym; ScriptC *s = (ScriptC *)pContext; if (!strcmp(name, "__isThreadable")) { - return (BCCvoid*) s->mEnviroment.mIsThreadable; + return (void*) s->mEnviroment.mIsThreadable; } else if (!strcmp(name, "__clearThreadable")) { s->mEnviroment.mIsThreadable = false; return NULL; @@ -399,52 +458,68 @@ static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) { return NULL; } +#if 0 extern const char rs_runtime_lib_bc[]; extern unsigned rs_runtime_lib_bc_size; +#endif -void ScriptCState::runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir) { - { - s->mBccScript = bccCreateScript(); - s->mEnviroment.mIsThreadable = true; - bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s); - // bccReadBC() reads in the BitCode, if no cache file corresponding to - // the resName is found. Otherwise, bccReadBC() returns a negative value - // and the "else" branch will be taken. - if (bccReadBC(s->mBccScript, - s->mEnviroment.mScriptText, - s->mEnviroment.mScriptTextLength, - resName, - cacheDir) >= 0) { - //bccLinkBC(s->mBccScript, rs_runtime_lib_bc, rs_runtime_lib_bc_size); - bccCompileBC(s->mBccScript); - } else { - // bccReadBC returns a neagative value: Didn't read any script, - // So, use cached binary instead - bccLoadBinary(s->mBccScript); - } - bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot); - bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit); +bool ScriptCState::runCompiler(Context *rsc, + ScriptC *s, + const char *resName, + const char *cacheDir) { + s->mBccScript = bccCreateScript(); + + s->mEnviroment.mIsThreadable = true; + + if (bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s) != 0) { + LOGE("bcc: FAILS to register symbol callback"); + return false; + } + + if (bccReadBC(s->mBccScript, + resName, + s->mEnviroment.mScriptText, + s->mEnviroment.mScriptTextLength, 0) != 0) { + LOGE("bcc: FAILS to read bitcode"); + return false; + } + +#if 1 + if (bccLinkFile(s->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { + LOGE("bcc: FAILS to link bitcode"); + return false; + } +#endif + char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); + + if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) { + LOGE("bcc: FAILS to prepare executable"); + return false; } - LOGV("%p ScriptCState::runCompiler root %p, init %p", rsc, s->mProgram.mRoot, s->mProgram.mInit); + + free(cachePath); + + s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root")); + s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init")); if (s->mProgram.mInit) { s->mProgram.mInit(); } - bccGetExportFuncs(s->mBccScript, (BCCsizei*) &s->mEnviroment.mInvokeFunctionCount, 0, NULL); + s->mEnviroment.mInvokeFunctionCount = bccGetExportFuncCount(s->mBccScript); if (s->mEnviroment.mInvokeFunctionCount <= 0) s->mEnviroment.mInvokeFunctions = NULL; else { s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t)); - bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions); + bccGetExportFuncList(s->mBccScript, s->mEnviroment.mInvokeFunctionCount, (void **) s->mEnviroment.mInvokeFunctions); } - bccGetExportVars(s->mBccScript, (BCCsizei*) &s->mEnviroment.mFieldCount, 0, NULL); + s->mEnviroment.mFieldCount = bccGetExportVarCount(s->mBccScript); if (s->mEnviroment.mFieldCount <= 0) s->mEnviroment.mFieldAddress = NULL; else { s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *)); - bccGetExportVars(s->mBccScript, NULL, s->mEnviroment.mFieldCount, (BCCvoid **) s->mEnviroment.mFieldAddress); + bccGetExportVarList(s->mBccScript, s->mEnviroment.mFieldCount, (void **) s->mEnviroment.mFieldAddress); s->initSlots(); } @@ -453,76 +528,87 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s, const char *resName, co s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); - if (s->mProgram.mRoot) { - const static int pragmaMax = 16; - BCCsizei pragmaCount; - BCCchar * str[pragmaMax]; - bccGetPragmas(s->mBccScript, &pragmaCount, pragmaMax, &str[0]); + const static int pragmaMax = 16; + size_t pragmaCount = bccGetPragmaCount(s->mBccScript); + char const *keys[pragmaMax]; + char const *values[pragmaMax]; + bccGetPragmaList(s->mBccScript, pragmaMax, keys, values); - for (int ct=0; ct < pragmaCount; ct+=2) { - //LOGE("pragme %s %s", str[ct], str[ct+1]); - if (!strcmp(str[ct], "version")) { + for (size_t i=0; i < pragmaCount; ++i) { + //LOGE("pragma %s %s", keys[i], values[i]); + if (!strcmp(keys[i], "version")) { + if (!strcmp(values[i], "1")) { continue; } + LOGE("Invalid version pragma value: %s\n", values[i]); + return false; + } - if (!strcmp(str[ct], "stateVertex")) { - if (!strcmp(str[ct+1], "default")) { - continue; - } - if (!strcmp(str[ct+1], "parent")) { - s->mEnviroment.mVertex.clear(); - continue; - } - LOGE("Unreconized value %s passed to stateVertex", str[ct+1]); + if (!strcmp(keys[i], "stateVertex")) { + if (!strcmp(values[i], "default")) { + continue; } - - if (!strcmp(str[ct], "stateRaster")) { - if (!strcmp(str[ct+1], "default")) { - continue; - } - if (!strcmp(str[ct+1], "parent")) { - s->mEnviroment.mRaster.clear(); - continue; - } - LOGE("Unreconized value %s passed to stateRaster", str[ct+1]); + if (!strcmp(values[i], "parent")) { + s->mEnviroment.mVertex.clear(); + continue; } + LOGE("Unrecognized value %s passed to stateVertex", values[i]); + return false; + } - if (!strcmp(str[ct], "stateFragment")) { - if (!strcmp(str[ct+1], "default")) { - continue; - } - if (!strcmp(str[ct+1], "parent")) { - s->mEnviroment.mFragment.clear(); - continue; - } - LOGE("Unreconized value %s passed to stateFragment", str[ct+1]); + if (!strcmp(keys[i], "stateRaster")) { + if (!strcmp(values[i], "default")) { + continue; } - - if (!strcmp(str[ct], "stateStore")) { - if (!strcmp(str[ct+1], "default")) { - continue; - } - if (!strcmp(str[ct+1], "parent")) { - s->mEnviroment.mFragmentStore.clear(); - continue; - } - LOGE("Unreconized value %s passed to stateStore", str[ct+1]); + if (!strcmp(values[i], "parent")) { + s->mEnviroment.mRaster.clear(); + continue; } + LOGE("Unrecognized value %s passed to stateRaster", values[i]); + return false; + } + if (!strcmp(keys[i], "stateFragment")) { + if (!strcmp(values[i], "default")) { + continue; + } + if (!strcmp(values[i], "parent")) { + s->mEnviroment.mFragment.clear(); + continue; + } + LOGE("Unrecognized value %s passed to stateFragment", values[i]); + return false; } + if (!strcmp(keys[i], "stateStore")) { + if (!strcmp(values[i], "default")) { + continue; + } + if (!strcmp(values[i], "parent")) { + s->mEnviroment.mFragmentStore.clear(); + continue; + } + LOGE("Unrecognized value %s passed to stateStore", values[i]); + return false; + } + } - } else { - // Deal with an error. + size_t objectSlotCount = bccGetObjectSlotCount(s->mBccScript); + uint32_t *objectSlots = NULL; + if (objectSlotCount) { + objectSlots = new uint32_t[objectSlotCount]; + bccGetObjectSlotList(s->mBccScript, objectSlotCount, objectSlots); + s->mProgram.mObjectSlotList = objectSlots; + s->mProgram.mObjectSlotCount = objectSlotCount; } + + return true; } namespace android { namespace renderscript { void rsi_ScriptCBegin(Context * rsc) { - ScriptCState *ss = &rsc->mScriptC; - ss->clear(rsc); } void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { @@ -531,21 +617,31 @@ void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { char *t = (char *)malloc(len + 1); memcpy(t, text, len); t[len] = 0; - ss->mScript->mEnviroment.mScriptText = t; - ss->mScript->mEnviroment.mScriptTextLength = len; + ss->mScriptText = t; + ss->mScriptLen = len; } -RsScript rsi_ScriptCCreate(Context * rsc, const char *resName, const char *cacheDir) + +RsScript rsi_ScriptCCreate(Context *rsc, + const char *packageName /* deprecated */, + const char *resName, + const char *cacheDir) { ScriptCState *ss = &rsc->mScriptC; - ObjectBaseRef<ScriptC> s(ss->mScript); - ss->mScript.clear(); + ScriptC *s = new ScriptC(rsc); + s->mEnviroment.mScriptText = ss->mScriptText; + s->mEnviroment.mScriptTextLength = ss->mScriptLen; + ss->mScriptText = NULL; + ss->mScriptLen = 0; s->incUserRef(); - ss->runCompiler(rsc, s.get(), resName, cacheDir); - ss->clear(rsc); - return s.get(); + if (!ss->runCompiler(rsc, s, resName, cacheDir)) { + // Error during compile, destroy s and return null. + delete s; + return NULL; + } + return s; } } diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index a71413294394..e794feb10edb 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -21,9 +21,7 @@ #include "RenderScriptEnv.h" -namespace bcc { -class BCCscript; -} +#include <bcc/bcc.h> // --------------------------------------------------------------------------- namespace android { @@ -44,11 +42,15 @@ public: RunScript_t mRoot; VoidFunc_t mInit; + + uint32_t * mObjectSlotList; + uint32_t mObjectSlotCount; }; + Program_t mProgram; - bcc::BCCscript* mBccScript; + BCCScriptRef mBccScript; const Allocation *ptrToAllocation(const void *) const; @@ -78,19 +80,16 @@ public: ScriptCState(); ~ScriptCState(); - ObjectBaseRef<ScriptC> mScript; - - void init(Context *rsc); + char * mScriptText; + size_t mScriptLen; - void clear(Context *rsc); - void runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir); + bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir); struct SymbolTable_t { const char * mName; void * mPtr; bool threadable; }; - //static SymbolTable_t gSyms[]; static const SymbolTable_t * lookupSymbol(const char *); static const SymbolTable_t * lookupSymbolCL(const char *); static const SymbolTable_t * lookupSymbolGL(const char *); diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index f61b983b6ce2..80da8aeed8af 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -100,70 +100,24 @@ static float SC_frac(float v) { // Time routines ////////////////////////////////////////////////////////////////////////////// -static int32_t SC_second() { +static time_t SC_time(time_t *timer) { GET_TLS(); - - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_sec; -} - -static int32_t SC_minute() { - GET_TLS(); - - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_min; + return time(timer); } -static int32_t SC_hour() { +static tm* SC_localtime(tm *local, time_t *timer) { GET_TLS(); + if (!local) { + return NULL; + } - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_hour; -} - -static int32_t SC_day() { - GET_TLS(); - - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_mday; -} - -static int32_t SC_month() { - GET_TLS(); - - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_mon; -} - -static int32_t SC_year() { - GET_TLS(); - - time_t rawtime; - time(&rawtime); - - struct tm *timeinfo; - timeinfo = localtime(&rawtime); - return timeinfo->tm_year; + // The native localtime function is not thread-safe, so we + // have to apply locking for proper behavior in RenderScript. + pthread_mutex_lock(&rsc->gLibMutex); + tm *tmp = localtime(timer); + memcpy(local, tmp, sizeof(*tmp)); + pthread_mutex_unlock(&rsc->gLibMutex); + return local; } static int64_t SC_uptimeMillis() { @@ -272,51 +226,51 @@ static bool SC_isObject(RsAllocation vsrc) { } static void SC_debugF(const char *s, float f) { - LOGE("%s %f, 0x%08x", s, f, *((int *) (&f))); + LOGD("%s %f, 0x%08x", s, f, *((int *) (&f))); } static void SC_debugFv2(const char *s, float f1, float f2) { - LOGE("%s {%f, %f}", s, f1, f2); + LOGD("%s {%f, %f}", s, f1, f2); } static void SC_debugFv3(const char *s, float f1, float f2, float f3) { - LOGE("%s {%f, %f, %f}", s, f1, f2, f3); + LOGD("%s {%f, %f, %f}", s, f1, f2, f3); } static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) { - LOGE("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); + LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); } static void SC_debugD(const char *s, double d) { - LOGE("%s %f, 0x%08llx", s, d, *((long long *) (&d))); + LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d))); } static void SC_debugFM4v4(const char *s, const float *f) { - LOGE("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); - LOGE("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); - LOGE("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); - LOGE("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); + LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); + LOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); + LOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); + LOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); } static void SC_debugFM3v3(const char *s, const float *f) { - LOGE("%s {%f, %f, %f", s, f[0], f[3], f[6]); - LOGE("%s %f, %f, %f", s, f[1], f[4], f[7]); - LOGE("%s %f, %f, %f}",s, f[2], f[5], f[8]); + LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]); + LOGD("%s %f, %f, %f", s, f[1], f[4], f[7]); + LOGD("%s %f, %f, %f}",s, f[2], f[5], f[8]); } static void SC_debugFM2v2(const char *s, const float *f) { - LOGE("%s {%f, %f", s, f[0], f[2]); - LOGE("%s %f, %f}",s, f[1], f[3]); + LOGD("%s {%f, %f", s, f[0], f[2]); + LOGD("%s %f, %f}",s, f[1], f[3]); } static void SC_debugI32(const char *s, int32_t i) { - LOGE("%s %i 0x%x", s, i, i); + LOGD("%s %i 0x%x", s, i, i); } static void SC_debugU32(const char *s, uint32_t i) { - LOGE("%s %u 0x%x", s, i, i); + LOGD("%s %u 0x%x", s, i, i); } static void SC_debugLL64(const char *s, long long ll) { - LOGE("%s %lld 0x%llx", s, ll, ll); + LOGD("%s %lld 0x%llx", s, ll, ll); } static void SC_debugULL64(const char *s, unsigned long long ll) { - LOGE("%s %llu 0x%llx", s, ll, ll); + LOGD("%s %llu 0x%llx", s, ll, ll); } static void SC_debugP(const char *s, const void *p) { - LOGE("%s %p", s, p); + LOGD("%s %p", s, p); } static uint32_t SC_toClient2(int cmdID, void *data, int len) { @@ -351,6 +305,14 @@ int SC_modsi3(int a, int b) { return a % b; } +unsigned int SC_udivsi3(unsigned int a, unsigned int b) { + return a / b; +} + +unsigned int SC_umodsi3(unsigned int a, unsigned int b) { + return a % b; +} + int SC_getAllocation(const void *ptr) { GET_TLS(); const Allocation *alloc = sc->ptrToAllocation(ptr); @@ -385,6 +347,489 @@ void SC_ForEach2(RsScript vs, s->runForEach(rsc, ain, aout, usr, call); } + +////////////////////////////////////////////////////////////////////////////// +// Heavy math functions +////////////////////////////////////////////////////////////////////////////// + +typedef struct { + float m[16]; +} rs_matrix4x4; + +typedef struct { + float m[9]; +} rs_matrix3x3; + +typedef struct { + float m[4]; +} rs_matrix2x2; + +static inline void +rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 4 + col] = v; +} + +static inline float +rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) { + return m->m[row * 4 + col]; +} + +static inline void +rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 3 + col] = v; +} + +static inline float +rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) { + return m->m[row * 3 + col]; +} + +static inline void +rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 2 + col] = v; +} + +static inline float +rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) { + return m->m[row * 2 + col]; +} + + +static void SC_MatrixLoadIdentity_4x4(rs_matrix4x4 *m) { + m->m[0] = 1.f; + m->m[1] = 0.f; + m->m[2] = 0.f; + m->m[3] = 0.f; + m->m[4] = 0.f; + m->m[5] = 1.f; + m->m[6] = 0.f; + m->m[7] = 0.f; + m->m[8] = 0.f; + m->m[9] = 0.f; + m->m[10] = 1.f; + m->m[11] = 0.f; + m->m[12] = 0.f; + m->m[13] = 0.f; + m->m[14] = 0.f; + m->m[15] = 1.f; +} + +static void SC_MatrixLoadIdentity_3x3(rs_matrix3x3 *m) { + m->m[0] = 1.f; + m->m[1] = 0.f; + m->m[2] = 0.f; + m->m[3] = 0.f; + m->m[4] = 1.f; + m->m[5] = 0.f; + m->m[6] = 0.f; + m->m[7] = 0.f; + m->m[8] = 1.f; +} + +static void SC_MatrixLoadIdentity_2x2(rs_matrix2x2 *m) { + m->m[0] = 1.f; + m->m[1] = 0.f; + m->m[2] = 0.f; + m->m[3] = 1.f; +} + +static void SC_MatrixLoad_4x4_f(rs_matrix4x4 *m, const float *v) { + m->m[0] = v[0]; + m->m[1] = v[1]; + m->m[2] = v[2]; + m->m[3] = v[3]; + m->m[4] = v[4]; + m->m[5] = v[5]; + m->m[6] = v[6]; + m->m[7] = v[7]; + m->m[8] = v[8]; + m->m[9] = v[9]; + m->m[10] = v[10]; + m->m[11] = v[11]; + m->m[12] = v[12]; + m->m[13] = v[13]; + m->m[14] = v[14]; + m->m[15] = v[15]; +} + +static void SC_MatrixLoad_3x3_f(rs_matrix3x3 *m, const float *v) { + m->m[0] = v[0]; + m->m[1] = v[1]; + m->m[2] = v[2]; + m->m[3] = v[3]; + m->m[4] = v[4]; + m->m[5] = v[5]; + m->m[6] = v[6]; + m->m[7] = v[7]; + m->m[8] = v[8]; +} + +static void SC_MatrixLoad_2x2_f(rs_matrix2x2 *m, const float *v) { + m->m[0] = v[0]; + m->m[1] = v[1]; + m->m[2] = v[2]; + m->m[3] = v[3]; +} + +static void SC_MatrixLoad_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *v) { + m->m[0] = v->m[0]; + m->m[1] = v->m[1]; + m->m[2] = v->m[2]; + m->m[3] = v->m[3]; + m->m[4] = v->m[4]; + m->m[5] = v->m[5]; + m->m[6] = v->m[6]; + m->m[7] = v->m[7]; + m->m[8] = v->m[8]; + m->m[9] = v->m[9]; + m->m[10] = v->m[10]; + m->m[11] = v->m[11]; + m->m[12] = v->m[12]; + m->m[13] = v->m[13]; + m->m[14] = v->m[14]; + m->m[15] = v->m[15]; +} + +static void SC_MatrixLoad_4x4_3x3(rs_matrix4x4 *m, const rs_matrix3x3 *v) { + m->m[0] = v->m[0]; + m->m[1] = v->m[1]; + m->m[2] = v->m[2]; + m->m[3] = 0.f; + m->m[4] = v->m[3]; + m->m[5] = v->m[4]; + m->m[6] = v->m[5]; + m->m[7] = 0.f; + m->m[8] = v->m[6]; + m->m[9] = v->m[7]; + m->m[10] = v->m[8]; + m->m[11] = 0.f; + m->m[12] = 0.f; + m->m[13] = 0.f; + m->m[14] = 0.f; + m->m[15] = 1.f; +} + +static void SC_MatrixLoad_4x4_2x2(rs_matrix4x4 *m, const rs_matrix2x2 *v) { + m->m[0] = v->m[0]; + m->m[1] = v->m[1]; + m->m[2] = 0.f; + m->m[3] = 0.f; + m->m[4] = v->m[2]; + m->m[5] = v->m[3]; + m->m[6] = 0.f; + m->m[7] = 0.f; + m->m[8] = 0.f; + m->m[9] = 0.f; + m->m[10] = 1.f; + m->m[11] = 0.f; + m->m[12] = 0.f; + m->m[13] = 0.f; + m->m[14] = 0.f; + m->m[15] = 1.f; +} + +static void SC_MatrixLoad_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *v) { + m->m[0] = v->m[0]; + m->m[1] = v->m[1]; + m->m[2] = v->m[2]; + m->m[3] = v->m[3]; + m->m[4] = v->m[4]; + m->m[5] = v->m[5]; + m->m[6] = v->m[6]; + m->m[7] = v->m[7]; + m->m[8] = v->m[8]; +} + +static void SC_MatrixLoad_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *v) { + m->m[0] = v->m[0]; + m->m[1] = v->m[1]; + m->m[2] = v->m[2]; + m->m[3] = v->m[3]; +} + +static void SC_MatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { + float c, s; + m->m[3] = 0; + m->m[7] = 0; + m->m[11]= 0; + m->m[12]= 0; + m->m[13]= 0; + m->m[14]= 0; + m->m[15]= 1; + rot *= (float)(M_PI / 180.0f); + c = cos(rot); + s = sin(rot); + + const float len = x*x + y*y + z*z; + if (len != 1) { + const float recipLen = 1.f / sqrt(len); + x *= recipLen; + y *= recipLen; + z *= recipLen; + } + const float nc = 1.0f - c; + const float xy = x * y; + const float yz = y * z; + const float zx = z * x; + const float xs = x * s; + const float ys = y * s; + const float zs = z * s; + m->m[ 0] = x*x*nc + c; + m->m[ 4] = xy*nc - zs; + m->m[ 8] = zx*nc + ys; + m->m[ 1] = xy*nc + zs; + m->m[ 5] = y*y*nc + c; + m->m[ 9] = yz*nc - xs; + m->m[ 2] = zx*nc - ys; + m->m[ 6] = yz*nc + xs; + m->m[10] = z*z*nc + c; +} + +static void SC_MatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) { + SC_MatrixLoadIdentity_4x4(m); + m->m[0] = x; + m->m[5] = y; + m->m[10] = z; +} + +static void SC_MatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) { + SC_MatrixLoadIdentity_4x4(m); + m->m[12] = x; + m->m[13] = y; + m->m[14] = z; +} + +static void SC_MatrixLoadMultiply_4x4_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) { + for (int i=0 ; i<4 ; i++) { + float ri0 = 0; + float ri1 = 0; + float ri2 = 0; + float ri3 = 0; + for (int j=0 ; j<4 ; j++) { + const float rhs_ij = rsMatrixGet(rhs, i,j); + ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; + ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; + ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; + ri3 += rsMatrixGet(lhs, j, 3) * rhs_ij; + } + rsMatrixSet(m, i, 0, ri0); + rsMatrixSet(m, i, 1, ri1); + rsMatrixSet(m, i, 2, ri2); + rsMatrixSet(m, i, 3, ri3); + } +} + +static void SC_MatrixMultiply_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) { + rs_matrix4x4 mt; + SC_MatrixLoadMultiply_4x4_4x4_4x4(&mt, m, rhs); + SC_MatrixLoad_4x4_4x4(m, &mt); +} + +static void SC_MatrixLoadMultiply_3x3_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) { + for (int i=0 ; i<3 ; i++) { + float ri0 = 0; + float ri1 = 0; + float ri2 = 0; + for (int j=0 ; j<3 ; j++) { + const float rhs_ij = rsMatrixGet(rhs, i,j); + ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; + ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; + ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; + } + rsMatrixSet(m, i, 0, ri0); + rsMatrixSet(m, i, 1, ri1); + rsMatrixSet(m, i, 2, ri2); + } +} + +static void SC_MatrixMultiply_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) { + rs_matrix3x3 mt; + SC_MatrixLoadMultiply_3x3_3x3_3x3(&mt, m, rhs); + SC_MatrixLoad_3x3_3x3(m, &mt); +} + +static void SC_MatrixLoadMultiply_2x2_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) { + for (int i=0 ; i<2 ; i++) { + float ri0 = 0; + float ri1 = 0; + for (int j=0 ; j<2 ; j++) { + const float rhs_ij = rsMatrixGet(rhs, i,j); + ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; + ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; + } + rsMatrixSet(m, i, 0, ri0); + rsMatrixSet(m, i, 1, ri1); + } +} + +static void SC_MatrixMultiply_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) { + rs_matrix2x2 mt; + SC_MatrixLoadMultiply_2x2_2x2_2x2(&mt, m, rhs); + SC_MatrixLoad_2x2_2x2(m, &mt); +} + +static void SC_MatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { + rs_matrix4x4 m1; + SC_MatrixLoadRotate(&m1, rot, x, y, z); + SC_MatrixMultiply_4x4_4x4(m, &m1); +} + +static void SC_MatrixScale(rs_matrix4x4 *m, float x, float y, float z) { + rs_matrix4x4 m1; + SC_MatrixLoadScale(&m1, x, y, z); + SC_MatrixMultiply_4x4_4x4(m, &m1); +} + +static void SC_MatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) { + rs_matrix4x4 m1; + SC_MatrixLoadTranslate(&m1, x, y, z); + SC_MatrixMultiply_4x4_4x4(m, &m1); +} + +static void SC_MatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { + SC_MatrixLoadIdentity_4x4(m); + m->m[0] = 2.f / (right - left); + m->m[5] = 2.f / (top - bottom); + m->m[10]= -2.f / (far - near); + m->m[12]= -(right + left) / (right - left); + m->m[13]= -(top + bottom) / (top - bottom); + m->m[14]= -(far + near) / (far - near); +} + +static void SC_MatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { + SC_MatrixLoadIdentity_4x4(m); + m->m[0] = 2.f * near / (right - left); + m->m[5] = 2.f * near / (top - bottom); + m->m[8] = (right + left) / (right - left); + m->m[9] = (top + bottom) / (top - bottom); + m->m[10]= -(far + near) / (far - near); + m->m[11]= -1.f; + m->m[14]= -2.f * far * near / (far - near); + m->m[15]= 0.f; +} + +static void SC_MatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) { + float top = near * tan((float) (fovy * M_PI / 360.0f)); + float bottom = -top; + float left = bottom * aspect; + float right = top * aspect; + SC_MatrixLoadFrustum(m, left, right, bottom, top, near, far); +} + + +// Returns true if the matrix was successfully inversed +static bool SC_MatrixInverse_4x4(rs_matrix4x4 *m) { + rs_matrix4x4 result; + + int i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + // computeCofactor for int i, int j + int c0 = (i+1) % 4; + int c1 = (i+2) % 4; + int c2 = (i+3) % 4; + int r0 = (j+1) % 4; + int r1 = (j+2) % 4; + int r2 = (j+3) % 4; + + float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) + - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) + + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); + + float cofactor = (i+j) & 1 ? -minor : minor; + + result.m[4*i + j] = cofactor; + } + } + + // Dot product of 0th column of source and 0th row of result + float det = m->m[0]*result.m[0] + m->m[4]*result.m[1] + + m->m[8]*result.m[2] + m->m[12]*result.m[3]; + + if (fabs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (i = 0; i < 16; ++i) { + m->m[i] = result.m[i] * det; + } + + return true; +} + +// Returns true if the matrix was successfully inversed +static bool SC_MatrixInverseTranspose_4x4(rs_matrix4x4 *m) { + rs_matrix4x4 result; + + int i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + // computeCofactor for int i, int j + int c0 = (i+1) % 4; + int c1 = (i+2) % 4; + int c2 = (i+3) % 4; + int r0 = (j+1) % 4; + int r1 = (j+2) % 4; + int r2 = (j+3) % 4; + + float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) + - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) + + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); + + float cofactor = (i+j) & 1 ? -minor : minor; + + result.m[4*j + i] = cofactor; + } + } + + // Dot product of 0th column of source and 0th column of result + float det = m->m[0]*result.m[0] + m->m[4]*result.m[4] + + m->m[8]*result.m[8] + m->m[12]*result.m[12]; + + if (fabs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (i = 0; i < 16; ++i) { + m->m[i] = result.m[i] * det; + } + + return true; +} + +static void SC_MatrixTranspose_4x4(rs_matrix4x4 *m) { + int i, j; + float temp; + for (i = 0; i < 3; ++i) { + for (j = i + 1; j < 4; ++j) { + temp = m->m[i*4 + j]; + m->m[i*4 + j] = m->m[j*4 + i]; + m->m[j*4 + i] = temp; + } + } +} + +static void SC_MatrixTranspose_3x3(rs_matrix3x3 *m) { + int i, j; + float temp; + for (i = 0; i < 2; ++i) { + for (j = i + 1; j < 3; ++j) { + temp = m->m[i*3 + j]; + m->m[i*3 + j] = m->m[j*4 + i]; + m->m[j*3 + i] = temp; + } + } +} + +static void SC_MatrixTranspose_2x2(rs_matrix2x2 *m) { + float temp = m->m[1]; + m->m[1] = m->m[2]; + m->m[2] = temp; +} + + ////////////////////////////////////////////////////////////////////////////// // Class implementation ////////////////////////////////////////////////////////////////////////////// @@ -409,6 +854,10 @@ void SC_ForEach2(RsScript vs, static ScriptCState::SymbolTable_t gSyms[] = { { "__divsi3", (void *)&SC_divsi3, true }, { "__modsi3", (void *)&SC_modsi3, true }, + { "__udivsi3", (void *)&SC_udivsi3, true }, + { "__umodsi3", (void *)&SC_umodsi3, true }, + { "memset", (void *)&memset, true }, + { "memcpy", (void *)&memcpy, true }, // allocation { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true }, @@ -498,12 +947,8 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z6rsFracf", (void *)&SC_frac, true }, // time - { "_Z8rsSecondv", (void *)&SC_second, true }, - { "_Z8rsMinutev", (void *)&SC_minute, true }, - { "_Z6rsHourv", (void *)&SC_hour, true }, - { "_Z5rsDayv", (void *)&SC_day, true }, - { "_Z7rsMonthv", (void *)&SC_month, true }, - { "_Z6rsYearv", (void *)&SC_year, true }, + { "_Z6rsTimePi", (void *)&SC_time, true }, + { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true }, { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true }, { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true }, { "_Z7rsGetDtv", (void*)&SC_getDt, false }, @@ -513,6 +958,45 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false }, { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false }, + // matrix + { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, false }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, false }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, false }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, false }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, false }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, false }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, false }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, false }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, false }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, false }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, false }, + + { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, false }, + { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, false }, + { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, false }, + { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, false }, + { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, false }, + { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, false }, + + { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, false }, + { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, false }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, false }, + { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, false }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, false }, + { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, false }, + + { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, false }, + { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, false }, + { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, false }, + + { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, false }, + { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, false }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, false }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, false }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, false }, + { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false }, //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true }, diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp index 6c0e164f6894..57855db2cf20 100644 --- a/libs/rs/rsScriptC_LibCL.cpp +++ b/libs/rs/rsScriptC_LibCL.cpp @@ -24,26 +24,6 @@ using namespace android; using namespace android::renderscript; -static float SC_acospi(float v) { - return acosf(v)/ M_PI; -} - -static float SC_asinpi(float v) { - return asinf(v) / M_PI; -} - -static float SC_atanpi(float v) { - return atanf(v) / M_PI; -} - -static float SC_atan2pi(float y, float x) { - return atan2f(y, x) / M_PI; -} - -static float SC_cospi(float v) { - return cosf(v * M_PI); -} - static float SC_exp10(float v) { return pow(10.f, v); } @@ -58,6 +38,10 @@ static float SC_log2(float v) { return log10(v) / log10(2.f); } +static float SC_mad(float v1, float v2, float v3) { + return v1 * v2 + v3; +} + static float SC_pown(float v, int p) { return powf(v, (float)p); } @@ -79,14 +63,6 @@ float SC_sincos(float v, float *cosptr) { return sinf(v); } -static float SC_sinpi(float v) { - return sinf(v * M_PI); -} - -static float SC_tanpi(float v) { - return tanf(v * M_PI); -} - ////////////////////////////////////////////////////////////////////////////// // Integer ////////////////////////////////////////////////////////////////////////////// @@ -182,20 +158,16 @@ static ScriptCState::SymbolTable_t gSyms[] = { // OpenCL math { "_Z4acosf", (void *)&acosf, true }, { "_Z5acoshf", (void *)&acoshf, true }, - { "_Z6acospif", (void *)&SC_acospi, true }, { "_Z4asinf", (void *)&asinf, true }, { "_Z5asinhf", (void *)&asinhf, true }, - { "_Z6asinpif", (void *)&SC_asinpi, true }, { "_Z4atanf", (void *)&atanf, true }, { "_Z5atan2ff", (void *)&atan2f, true }, - { "_Z6atanpif", (void *)&SC_atanpi, true }, - { "_Z7atan2piff", (void *)&SC_atan2pi, true }, + { "_Z5atanhf", (void *)&atanhf, true }, { "_Z4cbrtf", (void *)&cbrtf, true }, { "_Z4ceilf", (void *)&ceilf, true }, { "_Z8copysignff", (void *)©signf, true }, { "_Z3cosf", (void *)&cosf, true }, { "_Z4coshf", (void *)&coshf, true }, - { "_Z5cospif", (void *)&SC_cospi, true }, { "_Z4erfcf", (void *)&erfcf, true }, { "_Z3erff", (void *)&erff, true }, { "_Z3expf", (void *)&expf, true }, @@ -215,33 +187,30 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z5ilogbf", (void *)&ilogbf, true }, { "_Z5ldexpfi", (void *)&ldexpf, true }, { "_Z6lgammaf", (void *)&lgammaf, true }, + { "_Z6lgammafPi", (void *)&lgammaf_r, true }, { "_Z3logf", (void *)&logf, true }, { "_Z4log2f", (void *)&SC_log2, true }, { "_Z5log10f", (void *)&log10f, true }, { "_Z5log1pf", (void *)&log1pf, true }, - //{ "logb", (void *)&, true }, - //{ "mad", (void *)&, true }, - { "modf", (void *)&modff, true }, - //{ "nan", (void *)&, true }, + { "_Z4logbf", (void *)&logbf, true }, + { "_Z3madfff", (void *)&SC_mad, true }, + { "_Z4modffPf", (void *)&modff, true }, + //{ "_Z3nanj", (void *)&SC_nan, true }, { "_Z9nextafterff", (void *)&nextafterf, true }, { "_Z3powff", (void *)&powf, true }, - { "_Z4pownfi", (void *)&SC_pown, true }, - { "_Z4powrff", (void *)&SC_powr, true }, { "_Z9remainderff", (void *)&remainderf, true }, - { "remquo", (void *)&remquof, true }, + { "_Z6remquoffPi", (void *)&remquof, true }, { "_Z4rintf", (void *)&rintf, true }, { "_Z5rootnfi", (void *)&SC_rootn, true }, { "_Z5roundf", (void *)&roundf, true }, { "_Z5rsqrtf", (void *)&SC_rsqrt, true }, { "_Z3sinf", (void *)&sinf, true }, - { "sincos", (void *)&SC_sincos, true }, + { "_Z6sincosfPf", (void *)&SC_sincos, true }, { "_Z4sinhf", (void *)&sinhf, true }, - { "_Z5sinpif", (void *)&SC_sinpi, true }, { "_Z4sqrtf", (void *)&sqrtf, true }, { "_Z3tanf", (void *)&tanf, true }, { "_Z4tanhf", (void *)&tanhf, true }, - { "_Z5tanpif", (void *)&SC_tanpi, true }, - //{ "tgamma", (void *)&, true }, + { "_Z6tgammaf", (void *)&tgammaf, true }, { "_Z5truncf", (void *)&truncf, true }, // OpenCL Int diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index fb5980affa27..48a0969f06f7 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -287,24 +287,6 @@ static void SC_allocationSyncAll2(RsAllocation va, RsAllocationUsageType source) static_cast<Allocation *>(va)->syncAll(rsc, source); } -static void SC_uploadToTexture2(RsAllocation va, uint32_t baseMipLevel) { - CHECK_OBJ(va); - GET_TLS(); - rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel); -} - -static void SC_uploadToTexture(RsAllocation va) { - CHECK_OBJ(va); - GET_TLS(); - rsi_AllocationUploadToTexture(rsc, va, false, 0); -} - -static void SC_uploadToBufferObject(RsAllocation va) { - CHECK_OBJ(va); - GET_TLS(); - rsi_AllocationUploadToBufferObject(rsc, va); -} - static void SC_ClearColor(float r, float g, float b, float a) { GET_TLS(); rsc->setupProgramStore(); @@ -439,10 +421,6 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z20rsgAllocationSyncAll13rs_allocation", (void *)&SC_allocationSyncAll, false }, - { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2, false }, - { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture, false }, - { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject, false }, - { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect, false }, { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad, false }, { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords, false }, diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp index 45384c98f247..e8d89c21cb77 100644 --- a/libs/rs/rsShaderCache.cpp +++ b/libs/rs/rsShaderCache.cpp @@ -14,14 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES2/gl2.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#endif //ANDROID_RS_BUILD_FOR_HOST +#endif //ANDROID_RS_SERIALIZE using namespace android; using namespace android::renderscript; @@ -32,10 +29,7 @@ ShaderCache::ShaderCache() { } ShaderCache::~ShaderCache() { - for (uint32_t ct=0; ct < mEntries.size(); ct++) { - glDeleteProgram(mEntries[ct]->program); - free(mEntries[ct]); - } + cleanupAll(); } void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID, @@ -251,5 +245,10 @@ void ShaderCache::cleanupFragment(uint32_t id) { } void ShaderCache::cleanupAll() { + for (uint32_t ct=0; ct < mEntries.size(); ct++) { + glDeleteProgram(mEntries[ct]->program); + free(mEntries[ct]); + } + mEntries.clear(); } diff --git a/libs/rs/rsStream.cpp b/libs/rs/rsStream.cpp index 49ed567dceca..b9df0ccfac6a 100644 --- a/libs/rs/rsStream.cpp +++ b/libs/rs/rsStream.cpp @@ -15,12 +15,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#else -#include "rsContextHostStub.h" -#endif - #include "rsStream.h" using namespace android; diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 1c6c5ac426bb..6cf07de7920b 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -53,6 +53,11 @@ bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) { waitForCommand = false; //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize); + if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) { + rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *))); + LOGE("playCoreCommands error con %p, cmd %i", con, cmdID); + mToCore.printDebugData(); + } gPlaybackFuncs[cmdID](con, data); mToCore.next(); } diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp index 670ea33a111f..cd2be94979a8 100644 --- a/libs/rs/rsType.cpp +++ b/libs/rs/rsType.cpp @@ -14,13 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include <GLES/gl.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> -#endif using namespace android; using namespace android::renderscript; @@ -132,10 +126,21 @@ uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) co return offset; } +uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const { + uint32_t offset = mLODs[lod].mOffset; + offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes(); + + if (face != 0) { + uint32_t faceOffset = getSizeBytes() / 6; + offset += faceOffset * face; + } + return offset; +} + void Type::dumpLOGV(const char *prefix) const { char buf[1024]; ObjectBase::dumpLOGV(prefix); - LOGV("%s Type: x=%i y=%i z=%i mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces); + LOGV("%s Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces); snprintf(buf, sizeof(buf), "%s element: ", prefix); mElement->dumpLOGV(buf); } diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h index 34498f076464..90ae039da3e3 100644 --- a/libs/rs/rsType.h +++ b/libs/rs/rsType.h @@ -44,12 +44,14 @@ public: uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;} uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;} uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;} - uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;} + uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;} uint32_t getLODOffset(uint32_t lod, uint32_t x) const; uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const; uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const; + uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const; + uint32_t getLODCount() const {return mLODCount;} bool getIsNp2() const; diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h index 0699b57fa7fb..3b60af58fb4d 100644 --- a/libs/rs/rsUtils.h +++ b/libs/rs/rsUtils.h @@ -32,7 +32,7 @@ #include <time.h> #include <cutils/atomic.h> -#ifndef ANDROID_RS_BUILD_FOR_HOST +#ifndef ANDROID_RS_SERIALIZE #include <EGL/egl.h> #endif diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp index d9393fe303af..354ee89f7c5b 100644 --- a/libs/rs/rsVertexArray.cpp +++ b/libs/rs/rsVertexArray.cpp @@ -14,13 +14,10 @@ * limitations under the License. */ -#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> #include <GLES2/gl2.h> -#else -#include "rsContextHostStub.h" -#include <OpenGL/gl.h> #endif using namespace android; diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 1e468bb985e4..4ac5b7fce136 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -219,7 +219,7 @@ void printPlaybackCpp(FILE *f) { fprintf(f, "};\n\n"); } - fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n"); + fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1); fprintf(f, " NULL,\n"); for (ct=0; ct < apiCount; ct++) { fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); @@ -265,7 +265,7 @@ int main(int argc, char **argv) { printFuncDecls(f, "rsi_", 1); printPlaybackFuncs(f, "rsp_"); fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n"); - fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n"); + fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[%i];\n", apiCount + 1); fprintf(f, "}\n"); fprintf(f, "}\n"); diff --git a/libs/rs/rslib.bc b/libs/rs/rslib.bc Binary files differdeleted file mode 100644 index 1897c3ba37bc..000000000000 --- a/libs/rs/rslib.bc +++ /dev/null diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh index 64844a488ead..d78e62e1d54a 100644 --- a/libs/rs/scriptc/rs_cl.rsh +++ b/libs/rs/scriptc/rs_cl.rsh @@ -1,31 +1,25 @@ #ifndef __RS_CL_RSH__ #define __RS_CL_RSH__ -#define M_PI 3.14159265358979323846264338327950288f /* pi */ - +#define _RS_RUNTIME extern // Conversions -#define CVT_FUNC_2(typeout, typein) \ -static typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \ - typeout##2 r = {(typeout)v.x, (typeout)v.y}; \ - return r; \ -} \ -static typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \ - typeout##3 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z}; \ - return r; \ -} \ -static typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \ - typeout##4 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z, (typeout)v.w}; \ - return r; \ -} - -#define CVT_FUNC(type) CVT_FUNC_2(type, uchar) \ - CVT_FUNC_2(type, char) \ - CVT_FUNC_2(type, ushort) \ - CVT_FUNC_2(type, short) \ - CVT_FUNC_2(type, int) \ - CVT_FUNC_2(type, uint) \ - CVT_FUNC_2(type, float) +#define CVT_FUNC_2(typeout, typein) \ +_RS_RUNTIME typeout##2 __attribute__((overloadable)) \ + convert_##typeout##2(typein##2 v); \ +_RS_RUNTIME typeout##3 __attribute__((overloadable)) \ + convert_##typeout##3(typein##3 v); \ +_RS_RUNTIME typeout##4 __attribute__((overloadable)) \ + convert_##typeout##4(typein##4 v); + + +#define CVT_FUNC(type) CVT_FUNC_2(type, uchar) \ + CVT_FUNC_2(type, char) \ + CVT_FUNC_2(type, ushort) \ + CVT_FUNC_2(type, short) \ + CVT_FUNC_2(type, uint) \ + CVT_FUNC_2(type, int) \ + CVT_FUNC_2(type, float) CVT_FUNC(char) CVT_FUNC(uchar) @@ -35,666 +29,367 @@ CVT_FUNC(int) CVT_FUNC(uint) CVT_FUNC(float) - - // Float ops, 6.11.2 -#define DEF_FUNC_1(fnc) \ -static float2 __attribute__((overloadable)) fnc(float2 v) { \ - float2 r; \ - r.x = fnc(v.x); \ - r.y = fnc(v.y); \ - return r; \ -} \ -static float3 __attribute__((overloadable)) fnc(float3 v) { \ - float3 r; \ - r.x = fnc(v.x); \ - r.y = fnc(v.y); \ - r.z = fnc(v.z); \ - return r; \ -} \ -static float4 __attribute__((overloadable)) fnc(float4 v) { \ - float4 r; \ - r.x = fnc(v.x); \ - r.y = fnc(v.y); \ - r.z = fnc(v.z); \ - r.w = fnc(v.w); \ - return r; \ -} - -#define DEF_FUNC_2(fnc) \ -static float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \ - float2 r; \ - r.x = fnc(v1.x, v2.x); \ - r.y = fnc(v1.y, v2.y); \ - return r; \ -} \ -static float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \ - float3 r; \ - r.x = fnc(v1.x, v2.x); \ - r.y = fnc(v1.y, v2.y); \ - r.z = fnc(v1.z, v2.z); \ - return r; \ -} \ -static float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \ - float4 r; \ - r.x = fnc(v1.x, v2.x); \ - r.y = fnc(v1.y, v2.y); \ - r.z = fnc(v1.z, v2.z); \ - r.w = fnc(v1.w, v2.z); \ - return r; \ -} - -#define DEF_FUNC_2F(fnc) \ -static float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \ - float2 r; \ - r.x = fnc(v1.x, v2); \ - r.y = fnc(v1.y, v2); \ - return r; \ -} \ -static float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \ - float3 r; \ - r.x = fnc(v1.x, v2); \ - r.y = fnc(v1.y, v2); \ - r.z = fnc(v1.z, v2); \ - return r; \ -} \ -static float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \ - float4 r; \ - r.x = fnc(v1.x, v2); \ - r.y = fnc(v1.y, v2); \ - r.z = fnc(v1.z, v2); \ - r.w = fnc(v1.w, v2); \ - return r; \ -} +#define FN_FUNC_FN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v); + +#define IN_FUNC_FN(fnc) \ +_RS_RUNTIME int2 __attribute__((overloadable)) fnc(float2 v); \ +_RS_RUNTIME int3 __attribute__((overloadable)) fnc(float3 v); \ +_RS_RUNTIME int4 __attribute__((overloadable)) fnc(float4 v); + +#define FN_FUNC_FN_FN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2); + +#define FN_FUNC_FN_F(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v1, float v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v1, float v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v1, float v2); + +#define FN_FUNC_FN_IN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v1, int2 v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v1, int3 v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v1, int4 v2); \ + +#define FN_FUNC_FN_I(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v1, int v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v1, int v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v1, int v2); + +#define FN_FUNC_FN_PFN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) \ + fnc(float2 v1, float2 *v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) \ + fnc(float3 v1, float3 *v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) \ + fnc(float4 v1, float4 *v2); + +#define FN_FUNC_FN_PIN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) fnc(float2 v1, int2 *v2); \ +_RS_RUNTIME float3 __attribute__((overloadable)) fnc(float3 v1, int3 *v2); \ +_RS_RUNTIME float4 __attribute__((overloadable)) fnc(float4 v1, int4 *v2); + +#define FN_FUNC_FN_FN_FN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) \ + fnc(float2 v1, float2 v2, float2 v3); \ +_RS_RUNTIME float3 __attribute__((overloadable)) \ + fnc(float3 v1, float3 v2, float3 v3); \ +_RS_RUNTIME float4 __attribute__((overloadable)) \ + fnc(float4 v1, float4 v2, float4 v3); + +#define FN_FUNC_FN_FN_PIN(fnc) \ +_RS_RUNTIME float2 __attribute__((overloadable)) \ + fnc(float2 v1, float2 v2, int2 *v3); \ +_RS_RUNTIME float3 __attribute__((overloadable)) \ + fnc(float3 v1, float3 v2, int3 *v3); \ +_RS_RUNTIME float4 __attribute__((overloadable)) \ + fnc(float4 v1, float4 v2, int4 *v3); extern float __attribute__((overloadable)) acos(float); -DEF_FUNC_1(acos) +FN_FUNC_FN(acos) extern float __attribute__((overloadable)) acosh(float); -DEF_FUNC_1(acosh) +FN_FUNC_FN(acosh) + +_RS_RUNTIME float __attribute__((overloadable)) acospi(float v); -static float __attribute__((overloadable)) acospi(float v) { - return acos(v) / M_PI; -} -DEF_FUNC_1(acospi) + +FN_FUNC_FN(acospi) extern float __attribute__((overloadable)) asin(float); -DEF_FUNC_1(asin) +FN_FUNC_FN(asin) extern float __attribute__((overloadable)) asinh(float); -DEF_FUNC_1(asinh) +FN_FUNC_FN(asinh) + -static float __attribute__((overloadable)) asinpi(float v) { - return asin(v) / M_PI; -} -DEF_FUNC_1(asinpi) +_RS_RUNTIME float __attribute__((overloadable)) asinpi(float v); +FN_FUNC_FN(asinpi) extern float __attribute__((overloadable)) atan(float); -DEF_FUNC_1(atan) +FN_FUNC_FN(atan) extern float __attribute__((overloadable)) atan2(float, float); -DEF_FUNC_2(atan2) +FN_FUNC_FN_FN(atan2) extern float __attribute__((overloadable)) atanh(float); -DEF_FUNC_1(atanh) +FN_FUNC_FN(atanh) + -static float __attribute__((overloadable)) atanpi(float v) { - return atan(v) / M_PI; -} -DEF_FUNC_1(atanpi) +_RS_RUNTIME float __attribute__((overloadable)) atanpi(float v); +FN_FUNC_FN(atanpi) -static float __attribute__((overloadable)) atan2pi(float y, float x) { - return atan2(y, x) / M_PI; -} -DEF_FUNC_2(atan2pi) + +_RS_RUNTIME float __attribute__((overloadable)) atan2pi(float y, float x); +FN_FUNC_FN_FN(atan2pi) extern float __attribute__((overloadable)) cbrt(float); -DEF_FUNC_1(cbrt) +FN_FUNC_FN(cbrt) extern float __attribute__((overloadable)) ceil(float); -DEF_FUNC_1(ceil) +FN_FUNC_FN(ceil) extern float __attribute__((overloadable)) copysign(float, float); -DEF_FUNC_2(copysign) +FN_FUNC_FN_FN(copysign) extern float __attribute__((overloadable)) cos(float); -DEF_FUNC_1(cos) +FN_FUNC_FN(cos) extern float __attribute__((overloadable)) cosh(float); -DEF_FUNC_1(cosh) +FN_FUNC_FN(cosh) + -static float __attribute__((overloadable)) cospi(float v) { - return cos(v * M_PI); -} -DEF_FUNC_1(cospi) +_RS_RUNTIME float __attribute__((overloadable)) cospi(float v); +FN_FUNC_FN(cospi) extern float __attribute__((overloadable)) erfc(float); -DEF_FUNC_1(erfc) +FN_FUNC_FN(erfc) extern float __attribute__((overloadable)) erf(float); -DEF_FUNC_1(erf) +FN_FUNC_FN(erf) extern float __attribute__((overloadable)) exp(float); -DEF_FUNC_1(exp) +FN_FUNC_FN(exp) extern float __attribute__((overloadable)) exp2(float); -DEF_FUNC_1(exp2) +FN_FUNC_FN(exp2) extern float __attribute__((overloadable)) pow(float, float); -static float __attribute__((overloadable)) exp10(float v) { - return pow(10.f, v); -} -DEF_FUNC_1(exp10) + +_RS_RUNTIME float __attribute__((overloadable)) exp10(float v); +FN_FUNC_FN(exp10) extern float __attribute__((overloadable)) expm1(float); -DEF_FUNC_1(expm1) +FN_FUNC_FN(expm1) extern float __attribute__((overloadable)) fabs(float); -DEF_FUNC_1(fabs) +FN_FUNC_FN(fabs) extern float __attribute__((overloadable)) fdim(float, float); -DEF_FUNC_2(fdim) +FN_FUNC_FN_FN(fdim) extern float __attribute__((overloadable)) floor(float); -DEF_FUNC_1(floor) +FN_FUNC_FN(floor) extern float __attribute__((overloadable)) fma(float, float, float); -extern float2 __attribute__((overloadable)) fma(float2, float2, float2); -extern float3 __attribute__((overloadable)) fma(float3, float3, float3); -extern float4 __attribute__((overloadable)) fma(float4, float4, float4); +FN_FUNC_FN_FN_FN(fma) extern float __attribute__((overloadable)) fmax(float, float); -DEF_FUNC_2(fmax); -DEF_FUNC_2F(fmax); +FN_FUNC_FN_FN(fmax); +FN_FUNC_FN_F(fmax); extern float __attribute__((overloadable)) fmin(float, float); -DEF_FUNC_2(fmin); -DEF_FUNC_2F(fmin); +FN_FUNC_FN_FN(fmin); +FN_FUNC_FN_F(fmin); extern float __attribute__((overloadable)) fmod(float, float); -DEF_FUNC_2(fmod) - -static float __attribute__((overloadable)) fract(float v, float *iptr) { - int i = (int)floor(v); - iptr[0] = i; - return fmin(v - i, 0x1.fffffep-1f); -} -static float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) { - float t[2]; - float2 r; - r.x = fract(v.x, &t[0]); - r.y = fract(v.y, &t[1]); - iptr[0] = t[0]; - iptr[1] = t[1]; - return r; -} -static float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) { - float t[3]; - float3 r; - r.x = fract(v.x, &t[0]); - r.y = fract(v.y, &t[1]); - r.z = fract(v.z, &t[2]); - iptr[0] = t[0]; - iptr[1] = t[1]; - iptr[2] = t[2]; - return r; -} -static float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) { - float t[4]; - float4 r; - r.x = fract(v.x, &t[0]); - r.y = fract(v.y, &t[1]); - r.z = fract(v.z, &t[2]); - r.w = fract(v.w, &t[3]); - iptr[0] = t[0]; - iptr[1] = t[1]; - iptr[2] = t[2]; - iptr[3] = t[3]; - return r; -} - -extern float __attribute__((overloadable)) frexp(float, float *); -extern float2 __attribute__((overloadable)) frexp(float2, float2 *); -extern float3 __attribute__((overloadable)) frexp(float3, float3 *); -extern float4 __attribute__((overloadable)) frexp(float4, float4 *); +FN_FUNC_FN_FN(fmod) + + +_RS_RUNTIME float __attribute__((overloadable)) fract(float v, float *iptr); +FN_FUNC_FN_PFN(fract) + +extern float __attribute__((overloadable)) frexp(float, int *); +FN_FUNC_FN_PIN(frexp) extern float __attribute__((overloadable)) hypot(float, float); -DEF_FUNC_2(hypot) +FN_FUNC_FN_FN(hypot) extern int __attribute__((overloadable)) ilogb(float); -DEF_FUNC_1(ilogb) +IN_FUNC_FN(ilogb) extern float __attribute__((overloadable)) ldexp(float, int); -extern float2 __attribute__((overloadable)) ldexp(float2, int2); -extern float3 __attribute__((overloadable)) ldexp(float3, int3); -extern float4 __attribute__((overloadable)) ldexp(float4, int4); -extern float2 __attribute__((overloadable)) ldexp(float2, int); -extern float3 __attribute__((overloadable)) ldexp(float3, int); -extern float4 __attribute__((overloadable)) ldexp(float4, int); +FN_FUNC_FN_IN(ldexp) +FN_FUNC_FN_I(ldexp) extern float __attribute__((overloadable)) lgamma(float); -DEF_FUNC_1(lgamma) -extern float __attribute__((overloadable)) lgamma(float, float *); -extern float2 __attribute__((overloadable)) lgamma(float2, float2 *); -extern float3 __attribute__((overloadable)) lgamma(float3, float3 *); -extern float4 __attribute__((overloadable)) lgamma(float4, float4 *); +FN_FUNC_FN(lgamma) +extern float __attribute__((overloadable)) lgamma(float, int*); +FN_FUNC_FN_PIN(lgamma) extern float __attribute__((overloadable)) log(float); -DEF_FUNC_1(log) +FN_FUNC_FN(log) extern float __attribute__((overloadable)) log10(float); -DEF_FUNC_1(log10) +FN_FUNC_FN(log10) -static float __attribute__((overloadable)) log2(float v) { - return log10(v) / log10(2.f); -} -DEF_FUNC_1(log2) + +_RS_RUNTIME float __attribute__((overloadable)) log2(float v); +FN_FUNC_FN(log2) extern float __attribute__((overloadable)) log1p(float); -DEF_FUNC_1(log1p) +FN_FUNC_FN(log1p) extern float __attribute__((overloadable)) logb(float); -DEF_FUNC_1(logb) +FN_FUNC_FN(logb) extern float __attribute__((overloadable)) mad(float, float, float); -extern float2 __attribute__((overloadable)) mad(float2, float2, float2); -extern float3 __attribute__((overloadable)) mad(float3, float3, float3); -extern float4 __attribute__((overloadable)) mad(float4, float4, float4); +FN_FUNC_FN_FN_FN(mad) extern float __attribute__((overloadable)) modf(float, float *); -extern float2 __attribute__((overloadable)) modf(float2, float2 *); -extern float3 __attribute__((overloadable)) modf(float3, float3 *); -extern float4 __attribute__((overloadable)) modf(float4, float4 *); +FN_FUNC_FN_PFN(modf); //extern float __attribute__((overloadable)) nan(uint); extern float __attribute__((overloadable)) nextafter(float, float); -DEF_FUNC_2(nextafter) - -DEF_FUNC_2(pow) - -static float __attribute__((overloadable)) pown(float v, int p) { - return pow(v, (float)p); -} -static float2 __attribute__((overloadable)) pown(float2 v, int2 p) { - return pow(v, (float2)p); -} -static float3 __attribute__((overloadable)) pown(float3 v, int3 p) { - return pow(v, (float3)p); -} -static float4 __attribute__((overloadable)) pown(float4 v, int4 p) { - return pow(v, (float4)p); -} - -static float __attribute__((overloadable)) powr(float v, float p) { - return pow(v, p); -} -static float2 __attribute__((overloadable)) powr(float2 v, float2 p) { - return pow(v, p); -} -static float3 __attribute__((overloadable)) powr(float3 v, float3 p) { - return pow(v, p); -} -static float4 __attribute__((overloadable)) powr(float4 v, float4 p) { - return pow(v, p); -} +FN_FUNC_FN_FN(nextafter) + +FN_FUNC_FN_FN(pow) + +_RS_RUNTIME float __attribute__((overloadable)) pown(float v, int p); +_RS_RUNTIME float2 __attribute__((overloadable)) pown(float2 v, int2 p); +_RS_RUNTIME float3 __attribute__((overloadable)) pown(float3 v, int3 p); +_RS_RUNTIME float4 __attribute__((overloadable)) pown(float4 v, int4 p); + +_RS_RUNTIME float __attribute__((overloadable)) powr(float v, float p); +_RS_RUNTIME float2 __attribute__((overloadable)) powr(float2 v, float2 p); +_RS_RUNTIME float3 __attribute__((overloadable)) powr(float3 v, float3 p); +_RS_RUNTIME float4 __attribute__((overloadable)) powr(float4 v, float4 p); extern float __attribute__((overloadable)) remainder(float, float); -DEF_FUNC_2(remainder) +FN_FUNC_FN_FN(remainder) -extern float __attribute__((overloadable)) remquo(float, float, float *); -extern float2 __attribute__((overloadable)) remquo(float2, float2, float2 *); -extern float3 __attribute__((overloadable)) remquo(float3, float3, float3 *); -extern float4 __attribute__((overloadable)) remquo(float4, float4, float4 *); +extern float __attribute__((overloadable)) remquo(float, float, int *); +FN_FUNC_FN_FN_PIN(remquo) extern float __attribute__((overloadable)) rint(float); -DEF_FUNC_1(rint) - -static float __attribute__((overloadable)) rootn(float v, int r) { - return pow(v, 1.f / r); -} -static float2 __attribute__((overloadable)) rootn(float2 v, int2 r) { - float2 t = {1.f / r.x, 1.f / r.y}; - return pow(v, t); -} -static float3 __attribute__((overloadable)) rootn(float3 v, int3 r) { - float3 t = {1.f / r.x, 1.f / r.y, 1.f / r.z}; - return pow(v, t); -} -static float4 __attribute__((overloadable)) rootn(float4 v, int4 r) { - float4 t = {1.f / r.x, 1.f / r.y, 1.f / r.z, 1.f / r.w}; - return pow(v, t); -} +FN_FUNC_FN(rint) + + +_RS_RUNTIME float __attribute__((overloadable)) rootn(float v, int r); +_RS_RUNTIME float2 __attribute__((overloadable)) rootn(float2 v, int2 r); +_RS_RUNTIME float3 __attribute__((overloadable)) rootn(float3 v, int3 r); +_RS_RUNTIME float4 __attribute__((overloadable)) rootn(float4 v, int4 r); + extern float __attribute__((overloadable)) round(float); -DEF_FUNC_1(round) +FN_FUNC_FN(round) + extern float __attribute__((overloadable)) sqrt(float); -/*static float __attribute__((overloadable)) rsqrt(float v) { - return 1.f / sqrt(v); -} -DEF_FUNC_1(rsqrt)*/ +_RS_RUNTIME float __attribute__((overloadable)) rsqrt(float v); +FN_FUNC_FN(rsqrt) extern float __attribute__((overloadable)) sin(float); -DEF_FUNC_1(sin) - -static float __attribute__((overloadable)) sincos(float v, float *cosptr) { - *cosptr = cos(v); - return sin(v); -} -static float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) { - *cosptr = cos(v); - return sin(v); -} -static float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) { - *cosptr = cos(v); - return sin(v); -} -static float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) { - *cosptr = cos(v); - return sin(v); -} +FN_FUNC_FN(sin) + +_RS_RUNTIME float __attribute__((overloadable)) sincos(float v, float *cosptr); +_RS_RUNTIME float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr); +_RS_RUNTIME float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr); +_RS_RUNTIME float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr); extern float __attribute__((overloadable)) sinh(float); -DEF_FUNC_1(sinh) +FN_FUNC_FN(sinh) -static float __attribute__((overloadable)) sinpi(float v) { - return sin(v * M_PI); -} -DEF_FUNC_1(sinpi) +_RS_RUNTIME float __attribute__((overloadable)) sinpi(float v); +FN_FUNC_FN(sinpi) -DEF_FUNC_1(sqrt) +FN_FUNC_FN(sqrt) extern float __attribute__((overloadable)) tan(float); -DEF_FUNC_1(tan) +FN_FUNC_FN(tan) extern float __attribute__((overloadable)) tanh(float); -DEF_FUNC_1(tanh) +FN_FUNC_FN(tanh) + +_RS_RUNTIME float __attribute__((overloadable)) tanpi(float v); +FN_FUNC_FN(tanpi) -static float __attribute__((overloadable)) tanpi(float v) { - return tan(v * M_PI); -} -DEF_FUNC_1(tanpi) extern float __attribute__((overloadable)) tgamma(float); -DEF_FUNC_1(tgamma) +FN_FUNC_FN(tgamma) extern float __attribute__((overloadable)) trunc(float); -DEF_FUNC_1(trunc) +FN_FUNC_FN(trunc) // Int ops (partial), 6.11.3 -extern uint __attribute__((overloadable)) abs(int); -extern ushort __attribute__((overloadable)) abs(short); -extern uchar __attribute__((overloadable)) abs(char); - -extern uint __attribute__((overloadable)) clz(uint); -extern int __attribute__((overloadable)) clz(int); -extern ushort __attribute__((overloadable)) clz(ushort); -extern short __attribute__((overloadable)) clz(short); -extern uchar __attribute__((overloadable)) clz(uchar); -extern char __attribute__((overloadable)) clz(char); - -static uint __attribute__((overloadable)) min(uint v1, uint v2) { - return v1 < v2 ? v1 : v2; -} -static int __attribute__((overloadable)) min(int v1, int v2) { - return v1 < v2 ? v1 : v2; -} -static ushort __attribute__((overloadable)) min(ushort v1, ushort v2) { - return v1 < v2 ? v1 : v2; -} -static short __attribute__((overloadable)) min(short v1, short v2) { - return v1 < v2 ? v1 : v2; -} -static uchar __attribute__((overloadable)) min(uchar v1, uchar v2) { - return v1 < v2 ? v1 : v2; -} -static char __attribute__((overloadable)) min(char v1, char v2) { - return v1 < v2 ? v1 : v2; -} - -static uint __attribute__((overloadable)) max(uint v1, uint v2) { - return v1 > v2 ? v1 : v2; -} -static int __attribute__((overloadable)) max(int v1, int v2) { - return v1 > v2 ? v1 : v2; -} -static ushort __attribute__((overloadable)) max(ushort v1, ushort v2) { - return v1 > v2 ? v1 : v2; -} -static short __attribute__((overloadable)) max(short v1, short v2) { - return v1 > v2 ? v1 : v2; -} -static uchar __attribute__((overloadable)) max(uchar v1, uchar v2) { - return v1 > v2 ? v1 : v2; -} -static char __attribute__((overloadable)) max(char v1, char v2) { - return v1 > v2 ? v1 : v2; -} - - +#define XN_FUNC_YN(typeout, fnc, typein) \ +extern typeout __attribute__((overloadable)) fnc(typein); \ +_RS_RUNTIME typeout##2 __attribute__((overloadable)) fnc(typein##2 v); \ +_RS_RUNTIME typeout##3 __attribute__((overloadable)) fnc(typein##3 v); \ +_RS_RUNTIME typeout##4 __attribute__((overloadable)) fnc(typein##4 v); + +#define UIN_FUNC_IN(fnc) \ +XN_FUNC_YN(uchar, fnc, char) \ +XN_FUNC_YN(ushort, fnc, short) \ +XN_FUNC_YN(uint, fnc, int) + +#define IN_FUNC_IN(fnc) \ +XN_FUNC_YN(uchar, fnc, uchar) \ +XN_FUNC_YN(char, fnc, char) \ +XN_FUNC_YN(ushort, fnc, ushort) \ +XN_FUNC_YN(short, fnc, short) \ +XN_FUNC_YN(uint, fnc, uint) \ +XN_FUNC_YN(int, fnc, int) + + +#define XN_FUNC_XN_XN_BODY(type, fnc, body) \ +_RS_RUNTIME type __attribute__((overloadable)) \ + fnc(type v1, type v2); \ +_RS_RUNTIME type##2 __attribute__((overloadable)) \ + fnc(type##2 v1, type##2 v2); \ +_RS_RUNTIME type##3 __attribute__((overloadable)) \ + fnc(type##3 v1, type##3 v2); \ +_RS_RUNTIME type##4 __attribute__((overloadable)) \ + fnc(type##4 v1, type##4 v2); + +#define IN_FUNC_IN_IN_BODY(fnc, body) \ +XN_FUNC_XN_XN_BODY(uchar, fnc, body) \ +XN_FUNC_XN_XN_BODY(char, fnc, body) \ +XN_FUNC_XN_XN_BODY(ushort, fnc, body) \ +XN_FUNC_XN_XN_BODY(short, fnc, body) \ +XN_FUNC_XN_XN_BODY(uint, fnc, body) \ +XN_FUNC_XN_XN_BODY(int, fnc, body) \ +XN_FUNC_XN_XN_BODY(float, fnc, body) + +UIN_FUNC_IN(abs) +IN_FUNC_IN(clz) + +IN_FUNC_IN_IN_BODY(min, (v1 < v2 ? v1 : v2)) +FN_FUNC_FN_F(min) + +IN_FUNC_IN_IN_BODY(max, (v1 > v2 ? v1 : v2)) +FN_FUNC_FN_F(max) // 6.11.4 -static float __attribute__((overloadable)) clamp(float amount, float low, float high) { - return amount < low ? low : (amount > high ? high : amount); -} -static float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) { - float2 r; - r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); - r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); - return r; -} -static float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) { - float3 r; - r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); - r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); - r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z); - return r; -} -static float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) { - float4 r; - r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); - r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); - r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z); - r.w = amount.w < low.w ? low.w : (amount.w > high.w ? high.w : amount.w); - return r; -} -static float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) { - float2 r; - r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); - r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); - return r; -} -static float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) { - float3 r; - r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); - r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); - r.z = amount.z < low ? low : (amount.z > high ? high : amount.z); - return r; -} -static float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) { - float4 r; - r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); - r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); - r.z = amount.z < low ? low : (amount.z > high ? high : amount.z); - r.w = amount.w < low ? low : (amount.w > high ? high : amount.w); - return r; -} - -static float __attribute__((overloadable)) degrees(float radians) { - return radians * (180.f / M_PI); -} -DEF_FUNC_1(degrees) - -static float __attribute__((overloadable)) max(float v1, float v2) { - return v1 > v2 ? v1 : v2; -} -static float2 __attribute__((overloadable)) max(float2 v1, float2 v2) { - float2 r; - r.x = v1.x > v2.x ? v1.x : v2.x; - r.y = v1.y > v2.y ? v1.y : v2.y; - return r; -} -static float3 __attribute__((overloadable)) max(float3 v1, float3 v2) { - float3 r; - r.x = v1.x > v2.x ? v1.x : v2.x; - r.y = v1.y > v2.y ? v1.y : v2.y; - r.z = v1.z > v2.z ? v1.z : v2.z; - return r; -} -static float4 __attribute__((overloadable)) max(float4 v1, float4 v2) { - float4 r; - r.x = v1.x > v2.x ? v1.x : v2.x; - r.y = v1.y > v2.y ? v1.y : v2.y; - r.z = v1.z > v2.z ? v1.z : v2.z; - r.w = v1.w > v2.w ? v1.w : v2.w; - return r; -} -static float2 __attribute__((overloadable)) max(float2 v1, float v2) { - float2 r; - r.x = v1.x > v2 ? v1.x : v2; - r.y = v1.y > v2 ? v1.y : v2; - return r; -} -static float3 __attribute__((overloadable)) max(float3 v1, float v2) { - float3 r; - r.x = v1.x > v2 ? v1.x : v2; - r.y = v1.y > v2 ? v1.y : v2; - r.z = v1.z > v2 ? v1.z : v2; - return r; -} -static float4 __attribute__((overloadable)) max(float4 v1, float v2) { - float4 r; - r.x = v1.x > v2 ? v1.x : v2; - r.y = v1.y > v2 ? v1.y : v2; - r.z = v1.z > v2 ? v1.z : v2; - r.w = v1.w > v2 ? v1.w : v2; - return r; -} - -static float __attribute__((overloadable)) min(float v1, float v2) { - return v1 < v2 ? v1 : v2; -} -static float2 __attribute__((overloadable)) min(float2 v1, float2 v2) { - float2 r; - r.x = v1.x < v2.x ? v1.x : v2.x; - r.y = v1.y < v2.y ? v1.y : v2.y; - return r; -} -static float3 __attribute__((overloadable)) min(float3 v1, float3 v2) { - float3 r; - r.x = v1.x < v2.x ? v1.x : v2.x; - r.y = v1.y < v2.y ? v1.y : v2.y; - r.z = v1.z < v2.z ? v1.z : v2.z; - return r; -} -static float4 __attribute__((overloadable)) min(float4 v1, float4 v2) { - float4 r; - r.x = v1.x < v2.x ? v1.x : v2.x; - r.y = v1.y < v2.y ? v1.y : v2.y; - r.z = v1.z < v2.z ? v1.z : v2.z; - r.w = v1.w < v2.w ? v1.w : v2.w; - return r; -} -static float2 __attribute__((overloadable)) min(float2 v1, float v2) { - float2 r; - r.x = v1.x < v2 ? v1.x : v2; - r.y = v1.y < v2 ? v1.y : v2; - return r; -} -static float3 __attribute__((overloadable)) min(float3 v1, float v2) { - float3 r; - r.x = v1.x < v2 ? v1.x : v2; - r.y = v1.y < v2 ? v1.y : v2; - r.z = v1.z < v2 ? v1.z : v2; - return r; -} -static float4 __attribute__((overloadable)) min(float4 v1, float v2) { - float4 r; - r.x = v1.x < v2 ? v1.x : v2; - r.y = v1.y < v2 ? v1.y : v2; - r.z = v1.z < v2 ? v1.z : v2; - r.w = v1.w < v2 ? v1.w : v2; - return r; -} - -static float __attribute__((overloadable)) mix(float start, float stop, float amount) { - return start + (stop - start) * amount; -} -static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) { - return start + (stop - start) * amount; -} -static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) { - return start + (stop - start) * amount; -} -static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) { - return start + (stop - start) * amount; -} -static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) { - return start + (stop - start) * amount; -} -static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) { - return start + (stop - start) * amount; -} -static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) { - return start + (stop - start) * amount; -} - -static float __attribute__((overloadable)) radians(float degrees) { - return degrees * (M_PI / 180.f); -} -DEF_FUNC_1(radians) - -static float __attribute__((overloadable)) step(float edge, float v) { - return (v < edge) ? 0.f : 1.f; -} -static float2 __attribute__((overloadable)) step(float2 edge, float2 v) { - float2 r; - r.x = (v.x < edge.x) ? 0.f : 1.f; - r.y = (v.y < edge.y) ? 0.f : 1.f; - return r; -} -static float3 __attribute__((overloadable)) step(float3 edge, float3 v) { - float3 r; - r.x = (v.x < edge.x) ? 0.f : 1.f; - r.y = (v.y < edge.y) ? 0.f : 1.f; - r.z = (v.z < edge.z) ? 0.f : 1.f; - return r; -} -static float4 __attribute__((overloadable)) step(float4 edge, float4 v) { - float4 r; - r.x = (v.x < edge.x) ? 0.f : 1.f; - r.y = (v.y < edge.y) ? 0.f : 1.f; - r.z = (v.z < edge.z) ? 0.f : 1.f; - r.w = (v.w < edge.w) ? 0.f : 1.f; - return r; -} -static float2 __attribute__((overloadable)) step(float2 edge, float v) { - float2 r; - r.x = (v < edge.x) ? 0.f : 1.f; - r.y = (v < edge.y) ? 0.f : 1.f; - return r; -} -static float3 __attribute__((overloadable)) step(float3 edge, float v) { - float3 r; - r.x = (v < edge.x) ? 0.f : 1.f; - r.y = (v < edge.y) ? 0.f : 1.f; - r.z = (v < edge.z) ? 0.f : 1.f; - return r; -} -static float4 __attribute__((overloadable)) step(float4 edge, float v) { - float4 r; - r.x = (v < edge.x) ? 0.f : 1.f; - r.y = (v < edge.y) ? 0.f : 1.f; - r.z = (v < edge.z) ? 0.f : 1.f; - r.w = (v < edge.w) ? 0.f : 1.f; - return r; -} +_RS_RUNTIME float __attribute__((overloadable)) clamp(float amount, float low, float high); +_RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high); +_RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high); +_RS_RUNTIME float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high); +_RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high); +_RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high); +_RS_RUNTIME float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high); + +_RS_RUNTIME float __attribute__((overloadable)) degrees(float radians); +FN_FUNC_FN(degrees) + +_RS_RUNTIME float __attribute__((overloadable)) mix(float start, float stop, float amount); +_RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount); +_RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount); +_RS_RUNTIME float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount); +_RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount); +_RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount); +_RS_RUNTIME float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount); + +_RS_RUNTIME float __attribute__((overloadable)) radians(float degrees); +FN_FUNC_FN(radians) + +_RS_RUNTIME float __attribute__((overloadable)) step(float edge, float v); +_RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float2 v); +_RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float3 v); +_RS_RUNTIME float4 __attribute__((overloadable)) step(float4 edge, float4 v); +_RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float v); +_RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float v); +_RS_RUNTIME float4 __attribute__((overloadable)) step(float4 edge, float v); extern float __attribute__((overloadable)) smoothstep(float, float, float); extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2); @@ -704,82 +399,51 @@ extern float2 __attribute__((overloadable)) smoothstep(float, float, float2); extern float3 __attribute__((overloadable)) smoothstep(float, float, float3); extern float4 __attribute__((overloadable)) smoothstep(float, float, float4); -static float __attribute__((overloadable)) sign(float v) { - if (v > 0) return 1.f; - if (v < 0) return -1.f; - return v; -} -DEF_FUNC_1(sign) +_RS_RUNTIME float __attribute__((overloadable)) sign(float v); +FN_FUNC_FN(sign) // 6.11.5 -static float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) { - float3 r; - r.x = lhs.y * rhs.z - lhs.z * rhs.y; - r.y = lhs.z * rhs.x - lhs.x * rhs.z; - r.z = lhs.x * rhs.y - lhs.y * rhs.x; - return r; -} - -static float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) { - float4 r; - r.x = lhs.y * rhs.z - lhs.z * rhs.y; - r.y = lhs.z * rhs.x - lhs.x * rhs.z; - r.z = lhs.x * rhs.y - lhs.y * rhs.x; - r.w = 0.f; - return r; -} - -static float __attribute__((overloadable)) dot(float lhs, float rhs) { - return lhs * rhs; -} -static float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) { - return lhs.x*rhs.x + lhs.y*rhs.y; -} -static float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) { - return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; -} -static float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) { - return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w; -} - -static float __attribute__((overloadable)) length(float v) { - return v; -} -static float __attribute__((overloadable)) length(float2 v) { - return sqrt(v.x*v.x + v.y*v.y); -} -static float __attribute__((overloadable)) length(float3 v) { - return sqrt(v.x*v.x + v.y*v.y + v.z*v.z); -} -static float __attribute__((overloadable)) length(float4 v) { - return sqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); -} - -static float __attribute__((overloadable)) distance(float lhs, float rhs) { - return length(lhs - rhs); -} -static float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) { - return length(lhs - rhs); -} -static float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) { - return length(lhs - rhs); -} -static float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) { - return length(lhs - rhs); -} - -static float __attribute__((overloadable)) normalize(float v) { - return 1.f; -} -static float2 __attribute__((overloadable)) normalize(float2 v) { - return v / length(v); -} -static float3 __attribute__((overloadable)) normalize(float3 v) { - return v / length(v); -} -static float4 __attribute__((overloadable)) normalize(float4 v) { - return v / length(v); -} - +_RS_RUNTIME float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs); + +_RS_RUNTIME float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs); + +_RS_RUNTIME float __attribute__((overloadable)) dot(float lhs, float rhs); +_RS_RUNTIME float __attribute__((overloadable)) dot(float2 lhs, float2 rhs); +_RS_RUNTIME float __attribute__((overloadable)) dot(float3 lhs, float3 rhs); +_RS_RUNTIME float __attribute__((overloadable)) dot(float4 lhs, float4 rhs); + +_RS_RUNTIME float __attribute__((overloadable)) length(float v); +_RS_RUNTIME float __attribute__((overloadable)) length(float2 v); +_RS_RUNTIME float __attribute__((overloadable)) length(float3 v); +_RS_RUNTIME float __attribute__((overloadable)) length(float4 v); + +_RS_RUNTIME float __attribute__((overloadable)) distance(float lhs, float rhs); +_RS_RUNTIME float __attribute__((overloadable)) distance(float2 lhs, float2 rhs); +_RS_RUNTIME float __attribute__((overloadable)) distance(float3 lhs, float3 rhs); +_RS_RUNTIME float __attribute__((overloadable)) distance(float4 lhs, float4 rhs); + +_RS_RUNTIME float __attribute__((overloadable)) normalize(float v); +_RS_RUNTIME float2 __attribute__((overloadable)) normalize(float2 v); +_RS_RUNTIME float3 __attribute__((overloadable)) normalize(float3 v); +_RS_RUNTIME float4 __attribute__((overloadable)) normalize(float4 v); + +#undef CVT_FUNC +#undef CVT_FUNC_2 +#undef FN_FUNC_FN +#undef IN_FUNC_FN +#undef FN_FUNC_FN_FN +#undef FN_FUNC_FN_F +#undef FN_FUNC_FN_IN +#undef FN_FUNC_FN_I +#undef FN_FUNC_FN_PFN +#undef FN_FUNC_FN_PIN +#undef FN_FUNC_FN_FN_FN +#undef FN_FUNC_FN_FN_PIN +#undef XN_FUNC_YN +#undef UIN_FUNC_IN +#undef IN_FUNC_IN +#undef XN_FUNC_XN_XN_BODY +#undef IN_FUNC_IN_IN_BODY +#undef _RS_RUNTIME #endif diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh index 16482c1d9219..4768bbed1f14 100644 --- a/libs/rs/scriptc/rs_core.rsh +++ b/libs/rs/scriptc/rs_core.rsh @@ -1,649 +1,298 @@ #ifndef __RS_CORE_RSH__ #define __RS_CORE_RSH__ -// Debugging, print to the LOG a description string and a value. +#define _RS_RUNTIME extern + +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, float); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, float, float); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, float, float, float); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, float, float, float, float); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, double); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, const rs_matrix4x4 *); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, const rs_matrix3x3 *); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, const rs_matrix2x2 *); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, int); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, uint); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, long); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, unsigned long); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, long long); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, unsigned long long); +/** + * Debug function. Prints a string and value to the log. + */ extern void __attribute__((overloadable)) rsDebug(const char *, const void *); #define RS_DEBUG(a) rsDebug(#a, a) #define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__) -static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) { - rsDebug(s, v.x, v.y); -} -static void __attribute__((overloadable)) rsDebug(const char *s, float3 v) { - rsDebug(s, v.x, v.y, v.z); -} -static void __attribute__((overloadable)) rsDebug(const char *s, float4 v) { - rsDebug(s, v.x, v.y, v.z, v.w); -} - -static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b) -{ - uchar4 c; - c.x = (uchar)(r * 255.f); - c.y = (uchar)(g * 255.f); - c.z = (uchar)(b * 255.f); - c.w = 255; - return c; -} - -static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a) -{ - uchar4 c; - c.x = (uchar)(r * 255.f); - c.y = (uchar)(g * 255.f); - c.z = (uchar)(b * 255.f); - c.w = (uchar)(a * 255.f); - return c; -} - -static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color) -{ - color *= 255.f; - uchar4 c = {color.x, color.y, color.z, 255}; - return c; -} - -static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color) -{ - color *= 255.f; - uchar4 c = {color.x, color.y, color.z, color.w}; - return c; -} - -static float4 rsUnpackColor8888(uchar4 c) -{ - float4 ret = (float4)0.0039156862745f; - ret *= convert_float4(c); - return ret; -} -//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b); -//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3); -//extern float4 rsUnpackColor565(uchar4); +/** + * Debug function. Prints a string and value to the log. + */ +_RS_RUNTIME void __attribute__((overloadable)) rsDebug(const char *s, float2 v); +/** + * Debug function. Prints a string and value to the log. + */ +_RS_RUNTIME void __attribute__((overloadable)) rsDebug(const char *s, float3 v); +/** + * Debug function. Prints a string and value to the log. + */ +_RS_RUNTIME void __attribute__((overloadable)) rsDebug(const char *s, float4 v); + + +/** + * Pack floating point (0-1) RGB values into a uchar4. The alpha component is + * set to 255 (1.0). + * + * @param r + * @param g + * @param b + * + * @return uchar4 + */ +_RS_RUNTIME uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b); + +/** + * Pack floating point (0-1) RGBA values into a uchar4. + * + * @param r + * @param g + * @param b + * @param a + * + * @return uchar4 + */ +_RS_RUNTIME uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a); + +/** + * Pack floating point (0-1) RGB values into a uchar4. The alpha component is + * set to 255 (1.0). + * + * @param color + * + * @return uchar4 + */ +_RS_RUNTIME uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color); + +/** + * Pack floating point (0-1) RGBA values into a uchar4. + * + * @param color + * + * @return uchar4 + */ +_RS_RUNTIME uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color); + +/** + * Unpack a uchar4 color to float4. The resulting float range will be (0-1). + * + * @param c + * + * @return float4 + */ +_RS_RUNTIME float4 rsUnpackColor8888(uchar4 c); ///////////////////////////////////////////////////// // Matrix ops ///////////////////////////////////////////////////// -static void __attribute__((overloadable)) -rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 4 + col] = v; -} - -static float __attribute__((overloadable)) -rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) { - return m->m[row * 4 + col]; -} - -static void __attribute__((overloadable)) -rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 3 + col] = v; -} - -static float __attribute__((overloadable)) -rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) { - return m->m[row * 3 + col]; -} - -static void __attribute__((overloadable)) -rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 2 + col] = v; -} - -static float __attribute__((overloadable)) -rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) { - return m->m[row * 2 + col]; -} - -static void __attribute__((overloadable)) -rsMatrixLoadIdentity(rs_matrix4x4 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = 0.f; - m->m[5] = 1.f; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = 0.f; - m->m[9] = 0.f; - m->m[10] = 1.f; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void __attribute__((overloadable)) -rsMatrixLoadIdentity(rs_matrix3x3 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = 1.f; - m->m[5] = 0.f; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = 1.f; -} - -static void __attribute__((overloadable)) -rsMatrixLoadIdentity(rs_matrix2x2 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 1.f; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix4x4 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; - m->m[4] = v[4]; - m->m[5] = v[5]; - m->m[6] = v[6]; - m->m[7] = v[7]; - m->m[8] = v[8]; - m->m[9] = v[9]; - m->m[10] = v[10]; - m->m[11] = v[11]; - m->m[12] = v[12]; - m->m[13] = v[13]; - m->m[14] = v[14]; - m->m[15] = v[15]; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix3x3 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; - m->m[4] = v[4]; - m->m[5] = v[5]; - m->m[6] = v[6]; - m->m[7] = v[7]; - m->m[8] = v[8]; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix2x2 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix4x4 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; - m->m[4] = v->m[4]; - m->m[5] = v->m[5]; - m->m[6] = v->m[6]; - m->m[7] = v->m[7]; - m->m[8] = v->m[8]; - m->m[9] = v->m[9]; - m->m[10] = v->m[10]; - m->m[11] = v->m[11]; - m->m[12] = v->m[12]; - m->m[13] = v->m[13]; - m->m[14] = v->m[14]; - m->m[15] = v->m[15]; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix3x3 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = 0.f; - m->m[4] = v->m[3]; - m->m[5] = v->m[4]; - m->m[6] = v->m[5]; - m->m[7] = 0.f; - m->m[8] = v->m[6]; - m->m[9] = v->m[7]; - m->m[10] = v->m[8]; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix2x2 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = v->m[3]; - m->m[5] = v->m[4]; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = v->m[6]; - m->m[9] = v->m[7]; - m->m[10] = 1.f; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix3x3 *m, const rs_matrix3x3 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; - m->m[4] = v->m[4]; - m->m[5] = v->m[5]; - m->m[6] = v->m[6]; - m->m[7] = v->m[7]; - m->m[8] = v->m[8]; -} - -static void __attribute__((overloadable)) -rsMatrixLoad(rs_matrix2x2 *m, const rs_matrix2x2 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; -} - -static void __attribute__((overloadable)) -rsMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { - float c, s; - m->m[3] = 0; - m->m[7] = 0; - m->m[11]= 0; - m->m[12]= 0; - m->m[13]= 0; - m->m[14]= 0; - m->m[15]= 1; - rot *= (float)(M_PI / 180.0f); - c = cos(rot); - s = sin(rot); - - const float len = x*x + y*y + z*z; - if (len != 1) { - const float recipLen = 1.f / sqrt(len); - x *= recipLen; - y *= recipLen; - z *= recipLen; - } - const float nc = 1.0f - c; - const float xy = x * y; - const float yz = y * z; - const float zx = z * x; - const float xs = x * s; - const float ys = y * s; - const float zs = z * s; - m->m[ 0] = x*x*nc + c; - m->m[ 4] = xy*nc - zs; - m->m[ 8] = zx*nc + ys; - m->m[ 1] = xy*nc + zs; - m->m[ 5] = y*y*nc + c; - m->m[ 9] = yz*nc - xs; - m->m[ 2] = zx*nc - ys; - m->m[ 6] = yz*nc + xs; - m->m[10] = z*z*nc + c; -} - -static void __attribute__((overloadable)) -rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) { - rsMatrixLoadIdentity(m); - m->m[0] = x; - m->m[5] = y; - m->m[10] = z; -} - -static void __attribute__((overloadable)) -rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) { - rsMatrixLoadIdentity(m); - m->m[12] = x; - m->m[13] = y; - m->m[14] = z; -} - -static void __attribute__((overloadable)) -rsMatrixLoadMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) { - for (int i=0 ; i<4 ; i++) { - float ri0 = 0; - float ri1 = 0; - float ri2 = 0; - float ri3 = 0; - for (int j=0 ; j<4 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; - ri3 += rsMatrixGet(lhs, j, 3) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - rsMatrixSet(m, i, 2, ri2); - rsMatrixSet(m, i, 3, ri3); - } -} - -static void __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) { - rs_matrix4x4 mt; - rsMatrixLoadMultiply(&mt, m, rhs); - rsMatrixLoad(m, &mt); -} - -static void __attribute__((overloadable)) -rsMatrixLoadMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) { - for (int i=0 ; i<3 ; i++) { - float ri0 = 0; - float ri1 = 0; - float ri2 = 0; - for (int j=0 ; j<3 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - rsMatrixSet(m, i, 2, ri2); - } -} +/** + * Set one element of a matrix. + * + * @param m The matrix to be set + * @param row + * @param col + * @param v + * + * @return void + */ +_RS_RUNTIME void __attribute__((overloadable)) +rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v); +_RS_RUNTIME void __attribute__((overloadable)) +rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v); +_RS_RUNTIME void __attribute__((overloadable)) +rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v); + +/** + * Get one element of a matrix. + * + * @param m The matrix to read from + * @param row + * @param col + * + * @return float + */ +_RS_RUNTIME float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col); +_RS_RUNTIME float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col); +_RS_RUNTIME float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col); + +/** + * Set the elements of a matrix to the identity matrix. + * + * @param m + */ +extern void __attribute__((overloadable)) rsMatrixLoadIdentity(rs_matrix4x4 *m); +extern void __attribute__((overloadable)) rsMatrixLoadIdentity(rs_matrix3x3 *m); +extern void __attribute__((overloadable)) rsMatrixLoadIdentity(rs_matrix2x2 *m); + +/** + * Set the elements of a matrix from an array of floats. + * + * @param m + */ +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix4x4 *m, const float *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix3x3 *m, const float *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix2x2 *m, const float *v); + +/** + * Set the elements of a matrix from another matrix. + * + * @param m + */ +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix4x4 *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix3x3 *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix2x2 *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix3x3 *m, const rs_matrix3x3 *v); +extern void __attribute__((overloadable)) rsMatrixLoad(rs_matrix2x2 *m, const rs_matrix2x2 *v); + +/** + * Load a rotation matrix. + * + * @param m + * @param rot + * @param x + * @param y + * @param z + */ +extern void __attribute__((overloadable)) +rsMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z); -static void __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) { - rs_matrix3x3 mt; - rsMatrixLoadMultiply(&mt, m, rhs); - rsMatrixLoad(m, &mt); -} +extern void __attribute__((overloadable)) +rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z); -static void __attribute__((overloadable)) -rsMatrixLoadMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) { - for (int i=0 ; i<2 ; i++) { - float ri0 = 0; - float ri1 = 0; - for (int j=0 ; j<2 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - } -} +extern void __attribute__((overloadable)) +rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z); -static void __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) { - rs_matrix2x2 mt; - rsMatrixLoadMultiply(&mt, m, rhs); - rsMatrixLoad(m, &mt); -} +extern void __attribute__((overloadable)) +rsMatrixLoadMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs); -static void __attribute__((overloadable)) -rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { - rs_matrix4x4 m1; - rsMatrixLoadRotate(&m1, rot, x, y, z); - rsMatrixMultiply(m, &m1); -} +extern void __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs); -static void __attribute__((overloadable)) -rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z) { - rs_matrix4x4 m1; - rsMatrixLoadScale(&m1, x, y, z); - rsMatrixMultiply(m, &m1); -} +extern void __attribute__((overloadable)) +rsMatrixLoadMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs); -static void __attribute__((overloadable)) -rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) { - rs_matrix4x4 m1; - rsMatrixLoadTranslate(&m1, x, y, z); - rsMatrixMultiply(m, &m1); -} +extern void __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs); -static void __attribute__((overloadable)) -rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { - rsMatrixLoadIdentity(m); - m->m[0] = 2.f / (right - left); - m->m[5] = 2.f / (top - bottom); - m->m[10]= -2.f / (far - near); - m->m[12]= -(right + left) / (right - left); - m->m[13]= -(top + bottom) / (top - bottom); - m->m[14]= -(far + near) / (far - near); -} +extern void __attribute__((overloadable)) +rsMatrixLoadMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs); -static void __attribute__((overloadable)) -rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { - rsMatrixLoadIdentity(m); - m->m[0] = 2.f * near / (right - left); - m->m[5] = 2.f * near / (top - bottom); - m->m[8] = (right + left) / (right - left); - m->m[9] = (top + bottom) / (top - bottom); - m->m[10]= -(far + near) / (far - near); - m->m[11]= -1.f; - m->m[14]= -2.f * far * near / (far - near); - m->m[15]= 0.f; -} +extern void __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs); -static void __attribute__((overloadable)) -rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) { - float top = near * tan((float) (fovy * M_PI / 360.0f)); - float bottom = -top; - float left = bottom * aspect; - float right = top * aspect; - rsMatrixLoadFrustum(m, left, right, bottom, top, near, far); -} +extern void __attribute__((overloadable)) +rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z); -static float4 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix4x4 *m, float4 in) { - float4 ret; - ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + (m->m[12] * in.w); - ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + (m->m[9] * in.z) + (m->m[13] * in.w); - ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + (m->m[10] * in.z) + (m->m[14] * in.w); - ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + (m->m[11] * in.z) + (m->m[15] * in.w); - return ret; -} +extern void __attribute__((overloadable)) +rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z); -static float4 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix4x4 *m, float3 in) { - float4 ret; - ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + m->m[12]; - ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + (m->m[9] * in.z) + m->m[13]; - ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + (m->m[10] * in.z) + m->m[14]; - ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + (m->m[11] * in.z) + m->m[15]; - return ret; -} +extern void __attribute__((overloadable)) +rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z); -static float4 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix4x4 *m, float2 in) { - float4 ret; - ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + m->m[12]; - ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + m->m[13]; - ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + m->m[14]; - ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + m->m[15]; - return ret; -} +extern void __attribute__((overloadable)) +rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far); -static float3 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix3x3 *m, float3 in) { - float3 ret; - ret.x = (m->m[0] * in.x) + (m->m[3] * in.y) + (m->m[6] * in.z); - ret.y = (m->m[1] * in.x) + (m->m[4] * in.y) + (m->m[7] * in.z); - ret.z = (m->m[2] * in.x) + (m->m[5] * in.y) + (m->m[8] * in.z); - return ret; -} +extern void __attribute__((overloadable)) +rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far); -static float3 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix3x3 *m, float2 in) { - float3 ret; - ret.x = (m->m[0] * in.x) + (m->m[3] * in.y); - ret.y = (m->m[1] * in.x) + (m->m[4] * in.y); - ret.z = (m->m[2] * in.x) + (m->m[5] * in.y); - return ret; -} +extern void __attribute__((overloadable)) +rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far); -static float2 __attribute__((overloadable)) -rsMatrixMultiply(rs_matrix2x2 *m, float2 in) { - float2 ret; - ret.x = (m->m[0] * in.x) + (m->m[2] * in.y); - ret.y = (m->m[1] * in.x) + (m->m[3] * in.y); - return ret; -} +_RS_RUNTIME float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float4 in); -// Returns true if the matrix was successfully inversed -static bool __attribute__((overloadable)) -rsMatrixInverse(rs_matrix4x4 *m) { - rs_matrix4x4 result; - - int i, j; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - // computeCofactor for int i, int j - int c0 = (i+1) % 4; - int c1 = (i+2) % 4; - int c2 = (i+3) % 4; - int r0 = (j+1) % 4; - int r1 = (j+2) % 4; - int r2 = (j+3) % 4; - - float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) - - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) - + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); - - float cofactor = (i+j) & 1 ? -minor : minor; - - result.m[4*i + j] = cofactor; - } - } +_RS_RUNTIME float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float3 in); - // Dot product of 0th column of source and 0th row of result - float det = m->m[0]*result.m[0] + m->m[4]*result.m[1] + - m->m[8]*result.m[2] + m->m[12]*result.m[3]; +_RS_RUNTIME float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float2 in); - if (fabs(det) < 1e-6) { - return false; - } +_RS_RUNTIME float3 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, float3 in); - det = 1.0f / det; - for (i = 0; i < 16; ++i) { - m->m[i] = result.m[i] * det; - } +_RS_RUNTIME float3 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, float2 in); - return true; -} +_RS_RUNTIME float2 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix2x2 *m, float2 in); // Returns true if the matrix was successfully inversed -static bool __attribute__((overloadable)) -rsMatrixInverseTranspose(rs_matrix4x4 *m) { - rs_matrix4x4 result; - - int i, j; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - // computeCofactor for int i, int j - int c0 = (i+1) % 4; - int c1 = (i+2) % 4; - int c2 = (i+3) % 4; - int r0 = (j+1) % 4; - int r1 = (j+2) % 4; - int r2 = (j+3) % 4; - - float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) - - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) - + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); - - float cofactor = (i+j) & 1 ? -minor : minor; - - result.m[4*j + i] = cofactor; - } - } - - // Dot product of 0th column of source and 0th column of result - float det = m->m[0]*result.m[0] + m->m[4]*result.m[4] + - m->m[8]*result.m[8] + m->m[12]*result.m[12]; - - if (fabs(det) < 1e-6) { - return false; - } - - det = 1.0f / det; - for (i = 0; i < 16; ++i) { - m->m[i] = result.m[i] * det; - } - - return true; -} - -static void __attribute__((overloadable)) -rsMatrixTranspose(rs_matrix4x4 *m) { - int i, j; - float temp; - for (i = 0; i < 3; ++i) { - for (j = i + 1; j < 4; ++j) { - temp = m->m[i*4 + j]; - m->m[i*4 + j] = m->m[j*4 + i]; - m->m[j*4 + i] = temp; - } - } -} - -static void __attribute__((overloadable)) -rsMatrixTranspose(rs_matrix3x3 *m) { - int i, j; - float temp; - for (i = 0; i < 2; ++i) { - for (j = i + 1; j < 3; ++j) { - temp = m->m[i*3 + j]; - m->m[i*3 + j] = m->m[j*4 + i]; - m->m[j*3 + i] = temp; - } - } -} - -static void __attribute__((overloadable)) -rsMatrixTranspose(rs_matrix2x2 *m) { - float temp = m->m[1]; - m->m[1] = m->m[2]; - m->m[2] = temp; -} +extern bool __attribute__((overloadable)) rsMatrixInverse(rs_matrix4x4 *m); +extern bool __attribute__((overloadable)) rsMatrixInverseTranspose(rs_matrix4x4 *m); +extern void __attribute__((overloadable)) rsMatrixTranspose(rs_matrix4x4 *m); +extern void __attribute__((overloadable)) rsMatrixTranspose(rs_matrix3x3 *m); +extern void __attribute__((overloadable)) rsMatrixTranspose(rs_matrix2x2 *m); ///////////////////////////////////////////////////// // quaternion ops @@ -677,7 +326,7 @@ static void __attribute__((overloadable)) rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) { q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w; q->x = q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x; - q->y = -q->x*rhs->z + q->y*rhs->w + q->z*rhs->z + q->w*rhs->y; + q->y = -q->x*rhs->z + q->y*rhs->w + q->z*rhs->x + q->w*rhs->y; q->z = q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z; } @@ -899,26 +548,13 @@ rsIsSphereInFrustum(float4 *sphere, // int ops ///////////////////////////////////////////////////// -__inline__ static uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) { - return amount < low ? low : (amount > high ? high : amount); -} -__inline__ static int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) { - return amount < low ? low : (amount > high ? high : amount); -} -__inline__ static ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) { - return amount < low ? low : (amount > high ? high : amount); -} -__inline__ static short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) { - return amount < low ? low : (amount > high ? high : amount); -} -__inline__ static uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) { - return amount < low ? low : (amount > high ? high : amount); -} -__inline__ static char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) { - return amount < low ? low : (amount > high ? high : amount); -} - +_RS_RUNTIME uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high); +_RS_RUNTIME int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high); +_RS_RUNTIME ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high); +_RS_RUNTIME short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high); +_RS_RUNTIME uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high); +_RS_RUNTIME char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high); +#undef _RS_RUNTIME #endif - diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh index 3e708aae5618..67ffc3d9e56b 100644 --- a/libs/rs/scriptc/rs_graphics.rsh +++ b/libs/rs/scriptc/rs_graphics.rsh @@ -1,21 +1,60 @@ #ifndef __RS_GRAPHICS_RSH__ #define __RS_GRAPHICS_RSH__ -// Bind a ProgramFragment to the RS context. + +/** + * Bind a new ProgramFragment to the rendering context. + * + * @param pf + */ extern void __attribute__((overloadable)) - rsgBindProgramFragment(rs_program_fragment); + rsgBindProgramFragment(rs_program_fragment pf); + +/** + * Bind a new ProgramStore to the rendering context. + * + * @param ps + */ extern void __attribute__((overloadable)) - rsgBindProgramStore(rs_program_store); + rsgBindProgramStore(rs_program_store ps); + +/** + * Bind a new ProgramVertex to the rendering context. + * + * @param pv + */ extern void __attribute__((overloadable)) - rsgBindProgramVertex(rs_program_vertex); + rsgBindProgramVertex(rs_program_vertex pv); + +/** + * Bind a new ProgramRaster to the rendering context. + * + * @param pr + */ extern void __attribute__((overloadable)) - rsgBindProgramRaster(rs_program_raster); + rsgBindProgramRaster(rs_program_raster pr); +/** + * Bind a new Sampler object to a ProgramFragment. The sampler will + * operate on the texture bound at the matching slot. + * + * @param slot + */ extern void __attribute__((overloadable)) rsgBindSampler(rs_program_fragment, uint slot, rs_sampler); + +/** + * Bind a new Allocation object to a ProgramFragment. The + * Allocation must be a valid texture for the Program. The sampling + * of the texture will be controled by the Sampler bound at the + * matching slot. + * + * @param slot + */ extern void __attribute__((overloadable)) rsgBindTexture(rs_program_fragment, uint slot, rs_allocation); + extern void __attribute__((overloadable)) rsgProgramVertexLoadProjectionMatrix(const rs_matrix4x4 *); extern void __attribute__((overloadable)) @@ -26,39 +65,134 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsgProgramVertexGetProjectionMatrix(rs_matrix4x4 *); -extern void __attribute__((overloadable)) - rsgProgramFragmentConstantColor(rs_program_fragment, float, float, float, float); - +/** + * Set the constant color for a fixed function emulation program. + * + * @param pf + * @param r + * @param g + * @param b + * @param a + */ +extern void __attribute__((overloadable)) + rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a); + +/** + * Get the width of the current rendering surface. + * + * @return uint + */ extern uint __attribute__((overloadable)) rsgGetWidth(void); + +/** + * Get the height of the current rendering surface. + * + * @return uint + */ extern uint __attribute__((overloadable)) rsgGetHeight(void); -extern void __attribute__((overloadable)) - rsgAllocationSyncAll(rs_allocation); +/** + * Sync the contents of an allocation from its SCRIPT memory space to its HW + * memory spaces. + * + * @param alloc + */ extern void __attribute__((overloadable)) - rsgUploadToTexture(rs_allocation); -extern void __attribute__((overloadable)) - rsgUploadToTexture(rs_allocation, uint mipLevel); -extern void __attribute__((overloadable)) - rsgUploadToBufferObject(rs_allocation); + rsgAllocationSyncAll(rs_allocation alloc); +/** + * Low performance utility function for drawing a simple rectangle. Not + * intended for drawing large quantities of geometry. + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param z + */ extern void __attribute__((overloadable)) rsgDrawRect(float x1, float y1, float x2, float y2, float z); + +/** + * Low performance utility function for drawing a simple quad. Not intended for + * drawing large quantities of geometry. + * + * @param x1 + * @param y1 + * @param z1 + * @param x2 + * @param y2 + * @param z2 + * @param x3 + * @param y3 + * @param z3 + * @param x4 + * @param y4 + * @param z4 + */ extern void __attribute__((overloadable)) rsgDrawQuad(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4); + + +/** + * Low performance utility function for drawing a textured quad. Not intended + * for drawing large quantities of geometry. + * + * @param x1 + * @param y1 + * @param z1 + * @param u1 + * @param v1 + * @param x2 + * @param y2 + * @param z2 + * @param u2 + * @param v2 + * @param x3 + * @param y3 + * @param z3 + * @param u3 + * @param v3 + * @param x4 + * @param y4 + * @param z4 + * @param u4 + * @param v4 + */ extern void __attribute__((overloadable)) rsgDrawQuadTexCoords(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4); + + +/** + * Low performance function for drawing rectangles in screenspace. This + * function uses the default passthough ProgramVertex. Any bound ProgramVertex + * is ignored. This function has considerable overhead and should not be used + * for drawing in shipping applications. + * + * @param x + * @param y + * @param z + * @param w + * @param h + */ extern void __attribute__((overloadable)) rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h); +/** + * Draw a mesh of geometry using the current context state. The whole mesh is + * rendered. + * + * @param ism + */ extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism); extern void __attribute__((overloadable)) @@ -66,10 +200,23 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism, uint primitiveIndex, uint start, uint len); +/** + * Clears the rendering surface to the specified color. + * + * @param r + * @param g + * @param b + * @param a + */ extern void __attribute__((overloadable)) - rsgClearColor(float, float, float, float); + rsgClearColor(float r, float g, float b, float a); + +/** + * Clears the depth suface to the specified value. + * + */ extern void __attribute__((overloadable)) - rsgClearDepth(float); + rsgClearDepth(float value); extern void __attribute__((overloadable)) rsgDrawText(const char *, int x, int y); @@ -101,12 +248,5 @@ rsgMeshComputeBoundingBox(rs_mesh mesh, float3 *bBoxMin, float3 *bBoxMax) { bBoxMax->z = z2; } -/////////////////////////////////////////////////////// -// misc - -// Depricated -extern void __attribute__((overloadable)) - color(float, float, float, float); - #endif diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh index d059997ca982..6e3cfdb77529 100644 --- a/libs/rs/scriptc/rs_math.rsh +++ b/libs/rs/scriptc/rs_math.rsh @@ -1,6 +1,12 @@ #ifndef __RS_MATH_RSH__ #define __RS_MATH_RSH__ +/** + * Copy reference to the specified object. + * + * @param dst + * @param src + */ extern void __attribute__((overloadable)) rsSetObject(rs_element *dst, rs_element src); extern void __attribute__((overloadable)) @@ -24,6 +30,11 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsSetObject(rs_font *dst, rs_font src); +/** + * Sets the object to NULL. + * + * @return bool + */ extern void __attribute__((overloadable)) rsClearObject(rs_element *dst); extern void __attribute__((overloadable)) @@ -47,6 +58,12 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsClearObject(rs_font *dst); +/** + * Tests if the object is valid. Returns true if the object is valid, false if + * it is NULL. + * + * @return bool + */ extern bool __attribute__((overloadable)) rsIsObject(rs_element); extern bool __attribute__((overloadable)) @@ -71,27 +88,51 @@ extern bool __attribute__((overloadable)) rsIsObject(rs_font); - -// Allocations - -// Return the rs_allocation associated with a bound data -// pointer. +/** + * Returns the Allocation for a given pointer. The pointer should point within + * a valid allocation. The results are undefined if the pointer is not from a + * valid allocation. + */ extern rs_allocation __attribute__((overloadable)) rsGetAllocation(const void *); -// Mark the allocation dirty and notify those using it -extern void __attribute__((overloadable)) - rsAllocationMarkDirty(rs_allocation); - -// Return the dimensions associated with an allocation. +/** + * Query the dimension of an allocation. + * + * @return uint32_t The X dimension of the allocation. + */ extern uint32_t __attribute__((overloadable)) rsAllocationGetDimX(rs_allocation); + +/** + * Query the dimension of an allocation. + * + * @return uint32_t The Y dimension of the allocation. + */ extern uint32_t __attribute__((overloadable)) rsAllocationGetDimY(rs_allocation); + +/** + * Query the dimension of an allocation. + * + * @return uint32_t The Z dimension of the allocation. + */ extern uint32_t __attribute__((overloadable)) rsAllocationGetDimZ(rs_allocation); + +/** + * Query an allocation for the presence of more than one LOD. + * + * @return uint32_t Returns 1 if more than one LOD is present, 0 otherwise. + */ extern uint32_t __attribute__((overloadable)) rsAllocationGetDimLOD(rs_allocation); + +/** + * Query an allocation for the presence of more than one face. + * + * @return uint32_t Returns 1 if more than one face is present, 0 otherwise. + */ extern uint32_t __attribute__((overloadable)) rsAllocationGetDimFaces(rs_allocation); @@ -118,32 +159,6 @@ extern float __attribute__((overloadable)) extern float __attribute__((overloadable)) rsFrac(float); -// time -extern int32_t __attribute__((overloadable)) - rsSecond(void); -extern int32_t __attribute__((overloadable)) - rsMinute(void); -extern int32_t __attribute__((overloadable)) - rsHour(void); -extern int32_t __attribute__((overloadable)) - rsDay(void); -extern int32_t __attribute__((overloadable)) - rsMonth(void); -extern int32_t __attribute__((overloadable)) - rsYear(void); - -// Return the current system clock in milliseconds -extern int64_t __attribute__((overloadable)) - rsUptimeMillis(void); - -// Return the current system clock in nanoseconds -extern int64_t __attribute__((overloadable)) - rsUptimeNanos(void); - -// Return the time in seconds since function was last called in this script. -extern float __attribute__((overloadable)) - rsGetDt(void); - // Send a message back to the client. Will not block and returns true // if the message was sendable and false if the fifo was full. // A message ID is required. Data payload is optional. diff --git a/libs/rs/scriptc/rs_time.rsh b/libs/rs/scriptc/rs_time.rsh new file mode 100644 index 000000000000..f1abed6308e4 --- /dev/null +++ b/libs/rs/scriptc/rs_time.rsh @@ -0,0 +1,36 @@ +#ifndef __RS_TIME_RSH__ +#define __RS_TIME_RSH__ + +typedef int rs_time_t; + +typedef struct { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +} rs_tm; + +extern rs_time_t __attribute__((overloadable)) + rsTime(rs_time_t *timer); + +extern rs_tm * __attribute__((overloadable)) + rsLocaltime(rs_tm *local, const rs_time_t *timer); + +// Return the current system clock in milliseconds +extern int64_t __attribute__((overloadable)) + rsUptimeMillis(void); + +// Return the current system clock in nanoseconds +extern int64_t __attribute__((overloadable)) + rsUptimeNanos(void); + +// Return the time in seconds since function was last called in this script. +extern float __attribute__((overloadable)) + rsGetDt(void); + +#endif diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh index 212eb8377cda..a010096507b1 100644 --- a/libs/rs/scriptc/rs_types.rsh +++ b/libs/rs/scriptc/rs_types.rsh @@ -1,6 +1,9 @@ #ifndef __RS_TYPES_RSH__ #define __RS_TYPES_RSH__ +#define M_PI 3.14159265358979323846264338327950288f /* pi */ + +#include "stdbool.h" typedef char int8_t; typedef short int16_t; typedef int int32_t; diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp index b5f9c4750a29..7fbf67a02764 100644 --- a/libs/storage/IMountService.cpp +++ b/libs/storage/IMountService.cpp @@ -48,6 +48,8 @@ enum { TRANSACTION_isObbMounted, TRANSACTION_getMountedObbPath, TRANSACTION_isExternalStorageEmulated, + TRANSACTION_decryptStorage, + TRANSACTION_encryptStorage, }; class BpMountService: public BpInterface<IMountService> @@ -504,6 +506,40 @@ public: path = reply.readString16(); return true; } + + int32_t decryptStorage(const String16& password) + { + Parcel data, reply; + data.writeInterfaceToken(IMountService::getInterfaceDescriptor()); + data.writeString16(password); + if (remote()->transact(TRANSACTION_decryptStorage, data, &reply) != NO_ERROR) { + LOGD("decryptStorage could not contact remote\n"); + return -1; + } + int32_t err = reply.readExceptionCode(); + if (err < 0) { + LOGD("decryptStorage caught exception %d\n", err); + return err; + } + return reply.readInt32(); + } + + int32_t encryptStorage(const String16& password) + { + Parcel data, reply; + data.writeInterfaceToken(IMountService::getInterfaceDescriptor()); + data.writeString16(password); + if (remote()->transact(TRANSACTION_encryptStorage, data, &reply) != NO_ERROR) { + LOGD("encryptStorage could not contact remote\n"); + return -1; + } + int32_t err = reply.readExceptionCode(); + if (err < 0) { + LOGD("encryptStorage caught exception %d\n", err); + return err; + } + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MountService, "IMountService"); diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index ce3c71a7d9bb..4a0faf06a12c 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ ISurfaceComposer.cpp \ ISurface.cpp \ ISurfaceComposerClient.cpp \ + IGraphicBufferAlloc.cpp \ LayerState.cpp \ SharedBufferStack.cpp \ Surface.cpp \ diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp new file mode 100644 index 000000000000..e05da725c47f --- /dev/null +++ b/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 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. + */ + +// tag as surfaceflinger +#define LOG_TAG "SurfaceFlinger" + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/Parcel.h> + +#include <ui/GraphicBuffer.h> + +#include <surfaceflinger/IGraphicBufferAlloc.h> + +// --------------------------------------------------------------------------- + +namespace android { + +enum { + CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, +}; + +class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc> +{ +public: + BpGraphicBufferAlloc(const sp<IBinder>& impl) + : BpInterface<IGraphicBufferAlloc>(impl) + { + } + + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage) { + Parcel data, reply; + data.writeInterfaceToken( + IGraphicBufferAlloc::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); + data.writeInt32(usage); + remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); + sp<GraphicBuffer> graphicBuffer; + bool nonNull = (bool)reply.readInt32(); + if (nonNull) { + graphicBuffer = new GraphicBuffer(); + reply.read(*graphicBuffer); + } + return graphicBuffer; + } + + virtual void freeAllGraphicBuffersExcept(int bufIdx) { + Parcel data, reply; + data.writeInterfaceToken( + IGraphicBufferAlloc::getInterfaceDescriptor()); + data.writeInt32(bufIdx); + remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); + +// ---------------------------------------------------------------------- + +status_t BnGraphicBufferAlloc::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + // codes that don't require permission check + + switch(code) { + case CREATE_GRAPHIC_BUFFER: { + CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + PixelFormat format = data.readInt32(); + uint32_t usage = data.readInt32(); + sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage)); + reply->writeInt32(result != 0); + if (result != 0) { + reply->write(*result); + } + return NO_ERROR; + } break; + case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: { + CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); + int bufIdx = data.readInt32(); + freeAllGraphicBuffersExcept(bufIdx); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index b8a7a794d383..01ae23fe265c 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -64,6 +64,15 @@ public: return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); } + virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() + { + uint32_t n; + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply); + return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder()); + } + virtual sp<IMemoryHeap> getCblk() const { Parcel data, reply; @@ -189,6 +198,11 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = createClientConnection()->asBinder(); reply->writeStrongBinder(b); } break; + case CREATE_GRAPHIC_BUFFER_ALLOC: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> b = createGraphicBufferAlloc()->asBinder(); + reply->writeStrongBinder(b); + } break; case OPEN_GLOBAL_TRANSACTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); openGlobalTransaction(); @@ -252,13 +266,13 @@ status_t BnSurfaceComposer::onTransact( int32_t mode = data.readInt32(); status_t res = turnElectronBeamOff(mode); reply->writeInt32(res); - } + } break; case TURN_ELECTRON_BEAM_ON: { CHECK_INTERFACE(ISurfaceComposer, data, reply); int32_t mode = data.readInt32(); status_t res = turnElectronBeamOn(mode); reply->writeInt32(res); - } + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 3b2ef848b38f..7505d530e0c5 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -58,7 +58,6 @@ SharedBufferStack::SharedBufferStack() void SharedBufferStack::init(int32_t i) { - inUse = -2; status = NO_ERROR; identity = i; } @@ -199,9 +198,9 @@ String8 SharedBufferBase::dump(char const* prefix) const SharedBufferStack& stack( *mSharedStack ); snprintf(buffer, SIZE, "%s[ head=%2d, available=%2d, queued=%2d ] " - "reallocMask=%08x, inUse=%2d, identity=%d, status=%d", + "reallocMask=%08x, identity=%d, status=%d", prefix, stack.head, stack.available, stack.queued, - stack.reallocMask, stack.inUse, stack.identity, stack.status); + stack.reallocMask, stack.identity, stack.status); result.append(buffer); result.append("\n"); return result; @@ -261,8 +260,7 @@ bool SharedBufferClient::LockCondition::operator()() const { // NOTE: if stack.head is messed up, we could crash the client // or cause some drawing artifacts. This is okay, as long as it is // limited to the client. - return (buf != stack.index[stack.head] || - (stack.queued > 0 && stack.inUse != buf)); + return (buf != stack.index[stack.head]); } SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition( @@ -303,22 +301,6 @@ ssize_t SharedBufferClient::CancelUpdate::operator()() { 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 " - "(identity=%d, token=%d)", - lockedBuffer, stack.inUse, - stack.identity, stack.token); - return BAD_VALUE; - } - android_atomic_write(-1, &stack.inUse); - return NO_ERROR; -} - SharedBufferServer::RetireUpdate::RetireUpdate( SharedBufferBase* sbb, int numBuffers) : UpdateBase(sbb), numBuffers(numBuffers) { @@ -328,9 +310,6 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) return BAD_VALUE; - // Preventively lock the current buffer before updating queued. - android_atomic_write(stack.headBuf, &stack.inUse); - // Decrement the number of queued buffers int32_t queued; do { @@ -346,7 +325,6 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { head = (head + 1) % numBuffers; const int8_t headBuf = stack.index[head]; stack.headBuf = headBuf; - android_atomic_write(headBuf, &stack.inUse); // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); @@ -547,13 +525,6 @@ ssize_t SharedBufferServer::retireAndLock() return buf; } -status_t SharedBufferServer::unlock(int buf) -{ - UnlockUpdate update(this, buf); - status_t err = updateCondition( update ); - return err; -} - void SharedBufferServer::setStatus(status_t status) { if (status < NO_ERROR) { @@ -695,12 +666,6 @@ status_t SharedBufferServer::shrink(int newNumBuffers) stack.head = 0; stack.headBuf = 0; - // If one of the buffers is in use it must be the head buffer, which we are - // renaming to buffer 0. - if (stack.inUse > 0) { - stack.inUse = 0; - } - // Free the buffers from the end of the list that are no longer needed. for (int i = newNumBuffers; i < mNumBuffers; i++) { mBufferList.remove(i); diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index aa0c2e8b9366..1e9bd744f51c 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -466,7 +466,7 @@ bool Surface::isValid() { return mInitCheck == NO_ERROR; } -status_t Surface::validate() const +status_t Surface::validate(bool inCancelBuffer) const { // check that we initialized ourself properly if (mInitCheck != NO_ERROR) { @@ -476,15 +476,6 @@ status_t Surface::validate() const // verify the identity of this surface uint32_t identity = mSharedBufferClient->getIdentity(); - - // this is a bit of a (temporary) special case, identity==0 means that - // no operation are allowed from the client (eg: dequeue/queue), this - // is used with PUSH_BUFFER surfaces for instance - if (identity == 0) { - LOGE("[Surface] invalid operation (identity=%u)", mIdentity); - return INVALID_OPERATION; - } - if (mIdentity != identity) { LOGE("[Surface] using an invalid surface, " "identity=%u should be %d", @@ -492,17 +483,19 @@ status_t Surface::validate() const CallStack stack; stack.update(); stack.dump("Surface"); - return NO_INIT; + return BAD_INDEX; } // check the surface didn't become invalid status_t err = mSharedBufferClient->getStatus(); if (err != NO_ERROR) { - LOGE("surface (identity=%u) is invalid, err=%d (%s)", - mIdentity, err, strerror(-err)); - CallStack stack; - stack.update(); - stack.dump("Surface"); + if (!inCancelBuffer) { + LOGE("surface (identity=%u) is invalid, err=%d (%s)", + mIdentity, err, strerror(-err)); + CallStack stack; + stack.update(); + stack.dump("Surface"); + } return err; } @@ -633,12 +626,12 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) int Surface::cancelBuffer(android_native_buffer_t* buffer) { - status_t err = validate(); + status_t err = validate(true); switch (err) { case NO_ERROR: // no error, common case break; - case INVALID_OPERATION: + case BAD_INDEX: // legitimate errors here return err; default: @@ -834,13 +827,15 @@ int Surface::disconnect(int api) int Surface::crop(Rect const* rect) { - // empty/invalid rects are not allowed - if (rect->isEmpty()) - return BAD_VALUE; - Mutex::Autolock _l(mSurfaceLock); // TODO: validate rect size - mNextBufferCrop = *rect; + + if (rect == NULL || rect->isEmpty()) { + mNextBufferCrop = Rect(0,0); + } else { + mNextBufferCrop = *rect; + } + return NO_ERROR; } @@ -891,6 +886,9 @@ int Surface::setBuffersGeometry(int w, int h, int format) // EGLConfig validation. mFormat = format; } + + mNextBufferCrop = Rect(0,0); + return NO_ERROR; } diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 4ba8b5bf1664..0d55f0861d60 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -43,16 +43,12 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ $(commonSources) \ EGLUtils.cpp \ - EventHub.cpp \ EventRecurrence.cpp \ FramebufferNativeWindow.cpp \ GraphicBuffer.cpp \ GraphicBufferAllocator.cpp \ GraphicBufferMapper.cpp \ GraphicLog.cpp \ - InputDispatcher.cpp \ - InputManager.cpp \ - InputReader.cpp \ InputTransport.cpp \ PixelFormat.cpp \ Rect.cpp \ diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp index 1663313f2e3f..f24a71d88d9d 100644 --- a/libs/ui/EGLUtils.cpp +++ b/libs/ui/EGLUtils.cpp @@ -66,12 +66,6 @@ status_t EGLUtils::selectConfigForPixelFormat( 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; @@ -81,23 +75,14 @@ status_t EGLUtils::selectConfigForPixelFormat( 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; + EGLint nativeVisualId = 0; + eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); + if (nativeVisualId>0 && format == nativeVisualId) { + config = configs[i]; break; } } diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp deleted file mode 100644 index 8f4bac6c75ff..000000000000 --- a/libs/ui/EventHub.cpp +++ /dev/null @@ -1,1092 +0,0 @@ -// -// Copyright 2005 The Android Open Source Project -// -// Handle events, like key input and vsync. -// -// The goal is to provide an optimized solution for Linux, not an -// implementation that works well across all platforms. We expect -// events to arrive on file descriptors, so that we can use a select() -// select() call to sleep. -// -// We can't select() on anything but network sockets in Windows, so we -// provide an alternative implementation of waitEvent for that platform. -// -#define LOG_TAG "EventHub" - -//#define LOG_NDEBUG 0 - -#include <ui/EventHub.h> -#include <hardware_legacy/power.h> - -#include <cutils/properties.h> -#include <utils/Log.h> -#include <utils/Timers.h> -#include <utils/threads.h> -#include <utils/Errors.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> - -#include <ui/KeyLayoutMap.h> -#include <ui/KeyCharacterMap.h> -#include <ui/VirtualKeyMap.h> - -#include <string.h> -#include <stdint.h> -#include <dirent.h> -#ifdef HAVE_INOTIFY -# include <sys/inotify.h> -#endif -#ifdef HAVE_ANDROID_OS -# include <sys/limits.h> /* not part of Linux */ -#endif -#include <sys/poll.h> -#include <sys/ioctl.h> - -/* this macro is used to tell if "bit" is set in "array" - * it selects a byte from the array, and does a boolean AND - * operation with a byte that only has the relevant bit set. - * eg. to check for the 12th bit, we do (array[1] & 1<<4) - */ -#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - -/* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) ((bits + 7) / 8) - -#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 - -// Fd at index 0 is always reserved for inotify -#define FIRST_ACTUAL_DEVICE_INDEX 1 - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " - -namespace android { - -static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *DEVICE_PATH = "/dev/input"; - -/* return the larger integer */ -static inline int max(int v1, int v2) -{ - return (v1 > v2) ? v1 : v2; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -// --- EventHub::Device --- - -EventHub::Device::Device(int fd, int32_t id, const String8& path, - const InputDeviceIdentifier& identifier) : - next(NULL), - fd(fd), id(id), path(path), identifier(identifier), - classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) { -} - -EventHub::Device::~Device() { - close(); - delete[] keyBitmask; - delete configuration; - delete virtualKeyMap; -} - -void EventHub::Device::close() { - if (fd >= 0) { - ::close(fd); - fd = -1; - } -} - - -// --- EventHub --- - -EventHub::EventHub(void) : - mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), - mOpeningDevices(0), mClosingDevices(0), - mOpened(false), mNeedToSendFinishedDeviceScan(false), - mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); -#ifdef EV_SW - memset(mSwitches, 0, sizeof(mSwitches)); -#endif -} - -EventHub::~EventHub(void) { - release_wake_lock(WAKE_LOCK_ID); - // we should free stuff here... -} - -status_t EventHub::errorCheck() const { - return mError; -} - -String8 EventHub::getDeviceName(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return String8(); - return device->identifier.name; -} - -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return 0; - return device->classes; -} - -void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->configuration) { - *outConfiguration = *device->configuration; - } else { - outConfiguration->clear(); - } -} - -status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->clear(); - - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return -1; - - struct input_absinfo info; - - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - LOGW("Error reading absolute controller %d for device %s fd %d\n", - axis, device->identifier.name.string(), device->fd); - return -errno; - } - - if (info.minimum != info.maximum) { - outAxisInfo->valid = true; - outAxisInfo->minValue = info.minimum; - outAxisInfo->maxValue = info.maximum; - outAxisInfo->flat = info.flat; - outAxisInfo->fuzz = info.fuzz; - } - return OK; -} - -int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != NULL) { - return getScanCodeStateLocked(device, scanCode); - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const { - uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; - memset(key_bitmask, 0, sizeof(key_bitmask)); - if (ioctl(device->fd, - EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { - return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != NULL) { - return getKeyCodeStateLocked(device, keyCode); - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const { - if (!device->keyMap.haveKeyLayout()) { - return AKEY_STATE_UNKNOWN; - } - - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes); - - uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; - memset(key_bitmask, 0, sizeof(key_bitmask)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { - #if 0 - for (size_t i=0; i<=KEY_MAX; i++) { - LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask)); - } - #endif - const size_t N = scanCodes.size(); - for (size_t i=0; i<N && i<=KEY_MAX; i++) { - int32_t sc = scanCodes.itemAt(i); - //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask)); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { -#ifdef EV_SW - if (sw >= 0 && sw <= SW_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != NULL) { - return getSwitchStateLocked(device, sw); - } - } -#endif - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const { - uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; - memset(sw_bitmask, 0, sizeof(sw_bitmask)); - if (ioctl(device->fd, - EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) { - return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - return AKEY_STATE_UNKNOWN; -} - -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != NULL) { - return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags); - } - return false; -} - -bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { - return false; - } - - Vector<int32_t> scanCodes; - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { - scanCodes.clear(); - - status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); - if (! err) { - // check the possible scan codes identified by the layout map against the - // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (test_bit(scanCodes[sc], device->keyBitmask)) { - outFlags[codeIndex] = 1; - break; - } - } - } - } - return true; -} - -status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, - int32_t* outKeycode, uint32_t* outFlags) const -{ - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); - if (err == NO_ERROR) { - return NO_ERROR; - } - } - - if (mBuiltInKeyboardId != -1) { - device = getDeviceLocked(mBuiltInKeyboardId); - - if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->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) -{ - AutoMutex _l(mLock); - - String8 name(deviceName); - mExcludedDevices.push_back(name); -} - -bool EventHub::hasLed(int32_t deviceId, int32_t led) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)]; - memset(bitmask, 0, sizeof(bitmask)); - if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) { - if (test_bit(led, bitmask)) { - return true; - } - } - } - return false; -} - -void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_LED; - ev.code = led; - ev.value = on ? 1 : 0; - - ssize_t nWrite; - do { - nWrite = write(device->fd, &ev, sizeof(struct input_event)); - } while (nWrite == -1 && errno == EINTR); - } -} - -void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const { - outVirtualKeys.clear(); - - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->virtualKeyMap) { - outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); - } -} - -EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { - if (deviceId == 0) { - deviceId = mBuiltInKeyboardId; - } - - size_t numDevices = mDevices.size(); - for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) { - Device* device = mDevices[i]; - if (device->id == deviceId) { - return device; - } - } - return NULL; -} - -bool EventHub::getEvent(RawEvent* outEvent) { - outEvent->deviceId = 0; - outEvent->type = 0; - outEvent->scanCode = 0; - outEvent->keyCode = 0; - outEvent->flags = 0; - outEvent->value = 0; - outEvent->when = 0; - - // 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; - mNeedToSendFinishedDeviceScan = true; - } - - for (;;) { - // Report any devices that had last been added/removed. - if (mClosingDevices != NULL) { - Device* device = mClosingDevices; - LOGV("Reporting device closed: id=%d, name=%s\n", - device->id, device->path.string()); - mClosingDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_REMOVED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - delete device; - mNeedToSendFinishedDeviceScan = true; - return true; - } - - if (mOpeningDevices != NULL) { - Device* device = mOpeningDevices; - LOGV("Reporting device opened: id=%d, name=%s\n", - device->id, device->path.string()); - mOpeningDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_ADDED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - mNeedToSendFinishedDeviceScan = true; - return true; - } - - if (mNeedToSendFinishedDeviceScan) { - mNeedToSendFinishedDeviceScan = false; - outEvent->type = FINISHED_DEVICE_SCAN; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; - } - - // Grab the next input event. - for (;;) { - // Consume buffered input events, if any. - if (mInputBufferIndex < mInputBufferCount) { - const struct input_event& iev = mInputBufferData[mInputBufferIndex++]; - const Device* device = mDevices[mInputFdIndex]; - - LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = iev.type; - outEvent->scanCode = iev.code; - outEvent->flags = 0; - if (iev.type == EV_KEY) { - outEvent->keyCode = AKEYCODE_UNKNOWN; - if (device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->map(iev.code, - &outEvent->keyCode, &outEvent->flags); - LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", - iev.code, outEvent->keyCode, outEvent->flags, err); - } - } else { - outEvent->keyCode = iev.code; - } - outEvent->value = iev.value; - - // Use an event timestamp in the same timebase as - // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis() - // as expected by the rest of the system. - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; - } - - // Finish reading all events from devices identified in previous poll(). - // This code assumes that mInputDeviceIndex is initially 0 and that the - // revents member of pollfd is initialized to 0 when the device is first added. - // Since mFds[0] is used for inotify, we process regular events starting at index 1. - mInputFdIndex += 1; - if (mInputFdIndex >= mFds.size()) { - break; - } - - const struct pollfd& pfd = mFds[mInputFdIndex]; - if (pfd.revents & POLLIN) { - int32_t readSize = read(pfd.fd, mInputBufferData, - sizeof(struct input_event) * INPUT_BUFFER_SIZE); - if (readSize < 0) { - if (errno != EAGAIN && errno != EINTR) { - LOGW("could not get event (errno=%d)", errno); - } - } else if ((readSize % sizeof(struct input_event)) != 0) { - LOGE("could not get event (wrong size: %d)", readSize); - } else { - mInputBufferCount = size_t(readSize) / sizeof(struct input_event); - mInputBufferIndex = 0; - } - } - } - -#if HAVE_INOTIFY - // readNotify() will modify mFDs and mFDCount, so this must be done after - // processing all other events. - if(mFds[0].revents & POLLIN) { - readNotify(mFds[0].fd); - mFds.editItemAt(0).revents = 0; - continue; // report added or removed devices immediately - } -#endif - - mInputFdIndex = 0; - - // Poll for events. Mind the wake lock dance! - // We hold a wake lock at all times except during poll(). This works due to some - // subtle choreography. When a device driver has pending (unread) events, it acquires - // a kernel wake lock. However, once the last pending event has been read, the device - // driver will release the kernel wake lock. To prevent the system from going to sleep - // when this happens, the EventHub holds onto its own user wake lock while the client - // is processing events. Thus the system can only sleep if there are no events - // pending or currently being processed. - release_wake_lock(WAKE_LOCK_ID); - - int pollResult = poll(mFds.editArray(), mFds.size(), -1); - - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - - if (pollResult <= 0) { - if (errno != EINTR) { - LOGW("poll failed (errno=%d)\n", errno); - usleep(100000); - } - } - } -} - -/* - * Open the platform-specific input device. - */ -bool EventHub::openPlatformInput(void) { - /* - * Open platform-specific input device(s). - */ - int res, fd; - -#ifdef HAVE_INOTIFY - fd = inotify_init(); - res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE); - if(res < 0) { - LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno)); - } -#else - /* - * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd. - * We allocate space for it and set it to something invalid. - */ - fd = -1; -#endif - - // Reserve fd index 0 for inotify. - struct pollfd pollfd; - pollfd.fd = fd; - pollfd.events = POLLIN; - pollfd.revents = 0; - mFds.push(pollfd); - mDevices.push(NULL); - - res = scanDir(DEVICE_PATH); - if(res < 0) { - LOGE("scan dir failed for %s\n", DEVICE_PATH); - } - - return true; -} - -// ---------------------------------------------------------------------------- - -static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { - const uint8_t* end = array + endIndex; - array += startIndex; - while (array != end) { - if (*(array++) != 0) { - return true; - } - } - return false; -} - -static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE -}; - -int EventHub::openDevice(const char *devicePath) { - char buffer[80]; - - LOGV("Opening device: %s", devicePath); - - AutoMutex _l(mLock); - - int fd = open(devicePath, O_RDWR); - if(fd < 0) { - LOGE("could not open %s, %s\n", devicePath, strerror(errno)); - return -1; - } - - InputDeviceIdentifier identifier; - - // Get device name. - if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.name.setTo(buffer); - } - - // 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 (identifier.name == test) { - LOGI("ignoring event id %s driver %s\n", devicePath, test); - close(fd); - return -1; - } - } - - // Get device driver version. - int driverVersion; - if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { - LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - - // Get device identifier. - struct input_id inputId; - if(ioctl(fd, EVIOCGID, &inputId)) { - LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - identifier.bus = inputId.bustype; - identifier.product = inputId.product; - identifier.vendor = inputId.vendor; - identifier.version = inputId.version; - - // Get device physical location. - if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.location.setTo(buffer); - } - - // Get device unique id. - if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.uniqueId.setTo(buffer); - } - - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - LOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - - // Allocate device. (The device object takes ownership of the fd at this point.) - int32_t deviceId = mNextDeviceId++; - Device* device = new Device(fd, deviceId, String8(devicePath), identifier); - -#if 0 - LOGI("add device %d: %s\n", deviceId, devicePath); - LOGI(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); - LOGI(" name: \"%s\"\n", identifier.name.string()); - LOGI(" location: \"%s\"\n", identifier.location.string()); - LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); - LOGI(" driver: v%d.%d.%d\n", - driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); -#endif - - // Load the configuration file for the device. - loadConfiguration(device); - - // Figure out the kinds of events the device reports. - - uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; - memset(key_bitmask, 0, sizeof(key_bitmask)); - - LOGV("Getting keys..."); - if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { - //LOGI("MAP\n"); - //for (int i = 0; i < sizeof(key_bitmask); i++) { - // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); - //} - - // See if this is a keyboard. Ignore everything in the button range except for - // gamepads which are also considered keyboards. - if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD), - sizeof_bit_array(BTN_DIGI)) - || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1))) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - - device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; - if (device->keyBitmask != NULL) { - memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); - } else { - delete device; - LOGE("out of memory allocating key bitmask"); - return -1; - } - } - } - - // See if this is a trackball (or mouse). - if (test_bit(BTN_MOUSE, key_bitmask)) { - uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; - memset(rel_bitmask, 0, sizeof(rel_bitmask)); - LOGV("Getting relative controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { - if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TRACKBALL; - } - } - } - - // See if this is a touch pad. - uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; - memset(abs_bitmask, 0, sizeof(abs_bitmask)); - LOGV("Getting absolute controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, abs_bitmask) - && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_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 |= INPUT_DEVICE_CLASS_TOUCHSCREEN; - } - } - -#ifdef EV_SW - // figure out the switches this device reports - uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; - memset(sw_bitmask, 0, sizeof(sw_bitmask)); - bool hasSwitches = false; - if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { - for (int i=0; i<EV_SW; i++) { - //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); - if (test_bit(i, sw_bitmask)) { - hasSwitches = true; - if (mSwitches[i] == 0) { - mSwitches[i] = device->id; - } - } - } - } - if (hasSwitches) { - device->classes |= INPUT_DEVICE_CLASS_SWITCH; - } -#endif - - if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) { - // Load the virtual keys for the touch screen, if any. - // We do this now so that we can make sure to load the keymap if necessary. - status_t status = loadVirtualKeyMap(device); - if (!status) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - } - - if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { - // Load the keymap for the device. - status_t status = loadKeyMap(device); - - // Set system properties for the keyboard. - setKeyboardProperties(device, false); - - // Register the keyboard as a built-in keyboard if it is eligible. - if (!status - && mBuiltInKeyboardId == -1 - && isEligibleBuiltInKeyboard(device->identifier, - device->configuration, &device->keyMap)) { - mBuiltInKeyboardId = device->id; - setKeyboardProperties(device, true); - } - - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycodeLocked(device, AKEYCODE_Q)) { - device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; - } - - // See if this device has a DPAD. - if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { - device->classes |= INPUT_DEVICE_CLASS_DPAD; - } - - // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { - if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { - device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; - break; - } - } - } - - // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == 0) { - LOGV("Dropping device: id=%d, path='%s', name='%s'", - deviceId, devicePath, device->identifier.name.string()); - delete device; - return -1; - } - - LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId)); - - struct pollfd pollfd; - pollfd.fd = fd; - pollfd.events = POLLIN; - pollfd.revents = 0; - mFds.push(pollfd); - mDevices.push(device); - - device->next = mOpeningDevices; - mOpeningDevices = device; - return 0; -} - -void EventHub::loadConfiguration(Device* device) { - device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( - device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); - if (device->configurationFile.isEmpty()) { - LOGD("No input device configuration file found for device '%s'.", - device->identifier.name.string()); - } else { - status_t status = PropertyMap::load(device->configurationFile, - &device->configuration); - if (status) { - LOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.string()); - } - } -} - -status_t EventHub::loadVirtualKeyMap(Device* device) { - // The virtual key map is supplied by the kernel as a system board property file. - String8 path; - path.append("/sys/board_properties/virtualkeys."); - path.append(device->identifier.name); - if (access(path.string(), R_OK)) { - return NAME_NOT_FOUND; - } - return VirtualKeyMap::load(path, &device->virtualKeyMap); -} - -status_t EventHub::loadKeyMap(Device* device) { - return device->keyMap.load(device->identifier, device->configuration); -} - -void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) { - int32_t id = builtInKeyboard ? 0 : device->id; - android::setKeyboardProperties(id, device->identifier, - device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile); -} - -void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) { - int32_t id = builtInKeyboard ? 0 : device->id; - android::clearKeyboardProperties(id); -} - -bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { - return false; - } - - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->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::closeDevice(const char *devicePath) { - AutoMutex _l(mLock); - - for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { - Device* device = mDevices[i]; - if (device->path == devicePath) { - LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", - device->path.string(), device->identifier.name.string(), device->id, - device->fd, device->classes); - -#ifdef EV_SW - for (int j=0; j<EV_SW; j++) { - if (mSwitches[j] == device->id) { - mSwitches[j] = 0; - } - } -#endif - - if (device->id == mBuiltInKeyboardId) { - LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mBuiltInKeyboardId); - mBuiltInKeyboardId = -1; - clearKeyboardProperties(device, true); - } - clearKeyboardProperties(device, false); - - mFds.removeAt(i); - mDevices.removeAt(i); - device->close(); - - device->next = mClosingDevices; - mClosingDevices = device; - return 0; - } - } - LOGE("remove device: %s not found\n", devicePath); - return -1; -} - -int EventHub::readNotify(int nfd) { -#ifdef HAVE_INOTIFY - int res; - char devname[PATH_MAX]; - char *filename; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event *event; - - LOGV("EventHub::readNotify nfd: %d\n", nfd); - res = read(nfd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - return 0; - LOGW("could not get event, %s\n", strerror(errno)); - return 1; - } - //printf("got %d bytes of event information\n", res); - - strcpy(devname, DEVICE_PATH); - filename = devname + strlen(devname); - *filename++ = '/'; - - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - if(event->len) { - strcpy(filename, event->name); - if(event->mask & IN_CREATE) { - openDevice(devname); - } - else { - closeDevice(devname); - } - } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } -#endif - return 0; -} - -int EventHub::scanDir(const char *dirname) -{ - char devname[PATH_MAX]; - char *filename; - DIR *dir; - struct dirent *de; - dir = opendir(dirname); - if(dir == NULL) - return -1; - strcpy(devname, dirname); - filename = devname + strlen(devname); - *filename++ = '/'; - while((de = readdir(dir))) { - if(de->d_name[0] == '.' && - (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && de->d_name[2] == '\0'))) - continue; - strcpy(filename, de->d_name); - openDevice(devname); - } - closedir(dir); - return 0; -} - -void EventHub::dump(String8& dump) { - dump.append("Event Hub State:\n"); - - { // acquire lock - AutoMutex _l(mLock); - - dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); - - dump.append(INDENT "Devices:\n"); - - for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { - const Device* device = mDevices[i]; - if (device) { - if (mBuiltInKeyboardId == device->id) { - dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.string()); - } else { - dump.appendFormat(INDENT2 "%d: %s\n", device->id, - device->identifier.name.string()); - } - dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); - dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); - dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); - dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); - dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.string()); - dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.string()); - dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.string()); - } - } - } // release lock -} - -}; // namespace android diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index ce84683375ba..33ef1fc8945c 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -61,7 +61,7 @@ void GraphicBufferAllocator::dump(String8& result) const const size_t c = list.size(); for (size_t i=0 ; i<c ; i++) { const alloc_rec_t& rec(list.valueAt(i)); - snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n", + snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n", list.keyAt(i), rec.size/1024.0f, rec.w, rec.s, rec.h, rec.format, rec.usage); result.append(buffer); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp deleted file mode 100644 index ed0cb8ec1e86..000000000000 --- a/libs/ui/InputDispatcher.cpp +++ /dev/null @@ -1,3710 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// The input dispatcher. -// -#define LOG_TAG "InputDispatcher" - -//#define LOG_NDEBUG 0 - -// Log detailed debug messages about each inbound event notification to the dispatcher. -#define DEBUG_INBOUND_EVENT_DETAILS 0 - -// Log detailed debug messages about each outbound event processed by the dispatcher. -#define DEBUG_OUTBOUND_EVENT_DETAILS 0 - -// Log debug messages about batching. -#define DEBUG_BATCHING 0 - -// Log debug messages about the dispatch cycle. -#define DEBUG_DISPATCH_CYCLE 0 - -// Log debug messages about registrations. -#define DEBUG_REGISTRATION 0 - -// Log debug messages about performance statistics. -#define DEBUG_PERFORMANCE_STATISTICS 0 - -// Log debug messages about input event injection. -#define DEBUG_INJECTION 0 - -// Log debug messages about input event throttling. -#define DEBUG_THROTTLING 0 - -// Log debug messages about input focus tracking. -#define DEBUG_FOCUS 0 - -// Log debug messages about the app switch latency optimization. -#define DEBUG_APP_SWITCH 0 - -#include <cutils/log.h> -#include <ui/InputDispatcher.h> -#include <ui/PowerManager.h> - -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> - -#define INDENT " " -#define INDENT2 " " - -namespace android { - -// Default input dispatching timeout if there is no focused application or paused window -// from which to determine an appropriate dispatching timeout. -const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec - -// Amount of time to allow for all pending events to be processed when an app switch -// key is on the way. This is used to preempt input dispatch and drop input events -// when an application takes too long to respond and the user has pressed an app switch key. -const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec - - -static inline nsecs_t now() { - return systemTime(SYSTEM_TIME_MONOTONIC); -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - -static bool isValidKeyAction(int32_t action) { - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; - } -} - -static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { - LOGE("Key event has invalid action code 0x%x", action); - return false; - } - return true; -} - -static bool isValidMotionAction(int32_t action, size_t pointerCount) { - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && size_t(index) < pointerCount; - } - default: - return false; - } -} - -static bool validateMotionEvent(int32_t action, size_t pointerCount, - const int32_t* pointerIds) { - if (! isValidMotionAction(action, pointerCount)) { - LOGE("Motion event has invalid action code 0x%x", action); - return false; - } - if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - LOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); - return false; - } - BitSet32 pointerIdBits; - for (size_t i = 0; i < pointerCount; i++) { - int32_t id = pointerIds[i]; - if (id < 0 || id > MAX_POINTER_ID) { - LOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); - return false; - } - if (pointerIdBits.hasBit(id)) { - LOGE("Motion event has duplicate pointer id %d", id); - return false; - } - pointerIdBits.markBit(id); - } - return true; -} - - -// --- InputWindow --- - -bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { - return x >= touchableAreaLeft && x <= touchableAreaRight - && y >= touchableAreaTop && y <= touchableAreaBottom; -} - -bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindow::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindow::supportsSplitTouch() const { - return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; -} - - -// --- InputDispatcher --- - -InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : - mPolicy(policy), - mPendingEvent(NULL), mAppSwitchDueTime(LONG_LONG_MAX), - mDispatchEnabled(true), mDispatchFrozen(false), - mFocusedWindow(NULL), - mFocusedApplication(NULL), - mCurrentInputTargetsValid(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { - mLooper = new Looper(false); - - mInboundQueue.headSentinel.refCount = -1; - mInboundQueue.headSentinel.type = EventEntry::TYPE_SENTINEL; - mInboundQueue.headSentinel.eventTime = LONG_LONG_MIN; - - mInboundQueue.tailSentinel.refCount = -1; - mInboundQueue.tailSentinel.type = EventEntry::TYPE_SENTINEL; - mInboundQueue.tailSentinel.eventTime = LONG_LONG_MAX; - - mKeyRepeatState.lastKeyEntry = NULL; - - int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); - mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; - mThrottleState.lastDeviceId = -1; - -#if DEBUG_THROTTLING - mThrottleState.originalSampleCount = 0; - LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); -#endif -} - -InputDispatcher::~InputDispatcher() { - { // acquire lock - AutoMutex _l(mLock); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - - while (mConnectionsByReceiveFd.size() != 0) { - unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel); - } -} - -void InputDispatcher::dispatchOnce() { - nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); - nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay(); - - nsecs_t nextWakeupTime = LONG_LONG_MAX; - { // acquire lock - AutoMutex _l(mLock); - dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime); - - if (runCommandsLockedInterruptible()) { - nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately - } - } // release lock - - // Wait for callback or timeout or wake. (make sure we round up, not down) - nsecs_t currentTime = now(); - int32_t timeoutMillis; - if (nextWakeupTime > currentTime) { - uint64_t timeout = uint64_t(nextWakeupTime - currentTime); - timeout = (timeout + 999999LL) / 1000000LL; - timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout); - } else { - timeoutMillis = 0; - } - - mLooper->pollOnce(timeoutMillis); -} - -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, - nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) { - nsecs_t currentTime = now(); - - // Reset the key repeat timer whenever we disallow key events, even if the next event - // is not a key. This is to ensure that we abort a key repeat if the device is just coming - // out of sleep. - if (keyRepeatTimeout < 0) { - resetKeyRepeatLocked(); - } - - // If dispatching is frozen, do not process timeouts or try to deliver any new events. - if (mDispatchFrozen) { -#if DEBUG_FOCUS - LOGD("Dispatch frozen. Waiting some more."); -#endif - return; - } - - // Optimize latency of app switches. - // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has - // been pressed. When it expires, we preempt dispatch and drop all other pending events. - bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; - if (mAppSwitchDueTime < *nextWakeupTime) { - *nextWakeupTime = mAppSwitchDueTime; - } - - // Ready to start a new event. - // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { - if (mInboundQueue.isEmpty()) { - if (isAppSwitchDue) { - // The inbound queue is empty so the app switch key we were waiting - // for will never arrive. Stop waiting for it. - resetPendingAppSwitchLocked(false); - isAppSwitchDue = false; - } - - // Synthesize a key repeat if appropriate. - if (mKeyRepeatState.lastKeyEntry) { - if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime, keyRepeatDelay); - } else { - if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { - *nextWakeupTime = mKeyRepeatState.nextRepeatTime; - } - } - } - if (! mPendingEvent) { - return; - } - } else { - // Inbound queue has at least one entry. - EventEntry* entry = mInboundQueue.headSentinel.next; - - // Throttle the entry if it is a move event and there are no - // other events behind it in the queue. Due to movement batching, additional - // samples may be appended to this event by the time the throttling timeout - // expires. - // TODO Make this smarter and consider throttling per device independently. - if (entry->type == EventEntry::TYPE_MOTION - && !isAppSwitchDue - && mDispatchEnabled - && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) - && !entry->isInjected()) { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - int32_t deviceId = motionEntry->deviceId; - uint32_t source = motionEntry->source; - if (! isAppSwitchDue - && motionEntry->next == & mInboundQueue.tailSentinel // exactly one event - && motionEntry->action == AMOTION_EVENT_ACTION_MOVE - && deviceId == mThrottleState.lastDeviceId - && source == mThrottleState.lastSource) { - nsecs_t nextTime = mThrottleState.lastEventTime - + mThrottleState.minTimeBetweenEvents; - if (currentTime < nextTime) { - // Throttle it! -#if DEBUG_THROTTLING - LOGD("Throttling - Delaying motion event for " - "device %d, source 0x%08x by up to %0.3fms.", - deviceId, source, (nextTime - currentTime) * 0.000001); -#endif - if (nextTime < *nextWakeupTime) { - *nextWakeupTime = nextTime; - } - if (mThrottleState.originalSampleCount == 0) { - mThrottleState.originalSampleCount = - motionEntry->countSamples(); - } - return; - } - } - -#if DEBUG_THROTTLING - if (mThrottleState.originalSampleCount != 0) { - uint32_t count = motionEntry->countSamples(); - LOGD("Throttling - Motion event sample count grew by %d from %d to %d.", - count - mThrottleState.originalSampleCount, - mThrottleState.originalSampleCount, count); - mThrottleState.originalSampleCount = 0; - } -#endif - - mThrottleState.lastEventTime = entry->eventTime < currentTime - ? entry->eventTime : currentTime; - mThrottleState.lastDeviceId = deviceId; - mThrottleState.lastSource = source; - } - - mInboundQueue.dequeue(entry); - mPendingEvent = entry; - } - - // Poke user activity for this event. - if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { - pokeUserActivityLocked(mPendingEvent); - } - } - - // Now we have an event to dispatch. - assert(mPendingEvent != NULL); - bool done = false; - DropReason dropReason = DROP_REASON_NOT_DROPPED; - if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { - dropReason = DROP_REASON_POLICY; - } else if (!mDispatchEnabled) { - dropReason = DROP_REASON_DISABLED; - } - switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast<ConfigurationChangedEntry*>(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEventLocked(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, - &dropReason, nextWakeupTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; - } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - - default: - assert(false); - break; - } - - if (done) { - if (dropReason != DROP_REASON_NOT_DROPPED) { - dropInboundEventLocked(mPendingEvent, dropReason); - } - - releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately - } -} - -bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { - bool needWake = mInboundQueue.isEmpty(); - mInboundQueue.enqueueAtTail(entry); - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); - if (isAppSwitchKeyEventLocked(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { -#if DEBUG_APP_SWITCH - LOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; - } - } - } - break; - } - } - - return needWake; -} - -void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { - const char* reason; - switch (dropReason) { - case DROP_REASON_POLICY: -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("Dropped event because policy consumed it."); -#endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - LOGI("Dropped event because input dispatch is disabled."); - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - LOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - default: - assert(false); - return; - } - - switch (entry->type) { - case EventEntry::TYPE_KEY: - synthesizeCancelationEventsForAllConnectionsLocked( - InputState::CANCEL_NON_POINTER_EVENTS, reason); - break; - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - synthesizeCancelationEventsForAllConnectionsLocked( - InputState::CANCEL_POINTER_EVENTS, reason); - } else { - synthesizeCancelationEventsForAllConnectionsLocked( - InputState::CANCEL_NON_POINTER_EVENTS, reason); - } - break; - } - } -} - -bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL; -} - -bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); -} - -bool InputDispatcher::isAppSwitchPendingLocked() { - return mAppSwitchDueTime != LONG_LONG_MAX; -} - -void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { - mAppSwitchDueTime = LONG_LONG_MAX; - -#if DEBUG_APP_SWITCH - if (handled) { - LOGD("App switch has arrived."); - } else { - LOGD("App switch was abandoned."); - } -#endif -} - -bool InputDispatcher::runCommandsLockedInterruptible() { - if (mCommandQueue.isEmpty()) { - return false; - } - - do { - CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); - - Command command = commandEntry->command; - (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' - - commandEntry->connection.clear(); - mAllocator.releaseCommandEntry(commandEntry); - } while (! mCommandQueue.isEmpty()); - return true; -} - -InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { - CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command); - mCommandQueue.enqueueAtTail(commandEntry); - return commandEntry; -} - -void InputDispatcher::drainInboundQueueLocked() { - while (! mInboundQueue.isEmpty()) { - EventEntry* entry = mInboundQueue.dequeueAtHead(); - releaseInboundEventLocked(entry); - } -} - -void InputDispatcher::releasePendingEventLocked() { - if (mPendingEvent) { - releaseInboundEventLocked(mPendingEvent); - mPendingEvent = NULL; - } -} - -void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { -#if DEBUG_DISPATCH_CYCLE - LOGD("Injected inbound event was dropped."); -#endif - setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); - } - mAllocator.releaseEventEntry(entry); -} - -void InputDispatcher::resetKeyRepeatLocked() { - if (mKeyRepeatState.lastKeyEntry) { - mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry); - mKeyRepeatState.lastKeyEntry = NULL; - } -} - -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( - nsecs_t currentTime, nsecs_t keyRepeatDelay) { - KeyEntry* entry = mKeyRepeatState.lastKeyEntry; - - // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) - | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; - if (entry->refCount == 1) { - mAllocator.recycleKeyEntry(entry); - entry->eventTime = currentTime; - entry->policyFlags = policyFlags; - entry->repeatCount += 1; - } else { - KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime, - entry->deviceId, entry->source, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); - - mKeyRepeatState.lastKeyEntry = newEntry; - mAllocator.releaseKeyEntry(entry); - - entry = newEntry; - } - entry->syntheticRepeat = true; - - // Increment reference count since we keep a reference to the event in - // mKeyRepeatState.lastKeyEntry in addition to the one we return. - entry->refCount += 1; - - if (entry->repeatCount == 1) { - entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; - } - - mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay; - return entry; -} - -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); -#endif - - // Reset key repeating in case a keyboard device was added or removed or something. - resetKeyRepeatLocked(); - - // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedInterruptible); - commandEntry->eventTime = entry->eventTime; - return true; -} - -bool InputDispatcher::dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, - DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && !entry->isInjected()) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { - // We have seen two identical key downs in a row which indicates that the device - // driver is automatically generating key repeats itself. We take note of the - // repeat here, but we disable our own next key repeat timer since it is clear that - // we will not need to synthesize key repeats ourselves. - entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves - } else { - // Not a repeat. Save key down state in case we do see a repeat later. - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout; - } - mKeyRepeatState.lastKeyEntry = entry; - entry->refCount += 1; - } else if (! entry->syntheticRepeat) { - resetKeyRepeatLocked(); - } - - entry->dispatchInProgress = true; - resetTargetsLocked(); - - logOutboundKeyDetailsLocked("dispatchKey - ", entry); - } - - // Give the policy a chance to intercept the key. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindow) { - commandEntry->inputChannel = mFocusedWindow->inputChannel; - } - commandEntry->keyEntry = entry; - entry->refCount += 1; - return false; // wait for the command to run - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } - } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { - if (*dropReason == DROP_REASON_NOT_DROPPED) { - *dropReason = DROP_REASON_POLICY; - } - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - resetTargetsLocked(); - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - // Identify targets. - if (! mCurrentInputTargetsValid) { - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, nextWakeupTime); - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - addMonitoringTargetsLocked(); - commitTargetsLocked(); - } - - // Dispatch the key. - dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false); - return true; -} - -void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "repeatCount=%d, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); -#endif -} - -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - entry->dispatchInProgress = true; - resetTargetsLocked(); - - logOutboundMotionDetailsLocked("dispatchMotion - ", entry); - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - resetTargetsLocked(); - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; - - // Identify targets. - if (! mCurrentInputTargetsValid) { - int32_t injectionResult; - if (isPointerEvent) { - // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, nextWakeupTime); - } else { - // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, nextWakeupTime); - } - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - addMonitoringTargetsLocked(); - commitTargetsLocked(); - } - - // Dispatch the motion. - dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false); - return true; -} - - -void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, - entry->metaState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); - - // Print the most recent sample that we have available, this may change due to batching. - size_t sampleCount = 1; - const MotionSample* sample = & entry->firstSample; - for (; sample->next != NULL; sample = sample->next) { - sampleCount += 1; - } - for (uint32_t i = 0; i < entry->pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerIds[i], - sample->pointerCoords[i].x, sample->pointerCoords[i].y, - sample->pointerCoords[i].pressure, sample->pointerCoords[i].size, - sample->pointerCoords[i].touchMajor, sample->pointerCoords[i].touchMinor, - sample->pointerCoords[i].toolMajor, sample->pointerCoords[i].toolMinor, - sample->pointerCoords[i].orientation); - } - - // Keep in mind that due to batching, it is possible for the number of samples actually - // dispatched to change before the application finally consumed them. - if (entry->action == AMOTION_EVENT_ACTION_MOVE) { - LOGD(" ... Total movement samples currently batched %d ...", sampleCount); - } -#endif -} - -void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, - EventEntry* eventEntry, bool resumeWithAppendedMotionSample) { -#if DEBUG_DISPATCH_CYCLE - LOGD("dispatchEventToCurrentInputTargets - " - "resumeWithAppendedMotionSample=%s", - toString(resumeWithAppendedMotionSample)); -#endif - - assert(eventEntry->dispatchInProgress); // should already have been set to true - - pokeUserActivityLocked(eventEntry); - - for (size_t i = 0; i < mCurrentInputTargets.size(); i++) { - const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i); - - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, - resumeWithAppendedMotionSample); - } else { -#if DEBUG_FOCUS - LOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().string()); -#endif - } - } -} - -void InputDispatcher::resetTargetsLocked() { - mCurrentInputTargetsValid = false; - mCurrentInputTargets.clear(); - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; -} - -void InputDispatcher::commitTargetsLocked() { - mCurrentInputTargetsValid = true; -} - -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, const InputApplication* application, const InputWindow* window, - nsecs_t* nextWakeupTime) { - if (application == NULL && window == NULL) { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { -#if DEBUG_FOCUS - LOGD("Waiting for system to become ready for input."); -#endif - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = LONG_LONG_MAX; - mInputTargetWaitTimeoutExpired = false; - } - } else { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { -#if DEBUG_FOCUS - LOGD("Waiting for application to become ready for input: %s", - getApplicationWindowLabelLocked(application, window).string()); -#endif - nsecs_t timeout = window ? window->dispatchingTimeout : - application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT; - - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = currentTime + timeout; - mInputTargetWaitTimeoutExpired = false; - } - } - - if (mInputTargetWaitTimeoutExpired) { - return INPUT_EVENT_INJECTION_TIMED_OUT; - } - - if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime); - - // Force poll loop to wake up immediately on next iteration once we get the - // ANR response back from the policy. - *nextWakeupTime = LONG_LONG_MIN; - return INPUT_EVENT_INJECTION_PENDING; - } else { - // Force poll loop to wake up when timeout is due. - if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { - *nextWakeupTime = mInputTargetWaitTimeoutTime; - } - return INPUT_EVENT_INJECTION_PENDING; - } -} - -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) { - if (newTimeout > 0) { - // Extend the timeout. - mInputTargetWaitTimeoutTime = now() + newTimeout; - } else { - // Give up. - mInputTargetWaitTimeoutExpired = true; - - // Release the touch targets. - mTouchState.reset(); - - // Input state will not be realistic. Mark it out of sync. - if (inputChannel.get()) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - if (connection->status == Connection::STATUS_NORMAL) { - synthesizeCancelationEventsForConnectionLocked( - connection, InputState::CANCEL_ALL_EVENTS, - "application not responding"); - } - } - } - } -} - -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { - if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - return currentTime - mInputTargetWaitStartTime; - } - return 0; -} - -void InputDispatcher::resetANRTimeoutsLocked() { -#if DEBUG_FOCUS - LOGD("Resetting ANR timeouts."); -#endif - - // Reset input target wait timeout. - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; -} - -int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, nsecs_t* nextWakeupTime) { - mCurrentInputTargets.clear(); - - int32_t injectionResult; - - // If there is no currently focused window and no focused application - // then drop the event. - if (! mFocusedWindow) { - if (mFocusedApplication) { -#if DEBUG_FOCUS - LOGD("Waiting because there is no focused window but there is a " - "focused application that may eventually add a window: %s.", - getApplicationWindowLabelLocked(mFocusedApplication, NULL).string()); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, NULL, nextWakeupTime); - goto Unresponsive; - } - - LOGI("Dropping event because there is no focused window or focused application."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check permissions. - if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - goto Failed; - } - - // If the currently focused window is paused then keep waiting. - if (mFocusedWindow->paused) { -#if DEBUG_FOCUS - LOGD("Waiting because focused window is paused."); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, mFocusedWindow, nextWakeupTime); - goto Unresponsive; - } - - // If the currently focused window is still working on previous events then keep waiting. - if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) { -#if DEBUG_FOCUS - LOGD("Waiting because focused window still processing previous input."); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, mFocusedWindow, nextWakeupTime); - goto Unresponsive; - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0)); - - // Done. -Failed: -Unresponsive: - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - LOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpendWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, nsecs_t* nextWakeupTime) { - enum InjectionPermission { - INJECTION_PERMISSION_UNKNOWN, - INJECTION_PERMISSION_GRANTED, - INJECTION_PERMISSION_DENIED - }; - - mCurrentInputTargets.clear(); - - nsecs_t startTime = now(); - - // For security reasons, we defer updating the touch state until we are sure that - // event injection will be allowed. - // - // FIXME In the original code, screenWasOff could never be set to true. - // The reason is that the POLICY_FLAG_WOKE_HERE - // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw - // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was - // actually enqueued using the policyFlags that appeared in the final EV_SYN - // events upon which no preprocessing took place. So policyFlags was always 0. - // In the new native input dispatcher we're a bit more careful about event - // preprocessing so the touches we receive can actually have non-zero policyFlags. - // Unfortunately we obtain undesirable behavior. - // - // Here's what happens: - // - // When the device dims in anticipation of going to sleep, touches - // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause - // the device to brighten and reset the user activity timer. - // Touches on other windows (such as the launcher window) - // are dropped. Then after a moment, the device goes to sleep. Oops. - // - // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE - // instead of POLICY_FLAG_WOKE_HERE... - // - bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE; - - int32_t action = entry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - - // Update the touch state as needed based on the properties of the touch event. - int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; - InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - mTempTouchState.reset(); - mTempTouchState.down = true; - } else { - mTempTouchState.copyFrom(mTouchState); - } - - bool isSplit = mTempTouchState.split && mTempTouchState.down; - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { - /* Case 1: New splittable pointer going down. */ - - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex].x); - int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].y); - const InputWindow* newTouchedWindow = NULL; - const InputWindow* topErrorWindow = NULL; - - // Traverse windows from front to back to find touched window and outside targets. - size_t numWindows = mWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - const InputWindow* window = & mWindows.editItemAt(i); - int32_t flags = window->layoutParamsFlags; - - if (flags & InputWindow::FLAG_SYSTEM_ERROR) { - if (! topErrorWindow) { - topErrorWindow = window; - } - } - - if (window->visible) { - if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE - | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || window->touchableAreaContainsPoint(x, y)) { - if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) { - newTouchedWindow = window; - } - break; // found touched window, exit window loop - } - } - - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) { - int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE; - if (isWindowObscuredAtPointLocked(window, x, y)) { - outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0)); - } - } - } - - // If there is an error window but it is not taking focus (typically because - // it is invisible) then wait for it. Any other focused window may in - // fact be in ANR state. - if (topErrorWindow && newTouchedWindow != topErrorWindow) { -#if DEBUG_FOCUS - LOGD("Waiting because system error window is pending."); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, NULL, nextWakeupTime); - injectionPermission = INJECTION_PERMISSION_UNKNOWN; - goto Unresponsive; - } - - // Figure out whether splitting will be allowed for this window. - if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) { - // New window supports splitting. - isSplit = true; - } else if (isSplit) { - // New window does not support splitting but we have already split events. - // Assign the pointer to the first foreground window we find. - // (May be NULL which is why we put this code block before the next check.) - newTouchedWindow = mTempTouchState.getFirstForegroundWindow(); - } - - // If we did not find a touched window then fail. - if (! newTouchedWindow) { - if (mFocusedApplication) { -#if DEBUG_FOCUS - LOGD("Waiting because there is no touched window but there is a " - "focused application that may eventually add a new window: %s.", - getApplicationWindowLabelLocked(mFocusedApplication, NULL).string()); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, NULL, nextWakeupTime); - goto Unresponsive; - } - - LOGI("Dropping event because there is no touched window or focused application."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - // Update the temporary touch state. - BitSet32 pointerIds; - if (isSplit) { - uint32_t pointerId = entry->pointerIds[pointerIndex]; - pointerIds.markBit(pointerId); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds); - } else { - /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ - - // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { -#if DEBUG_INPUT_DISPATCHER_POLICY - LOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - } - - // Check permission to inject into all touched foreground windows and ensure there - // is at least one touched foreground window. - { - bool haveForegroundWindow = false; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - injectionPermission = INJECTION_PERMISSION_DENIED; - goto Failed; - } - } - } - if (! haveForegroundWindow) { -#if DEBUG_INPUT_DISPATCHER_POLICY - LOGD("Dropping event because there is no touched foreground window to receive it."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Permission granted to injection into all touched foreground windows. - injectionPermission = INJECTION_PERMISSION_GRANTED; - } - - // Ensure all touched foreground windows are ready for new input. - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - // If the touched window is paused then keep waiting. - if (touchedWindow.window->paused) { -#if DEBUG_INPUT_DISPATCHER_POLICY - LOGD("Waiting because touched window is paused."); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.window, nextWakeupTime); - goto Unresponsive; - } - - // If the touched window is still working on previous events then keep waiting. - if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) { -#if DEBUG_FOCUS - LOGD("Waiting because touched window still processing previous input."); -#endif - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.window, nextWakeupTime); - goto Unresponsive; - } - } - } - - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow(); - if (foregroundWindow->hasWallpaper) { - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow* window = & mWindows[i]; - if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(window, - InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0)); - } - } - } - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); - addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags, - touchedWindow.pointerIds); - } - - // Drop the outside touch window since we will not care about them in the next iteration. - mTempTouchState.removeOutsideTouchWindows(); - -Failed: - // Check injection permission once and for all. - if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { - if (checkInjectionPermission(NULL, entry->injectionState)) { - injectionPermission = INJECTION_PERMISSION_GRANTED; - } else { - injectionPermission = INJECTION_PERMISSION_DENIED; - } - } - - // Update final pieces of touch state if the injector had permission. - if (injectionPermission == INJECTION_PERMISSION_GRANTED) { - if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { - // All pointers up or canceled. - mTempTouchState.reset(); - } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - // First pointer went down. - if (mTouchState.down) { -#if DEBUG_FOCUS - LOGD("Pointer down received while already down."); -#endif - } - } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - // One pointer went up. - if (isSplit) { - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry->pointerIds[pointerIndex]; - - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { - TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); - if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { - touchedWindow.pointerIds.clearBit(pointerId); - if (touchedWindow.pointerIds.isEmpty()) { - mTempTouchState.windows.removeAt(i); - continue; - } - } - i += 1; - } - } - } - - // Save changes to touch state. - mTouchState.copyFrom(mTempTouchState); - } else { -#if DEBUG_FOCUS - LOGD("Not updating touch focus because injection was denied."); -#endif - } - -Unresponsive: - // Reset temporary touch state to ensure we release unnecessary references to input channels. - mTempTouchState.reset(); - - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags, - BitSet32 pointerIds) { - mCurrentInputTargets.push(); - - InputTarget& target = mCurrentInputTargets.editTop(); - target.inputChannel = window->inputChannel; - target.flags = targetFlags; - target.xOffset = - window->frameLeft; - target.yOffset = - window->frameTop; - target.pointerIds = pointerIds; -} - -void InputDispatcher::addMonitoringTargetsLocked() { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - mCurrentInputTargets.push(); - - InputTarget& target = mCurrentInputTargets.editTop(); - target.inputChannel = mMonitoringChannels[i]; - target.flags = 0; - target.xOffset = 0; - target.yOffset = 0; - } -} - -bool InputDispatcher::checkInjectionPermission(const InputWindow* window, - const InjectionState* injectionState) { - if (injectionState - && (window == NULL || window->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { - if (window) { - LOGW("Permission denied: injecting event from pid %d uid %d to window " - "with input channel %s owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - window->inputChannel->getName().string(), - window->ownerUid); - } else { - LOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; - } - return true; -} - -bool InputDispatcher::isWindowObscuredAtPointLocked( - const InputWindow* window, int32_t x, int32_t y) const { - size_t numWindows = mWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - const InputWindow* other = & mWindows.itemAt(i); - if (other == window) { - break; - } - if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) { - return true; - } - } - return false; -} - -bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) { - ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - return connection->outboundQueue.isEmpty(); - } else { - return true; - } -} - -String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application, - const InputWindow* window) { - if (application) { - if (window) { - String8 label(application->name); - label.append(" - "); - label.append(window->name); - return label; - } else { - return application->name; - } - } else if (window) { - return window->name; - } else { - return String8("<unknown application or window>"); - } -} - -void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { - int32_t eventType = POWER_MANAGER_BUTTON_EVENT; - switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } - - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - eventType = POWER_MANAGER_TOUCH_EVENT; - } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; - } - break; - } - } - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); - commandEntry->eventTime = eventEntry->eventTime; - commandEntry->userActivityEventType = eventType; -} - -void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - bool resumeWithAppendedMotionSample) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, " - "xOffset=%f, yOffset=%f, " - "windowType=%d, pointerIds=0x%x, " - "resumeWithAppendedMotionSample=%s", - connection->getInputChannelName(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->windowType, inputTarget->pointerIds.value, - toString(resumeWithAppendedMotionSample)); -#endif - - // Make sure we are never called for streaming when splitting across multiple windows. - bool isSplit = inputTarget->flags & InputTarget::FLAG_SPLIT; - assert(! (resumeWithAppendedMotionSample && isSplit)); - - // Skip this event if the connection status is not normal. - // We don't want to enqueue additional outbound events if the connection is broken. - if (connection->status != Connection::STATUS_NORMAL) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName(), connection->getStatusLabel()); -#endif - return; - } - - // Split a motion event if needed. - if (isSplit) { - assert(eventEntry->type == EventEntry::TYPE_MOTION); - - MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry); - if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); -#if DEBUG_FOCUS - LOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName()); - logOutboundMotionDetailsLocked(" ", splitMotionEntry); -#endif - eventEntry = splitMotionEntry; - } - } - - // Resume the dispatch cycle with a freshly appended motion sample. - // First we check that the last dispatch entry in the outbound queue is for the same - // motion event to which we appended the motion sample. If we find such a dispatch - // entry, and if it is currently in progress then we try to stream the new sample. - bool wasEmpty = connection->outboundQueue.isEmpty(); - - if (! wasEmpty && resumeWithAppendedMotionSample) { - DispatchEntry* motionEventDispatchEntry = - connection->findQueuedDispatchEntryForEvent(eventEntry); - if (motionEventDispatchEntry) { - // If the dispatch entry is not in progress, then we must be busy dispatching an - // earlier event. Not a problem, the motion event is on the outbound queue and will - // be dispatched later. - if (! motionEventDispatchEntry->inProgress) { -#if DEBUG_BATCHING - LOGD("channel '%s' ~ Not streaming because the motion event has " - "not yet been dispatched. " - "(Waiting for earlier events to be consumed.)", - connection->getInputChannelName()); -#endif - return; - } - - // If the dispatch entry is in progress but it already has a tail of pending - // motion samples, then it must mean that the shared memory buffer filled up. - // Not a problem, when this dispatch cycle is finished, we will eventually start - // a new dispatch cycle to process the tail and that tail includes the newly - // appended motion sample. - if (motionEventDispatchEntry->tailMotionSample) { -#if DEBUG_BATCHING - LOGD("channel '%s' ~ Not streaming because no new samples can " - "be appended to the motion event in this dispatch cycle. " - "(Waiting for next dispatch cycle to start.)", - connection->getInputChannelName()); -#endif - return; - } - - // The dispatch entry is in progress and is still potentially open for streaming. - // Try to stream the new motion sample. This might fail if the consumer has already - // consumed the motion event (or if the channel is broken). - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - MotionSample* appendedMotionSample = motionEntry->lastSample; - status_t status = connection->inputPublisher.appendMotionSample( - appendedMotionSample->eventTime, appendedMotionSample->pointerCoords); - if (status == OK) { -#if DEBUG_BATCHING - LOGD("channel '%s' ~ Successfully streamed new motion sample.", - connection->getInputChannelName()); -#endif - return; - } - -#if DEBUG_BATCHING - if (status == NO_MEMORY) { - LOGD("channel '%s' ~ Could not append motion sample to currently " - "dispatched move event because the shared memory buffer is full. " - "(Waiting for next dispatch cycle to start.)", - connection->getInputChannelName()); - } else if (status == status_t(FAILED_TRANSACTION)) { - LOGD("channel '%s' ~ Could not append motion sample to currently " - "dispatched move event because the event has already been consumed. " - "(Waiting for next dispatch cycle to start.)", - connection->getInputChannelName()); - } else { - LOGD("channel '%s' ~ Could not append motion sample to currently " - "dispatched move event due to an error, status=%d. " - "(Waiting for next dispatch cycle to start.)", - connection->getInputChannelName(), status); - } -#endif - // Failed to stream. Start a new tail of pending motion samples to dispatch - // in the next cycle. - motionEventDispatchEntry->tailMotionSample = appendedMotionSample; - return; - } - } - - // This is a new event. - // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref - inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset); - if (dispatchEntry->hasForegroundTarget()) { - incrementPendingForegroundDispatchesLocked(eventEntry); - } - - // Handle the case where we could not stream a new motion sample because the consumer has - // already consumed the motion event (otherwise the corresponding dispatch entry would - // still be in the outbound queue for this connection). We set the head motion sample - // to the list starting with the newly appended motion sample. - if (resumeWithAppendedMotionSample) { -#if DEBUG_BATCHING - LOGD("channel '%s' ~ Preparing a new dispatch cycle for additional motion samples " - "that cannot be streamed because the motion event has already been consumed.", - connection->getInputChannelName()); -#endif - MotionSample* appendedMotionSample = static_cast<MotionEntry*>(eventEntry)->lastSample; - dispatchEntry->headMotionSample = appendedMotionSample; - } - - // Enqueue the dispatch entry. - connection->outboundQueue.enqueueAtTail(dispatchEntry); - - // If the outbound queue was previously empty, start the dispatch cycle going. - if (wasEmpty) { - activateConnectionLocked(connection.get()); - startDispatchCycleLocked(currentTime, connection); - } -} - -void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName()); -#endif - - assert(connection->status == Connection::STATUS_NORMAL); - assert(! connection->outboundQueue.isEmpty()); - - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; - assert(! dispatchEntry->inProgress); - - // Mark the dispatch entry as in progress. - dispatchEntry->inProgress = true; - - // Update the connection's input state. - EventEntry* eventEntry = dispatchEntry->eventEntry; - InputState::Consistency consistency = connection->inputState.trackEvent(eventEntry); - -#if FILTER_INPUT_EVENTS - // Filter out inconsistent sequences of input events. - // The input system may drop or inject events in a way that could violate implicit - // invariants on input state and potentially cause an application to crash - // or think that a key or pointer is stuck down. Technically we make no guarantees - // of consistency but it would be nice to improve on this where possible. - // XXX: This code is a proof of concept only. Not ready for prime time. - if (consistency == InputState::TOLERABLE) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ Sending an event that is inconsistent with the connection's " - "current input state but that is likely to be tolerated by the application.", - connection->getInputChannelName()); -#endif - } else if (consistency == InputState::BROKEN) { - LOGI("channel '%s' ~ Dropping an event that is inconsistent with the connection's " - "current input state and that is likely to cause the application to crash.", - connection->getInputChannelName()); - startNextDispatchCycleLocked(currentTime, connection); - return; - } -#endif - - // Publish the event. - status_t status; - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - - // Apply target flags. - int32_t action = keyEntry->action; - int32_t flags = keyEntry->flags; - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source, - action, flags, keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - - if (status) { - LOGE("channel '%s' ~ Could not publish key event, " - "status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - - // Apply target flags. - int32_t action = motionEntry->action; - int32_t flags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) { - action = AMOTION_EVENT_ACTION_OUTSIDE; - } - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - - // If headMotionSample is non-NULL, then it points to the first new sample that we - // were unable to dispatch during the previous cycle so we resume dispatching from - // that point in the list of motion samples. - // Otherwise, we just start from the first sample of the motion event. - MotionSample* firstMotionSample = dispatchEntry->headMotionSample; - if (! firstMotionSample) { - firstMotionSample = & motionEntry->firstSample; - } - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset; - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - xOffset = dispatchEntry->xOffset; - yOffset = dispatchEntry->yOffset; - } else { - xOffset = 0.0f; - yOffset = 0.0f; - } - - // Publish the motion event and the first motion sample. - status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId, - motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, firstMotionSample->eventTime, - motionEntry->pointerCount, motionEntry->pointerIds, - firstMotionSample->pointerCoords); - - if (status) { - LOGE("channel '%s' ~ Could not publish motion event, " - "status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; - } - - // Append additional motion samples. - MotionSample* nextMotionSample = firstMotionSample->next; - for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) { - status = connection->inputPublisher.appendMotionSample( - nextMotionSample->eventTime, nextMotionSample->pointerCoords); - if (status == NO_MEMORY) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will " - "be sent in the next dispatch cycle.", - connection->getInputChannelName()); -#endif - break; - } - if (status != OK) { - LOGE("channel '%s' ~ Could not append motion sample " - "for a reason other than out of memory, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; - } - } - - // Remember the next motion sample that we could not dispatch, in case we ran out - // of space in the shared memory buffer. - dispatchEntry->tailMotionSample = nextMotionSample; - break; - } - - default: { - assert(false); - } - } - - // Send the dispatch signal. - status = connection->inputPublisher.sendDispatchSignal(); - if (status) { - LOGE("channel '%s' ~ Could not send dispatch signal, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; - } - - // Record information about the newly started dispatch cycle. - connection->lastEventTime = eventEntry->eventTime; - connection->lastDispatchTime = currentTime; - - // Notify other system components. - onDispatchCycleStartedLocked(currentTime, connection); -} - -void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, bool handled) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, " - "%01.1fms since dispatch, handled=%s", - connection->getInputChannelName(), - connection->getEventLatencyMillis(currentTime), - connection->getDispatchLatencyMillis(currentTime), - toString(handled)); -#endif - - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { - return; - } - - // Reset the publisher since the event has been consumed. - // We do this now so that the publisher can release some of its internal resources - // while waiting for the next dispatch cycle to begin. - status_t status = connection->inputPublisher.reset(); - if (status) { - LOGE("channel '%s' ~ Could not reset publisher, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; - } - - // Notify other system components and prepare to start the next dispatch cycle. - onDispatchCycleFinishedLocked(currentTime, connection, handled); -} - -void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { - // Start the next dispatch cycle for this connection. - while (! connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; - if (dispatchEntry->inProgress) { - // Finish or resume current event in progress. - if (dispatchEntry->tailMotionSample) { - // We have a tail of undispatched motion samples. - // Reuse the same DispatchEntry and start a new cycle. - dispatchEntry->inProgress = false; - dispatchEntry->headMotionSample = dispatchEntry->tailMotionSample; - dispatchEntry->tailMotionSample = NULL; - startDispatchCycleLocked(currentTime, connection); - return; - } - // Finished. - connection->outboundQueue.dequeueAtHead(); - if (dispatchEntry->hasForegroundTarget()) { - decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); - } - mAllocator.releaseDispatchEntry(dispatchEntry); - } else { - // If the head is not in progress, then we must have already dequeued the in - // progress event, which means we actually aborted it. - // So just start the next event for this connection. - startDispatchCycleLocked(currentTime, connection); - return; - } - } - - // Outbound queue is empty, deactivate the connection. - deactivateConnectionLocked(connection.get()); -} - -void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { -#if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s", - connection->getInputChannelName(), toString(broken)); -#endif - - // Clear the outbound queue. - drainOutboundQueueLocked(connection.get()); - - // The connection appears to be unrecoverably broken. - // Ignore already broken or zombie connections. - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; - - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } -} - -void InputDispatcher::drainOutboundQueueLocked(Connection* connection) { - while (! connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead(); - if (dispatchEntry->hasForegroundTarget()) { - decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); - } - mAllocator.releaseDispatchEntry(dispatchEntry); - } - - deactivateConnectionLocked(connection); -} - -int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) { - InputDispatcher* d = static_cast<InputDispatcher*>(data); - - { // acquire lock - AutoMutex _l(d->mLock); - - ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd); - if (connectionIndex < 0) { - LOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", receiveFd, events); - return 0; // remove the callback - } - - nsecs_t currentTime = now(); - - sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex); - if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { - LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName(), events); - d->abortBrokenDispatchCycleLocked(currentTime, connection); - d->runCommandsLockedInterruptible(); - return 0; // remove the callback - } - - if (! (events & ALOOPER_EVENT_INPUT)) { - LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName(), events); - return 1; - } - - bool handled = false; - status_t status = connection->inputPublisher.receiveFinishedSignal(&handled); - if (status) { - LOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName(), status); - d->abortBrokenDispatchCycleLocked(currentTime, connection); - d->runCommandsLockedInterruptible(); - return 0; // remove the callback - } - - d->finishDispatchCycleLocked(currentTime, connection, handled); - d->runCommandsLockedInterruptible(); - return 1; - } // release lock -} - -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( - InputState::CancelationOptions options, const char* reason) { - for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByReceiveFd.valueAt(i), options, reason); - } -} - -void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( - const sp<InputChannel>& channel, InputState::CancelationOptions options, - const char* reason) { - ssize_t index = getConnectionIndexLocked(channel); - if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByReceiveFd.valueAt(index), options, reason); - } -} - -void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( - const sp<Connection>& connection, InputState::CancelationOptions options, - const char* reason) { - nsecs_t currentTime = now(); - - mTempCancelationEvents.clear(); - connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator, - mTempCancelationEvents, options); - - if (! mTempCancelationEvents.isEmpty() - && connection->status != Connection::STATUS_BROKEN) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " - "with reality: %s, options=%d.", - connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options); -#endif - for (size_t i = 0; i < mTempCancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked("cancel - ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked("cancel - ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; - } - - int32_t xOffset, yOffset; - const InputWindow* window = getWindowLocked(connection->inputChannel); - if (window) { - xOffset = -window->frameLeft; - yOffset = -window->frameTop; - } else { - xOffset = 0; - yOffset = 0; - } - - DispatchEntry* cancelationDispatchEntry = - mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref - 0, xOffset, yOffset); - connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry); - - mAllocator.releaseEventEntry(cancelationEventEntry); - } - - if (!connection->outboundQueue.headSentinel.next->inProgress) { - startDispatchCycleLocked(currentTime, connection); - } - } -} - -InputDispatcher::MotionEntry* -InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { - assert(pointerIds.value != 0); - - uint32_t splitPointerIndexMap[MAX_POINTERS]; - int32_t splitPointerIds[MAX_POINTERS]; - PointerCoords splitPointerCoords[MAX_POINTERS]; - - uint32_t originalPointerCount = originalMotionEntry->pointerCount; - uint32_t splitPointerCount = 0; - - for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { - int32_t pointerId = uint32_t(originalMotionEntry->pointerIds[originalPointerIndex]); - if (pointerIds.hasBit(pointerId)) { - splitPointerIndexMap[splitPointerCount] = originalPointerIndex; - splitPointerIds[splitPointerCount] = pointerId; - splitPointerCoords[splitPointerCount] = - originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]; - splitPointerCount += 1; - } - } - assert(splitPointerCount == pointerIds.count()); - - int32_t action = originalMotionEntry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); - int32_t pointerId = originalMotionEntry->pointerIds[originalPointerIndex]; - if (pointerIds.hasBit(pointerId)) { - if (pointerIds.count() == 1) { - // The first/last pointer went down/up. - action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - // A secondary pointer went down/up. - uint32_t splitPointerIndex = 0; - while (pointerId != splitPointerIds[splitPointerIndex]) { - splitPointerIndex += 1; - } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - } - } else { - // An unrelated pointer changed. - action = AMOTION_EVENT_ACTION_MOVE; - } - } - - MotionEntry* splitMotionEntry = mAllocator.obtainMotionEntry( - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - splitPointerCount, splitPointerIds, splitPointerCoords); - - for (MotionSample* originalMotionSample = originalMotionEntry->firstSample.next; - originalMotionSample != NULL; originalMotionSample = originalMotionSample->next) { - for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount; - splitPointerIndex++) { - uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex]; - splitPointerCoords[splitPointerIndex] = - originalMotionSample->pointerCoords[originalPointerIndex]; - } - - mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime, - splitPointerCoords); - } - - return splitMotionEntry; -} - -void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry(eventTime); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source, - uint32_t policyFlags, int32_t action, int32_t flags, - int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", - eventTime, deviceId, source, policyFlags, action, flags, - keyCode, scanCode, metaState, downTime); -#endif - if (! validateKeyEvent(action)) { - return; - } - - if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { - policyFlags |= POLICY_FLAG_VIRTUAL; - flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - - policyFlags |= POLICY_FLAG_TRUSTED; - - KeyEvent event; - event.initialize(deviceId, source, action, flags, keyCode, scanCode, - metaState, 0, downTime, eventTime); - - mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - int32_t repeatCount = 0; - KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime, - deviceId, source, policyFlags, action, flags, keyCode, scanCode, - metaState, repeatCount, downTime); - - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source, - uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", - eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags, - xPrecision, yPrecision, downTime); - for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, pointerIds[i], pointerCoords[i].x, pointerCoords[i].y, - pointerCoords[i].pressure, pointerCoords[i].size, - pointerCoords[i].touchMajor, pointerCoords[i].touchMinor, - pointerCoords[i].toolMajor, pointerCoords[i].toolMinor, - pointerCoords[i].orientation); - } -#endif - if (! validateMotionEvent(action, pointerCount, pointerIds)) { - return; - } - - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - // Attempt batching and streaming of move events. - if (action == AMOTION_EVENT_ACTION_MOVE) { - // BATCHING CASE - // - // Try to append a move sample to the tail of the inbound queue for this device. - // Give up if we encounter a non-move motion event for this device since that - // means we cannot append any new samples until a new motion event has started. - for (EventEntry* entry = mInboundQueue.tailSentinel.prev; - entry != & mInboundQueue.headSentinel; entry = entry->prev) { - if (entry->type != EventEntry::TYPE_MOTION) { - // Keep looking for motion events. - continue; - } - - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->deviceId != deviceId) { - // Keep looking for this device. - continue; - } - - if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE - || motionEntry->pointerCount != pointerCount - || motionEntry->isInjected()) { - // Last motion event in the queue for this device is not compatible for - // appending new samples. Stop here. - goto NoBatchingOrStreaming; - } - - // The last motion event is a move and is compatible for appending. - // Do the batching magic. - mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords); -#if DEBUG_BATCHING - LOGD("Appended motion sample onto batch for most recent " - "motion event for this device in the inbound queue."); -#endif - return; // done! - } - - // STREAMING CASE - // - // There is no pending motion event (of any kind) for this device in the inbound queue. - // Search the outbound queue for the current foreground targets to find a dispatched - // motion event that is still in progress. If found, then, appen the new sample to - // that event and push it out to all current targets. The logic in - // prepareDispatchCycleLocked takes care of the case where some targets may - // already have consumed the motion event by starting a new dispatch cycle if needed. - if (mCurrentInputTargetsValid) { - for (size_t i = 0; i < mCurrentInputTargets.size(); i++) { - const InputTarget& inputTarget = mCurrentInputTargets[i]; - if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) { - // Skip non-foreground targets. We only want to stream if there is at - // least one foreground target whose dispatch is still in progress. - continue; - } - - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex < 0) { - // Connection must no longer be valid. - continue; - } - - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - if (connection->outboundQueue.isEmpty()) { - // This foreground target has an empty outbound queue. - continue; - } - - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; - if (! dispatchEntry->inProgress - || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION - || dispatchEntry->isSplit()) { - // No motion event is being dispatched, or it is being split across - // windows in which case we cannot stream. - continue; - } - - MotionEntry* motionEntry = static_cast<MotionEntry*>( - dispatchEntry->eventEntry); - if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE - || motionEntry->deviceId != deviceId - || motionEntry->pointerCount != pointerCount - || motionEntry->isInjected()) { - // The motion event is not compatible with this move. - continue; - } - - // Hurray! This foreground target is currently dispatching a move event - // that we can stream onto. Append the motion sample and resume dispatch. - mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords); -#if DEBUG_BATCHING - LOGD("Appended motion sample onto batch for most recently dispatched " - "motion event for this device in the outbound queues. " - "Attempting to stream the motion sample."); -#endif - nsecs_t currentTime = now(); - dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry, - true /*resumeWithAppendedMotionSample*/); - - runCommandsLockedInterruptible(); - return; // done! - } - } - -NoBatchingOrStreaming:; - } - - // Just enqueue a new motion event. - MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime, - deviceId, source, policyFlags, action, flags, metaState, edgeFlags, - xPrecision, yPrecision, downTime, - pointerCount, pointerIds, pointerCoords); - - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, - uint32_t policyFlags) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x", - switchCode, switchValue, policyFlags); -#endif - - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags); -} - -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis); -#endif - - nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); - - uint32_t policyFlags = POLICY_FLAG_INJECTED; - if (hasInjectionPermission(injectorPid, injectorUid)) { - policyFlags |= POLICY_FLAG_TRUSTED; - } - - EventEntry* injectedEntry; - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event); - int32_t action = keyEvent->getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent->getFlags(); - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } - - mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - mLock.lock(); - injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), - policyFlags, action, flags, - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const int32_t* pointerIds = motionEvent->getPointerIds(); - if (! validateMotionEvent(action, pointerCount, pointerIds)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - nsecs_t eventTime = motionEvent->getEventTime(); - mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); - - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), uint32_t(pointerCount), - pointerIds, samplePointerCoords); - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); - } - injectedEntry = motionEntry; - break; - } - - default: - LOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; - } - - InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; - } - - injectionState->refCount += 1; - injectedEntry->injectionState = injectionState; - - bool needWake = enqueueInboundEventLocked(injectedEntry); - mLock.unlock(); - - if (needWake) { - mLooper->wake(); - } - - int32_t injectionResult; - { // acquire lock - AutoMutex _l(mLock); - - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - } else { - for (;;) { - injectionResult = injectionState->injectionResult; - if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { - break; - } - - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - LOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout); - } - - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { - while (injectionState->pendingForegroundDispatches != 0) { -#if DEBUG_INJECTION - LOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); -#endif - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - LOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout); - } - } - } - - mAllocator.releaseInjectionState(injectionState); - } // release lock - -#if DEBUG_INJECTION - LOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); -#endif - - return injectionResult; -} - -bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); -} - -void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { -#if DEBUG_INJECTION - LOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); -#endif - - if (injectionState->injectionIsAsync) { - // Log the outcome since the injector did not wait for the injection result. - switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - LOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - LOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - LOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - LOGW("Asynchronous input event injection timed out."); - break; - } - } - - injectionState->injectionResult = injectionResult; - mInjectionResultAvailableCondition.broadcast(); - } -} - -void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches += 1; - } -} - -void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches -= 1; - - if (injectionState->pendingForegroundDispatches == 0) { - mInjectionSyncFinishedCondition.broadcast(); - } - } -} - -const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) { - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow* window = & mWindows[i]; - if (window->inputChannel == inputChannel) { - return window; - } - } - return NULL; -} - -void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { -#if DEBUG_FOCUS - LOGD("setInputWindows"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - // Clear old window pointers. - sp<InputChannel> oldFocusedWindowChannel; - if (mFocusedWindow) { - oldFocusedWindowChannel = mFocusedWindow->inputChannel; - mFocusedWindow = NULL; - } - - mWindows.clear(); - - // Loop over new windows and rebuild the necessary window pointers for - // tracking focus and touch. - mWindows.appendVector(inputWindows); - - size_t numWindows = mWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - const InputWindow* window = & mWindows.itemAt(i); - if (window->hasFocus) { - mFocusedWindow = window; - break; - } - } - - if (oldFocusedWindowChannel != NULL) { - if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) { -#if DEBUG_FOCUS - LOGD("Focus left window: %s", - oldFocusedWindowChannel->getName().string()); -#endif - synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, - InputState::CANCEL_NON_POINTER_EVENTS, "focus left window"); - oldFocusedWindowChannel.clear(); - } - } - if (mFocusedWindow && oldFocusedWindowChannel == NULL) { -#if DEBUG_FOCUS - LOGD("Focus entered window: %s", - mFocusedWindow->inputChannel->getName().string()); -#endif - } - - for (size_t i = 0; i < mTouchState.windows.size(); ) { - TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - const InputWindow* window = getWindowLocked(touchedWindow.channel); - if (window) { - touchedWindow.window = window; - i += 1; - } else { -#if DEBUG_FOCUS - LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string()); -#endif - synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, - InputState::CANCEL_POINTER_EVENTS, "touched window was removed"); - mTouchState.windows.removeAt(i); - } - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) { -#if DEBUG_FOCUS - LOGD("setFocusedApplication"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - releaseFocusedApplicationLocked(); - - if (inputApplication) { - mFocusedApplicationStorage = *inputApplication; - mFocusedApplication = & mFocusedApplicationStorage; - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::releaseFocusedApplicationLocked() { - if (mFocusedApplication) { - mFocusedApplication = NULL; - mFocusedApplicationStorage.handle.clear(); - } -} - -void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { -#if DEBUG_FOCUS - LOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); -#endif - - bool changed; - { // acquire lock - AutoMutex _l(mLock); - - if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { - if (mDispatchFrozen && !frozen) { - resetANRTimeoutsLocked(); - } - - if (mDispatchEnabled && !enabled) { - resetAndDropEverythingLocked("dispatcher is being disabled"); - } - - mDispatchEnabled = enabled; - mDispatchFrozen = frozen; - changed = true; - } else { - changed = false; - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - if (changed) { - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - } -} - -bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) { -#if DEBUG_FOCUS - LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", - fromChannel->getName().string(), toChannel->getName().string()); -#endif - { // acquire lock - AutoMutex _l(mLock); - - const InputWindow* fromWindow = getWindowLocked(fromChannel); - const InputWindow* toWindow = getWindowLocked(toChannel); - if (! fromWindow || ! toWindow) { -#if DEBUG_FOCUS - LOGD("Cannot transfer focus because from or to window not found."); -#endif - return false; - } - if (fromWindow == toWindow) { -#if DEBUG_FOCUS - LOGD("Trivial transfer to same window."); -#endif - return true; - } - - bool found = false; - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.window == fromWindow) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - mTouchState.windows.removeAt(i); - - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT); - mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds); - - found = true; - break; - } - } - - if (! found) { -#if DEBUG_FOCUS - LOGD("Focus transfer failed because from window did not have focus."); -#endif - return false; - } - - ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); - ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); - if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex); - sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex); - - fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - synthesizeCancelationEventsForConnectionLocked(fromConnection, - InputState::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); - } - -#if DEBUG_FOCUS - logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - return true; -} - -void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { -#if DEBUG_FOCUS - LOGD("Resetting and dropping all events (%s).", reason); -#endif - - synthesizeCancelationEventsForAllConnectionsLocked(InputState::CANCEL_ALL_EVENTS, reason); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - resetTargetsLocked(); - - mTouchState.reset(); -} - -void InputDispatcher::logDispatchStateLocked() { - String8 dump; - dumpDispatchStateLocked(dump); - - char* text = dump.lockBuffer(dump.size()); - char* start = text; - while (*start != '\0') { - char* end = strchr(start, '\n'); - if (*end == '\n') { - *(end++) = '\0'; - } - LOGD("%s", start); - start = end; - } -} - -void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); - - if (mFocusedApplication) { - dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplication->name.string(), - mFocusedApplication->dispatchingTimeout / 1000000.0); - } else { - dump.append(INDENT "FocusedApplication: <null>\n"); - } - dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>"); - - dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); - dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); - if (!mTouchState.windows.isEmpty()) { - dump.append(INDENT "TouchedWindows:\n"); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value, - touchedWindow.targetFlags); - } - } else { - dump.append(INDENT "TouchedWindows: <none>\n"); - } - - if (!mWindows.isEmpty()) { - dump.append(INDENT "Windows:\n"); - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow& window = mWindows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], " - "visibleFrame=[%d,%d][%d,%d], " - "touchableArea=[%d,%d][%d,%d], " - "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - i, window.name.string(), - toString(window.paused), - toString(window.hasFocus), - toString(window.hasWallpaper), - toString(window.visible), - toString(window.canReceiveKeys), - window.layoutParamsFlags, window.layoutParamsType, - window.layer, - window.frameLeft, window.frameTop, - window.frameRight, window.frameBottom, - window.visibleFrameLeft, window.visibleFrameTop, - window.visibleFrameRight, window.visibleFrameBottom, - window.touchableAreaLeft, window.touchableAreaTop, - window.touchableAreaRight, window.touchableAreaBottom, - window.ownerPid, window.ownerUid, - window.dispatchingTimeout / 1000000.0); - } - } else { - dump.append(INDENT "Windows: <none>\n"); - } - - if (!mMonitoringChannels.isEmpty()) { - dump.append(INDENT "MonitoringChannels:\n"); - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); - } - } else { - dump.append(INDENT "MonitoringChannels: <none>\n"); - } - - dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); - - if (!mActiveConnections.isEmpty()) { - dump.append(INDENT "ActiveConnections:\n"); - for (size_t i = 0; i < mActiveConnections.size(); i++) { - const Connection* connection = mActiveConnections[i]; - dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, " - "inputState.isNeutral=%s\n", - i, connection->getInputChannelName(), connection->getStatusLabel(), - connection->outboundQueue.count(), - toString(connection->inputState.isNeutral())); - } - } else { - dump.append(INDENT "ActiveConnections: <none>\n"); - } - - if (isAppSwitchPendingLocked()) { - dump.appendFormat(INDENT "AppSwitch: pending, due in %01.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); - } else { - dump.append(INDENT "AppSwitch: not pending\n"); - } -} - -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { -#if DEBUG_REGISTRATION - LOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), - toString(monitor)); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (getConnectionIndexLocked(inputChannel) >= 0) { - LOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = new Connection(inputChannel); - status_t status = connection->initialize(); - if (status) { - LOGE("Failed to initialize input publisher for input channel '%s', status=%d", - inputChannel->getName().string(), status); - return status; - } - - int32_t receiveFd = inputChannel->getReceivePipeFd(); - mConnectionsByReceiveFd.add(receiveFd, connection); - - if (monitor) { - mMonitoringChannels.push(inputChannel); - } - - mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - - runCommandsLockedInterruptible(); - } // release lock - return OK; -} - -status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { -#if DEBUG_REGISTRATION - LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex < 0) { - LOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - mConnectionsByReceiveFd.removeItemsAt(connectionIndex); - - connection->status = Connection::STATUS_ZOMBIE; - - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - if (mMonitoringChannels[i] == inputChannel) { - mMonitoringChannels.removeAt(i); - break; - } - } - - mLooper->removeFd(inputChannel->getReceivePipeFd()); - - nsecs_t currentTime = now(); - abortBrokenDispatchCycleLocked(currentTime, connection); - - runCommandsLockedInterruptible(); - } // release lock - - // Wake the poll loop because removing the connection may have changed the current - // synchronization state. - mLooper->wake(); - return OK; -} - -ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { - ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd()); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - if (connection->inputChannel.get() == inputChannel.get()) { - return connectionIndex; - } - } - - return -1; -} - -void InputDispatcher::activateConnectionLocked(Connection* connection) { - for (size_t i = 0; i < mActiveConnections.size(); i++) { - if (mActiveConnections.itemAt(i) == connection) { - return; - } - } - mActiveConnections.add(connection); -} - -void InputDispatcher::deactivateConnectionLocked(Connection* connection) { - for (size_t i = 0; i < mActiveConnections.size(); i++) { - if (mActiveConnections.itemAt(i) == connection) { - mActiveConnections.removeAt(i); - return; - } - } -} - -void InputDispatcher::onDispatchCycleStartedLocked( - nsecs_t currentTime, const sp<Connection>& connection) { -} - -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); - commandEntry->connection = connection; - commandEntry->handled = handled; -} - -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection) { - LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName()); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); - commandEntry->connection = connection; -} - -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const InputApplication* application, const InputWindow* window, - nsecs_t eventTime, nsecs_t waitStartTime) { - LOGI("Application is not responding: %s. " - "%01.1fms since event, %01.1fms since wait started", - getApplicationWindowLabelLocked(application, window).string(), - (currentTime - eventTime) / 1000000.0, - (currentTime - waitStartTime) / 1000000.0); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); - if (application) { - commandEntry->inputApplicationHandle = application->handle; - } - if (window) { - commandEntry->inputChannel = window->inputChannel; - } -} - -void InputDispatcher::doNotifyConfigurationChangedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->notifyConfigurationChanged(commandEntry->eventTime); - - mLock.lock(); -} - -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - - if (connection->status != Connection::STATUS_ZOMBIE) { - mLock.unlock(); - - mPolicy->notifyInputChannelBroken(connection->inputChannel); - - mLock.lock(); - } -} - -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputChannel); - - mLock.lock(); - - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel); -} - -void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( - CommandEntry* commandEntry) { - KeyEntry* entry = commandEntry->keyEntry; - - KeyEvent event; - initializeKeyEvent(&event, entry); - - mLock.unlock(); - - bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel, - &event, entry->policyFlags); - - mLock.lock(); - - entry->interceptKeyResult = consumed - ? KeyEntry::INTERCEPT_KEY_RESULT_SKIP - : KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - mAllocator.releaseKeyEntry(entry); -} - -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - bool handled = commandEntry->handled; - - if (!connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; - if (dispatchEntry->inProgress - && dispatchEntry->hasForegroundTarget() - && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { - if (handled) { - // If the application handled a non-fallback key, then immediately - // cancel all fallback keys previously dispatched to the application. - // This behavior will prevent chording with fallback keys (so they cannot - // be used as modifiers) but it will ensure that fallback keys do not - // get stuck. This takes care of the case where the application does not handle - // the original DOWN so we generate a fallback DOWN but it does handle - // the original UP in which case we would not generate the fallback UP. - synthesizeCancelationEventsForConnectionLocked(connection, - InputState::CANCEL_FALLBACK_EVENTS, - "application handled a non-fallback event, canceling all fallback events"); - } else { - // If the application did not handle a non-fallback key, then ask - // the policy what to do with it. We might generate a fallback key - // event here. - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - - mLock.unlock(); - - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - if (connection->status != Connection::STATUS_NORMAL) { - return; - } - - assert(connection->outboundQueue.headSentinel.next == dispatchEntry); - - if (fallback) { - // Restart the dispatch cycle using the fallback key. - keyEntry->eventTime = event.getEventTime(); - keyEntry->deviceId = event.getDeviceId(); - keyEntry->source = event.getSource(); - keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; - keyEntry->keyCode = event.getKeyCode(); - keyEntry->scanCode = event.getScanCode(); - keyEntry->metaState = event.getMetaState(); - keyEntry->repeatCount = event.getRepeatCount(); - keyEntry->downTime = event.getDownTime(); - keyEntry->syntheticRepeat = false; - - dispatchEntry->inProgress = false; - startDispatchCycleLocked(now(), connection); - return; - } - } - } - } - } - - startNextDispatchCycleLocked(now(), connection); -} - -void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); - - mLock.lock(); -} - -void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { - event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); -} - -void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { - // TODO Write some statistics about how long we spend waiting. -} - -void InputDispatcher::dump(String8& dump) { - dump.append("Input Dispatcher State:\n"); - dumpDispatchStateLocked(dump); -} - - -// --- InputDispatcher::Queue --- - -template <typename T> -uint32_t InputDispatcher::Queue<T>::count() const { - uint32_t result = 0; - for (const T* entry = headSentinel.next; entry != & tailSentinel; entry = entry->next) { - result += 1; - } - return result; -} - - -// --- InputDispatcher::Allocator --- - -InputDispatcher::Allocator::Allocator() { -} - -InputDispatcher::InjectionState* -InputDispatcher::Allocator::obtainInjectionState(int32_t injectorPid, int32_t injectorUid) { - InjectionState* injectionState = mInjectionStatePool.alloc(); - injectionState->refCount = 1; - injectionState->injectorPid = injectorPid; - injectionState->injectorUid = injectorUid; - injectionState->injectionIsAsync = false; - injectionState->injectionResult = INPUT_EVENT_INJECTION_PENDING; - injectionState->pendingForegroundDispatches = 0; - return injectionState; -} - -void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type, - nsecs_t eventTime, uint32_t policyFlags) { - entry->type = type; - entry->refCount = 1; - entry->dispatchInProgress = false; - entry->eventTime = eventTime; - entry->policyFlags = policyFlags; - entry->injectionState = NULL; -} - -void InputDispatcher::Allocator::releaseEventEntryInjectionState(EventEntry* entry) { - if (entry->injectionState) { - releaseInjectionState(entry->injectionState); - entry->injectionState = NULL; - } -} - -InputDispatcher::ConfigurationChangedEntry* -InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) { - ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0); - return entry; -} - -InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t eventTime, - int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) { - KeyEntry* entry = mKeyEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags); - - entry->deviceId = deviceId; - entry->source = source; - entry->action = action; - entry->flags = flags; - entry->keyCode = keyCode; - entry->scanCode = scanCode; - entry->metaState = metaState; - entry->repeatCount = repeatCount; - entry->downTime = downTime; - entry->syntheticRepeat = false; - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - return entry; -} - -InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime, - int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, uint32_t pointerCount, - const int32_t* pointerIds, const PointerCoords* pointerCoords) { - MotionEntry* entry = mMotionEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags); - - entry->eventTime = eventTime; - entry->deviceId = deviceId; - entry->source = source; - entry->action = action; - entry->flags = flags; - entry->metaState = metaState; - entry->edgeFlags = edgeFlags; - entry->xPrecision = xPrecision; - entry->yPrecision = yPrecision; - entry->downTime = downTime; - entry->pointerCount = pointerCount; - entry->firstSample.eventTime = eventTime; - entry->firstSample.next = NULL; - entry->lastSample = & entry->firstSample; - for (uint32_t i = 0; i < pointerCount; i++) { - entry->pointerIds[i] = pointerIds[i]; - entry->firstSample.pointerCoords[i] = pointerCoords[i]; - } - return entry; -} - -InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry( - EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset) { - DispatchEntry* entry = mDispatchEntryPool.alloc(); - entry->eventEntry = eventEntry; - eventEntry->refCount += 1; - entry->targetFlags = targetFlags; - entry->xOffset = xOffset; - entry->yOffset = yOffset; - entry->inProgress = false; - entry->headMotionSample = NULL; - entry->tailMotionSample = NULL; - return entry; -} - -InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) { - CommandEntry* entry = mCommandEntryPool.alloc(); - entry->command = command; - return entry; -} - -void InputDispatcher::Allocator::releaseInjectionState(InjectionState* injectionState) { - injectionState->refCount -= 1; - if (injectionState->refCount == 0) { - mInjectionStatePool.free(injectionState); - } else { - assert(injectionState->refCount > 0); - } -} - -void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) { - switch (entry->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: - releaseConfigurationChangedEntry(static_cast<ConfigurationChangedEntry*>(entry)); - break; - case EventEntry::TYPE_KEY: - releaseKeyEntry(static_cast<KeyEntry*>(entry)); - break; - case EventEntry::TYPE_MOTION: - releaseMotionEntry(static_cast<MotionEntry*>(entry)); - break; - default: - assert(false); - break; - } -} - -void InputDispatcher::Allocator::releaseConfigurationChangedEntry( - ConfigurationChangedEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - mConfigurationChangeEntryPool.free(entry); - } else { - assert(entry->refCount > 0); - } -} - -void InputDispatcher::Allocator::releaseKeyEntry(KeyEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - mKeyEntryPool.free(entry); - } else { - assert(entry->refCount > 0); - } -} - -void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) { - MotionSample* next = sample->next; - mMotionSamplePool.free(sample); - sample = next; - } - mMotionEntryPool.free(entry); - } else { - assert(entry->refCount > 0); - } -} - -void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) { - releaseEventEntry(entry->eventEntry); - mDispatchEntryPool.free(entry); -} - -void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) { - mCommandEntryPool.free(entry); -} - -void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, - nsecs_t eventTime, const PointerCoords* pointerCoords) { - MotionSample* sample = mMotionSamplePool.alloc(); - sample->eventTime = eventTime; - uint32_t pointerCount = motionEntry->pointerCount; - for (uint32_t i = 0; i < pointerCount; i++) { - sample->pointerCoords[i] = pointerCoords[i]; - } - - sample->next = NULL; - motionEntry->lastSample->next = sample; - motionEntry->lastSample = sample; -} - -void InputDispatcher::Allocator::recycleKeyEntry(KeyEntry* keyEntry) { - releaseEventEntryInjectionState(keyEntry); - - keyEntry->dispatchInProgress = false; - keyEntry->syntheticRepeat = false; - keyEntry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; -} - - -// --- InputDispatcher::MotionEntry --- - -uint32_t InputDispatcher::MotionEntry::countSamples() const { - uint32_t count = 1; - for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { - count += 1; - } - return count; -} - - -// --- InputDispatcher::InputState --- - -InputDispatcher::InputState::InputState() { -} - -InputDispatcher::InputState::~InputState() { -} - -bool InputDispatcher::InputState::isNeutral() const { - return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); -} - -InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent( - const EventEntry* entry) { - switch (entry->type) { - case EventEntry::TYPE_KEY: - return trackKey(static_cast<const KeyEntry*>(entry)); - - case EventEntry::TYPE_MOTION: - return trackMotion(static_cast<const MotionEntry*>(entry)); - - default: - return CONSISTENT; - } -} - -InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey( - const KeyEntry* entry) { - int32_t action = entry->action; - for (size_t i = 0; i < mKeyMementos.size(); i++) { - KeyMemento& memento = mKeyMementos.editItemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.keyCode == entry->keyCode - && memento.scanCode == entry->scanCode) { - switch (action) { - case AKEY_EVENT_ACTION_UP: - mKeyMementos.removeAt(i); - return CONSISTENT; - - case AKEY_EVENT_ACTION_DOWN: - return TOLERABLE; - - default: - return BROKEN; - } - } - } - - switch (action) { - case AKEY_EVENT_ACTION_DOWN: { - mKeyMementos.push(); - KeyMemento& memento = mKeyMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.keyCode = entry->keyCode; - memento.scanCode = entry->scanCode; - memento.flags = entry->flags; - memento.downTime = entry->downTime; - return CONSISTENT; - } - - default: - return BROKEN; - } -} - -InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotion( - const MotionEntry* entry) { - int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK; - for (size_t i = 0; i < mMotionMementos.size(); i++) { - MotionMemento& memento = mMotionMementos.editItemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source) { - switch (action) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - mMotionMementos.removeAt(i); - return CONSISTENT; - - case AMOTION_EVENT_ACTION_DOWN: - return TOLERABLE; - - case AMOTION_EVENT_ACTION_POINTER_DOWN: - if (entry->pointerCount == memento.pointerCount + 1) { - memento.setPointers(entry); - return CONSISTENT; - } - return BROKEN; - - case AMOTION_EVENT_ACTION_POINTER_UP: - if (entry->pointerCount == memento.pointerCount - 1) { - memento.setPointers(entry); - return CONSISTENT; - } - return BROKEN; - - case AMOTION_EVENT_ACTION_MOVE: - if (entry->pointerCount == memento.pointerCount) { - return CONSISTENT; - } - return BROKEN; - - default: - return BROKEN; - } - } - } - - switch (action) { - case AMOTION_EVENT_ACTION_DOWN: { - mMotionMementos.push(); - MotionMemento& memento = mMotionMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.xPrecision = entry->xPrecision; - memento.yPrecision = entry->yPrecision; - memento.downTime = entry->downTime; - memento.setPointers(entry); - return CONSISTENT; - } - - default: - return BROKEN; - } -} - -void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { - pointerCount = entry->pointerCount; - for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerIds[i] = entry->pointerIds[i]; - pointerCoords[i] = entry->lastSample->pointerCoords[i]; - } -} - -void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - Allocator* allocator, Vector<EventEntry*>& outEvents, - CancelationOptions options) { - for (size_t i = 0; i < mKeyMementos.size(); ) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (shouldCancelKey(memento, options)) { - outEvents.push(allocator->obtainKeyEntry(currentTime, - memento.deviceId, memento.source, 0, - AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); - mKeyMementos.removeAt(i); - } else { - i += 1; - } - } - - for (size_t i = 0; i < mMotionMementos.size(); ) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (shouldCancelMotion(memento, options)) { - outEvents.push(allocator->obtainMotionEntry(currentTime, - memento.deviceId, memento.source, 0, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.pointerCount, memento.pointerIds, memento.pointerCoords)); - mMotionMementos.removeAt(i); - } else { - i += 1; - } - } -} - -void InputDispatcher::InputState::clear() { - mKeyMementos.clear(); - mMotionMementos.clear(); -} - -void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size(); ) { - const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); - if (memento.deviceId == otherMemento.deviceId - && memento.source == otherMemento.source) { - other.mMotionMementos.removeAt(j); - } else { - j += 1; - } - } - other.mMotionMementos.push(memento); - } - } -} - -bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, - CancelationOptions options) { - switch (options) { - case CANCEL_ALL_EVENTS: - case CANCEL_NON_POINTER_EVENTS: - return true; - case CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; - } -} - -bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, - CancelationOptions options) { - switch (options) { - case CANCEL_ALL_EVENTS: - return true; - case CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; - } -} - - -// --- InputDispatcher::Connection --- - -InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputPublisher(inputChannel), - lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) { -} - -InputDispatcher::Connection::~Connection() { -} - -status_t InputDispatcher::Connection::initialize() { - return inputPublisher.initialize(); -} - -const char* InputDispatcher::Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - - case STATUS_BROKEN: - return "BROKEN"; - - case STATUS_ZOMBIE: - return "ZOMBIE"; - - default: - return "UNKNOWN"; - } -} - -InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent( - const EventEntry* eventEntry) const { - for (DispatchEntry* dispatchEntry = outboundQueue.tailSentinel.prev; - dispatchEntry != & outboundQueue.headSentinel; dispatchEntry = dispatchEntry->prev) { - if (dispatchEntry->eventEntry == eventEntry) { - return dispatchEntry; - } - } - return NULL; -} - - -// --- InputDispatcher::CommandEntry --- - -InputDispatcher::CommandEntry::CommandEntry() : - keyEntry(NULL) { -} - -InputDispatcher::CommandEntry::~CommandEntry() { -} - - -// --- InputDispatcher::TouchState --- - -InputDispatcher::TouchState::TouchState() : - down(false), split(false) { -} - -InputDispatcher::TouchState::~TouchState() { -} - -void InputDispatcher::TouchState::reset() { - down = false; - split = false; - windows.clear(); -} - -void InputDispatcher::TouchState::copyFrom(const TouchState& other) { - down = other.down; - split = other.split; - windows.clear(); - windows.appendVector(other.windows); -} - -void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window, - int32_t targetFlags, BitSet32 pointerIds) { - if (targetFlags & InputTarget::FLAG_SPLIT) { - split = true; - } - - for (size_t i = 0; i < windows.size(); i++) { - TouchedWindow& touchedWindow = windows.editItemAt(i); - if (touchedWindow.window == window) { - touchedWindow.targetFlags |= targetFlags; - touchedWindow.pointerIds.value |= pointerIds.value; - return; - } - } - - windows.push(); - - TouchedWindow& touchedWindow = windows.editTop(); - touchedWindow.window = window; - touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; - touchedWindow.channel = window->inputChannel; -} - -void InputDispatcher::TouchState::removeOutsideTouchWindows() { - for (size_t i = 0 ; i < windows.size(); ) { - if (windows[i].targetFlags & InputTarget::FLAG_OUTSIDE) { - windows.removeAt(i); - } else { - i += 1; - } - } -} - -const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() { - for (size_t i = 0; i < windows.size(); i++) { - if (windows[i].targetFlags & InputTarget::FLAG_FOREGROUND) { - return windows[i].window; - } - } - return NULL; -} - - -// --- InputDispatcherThread --- - -InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : - Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { -} - -InputDispatcherThread::~InputDispatcherThread() { -} - -bool InputDispatcherThread::threadLoop() { - mDispatcher->dispatchOnce(); - return true; -} - -} // namespace android diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp deleted file mode 100644 index 09fce38d9c18..000000000000 --- a/libs/ui/InputManager.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// The input manager. -// -#define LOG_TAG "InputManager" - -//#define LOG_NDEBUG 0 - -#include <cutils/log.h> -#include <ui/InputManager.h> -#include <ui/InputReader.h> -#include <ui/InputDispatcher.h> - -namespace android { - -InputManager::InputManager( - const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& readerPolicy, - const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { - mDispatcher = new InputDispatcher(dispatcherPolicy); - mReader = new InputReader(eventHub, readerPolicy, mDispatcher); - initialize(); -} - -InputManager::InputManager( - const sp<InputReaderInterface>& reader, - const sp<InputDispatcherInterface>& dispatcher) : - mReader(reader), - mDispatcher(dispatcher) { - initialize(); -} - -InputManager::~InputManager() { - stop(); -} - -void InputManager::initialize() { - mReaderThread = new InputReaderThread(mReader); - mDispatcherThread = new InputDispatcherThread(mDispatcher); -} - -status_t InputManager::start() { - status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); - if (result) { - LOGE("Could not start InputDispatcher thread due to error %d.", result); - return result; - } - - result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - LOGE("Could not start InputReader thread due to error %d.", result); - - mDispatcherThread->requestExit(); - return result; - } - - return OK; -} - -status_t InputManager::stop() { - status_t result = mReaderThread->requestExitAndWait(); - if (result) { - LOGW("Could not stop InputReader thread due to error %d.", result); - } - - result = mDispatcherThread->requestExitAndWait(); - if (result) { - LOGW("Could not stop InputDispatcher thread due to error %d.", result); - } - - return OK; -} - -sp<InputReaderInterface> InputManager::getReader() { - return mReader; -} - -sp<InputDispatcherInterface> InputManager::getDispatcher() { - return mDispatcher; -} - -} // namespace android diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp deleted file mode 100644 index 51ed09f87ed3..000000000000 --- a/libs/ui/InputReader.cpp +++ /dev/null @@ -1,3549 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// The input reader. -// -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -#include <cutils/log.h> -#include <ui/InputReader.h> -#include <ui/Keyboard.h> -#include <ui/VirtualKeyMap.h> - -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> -#include <math.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " - -namespace android { - -// --- Static Functions --- - -template<typename T> -inline static T abs(const T& value) { - return value < 0 ? - value : value; -} - -template<typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template<typename T> -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -inline static float pythag(float x, float y) { - return sqrtf(x * x + y * y); -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, - { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, - { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, - { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, -}; -static const int keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - if (orientation != InputReaderPolicyInterface::ROTATION_0) { - for (int i = 0; i < keyCodeRotationMapSize; i++) { - if (keyCode == keyCodeRotationMap[i][0]) { - return keyCodeRotationMap[i][orientation]; - } - } - } - return keyCode; -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; -} - - -// --- InputReader --- - -InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputDispatcherInterface>& dispatcher) : - mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), - mGlobalMetaState(0) { - configureExcludedDevices(); - updateGlobalMetaState(); - updateInputConfiguration(); -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - RawEvent rawEvent; - mEventHub->getEvent(& rawEvent); - -#if DEBUG_RAW_EVENTS - LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d", - rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode, - rawEvent.value); -#endif - - process(& rawEvent); -} - -void InputReader::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDevice(rawEvent->deviceId); - break; - - case EventHubInterface::DEVICE_REMOVED: - removeDevice(rawEvent->deviceId); - break; - - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChanged(rawEvent->when); - break; - - default: - consumeEvent(rawEvent); - break; - } -} - -void InputReader::addDevice(int32_t deviceId) { - String8 name = mEventHub->getDeviceName(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - - InputDevice* device = createDevice(deviceId, name, classes); - device->configure(); - - if (device->isIgnored()) { - LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string()); - } else { - LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(), - device->getSources()); - } - - bool added = false; - { // acquire device registry writer lock - RWLock::AutoWLock _wl(mDeviceRegistryLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - mDevices.add(deviceId, device); - added = true; - } - } // release device registry writer lock - - if (! added) { - LOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - delete device; - return; - } -} - -void InputReader::removeDevice(int32_t deviceId) { - bool removed = false; - InputDevice* device = NULL; - { // acquire device registry writer lock - RWLock::AutoWLock _wl(mDeviceRegistryLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - removed = true; - } - } // release device registry writer lock - - if (! removed) { - LOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - if (device->isIgnored()) { - LOGI("Device removed: id=%d, name='%s' (ignored non-input device)", - device->getId(), device->getName().string()); - } else { - LOGI("Device removed: id=%d, name='%s', sources=0x%08x", - device->getId(), device->getName().string(), device->getSources()); - } - - device->reset(); - - delete device; -} - -InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) { - InputDevice* device = new InputDevice(this, deviceId, name); - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSources = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSources |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSources |= AINPUT_SOURCE_DPAD; - } - - if (keyboardSources != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType)); - } - - // Trackball-like devices. - if (classes & INPUT_DEVICE_CLASS_TRACKBALL) { - device->addMapper(new TrackballInputMapper(device)); - } - - // Touchscreen-like devices. - if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - return device; -} - -void InputReader::consumeEvent(const RawEvent* rawEvent) { - int32_t deviceId = rawEvent->deviceId; - - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - LOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - //LOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvent); - } // release device registry reader lock -} - -void InputReader::handleConfigurationChanged(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaState(); - - // Update input configuration. - updateInputConfiguration(); - - // Enqueue configuration changed. - mDispatcher->notifyConfigurationChanged(when); -} - -void InputReader::configureExcludedDevices() { - Vector<String8> excludedDeviceNames; - mPolicy->getExcludedDeviceNames(excludedDeviceNames); - - for (size_t i = 0; i < excludedDeviceNames.size(); i++) { - mEventHub->addExcludedDevice(excludedDeviceNames[i]); - } -} - -void InputReader::updateGlobalMetaState() { - { // acquire state lock - AutoMutex _l(mStateLock); - - mGlobalMetaState = 0; - - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } - } // release device registry reader lock - } // release state lock -} - -int32_t InputReader::getGlobalMetaState() { - { // acquire state lock - AutoMutex _l(mStateLock); - - return mGlobalMetaState; - } // release state lock -} - -void InputReader::updateInputConfiguration() { - { // acquire state lock - AutoMutex _l(mStateLock); - - int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH; - int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS; - int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV; - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - InputDeviceInfo deviceInfo; - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->getDeviceInfo(& deviceInfo); - uint32_t sources = deviceInfo.getSources(); - - if ((sources & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN) { - touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER; - } - if ((sources & AINPUT_SOURCE_TRACKBALL) == AINPUT_SOURCE_TRACKBALL) { - navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL; - } else if ((sources & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) { - navigationConfig = InputConfiguration::NAVIGATION_DPAD; - } - if (deviceInfo.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) { - keyboardConfig = InputConfiguration::KEYBOARD_QWERTY; - } - } - } // release device registry reader lock - - mInputConfiguration.touchScreen = touchScreenConfig; - mInputConfiguration.keyboard = keyboardConfig; - mInputConfiguration.navigation = navigationConfig; - } // release state lock -} - -void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) { - { // acquire state lock - AutoMutex _l(mStateLock); - - *outConfiguration = mInputConfiguration; - } // release state lock -} - -status_t InputReader::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) { - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - return NAME_NOT_FOUND; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - return NAME_NOT_FOUND; - } - - device->getDeviceInfo(outDeviceInfo); - return OK; - } // release device registy reader lock -} - -void InputReader::getInputDeviceIds(Vector<int32_t>& outDeviceIds) { - outDeviceIds.clear(); - - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored()) { - outDeviceIds.add(device->getId()); - } - } - } // release device registy reader lock -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) { - return getState(deviceId, sourceMask, keyCode, & InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) { - return getState(deviceId, sourceMask, scanCode, & InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - return getState(deviceId, sourceMask, switchCode, & InputDevice::getSwitchState); -} - -int32_t InputReader::getState(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - if (result >= AKEY_STATE_DOWN) { - return result; - } - } - } - } - return result; - } // release device registy reader lock -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - memset(outFlags, 0, numCodes); - return markSupportedKeyCodes(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } - return result; - } // release device registy reader lock -} - -void InputReader::dump(String8& dump) { - mEventHub->dump(dump); - dump.append("\n"); - - dump.append("Input Reader State:\n"); - - { // acquire device registry reader lock - RWLock::AutoRLock _rl(mDeviceRegistryLock); - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - } // release device registy reader lock -} - - -// --- InputReaderThread --- - -InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : - Thread(/*canCallJava*/ true), mReader(reader) { -} - -InputReaderThread::~InputReaderThread() { -} - -bool InputReaderThread::threadLoop() { - mReader->loopOnce(); - return true; -} - - -// --- InputDevice --- - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) : - mContext(context), mId(id), mName(name), mSources(0) { -} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -static void dumpMotionRange(String8& dump, const InputDeviceInfo& deviceInfo, - int32_t rangeType, const char* name) { - const InputDeviceInfo::MotionRange* range = deviceInfo.getMotionRange(rangeType); - if (range) { - dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n", - name, range->min, range->max, range->flat, range->fuzz); - } -} - -void InputDevice::dump(String8& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(& deviceInfo); - - dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getName().string()); - dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - if (!deviceInfo.getMotionRanges().isEmpty()) { - dump.append(INDENT2 "Motion Ranges:\n"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_X, "X"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_Y, "Y"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_PRESSURE, "Pressure"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_SIZE, "Size"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MAJOR, "TouchMajor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MINOR, "TouchMinor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MAJOR, "ToolMajor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MINOR, "ToolMinor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_ORIENTATION, "Orientation"); - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.add(mapper); -} - -void InputDevice::configure() { - if (! isIgnored()) { - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - mSources = 0; - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->configure(); - mSources |= mapper->getSources(); - } -} - -void InputDevice::reset() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->reset(); - } -} - -void InputDevice::process(const RawEvent* rawEvent) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mName); - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, & InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result = (mapper->*getStateFunc)(sourceMask, code); - if (result >= AKEY_STATE_DOWN) { - return result; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - result |= mapper->getMetaState(); - } - return result; -} - - -// --- InputMapper --- - -InputMapper::InputMapper(InputDevice* device) : - mDevice(device), mContext(device->getContext()) { -} - -InputMapper::~InputMapper() { -} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(String8& dump) { -} - -void InputMapper::configure() { -} - -void InputMapper::reset() { -} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -int32_t InputMapper::getMetaState() { - return 0; -} - - -// --- SwitchInputMapper --- - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) : - InputMapper(device) { -} - -SwitchInputMapper::~SwitchInputMapper() { -} - -uint32_t SwitchInputMapper::getSources() { - return 0; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->when, rawEvent->scanCode, rawEvent->value); - break; - } -} - -void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) { - getDispatcher()->notifySwitch(when, switchCode, switchValue, 0); -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t sources, int32_t keyboardType) : - InputMapper(device), mSources(sources), - mKeyboardType(keyboardType) { - initializeLocked(); -} - -KeyboardInputMapper::~KeyboardInputMapper() { -} - -void KeyboardInputMapper::initializeLocked() { - mLocked.metaState = AMETA_NONE; - mLocked.downTime = 0; -} - -uint32_t KeyboardInputMapper::getSources() { - return mSources; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); -} - -void KeyboardInputMapper::dump(String8& dump) { - { // acquire lock - AutoMutex _l(mLock); - dump.append(INDENT2 "Keyboard Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size()); - dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); - } // release lock -} - - -void KeyboardInputMapper::configure() { - InputMapper::configure(); - - // Configure basic parameters. - configureParameters(); - - // Reset LEDs. - { - AutoMutex _l(mLock); - resetLedStateLocked(); - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), - mParameters.orientationAware); - - mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1; -} - -void KeyboardInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", - mParameters.associatedDisplayId); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void KeyboardInputMapper::reset() { - for (;;) { - int32_t keyCode, scanCode; - { // acquire lock - AutoMutex _l(mLock); - - // Synthesize key up event on reset if keys are currently down. - if (mLocked.keyDowns.isEmpty()) { - initializeLocked(); - resetLedStateLocked(); - break; // done - } - - const KeyDown& keyDown = mLocked.keyDowns.top(); - keyCode = keyDown.keyCode; - scanCode = keyDown.scanCode; - } // release lock - - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - processKey(when, false, keyCode, scanCode, 0); - } - - InputMapper::reset(); - getContext()->updateGlobalMetaState(); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->scanCode; - if (isKeyboardOrGamepadKey(scanCode)) { - processKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode, - rawEvent->flags); - } - break; - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE - || scanCode >= KEY_OK - || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI); -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, - int32_t scanCode, uint32_t policyFlags) { - int32_t newMetaState; - nsecs_t downTime; - bool metaStateChanged = false; - - { // acquire lock - AutoMutex _l(mLock); - - if (down) { - // Rotate key codes according to orientation if needed. - // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { - int32_t orientation; - if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, - NULL, NULL, & orientation)) { - orientation = InputReaderPolicyInterface::ROTATION_0; - } - - keyCode = rotateKeyCode(keyCode, orientation); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDownLocked(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode; - } else { - // key down - mLocked.keyDowns.push(); - KeyDown& keyDown = mLocked.keyDowns.editTop(); - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - } - - mLocked.downTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDownLocked(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode; - mLocked.keyDowns.removeAt(size_t(keyDownIndex)); - } else { - // key was not actually down - LOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().string(), keyCode, scanCode); - return; - } - } - - int32_t oldMetaState = mLocked.metaState; - newMetaState = updateMetaState(keyCode, down, oldMetaState); - if (oldMetaState != newMetaState) { - mLocked.metaState = newMetaState; - metaStateChanged = true; - updateLedStateLocked(false); - } - - downTime = mLocked.downTime; - } // release lock - - if (metaStateChanged) { - getContext()->updateGlobalMetaState(); - } - - if (policyFlags & POLICY_FLAG_FUNCTION) { - newMetaState |= AMETA_FUNCTION_ON; - } - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); -} - -ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) { - size_t n = mLocked.keyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mLocked.keyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - { // acquire lock - AutoMutex _l(mLock); - return mLocked.metaState; - } // release lock -} - -void KeyboardInputMapper::resetLedStateLocked() { - initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL); - initializeLedStateLocked(mLocked.numLockLedState, LED_NUML); - initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL); - - updateLedStateLocked(true); -} - -void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedStateLocked(bool reset) { - updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL, - AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifierLocked(mLocked.numLockLedState, LED_NUML, - AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifierLocked(mLocked.scrollLockLedState, LED_SCROLLL, - AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& ledState, - int32_t led, int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mLocked.metaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - - -// --- TrackballInputMapper --- - -TrackballInputMapper::TrackballInputMapper(InputDevice* device) : - InputMapper(device) { - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - - initializeLocked(); -} - -TrackballInputMapper::~TrackballInputMapper() { -} - -uint32_t TrackballInputMapper::getSources() { - return AINPUT_SOURCE_TRACKBALL; -} - -void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); -} - -void TrackballInputMapper::dump(String8& dump) { - { // acquire lock - AutoMutex _l(mLock); - dump.append(INDENT2 "Trackball Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down)); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); - } // release lock -} - -void TrackballInputMapper::configure() { - InputMapper::configure(); - - // Configure basic parameters. - configureParameters(); -} - -void TrackballInputMapper::configureParameters() { - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("trackball.orientationAware"), - mParameters.orientationAware); - - mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1; -} - -void TrackballInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", - mParameters.associatedDisplayId); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void TrackballInputMapper::initializeLocked() { - mAccumulator.clear(); - - mLocked.down = false; - mLocked.downTime = 0; -} - -void TrackballInputMapper::reset() { - for (;;) { - { // acquire lock - AutoMutex _l(mLock); - - if (! mLocked.down) { - initializeLocked(); - break; // done - } - } // release lock - - // Synthesize trackball button up event on reset. - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; - mAccumulator.btnMouse = false; - sync(when); - } - - InputMapper::reset(); -} - -void TrackballInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: - switch (rawEvent->scanCode) { - case BTN_MOUSE: - mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE; - mAccumulator.btnMouse = rawEvent->value != 0; - // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and - // we need to ensure that we report the up/down promptly. - sync(rawEvent->when); - break; - } - break; - - case EV_REL: - switch (rawEvent->scanCode) { - case REL_X: - mAccumulator.fields |= Accumulator::FIELD_REL_X; - mAccumulator.relX = rawEvent->value; - break; - case REL_Y: - mAccumulator.fields |= Accumulator::FIELD_REL_Y; - mAccumulator.relY = rawEvent->value; - break; - } - break; - - case EV_SYN: - switch (rawEvent->scanCode) { - case SYN_REPORT: - sync(rawEvent->when); - break; - } - break; - } -} - -void TrackballInputMapper::sync(nsecs_t when) { - uint32_t fields = mAccumulator.fields; - if (fields == 0) { - return; // no new state changes, so nothing to do - } - - int motionEventAction; - PointerCoords pointerCoords; - nsecs_t downTime; - { // acquire lock - AutoMutex _l(mLock); - - bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; - - if (downChanged) { - if (mAccumulator.btnMouse) { - mLocked.down = true; - mLocked.downTime = when; - } else { - mLocked.down = false; - } - } - - downTime = mLocked.downTime; - float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f; - float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; - - if (downChanged) { - motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } - - pointerCoords.x = x; - pointerCoords.y = y; - pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f; - pointerCoords.size = 0; - pointerCoords.touchMajor = 0; - pointerCoords.touchMinor = 0; - pointerCoords.toolMajor = 0; - pointerCoords.toolMinor = 0; - pointerCoords.orientation = 0; - - if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0 - && (x != 0.0f || y != 0.0f)) { - // Rotate motion based on display orientation if needed. - // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - int32_t orientation; - if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, - NULL, NULL, & orientation)) { - orientation = InputReaderPolicyInterface::ROTATION_0; - } - - float temp; - switch (orientation) { - case InputReaderPolicyInterface::ROTATION_90: - temp = pointerCoords.x; - pointerCoords.x = pointerCoords.y; - pointerCoords.y = - temp; - break; - - case InputReaderPolicyInterface::ROTATION_180: - pointerCoords.x = - pointerCoords.x; - pointerCoords.y = - pointerCoords.y; - break; - - case InputReaderPolicyInterface::ROTATION_270: - temp = pointerCoords.x; - pointerCoords.x = - pointerCoords.y; - pointerCoords.y = temp; - break; - } - } - } // release lock - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t pointerId = 0; - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0, - motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); - - mAccumulator.clear(); -} - -int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) : - InputMapper(device) { - mLocked.surfaceOrientation = -1; - mLocked.surfaceWidth = -1; - mLocked.surfaceHeight = -1; - - initializeLocked(); -} - -TouchInputMapper::~TouchInputMapper() { -} - -uint32_t TouchInputMapper::getSources() { - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - return AINPUT_SOURCE_TOUCHSCREEN; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - return AINPUT_SOURCE_TOUCHPAD; - default: - assert(false); - return AINPUT_SOURCE_UNKNOWN; - } -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - { // acquire lock - AutoMutex _l(mLock); - - // Ensure surface information is up to date so that orientation changes are - // noticed immediately. - configureSurfaceLocked(); - - info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y); - - if (mLocked.orientedRanges.havePressure) { - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, - mLocked.orientedRanges.pressure); - } - - if (mLocked.orientedRanges.haveSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, - mLocked.orientedRanges.size); - } - - if (mLocked.orientedRanges.haveTouchSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, - mLocked.orientedRanges.touchMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, - mLocked.orientedRanges.touchMinor); - } - - if (mLocked.orientedRanges.haveToolSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, - mLocked.orientedRanges.toolMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, - mLocked.orientedRanges.toolMinor); - } - - if (mLocked.orientedRanges.haveOrientation) { - info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, - mLocked.orientedRanges.orientation); - } - } // release lock -} - -void TouchInputMapper::dump(String8& dump) { - { // acquire lock - AutoMutex _l(mLock); - dump.append(INDENT2 "Touch Input Mapper:\n"); - dumpParameters(dump); - dumpVirtualKeysLocked(dump); - dumpRawAxes(dump); - dumpCalibration(dump); - dumpSurfaceLocked(dump); - dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin); - dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin); - dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale); - dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale); - dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mLocked.xPrecision); - dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mLocked.yPrecision); - dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mLocked.geometricScale); - dump.appendFormat(INDENT4 "ToolSizeLinearScale: %0.3f\n", mLocked.toolSizeLinearScale); - dump.appendFormat(INDENT4 "ToolSizeLinearBias: %0.3f\n", mLocked.toolSizeLinearBias); - dump.appendFormat(INDENT4 "ToolSizeAreaScale: %0.3f\n", mLocked.toolSizeAreaScale); - dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias); - dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale); - dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale); - dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale); - } // release lock -} - -void TouchInputMapper::initializeLocked() { - mCurrentTouch.clear(); - mLastTouch.clear(); - mDownTime = 0; - - for (uint32_t i = 0; i < MAX_POINTERS; i++) { - mAveragingTouchFilter.historyStart[i] = 0; - mAveragingTouchFilter.historyEnd[i] = 0; - } - - mJumpyTouchFilter.jumpyPointsDropped = 0; - - mLocked.currentVirtualKey.down = false; - - mLocked.orientedRanges.havePressure = false; - mLocked.orientedRanges.haveSize = false; - mLocked.orientedRanges.haveTouchSize = false; - mLocked.orientedRanges.haveToolSize = false; - mLocked.orientedRanges.haveOrientation = false; -} - -void TouchInputMapper::configure() { - InputMapper::configure(); - - // Configure basic parameters. - configureParameters(); - - // Configure absolute axis information. - configureRawAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - - { // acquire lock - AutoMutex _l(mLock); - - // Configure surface dimensions and orientation. - configureSurfaceLocked(); - } // release lock -} - -void TouchInputMapper::configureParameters() { - mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); - - String8 deviceTypeString; - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString != "touchScreen") { - LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - - mParameters.orientationAware = isTouchScreen; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1; -} - -void TouchInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump.append(INDENT4 "DeviceType: touchScreen\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump.append(INDENT4 "DeviceType: touchPad\n"); - break; - default: - assert(false); - } - - dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", - mParameters.associatedDisplayId); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); - - dump.appendFormat(INDENT4 "UseBadTouchFilter: %s\n", - toString(mParameters.useBadTouchFilter)); - dump.appendFormat(INDENT4 "UseAveragingTouchFilter: %s\n", - toString(mParameters.useAveragingTouchFilter)); - dump.appendFormat(INDENT4 "UseJumpyTouchFilter: %s\n", - toString(mParameters.useJumpyTouchFilter)); -} - -void TouchInputMapper::configureRawAxes() { - mRawAxes.x.clear(); - mRawAxes.y.clear(); - mRawAxes.pressure.clear(); - mRawAxes.touchMajor.clear(); - mRawAxes.touchMinor.clear(); - mRawAxes.toolMajor.clear(); - mRawAxes.toolMinor.clear(); - mRawAxes.orientation.clear(); -} - -static void dumpAxisInfo(String8& dump, RawAbsoluteAxisInfo axis, const char* name) { - if (axis.valid) { - dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n", - name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz); - } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); - } -} - -void TouchInputMapper::dumpRawAxes(String8& dump) { - dump.append(INDENT3 "Raw Axes:\n"); - dumpAxisInfo(dump, mRawAxes.x, "X"); - dumpAxisInfo(dump, mRawAxes.y, "Y"); - dumpAxisInfo(dump, mRawAxes.pressure, "Pressure"); - dumpAxisInfo(dump, mRawAxes.touchMajor, "TouchMajor"); - dumpAxisInfo(dump, mRawAxes.touchMinor, "TouchMinor"); - dumpAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor"); - dumpAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor"); - dumpAxisInfo(dump, mRawAxes.orientation, "Orientation"); -} - -bool TouchInputMapper::configureSurfaceLocked() { - // Update orientation and dimensions if needed. - int32_t orientation = InputReaderPolicyInterface::ROTATION_0; - int32_t width = mRawAxes.x.getRange(); - int32_t height = mRawAxes.y.getRange(); - - if (mParameters.associatedDisplayId >= 0) { - bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - bool wantOrientation = mParameters.orientationAware; - - // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, - wantSize ? &width : NULL, wantSize ? &height : NULL, - wantOrientation ? &orientation : NULL)) { - return false; - } - } - - bool orientationChanged = mLocked.surfaceOrientation != orientation; - if (orientationChanged) { - mLocked.surfaceOrientation = orientation; - } - - bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; - if (sizeChanged) { - LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d", - getDeviceId(), getDeviceName().string(), width, height); - - mLocked.surfaceWidth = width; - mLocked.surfaceHeight = height; - - // Configure X and Y factors. - if (mRawAxes.x.valid && mRawAxes.y.valid) { - mLocked.xOrigin = mCalibration.haveXOrigin - ? mCalibration.xOrigin - : mRawAxes.x.minValue; - mLocked.yOrigin = mCalibration.haveYOrigin - ? mCalibration.yOrigin - : mRawAxes.y.minValue; - mLocked.xScale = mCalibration.haveXScale - ? mCalibration.xScale - : float(width) / mRawAxes.x.getRange(); - mLocked.yScale = mCalibration.haveYScale - ? mCalibration.yScale - : float(height) / mRawAxes.y.getRange(); - mLocked.xPrecision = 1.0f / mLocked.xScale; - mLocked.yPrecision = 1.0f / mLocked.yScale; - - configureVirtualKeysLocked(); - } else { - LOGW(INDENT "Touch device did not report support for X or Y axis!"); - mLocked.xOrigin = 0; - mLocked.yOrigin = 0; - mLocked.xScale = 1.0f; - mLocked.yScale = 1.0f; - mLocked.xPrecision = 1.0f; - mLocked.yPrecision = 1.0f; - } - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mLocked.geometricScale = avg(mLocked.xScale, mLocked.yScale); - - // Size of diagonal axis. - float diagonalSize = pythag(width, height); - - // TouchMajor and TouchMinor factors. - if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) { - mLocked.orientedRanges.haveTouchSize = true; - mLocked.orientedRanges.touchMajor.min = 0; - mLocked.orientedRanges.touchMajor.max = diagonalSize; - mLocked.orientedRanges.touchMajor.flat = 0; - mLocked.orientedRanges.touchMajor.fuzz = 0; - mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor; - } - - // ToolMajor and ToolMinor factors. - mLocked.toolSizeLinearScale = 0; - mLocked.toolSizeLinearBias = 0; - mLocked.toolSizeAreaScale = 0; - mLocked.toolSizeAreaBias = 0; - if (mCalibration.toolSizeCalibration != Calibration::TOOL_SIZE_CALIBRATION_NONE) { - if (mCalibration.toolSizeCalibration == Calibration::TOOL_SIZE_CALIBRATION_LINEAR) { - if (mCalibration.haveToolSizeLinearScale) { - mLocked.toolSizeLinearScale = mCalibration.toolSizeLinearScale; - } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { - mLocked.toolSizeLinearScale = float(min(width, height)) - / mRawAxes.toolMajor.maxValue; - } - - if (mCalibration.haveToolSizeLinearBias) { - mLocked.toolSizeLinearBias = mCalibration.toolSizeLinearBias; - } - } else if (mCalibration.toolSizeCalibration == - Calibration::TOOL_SIZE_CALIBRATION_AREA) { - if (mCalibration.haveToolSizeLinearScale) { - mLocked.toolSizeLinearScale = mCalibration.toolSizeLinearScale; - } else { - mLocked.toolSizeLinearScale = min(width, height); - } - - if (mCalibration.haveToolSizeLinearBias) { - mLocked.toolSizeLinearBias = mCalibration.toolSizeLinearBias; - } - - if (mCalibration.haveToolSizeAreaScale) { - mLocked.toolSizeAreaScale = mCalibration.toolSizeAreaScale; - } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { - mLocked.toolSizeAreaScale = 1.0f / mRawAxes.toolMajor.maxValue; - } - - if (mCalibration.haveToolSizeAreaBias) { - mLocked.toolSizeAreaBias = mCalibration.toolSizeAreaBias; - } - } - - mLocked.orientedRanges.haveToolSize = true; - mLocked.orientedRanges.toolMajor.min = 0; - mLocked.orientedRanges.toolMajor.max = diagonalSize; - mLocked.orientedRanges.toolMajor.flat = 0; - mLocked.orientedRanges.toolMajor.fuzz = 0; - mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor; - } - - // Pressure factors. - mLocked.pressureScale = 0; - if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) { - RawAbsoluteAxisInfo rawPressureAxis; - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_PRESSURE: - rawPressureAxis = mRawAxes.pressure; - break; - case Calibration::PRESSURE_SOURCE_TOUCH: - rawPressureAxis = mRawAxes.touchMajor; - break; - default: - rawPressureAxis.clear(); - } - - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mLocked.pressureScale = mCalibration.pressureScale; - } else if (rawPressureAxis.valid && rawPressureAxis.maxValue != 0) { - mLocked.pressureScale = 1.0f / rawPressureAxis.maxValue; - } - } - - mLocked.orientedRanges.havePressure = true; - mLocked.orientedRanges.pressure.min = 0; - mLocked.orientedRanges.pressure.max = 1.0; - mLocked.orientedRanges.pressure.flat = 0; - mLocked.orientedRanges.pressure.fuzz = 0; - } - - // Size factors. - mLocked.sizeScale = 0; - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_NORMALIZED) { - if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { - mLocked.sizeScale = 1.0f / mRawAxes.toolMajor.maxValue; - } - } - - mLocked.orientedRanges.haveSize = true; - mLocked.orientedRanges.size.min = 0; - mLocked.orientedRanges.size.max = 1.0; - mLocked.orientedRanges.size.flat = 0; - mLocked.orientedRanges.size.fuzz = 0; - } - - // Orientation - mLocked.orientationScale = 0; - if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration - == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawAxes.orientation.valid && mRawAxes.orientation.maxValue != 0) { - mLocked.orientationScale = float(M_PI_2) / mRawAxes.orientation.maxValue; - } - } - - mLocked.orientedRanges.orientation.min = - M_PI_2; - mLocked.orientedRanges.orientation.max = M_PI_2; - mLocked.orientedRanges.orientation.flat = 0; - mLocked.orientedRanges.orientation.fuzz = 0; - } - } - - if (orientationChanged || sizeChanged) { - // Compute oriented surface dimensions, precision, and scales. - float orientedXScale, orientedYScale; - switch (mLocked.surfaceOrientation) { - case InputReaderPolicyInterface::ROTATION_90: - case InputReaderPolicyInterface::ROTATION_270: - mLocked.orientedSurfaceWidth = mLocked.surfaceHeight; - mLocked.orientedSurfaceHeight = mLocked.surfaceWidth; - mLocked.orientedXPrecision = mLocked.yPrecision; - mLocked.orientedYPrecision = mLocked.xPrecision; - orientedXScale = mLocked.yScale; - orientedYScale = mLocked.xScale; - break; - default: - mLocked.orientedSurfaceWidth = mLocked.surfaceWidth; - mLocked.orientedSurfaceHeight = mLocked.surfaceHeight; - mLocked.orientedXPrecision = mLocked.xPrecision; - mLocked.orientedYPrecision = mLocked.yPrecision; - orientedXScale = mLocked.xScale; - orientedYScale = mLocked.yScale; - break; - } - - // Configure position ranges. - mLocked.orientedRanges.x.min = 0; - mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth; - mLocked.orientedRanges.x.flat = 0; - mLocked.orientedRanges.x.fuzz = orientedXScale; - - mLocked.orientedRanges.y.min = 0; - mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight; - mLocked.orientedRanges.y.flat = 0; - mLocked.orientedRanges.y.fuzz = orientedYScale; - } - - return true; -} - -void TouchInputMapper::dumpSurfaceLocked(String8& dump) { - dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mLocked.surfaceWidth); - dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mLocked.surfaceHeight); - dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mLocked.surfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeysLocked() { - assert(mRawAxes.x.valid && mRawAxes.y.valid); - - Vector<VirtualKeyDefinition> virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mLocked.virtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size()); - - int32_t touchScreenLeft = mRawAxes.x.minValue; - int32_t touchScreenTop = mRawAxes.y.minValue; - int32_t touchScreenWidth = mRawAxes.x.getRange(); - int32_t touchScreenHeight = mRawAxes.y.getRange(); - - for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const VirtualKeyDefinition& virtualKeyDefinition = - virtualKeyDefinitions[i]; - - mLocked.virtualKeys.add(); - VirtualKey& virtualKey = mLocked.virtualKeys.editTop(); - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - uint32_t flags; - if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, - & keyCode, & flags)) { - LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", - virtualKey.scanCode); - mLocked.virtualKeys.pop(); // drop the key - continue; - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - - } -} - -void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) { - if (!mLocked.virtualKeys.isEmpty()) { - dump.append(INDENT3 "Virtual Keys:\n"); - - for (size_t i = 0; i < mLocked.virtualKeys.size(); i++) { - const VirtualKey& virtualKey = mLocked.virtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, - virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Position - out.haveXOrigin = in.tryGetProperty(String8("touch.position.xOrigin"), out.xOrigin); - out.haveYOrigin = in.tryGetProperty(String8("touch.position.yOrigin"), out.yOrigin); - out.haveXScale = in.tryGetProperty(String8("touch.position.xScale"), out.xScale); - out.haveYScale = in.tryGetProperty(String8("touch.position.yScale"), out.yScale); - - // Touch Size - out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT; - String8 touchSizeCalibrationString; - if (in.tryGetProperty(String8("touch.touchSize.calibration"), touchSizeCalibrationString)) { - if (touchSizeCalibrationString == "none") { - out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_NONE; - } else if (touchSizeCalibrationString == "geometric") { - out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC; - } else if (touchSizeCalibrationString == "pressure") { - out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE; - } else if (touchSizeCalibrationString != "default") { - LOGW("Invalid value for touch.touchSize.calibration: '%s'", - touchSizeCalibrationString.string()); - } - } - - // Tool Size - out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_DEFAULT; - String8 toolSizeCalibrationString; - if (in.tryGetProperty(String8("touch.toolSize.calibration"), toolSizeCalibrationString)) { - if (toolSizeCalibrationString == "none") { - out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_NONE; - } else if (toolSizeCalibrationString == "geometric") { - out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC; - } else if (toolSizeCalibrationString == "linear") { - out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_LINEAR; - } else if (toolSizeCalibrationString == "area") { - out.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_AREA; - } else if (toolSizeCalibrationString != "default") { - LOGW("Invalid value for touch.toolSize.calibration: '%s'", - toolSizeCalibrationString.string()); - } - } - - out.haveToolSizeLinearScale = in.tryGetProperty(String8("touch.toolSize.linearScale"), - out.toolSizeLinearScale); - out.haveToolSizeLinearBias = in.tryGetProperty(String8("touch.toolSize.linearBias"), - out.toolSizeLinearBias); - out.haveToolSizeAreaScale = in.tryGetProperty(String8("touch.toolSize.areaScale"), - out.toolSizeAreaScale); - out.haveToolSizeAreaBias = in.tryGetProperty(String8("touch.toolSize.areaBias"), - out.toolSizeAreaBias); - out.haveToolSizeIsSummed = in.tryGetProperty(String8("touch.toolSize.isSummed"), - out.toolSizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - LOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.pressureSource = Calibration::PRESSURE_SOURCE_DEFAULT; - String8 pressureSourceString; - if (in.tryGetProperty(String8("touch.pressure.source"), pressureSourceString)) { - if (pressureSourceString == "pressure") { - out.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; - } else if (pressureSourceString == "touch") { - out.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; - } else if (pressureSourceString != "default") { - LOGW("Invalid value for touch.pressure.source: '%s'", - pressureSourceString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), - out.pressureScale); - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "normalized") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; - } else if (sizeCalibrationString != "default") { - LOGW("Invalid value for touch.size.calibration: '%s'", - sizeCalibrationString.string()); - } - } - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString != "default") { - LOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Pressure - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_DEFAULT: - if (mRawAxes.pressure.valid) { - mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; - } else if (mRawAxes.touchMajor.valid) { - mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; - } - break; - - case Calibration::PRESSURE_SOURCE_PRESSURE: - if (! mRawAxes.pressure.valid) { - LOGW("Calibration property touch.pressure.source is 'pressure' but " - "the pressure axis is not available."); - } - break; - - case Calibration::PRESSURE_SOURCE_TOUCH: - if (! mRawAxes.touchMajor.valid) { - LOGW("Calibration property touch.pressure.source is 'touch' but " - "the touchMajor axis is not available."); - } - break; - - default: - break; - } - - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_DEFAULT: - if (mCalibration.pressureSource != Calibration::PRESSURE_SOURCE_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - break; - - default: - break; - } - - // Tool Size - switch (mCalibration.toolSizeCalibration) { - case Calibration::TOOL_SIZE_CALIBRATION_DEFAULT: - if (mRawAxes.toolMajor.valid) { - mCalibration.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_LINEAR; - } else { - mCalibration.toolSizeCalibration = Calibration::TOOL_SIZE_CALIBRATION_NONE; - } - break; - - default: - break; - } - - // Touch Size - switch (mCalibration.touchSizeCalibration) { - case Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT: - if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE - && mCalibration.toolSizeCalibration != Calibration::TOOL_SIZE_CALIBRATION_NONE) { - mCalibration.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE; - } else { - mCalibration.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_NONE; - } - break; - - default: - break; - } - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_DEFAULT: - if (mRawAxes.toolMajor.valid) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - break; - - default: - break; - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_DEFAULT: - if (mRawAxes.orientation.valid) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - break; - - default: - break; - } -} - -void TouchInputMapper::dumpCalibration(String8& dump) { - dump.append(INDENT3 "Calibration:\n"); - - // Position - if (mCalibration.haveXOrigin) { - dump.appendFormat(INDENT4 "touch.position.xOrigin: %d\n", mCalibration.xOrigin); - } - if (mCalibration.haveYOrigin) { - dump.appendFormat(INDENT4 "touch.position.yOrigin: %d\n", mCalibration.yOrigin); - } - if (mCalibration.haveXScale) { - dump.appendFormat(INDENT4 "touch.position.xScale: %0.3f\n", mCalibration.xScale); - } - if (mCalibration.haveYScale) { - dump.appendFormat(INDENT4 "touch.position.yScale: %0.3f\n", mCalibration.yScale); - } - - // Touch Size - switch (mCalibration.touchSizeCalibration) { - case Calibration::TOUCH_SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.touchSize.calibration: none\n"); - break; - case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.touchSize.calibration: geometric\n"); - break; - case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE: - dump.append(INDENT4 "touch.touchSize.calibration: pressure\n"); - break; - default: - assert(false); - } - - // Tool Size - switch (mCalibration.toolSizeCalibration) { - case Calibration::TOOL_SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.toolSize.calibration: none\n"); - break; - case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.toolSize.calibration: geometric\n"); - break; - case Calibration::TOOL_SIZE_CALIBRATION_LINEAR: - dump.append(INDENT4 "touch.toolSize.calibration: linear\n"); - break; - case Calibration::TOOL_SIZE_CALIBRATION_AREA: - dump.append(INDENT4 "touch.toolSize.calibration: area\n"); - break; - default: - assert(false); - } - - if (mCalibration.haveToolSizeLinearScale) { - dump.appendFormat(INDENT4 "touch.toolSize.linearScale: %0.3f\n", - mCalibration.toolSizeLinearScale); - } - - if (mCalibration.haveToolSizeLinearBias) { - dump.appendFormat(INDENT4 "touch.toolSize.linearBias: %0.3f\n", - mCalibration.toolSizeLinearBias); - } - - if (mCalibration.haveToolSizeAreaScale) { - dump.appendFormat(INDENT4 "touch.toolSize.areaScale: %0.3f\n", - mCalibration.toolSizeAreaScale); - } - - if (mCalibration.haveToolSizeAreaBias) { - dump.appendFormat(INDENT4 "touch.toolSize.areaBias: %0.3f\n", - mCalibration.toolSizeAreaBias); - } - - if (mCalibration.haveToolSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %s\n", - toString(mCalibration.toolSizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.pressure.calibration: none\n"); - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump.append(INDENT4 "touch.pressure.calibration: physical\n"); - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); - break; - default: - assert(false); - } - - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_PRESSURE: - dump.append(INDENT4 "touch.pressure.source: pressure\n"); - break; - case Calibration::PRESSURE_SOURCE_TOUCH: - dump.append(INDENT4 "touch.pressure.source: touch\n"); - break; - case Calibration::PRESSURE_SOURCE_DEFAULT: - break; - default: - assert(false); - } - - if (mCalibration.havePressureScale) { - dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", - mCalibration.pressureScale); - } - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.size.calibration: none\n"); - break; - case Calibration::SIZE_CALIBRATION_NORMALIZED: - dump.append(INDENT4 "touch.size.calibration: normalized\n"); - break; - default: - assert(false); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump.append(INDENT4 "touch.orientation.calibration: none\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); - break; - default: - assert(false); - } -} - -void TouchInputMapper::reset() { - // Synthesize touch up event if touch is currently down. - // This will also take care of finishing virtual key processing if needed. - if (mLastTouch.pointerCount != 0) { - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mCurrentTouch.clear(); - syncTouch(when, true); - } - - { // acquire lock - AutoMutex _l(mLock); - initializeLocked(); - } // release lock - - InputMapper::reset(); -} - -void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { - uint32_t policyFlags = 0; - - // Preprocess pointer data. - - if (mParameters.useBadTouchFilter) { - if (applyBadTouchFilter()) { - havePointerIds = false; - } - } - - if (mParameters.useJumpyTouchFilter) { - if (applyJumpyTouchFilter()) { - havePointerIds = false; - } - } - - if (! havePointerIds) { - calculatePointerIds(); - } - - TouchData temp; - TouchData* savedTouch; - if (mParameters.useAveragingTouchFilter) { - temp.copyFrom(mCurrentTouch); - savedTouch = & temp; - - applyAveragingTouchFilter(); - } else { - savedTouch = & mCurrentTouch; - } - - // Process touches and virtual keys. - - TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); - if (touchResult == DISPATCH_TOUCH) { - dispatchTouches(when, policyFlags); - } - - // Copy current touch to last touch in preparation for the next cycle. - - if (touchResult == DROP_STROKE) { - mLastTouch.clear(); - } else { - mLastTouch.copyFrom(*savedTouch); - } -} - -TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( - nsecs_t when, uint32_t policyFlags) { - int32_t keyEventAction, keyEventFlags; - int32_t keyCode, scanCode, downTime; - TouchResult touchResult; - - { // acquire lock - AutoMutex _l(mLock); - - // Update surface size and orientation, including virtual key positions. - if (! configureSurfaceLocked()) { - return DROP_STROKE; - } - - // Check for virtual key press. - if (mLocked.currentVirtualKey.down) { - if (mCurrentTouch.pointerCount == 0) { - // Pointer went up while virtual key was down. - mLocked.currentVirtualKey.down = false; -#if DEBUG_VIRTUAL_KEYS - LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); -#endif - keyEventAction = AKEY_EVENT_ACTION_UP; - keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - touchResult = SKIP_TOUCH; - goto DispatchVirtualKey; - } - - if (mCurrentTouch.pointerCount == 1) { - int32_t x = mCurrentTouch.pointers[0].x; - int32_t y = mCurrentTouch.pointers[0].y; - const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y); - if (virtualKey && virtualKey->keyCode == mLocked.currentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return SKIP_TOUCH; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation and drop the stroke so subsequent motions will be - // considered fresh downs. This is useful when the user swipes away from the - // virtual key area into the main display surface. - mLocked.currentVirtualKey.down = false; -#if DEBUG_VIRTUAL_KEYS - LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); -#endif - keyEventAction = AKEY_EVENT_ACTION_UP; - keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED; - - // Check whether the pointer moved inside the display area where we should - // start a new stroke. - int32_t x = mCurrentTouch.pointers[0].x; - int32_t y = mCurrentTouch.pointers[0].y; - if (isPointInsideSurfaceLocked(x, y)) { - mLastTouch.clear(); - touchResult = DISPATCH_TOUCH; - } else { - touchResult = DROP_STROKE; - } - } else { - if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) { - // Pointer just went down. Handle off-screen touches, if needed. - int32_t x = mCurrentTouch.pointers[0].x; - int32_t y = mCurrentTouch.pointers[0].y; - if (! isPointInsideSurfaceLocked(x, y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentTouch.pointerCount == 1) { - const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y); - if (virtualKey) { - mLocked.currentVirtualKey.down = true; - mLocked.currentVirtualKey.downTime = when; - mLocked.currentVirtualKey.keyCode = virtualKey->keyCode; - mLocked.currentVirtualKey.scanCode = virtualKey->scanCode; -#if DEBUG_VIRTUAL_KEYS - LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mLocked.currentVirtualKey.keyCode, - mLocked.currentVirtualKey.scanCode); -#endif - keyEventAction = AKEY_EVENT_ACTION_DOWN; - keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM - | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - touchResult = SKIP_TOUCH; - goto DispatchVirtualKey; - } - } - return DROP_STROKE; - } - } - return DISPATCH_TOUCH; - } - - DispatchVirtualKey: - // Collect remaining state needed to dispatch virtual key. - keyCode = mLocked.currentVirtualKey.keyCode; - scanCode = mLocked.currentVirtualKey.scanCode; - downTime = mLocked.currentVirtualKey.downTime; - } // release lock - - // Dispatch virtual key. - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - return touchResult; -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - uint32_t currentPointerCount = mCurrentTouch.pointerCount; - uint32_t lastPointerCount = mLastTouch.pointerCount; - if (currentPointerCount == 0 && lastPointerCount == 0) { - return; // nothing to do! - } - - BitSet32 currentIdBits = mCurrentTouch.idBits; - BitSet32 lastIdBits = mLastTouch.idBits; - - if (currentIdBits == lastIdBits) { - // No pointer id changes so this is a move event. - // The dispatcher takes care of batching moves so we don't have to deal with that here. - int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE; - dispatchTouch(when, policyFlags, & mCurrentTouch, - currentIdBits, -1, currentPointerCount, motionEventAction); - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); - BitSet32 activeIdBits(lastIdBits.value); - uint32_t pointerCount = lastPointerCount; - - // Produce an intermediate representation of the touch data that consists of the - // old location of pointers that have just gone up and the new location of pointers that - // have just moved but omits the location of pointers that have just gone down. - TouchData interimTouch; - interimTouch.copyFrom(mLastTouch); - - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - bool moveNeeded = false; - while (!moveIdBits.isEmpty()) { - uint32_t moveId = moveIdBits.firstMarkedBit(); - moveIdBits.clearBit(moveId); - - int32_t oldIndex = mLastTouch.idToIndex[moveId]; - int32_t newIndex = mCurrentTouch.idToIndex[moveId]; - if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) { - interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex]; - moveNeeded = true; - } - } - - // Dispatch pointer up events using the interim pointer locations. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.firstMarkedBit(); - upIdBits.clearBit(upId); - BitSet32 oldActiveIdBits = activeIdBits; - activeIdBits.clearBit(upId); - - int32_t motionEventAction; - if (activeIdBits.isEmpty()) { - motionEventAction = AMOTION_EVENT_ACTION_UP; - } else { - motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP; - } - - dispatchTouch(when, policyFlags, &interimTouch, - oldActiveIdBits, upId, pointerCount, motionEventAction); - pointerCount -= 1; - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { - dispatchTouch(when, policyFlags, &mCurrentTouch, - activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.firstMarkedBit(); - downIdBits.clearBit(downId); - BitSet32 oldActiveIdBits = activeIdBits; - activeIdBits.markBit(downId); - - int32_t motionEventAction; - if (oldActiveIdBits.isEmpty()) { - motionEventAction = AMOTION_EVENT_ACTION_DOWN; - mDownTime = when; - } else { - motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN; - } - - pointerCount += 1; - dispatchTouch(when, policyFlags, &mCurrentTouch, - activeIdBits, downId, pointerCount, motionEventAction); - } - } -} - -void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, - TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, - int32_t motionEventAction) { - int32_t pointerIds[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - int32_t motionEventEdgeFlags = 0; - float xPrecision, yPrecision; - - { // acquire lock - AutoMutex _l(mLock); - - // Walk through the the active pointers and map touch screen coordinates (TouchData) into - // display coordinates (PointerCoords) and adjust for display orientation. - for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - uint32_t inIndex = touch->idToIndex[id]; - - const PointerData& in = touch->pointers[inIndex]; - - // X and Y - float x = float(in.x - mLocked.xOrigin) * mLocked.xScale; - float y = float(in.y - mLocked.yOrigin) * mLocked.yScale; - - // ToolMajor and ToolMinor - float toolMajor, toolMinor; - switch (mCalibration.toolSizeCalibration) { - case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC: - toolMajor = in.toolMajor * mLocked.geometricScale; - if (mRawAxes.toolMinor.valid) { - toolMinor = in.toolMinor * mLocked.geometricScale; - } else { - toolMinor = toolMajor; - } - break; - case Calibration::TOOL_SIZE_CALIBRATION_LINEAR: - toolMajor = in.toolMajor != 0 - ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias - : 0; - if (mRawAxes.toolMinor.valid) { - toolMinor = in.toolMinor != 0 - ? in.toolMinor * mLocked.toolSizeLinearScale - + mLocked.toolSizeLinearBias - : 0; - } else { - toolMinor = toolMajor; - } - break; - case Calibration::TOOL_SIZE_CALIBRATION_AREA: - if (in.toolMajor != 0) { - float diameter = sqrtf(in.toolMajor - * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias); - toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias; - } else { - toolMajor = 0; - } - toolMinor = toolMajor; - break; - default: - toolMajor = 0; - toolMinor = 0; - break; - } - - if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) { - toolMajor /= pointerCount; - toolMinor /= pointerCount; - } - - // Pressure - float rawPressure; - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_PRESSURE: - rawPressure = in.pressure; - break; - case Calibration::PRESSURE_SOURCE_TOUCH: - rawPressure = in.touchMajor; - break; - default: - rawPressure = 0; - } - - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = rawPressure * mLocked.pressureScale; - break; - default: - pressure = 1; - break; - } - - // TouchMajor and TouchMinor - float touchMajor, touchMinor; - switch (mCalibration.touchSizeCalibration) { - case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC: - touchMajor = in.touchMajor * mLocked.geometricScale; - if (mRawAxes.touchMinor.valid) { - touchMinor = in.touchMinor * mLocked.geometricScale; - } else { - touchMinor = touchMajor; - } - break; - case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE: - touchMajor = toolMajor * pressure; - touchMinor = toolMinor * pressure; - break; - default: - touchMajor = 0; - touchMinor = 0; - break; - } - - if (touchMajor > toolMajor) { - touchMajor = toolMajor; - } - if (touchMinor > toolMinor) { - touchMinor = toolMinor; - } - - // Size - float size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NORMALIZED: { - float rawSize = mRawAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) - : in.toolMajor; - size = rawSize * mLocked.sizeScale; - break; - } - default: - size = 0; - break; - } - - // Orientation - float orientation; - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mLocked.orientationScale; - break; - default: - orientation = 0; - } - - // Adjust coords for orientation. - switch (mLocked.surfaceOrientation) { - case InputReaderPolicyInterface::ROTATION_90: { - float xTemp = x; - x = y; - y = mLocked.surfaceWidth - xTemp; - orientation -= M_PI_2; - if (orientation < - M_PI_2) { - orientation += M_PI; - } - break; - } - case InputReaderPolicyInterface::ROTATION_180: { - x = mLocked.surfaceWidth - x; - y = mLocked.surfaceHeight - y; - orientation = - orientation; - break; - } - case InputReaderPolicyInterface::ROTATION_270: { - float xTemp = x; - x = mLocked.surfaceHeight - y; - y = xTemp; - orientation += M_PI_2; - if (orientation > M_PI_2) { - orientation -= M_PI; - } - break; - } - } - - // Write output coords. - PointerCoords& out = pointerCoords[outIndex]; - out.x = x; - out.y = y; - out.pressure = pressure; - out.size = size; - out.touchMajor = touchMajor; - out.touchMinor = touchMinor; - out.toolMajor = toolMajor; - out.toolMinor = toolMinor; - out.orientation = orientation; - - pointerIds[outIndex] = int32_t(id); - - if (id == changedId) { - motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - } - - // Check edge flags by looking only at the first pointer since the flags are - // global to the event. - if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { - if (pointerCoords[0].x <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; - } else if (pointerCoords[0].x >= mLocked.orientedSurfaceWidth) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; - } - if (pointerCoords[0].y <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; - } else if (pointerCoords[0].y >= mLocked.orientedSurfaceHeight) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; - } - } - - xPrecision = mLocked.orientedXPrecision; - yPrecision = mLocked.orientedYPrecision; - } // release lock - - getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags, - motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags, - pointerCount, pointerIds, pointerCoords, - xPrecision, yPrecision, mDownTime); -} - -bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { - if (mRawAxes.x.valid && mRawAxes.y.valid) { - return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue - && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; - } - return true; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked( - int32_t x, int32_t y) { - size_t numVirtualKeys = mLocked.virtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mLocked.virtualKeys[i]; - -#if DEBUG_VIRTUAL_KEYS - LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return NULL; -} - -void TouchInputMapper::calculatePointerIds() { - uint32_t currentPointerCount = mCurrentTouch.pointerCount; - uint32_t lastPointerCount = mLastTouch.pointerCount; - - if (currentPointerCount == 0) { - // No pointers to assign. - mCurrentTouch.idBits.clear(); - } else if (lastPointerCount == 0) { - // All pointers are new. - mCurrentTouch.idBits.clear(); - for (uint32_t i = 0; i < currentPointerCount; i++) { - mCurrentTouch.pointers[i].id = i; - mCurrentTouch.idToIndex[i] = i; - mCurrentTouch.idBits.markBit(i); - } - } else if (currentPointerCount == 1 && lastPointerCount == 1) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastTouch.pointers[0].id; - mCurrentTouch.pointers[0].id = id; - mCurrentTouch.idToIndex[id] = 0; - mCurrentTouch.idBits.value = BitSet32::valueForBit(id); - } else { - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - int64_t deltaX = mCurrentTouch.pointers[currentPointerIndex].x - - mLastTouch.pointers[lastPointerIndex].x; - int64_t deltaY = mCurrentTouch.pointers[currentPointerIndex].y - - mLastTouch.pointers[lastPointerIndex].y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) { - for (;;) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heapSize -= 1; - assert(heapSize > 0); - - // Sift down. - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = mLastTouch.pointers[lastPointerIndex].id; - mCurrentTouch.pointers[currentPointerIndex].id = id; - mCurrentTouch.idToIndex[id] = currentPointerIndex; - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to new pointers. - if (currentPointerCount > lastPointerCount) { - for (uint32_t i = currentPointerCount - lastPointerCount; ;) { - uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit(); - uint32_t id = usedIdBits.firstUnmarkedBit(); - - mCurrentTouch.pointers[currentPointerIndex].id = id; - mCurrentTouch.idToIndex[id] = currentPointerIndex; - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); -#endif - - if (--i == 0) break; // done - matchedCurrentBits.markBit(currentPointerIndex); - } - } - - // Fix id bits. - mCurrentTouch.idBits = usedIdBits; - } -} - -/* Special hack for devices that have bad screen data: if one of the - * points has moved more than a screen height from the last position, - * then drop it. */ -bool TouchInputMapper::applyBadTouchFilter() { - // This hack requires valid axis parameters. - if (! mRawAxes.y.valid) { - return false; - } - - uint32_t pointerCount = mCurrentTouch.pointerCount; - - // Nothing to do if there are no points. - if (pointerCount == 0) { - return false; - } - - // Don't do anything if a finger is going down or up. We run - // here before assigning pointer IDs, so there isn't a good - // way to do per-finger matching. - if (pointerCount != mLastTouch.pointerCount) { - return false; - } - - // We consider a single movement across more than a 7/16 of - // the long size of the screen to be bad. This was a magic value - // determined by looking at the maximum distance it is feasible - // to actually move in one sample. - int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16; - - // XXX The original code in InputDevice.java included commented out - // code for testing the X axis. Note that when we drop a point - // we don't actually restore the old X either. Strange. - // The old code also tries to track when bad points were previously - // detected but it turns out that due to the placement of a "break" - // at the end of the loop, we never set mDroppedBadPoint to true - // so it is effectively dead code. - // Need to figure out if the old code is busted or just overcomplicated - // but working as intended. - - // Look through all new points and see if any are farther than - // acceptable from all previous points. - for (uint32_t i = pointerCount; i-- > 0; ) { - int32_t y = mCurrentTouch.pointers[i].y; - int32_t closestY = INT_MAX; - int32_t closestDeltaY = 0; - -#if DEBUG_HACKS - LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y); -#endif - - for (uint32_t j = pointerCount; j-- > 0; ) { - int32_t lastY = mLastTouch.pointers[j].y; - int32_t deltaY = abs(y - lastY); - -#if DEBUG_HACKS - LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d", - j, lastY, deltaY); -#endif - - if (deltaY < maxDeltaY) { - goto SkipSufficientlyClosePoint; - } - if (deltaY < closestDeltaY) { - closestDeltaY = deltaY; - closestY = lastY; - } - } - - // Must not have found a close enough match. -#if DEBUG_HACKS - LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d", - i, y, closestY, closestDeltaY, maxDeltaY); -#endif - - mCurrentTouch.pointers[i].y = closestY; - return true; // XXX original code only corrects one point - - SkipSufficientlyClosePoint: ; - } - - // No change. - return false; -} - -/* Special hack for devices that have bad screen data: drop points where - * the coordinate value for one axis has jumped to the other pointer's location. - */ -bool TouchInputMapper::applyJumpyTouchFilter() { - // This hack requires valid axis parameters. - if (! mRawAxes.y.valid) { - return false; - } - - uint32_t pointerCount = mCurrentTouch.pointerCount; - if (mLastTouch.pointerCount != pointerCount) { -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Different pointer count %d -> %d", - mLastTouch.pointerCount, pointerCount); - for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d (%d, %d)", i, - mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y); - } -#endif - - if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) { - if (mLastTouch.pointerCount == 1 && pointerCount == 2) { - // Just drop the first few events going from 1 to 2 pointers. - // They're bad often enough that they're not worth considering. - mCurrentTouch.pointerCount = 1; - mJumpyTouchFilter.jumpyPointsDropped += 1; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Pointer 2 dropped"); -#endif - return true; - } else if (mLastTouch.pointerCount == 2 && pointerCount == 1) { - // The event when we go from 2 -> 1 tends to be messed up too - mCurrentTouch.pointerCount = 2; - mCurrentTouch.pointers[0] = mLastTouch.pointers[0]; - mCurrentTouch.pointers[1] = mLastTouch.pointers[1]; - mJumpyTouchFilter.jumpyPointsDropped += 1; - -#if DEBUG_HACKS - for (int32_t i = 0; i < 2; i++) { - LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i, - mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y); - } -#endif - return true; - } - } - // Reset jumpy points dropped on other transitions or if limit exceeded. - mJumpyTouchFilter.jumpyPointsDropped = 0; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Transition - drop limit reset"); -#endif - return false; - } - - // We have the same number of pointers as last time. - // A 'jumpy' point is one where the coordinate value for one axis - // has jumped to the other pointer's location. No need to do anything - // else if we only have one pointer. - if (pointerCount < 2) { - return false; - } - - if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { - int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; - - // We only replace the single worst jumpy point as characterized by pointer distance - // in a single axis. - int32_t badPointerIndex = -1; - int32_t badPointerReplacementIndex = -1; - int32_t badPointerDistance = INT_MIN; // distance to be corrected - - for (uint32_t i = pointerCount; i-- > 0; ) { - int32_t x = mCurrentTouch.pointers[i].x; - int32_t y = mCurrentTouch.pointers[i].y; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y); -#endif - - // Check if a touch point is too close to another's coordinates - bool dropX = false, dropY = false; - for (uint32_t j = 0; j < pointerCount; j++) { - if (i == j) { - continue; - } - - if (abs(x - mCurrentTouch.pointers[j].x) <= jumpyEpsilon) { - dropX = true; - break; - } - - if (abs(y - mCurrentTouch.pointers[j].y) <= jumpyEpsilon) { - dropY = true; - break; - } - } - if (! dropX && ! dropY) { - continue; // not jumpy - } - - // Find a replacement candidate by comparing with older points on the - // complementary (non-jumpy) axis. - int32_t distance = INT_MIN; // distance to be corrected - int32_t replacementIndex = -1; - - if (dropX) { - // X looks too close. Find an older replacement point with a close Y. - int32_t smallestDeltaY = INT_MAX; - for (uint32_t j = 0; j < pointerCount; j++) { - int32_t deltaY = abs(y - mLastTouch.pointers[j].y); - if (deltaY < smallestDeltaY) { - smallestDeltaY = deltaY; - replacementIndex = j; - } - } - distance = abs(x - mLastTouch.pointers[replacementIndex].x); - } else { - // Y looks too close. Find an older replacement point with a close X. - int32_t smallestDeltaX = INT_MAX; - for (uint32_t j = 0; j < pointerCount; j++) { - int32_t deltaX = abs(x - mLastTouch.pointers[j].x); - if (deltaX < smallestDeltaX) { - smallestDeltaX = deltaX; - replacementIndex = j; - } - } - distance = abs(y - mLastTouch.pointers[replacementIndex].y); - } - - // If replacing this pointer would correct a worse error than the previous ones - // considered, then use this replacement instead. - if (distance > badPointerDistance) { - badPointerIndex = i; - badPointerReplacementIndex = replacementIndex; - badPointerDistance = distance; - } - } - - // Correct the jumpy pointer if one was found. - if (badPointerIndex >= 0) { -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)", - badPointerIndex, - mLastTouch.pointers[badPointerReplacementIndex].x, - mLastTouch.pointers[badPointerReplacementIndex].y); -#endif - - mCurrentTouch.pointers[badPointerIndex].x = - mLastTouch.pointers[badPointerReplacementIndex].x; - mCurrentTouch.pointers[badPointerIndex].y = - mLastTouch.pointers[badPointerReplacementIndex].y; - mJumpyTouchFilter.jumpyPointsDropped += 1; - return true; - } - } - - mJumpyTouchFilter.jumpyPointsDropped = 0; - return false; -} - -/* Special hack for devices that have bad screen data: aggregate and - * compute averages of the coordinate data, to reduce the amount of - * jitter seen by applications. */ -void TouchInputMapper::applyAveragingTouchFilter() { - for (uint32_t currentIndex = 0; currentIndex < mCurrentTouch.pointerCount; currentIndex++) { - uint32_t id = mCurrentTouch.pointers[currentIndex].id; - int32_t x = mCurrentTouch.pointers[currentIndex].x; - int32_t y = mCurrentTouch.pointers[currentIndex].y; - int32_t pressure; - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_PRESSURE: - pressure = mCurrentTouch.pointers[currentIndex].pressure; - break; - case Calibration::PRESSURE_SOURCE_TOUCH: - pressure = mCurrentTouch.pointers[currentIndex].touchMajor; - break; - default: - pressure = 1; - break; - } - - if (mLastTouch.idBits.hasBit(id)) { - // Pointer was down before and is still down now. - // Compute average over history trace. - uint32_t start = mAveragingTouchFilter.historyStart[id]; - uint32_t end = mAveragingTouchFilter.historyEnd[id]; - - int64_t deltaX = x - mAveragingTouchFilter.historyData[end].pointers[id].x; - int64_t deltaY = y - mAveragingTouchFilter.historyData[end].pointers[id].y; - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld", - id, distance); -#endif - - if (distance < AVERAGING_DISTANCE_LIMIT) { - // Increment end index in preparation for recording new historical data. - end += 1; - if (end > AVERAGING_HISTORY_SIZE) { - end = 0; - } - - // If the end index has looped back to the start index then we have filled - // the historical trace up to the desired size so we drop the historical - // data at the start of the trace. - if (end == start) { - start += 1; - if (start > AVERAGING_HISTORY_SIZE) { - start = 0; - } - } - - // Add the raw data to the historical trace. - mAveragingTouchFilter.historyStart[id] = start; - mAveragingTouchFilter.historyEnd[id] = end; - mAveragingTouchFilter.historyData[end].pointers[id].x = x; - mAveragingTouchFilter.historyData[end].pointers[id].y = y; - mAveragingTouchFilter.historyData[end].pointers[id].pressure = pressure; - - // Average over all historical positions in the trace by total pressure. - int32_t averagedX = 0; - int32_t averagedY = 0; - int32_t totalPressure = 0; - for (;;) { - int32_t historicalX = mAveragingTouchFilter.historyData[start].pointers[id].x; - int32_t historicalY = mAveragingTouchFilter.historyData[start].pointers[id].y; - int32_t historicalPressure = mAveragingTouchFilter.historyData[start] - .pointers[id].pressure; - - averagedX += historicalX * historicalPressure; - averagedY += historicalY * historicalPressure; - totalPressure += historicalPressure; - - if (start == end) { - break; - } - - start += 1; - if (start > AVERAGING_HISTORY_SIZE) { - start = 0; - } - } - - if (totalPressure != 0) { - averagedX /= totalPressure; - averagedY /= totalPressure; - -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - " - "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, - averagedX, averagedY); -#endif - - mCurrentTouch.pointers[currentIndex].x = averagedX; - mCurrentTouch.pointers[currentIndex].y = averagedY; - } - } else { -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id); -#endif - } - } else { -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id); -#endif - } - - // Reset pointer history. - mAveragingTouchFilter.historyStart[id] = 0; - mAveragingTouchFilter.historyEnd[id] = 0; - mAveragingTouchFilter.historyData[0].pointers[id].x = x; - mAveragingTouchFilter.historyData[0].pointers[id].y = y; - mAveragingTouchFilter.historyData[0].pointers[id].pressure = pressure; - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - { // acquire lock - AutoMutex _l(mLock); - - if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mLocked.virtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mLocked.virtualKeys[i]; - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - } // release lock - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - { // acquire lock - AutoMutex _l(mLock); - - if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mLocked.virtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mLocked.virtualKeys[i]; - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - } // release lock - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - { // acquire lock - AutoMutex _l(mLock); - - size_t numVirtualKeys = mLocked.virtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mLocked.virtualKeys[i]; - - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - } // release lock - - return true; -} - - -// --- SingleTouchInputMapper --- - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { - initialize(); -} - -SingleTouchInputMapper::~SingleTouchInputMapper() { -} - -void SingleTouchInputMapper::initialize() { - mAccumulator.clear(); - - mDown = false; - mX = 0; - mY = 0; - mPressure = 0; // default to 0 for devices that don't report pressure - mToolWidth = 0; // default to 0 for devices that don't report tool width -} - -void SingleTouchInputMapper::reset() { - TouchInputMapper::reset(); - - initialize(); - } - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: - switch (rawEvent->scanCode) { - case BTN_TOUCH: - mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH; - mAccumulator.btnTouch = rawEvent->value != 0; - // Don't sync immediately. Wait until the next SYN_REPORT since we might - // not have received valid position information yet. This logic assumes that - // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet. - break; - } - break; - - case EV_ABS: - switch (rawEvent->scanCode) { - case ABS_X: - mAccumulator.fields |= Accumulator::FIELD_ABS_X; - mAccumulator.absX = rawEvent->value; - break; - case ABS_Y: - mAccumulator.fields |= Accumulator::FIELD_ABS_Y; - mAccumulator.absY = rawEvent->value; - break; - case ABS_PRESSURE: - mAccumulator.fields |= Accumulator::FIELD_ABS_PRESSURE; - mAccumulator.absPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAccumulator.fields |= Accumulator::FIELD_ABS_TOOL_WIDTH; - mAccumulator.absToolWidth = rawEvent->value; - break; - } - break; - - case EV_SYN: - switch (rawEvent->scanCode) { - case SYN_REPORT: - sync(rawEvent->when); - break; - } - break; - } -} - -void SingleTouchInputMapper::sync(nsecs_t when) { - uint32_t fields = mAccumulator.fields; - if (fields == 0) { - return; // no new state changes, so nothing to do - } - - if (fields & Accumulator::FIELD_BTN_TOUCH) { - mDown = mAccumulator.btnTouch; - } - - if (fields & Accumulator::FIELD_ABS_X) { - mX = mAccumulator.absX; - } - - if (fields & Accumulator::FIELD_ABS_Y) { - mY = mAccumulator.absY; - } - - if (fields & Accumulator::FIELD_ABS_PRESSURE) { - mPressure = mAccumulator.absPressure; - } - - if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) { - mToolWidth = mAccumulator.absToolWidth; - } - - mCurrentTouch.clear(); - - if (mDown) { - mCurrentTouch.pointerCount = 1; - mCurrentTouch.pointers[0].id = 0; - mCurrentTouch.pointers[0].x = mX; - mCurrentTouch.pointers[0].y = mY; - mCurrentTouch.pointers[0].pressure = mPressure; - mCurrentTouch.pointers[0].touchMajor = 0; - mCurrentTouch.pointers[0].touchMinor = 0; - mCurrentTouch.pointers[0].toolMajor = mToolWidth; - mCurrentTouch.pointers[0].toolMinor = mToolWidth; - mCurrentTouch.pointers[0].orientation = 0; - mCurrentTouch.idToIndex[0] = 0; - mCurrentTouch.idBits.markBit(0); - } - - syncTouch(when, true); - - mAccumulator.clear(); -} - -void SingleTouchInputMapper::configureRawAxes() { - TouchInputMapper::configureRawAxes(); - - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mRawAxes.pressure); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mRawAxes.toolMajor); -} - - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { - initialize(); -} - -MultiTouchInputMapper::~MultiTouchInputMapper() { -} - -void MultiTouchInputMapper::initialize() { - mAccumulator.clear(); -} - -void MultiTouchInputMapper::reset() { - TouchInputMapper::reset(); - - initialize(); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - uint32_t pointerIndex = mAccumulator.pointerCount; - Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex]; - - switch (rawEvent->scanCode) { - case ABS_MT_POSITION_X: - pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X; - pointer->absMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y; - pointer->absMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR; - pointer->absMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR; - pointer->absMTTouchMinor = rawEvent->value; - break; - case ABS_MT_WIDTH_MAJOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR; - pointer->absMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR; - pointer->absMTWidthMinor = rawEvent->value; - break; - case ABS_MT_ORIENTATION: - pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION; - pointer->absMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; - pointer->absMTTrackingId = rawEvent->value; - break; - case ABS_MT_PRESSURE: - pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; - pointer->absMTPressure = rawEvent->value; - break; - } - break; - } - - case EV_SYN: - switch (rawEvent->scanCode) { - case SYN_MT_REPORT: { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - uint32_t pointerIndex = mAccumulator.pointerCount; - - if (mAccumulator.pointers[pointerIndex].fields) { - if (pointerIndex == MAX_POINTERS) { - LOGW("MultiTouch device driver returned more than maximum of %d pointers.", - MAX_POINTERS); - } else { - pointerIndex += 1; - mAccumulator.pointerCount = pointerIndex; - } - } - - mAccumulator.pointers[pointerIndex].clear(); - break; - } - - case SYN_REPORT: - sync(rawEvent->when); - break; - } - break; - } -} - -void MultiTouchInputMapper::sync(nsecs_t when) { - static const uint32_t REQUIRED_FIELDS = - Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y; - - uint32_t inCount = mAccumulator.pointerCount; - uint32_t outCount = 0; - bool havePointerIds = true; - - mCurrentTouch.clear(); - - for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) { - const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex]; - uint32_t fields = inPointer.fields; - - if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) { - // Some drivers send empty MT sync packets without X / Y to indicate a pointer up. - // Drop this finger. - continue; - } - - PointerData& outPointer = mCurrentTouch.pointers[outCount]; - outPointer.x = inPointer.absMTPositionX; - outPointer.y = inPointer.absMTPositionY; - - if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { - if (inPointer.absMTPressure <= 0) { - // Some devices send sync packets with X / Y but with a 0 pressure to indicate - // a pointer going up. Drop this finger. - continue; - } - outPointer.pressure = inPointer.absMTPressure; - } else { - // Default pressure to 0 if absent. - outPointer.pressure = 0; - } - - if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) { - if (inPointer.absMTTouchMajor <= 0) { - // Some devices send sync packets with X / Y but with a 0 touch major to indicate - // a pointer going up. Drop this finger. - continue; - } - outPointer.touchMajor = inPointer.absMTTouchMajor; - } else { - // Default touch area to 0 if absent. - outPointer.touchMajor = 0; - } - - if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) { - outPointer.touchMinor = inPointer.absMTTouchMinor; - } else { - // Assume touch area is circular. - outPointer.touchMinor = outPointer.touchMajor; - } - - if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) { - outPointer.toolMajor = inPointer.absMTWidthMajor; - } else { - // Default tool area to 0 if absent. - outPointer.toolMajor = 0; - } - - if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) { - outPointer.toolMinor = inPointer.absMTWidthMinor; - } else { - // Assume tool area is circular. - outPointer.toolMinor = outPointer.toolMajor; - } - - if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) { - outPointer.orientation = inPointer.absMTOrientation; - } else { - // Default orientation to vertical if absent. - outPointer.orientation = 0; - } - - // Assign pointer id using tracking id if available. - if (havePointerIds) { - if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { - uint32_t id = uint32_t(inPointer.absMTTrackingId); - - if (id > MAX_POINTER_ID) { -#if DEBUG_POINTERS - LOGD("Pointers: Ignoring driver provided pointer id %d because " - "it is larger than max supported id %d", - id, MAX_POINTER_ID); -#endif - havePointerIds = false; - } - else { - outPointer.id = id; - mCurrentTouch.idToIndex[id] = outCount; - mCurrentTouch.idBits.markBit(id); - } - } else { - havePointerIds = false; - } - } - - outCount += 1; - } - - mCurrentTouch.pointerCount = outCount; - - syncTouch(when, havePointerIds); - - mAccumulator.clear(); -} - -void MultiTouchInputMapper::configureRawAxes() { - TouchInputMapper::configureRawAxes(); - - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mRawAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mRawAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mRawAxes.touchMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mRawAxes.touchMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mRawAxes.toolMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mRawAxes.toolMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mRawAxes.orientation); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mRawAxes.pressure); -} - - -} // namespace android diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp index 9bfa8f6de440..2decfe93215a 100644 --- a/libs/ui/KeyCharacterMap.cpp +++ b/libs/ui/KeyCharacterMap.cpp @@ -185,9 +185,11 @@ bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { - outFallbackAction->keyCode = behavior->fallbackKeyCode; - outFallbackAction->metaState = metaState & ~behavior->metaState; - result = true; + if (behavior->fallbackKeyCode) { + outFallbackAction->keyCode = behavior->fallbackKeyCode; + outFallbackAction->metaState = metaState & ~behavior->metaState; + result = true; + } } #if DEBUG_MAPPING LOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index aa017b978825..580d73cf384c 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -7,8 +7,6 @@ ifneq ($(TARGET_SIMULATOR),true) # Build the unit tests. test_src_files := \ InputChannel_test.cpp \ - InputReader_test.cpp \ - InputDispatcher_test.cpp \ InputPublisherAndConsumer_test.cpp shared_libraries := \ diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp deleted file mode 100644 index 7e17c57a9227..000000000000 --- a/libs/ui/tests/InputDispatcher_test.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// - -#include <ui/InputDispatcher.h> -#include <gtest/gtest.h> -#include <linux/input.h> - -namespace android { - -// An arbitrary time value. -static const nsecs_t ARBITRARY_TIME = 1234; - -// An arbitrary device id. -static const int32_t DEVICE_ID = 1; - -// An arbitrary injector pid / uid pair that has permission to inject events. -static const int32_t INJECTOR_PID = 999; -static const int32_t INJECTOR_UID = 1001; - - -// --- FakeInputDispatcherPolicy --- - -class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { -protected: - virtual ~FakeInputDispatcherPolicy() { - } - -public: - FakeInputDispatcherPolicy() { - } - -private: - virtual void notifyConfigurationChanged(nsecs_t when) { - } - - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) { - return 0; - } - - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { - } - - virtual nsecs_t getKeyRepeatTimeout() { - return 500 * 1000000LL; - } - - virtual nsecs_t getKeyRepeatDelay() { - return 50 * 1000000LL; - } - - virtual int32_t getMaxEventsPerSecond() { - return 60; - } - - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { - } - - virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { - } - - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, - const KeyEvent* keyEvent, uint32_t policyFlags) { - return false; - } - - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { - return false; - } - - virtual void notifySwitch(nsecs_t when, - int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { - } - - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) { - } - - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) { - return false; - } -}; - - -// --- InputDispatcherTest --- - -class InputDispatcherTest : public testing::Test { -protected: - sp<FakeInputDispatcherPolicy> mFakePolicy; - sp<InputDispatcher> mDispatcher; - - virtual void SetUp() { - mFakePolicy = new FakeInputDispatcherPolicy(); - mDispatcher = new InputDispatcher(mFakePolicy); - } - - virtual void TearDown() { - mFakePolicy.clear(); - mDispatcher.clear(); - } -}; - - -TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { - KeyEvent event; - - // Rejects undefined key actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - /*action*/ -1, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject key events with undefined action."; - - // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - AKEY_EVENT_ACTION_MULTIPLE, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject key events with ACTION_MULTIPLE."; -} - -TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { - MotionEvent event; - int32_t pointerIds[MAX_POINTERS + 1]; - PointerCoords pointerCoords[MAX_POINTERS + 1]; - for (int i = 0; i <= MAX_POINTERS; i++) { - pointerIds[i] = i; - } - - // Rejects undefined motion actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with undefined action."; - - // Rejects pointer down with invalid index. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer down index too large."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer down index too small."; - - // Rejects pointer up with invalid index. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer up index too large."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer up index too small."; - - // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 0, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with 0 pointers."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with more than MAX_POINTERS pointers."; - - // Rejects motion events with invalid pointer ids. - pointerIds[0] = -1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer ids less than 0."; - - pointerIds[0] = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; - - // Rejects motion events with duplicate pointer ids. - pointerIds[0] = 1; - pointerIds[1] = 1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 2, pointerIds, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) - << "Should reject motion events with duplicate pointer ids."; -} - -} // namespace android diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp deleted file mode 100644 index 97cbc25a3615..000000000000 --- a/libs/ui/tests/InputReader_test.cpp +++ /dev/null @@ -1,3497 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// - -#include <ui/InputReader.h> -#include <utils/List.h> -#include <gtest/gtest.h> -#include <math.h> - -namespace android { - -// An arbitrary time value. -static const nsecs_t ARBITRARY_TIME = 1234; - -// Arbitrary display properties. -static const int32_t DISPLAY_ID = 0; -static const int32_t DISPLAY_WIDTH = 480; -static const int32_t DISPLAY_HEIGHT = 800; - -// Error tolerance for floating point assertions. -static const float EPSILON = 0.001f; - -template<typename T> -static inline T min(T a, T b) { - return a < b ? a : b; -} - -static inline float avg(float x, float y) { - return (x + y) / 2; -} - - -// --- FakeInputReaderPolicy --- - -class FakeInputReaderPolicy : public InputReaderPolicyInterface { - struct DisplayInfo { - int32_t width; - int32_t height; - int32_t orientation; - }; - - KeyedVector<int32_t, DisplayInfo> mDisplayInfos; - bool mFilterTouchEvents; - bool mFilterJumpyTouchEvents; - Vector<String8> mExcludedDeviceNames; - -protected: - virtual ~FakeInputReaderPolicy() { } - -public: - FakeInputReaderPolicy() : - mFilterTouchEvents(false), mFilterJumpyTouchEvents(false) { - } - - void removeDisplayInfo(int32_t displayId) { - mDisplayInfos.removeItem(displayId); - } - - void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { - removeDisplayInfo(displayId); - - DisplayInfo info; - info.width = width; - info.height = height; - info.orientation = orientation; - mDisplayInfos.add(displayId, info); - } - - void setFilterTouchEvents(bool enabled) { - mFilterTouchEvents = enabled; - } - - void setFilterJumpyTouchEvents(bool enabled) { - mFilterJumpyTouchEvents = enabled; - } - - void addExcludedDeviceName(const String8& deviceName) { - mExcludedDeviceNames.push(deviceName); - } - -private: - virtual bool getDisplayInfo(int32_t displayId, - int32_t* width, int32_t* height, int32_t* orientation) { - ssize_t index = mDisplayInfos.indexOfKey(displayId); - if (index >= 0) { - const DisplayInfo& info = mDisplayInfos.valueAt(index); - if (width) { - *width = info.width; - } - if (height) { - *height = info.height; - } - if (orientation) { - *orientation = info.orientation; - } - return true; - } - return false; - } - - virtual bool filterTouchEvents() { - return mFilterTouchEvents; - } - - virtual bool filterJumpyTouchEvents() { - return mFilterJumpyTouchEvents; - } - - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { - outExcludedDeviceNames.appendVector(mExcludedDeviceNames); - } -}; - - -// --- FakeInputDispatcher --- - -class FakeInputDispatcher : public InputDispatcherInterface { -public: - struct NotifyConfigurationChangedArgs { - nsecs_t eventTime; - }; - - struct NotifyKeyArgs { - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - nsecs_t downTime; - }; - - struct NotifyMotionArgs { - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t edgeFlags; - uint32_t pointerCount; - Vector<int32_t> pointerIds; - Vector<PointerCoords> pointerCoords; - float xPrecision; - float yPrecision; - nsecs_t downTime; - }; - - struct NotifySwitchArgs { - nsecs_t when; - int32_t switchCode; - int32_t switchValue; - uint32_t policyFlags; - }; - -private: - List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgs; - List<NotifyKeyArgs> mNotifyKeyArgs; - List<NotifyMotionArgs> mNotifyMotionArgs; - List<NotifySwitchArgs> mNotifySwitchArgs; - -protected: - virtual ~FakeInputDispatcher() { } - -public: - FakeInputDispatcher() { - } - - void assertNotifyConfigurationChangedWasCalled(NotifyConfigurationChangedArgs* outArgs = NULL) { - ASSERT_FALSE(mNotifyConfigurationChangedArgs.empty()) - << "Expected notifyConfigurationChanged() to have been called."; - if (outArgs) { - *outArgs = *mNotifyConfigurationChangedArgs.begin(); - } - mNotifyConfigurationChangedArgs.erase(mNotifyConfigurationChangedArgs.begin()); - } - - void assertNotifyKeyWasCalled(NotifyKeyArgs* outArgs = NULL) { - ASSERT_FALSE(mNotifyKeyArgs.empty()) - << "Expected notifyKey() to have been called."; - if (outArgs) { - *outArgs = *mNotifyKeyArgs.begin(); - } - mNotifyKeyArgs.erase(mNotifyKeyArgs.begin()); - } - - void assertNotifyKeyWasNotCalled() { - ASSERT_TRUE(mNotifyKeyArgs.empty()) - << "Expected notifyKey() to not have been called."; - } - - void assertNotifyMotionWasCalled(NotifyMotionArgs* outArgs = NULL) { - ASSERT_FALSE(mNotifyMotionArgs.empty()) - << "Expected notifyMotion() to have been called."; - if (outArgs) { - *outArgs = *mNotifyMotionArgs.begin(); - } - mNotifyMotionArgs.erase(mNotifyMotionArgs.begin()); - } - - void assertNotifyMotionWasNotCalled() { - ASSERT_TRUE(mNotifyMotionArgs.empty()) - << "Expected notifyMotion() to not have been called."; - } - - void assertNotifySwitchWasCalled(NotifySwitchArgs* outArgs = NULL) { - ASSERT_FALSE(mNotifySwitchArgs.empty()) - << "Expected notifySwitch() to have been called."; - if (outArgs) { - *outArgs = *mNotifySwitchArgs.begin(); - } - mNotifySwitchArgs.erase(mNotifySwitchArgs.begin()); - } - -private: - virtual void notifyConfigurationChanged(nsecs_t eventTime) { - NotifyConfigurationChangedArgs args; - args.eventTime = eventTime; - mNotifyConfigurationChangedArgs.push_back(args); - } - - virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source, - uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, - int32_t scanCode, int32_t metaState, nsecs_t downTime) { - NotifyKeyArgs args; - args.eventTime = eventTime; - args.deviceId = deviceId; - args.source = source; - args.policyFlags = policyFlags; - args.action = action; - args.flags = flags; - args.keyCode = keyCode; - args.scanCode = scanCode; - args.metaState = metaState; - args.downTime = downTime; - mNotifyKeyArgs.push_back(args); - } - - virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source, - uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime) { - NotifyMotionArgs args; - args.eventTime = eventTime; - args.deviceId = deviceId; - args.source = source; - args.policyFlags = policyFlags; - args.action = action; - args.flags = flags; - args.metaState = metaState; - args.edgeFlags = edgeFlags; - args.pointerCount = pointerCount; - args.pointerIds.clear(); - args.pointerIds.appendArray(pointerIds, pointerCount); - args.pointerCoords.clear(); - args.pointerCoords.appendArray(pointerCoords, pointerCount); - args.xPrecision = xPrecision; - args.yPrecision = yPrecision; - args.downTime = downTime; - mNotifyMotionArgs.push_back(args); - } - - virtual void notifySwitch(nsecs_t when, - int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { - NotifySwitchArgs args; - args.when = when; - args.switchCode = switchCode; - args.switchValue = switchValue; - args.policyFlags = policyFlags; - mNotifySwitchArgs.push_back(args); - } - - virtual void dump(String8& dump) { - ADD_FAILURE() << "Should never be called by input reader."; - } - - virtual void dispatchOnce() { - ADD_FAILURE() << "Should never be called by input reader."; - } - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) { - ADD_FAILURE() << "Should never be called by input reader."; - return INPUT_EVENT_INJECTION_FAILED; - } - - virtual void setInputWindows(const Vector<InputWindow>& inputWindows) { - ADD_FAILURE() << "Should never be called by input reader."; - } - - virtual void setFocusedApplication(const InputApplication* inputApplication) { - ADD_FAILURE() << "Should never be called by input reader."; - } - - virtual void setInputDispatchMode(bool enabled, bool frozen) { - ADD_FAILURE() << "Should never be called by input reader."; - } - - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) { - ADD_FAILURE() << "Should never be called by input reader."; - return 0; - } - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { - ADD_FAILURE() << "Should never be called by input reader."; - return 0; - } - - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) { - ADD_FAILURE() << "Should never be called by input reader."; - return 0; - } -}; - - -// --- FakeEventHub --- - -class FakeEventHub : public EventHubInterface { - struct KeyInfo { - int32_t keyCode; - uint32_t flags; - }; - - struct Device { - String8 name; - uint32_t classes; - PropertyMap configuration; - KeyedVector<int, RawAbsoluteAxisInfo> axes; - KeyedVector<int32_t, int32_t> keyCodeStates; - KeyedVector<int32_t, int32_t> scanCodeStates; - KeyedVector<int32_t, int32_t> switchStates; - KeyedVector<int32_t, KeyInfo> keys; - KeyedVector<int32_t, bool> leds; - Vector<VirtualKeyDefinition> virtualKeys; - - Device(const String8& name, uint32_t classes) : - name(name), classes(classes) { - } - }; - - KeyedVector<int32_t, Device*> mDevices; - Vector<String8> mExcludedDevices; - List<RawEvent> mEvents; - -protected: - virtual ~FakeEventHub() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } - } - -public: - FakeEventHub() { } - - void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { - Device* device = new Device(name, classes); - mDevices.add(deviceId, device); - - enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0, 0, 0); - } - - void removeDevice(int32_t deviceId) { - delete mDevices.valueFor(deviceId); - mDevices.removeItem(deviceId); - - enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0, 0, 0); - } - - void finishDeviceScan() { - enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0, 0, 0); - } - - void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { - Device* device = getDevice(deviceId); - device->configuration.addProperty(key, value); - } - - void addAxis(int32_t deviceId, int axis, - int32_t minValue, int32_t maxValue, int flat, int fuzz) { - Device* device = getDevice(deviceId); - - RawAbsoluteAxisInfo info; - info.valid = true; - info.minValue = minValue; - info.maxValue = maxValue; - info.flat = flat; - info.fuzz = fuzz; - device->axes.add(axis, info); - } - - void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { - Device* device = getDevice(deviceId); - device->keyCodeStates.replaceValueFor(keyCode, state); - } - - void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { - Device* device = getDevice(deviceId); - device->scanCodeStates.replaceValueFor(scanCode, state); - } - - void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { - Device* device = getDevice(deviceId); - device->switchStates.replaceValueFor(switchCode, state); - } - - void addKey(int32_t deviceId, int32_t scanCode, int32_t keyCode, uint32_t flags) { - Device* device = getDevice(deviceId); - KeyInfo info; - info.keyCode = keyCode; - info.flags = flags; - device->keys.add(scanCode, info); - } - - void addLed(int32_t deviceId, int32_t led, bool initialState) { - Device* device = getDevice(deviceId); - device->leds.add(led, initialState); - } - - bool getLedState(int32_t deviceId, int32_t led) { - Device* device = getDevice(deviceId); - return device->leds.valueFor(led); - } - - Vector<String8>& getExcludedDevices() { - return mExcludedDevices; - } - - void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { - Device* device = getDevice(deviceId); - device->virtualKeys.push(definition); - } - - void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, - int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { - RawEvent event; - event.when = when; - event.deviceId = deviceId; - event.type = type; - event.scanCode = scanCode; - event.keyCode = keyCode; - event.value = value; - event.flags = flags; - mEvents.push_back(event); - } - - void assertQueueIsEmpty() { - ASSERT_EQ(size_t(0), mEvents.size()) - << "Expected the event queue to be empty (fully consumed)."; - } - -private: - Device* getDevice(int32_t deviceId) const { - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : NULL; - } - - virtual uint32_t getDeviceClasses(int32_t deviceId) const { - Device* device = getDevice(deviceId); - return device ? device->classes : 0; - } - - virtual String8 getDeviceName(int32_t deviceId) const { - Device* device = getDevice(deviceId); - return device ? device->name : String8("unknown"); - } - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - Device* device = getDevice(deviceId); - if (device) { - *outConfiguration = device->configuration; - } - } - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->axes.indexOfKey(axis); - if (index >= 0) { - *outAxisInfo = device->axes.valueAt(index); - return OK; - } - } - return -1; - } - - virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, - int32_t* outKeycode, uint32_t* outFlags) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keys.indexOfKey(scancode); - if (index >= 0) { - if (outKeycode) { - *outKeycode = device->keys.valueAt(index).keyCode; - } - if (outFlags) { - *outFlags = device->keys.valueAt(index).flags; - } - return OK; - } - } - return NAME_NOT_FOUND; - } - - virtual void addExcludedDevice(const char* deviceName) { - mExcludedDevices.add(String8(deviceName)); - } - - virtual bool getEvent(RawEvent* outEvent) { - if (mEvents.empty()) { - return false; - } - - *outEvent = *mEvents.begin(); - mEvents.erase(mEvents.begin()); - return true; - } - - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->scanCodeStates.indexOfKey(scanCode); - if (index >= 0) { - return device->scanCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keyCodeStates.indexOfKey(keyCode); - if (index >= 0) { - return device->keyCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->switchStates.indexOfKey(sw); - if (index >= 0) { - return device->switchStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const { - bool result = false; - Device* device = getDevice(deviceId); - if (device) { - for (size_t i = 0; i < numCodes; i++) { - for (size_t j = 0; j < device->keys.size(); j++) { - if (keyCodes[i] == device->keys.valueAt(j).keyCode) { - outFlags[i] = 1; - result = true; - } - } - } - } - return result; - } - - virtual bool hasLed(int32_t deviceId, int32_t led) const { - Device* device = getDevice(deviceId); - return device && device->leds.indexOfKey(led) >= 0; - } - - virtual void setLedState(int32_t deviceId, int32_t led, bool on) { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->leds.indexOfKey(led); - if (index >= 0) { - device->leds.replaceValueAt(led, on); - } else { - ADD_FAILURE() - << "Attempted to set the state of an LED that the EventHub declared " - "was not present. led=" << led; - } - } - } - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const { - outVirtualKeys.clear(); - - Device* device = getDevice(deviceId); - if (device) { - outVirtualKeys.appendVector(device->virtualKeys); - } - } - - virtual void dump(String8& dump) { - } -}; - - -// --- FakeInputReaderContext --- - -class FakeInputReaderContext : public InputReaderContext { - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<InputDispatcherInterface> mDispatcher; - int32_t mGlobalMetaState; - bool mUpdateGlobalMetaStateWasCalled; - -public: - FakeInputReaderContext(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputDispatcherInterface>& dispatcher) : - mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), - mGlobalMetaState(0) { - } - - virtual ~FakeInputReaderContext() { } - - void assertUpdateGlobalMetaStateWasCalled() { - ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled) - << "Expected updateGlobalMetaState() to have been called."; - mUpdateGlobalMetaStateWasCalled = false; - } - - void setGlobalMetaState(int32_t state) { - mGlobalMetaState = state; - } - -private: - virtual void updateGlobalMetaState() { - mUpdateGlobalMetaStateWasCalled = true; - } - - virtual int32_t getGlobalMetaState() { - return mGlobalMetaState; - } - - virtual EventHubInterface* getEventHub() { - return mEventHub.get(); - } - - virtual InputReaderPolicyInterface* getPolicy() { - return mPolicy.get(); - } - - virtual InputDispatcherInterface* getDispatcher() { - return mDispatcher.get(); - } -}; - - -// --- FakeInputMapper --- - -class FakeInputMapper : public InputMapper { - uint32_t mSources; - int32_t mKeyboardType; - int32_t mMetaState; - KeyedVector<int32_t, int32_t> mKeyCodeStates; - KeyedVector<int32_t, int32_t> mScanCodeStates; - KeyedVector<int32_t, int32_t> mSwitchStates; - Vector<int32_t> mSupportedKeyCodes; - RawEvent mLastEvent; - - bool mConfigureWasCalled; - bool mResetWasCalled; - bool mProcessWasCalled; - -public: - FakeInputMapper(InputDevice* device, uint32_t sources) : - InputMapper(device), - mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), - mMetaState(0), - mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { - } - - virtual ~FakeInputMapper() { } - - void setKeyboardType(int32_t keyboardType) { - mKeyboardType = keyboardType; - } - - void setMetaState(int32_t metaState) { - mMetaState = metaState; - } - - void assertConfigureWasCalled() { - ASSERT_TRUE(mConfigureWasCalled) - << "Expected configure() to have been called."; - mConfigureWasCalled = false; - } - - void assertResetWasCalled() { - ASSERT_TRUE(mResetWasCalled) - << "Expected reset() to have been called."; - mResetWasCalled = false; - } - - void assertProcessWasCalled(RawEvent* outLastEvent = NULL) { - ASSERT_TRUE(mProcessWasCalled) - << "Expected process() to have been called."; - if (outLastEvent) { - *outLastEvent = mLastEvent; - } - mProcessWasCalled = false; - } - - void setKeyCodeState(int32_t keyCode, int32_t state) { - mKeyCodeStates.replaceValueFor(keyCode, state); - } - - void setScanCodeState(int32_t scanCode, int32_t state) { - mScanCodeStates.replaceValueFor(scanCode, state); - } - - void setSwitchState(int32_t switchCode, int32_t state) { - mSwitchStates.replaceValueFor(switchCode, state); - } - - void addSupportedKeyCode(int32_t keyCode) { - mSupportedKeyCodes.add(keyCode); - } - -private: - virtual uint32_t getSources() { - return mSources; - } - - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) { - InputMapper::populateDeviceInfo(deviceInfo); - - if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { - deviceInfo->setKeyboardType(mKeyboardType); - } - } - - virtual void configure() { - mConfigureWasCalled = true; - } - - virtual void reset() { - mResetWasCalled = true; - } - - virtual void process(const RawEvent* rawEvent) { - mLastEvent = *rawEvent; - mProcessWasCalled = true; - } - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - ssize_t index = mKeyCodeStates.indexOfKey(keyCode); - return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - ssize_t index = mScanCodeStates.indexOfKey(scanCode); - return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) { - ssize_t index = mSwitchStates.indexOfKey(switchCode); - return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - for (size_t i = 0; i < numCodes; i++) { - for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { - if (keyCodes[i] == mSupportedKeyCodes[j]) { - outFlags[i] = 1; - result = true; - } - } - } - return result; - } - - virtual int32_t getMetaState() { - return mMetaState; - } -}; - - -// --- InstrumentedInputReader --- - -class InstrumentedInputReader : public InputReader { - InputDevice* mNextDevice; - -public: - InstrumentedInputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputDispatcherInterface>& dispatcher) : - InputReader(eventHub, policy, dispatcher) { - } - - virtual ~InstrumentedInputReader() { - if (mNextDevice) { - delete mNextDevice; - } - } - - void setNextDevice(InputDevice* device) { - mNextDevice = device; - } - -protected: - virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes) { - if (mNextDevice) { - InputDevice* device = mNextDevice; - mNextDevice = NULL; - return device; - } - return InputReader::createDevice(deviceId, name, classes); - } - - friend class InputReaderTest; -}; - - -// --- InputReaderTest --- - -class InputReaderTest : public testing::Test { -protected: - sp<FakeInputDispatcher> mFakeDispatcher; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeEventHub> mFakeEventHub; - sp<InstrumentedInputReader> mReader; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeDispatcher = new FakeInputDispatcher(); - - mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeDispatcher); - } - - virtual void TearDown() { - mReader.clear(); - - mFakeDispatcher.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } - - void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { - mFakeEventHub->addDevice(deviceId, name, classes); - mFakeEventHub->finishDeviceScan(); - mReader->loopOnce(); - mReader->loopOnce(); - mFakeEventHub->assertQueueIsEmpty(); - } - - FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, - const String8& name, uint32_t classes, uint32_t sources) { - InputDevice* device = new InputDevice(mReader.get(), deviceId, name); - FakeInputMapper* mapper = new FakeInputMapper(device, sources); - device->addMapper(mapper); - mReader->setNextDevice(device); - addDevice(deviceId, name, classes); - return mapper; - } -}; - -TEST_F(InputReaderTest, GetInputConfiguration_WhenNoDevices_ReturnsDefaults) { - InputConfiguration config; - mReader->getInputConfiguration(&config); - - ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); - ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); - ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); -} - -TEST_F(InputReaderTest, GetInputConfiguration_WhenAlphabeticKeyboardPresent_ReturnsQwertyKeyboard) { - ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); - - InputConfiguration config; - mReader->getInputConfiguration(&config); - - ASSERT_EQ(InputConfiguration::KEYBOARD_QWERTY, config.keyboard); - ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); - ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); -} - -TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFingerTouchScreen) { - ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("touchscreen"), - INPUT_DEVICE_CLASS_TOUCHSCREEN)); - - InputConfiguration config; - mReader->getInputConfiguration(&config); - - ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); - ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); - ASSERT_EQ(InputConfiguration::TOUCHSCREEN_FINGER, config.touchScreen); -} - -TEST_F(InputReaderTest, GetInputConfiguration_WhenTrackballPresent_ReturnsTrackballNavigation) { - ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("trackball"), - INPUT_DEVICE_CLASS_TRACKBALL)); - - InputConfiguration config; - mReader->getInputConfiguration(&config); - - ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); - ASSERT_EQ(InputConfiguration::NAVIGATION_TRACKBALL, config.navigation); - ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); -} - -TEST_F(InputReaderTest, GetInputConfiguration_WhenDPadPresent_ReturnsDPadNavigation) { - ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("dpad"), - INPUT_DEVICE_CLASS_DPAD)); - - InputConfiguration config; - mReader->getInputConfiguration(&config); - - ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); - ASSERT_EQ(InputConfiguration::NAVIGATION_DPAD, config.navigation); - ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); -} - -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsValid) { - ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD)); - - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(1, &info); - - ASSERT_EQ(OK, result); - ASSERT_EQ(1, info.getId()); - ASSERT_STREQ("keyboard", info.getName().string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, info.getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, info.getSources()); - ASSERT_EQ(size_t(0), info.getMotionRanges().size()); -} - -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsInvalid) { - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(-1, &info); - - ASSERT_EQ(NAME_NOT_FOUND, result); -} - -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) { - addDevice(1, String8("ignored"), 0); // no classes so device will be ignored - - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(1, &info); - - ASSERT_EQ(NAME_NOT_FOUND, result); -} - -TEST_F(InputReaderTest, GetInputDeviceIds) { - ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("trackball"), - INPUT_DEVICE_CLASS_TRACKBALL)); - - Vector<int32_t> ids; - mReader->getInputDeviceIds(ids); - - ASSERT_EQ(size_t(2), ids.size()); - ASSERT_EQ(1, ids[0]); - ASSERT_EQ(2, ids[1]); -} - -TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); - mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, - AINPUT_SOURCE_ANY, AKEYCODE_A)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, - AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); - mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, - AINPUT_SOURCE_ANY, KEY_A)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, - AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); - mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, - AINPUT_SOURCE_ANY, SW_LID)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, - AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); - mapper->addSupportedKeyCode(AKEYCODE_A); - mapper->addSupportedKeyCode(AKEYCODE_B); - - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; - uint8_t flags[4] = { 0, 0, 0, 1 }; - - ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) - << "Should return false when device id is >= 0 but unknown."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when device id is valid but the sources are not supported by the device."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when the device id is < 0 but the sources are not supported by any device."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; - ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); -} - -TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { - addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD); - - FakeInputDispatcher::NotifyConfigurationChangedArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyConfigurationChangedWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); -} - -TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); - - mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, AKEYCODE_A, 1, POLICY_FLAG_WAKE); - mReader->loopOnce(); - ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); - - RawEvent event; - ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); - ASSERT_EQ(0, event.when); - ASSERT_EQ(1, event.deviceId); - ASSERT_EQ(EV_KEY, event.type); - ASSERT_EQ(KEY_A, event.scanCode); - ASSERT_EQ(AKEYCODE_A, event.keyCode); - ASSERT_EQ(1, event.value); - ASSERT_EQ(POLICY_FLAG_WAKE, event.flags); -} - - -// --- InputDeviceTest --- - -class InputDeviceTest : public testing::Test { -protected: - static const char* DEVICE_NAME; - static const int32_t DEVICE_ID; - - sp<FakeEventHub> mFakeEventHub; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeInputDispatcher> mFakeDispatcher; - FakeInputReaderContext* mFakeContext; - - InputDevice* mDevice; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeDispatcher = new FakeInputDispatcher(); - mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher); - - mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); - mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME)); - } - - virtual void TearDown() { - delete mDevice; - - delete mFakeContext; - mFakeDispatcher.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } -}; - -const char* InputDeviceTest::DEVICE_NAME = "device"; -const int32_t InputDeviceTest::DEVICE_ID = 1; - -TEST_F(InputDeviceTest, ImmutableProperties) { - ASSERT_EQ(DEVICE_ID, mDevice->getId()); - ASSERT_STREQ(DEVICE_NAME, mDevice->getName()); -} - -TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { - // Configuration. - mDevice->configure(); - - // Metadata. - ASSERT_TRUE(mDevice->isIgnored()); - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources()); - - InputDeviceInfo info; - mDevice->getDeviceInfo(&info); - ASSERT_EQ(DEVICE_ID, info.getId()); - ASSERT_STREQ(DEVICE_NAME, info.getName().string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources()); - - // State queries. - ASSERT_EQ(0, mDevice->getMetaState()); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown key code state."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown scan code state."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown switch state."; - - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; - uint8_t flags[2] = { 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) - << "Ignored device should never mark any key codes."; - ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; - ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; - - // Reset. - mDevice->reset(); -} - -TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { - // Configuration. - mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); - - FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); - mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mapper1->setMetaState(AMETA_ALT_ON); - mapper1->addSupportedKeyCode(AKEYCODE_A); - mapper1->addSupportedKeyCode(AKEYCODE_B); - mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); - mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); - mapper1->setScanCodeState(2, AKEY_STATE_DOWN); - mapper1->setScanCodeState(3, AKEY_STATE_UP); - mapper1->setSwitchState(4, AKEY_STATE_DOWN); - mDevice->addMapper(mapper1); - - FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); - mapper2->setMetaState(AMETA_SHIFT_ON); - mDevice->addMapper(mapper2); - - mDevice->configure(); - - String8 propertyValue; - ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) - << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); - - // Metadata. - ASSERT_FALSE(mDevice->isIgnored()); - ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); - - InputDeviceInfo info; - mDevice->getDeviceInfo(&info); - ASSERT_EQ(DEVICE_ID, info.getId()); - ASSERT_STREQ(DEVICE_NAME, info.getName().string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType()); - ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources()); - - // State queries. - ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState()) - << "Should query mappers and combine meta states."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown key code state when source not supported."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown scan code state when source not supported."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown switch state when source not supported."; - - ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A)) - << "Should query mapper when source is supported."; - ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3)) - << "Should query mapper when source is supported."; - ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) - << "Should query mapper when source is supported."; - - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; - uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should do nothing when source is unsupported."; - ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; - - ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) - << "Should query mapper when source is supported."; - ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; - ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; - ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged."; - ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged."; - - // Event handling. - RawEvent event; - mDevice->process(&event); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); - - // Reset. - mDevice->reset(); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); -} - - -// --- InputMapperTest --- - -class InputMapperTest : public testing::Test { -protected: - static const char* DEVICE_NAME; - static const int32_t DEVICE_ID; - - sp<FakeEventHub> mFakeEventHub; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeInputDispatcher> mFakeDispatcher; - FakeInputReaderContext* mFakeContext; - InputDevice* mDevice; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeDispatcher = new FakeInputDispatcher(); - mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher); - mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME)); - - mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); - } - - virtual void TearDown() { - delete mDevice; - delete mFakeContext; - mFakeDispatcher.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } - - void addConfigurationProperty(const char* key, const char* value) { - mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value)); - } - - void addMapperAndConfigure(InputMapper* mapper) { - mDevice->addMapper(mapper); - mDevice->configure(); - } - - static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, - int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { - RawEvent event; - event.when = when; - event.deviceId = deviceId; - event.type = type; - event.scanCode = scanCode; - event.keyCode = keyCode; - event.value = value; - event.flags = flags; - mapper->process(&event); - } - - static void assertMotionRange(const InputDeviceInfo& info, - int32_t rangeType, float min, float max, float flat, float fuzz) { - const InputDeviceInfo::MotionRange* range = info.getMotionRange(rangeType); - ASSERT_TRUE(range != NULL) << "Range: " << rangeType; - ASSERT_NEAR(min, range->min, EPSILON) << "Range: " << rangeType; - ASSERT_NEAR(max, range->max, EPSILON) << "Range: " << rangeType; - ASSERT_NEAR(flat, range->flat, EPSILON) << "Range: " << rangeType; - ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Range: " << rangeType; - } - - static void assertPointerCoords(const PointerCoords& coords, - float x, float y, float pressure, float size, - float touchMajor, float touchMinor, float toolMajor, float toolMinor, - float orientation) { - ASSERT_NEAR(x, coords.x, 1); - ASSERT_NEAR(y, coords.y, 1); - ASSERT_NEAR(pressure, coords.pressure, EPSILON); - ASSERT_NEAR(size, coords.size, EPSILON); - ASSERT_NEAR(touchMajor, coords.touchMajor, 1); - ASSERT_NEAR(touchMinor, coords.touchMinor, 1); - ASSERT_NEAR(toolMajor, coords.toolMajor, 1); - ASSERT_NEAR(toolMinor, coords.toolMinor, 1); - ASSERT_NEAR(orientation, coords.orientation, EPSILON); - } -}; - -const char* InputMapperTest::DEVICE_NAME = "device"; -const int32_t InputMapperTest::DEVICE_ID = 1; - - -// --- SwitchInputMapperTest --- - -class SwitchInputMapperTest : public InputMapperTest { -protected: -}; - -TEST_F(SwitchInputMapperTest, GetSources) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - ASSERT_EQ(uint32_t(0), mapper->getSources()); -} - -TEST_F(SwitchInputMapperTest, GetSwitchState) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); - ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); - - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); - ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); -} - -TEST_F(SwitchInputMapperTest, Process) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 0, 1, 0); - - FakeInputDispatcher::NotifySwitchArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifySwitchWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.when); - ASSERT_EQ(SW_LID, args.switchCode); - ASSERT_EQ(1, args.switchValue); - ASSERT_EQ(uint32_t(0), args.policyFlags); -} - - -// --- KeyboardInputMapperTest --- - -class KeyboardInputMapperTest : public InputMapperTest { -protected: - void testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode); -}; - -void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) { - FakeInputDispatcher::NotifyKeyArgs args; - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, originalKeyCode, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(originalScanCode, args.scanCode); - ASSERT_EQ(rotatedKeyCode, args.keyCode); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, originalKeyCode, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(originalScanCode, args.scanCode); - ASSERT_EQ(rotatedKeyCode, args.keyCode); -} - - -TEST_F(KeyboardInputMapperTest, GetSources) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); -} - -TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Key down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 1, POLICY_FLAG_WAKE); - FakeInputDispatcher::NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key up. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 0, POLICY_FLAG_WAKE); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Key down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 1, POLICY_FLAG_WAKE); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Key up. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 0, POLICY_FLAG_WAKE); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Reset. Since no keys still down, should not synthesize any key ups. - mapper->reset(); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); -} - -TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Metakey down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Key down. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_A, AKEYCODE_A, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Reset. Since two keys are still down, should synthesize two key ups in reverse order. - mapper->reset(); - - FakeInputDispatcher::NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_A, args.keyCode); - ASSERT_EQ(KEY_A, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_SHIFT_LEFT, args.keyCode); - ASSERT_EQ(KEY_LEFTSHIFT, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); - - // And that's it. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); -} - -TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Initial metastate. - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); - - // Metakey down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 1, 0); - FakeInputDispatcher::NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); - - // Key down. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_A, AKEYCODE_A, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - - // Key up. - process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, - EV_KEY, KEY_A, AKEYCODE_A, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - - // Metakey up. - process(mapper, ARBITRARY_TIME + 3, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); - ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); -} - -TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_90); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); -} - -TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addConfigurationProperty("keyboard.orientationAware", "1"); - addMapperAndConfigure(mapper); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_0); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_90); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_180); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_270); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP)); - - // Special case: if orientation changes while key is down, we still emit the same keycode - // in the key up as we did in the key down. - FakeInputDispatcher::NotifyKeyArgs args; - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_270); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(KEY_UP, args.scanCode); - ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_180); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(KEY_UP, args.scanCode); - ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); -} - -TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); - ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); - - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); - ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); -} - -TEST_F(KeyboardInputMapperTest, GetScanCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); - ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); - - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); - ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); -} - -TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->addKey(DEVICE_ID, KEY_A, AKEYCODE_A, 0); - - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; - uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); - ASSERT_TRUE(flags[0]); - ASSERT_FALSE(flags[1]); -} - -TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) { - mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/); - mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); - mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Initialization should have turned all of the lights off. - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - - // Toggle caps lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState()); - - // Toggle num lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState()); - - // Toggle caps lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState()); - - // Toggle scroll lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); - - // Toggle num lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); - - // Toggle scroll lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); -} - - -// --- TrackballInputMapperTest --- - -class TrackballInputMapperTest : public InputMapperTest { -protected: - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; - - void testMotionRotation(TrackballInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); -}; - -const int32_t TrackballInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; - -void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { - FakeInputDispatcher::NotifyMotionArgs args; - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, originalX, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, originalY, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, - float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(TrackballInputMapperTest, GetSources) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); -} - -TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - InputDeviceInfo info; - mapper->populateDeviceInfo(&info); - - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X, - -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y, - -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); -} - -TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Button press. - // Mostly testing non x/y behavior here so we don't need to check again elsewhere. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(0, args.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(0, args.edgeFlags); - ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Button release. Should have same down time. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_EQ(0, args.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(0, args.edgeFlags); - ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Motion in X but not Y. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Motion in Y but not X. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, -2, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NEAR(0.0f, args.pointerCoords[0].x, EPSILON); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Button press without following sync. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Button release without following sync. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Combined X, Y and Button. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, -2, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Move X, Y a bit while pressed. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 2, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Release Button. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Button press. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - - // Button release. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - - // Reset. Should not synthesize button up since button is not pressed. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Button press. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - - // Reset. Should synthesize button up. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addMapperAndConfigure(mapper); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_90); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); -} - -TEST_F(TrackballInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addConfigurationProperty("trackball.orientationAware", "1"); - addMapperAndConfigure(mapper); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_0); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_90); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_180); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); - - mFakePolicy->setDisplayInfo(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - InputReaderPolicyInterface::ROTATION_270); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); -} - - -// --- TouchInputMapperTest --- - -class TouchInputMapperTest : public InputMapperTest { -protected: - static const int32_t RAW_X_MIN; - static const int32_t RAW_X_MAX; - static const int32_t RAW_Y_MIN; - static const int32_t RAW_Y_MAX; - static const int32_t RAW_TOUCH_MIN; - static const int32_t RAW_TOUCH_MAX; - static const int32_t RAW_TOOL_MIN; - static const int32_t RAW_TOOL_MAX; - static const int32_t RAW_PRESSURE_MIN; - static const int32_t RAW_PRESSURE_MAX; - static const int32_t RAW_ORIENTATION_MIN; - static const int32_t RAW_ORIENTATION_MAX; - static const int32_t RAW_ID_MIN; - static const int32_t RAW_ID_MAX; - static const float X_PRECISION; - static const float Y_PRECISION; - - static const VirtualKeyDefinition VIRTUAL_KEYS[2]; - - enum Axes { - POSITION = 1 << 0, - TOUCH = 1 << 1, - TOOL = 1 << 2, - PRESSURE = 1 << 3, - ORIENTATION = 1 << 4, - MINOR = 1 << 5, - ID = 1 << 6, - }; - - void prepareDisplay(int32_t orientation); - void prepareVirtualKeys(); - int32_t toRawX(float displayX); - int32_t toRawY(float displayY); - float toDisplayX(int32_t rawX); - float toDisplayY(int32_t rawY); -}; - -const int32_t TouchInputMapperTest::RAW_X_MIN = 25; -const int32_t TouchInputMapperTest::RAW_X_MAX = 1020; -const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; -const int32_t TouchInputMapperTest::RAW_Y_MAX = 1010; -const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; -const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; -const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; -const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; -const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; -const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; -const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; -const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; -const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH; -const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT; - -const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { - { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, - { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, -}; - -void TouchInputMapperTest::prepareDisplay(int32_t orientation) { - mFakePolicy->setDisplayInfo(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); -} - -void TouchInputMapperTest::prepareVirtualKeys() { - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE); -} - -int32_t TouchInputMapperTest::toRawX(float displayX) { - return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH + RAW_X_MIN); -} - -int32_t TouchInputMapperTest::toRawY(float displayY) { - return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT + RAW_Y_MIN); -} - -float TouchInputMapperTest::toDisplayX(int32_t rawX) { - return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN); -} - -float TouchInputMapperTest::toDisplayY(int32_t rawY) { - return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN); -} - - -// --- SingleTouchInputMapperTest --- - -class SingleTouchInputMapperTest : public TouchInputMapperTest { -protected: - void prepareAxes(int axes); - - void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processUp(SingleTouchInputMapper* mappery); - void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); - void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); - void processSync(SingleTouchInputMapper* mapper); -}; - -void SingleTouchInputMapperTest::prepareAxes(int axes) { - if (axes & POSITION) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); - } - if (axes & PRESSURE) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); - } - if (axes & TOOL) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); - } -} - -void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, 0, x, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, 0, y, 0); -} - -void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, 0, x, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, 0, y, 0); -} - -void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0, 0, 0); -} - -void SingleTouchInputMapperTest::processPressure( - SingleTouchInputMapper* mapper, int32_t pressure) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, 0, pressure, 0); -} - -void SingleTouchInputMapperTest::processToolMajor( - SingleTouchInputMapper* mapper, int32_t toolMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, 0, toolMajor, 0); -} - -void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); -} - - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchPad"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); - - // Virtual key is down. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); - - // Virtual key is up. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); -} - -TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); - - // Virtual key is down. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); - - // Virtual key is up. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); -} - -TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; - uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); - ASSERT_TRUE(flags[0]); - ASSERT_FALSE(flags[1]); -} - -TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) { - // Note: Ideally we should send cancels but the implementation is more straightforward - // with up and this will only happen if a device is forcibly removed. - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Reset. Since key is down, synthesize key up. - mapper->reset(); - - FakeInputDispatcher::NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - //ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Release virtual key. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); - - // Reset. Since no key is down, nothing happens. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyKeyArgs args; - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Release virtual key. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Should not have sent any motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyKeyArgs keyArgs; - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); - ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags); - ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); - ASSERT_EQ(KEY_HOME, keyArgs.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); - - // Move out of bounds. This should generate a cancel and a pointer down since we moved - // into the display area. - y -= 100; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); - ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags); - ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); - ASSERT_EQ(KEY_HOME, keyArgs.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); - - FakeInputDispatcher::NotifyMotionArgs motionArgs; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Keep moving out of bounds. Should generate a pointer move. - y -= 50; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Release out of bounds. Should generate a pointer up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyMotionArgs motionArgs; - - // Initially go down out of bounds. - int32_t x = -10; - int32_t y = -10; - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); - - // Move into the display area. Should generate a pointer down. - x = 50; - y = 75; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Release. Should generate a pointer up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyMotionArgs motionArgs; - - // Down. - int32_t x = 100; - int32_t y = 125; - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x += 50; - y += 75; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareAxes(POSITION); - addConfigurationProperty("touch.orientationAware", "0"); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Rotation 90. - prepareDisplay(InputReaderPolicyInterface::ROTATION_90); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].x, 1); - ASSERT_NEAR(75, args.pointerCoords[0].y, 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - - // Rotation 0. - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].x, 1); - ASSERT_NEAR(75, args.pointerCoords[0].y, 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); - - // Rotation 90. - prepareDisplay(InputReaderPolicyInterface::ROTATION_90); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(75, args.pointerCoords[0].x, 1); - ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].y, 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); - - // Rotation 180. - prepareDisplay(InputReaderPolicyInterface::ROTATION_180); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].x, 1); - ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].y, 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); - - // Rotation 270. - prepareDisplay(InputReaderPolicyInterface::ROTATION_270); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].x, 1); - ASSERT_NEAR(50, args.pointerCoords[0].y, 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | PRESSURE | TOOL); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawPressure = 10; - int32_t rawToolMajor = 12; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawPressure) / RAW_PRESSURE_MAX; - float size = float(rawToolMajor) / RAW_TOOL_MAX; - float tool = min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * size; - float touch = min(tool * pressure, tool); - - processDown(mapper, rawX, rawY); - processPressure(mapper, rawPressure); - processToolMajor(mapper, rawToolMajor); - processSync(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touch, touch, tool, tool, 0)); -} - - -// --- MultiTouchInputMapperTest --- - -class MultiTouchInputMapperTest : public TouchInputMapperTest { -protected: - void prepareAxes(int axes); - - void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); - void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); - void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); - void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); - void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); - void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); - void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); - void processId(MultiTouchInputMapper* mapper, int32_t id); - void processMTSync(MultiTouchInputMapper* mapper); - void processSync(MultiTouchInputMapper* mapper); -}; - -void MultiTouchInputMapperTest::prepareAxes(int axes) { - if (axes & POSITION) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); - } - if (axes & TOUCH) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); - if (axes & MINOR) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, - RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); - } - } - if (axes & TOOL) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); - if (axes & MINOR) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, - RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); - } - } - if (axes & ORIENTATION) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_ORIENTATION, - RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); - } - if (axes & PRESSURE) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_PRESSURE, - RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); - } - if (axes & ID) { - mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TRACKING_ID, - RAW_ID_MIN, RAW_ID_MAX, 0, 0); - } -} - -void MultiTouchInputMapperTest::processPosition( - MultiTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 0, x, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 0, y, 0); -} - -void MultiTouchInputMapperTest::processTouchMajor( - MultiTouchInputMapper* mapper, int32_t touchMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, 0, touchMajor, 0); -} - -void MultiTouchInputMapperTest::processTouchMinor( - MultiTouchInputMapper* mapper, int32_t touchMinor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, 0, touchMinor, 0); -} - -void MultiTouchInputMapperTest::processToolMajor( - MultiTouchInputMapper* mapper, int32_t toolMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, 0, toolMajor, 0); -} - -void MultiTouchInputMapperTest::processToolMinor( - MultiTouchInputMapper* mapper, int32_t toolMinor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, 0, toolMinor, 0); -} - -void MultiTouchInputMapperTest::processOrientation( - MultiTouchInputMapper* mapper, int32_t orientation) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, 0, orientation, 0); -} - -void MultiTouchInputMapperTest::processPressure( - MultiTouchInputMapper* mapper, int32_t pressure) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, 0, pressure, 0); -} - -void MultiTouchInputMapperTest::processId( - MultiTouchInputMapper* mapper, int32_t id) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, 0, id, 0); -} - -void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0, 0, 0); -} - -void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); -} - - -TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyMotionArgs motionArgs; - - // Two fingers down at once. - int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; - processPosition(mapper, x1, y1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x1 += 10; y1 += 15; x2 += 5; y2 -= 10; - processPosition(mapper, x1, y1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // First finger up. - x2 += 15; y2 -= 20; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x2 += 20; y2 -= 25; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // New finger down. - int32_t x3 = 700, y3 = 300; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processPosition(mapper, x3, y3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Second finger up. - x3 += 30; y3 -= 20; - processPosition(mapper, x3, y3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Last finger up. - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | ID); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - FakeInputDispatcher::NotifyMotionArgs motionArgs; - - // Two fingers down at once. - int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; - processPosition(mapper, x1, y1); - processId(mapper, 1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - - // Move. - x1 += 10; y1 += 15; x2 += 5; y2 -= 10; - processPosition(mapper, x1, y1); - processId(mapper, 1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - - // First finger up. - x2 += 15; y2 -= 20; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - - // Move. - x2 += 20; y2 -= 25; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - - // New finger down. - int32_t x3 = 700, y3 = 300; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processPosition(mapper, x3, y3); - processId(mapper, 3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_EQ(3, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - - // Second finger up. - x3 += 30; y3 -= 20; - processPosition(mapper, x3, y3); - processId(mapper, 3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_EQ(3, motionArgs.pointerIds[1]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(3, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - - // Last finger up. - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(3, motionArgs.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); -} - -TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 7; - int32_t rawTouchMinor = 6; - int32_t rawToolMajor = 9; - int32_t rawToolMinor = 8; - int32_t rawPressure = 11; - int32_t rawOrientation = 3; - int32_t id = 5; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawPressure) / RAW_PRESSURE_MAX; - float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX; - float toolMajor = float(min(DISPLAY_WIDTH, DISPLAY_HEIGHT)) * rawToolMajor / RAW_TOOL_MAX; - float toolMinor = float(min(DISPLAY_WIDTH, DISPLAY_HEIGHT)) * rawToolMinor / RAW_TOOL_MAX; - float touchMajor = min(toolMajor * pressure, toolMajor); - float touchMinor = min(toolMinor * pressure, toolMinor); - float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2; - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processTouchMinor(mapper, rawTouchMinor); - processToolMajor(mapper, rawToolMajor); - processToolMinor(mapper, rawToolMinor); - processPressure(mapper, rawPressure); - processOrientation(mapper, rawOrientation); - processId(mapper, id); - processMTSync(mapper); - processSync(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(id, args.pointerIds[0]); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, orientation)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | TOUCH | TOOL | MINOR); - addConfigurationProperty("touch.touchSize.calibration", "geometric"); - addConfigurationProperty("touch.toolSize.calibration", "geometric"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 140; - int32_t rawTouchMinor = 120; - int32_t rawToolMajor = 180; - int32_t rawToolMinor = 160; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawTouchMajor) / RAW_TOUCH_MAX; - float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX; - float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN), - float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN)); - float toolMajor = float(rawToolMajor) * scale; - float toolMinor = float(rawToolMinor) * scale; - float touchMajor = min(float(rawTouchMajor) * scale, toolMajor); - float touchMinor = min(float(rawTouchMinor) * scale, toolMinor); - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processTouchMinor(mapper, rawTouchMinor); - processToolMajor(mapper, rawToolMajor); - processToolMinor(mapper, rawToolMinor); - processMTSync(mapper); - processSync(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | TOUCH | TOOL); - addConfigurationProperty("touch.touchSize.calibration", "pressure"); - addConfigurationProperty("touch.toolSize.calibration", "linear"); - addConfigurationProperty("touch.toolSize.linearScale", "10"); - addConfigurationProperty("touch.toolSize.linearBias", "160"); - addConfigurationProperty("touch.toolSize.isSummed", "1"); - addConfigurationProperty("touch.pressure.calibration", "amplitude"); - addConfigurationProperty("touch.pressure.source", "touch"); - addConfigurationProperty("touch.pressure.scale", "0.01"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - // Note: We only provide a single common touch/tool value because the device is assumed - // not to emit separate values for each pointer (isSummed = 1). - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawX2 = 150; - int32_t rawY2 = 250; - int32_t rawTouchMajor = 60; - int32_t rawToolMajor = 5; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float x2 = toDisplayX(rawX2); - float y2 = toDisplayY(rawY2); - float pressure = float(rawTouchMajor) * 0.01f; - float size = float(rawToolMajor) / RAW_TOOL_MAX; - float tool = (float(rawToolMajor) * 10.0f + 160.0f) / 2; - float touch = min(tool * pressure, tool); - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processPosition(mapper, rawX2, rawY2); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processSync(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); - ASSERT_EQ(size_t(2), args.pointerCount); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touch, touch, tool, tool, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1], - x2, y2, pressure, size, touch, touch, tool, tool, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - prepareDisplay(InputReaderPolicyInterface::ROTATION_0); - prepareAxes(POSITION | TOUCH | TOOL); - addConfigurationProperty("touch.touchSize.calibration", "pressure"); - addConfigurationProperty("touch.toolSize.calibration", "area"); - addConfigurationProperty("touch.toolSize.areaScale", "22"); - addConfigurationProperty("touch.toolSize.areaBias", "1"); - addConfigurationProperty("touch.toolSize.linearScale", "9.2"); - addConfigurationProperty("touch.toolSize.linearBias", "3"); - addConfigurationProperty("touch.pressure.calibration", "amplitude"); - addConfigurationProperty("touch.pressure.source", "touch"); - addConfigurationProperty("touch.pressure.scale", "0.01"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 60; - int32_t rawToolMajor = 5; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawTouchMajor) * 0.01f; - float size = float(rawToolMajor) / RAW_TOOL_MAX; - float tool = sqrtf(float(rawToolMajor) * 22.0f + 1.0f) * 9.2f + 3.0f; - float touch = min(tool * pressure, tool); - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processSync(mapper); - - FakeInputDispatcher::NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touch, touch, tool, tool, 0)); -} - -} // namespace android diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp index fd7edecf9a65..d472d45c4dd1 100644 --- a/libs/utils/PropertyMap.cpp +++ b/libs/utils/PropertyMap.cpp @@ -109,6 +109,12 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { return true; } +void PropertyMap::addAll(const PropertyMap* map) { + for (size_t i = 0; i < map->mProperties.size(); i++) { + mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); + } +} + status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) { *outMap = NULL; diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index bbf50934df92..7197ad7a2b7e 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -3703,9 +3703,9 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs) const void ResTable::getLocales(Vector<String8>* locales) const { Vector<ResTable_config> configs; - LOGD("calling getConfigurations"); + LOGV("calling getConfigurations"); getConfigurations(&configs); - LOGD("called getConfigurations size=%d", (int)configs.size()); + LOGV("called getConfigurations size=%d", (int)configs.size()); const size_t I = configs.size(); for (size_t i=0; i<I; i++) { char locale[6]; @@ -4141,6 +4141,38 @@ void print_complex(uint32_t complex, bool isFraction) } } +// Normalize a string for output +String8 ResTable::normalizeForOutput( const char *input ) +{ + String8 ret; + char buff[2]; + buff[1] = '\0'; + + while (*input != '\0') { + switch (*input) { + // All interesting characters are in the ASCII zone, so we are making our own lives + // easier by scanning the string one byte at a time. + case '\\': + ret += "\\\\"; + break; + case '\n': + ret += "\\n"; + break; + case '"': + ret += "\\\""; + break; + default: + buff[0] = *input; + ret += buff; + break; + } + + input++; + } + + return ret; +} + void ResTable::print_value(const Package* pkg, const Res_value& value) const { if (value.dataType == Res_value::TYPE_NULL) { @@ -4154,13 +4186,13 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const const char* str8 = pkg->header->values.string8At( value.data, &len); if (str8 != NULL) { - printf("(string8) \"%s\"\n", str8); + printf("(string8) \"%s\"\n", normalizeForOutput(str8).string()); } else { const char16_t* str16 = pkg->header->values.stringAt( value.data, &len); if (str16 != NULL) { printf("(string16) \"%s\"\n", - String8(str16, len).string()); + normalizeForOutput(String8(str16, len).string()).string()); } else { printf("(string) null\n"); } diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index f6c55e4d89de..b1bd8284430f 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -774,7 +774,11 @@ int Thread::_threadLoop(void* user) self->mExitPending = true; self->mLock.lock(); self->mRunning = false; + // clear thread ID so that requestExitAndWait() does not exit if + // called by a new thread using the same thread ID as this one. + self->mThread = thread_id_t(-1); self->mThreadExitedCondition.broadcast(); + self->mThread = thread_id_t(-1); // thread id could be reused self->mLock.unlock(); break; } |