diff options
90 files changed, 2033 insertions, 1015 deletions
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index 3155766a8f..ddf3aa8686 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -207,7 +207,7 @@ bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp<GLConsumer> glc = new GLConsumer(consumer, name, GL_TEXTURE_EXTERNAL_OES, false, true); glc->setDefaultBufferSize(w, h); - glc->setDefaultMaxBufferCount(3); + producer->setMaxDequeuedBufferCount(2); glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); sp<ANativeWindow> anw = new Surface(producer); diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc index e73516dbbd..7154fabcc7 100644 --- a/cmds/servicemanager/servicemanager.rc +++ b/cmds/servicemanager/servicemanager.rc @@ -7,4 +7,5 @@ service servicemanager /system/bin/servicemanager onrestart restart zygote onrestart restart media onrestart restart surfaceflinger + onrestart restart inputflinger onrestart restart drm diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 421abe5477..ac07190fc5 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -732,9 +732,23 @@ enum { AKEYCODE_STEM_2 = 266, /** Generic stem key 3 for Wear */ AKEYCODE_STEM_3 = 267, + /** Directional Pad Up-Left */ + AKEYCODE_DPAD_UP_LEFT = 268, + /** Directional Pad Down-Left */ + AKEYCODE_DPAD_DOWN_LEFT = 269, + /** Directional Pad Up-Right */ + AKEYCODE_DPAD_UP_RIGHT = 270, + /** Directional Pad Down-Right */ + AKEYCODE_DPAD_DOWN_RIGHT = 271, + /** Skip forward media key */ AKEYCODE_MEDIA_SKIP_FORWARD = 272, + /** Skip backward media key */ AKEYCODE_MEDIA_SKIP_BACKWARD = 273, + /** Step forward media key. + * Steps media forward one from at a time. */ AKEYCODE_MEDIA_STEP_FORWARD = 274, + /** Step backward media key. + * Steps media backward one from at a time. */ AKEYCODE_MEDIA_STEP_BACKWARD = 275, /** Put device to sleep unless a wakelock is held. */ AKEYCODE_SOFT_SLEEP = 276 diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h index 145efe6f60..504ac64e38 100644 --- a/include/gui/BufferItem.h +++ b/include/gui/BufferItem.h @@ -98,13 +98,8 @@ class BufferItem : public Flattenable<BufferItem> { }; }; - union { - // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mSlot; - - // mBuf is the former name for mSlot - int mBuf; - }; + // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). + int mSlot; // mIsDroppable whether this buffer was queued with the // property that it can be replaced by a new buffer for the purpose of diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h index cde302f8a6..b2daae47c3 100644 --- a/include/gui/BufferQueueConsumer.h +++ b/include/gui/BufferQueueConsumer.h @@ -100,20 +100,8 @@ public: // is 1x1. virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount); - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before connect(). - virtual status_t disableAsyncBuffer(); + // see IGraphicBufferConsumer::setMaxBufferCount + virtual status_t setMaxBufferCount(int bufferCount); // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h index 99134ea501..36cd238f29 100644 --- a/include/gui/BufferQueueCore.h +++ b/include/gui/BufferQueueCore.h @@ -85,31 +85,25 @@ private: // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we're in asynchronous mode. - int getMinUndequeuedBufferCountLocked(bool async) const; + int getMinUndequeuedBufferCountLocked() const; // getMinMaxBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. The async parameter tells whether // we're in asynchonous mode. - int getMinMaxBufferCountLocked(bool async) const; + int getMinMaxBufferCountLocked() const; // getMaxBufferCountLocked returns the maximum number of buffers that can be // allocated at once. This value depends on the following member variables: // - // mDequeueBufferCannotBlock + // mMaxDequeuedBufferCount // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // async parameter + // mMaxBufferCount + // mAsyncMode + // mDequeueBufferCannotBlock // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked(bool async) const; - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The - // initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); + int getMaxBufferCountLocked() const; // freeBufferLocked frees the GraphicBuffer and sync resources for the // given slot. @@ -192,21 +186,10 @@ private: // a buffer attached std::list<int> mFreeBuffers; - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the producer by calling - // setBufferCount. The default is 0, which means that the producer doesn't - // care about the number of buffers in the pool. In that case, - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - // mDequeueCondition is a condition variable used for dequeueBuffer in // synchronous mode. mutable Condition mDequeueCondition; - // mUseAsyncBuffer indicates whether an extra buffer is used in async mode - // to prevent dequeueBuffer from blocking. - bool mUseAsyncBuffer; - // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and // consumer are controlled by the application. @@ -229,11 +212,9 @@ private: // is specified. android_dataspace mDefaultBufferDataSpace; - // mDefaultMaxBufferCount is the default limit on the number of buffers that - // will be allocated at one time. This default limit is set by the consumer. - // The limit (as opposed to the default limit) may be overriden by the - // producer. - int mDefaultMaxBufferCount; + // mMaxBufferCount is the limit on the number of buffers that will be + // allocated at one time. This limit can be set by the consumer. + int mMaxBufferCount; // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer @@ -242,6 +223,11 @@ private: // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. int mMaxAcquiredBufferCount; + // mMaxDequeuedBufferCount is the number of buffers that the producer may + // dequeue at one time. It defaults to 1, and can be changed by the producer + // via setMaxDequeuedBufferCount. + int mMaxDequeuedBufferCount; + // mBufferHasBeenQueued is true once a buffer has been queued. It is reset // when something causes all buffers to be freed (e.g., changing the buffer // count). @@ -280,6 +266,11 @@ private: // number will fail. uint32_t mGenerationNumber; + // mAsyncMode indicates whether or not async mode is enabled. + // In async mode an extra buffer will be allocated to allow the producer to + // enqueue buffers without blocking. + bool mAsyncMode; + }; // class BufferQueueCore } // namespace android diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index 9754a89eac..6e16a608ee 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -39,22 +39,11 @@ public: // flags indicating that previously-returned buffers are no longer valid. virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the BufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); + // see IGraphicsBufferProducer::setMaxDequeuedBufferCount + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); + + // see IGraphicsBufferProducer::setAsyncMode + virtual status_t setAsyncMode(bool async); // dequeueBuffer gets the next buffer slot index for the producer to use. // If a buffer slot is available then that slot index is written to the @@ -92,7 +81,7 @@ public: // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, - bool async, uint32_t width, uint32_t height, PixelFormat format, + uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); // See IGraphicBufferProducer::detachBuffer @@ -128,7 +117,7 @@ public: // // The buffer will not be overwritten until the fence signals. The fence // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int slot, const sp<Fence>& fence); + virtual status_t cancelBuffer(int slot, const sp<Fence>& fence); // Query native window attributes. The "what" values are enumerated in // window.h (e.g. NATIVE_WINDOW_FORMAT). @@ -169,7 +158,7 @@ public: virtual status_t setSidebandStream(const sp<NativeHandle>& stream); // See IGraphicBufferProducer::allocateBuffers - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); // See IGraphicBufferProducer::allowAllocation @@ -190,8 +179,8 @@ private: // mode (producer and consumer controlled by the application). If it blocks, // it will release mCore->mMutex while blocked so that other operations on // the BufferQueue may succeed. - status_t waitForFreeSlotThenRelock(const char* caller, bool async, - int* found, status_t* returnFlags) const; + status_t waitForFreeSlotThenRelock(const char* caller, int* found, + status_t* returnFlags) const; sp<BufferQueueCore> mCore; diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h index 3b07a31750..f9d0e7db78 100644 --- a/include/gui/CpuConsumer.h +++ b/include/gui/CpuConsumer.h @@ -67,6 +67,25 @@ class CpuConsumer : public ConsumerBase uint8_t *dataCr; uint32_t chromaStride; uint32_t chromaStep; + + LockedBuffer() : + data(NULL), + width(0), + height(0), + format(PIXEL_FORMAT_NONE), + stride(0), + crop(0, 0, 0, 0), + transform(0), + scalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + timestamp(0), + dataSpace(HAL_DATASPACE_UNKNOWN), + frameNumber(0), + flexFormat(PIXEL_FORMAT_NONE), + dataCb(NULL), + dataCr(NULL), + chromaStride(0), + chromaStep(0) + {} }; // Create a new CPU consumer. The maxLockedBuffers parameter specifies diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index c35c7be064..0e4acee838 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -112,11 +112,6 @@ public: // union fence. void setReleaseFence(const sp<Fence>& fence); - // setDefaultMaxBufferCount sets the default limit on the maximum number - // of buffers that will be allocated at one time. The image producer may - // override the limit. - status_t setDefaultMaxBufferCount(int bufferCount); - // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix // associated with the texture image set by the most recent call to // updateTexImage. @@ -201,6 +196,7 @@ public: status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); status_t setConsumerUsageBits(uint32_t usage); status_t setTransformHint(uint32_t hint); + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 60ec9cc0e9..d4c9ee535f 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -188,32 +188,28 @@ public: // * BAD_VALUE - either w or h was zero virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. + // setMaxBufferCount sets the maximum value for the number of buffers used + // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call + // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode + // or setMaxDequeuedBufferCount (by the producer), would cause this value to + // be exceeded then that call will fail. This call will fail if a producer + // is connected to the BufferQueue. // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. + // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count + // cannot be less than maxAcquiredBufferCount. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - bufferCount was out of range (see above). - virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - // - // Return of a value other than NO_ERROR means an error has occurred: - // * INVALID_OPERATION - attempting to call this after consumerConnect. - virtual status_t disableAsyncBuffer() = 0; + // * INVALID_OPERATION - attempting to call this after a producer connected. + virtual status_t setMaxBufferCount(int bufferCount) = 0; // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. // - // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. + // maxAcquiredBuffers must be (inclusive) between 1 and + // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value + // to be exceeded. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - maxAcquiredBuffers was out of range (see above). diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 9530de1aa8..b8cba2f430 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -74,33 +74,50 @@ public: // The slot must be in the range of [0, NUM_BUFFER_SLOTS). // // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - one of the two conditions occurred: // * slot was out of range (see above) // * buffer specified by the slot is not dequeued virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0; - // setBufferCount sets the number of buffer slots available. Calling this - // will also cause all buffer slots to be emptied. The caller should empty - // its mirrored copy of the buffer slots when calling this method. - // - // This function should not be called when there are any dequeued buffer - // slots, doing so will result in a BAD_VALUE error returned. + // setMaxDequeuedBufferCount sets the maximum number of buffers that can be + // dequeued by the producer at one time. If this method succeeds, buffer + // slots will be both unallocated and owned by the BufferQueue object (i.e. + // they are not owned by the producer or consumer). Calling this will also + // cause all buffer slots to be emptied. If the caller is caching the + // contents of the buffer slots, it should empty that cache after calling + // this method. // - // The buffer count should be at most NUM_BUFFER_SLOTS (inclusive), but at least - // the minimum undequeued buffer count (exclusive). The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS). - // In particular the range is (minUndequeudBuffers, NUM_BUFFER_SLOTS]. + // This function should not be called when there are any currently dequeued + // buffer slots. Doing so will result in a BAD_VALUE error. // - // The buffer count may also be set to 0 (the default), to indicate that - // the producer does not wish to set a value. + // The buffer count should be at least 1 (inclusive), but at most + // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The + // minimum undequeued buffer count can be obtained by calling + // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. // * BAD_VALUE - one of the below conditions occurred: - // * bufferCount was out of range (see above) - // * client has one or more buffers dequeued - virtual status_t setBufferCount(int bufferCount) = 0; + // * bufferCount was out of range (see above) + // * client has one or more buffers dequeued + // * this call would cause the maxBufferCount value to be exceeded + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0; + + // Set the async flag if the producer intends to asynchronously queue + // buffers without blocking. Typically this is used for triple-buffering + // and/or when the swap interval is set to zero. + // + // Enabling async mode will internally allocate an additional buffer to + // allow for the asynchronous behavior. If it is not enabled queue/dequeue + // calls may block. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the buffer queue has been abandoned. + // * BAD_VALUE - this call would cause the maxBufferCount value to be + // exceeded + virtual status_t setAsyncMode(bool async) = 0; // dequeueBuffer requests a new buffer slot for the client to use. Ownership // of the slot is transfered to the client, meaning that the server will not @@ -126,9 +143,6 @@ public: // fence signals. If the fence is Fence::NO_FENCE, the buffer may be written // immediately. // - // The async parameter sets whether we're in asynchronous mode for this - // dequeueBuffer() call. - // // The width and height parameters must be no greater than the minimum of // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). // An error due to invalid dimensions might not be reported until @@ -150,7 +164,8 @@ public: // success. // // Return of a negative means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - both in async mode and buffer count was less than the // max numbers of buffers that can be allocated at once. // * INVALID_OPERATION - cannot attach the buffer because it would cause @@ -165,8 +180,8 @@ public: // // All other negative values are an unknown error returned downstream // from the graphics allocator (typically errno). - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0; + virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, + uint32_t h, PixelFormat format, uint32_t usage) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be @@ -178,7 +193,8 @@ public: // requestBuffer). // // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - the given slot number is invalid, either because it is // out of the range [0, NUM_BUFFER_SLOTS), or because the slot // it refers to is not currently dequeued and requested. @@ -198,7 +214,8 @@ public: // equivalent to fence from the dequeueBuffer call. // // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - either outBuffer or outFence were NULL. // * NO_MEMORY - no slots were found that were both free and contained a // GraphicBuffer. @@ -217,7 +234,8 @@ public: // success. // // Return of a negative value means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - outSlot or buffer were NULL, invalid combination of // async mode and buffer count override, or the generation // number of the buffer did not match the buffer queue. @@ -251,7 +269,8 @@ public: // (refer to the documentation below). // // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. // * BAD_VALUE - one of the below conditions occurred: // * fence was NULL // * scaling mode was unknown @@ -271,23 +290,21 @@ public: // crop - a crop rectangle that's used as a hint to the consumer // scalingMode - a set of flags from NATIVE_WINDOW_SCALING_* in <window.h> // transform - a set of flags from NATIVE_WINDOW_TRANSFORM_* in <window.h> - // async - if the buffer is queued in asynchronous mode // fence - a fence that the consumer must wait on before reading the buffer, // set this to Fence::NO_FENCE if the buffer is ready immediately // sticky - the sticky transform set in Surface (only used by the LEGACY // camera mode). inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp, android_dataspace dataSpace, const Rect& crop, int scalingMode, - uint32_t transform, bool async, const sp<Fence>& fence, - uint32_t sticky = 0) + uint32_t transform, const sp<Fence>& fence, uint32_t sticky = 0) : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), dataSpace(dataSpace), crop(crop), scalingMode(scalingMode), - transform(transform), stickyTransform(sticky), - async(async), fence(fence), surfaceDamage() { } + transform(transform), stickyTransform(sticky), fence(fence), + surfaceDamage() { } inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, android_dataspace* outDataSpace, Rect* outCrop, int* outScalingMode, - uint32_t* outTransform, bool* outAsync, sp<Fence>* outFence, + uint32_t* outTransform, sp<Fence>* outFence, uint32_t* outStickyTransform = NULL) const { *outTimestamp = timestamp; *outIsAutoTimestamp = bool(isAutoTimestamp); @@ -295,7 +312,6 @@ public: *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; - *outAsync = bool(async); *outFence = fence; if (outStickyTransform != NULL) { *outStickyTransform = stickyTransform; @@ -319,7 +335,6 @@ public: int scalingMode; uint32_t transform; uint32_t stickyTransform; - int async; sp<Fence> fence; Region surfaceDamage; }; @@ -355,8 +370,8 @@ public: uint32_t numPendingBuffers; }; - virtual status_t queueBuffer(int slot, - const QueueBufferInput& input, QueueBufferOutput* output) = 0; + virtual status_t queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) = 0; // cancelBuffer indicates that the client does not wish to fill in the // buffer associated with slot and transfers ownership of the slot back to @@ -364,9 +379,19 @@ public: // // The buffer is not queued for use by the consumer. // + // The slot must be in the range of [0, NUM_BUFFER_SLOTS). + // // The buffer will not be overwritten until the fence signals. The fence // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0; + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. + // * BAD_VALUE - one of the below conditions occurred: + // * fence was NULL + // * slot index was out of range (see above). + // * the slot was not in the dequeued state + virtual status_t cancelBuffer(int slot, const sp<Fence>& fence) = 0; // query retrieves some information for this surface // 'what' tokens allowed are that of NATIVE_WINDOW_* in <window.h> @@ -457,7 +482,7 @@ public: // allocated. This is most useful to avoid an allocation delay during // dequeueBuffer. If there are already the maximum number of buffers // allocated, this function has no effect. - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) = 0; // Sets whether dequeueBuffer is allowed to allocate new buffers. diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 72f1067076..ed2331b1e6 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -183,6 +183,8 @@ protected: virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: + virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers); + virtual int setAsyncMode(bool async); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index f0a6238e94..efc1687667 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -307,6 +307,10 @@ static const InputEventLabel KEYCODES[] = { DEFINE_KEYCODE(STEM_1), DEFINE_KEYCODE(STEM_2), DEFINE_KEYCODE(STEM_3), + DEFINE_KEYCODE(DPAD_UP_LEFT), + DEFINE_KEYCODE(DPAD_DOWN_LEFT), + DEFINE_KEYCODE(DPAD_UP_RIGHT), + DEFINE_KEYCODE(DPAD_DOWN_RIGHT), DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), DEFINE_KEYCODE(MEDIA_STEP_FORWARD), diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index cbe87330ed..b2574d0818 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -58,11 +58,10 @@ struct layer_state_t { : what(0), x(0), y(0), z(0), w(0), h(0), layerStack(0), alpha(0), flags(0), mask(0), - reserved(0) + reserved(0), crop(Rect::INVALID_RECT) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; - crop.makeInvalid(); } status_t write(Parcel& output) const; @@ -117,6 +116,8 @@ struct DisplayState { eDisplaySizeChanged = 0x08 }; + DisplayState(); + uint32_t what; sp<IBinder> token; sp<IGraphicBufferProducer> surface; diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h index 8c190dd40b..84eb10079b 100644 --- a/include/private/ui/RegionHelper.h +++ b/include/private/ui/RegionHelper.h @@ -72,7 +72,7 @@ public: } void operator()(region_rasterizer& rasterizer) { - RECT current; + RECT current(Rect::EMPTY_RECT); do { SpannerInner spannerInner(spanner.lhs, spanner.rhs); int inside = spanner.next(current.top, current.bottom); diff --git a/include/ui/Rect.h b/include/ui/Rect.h index 3886f93142..6310502b34 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -32,13 +32,12 @@ public: typedef ARect::value_type value_type; static const Rect INVALID_RECT; + static const Rect EMPTY_RECT; // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions - inline Rect() { - left = right = top = bottom = 0; - } + inline Rect() : Rect(INVALID_RECT) {} inline Rect(int32_t w, int32_t h) { left = top = 0; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 45191f5bd9..8315c58843 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -350,13 +350,11 @@ size_t Parcel::dataSize() const size_t Parcel::dataAvail() const { - // TODO: decide what to do about the possibility that this can - // report an available-data size that exceeds a Java int's max - // positive value, causing havoc. Fortunately this will only - // happen if someone constructs a Parcel containing more than two - // gigabytes of data, which on typical phone hardware is simply - // not possible. - return dataSize() - dataPosition(); + size_t result = dataSize() - dataPosition(); + if (result > INT32_MAX) { + abort(); + } + return result; } size_t Parcel::dataPosition() const diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 8f64ae0e04..6a883cf807 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -24,6 +24,7 @@ namespace android { BufferItem::BufferItem() : + mCrop(Rect::INVALID_RECT), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), @@ -34,7 +35,6 @@ BufferItem::BufferItem() : mIsDroppable(false), mAcquireCalled(false), mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); } BufferItem::~BufferItem() {} diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 578b8d96b1..6f4c89dd8d 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -78,7 +78,7 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, } } - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; + item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer; return OK; } @@ -89,9 +89,9 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); - err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); + err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, + err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index bb3e1b0a4d..d52b47f3b0 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -482,24 +482,29 @@ status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, return NO_ERROR; } -status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { +status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - return mCore->setDefaultMaxBufferCountLocked(bufferCount); -} -status_t BufferQueueConsumer::disableAsyncBuffer() { - ATRACE_CALL(); + if (bufferCount < 1 || bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("setMaxBufferCount: invalid count %d", bufferCount); + return BAD_VALUE; + } Mutex::Autolock lock(mCore->mMutex); - if (mCore->mConsumerListener != NULL) { - BQ_LOGE("disableAsyncBuffer: consumer already connected"); + if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("setMaxBufferCount: producer is already connected"); return INVALID_OPERATION; } - BQ_LOGV("disableAsyncBuffer"); - mCore->mUseAsyncBuffer = false; + if (bufferCount < mCore->mMaxAcquiredBufferCount) { + BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than" + "mMaxAcquiredBufferCount (%d)", bufferCount, + mCore->mMaxAcquiredBufferCount); + return BAD_VALUE; + } + + mCore->mMaxBufferCount = bufferCount; return NO_ERROR; } @@ -521,6 +526,17 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( return INVALID_OPERATION; } + if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount + + (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) > + mCore->mMaxBufferCount) { + BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed " + "the maxBufferCount (%d) (maxDequeued %d async %d)", + maxAcquiredBuffers, mCore->mMaxBufferCount, + mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode || + mCore->mDequeueBufferCannotBlock); + return BAD_VALUE; + } + BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; return NO_ERROR; diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 851a396155..b1cbc86068 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -30,9 +30,6 @@ #include <gui/ISurfaceComposer.h> #include <private/gui/ComposerService.h> -template <typename T> -static inline T max(T a, T b) { return a > b ? a : b; } - namespace android { static String8 getUniqueName() { @@ -55,16 +52,15 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mQueue(), mFreeSlots(), mFreeBuffers(), - mOverrideMaxBufferCount(0), mDequeueCondition(), - mUseAsyncBuffer(true), mDequeueBufferCannotBlock(false), mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), - mDefaultMaxBufferCount(2), + mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), mMaxAcquiredBufferCount(1), + mMaxDequeuedBufferCount(1), mBufferHasBeenQueued(false), mFrameCounter(0), mTransformHint(0), @@ -72,7 +68,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mIsAllocatingCondition(), mAllowAllocation(true), mBufferAge(0), - mGenerationNumber(0) + mGenerationNumber(0), + mAsyncMode(false) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); @@ -104,11 +101,13 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { } result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " - "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", - prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, - mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, - mQueue.size(), fifo.string()); + "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d " + "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, " + "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix, + mMaxAcquiredBufferCount, mMaxDequeuedBufferCount, + mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth, + mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(), + fifo.string()); // Trim the free buffers so as to not spam the dump int maxBufferCount = 0; @@ -139,32 +138,26 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { } } -int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { +int BufferQueueCore::getMinUndequeuedBufferCountLocked() const { // If dequeueBuffer is allowed to error out, we don't have to add an // extra buffer. - if (!mUseAsyncBuffer) { - return mMaxAcquiredBufferCount; - } - - if (mDequeueBufferCannotBlock || async) { + if (mAsyncMode || mDequeueBufferCannotBlock) { return mMaxAcquiredBufferCount + 1; } return mMaxAcquiredBufferCount; } -int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const { - return getMinUndequeuedBufferCountLocked(async) + 1; +int BufferQueueCore::getMinMaxBufferCountLocked() const { + return getMinUndequeuedBufferCountLocked() + 1; } -int BufferQueueCore::getMaxBufferCountLocked(bool async) const { - int minMaxBufferCount = getMinMaxBufferCountLocked(async); +int BufferQueueCore::getMaxBufferCountLocked() const { + int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount + + (mAsyncMode || mDequeueBufferCannotBlock ? 1 : 0); - int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount); - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } + // limit maxBufferCount by mMaxBufferCount always + maxBufferCount = std::min(mMaxBufferCount, maxBufferCount); // Any buffers that are dequeued by the producer or sitting in the queue // waiting to be consumed need to have their slots preserved. Such buffers @@ -180,22 +173,6 @@ int BufferQueueCore::getMaxBufferCountLocked(bool async) const { return maxBufferCount; } -status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) { - const int minBufferCount = mUseAsyncBuffer ? 2 : 1; - if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in " - "[%d, %d]", - count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count); - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - void BufferQueueCore::freeBufferLocked(int slot) { BQ_LOGV("freeBufferLocked: slot %d", slot); bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 87e5b4d279..0cb018ccae 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -57,6 +57,11 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_INIT; } + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("requestBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); @@ -72,9 +77,11 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_ERROR; } -status_t BufferQueueProducer::setBufferCount(int bufferCount) { +status_t BufferQueueProducer::setMaxDequeuedBufferCount( + int maxDequeuedBuffers) { ATRACE_CALL(); - BQ_LOGV("setBufferCount: count = %d", bufferCount); + BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d", + maxDequeuedBuffers); sp<IConsumerListener> listener; { // Autolock scope @@ -82,34 +89,41 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { - BQ_LOGE("setBufferCount: BufferQueue has been abandoned"); + BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been " + "abandoned"); return NO_INIT; } - if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)", - bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - // There must be no dequeued buffers when changing the buffer count. for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) { - BQ_LOGE("setBufferCount: buffer owned by producer"); + BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer"); return BAD_VALUE; } } - if (bufferCount == 0) { - mCore->mOverrideMaxBufferCount = 0; - mCore->mDequeueCondition.broadcast(); - return NO_ERROR; + int bufferCount = mCore->getMinUndequeuedBufferCountLocked(); + bufferCount += maxDequeuedBuffers; + + if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large " + "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; } - const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false); + const int minBufferSlots = mCore->getMinMaxBufferCountLocked(); if (bufferCount < minBufferSlots) { - BQ_LOGE("setBufferCount: requested buffer count %d is less than " - "minimum %d", bufferCount, minBufferSlots); + BQ_LOGE("setMaxDequeuedBufferCount: requested buffer count %d is " + "less than minimum %d", bufferCount, minBufferSlots); + return BAD_VALUE; + } + + if (bufferCount > mCore->mMaxBufferCount) { + BQ_LOGE("setMaxDequeuedBufferCount: %d dequeued buffers would " + "exceed the maxBufferCount (%d) (maxAcquired %d async %d " + "mDequeuedBufferCannotBlock %d)", maxDequeuedBuffers, + mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount, + mCore->mAsyncMode, mCore->mDequeueBufferCannotBlock); return BAD_VALUE; } @@ -118,7 +132,7 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { // clear the queue, however, so that currently queued buffers still // get displayed. mCore->freeAllBuffersLocked(); - mCore->mOverrideMaxBufferCount = bufferCount; + mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers; mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; } // Autolock scope @@ -131,8 +145,46 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { return NO_ERROR; } +status_t BufferQueueProducer::setAsyncMode(bool async) { + ATRACE_CALL(); + BQ_LOGV("setAsyncMode: async = %d", async); + + sp<IConsumerListener> listener; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + if (mCore->mIsAbandoned) { + BQ_LOGE("setAsyncMode: BufferQueue has been abandoned"); + return NO_INIT; + } + + if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount + + (async || mCore->mDequeueBufferCannotBlock ? 1 : 0)) > + mCore->mMaxBufferCount) { + BQ_LOGE("setAsyncMode(%d): this call would cause the " + "maxBufferCount (%d) to be exceeded (maxAcquired %d " + "maxDequeued %d mDequeueBufferCannotBlock %d)", async, + mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount, + mCore->mMaxDequeuedBufferCount, + mCore->mDequeueBufferCannotBlock); + return BAD_VALUE; + } + + mCore->mAsyncMode = async; + mCore->mDequeueCondition.broadcast(); + listener = mCore->mConsumerListener; + } // Autolock scope + + // Call back without lock held + if (listener != NULL) { + listener->onBuffersReleased(); + } + return NO_ERROR; +} + status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, - bool async, int* found, status_t* returnFlags) const { + int* found, status_t* returnFlags) const { bool tryAgain = true; while (tryAgain) { if (mCore->mIsAbandoned) { @@ -140,17 +192,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, return NO_INIT; } - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - BQ_LOGE("%s: async mode is invalid with buffer count override", - caller); - return BAD_VALUE; - } - } + const int maxBufferCount = mCore->getMaxBufferCountLocked(); // Free up any buffers that are in slots beyond the max buffer count for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { @@ -176,33 +218,16 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } } - // Producers are not allowed to dequeue more than one buffer if they - // did not set a buffer count - if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { - BQ_LOGE("%s: can't dequeue multiple buffers without setting the " - "buffer count", caller); + // Producers are not allowed to dequeue more than + // mMaxDequeuedBufferCount buffers. + // This check is only done if a buffer has already been queued + if (mCore->mBufferHasBeenQueued && + dequeuedCount >= mCore->mMaxDequeuedBufferCount) { + BQ_LOGE("%s: attempting to exceed the max dequeued buffer count " + "(%d)", caller, mCore->mMaxDequeuedBufferCount); return INVALID_OPERATION; } - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below - if (mCore->mBufferHasBeenQueued) { - // Make sure the producer is not trying to dequeue more buffers - // than allowed - const int newUndequeuedCount = - maxBufferCount - (dequeuedCount + 1); - const int minUndequeuedCount = - mCore->getMinUndequeuedBufferCountLocked(async); - if (newUndequeuedCount < minUndequeuedCount) { - BQ_LOGE("%s: min undequeued buffer count (%d) exceeded " - "(dequeued=%d undequeued=%d)", - caller, minUndequeuedCount, - dequeuedCount, newUndequeuedCount); - return INVALID_OPERATION; - } - } - *found = BufferQueueCore::INVALID_BUFFER_SLOT; // If we disconnect and reconnect quickly, we can be in a state where @@ -241,7 +266,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, // buffer (which could cause us to have to wait here), which is // okay, since it is only used to implement an atomic acquire + // release (e.g., in GLConsumer::updateTexImage()) - if (mCore->mDequeueBufferCannotBlock && + if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) && (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } @@ -253,16 +278,26 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } status_t BufferQueueProducer::dequeueBuffer(int *outSlot, - sp<android::Fence> *outFence, bool async, - uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { + sp<android::Fence> *outFence, uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; + + if (mCore->mIsAbandoned) { + BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } + + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } } // Autolock scope - BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", - async ? "true" : "false", width, height, format, usage); + BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height, + format, usage); if ((width && !height) || (!width && height)) { BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); @@ -293,8 +328,8 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, int found = BufferItem::INVALID_BUFFER_SLOT; while (found == BufferItem::INVALID_BUFFER_SLOT) { - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); + status_t status = waitForFreeSlotThenRelock("dequeueBuffer", &found, + &returnFlags); if (status != NO_ERROR) { return status; } @@ -426,6 +461,11 @@ status_t BufferQueueProducer::detachBuffer(int slot) { return NO_INIT; } + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("detachBuffer(P): BufferQueue has no connected producer"); + return NO_INIT; + } + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); @@ -460,13 +500,19 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, } Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned"); return NO_INIT; } + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + mCore->waitWhileAllocatingLocked(); + if (mCore->mFreeBuffers.empty()) { return NO_MEMORY; } @@ -497,7 +543,16 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, } Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); + + if (mCore->mIsAbandoned) { + BQ_LOGE("attachBuffer(P): BufferQueue has been abandoned"); + return NO_INIT; + } + + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("attachBuffer(P): BufferQueue has no connected producer"); + return NO_INIT; + } if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " @@ -506,13 +561,12 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, return BAD_VALUE; } + mCore->waitWhileAllocatingLocked(); + status_t returnFlags = NO_ERROR; int found; - // TODO: Should we provide an async flag to attachBuffer? It seems - // unlikely that buffers which we are attaching to a BufferQueue will - // be asynchronous (droppable), but it may not be impossible. - status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false, - &found, &returnFlags); + status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", &found, + &returnFlags); if (status != NO_ERROR) { return status; } @@ -547,14 +601,13 @@ status_t BufferQueueProducer::queueBuffer(int slot, int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; - Rect crop; + Rect crop(Rect::EMPTY_RECT); int scalingMode; uint32_t transform; uint32_t stickyTransform; - bool async; sp<Fence> fence; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, - &transform, &async, &fence, &stickyTransform); + &transform, &fence, &stickyTransform); Region surfaceDamage = input.getSurfaceDamage(); if (fence == NULL) { @@ -585,18 +638,13 @@ status_t BufferQueueProducer::queueBuffer(int slot, return NO_INIT; } - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - BQ_LOGE("queueBuffer: async mode is invalid with " - "buffer count override"); - return BAD_VALUE; - } + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("queueBuffer: BufferQueue has no connected producer"); + return NO_INIT; } + const int maxBufferCount = mCore->getMaxBufferCountLocked(); + if (slot < 0 || slot >= maxBufferCount) { BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot, maxBufferCount); @@ -619,7 +667,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedRect; + Rect croppedRect(Rect::EMPTY_RECT); crop.intersect(bufferRect, &croppedRect); if (croppedRect != crop) { BQ_LOGE("queueBuffer: crop rect is not contained within the " @@ -651,7 +699,8 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mFrameNumber = mCore->mFrameCounter; item.mSlot = slot; item.mFence = fence; - item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + item.mIsDroppable = mCore->mAsyncMode || + mCore->mDequeueBufferCannotBlock; item.mSurfaceDamage = surfaceDamage; mStickyTransform = stickyTransform; @@ -731,27 +780,32 @@ status_t BufferQueueProducer::queueBuffer(int slot, return NO_ERROR; } -void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { +status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { ATRACE_CALL(); BQ_LOGV("cancelBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); - return; + return NO_INIT; + } + + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("cancelBuffer: BufferQueue has no connected producer"); + return NO_INIT; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); - return; + return BAD_VALUE; } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); - return; + return BAD_VALUE; } else if (fence == NULL) { BQ_LOGE("cancelBuffer: fence is NULL"); - return; + return BAD_VALUE; } mCore->mFreeBuffers.push_front(slot); @@ -759,6 +813,8 @@ void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { mSlots[slot].mFence = fence; mCore->mDequeueCondition.broadcast(); mCore->validateConsistencyLocked(); + + return NO_ERROR; } int BufferQueueProducer::query(int what, int *outValue) { @@ -787,7 +843,7 @@ int BufferQueueProducer::query(int what, int *outValue) { value = static_cast<int32_t>(mCore->mDefaultBufferFormat); break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mCore->getMinUndequeuedBufferCountLocked(false); + value = mCore->getMinUndequeuedBufferCountLocked(); break; case NATIVE_WINDOW_STICKY_TRANSFORM: value = static_cast<int32_t>(mStickyTransform); @@ -877,8 +933,8 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, } mCore->mBufferHasBeenQueued = false; - mCore->mDequeueBufferCannotBlock = - mCore->mConsumerControlledByApp && producerControlledByApp; + mCore->mDequeueBufferCannotBlock = mCore->mConsumerControlledByApp && + producerControlledByApp; mCore->mAllowAllocation = true; return status; @@ -957,8 +1013,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) return NO_ERROR; } -void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, PixelFormat format, uint32_t usage) { +void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage) { ATRACE_CALL(); while (true) { Vector<int> freeSlots; @@ -992,7 +1048,7 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, } } - int maxBufferCount = mCore->getMaxBufferCountLocked(async); + int maxBufferCount = mCore->getMaxBufferCountLocked(); BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers", currentBufferCount, maxBufferCount); if (maxBufferCount <= currentBufferCount) diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 04ab06b557..d01187fbbf 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -239,14 +239,14 @@ status_t ConsumerBase::acquireBufferLocked(BufferItem *item, } if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; + mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; } - mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; - mSlots[item->mBuf].mFence = item->mFence; + mSlots[item->mSlot].mFrameNumber = item->mFrameNumber; + mSlots[item->mSlot].mFence = item->mFence; CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, - item->mBuf, item->mFrameNumber); + item->mSlot, item->mFrameNumber); return OK; } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index e29b740188..7ed3d0f893 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -106,22 +106,22 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - int buf = b.mBuf; + int slot = b.mSlot; void *bufferPointer = NULL; android_ycbcr ycbcr = android_ycbcr(); - PixelFormat format = mSlots[buf].mGraphicBuffer->getPixelFormat(); + PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); PixelFormat flexFormat = format; if (isPossiblyYUV(format)) { if (b.mFence.get()) { - err = mSlots[buf].mGraphicBuffer->lockAsyncYCbCr( + err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &ycbcr, b.mFence->dup()); } else { - err = mSlots[buf].mGraphicBuffer->lockYCbCr( + err = mSlots[slot].mGraphicBuffer->lockYCbCr( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &ycbcr); @@ -141,13 +141,13 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { if (bufferPointer == NULL) { // not flexible YUV if (b.mFence.get()) { - err = mSlots[buf].mGraphicBuffer->lockAsync( + err = mSlots[slot].mGraphicBuffer->lockAsync( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &bufferPointer, b.mFence->dup()); } else { - err = mSlots[buf].mGraphicBuffer->lock( + err = mSlots[slot].mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &bufferPointer); @@ -169,19 +169,19 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { assert(lockedIdx < mMaxLockedBuffers); AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = buf; + ab.mSlot = slot; ab.mBufferPointer = bufferPointer; - ab.mGraphicBuffer = mSlots[buf].mGraphicBuffer; + ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; nativeBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer); - nativeBuffer->width = mSlots[buf].mGraphicBuffer->getWidth(); - nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight(); + nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); + nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); nativeBuffer->format = format; nativeBuffer->flexFormat = flexFormat; nativeBuffer->stride = (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : - mSlots[buf].mGraphicBuffer->getStride(); + mSlots[slot].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 757e08a907..1572a89222 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -130,6 +130,7 @@ static bool isEglImageCroppable(const Rect& crop) { GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), + mCurrentCrop(Rect::EMPTY_RECT), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), @@ -157,6 +158,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), + mCurrentCrop(Rect::EMPTY_RECT), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), @@ -181,12 +183,6 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } -status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) { - Mutex::Autolock lock(mMutex); - return mConsumer->setDefaultMaxBufferCount(bufferCount); -} - - status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock lock(mMutex); @@ -355,7 +351,7 @@ status_t GLConsumer::acquireBufferLocked(BufferItem *item, // before, so any prior EglImage created is using a stale buffer. This // replaces any old EglImage with a new one (using the new buffer). if (item->mGraphicBuffer != NULL) { - int slot = item->mBuf; + int slot = item->mSlot; mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); } @@ -379,12 +375,12 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) { status_t err = NO_ERROR; - int buf = item.mBuf; + int slot = item.mSlot; if (!mAttached) { GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); - releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return INVALID_OPERATION; } @@ -392,7 +388,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) // Confirm state. err = checkAndUpdateEglStateLocked(); if (err != NO_ERROR) { - releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return err; } @@ -402,11 +398,11 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) // ConsumerBase. // We may have to do this even when item.mGraphicBuffer == NULL (which // means the buffer was previously acquired). - err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); + err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); if (err != NO_ERROR) { GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", - mEglDisplay, buf); - releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + mEglDisplay, slot); + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return UNKNOWN_ERROR; } @@ -418,7 +414,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) // release the old buffer, so instead we just drop the new frame. // As we are still under lock since acquireBuffer, it is safe to // release by slot. - releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return err; } @@ -426,7 +422,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, - buf, mSlots[buf].mGraphicBuffer->handle); + slot, mSlots[slot].mGraphicBuffer->handle); // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { @@ -442,8 +438,8 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) } // Update the GLConsumer state. - mCurrentTexture = buf; - mCurrentTextureImage = mEglSlots[buf].mEglImage; + mCurrentTexture = slot; + mCurrentTextureImage = mEglSlots[slot].mEglImage; mCurrentCrop = item.mCrop; mCurrentTransform = item.mTransform; mCurrentScalingMode = item.mScalingMode; @@ -1046,6 +1042,11 @@ status_t GLConsumer::setTransformHint(uint32_t hint) { return mConsumer->setTransformHint(hint); } +status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Mutex::Autolock lock(mMutex); + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); +} + void GLConsumer::dumpLocked(String8& result, const char* prefix) const { result.appendFormat( @@ -1083,7 +1084,8 @@ static void mtxMul(float out[16], const float a[16], const float b[16]) { GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), - mEglDisplay(EGL_NO_DISPLAY) { + mEglDisplay(EGL_NO_DISPLAY), + mCropRect(Rect::EMPTY_RECT) { } GLConsumer::EglImage::~EglImage() { diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index b86f4c5d23..d2f482e377 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -43,8 +43,7 @@ enum { CONSUMER_DISCONNECT, GET_RELEASED_BUFFERS, SET_DEFAULT_BUFFER_SIZE, - SET_DEFAULT_MAX_BUFFER_COUNT, - DISABLE_ASYNC_BUFFER, + SET_MAX_BUFFER_COUNT, SET_MAX_ACQUIRED_BUFFER_COUNT, SET_CONSUMER_NAME, SET_DEFAULT_BUFFER_FORMAT, @@ -172,21 +171,11 @@ public: return reply.readInt32(); } - virtual status_t setDefaultMaxBufferCount(int bufferCount) { + virtual status_t setMaxBufferCount(int bufferCount) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(bufferCount); - status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t disableAsyncBuffer() { - Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); + status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { return result; } @@ -363,16 +352,10 @@ status_t BnGraphicBufferConsumer::onTransact( reply->writeInt32(result); return NO_ERROR; } - case SET_DEFAULT_MAX_BUFFER_COUNT: { + case SET_MAX_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int bufferCount = data.readInt32(); - status_t result = setDefaultMaxBufferCount(bufferCount); - reply->writeInt32(result); - return NO_ERROR; - } - case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - status_t result = disableAsyncBuffer(); + status_t result = setMaxBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 8bdbc22ec9..8ab963d8db 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -34,7 +34,6 @@ namespace android { enum { REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - SET_BUFFER_COUNT, DEQUEUE_BUFFER, DETACH_BUFFER, DETACH_NEXT_BUFFER, @@ -49,6 +48,8 @@ enum { ALLOW_ALLOCATION, SET_GENERATION_NUMBER, GET_CONSUMER_NAME, + SET_MAX_DEQUEUED_BUFFER_COUNT, + SET_ASYNC_MODE }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -82,12 +83,27 @@ public: return result; } - virtual status_t setBufferCount(int bufferCount) - { + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(bufferCount); - status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply); + data.writeInterfaceToken( + IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(maxDequeuedBuffers); + status_t result = remote()->transact(SET_MAX_DEQUEUED_BUFFER_COUNT, + data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + + virtual status_t setAsyncMode(bool async) { + Parcel data, reply; + data.writeInterfaceToken( + IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(async); + status_t result = remote()->transact(SET_ASYNC_MODE, + data, &reply); if (result != NO_ERROR) { return result; } @@ -95,12 +111,10 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async, - uint32_t width, uint32_t height, PixelFormat format, - uint32_t usage) { + virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(static_cast<int32_t>(async)); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); @@ -190,12 +204,17 @@ public: return result; } - virtual void cancelBuffer(int buf, const sp<Fence>& fence) { + virtual status_t cancelBuffer(int buf, const sp<Fence>& fence) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); data.write(*fence.get()); - remote()->transact(CANCEL_BUFFER, data, &reply); + status_t result = remote()->transact(CANCEL_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; } virtual int query(int what, int* value) { @@ -260,11 +279,10 @@ public: return result; } - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(static_cast<int32_t>(async)); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); @@ -334,24 +352,30 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } - case SET_BUFFER_COUNT: { + case SET_MAX_DEQUEUED_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); - int bufferCount = data.readInt32(); - int result = setBufferCount(bufferCount); + int maxDequeuedBuffers = data.readInt32(); + int result = setMaxDequeuedBufferCount(maxDequeuedBuffers); + reply->writeInt32(result); + return NO_ERROR; + } + case SET_ASYNC_MODE: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool async = data.readInt32(); + int result = setAsyncMode(async); reply->writeInt32(result); return NO_ERROR; } case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); - bool async = static_cast<bool>(data.readInt32()); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast<PixelFormat>(data.readInt32()); uint32_t usage = data.readUint32(); int buf = 0; sp<Fence> fence; - int result = dequeueBuffer(&buf, &fence, async, width, height, - format, usage); + int result = dequeueBuffer(&buf, &fence, width, height, format, + usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { @@ -411,7 +435,8 @@ status_t BnGraphicBufferProducer::onTransact( int buf = data.readInt32(); sp<Fence> fence = new Fence(); data.read(*fence.get()); - cancelBuffer(buf, fence); + status_t result = cancelBuffer(buf, fence); + reply->writeInt32(result); return NO_ERROR; } case QUERY: { @@ -457,12 +482,11 @@ status_t BnGraphicBufferProducer::onTransact( } case ALLOCATE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); - bool async = static_cast<bool>(data.readInt32()); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast<PixelFormat>(data.readInt32()); uint32_t usage = data.readUint32(); - allocateBuffers(async, width, height, format, usage); + allocateBuffers(width, height, format, usage); return NO_ERROR; } case ALLOW_ALLOCATION: { @@ -502,7 +526,6 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { + sizeof(scalingMode) + sizeof(transform) + sizeof(stickyTransform) - + sizeof(async) + fence->getFlattenedSize() + surfaceDamage.getFlattenedSize(); } @@ -524,7 +547,6 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); - FlattenableUtils::write(buffer, size, async); status_t result = fence->flatten(buffer, size, fds, count); if (result != NO_ERROR) { return result; @@ -542,8 +564,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) - + sizeof(stickyTransform) - + sizeof(async); + + sizeof(stickyTransform); if (size < minNeeded) { return NO_MEMORY; @@ -556,7 +577,6 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); FlattenableUtils::read(buffer, size, stickyTransform); - FlattenableUtils::read(buffer, size, async); fence = new Fence(); status_t result = fence->unflatten(buffer, size, fds, count); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 78886d5bb6..b4cbf84286 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -353,7 +353,7 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> display = data.readStrongBinder(); sp<IGraphicBufferProducer> producer = interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); - Rect sourceCrop; + Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); uint32_t reqHeight = data.readUint32(); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 00323dc4f2..eafda86917 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -77,6 +77,16 @@ status_t ComposerState::read(const Parcel& input) { } +DisplayState::DisplayState() : + what(0), + layerStack(0), + orientation(eOrientationDefault), + viewport(Rect::EMPTY_RECT), + frame(Rect::EMPTY_RECT), + width(0), + height(0) { +} + status_t DisplayState::write(Parcel& output) const { output.writeStrongBinder(token); output.writeStrongBinder(IInterface::asBinder(surface)); diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index 4b3603ee12..81c05496b2 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -38,7 +38,8 @@ namespace android { Sensor::Sensor() : mHandle(0), mType(0), mMinValue(0), mMaxValue(0), mResolution(0), - mPower(0), mMinDelay(0), mFifoReservedEventCount(0), mFifoMaxEventCount(0), + mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0), + mFifoMaxEventCount(0), mRequiredAppOp(0), mMaxDelay(0), mFlags(0) { } diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 43f9214fc7..bafe947efe 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -132,7 +132,7 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { ALOGV("acquired buffer %#" PRIx64 " from input", bufferItem.mGraphicBuffer->getId()); - status = mInput->detachBuffer(bufferItem.mBuf); + status = mInput->detachBuffer(bufferItem.mSlot); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "detaching buffer from input failed (%d)", status); @@ -144,8 +144,7 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, bufferItem.mDataSpace, bufferItem.mCrop, static_cast<int32_t>(bufferItem.mScalingMode), - bufferItem.mTransform, bufferItem.mIsDroppable, - bufferItem.mFence); + bufferItem.mTransform, bufferItem.mFence); // Attach and queue the buffer to each of the outputs Vector<sp<IGraphicBufferProducer> >::iterator output = mOutputs.begin(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 4b76f9834c..a31876bcc9 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ Surface::Surface( const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), + mCrop(Rect::EMPTY_RECT), mGenerationNumber(0) { // Initialize the ANativeWindow function pointers. @@ -67,7 +68,6 @@ Surface::Surface( mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; mDataSpace = HAL_DATASPACE_UNKNOWN; - mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; @@ -99,8 +99,8 @@ void Surface::setSidebandStream(const sp<NativeHandle>& stream) { void Surface::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; - mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth, - reqHeight, mReqFormat, mReqUsage); + mGraphicBufferProducer->allocateBuffers(reqWidth, reqHeight, + mReqFormat, mReqUsage); } status_t Surface::setGenerationNumber(uint32_t generation) { @@ -184,7 +184,9 @@ int Surface::hook_perform(ANativeWindow* window, int operation, ...) { va_list args; va_start(args, operation); Surface* c = getSelf(window); - return c->perform(operation, args); + int result = c->perform(operation, args); + va_end(args); + return result; } int Surface::setSwapInterval(int interval) { @@ -200,6 +202,7 @@ int Surface::setSwapInterval(int interval) { interval = maxSwapInterval; mSwapIntervalZero = (interval == 0); + mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero); return NO_ERROR; } @@ -210,7 +213,6 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { uint32_t reqWidth; uint32_t reqHeight; - bool swapIntervalZero; PixelFormat reqFormat; uint32_t reqUsage; @@ -220,20 +222,19 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { reqWidth = mReqWidth ? mReqWidth : mUserWidth; reqHeight = mReqHeight ? mReqHeight : mUserHeight; - swapIntervalZero = mSwapIntervalZero; reqFormat = mReqFormat; reqUsage = mReqUsage; } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer int buf = -1; sp<Fence> fence; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, reqFormat, reqUsage); if (result < 0) { - ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" - "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat, - reqUsage, result); + ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer" + "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat, + reqUsage, result); return result; } @@ -332,14 +333,14 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { // Make sure the crop rectangle is entirely inside the buffer. - Rect crop; + Rect crop(Rect::EMPTY_RECT); mCrop.intersect(Rect(buffer->width, buffer->height), &crop); sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - mSwapIntervalZero, fence, mStickyTransform); + fence, mStickyTransform); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); @@ -779,7 +780,7 @@ int Surface::setCrop(Rect const* rect) { ATRACE_CALL(); - Rect realRect; + Rect realRect(Rect::EMPTY_RECT); if (rect == NULL || rect->isEmpty()) { realRect.clear(); } else { @@ -800,9 +801,54 @@ int Surface::setBufferCount(int bufferCount) ALOGV("Surface::setBufferCount"); Mutex::Autolock lock(mMutex); - status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); + status_t err = NO_ERROR; + if (bufferCount == 0) { + err = mGraphicBufferProducer->setMaxDequeuedBufferCount(1); + } else { + int minUndequeuedBuffers = 0; + err = mGraphicBufferProducer->query( + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers); + if (err == NO_ERROR) { + err = mGraphicBufferProducer->setMaxDequeuedBufferCount( + bufferCount - minUndequeuedBuffers); + } + } + + if (err == NO_ERROR) { + freeAllBuffers(); + } + ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", - bufferCount, strerror(-err)); + bufferCount, strerror(-err)); + + return err; +} + +int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) { + ATRACE_CALL(); + ALOGV("Surface::setMaxDequeuedBufferCount"); + Mutex::Autolock lock(mMutex); + + status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount( + maxDequeuedBuffers); + ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) " + "returned %s", maxDequeuedBuffers, strerror(-err)); + + if (err == NO_ERROR) { + freeAllBuffers(); + } + + return err; +} + +int Surface::setAsyncMode(bool async) { + ATRACE_CALL(); + ALOGV("Surface::setAsyncMode"); + Mutex::Autolock lock(mMutex); + + status_t err = mGraphicBufferProducer->setAsyncMode(async); + ALOGE_IF(err, "IGraphicBufferProducer::setAsyncMode(%d) returned %s", + async, strerror(-err)); if (err == NO_ERROR) { freeAllBuffers(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6ad47d8b71..9167a0cc08 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -310,9 +310,9 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - if (mask & layer_state_t::eLayerOpaque || - mask & layer_state_t::eLayerHidden || - mask & layer_state_t::eLayerSecure) { + if ((mask & layer_state_t::eLayerOpaque) || + (mask & layer_state_t::eLayerHidden) || + (mask & layer_state_t::eLayerSecure)) { s->what |= layer_state_t::eFlagsChanged; } s->flags &= ~mask; diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 1a54875446..5244d82831 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -113,7 +113,7 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -125,7 +125,7 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); BufferItem item; @@ -145,19 +145,19 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { IGraphicBufferProducer::QueueBufferOutput qbo; mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); - mProducer->setBufferCount(4); + mProducer->setMaxDequeuedBufferCount(3); int slot; sp<Fence> fence; sp<GraphicBuffer> buf; IGraphicBufferProducer::QueueBufferInput qbi(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0, + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); @@ -165,7 +165,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0, + mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); @@ -189,6 +189,9 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount( BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100)); + + EXPECT_EQ(OK, mConsumer->setMaxBufferCount(5)); + EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(5)); } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { @@ -206,6 +209,28 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { BufferQueue::MAX_MAX_ACQUIRED_BUFFERS)); } +TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + + // Test single buffer mode + EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); +} + +TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + + EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0)); + EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount( + BufferQueue::NUM_BUFFER_SLOTS + 1)); + + EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(5)); + EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(3)); +} + TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); @@ -223,7 +248,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -247,7 +272,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output)); BufferItem item; @@ -272,12 +297,12 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(-1)); // Index too low @@ -288,8 +313,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); - ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); - ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mBuf)); // Not acquired + ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot)); + ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mSlot)); // Not acquired uint32_t* dataIn; ASSERT_EQ(OK, item.mGraphicBuffer->lock( @@ -308,7 +333,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { EGL_NO_SYNC_KHR, Fence::NO_FENCE)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -331,7 +356,7 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -343,12 +368,12 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); - ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); + ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot)); int newSlot; ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, item.mGraphicBuffer)); @@ -380,13 +405,13 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { sp<GraphicBuffer> buffer; // This should return an error since it would require an allocation ASSERT_EQ(OK, mProducer->allowAllocation(false)); - ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); // This should succeed, now that we've lifted the prohibition ASSERT_EQ(OK, mProducer->allowAllocation(true)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); // Release the previous buffer back to the BufferQueue @@ -394,7 +419,7 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { // This should fail since we're requesting a different size ASSERT_EQ(OK, mProducer->allowAllocation(false)); - ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } @@ -412,7 +437,7 @@ TEST_F(BufferQueueTest, TestGenerationNumbers) { int slot; sp<Fence> fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); sp<GraphicBuffer> buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 2dc9cccb56..289cc74039 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -444,19 +444,14 @@ void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) { } } -void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, - const android_native_rect_t& rect); - -void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride); - -void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, - uint8_t g, uint8_t b, uint8_t a); - // Configures the ANativeWindow producer-side interface based on test parameters void configureANW(const sp<ANativeWindow>& anw, const CpuConsumerTestParams& params, int maxBufferSlack) { status_t err; + err = native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU); + ASSERT_NO_ERROR(err, "connect error: "); + err = native_window_set_buffers_dimensions(anw.get(), params.width, params.height); ASSERT_NO_ERROR(err, "set_buffers_dimensions error: "); diff --git a/libs/gui/tests/GLTest.h b/libs/gui/tests/GLTest.h index d3c4a951f3..f0d27a8a34 100644 --- a/libs/gui/tests/GLTest.h +++ b/libs/gui/tests/GLTest.h @@ -35,9 +35,11 @@ public: protected: GLTest() : + mDisplaySecs(0), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), - mEglContext(EGL_NO_CONTEXT) { + mEglContext(EGL_NO_CONTEXT), + mGlConfig(NULL) { } virtual void SetUp(); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index 4ef9a69844..882b14cb13 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -61,7 +61,6 @@ namespace { const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; - const bool QUEUE_BUFFER_INPUT_ASYNC = false; const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; }; // namespace anonymous @@ -131,7 +130,6 @@ protected: crop = QUEUE_BUFFER_INPUT_RECT; scalingMode = QUEUE_BUFFER_INPUT_SCALING_MODE; transform = QUEUE_BUFFER_INPUT_TRANSFORM; - async = QUEUE_BUFFER_INPUT_ASYNC; fence = QUEUE_BUFFER_INPUT_FENCE; } @@ -143,7 +141,6 @@ protected: crop, scalingMode, transform, - async, fence); } @@ -177,11 +174,6 @@ protected: return *this; } - QueueBufferInputBuilder& setAsync(bool async) { - this->async = async; - return *this; - } - QueueBufferInputBuilder& setFence(sp<Fence> fence) { this->fence = fence; return *this; @@ -194,7 +186,6 @@ protected: Rect crop; int scalingMode; uint32_t transform; - int async; sp<Fence> fence; }; // struct QueueBufferInputBuilder @@ -204,8 +195,28 @@ protected: sp<Fence> fence; }; - status_t dequeueBuffer(bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) { - return mProducer->dequeueBuffer(&result->slot, &result->fence, async, w, h, format, usage); + status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) { + return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage); + } + + void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence, + sp<GraphicBuffer> *buffer) + { + ASSERT_TRUE(slot != NULL); + ASSERT_TRUE(fence != NULL); + ASSERT_TRUE(buffer != NULL); + + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); + + EXPECT_LE(0, *slot); + EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot); + + // Request the buffer (pre-requisite for queueing) + ASSERT_OK(mProducer->requestBuffer(*slot, buffer)); } private: // hide from test body @@ -334,12 +345,11 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - // XX: OK to assume first call returns this flag or not? Not really documented. - ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - QUEUE_BUFFER_INPUT_ASYNC, + + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS)); + TEST_PRODUCER_USAGE_BITS))); EXPECT_LE(0, dequeuedSlot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot); @@ -400,11 +410,10 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - QUEUE_BUFFER_INPUT_ASYNC, + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS)); + TEST_PRODUCER_USAGE_BITS))); // Slot was enqueued without requesting a buffer { @@ -470,30 +479,28 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - QUEUE_BUFFER_INPUT_ASYNC, + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS)); + TEST_PRODUCER_USAGE_BITS))); // No return code, but at least test that it doesn't blow up... // TODO: add a return code mProducer->cancelBuffer(dequeuedSlot, dequeuedFence); } -TEST_F(IGraphicBufferProducerTest, SetBufferCount_Succeeds) { - - // The producer does not wish to set a buffer count - EXPECT_OK(mProducer->setBufferCount(0)) << "bufferCount: " << 0; - // TODO: how to test "0" buffer count? - - int minBuffers; - ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers)); +TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + int minUndequeuedBuffers; + ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); - // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1 - minBuffers++; + const int minBuffers = 1; + const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers; - ASSERT_OK(mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers; + ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false; + ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; std::vector<DequeueBufferResult> dequeueList; @@ -501,72 +508,217 @@ TEST_F(IGraphicBufferProducerTest, SetBufferCount_Succeeds) { for (int i = 0; i < minBuffers; ++i) { DequeueBufferResult result; - EXPECT_LE(OK, - dequeueBuffer(QUEUE_BUFFER_INPUT_ASYNC, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS, &result)) + EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS, &result))) << "iteration: " << i << ", slot: " << result.slot; dequeueList.push_back(result); } // Cancel every buffer, so we can set buffer count again - for (int i = 0; i < minBuffers; ++i) { - DequeueBufferResult& result = dequeueList[i]; + for (auto& result : dequeueList) { mProducer->cancelBuffer(result.slot, result.fence); } - ASSERT_OK(mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS)); + ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers)); - // Should now be able to dequeue up to NUM_BUFFER_SLOTS times - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; ++i) { + // Should now be able to dequeue up to maxBuffers times + for (int i = 0; i < maxBuffers; ++i) { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - EXPECT_LE(OK, - mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - QUEUE_BUFFER_INPUT_ASYNC, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS)) + EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, + DEFAULT_WIDTH, DEFAULT_HEIGHT, + DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS))) << "iteration: " << i << ", slot: " << dequeuedSlot; } } -TEST_F(IGraphicBufferProducerTest, SetBufferCount_Fails) { - int minBuffers; - ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers)); +TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + int minUndequeuedBuffers; + ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers)); - // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1 - minBuffers++; + const int minBuffers = 1; + const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers; + ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false; // Buffer count was out of range - EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(-1)) << "bufferCount: " << -1; - EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers - 1)) << "bufferCount: " << minBuffers - 1; - EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS + 1)) - << "bufferCount: " << BufferQueue::NUM_BUFFER_SLOTS + 1; + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0)) + << "bufferCount: " << 0; + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1)) + << "bufferCount: " << maxBuffers + 1; - // Pre-requisite to fail out a valid setBufferCount call + // Prerequisite to fail out a valid setBufferCount call { int dequeuedSlot = -1; sp<Fence> dequeuedFence; - ASSERT_LE(OK, - mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, - QUEUE_BUFFER_INPUT_ASYNC, - DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS)) + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, + DEFAULT_WIDTH, DEFAULT_HEIGHT, + DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot; } // Client has one or more buffers dequeued - EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers; + EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; // Abandon buffer queue ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers; + EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; + +} + +TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { + ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1; + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true; + ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1)) << "maxDequeue: " << 1; + + int dequeuedSlot = -1; + sp<Fence> dequeuedFence; + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + sp<GraphicBuffer> dequeuedBuffer; + + // Should now be able to queue/dequeue as many buffers as we want without + // blocking + for (int i = 0; i < 5; ++i) { + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, + DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS))) << "slot : " << dequeuedSlot; + ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); + ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); + } +} + +TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + // Prerequisite to fail out a valid setBufferCount call + { + int dequeuedSlot = -1; + sp<Fence> dequeuedFence; + + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, + DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, + TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot; + } + + // Abandon buffer queue + ASSERT_OK(mConsumer->consumerDisconnect()); + + // Fail because the buffer queue was abandoned + EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " + << false; +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_dequeueBuffer) { + int slot = -1; + sp<Fence> fence; + + ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)); +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_detachNextBuffer) { + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_requestBuffer) { + ASSERT_NO_FATAL_FAILURE(ConnectProducer()); + + int slot = -1; + sp<Fence> fence; + + ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & + (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); + + EXPECT_LE(0, slot); + EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot); + + ASSERT_OK(mProducer->disconnect(TEST_API)); + + sp<GraphicBuffer> buffer; + + ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer)); +} + + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_detachBuffer) { + int slot = -1; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + setupDequeueRequestBuffer(&slot, &fence, &buffer); + + ASSERT_OK(mProducer->disconnect(TEST_API)); + + ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_queueBuffer) { + int slot = -1; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + setupDequeueRequestBuffer(&slot, &fence, &buffer); + + ASSERT_OK(mProducer->disconnect(TEST_API)); + + // A generic "valid" input + IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); + IGraphicBufferProducer::QueueBufferOutput output; + + ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_cancelBuffer) { + int slot = -1; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + setupDequeueRequestBuffer(&slot, &fence, &buffer); + + ASSERT_OK(mProducer->disconnect(TEST_API)); + + ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence)); +} + +TEST_F(IGraphicBufferProducerTest, + DisconnectedProducerReturnsError_attachBuffer) { + int slot = -1; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + setupDequeueRequestBuffer(&slot, &fence, &buffer); + + ASSERT_OK(mProducer->detachBuffer(slot)); + + ASSERT_OK(mProducer->disconnect(TEST_API)); + ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); } } // namespace android diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 00cc39dc06..c7ce263e5a 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -103,7 +103,7 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); @@ -114,9 +114,8 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, - HAL_DATASPACE_UNKNOWN, - Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, - Fence::NO_FENCE); + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); BufferItem item; @@ -128,11 +127,11 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); - ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, + ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(1, allocator->getAllocCount()); @@ -170,7 +169,7 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); @@ -181,9 +180,8 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, - HAL_DATASPACE_UNKNOWN, - Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, - Fence::NO_FENCE); + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); for (int output = 0; output < NUM_OUTPUTS; ++output) { @@ -196,13 +194,13 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); - ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mBuf, + ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(1, allocator->getAllocCount()); @@ -231,7 +229,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); @@ -239,14 +237,13 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { outputConsumer->consumerDisconnect(); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, - HAL_DATASPACE_UNKNOWN, - Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, - Fence::NO_FENCE); + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); // Input should be abandoned - ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, - 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); + ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, + GRALLOC_USAGE_SW_WRITE_OFTEN)); } } // namespace android diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 1a50b2480d..2356f54c89 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -37,7 +37,8 @@ protected: SurfaceTextureClientTest(): mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), - mEglContext(EGL_NO_CONTEXT) { + mEglContext(EGL_NO_CONTEXT), + mEglConfig(NULL) { } virtual void SetUp() { @@ -215,6 +216,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { } TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); @@ -224,6 +226,7 @@ TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { } TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); @@ -235,6 +238,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { } TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); @@ -246,6 +250,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { } TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); @@ -257,6 +262,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); @@ -275,6 +281,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); @@ -292,6 +299,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); sp<GLConsumer> st(mST); ANativeWindowBuffer* buf; EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); @@ -304,6 +312,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { ANativeWindowBuffer* buf[2]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -324,6 +333,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { ANativeWindowBuffer* buf[2]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -350,6 +360,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); @@ -373,6 +384,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -393,6 +405,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -413,8 +426,8 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); - ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); @@ -438,6 +451,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { android_native_buffer_t* buf[3]; android_native_buffer_t* firstBuf; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); @@ -457,6 +471,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. @@ -482,6 +497,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { } TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); android_native_rect_t rect = {-2, -13, 40, 18}; native_window_set_crop(mANW.get(), &rect); @@ -536,6 +552,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { }; android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -559,6 +576,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) { android_native_buffer_t* buf[3]; float mtx[16] = {}; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); @@ -589,6 +607,7 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) { TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) { android_native_buffer_t* buf[3]; float mtx[16] = {}; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); @@ -638,6 +657,7 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi crop.right = 5; crop.bottom = 5; + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8)); ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index c243fc047e..0606839506 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -27,6 +27,8 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { const int texWidth = 64; const int texHeight = 64; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp index 9776733efd..c4d0aaa4bb 100644 --- a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp @@ -31,6 +31,8 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; + SetUpWindowAndContext(); + runProducerThread(new PT()); mFC->waitForFrame(); @@ -50,6 +52,8 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; + SetUpWindowAndContext(); + runProducerThread(new PT()); mFC->waitForFrame(); @@ -75,6 +79,8 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; + SetUpWindowAndContext(); + runProducerThread(new PT()); for (int i = 0; i < NUM_ITERATIONS; i++) { @@ -104,6 +110,8 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; + SetUpWindowAndContext(); + runProducerThread(new PT()); for (int i = 0; i < NUM_ITERATIONS; i++) { @@ -134,7 +142,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; - ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); + SetUpWindowAndContext(); runProducerThread(new PT()); diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h index 5a2eff3951..5d43a48898 100644 --- a/libs/gui/tests/SurfaceTextureGLToGL.h +++ b/libs/gui/tests/SurfaceTextureGLToGL.h @@ -34,7 +34,9 @@ protected: virtual void SetUp() { SurfaceTextureGLTest::SetUp(); + } + void SetUpWindowAndContext() { mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mANW.get(), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp index 6edbfb87a6..c28b4d141c 100644 --- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp @@ -29,8 +29,11 @@ TEST_F(SurfaceTextureGLToGLTest, TransformHintGetsRespected) { mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); // This test requires 3 buffers to avoid deadlock because we're - // both producer and consumer, and only using one thread. - mST->setDefaultMaxBufferCount(3); + // both producer and consumer, and only using one thread. Set max dequeued + // to 2, and max acquired already defaults to 1. + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); + + SetUpWindowAndContext(); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, @@ -81,7 +84,10 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) { mST->setDefaultBufferSize(texWidth, texHeight); // This test requires 3 buffers to complete run on a single thread. - mST->setDefaultMaxBufferCount(3); + // Set max dequeued to 2, and max acquired already defaults to 1. + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); + + SetUpWindowAndContext(); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, @@ -150,6 +156,7 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) { } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { + SetUpWindowAndContext(); sp<GraphicBuffer> buffers[2]; // This test requires async mode to run on a single thread. @@ -195,6 +202,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { + SetUpWindowAndContext(); sp<GraphicBuffer> buffers[3]; // This test requires async mode to run on a single thread. @@ -252,6 +260,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { } TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) { + SetUpWindowAndContext(); sp<GraphicBuffer> buffer; EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, @@ -289,6 +298,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) } TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) { + SetUpWindowAndContext(); sp<GraphicBuffer> buffer; EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, @@ -330,7 +340,10 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) { enum { texHeight = 64 }; // This test requires 3 buffers to complete run on a single thread. - mST->setDefaultMaxBufferCount(3); + // Set max dequeued to 2, and max acquired already defaults to 1. + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); + + SetUpWindowAndContext(); // Set the user buffer size. native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight); @@ -387,7 +400,10 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedUserSizedGLFilledBuffer) enum { texHeight = 16 }; // This test requires 3 buffers to complete run on a single thread. - mST->setDefaultMaxBufferCount(3); + // Set max dequeued to 2, and max acquired already defaults to 1. + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); + + SetUpWindowAndContext(); // Set the transform hint. mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); @@ -448,7 +464,10 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) { enum { texHeight = 16 }; // This test requires 3 buffers to complete run on a single thread. - mST->setDefaultMaxBufferCount(3); + // Set max dequeued to 2, and max acquired already defaults to 1. + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); + + SetUpWindowAndContext(); // Set the transform hint. mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index fad133fcb8..1a904b57fd 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -28,6 +28,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { const int texWidth = 64; const int texHeight = 66; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -76,6 +78,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { const int texWidth = 64; const int texHeight = 64; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -124,6 +128,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { const int texWidth = 64; const int texHeight = 66; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -190,7 +196,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { enum { texHeight = 16 }; enum { numFrames = 1024 }; - ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -334,6 +341,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) { const int texWidth = 64; const int texHeight = 66; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -378,6 +387,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), @@ -436,7 +447,10 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { virtual bool threadLoop() { ANativeWindowBuffer* anb; - native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL); + if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) != + NO_ERROR) { + return false; + } for (int numFrames =0 ; numFrames < 2; numFrames ++) { @@ -453,7 +467,10 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { } } - native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL); + if (native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU) + != NO_ERROR) { + return false; + } return false; } @@ -487,7 +504,7 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { // attempt to release a buffer that it does not owned TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), - NATIVE_WINDOW_API_EGL)); + NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer *anb; @@ -501,9 +518,9 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { EXPECT_EQ(OK,mST->updateTexImage()); ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(), - NATIVE_WINDOW_API_EGL)); + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_api_connect(mANW.get(), - NATIVE_WINDOW_API_EGL)); + NATIVE_WINDOW_API_CPU)); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); @@ -513,7 +530,7 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { EXPECT_EQ(OK,mST->updateTexImage()); ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(), - NATIVE_WINDOW_API_EGL)); + NATIVE_WINDOW_API_CPU)); } TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { @@ -615,6 +632,11 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { Mutex::Autolock lock(mMutex); ANativeWindowBuffer* anb; + if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) != + NO_ERROR) { + return false; + } + // Frame 1 if (native_window_dequeue_buffer_and_wait(mANW.get(), &anb) != NO_ERROR) { @@ -658,8 +680,6 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { Mutex mMutex; }; - ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); - sp<Thread> pt(new ProducerThread(mANW)); pt->run(); @@ -681,6 +701,9 @@ TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { int texHeight = 16; ANativeWindowBuffer* anb; + ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), + NATIVE_WINDOW_API_CPU)); + GLint maxTextureSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL.h b/libs/gui/tests/SurfaceTextureMultiContextGL.h index 7934bbccfd..3cca035f27 100644 --- a/libs/gui/tests/SurfaceTextureMultiContextGL.h +++ b/libs/gui/tests/SurfaceTextureMultiContextGL.h @@ -27,7 +27,8 @@ protected: enum { THIRD_TEX_ID = 456 }; SurfaceTextureMultiContextGLTest(): - mSecondEglContext(EGL_NO_CONTEXT) { + mSecondEglContext(EGL_NO_CONTEXT), + mThirdEglContext(EGL_NO_CONTEXT) { } virtual void SetUp() { diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp index 1cd101e199..5b02dcf539 100644 --- a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp @@ -26,6 +26,7 @@ namespace android { TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -40,6 +41,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) { } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -55,6 +57,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) { TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceedsAfterProducerDisconnect) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -70,6 +73,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -82,6 +86,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) { } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -96,6 +101,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) { } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -112,6 +118,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) { } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -128,6 +135,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) { } TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. @@ -139,6 +147,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) { } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -169,6 +178,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) { TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsAfterProducerDisconnect) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -200,6 +210,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsBeforeUpdateTexImage) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. @@ -230,6 +241,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -247,6 +259,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) { } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -259,6 +272,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) { TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttachedBeforeUpdateTexImage) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Attempt to attach to the primary context. @@ -266,6 +280,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -285,6 +300,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) { } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. @@ -323,6 +339,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) { TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwiceBeforeUpdateTexImage) { + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. @@ -361,7 +378,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageSucceedsForBufferConsumedBeforeDetach) { - ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); // produce two frames and consume them both on the primary context ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); @@ -388,7 +405,7 @@ TEST_F(SurfaceTextureMultiContextGLTest, TEST_F(SurfaceTextureMultiContextGLTest, AttachAfterDisplayTerminatedSucceeds) { - ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); + ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); // produce two frames and consume them both on the primary context ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3f495f8dee..6f0104a25a 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -100,6 +100,8 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 64, 64, 0, 0x7fffffff, false)); + ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), + NATIVE_WINDOW_API_CPU)); // Set the PROTECTED usage bit and verify that the screenshot fails. Note // that we need to dequeue a buffer in order for it to actually get // allocated in SurfaceFlinger. @@ -190,6 +192,8 @@ TEST_F(SurfaceTest, SettingGenerationNumber) { // Allocate a buffer with a generation number of 0 ANativeWindowBuffer* buffer; int fenceFd; + ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), + NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd)); diff --git a/libs/gui/tests/TextureRenderer.cpp b/libs/gui/tests/TextureRenderer.cpp index 90951b3b20..e822e6eaf8 100644 --- a/libs/gui/tests/TextureRenderer.cpp +++ b/libs/gui/tests/TextureRenderer.cpp @@ -28,7 +28,8 @@ namespace android { TextureRenderer::TextureRenderer(GLuint texName, - const sp<GLConsumer>& st) : mTexName(texName), mST(st) { + const sp<GLConsumer>& st) : mTexName(texName), mST(st), mPgm(0), + mPositionHandle(-1), mTexSamplerHandle(-1), mTexMatrixHandle(-1) { } void TextureRenderer::SetUp() { diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 3ead25cfe8..59db157506 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -74,7 +74,7 @@ private: */ FramebufferNativeWindow::FramebufferNativeWindow() - : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) + : BASE(), fbDev(0), grDev(0), mCurrentBufferIndex(0), mUpdateOnDemand(false) { hw_module_t const* module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index e55db30f8e..4fe0946989 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -43,7 +43,7 @@ static uint64_t getUniqueId() { GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()) + mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = height = @@ -56,7 +56,7 @@ GraphicBuffer::GraphicBuffer() GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()) + mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = height = @@ -72,7 +72,7 @@ GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, native_handle_t* inHandle, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mId(getUniqueId()) + mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = static_cast<int>(inWidth); height = static_cast<int>(inHeight); @@ -85,7 +85,8 @@ GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()) + mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()), + mGenerationNumber(0) { width = buffer->width; height = buffer->height; @@ -112,6 +113,7 @@ void GraphicBuffer::free_handle() GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); } + handle = NULL; mWrappedBuffer = 0; } diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index dcce21f15a..99cbedc2ff 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -20,6 +20,7 @@ namespace android { const Rect Rect::INVALID_RECT{0, 0, -1, -1}; +const Rect Rect::EMPTY_RECT{0, 0, 0, 0}; static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; @@ -110,7 +111,7 @@ Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) const { } Rect Rect::reduce(const Rect& exclude) const { - Rect result; + Rect result(Rect::EMPTY_RECT); uint32_t mask = 0; mask |= (exclude.left > left) ? 1 : 0; diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index a3558bd5c2..ac379901c8 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -798,7 +798,7 @@ status_t Region::unflatten(void const* buffer, size_t size) { Region result; result.mStorage.clear(); for (size_t r = 0; r < numRects; ++r) { - Rect rect; + Rect rect(Rect::EMPTY_RECT); status_t status = rect.unflatten(buffer, size); if (status != NO_ERROR) { return status; diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk index b82817545b..0a7fc27ade 100644 --- a/services/inputflinger/host/Android.mk +++ b/services/inputflinger/host/Android.mk @@ -58,5 +58,6 @@ LOCAL_SHARED_LIBRARIES := \ libutils LOCAL_MODULE := inputflinger +LOCAL_INIT_RC := inputflinger.rc include $(BUILD_EXECUTABLE) diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 630a596b7b..bd11d5620b 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#include <functional> #include <stdint.h> #include <sys/types.h> +#include <unordered_map> +#include <vector> #define LOG_TAG "InputDriver" @@ -25,11 +28,64 @@ #include "InputHost.h" #include <hardware/input.h> +#include <input/InputDevice.h> #include <utils/Log.h> +#include <utils/PropertyMap.h> #include <utils/String8.h> #define INDENT2 " " +struct input_property_map { + android::PropertyMap* propertyMap; +}; + +struct input_property { + android::String8 key; + android::String8 value; +}; + +struct input_device_identifier { + const char* name; + const char* uniqueId; + input_bus_t bus; + int32_t vendorId; + int32_t productId; + int32_t version; +}; + +struct input_device_definition { + std::vector<input_report_definition*> reportDefs; +}; + +struct input_device_handle { + input_device_identifier_t* id; + input_device_definition_t* def; +}; + +struct input_int_usage { + input_usage_t usage; + int32_t min; + int32_t max; + float resolution; +}; + +struct input_collection { + int32_t arity; + std::vector<input_int_usage> intUsages; + std::vector<input_usage_t> boolUsages; +}; + +struct InputCollectionIdHasher { + std::size_t operator()(const input_collection_id& id) const { + return std::hash<int>()(static_cast<int>(id)); + } +}; + +struct input_report_definition { + std::unordered_map<input_collection_id_t, input_collection, InputCollectionIdHasher> collections; +}; + + namespace android { static input_host_callbacks_t kCallbacks = { @@ -37,6 +93,7 @@ static input_host_callbacks_t kCallbacks = { .create_device_definition = create_device_definition, .create_input_report_definition = create_input_report_definition, .create_output_report_definition = create_output_report_definition, + .free_report_definition = free_report_definition, .input_device_definition_add_report = input_device_definition_add_report, .input_report_definition_add_collection = input_report_definition_add_collection, .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int, @@ -61,86 +118,295 @@ InputDriver::InputDriver(const char* name) : mName(String8(name)) { mHal = reinterpret_cast<const input_module_t*>(module); } -void InputDriver::init(InputHostInterface* host) { - mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks); +void InputDriver::init() { + mHal->init(mHal, static_cast<input_host_t*>(this), kCallbacks); +} + +input_device_identifier_t* InputDriver::createDeviceIdentifier( + const char* name, int32_t productId, int32_t vendorId, + input_bus_t bus, const char* uniqueId) { + auto identifier = new ::input_device_identifier { + .name = name, + .productId = productId, + .vendorId = vendorId, + .bus = bus, + .uniqueId = uniqueId, + }; + // TODO: store this identifier somewhere + return identifier; +} + +input_device_definition_t* InputDriver::createDeviceDefinition() { + return new ::input_device_definition; +} + +input_report_definition_t* InputDriver::createInputReportDefinition() { + return new ::input_report_definition; +} + +input_report_definition_t* InputDriver::createOutputReportDefinition() { + return new ::input_report_definition; +} + +void InputDriver::freeReportDefinition(input_report_definition_t* reportDef) { + delete reportDef; +} + +void InputDriver::inputDeviceDefinitionAddReport(input_device_definition_t* d, + input_report_definition_t* r) { + d->reportDefs.push_back(r); +} + +void InputDriver::inputReportDefinitionAddCollection(input_report_definition_t* report, + input_collection_id_t id, int32_t arity) { + report->collections[id] = {.arity = arity}; +} + +void InputDriver::inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, + input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, + float resolution) { + if (report->collections.find(id) != report->collections.end()) { + report->collections[id].intUsages.push_back({ + .usage = usage, .min = min, .max = max, .resolution = resolution}); + } +} + +void InputDriver::inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, + input_collection_id_t id, input_usage_t* usage, size_t usageCount) { + if (report->collections.find(id) != report->collections.end()) { + for (size_t i = 0; i < usageCount; ++i) { + report->collections[id].boolUsages.push_back(usage[i]); + } + } +} + +input_device_handle_t* InputDriver::registerDevice(input_device_identifier_t* id, + input_device_definition_t* d) { + ALOGD("Registering device %s with %zu input reports", id->name, d->reportDefs.size()); + // TODO: save this device handle + return new input_device_handle{ .id = id, .def = d }; +} + +void InputDriver::unregisterDevice(input_device_handle_t* handle) { + delete handle; +} + +input_report_t* InputDriver::inputAllocateReport(input_report_definition_t* r) { + ALOGD("Allocating input report for definition %p", r); + return nullptr; +} + +void InputDriver::inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, + input_usage_t usage, int32_t value, int32_t arity_index) { +} + +void InputDriver::inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, + input_usage_t usage, bool value, int32_t arity_index) { +} + +void InputDriver::reportEvent(input_device_handle_t* d, input_report_t* report) { + ALOGD("report_event %p for handle %p", report, d); +} + +input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identifier_t* id) { + InputDeviceIdentifier idi; + idi.name = id->name; + idi.uniqueId = id->uniqueId; + idi.bus = id->bus; + idi.vendor = id->vendorId; + idi.product = id->productId; + idi.version = id->version; + + String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( + idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); + if (configFile.isEmpty()) { + ALOGD("No input device configuration file found for device '%s'.", + idi.name.string()); + } else { + auto propMap = new input_property_map_t(); + status_t status = PropertyMap::load(configFile, &propMap->propertyMap); + if (status) { + ALOGE("Error loading input device configuration file for device '%s'. " + "Using default configuration.", + idi.name.string()); + delete propMap; + return nullptr; + } + return propMap; + } + return nullptr; +} + +input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, + const char* key) { + String8 keyString(key); + if (map != nullptr) { + if (map->propertyMap->hasProperty(keyString)) { + auto prop = new input_property_t(); + if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { + delete prop; + return nullptr; + } + prop->key = keyString; + return prop; + } + } + return nullptr; +} + +const char* InputDriver::inputGetPropertyKey(input_property_t* property) { + if (property != nullptr) { + return property->key.string(); + } + return nullptr; +} + +const char* InputDriver::inputGetPropertyValue(input_property_t* property) { + if (property != nullptr) { + return property->value.string(); + } + return nullptr; +} + +void InputDriver::inputFreeDeviceProperty(input_property_t* property) { + if (property != nullptr) { + delete property; + } +} + +void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) { + if (map != nullptr) { + delete map->propertyMap; + delete map; + } } void InputDriver::dump(String8& result) { result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); } +} // namespace android // HAL wrapper functions -input_device_identifier_t* create_device_identifier(input_host_t* host, +namespace android { + +::input_device_identifier_t* create_device_identifier(input_host_t* host, const char* name, int32_t product_id, int32_t vendor_id, input_bus_t bus, const char* unique_id) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->createDeviceIdentifier(name, product_id, vendor_id, bus, unique_id); } input_device_definition_t* create_device_definition(input_host_t* host) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->createDeviceDefinition(); } input_report_definition_t* create_input_report_definition(input_host_t* host) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->createInputReportDefinition(); } input_report_definition_t* create_output_report_definition(input_host_t* host) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->createOutputReportDefinition(); +} + +void free_report_definition(input_host_t* host, input_report_definition_t* report_def) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->freeReportDefinition(report_def); } void input_device_definition_add_report(input_host_t* host, - input_device_definition_t* d, input_report_definition_t* r) { } + input_device_definition_t* d, input_report_definition_t* r) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputDeviceDefinitionAddReport(d, r); +} void input_report_definition_add_collection(input_host_t* host, - input_report_definition_t* report, input_collection_id_t id, int32_t arity) { } + input_report_definition_t* report, input_collection_id_t id, int32_t arity) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputReportDefinitionAddCollection(report, id, arity); +} void input_report_definition_declare_usage_int(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, - input_usage_t usage, int32_t min, int32_t max, float resolution) { } + input_usage_t usage, int32_t min, int32_t max, float resolution) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputReportDefinitionDeclareUsageInt(report, id, usage, min, max, resolution); +} void input_report_definition_declare_usages_bool(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, - input_usage_t* usage, size_t usage_count) { } - + input_usage_t* usage, size_t usage_count) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputReportDefinitionDeclareUsagesBool(report, id, usage, usage_count); +} input_device_handle_t* register_device(input_host_t* host, input_device_identifier_t* id, input_device_definition_t* d) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->registerDevice(id, d); +} + +void unregister_device(input_host_t* host, input_device_handle_t* handle) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->unregisterDevice(handle); } input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->inputAllocateReport(r); } + void input_report_set_usage_int(input_host_t* host, input_report_t* r, - input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { } + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputReportSetUsageInt(r, id, usage, value, arity_index); +} void input_report_set_usage_bool(input_host_t* host, input_report_t* r, - input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { } + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputReportSetUsageBool(r, id, usage, value, arity_index); +} -void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { } +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->reportEvent(d, report); +} input_property_map_t* input_get_device_property_map(input_host_t* host, input_device_identifier_t* id) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->inputGetDevicePropertyMap(id); } input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, const char* key) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->inputGetDeviceProperty(map, key); } const char* input_get_property_key(input_host_t* host, input_property_t* property) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->inputGetPropertyKey(property); } const char* input_get_property_value(input_host_t* host, input_property_t* property) { - return nullptr; + auto driver = static_cast<InputDriverInterface*>(host); + return driver->inputGetPropertyValue(property); } -void input_free_device_property(input_host_t* host, input_property_t* property) { } +void input_free_device_property(input_host_t* host, input_property_t* property) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputFreeDeviceProperty(property); +} -void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { } +void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { + auto driver = static_cast<InputDriverInterface*>(host); + driver->inputFreeDevicePropertyMap(map); +} } // namespace android diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h index 7734ac2962..8d5a31e0c5 100644 --- a/services/inputflinger/host/InputDriver.h +++ b/services/inputflinger/host/InputDriver.h @@ -26,17 +26,56 @@ #include <utils/RefBase.h> #include <utils/String8.h> -namespace android { +// Declare a concrete type for the HAL +struct input_host { +}; -class InputHostInterface; +namespace android { -class InputDriverInterface : public virtual RefBase { +class InputDriverInterface : public input_host_t, public virtual RefBase { protected: InputDriverInterface() = default; virtual ~InputDriverInterface() = default; public: - virtual void init(InputHostInterface* host) = 0; + virtual void init() = 0; + + virtual input_device_identifier_t* createDeviceIdentifier( + const char* name, int32_t productId, int32_t vendorId, + input_bus_t bus, const char* uniqueId) = 0; + virtual input_device_definition_t* createDeviceDefinition() = 0; + virtual input_report_definition_t* createInputReportDefinition() = 0; + virtual input_report_definition_t* createOutputReportDefinition() = 0; + virtual void freeReportDefinition(input_report_definition_t* reportDef) = 0; + + virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d, + input_report_definition_t* r) = 0; + virtual void inputReportDefinitionAddCollection(input_report_definition_t* report, + input_collection_id_t id, int32_t arity) = 0; + virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, + input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, + float resolution) = 0; + virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, + input_collection_id_t id, input_usage_t* usage, size_t usageCount) = 0; + + virtual input_device_handle_t* registerDevice(input_device_identifier_t* id, + input_device_definition_t* d) = 0; + virtual void unregisterDevice(input_device_handle_t* handle) = 0; + + virtual input_report_t* inputAllocateReport(input_report_definition_t* r) = 0; + virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, + input_usage_t usage, int32_t value, int32_t arity_index) = 0; + virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, + input_usage_t usage, bool value, int32_t arity_index) = 0; + virtual void reportEvent(input_device_handle_t* d, input_report_t* report) = 0; + + virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) = 0; + virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map, + const char* key) = 0; + virtual const char* inputGetPropertyKey(input_property_t* property) = 0; + virtual const char* inputGetPropertyValue(input_property_t* property) = 0; + virtual void inputFreeDeviceProperty(input_property_t* property) = 0; + virtual void inputFreeDevicePropertyMap(input_property_map_t* map) = 0; virtual void dump(String8& result) = 0; }; @@ -46,7 +85,44 @@ public: InputDriver(const char* name); virtual ~InputDriver() = default; - virtual void init(InputHostInterface* host) override; + virtual void init() override; + + virtual input_device_identifier_t* createDeviceIdentifier( + const char* name, int32_t productId, int32_t vendorId, + input_bus_t bus, const char* uniqueId) override; + virtual input_device_definition_t* createDeviceDefinition() override; + virtual input_report_definition_t* createInputReportDefinition() override; + virtual input_report_definition_t* createOutputReportDefinition() override; + virtual void freeReportDefinition(input_report_definition_t* reportDef) override; + + virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d, + input_report_definition_t* r) override; + virtual void inputReportDefinitionAddCollection(input_report_definition_t* report, + input_collection_id_t id, int32_t arity) override; + virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, + input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, + float resolution) override; + virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, + input_collection_id_t id, input_usage_t* usage, size_t usageCount) override; + + virtual input_device_handle_t* registerDevice(input_device_identifier_t* id, + input_device_definition_t* d) override; + virtual void unregisterDevice(input_device_handle_t* handle) override; + + virtual input_report_t* inputAllocateReport(input_report_definition_t* r) override; + virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, + input_usage_t usage, int32_t value, int32_t arity_index) override; + virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, + input_usage_t usage, bool value, int32_t arity_index) override; + virtual void reportEvent(input_device_handle_t* d, input_report_t* report) override; + + virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) override; + virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map, + const char* key) override; + virtual const char* inputGetPropertyKey(input_property_t* property) override; + virtual const char* inputGetPropertyValue(input_property_t* property) override; + virtual void inputFreeDeviceProperty(input_property_t* property) override; + virtual void inputFreeDevicePropertyMap(input_property_map_t* map) override; virtual void dump(String8& result) override; @@ -68,6 +144,8 @@ input_report_definition_t* create_input_report_definition(input_host_t* host); input_report_definition_t* create_output_report_definition(input_host_t* host); +void free_report_definition(input_host_t* host, input_report_definition_t* report_def); + void input_device_definition_add_report(input_host_t* host, input_device_definition_t* d, input_report_definition_t* r); diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp index 51d3e6b579..094200af7d 100644 --- a/services/inputflinger/host/InputHost.cpp +++ b/services/inputflinger/host/InputHost.cpp @@ -28,7 +28,7 @@ namespace android { void InputHost::registerInputDriver(InputDriverInterface* driver) { LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!"); - driver->init(this); + driver->init(); mDrivers.push_back(driver); } diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h index 42a66e073e..eda4a89c73 100644 --- a/services/inputflinger/host/InputHost.h +++ b/services/inputflinger/host/InputHost.h @@ -26,15 +26,11 @@ #include "InputDriver.h" -// Declare a concrete type for the HAL -struct input_host { -}; - namespace android { class InputDriverInterface; -class InputHostInterface : public input_host_t, public virtual RefBase { +class InputHostInterface : public virtual RefBase { protected: InputHostInterface() = default; virtual ~InputHostInterface() = default; diff --git a/services/inputflinger/host/inputflinger.rc b/services/inputflinger/host/inputflinger.rc new file mode 100644 index 0000000000..ae71ee5b8c --- /dev/null +++ b/services/inputflinger/host/inputflinger.rc @@ -0,0 +1,5 @@ +service inputflinger /system/bin/inputflinger + class main + user system + group input +# onrestart restart zygote diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp index b07d5448a6..7b1f3460ea 100644 --- a/services/sensorservice/CorrectedGyroSensor.cpp +++ b/services/sensorservice/CorrectedGyroSensor.cpp @@ -58,12 +58,12 @@ bool CorrectedGyroSensor::process(sensors_event_t* outEvent, status_t CorrectedGyroSensor::activate(void* ident, bool enabled) { mSensorDevice.activate(ident, mGyro.getHandle(), enabled); - return mSensorFusion.activate(ident, enabled); + return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t CorrectedGyroSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { mSensorDevice.setDelay(ident, mGyro.getHandle(), ns); - return mSensorFusion.setDelay(ident, ns); + return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } Sensor CorrectedGyroSensor::getSensor() const { diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp index 4f63c31d16..359d289773 100644 --- a/services/sensorservice/Fusion.cpp +++ b/services/sensorservice/Fusion.cpp @@ -24,28 +24,44 @@ namespace android { // ----------------------------------------------------------------------- +/*==================== BEGIN FUSION SENSOR PARAMETER =========================*/ + +/* Note: + * If a platform uses software fusion, it is necessary to tune the following + * parameters to fit the hardware sensors prior to release. + * + * The DEFAULT_ parameters will be used in FUSION_9AXIS and FUSION_NOMAG mode. + * The GEOMAG_ parameters will be used in FUSION_NOGYRO mode. + */ + /* - * gyroVAR gives the measured variance of the gyro's output per + * GYRO_VAR gives the measured variance of the gyro's output per * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro, * which is independent of the sampling frequency. * * The variance of gyro's output at a given sampling period can be * calculated as: - * variance(T) = gyroVAR / T + * variance(T) = GYRO_VAR / T * * The variance of the INTEGRATED OUTPUT at a given sampling period can be * calculated as: - * variance_integrate_output(T) = gyroVAR * T - * + * variance_integrate_output(T) = GYRO_VAR * T */ -static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz -static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed) +static const float DEFAULT_GYRO_VAR = 1e-7; // (rad/s)^2 / Hz +static const float DEFAULT_GYRO_BIAS_VAR = 1e-12; // (rad/s)^2 / s (guessed) +static const float GEOMAG_GYRO_VAR = 1e-4; // (rad/s)^2 / Hz +static const float GEOMAG_GYRO_BIAS_VAR = 1e-8; // (rad/s)^2 / s (guessed) /* * Standard deviations of accelerometer and magnetometer */ -static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) -static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5) +static const float DEFAULT_ACC_STDEV = 0.015f; // m/s^2 (measured 0.08 / CDD 0.05) +static const float DEFAULT_MAG_STDEV = 0.1f; // uT (measured 0.7 / CDD 0.5) +static const float GEOMAG_ACC_STDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) +static const float GEOMAG_MAG_STDEV = 0.1f; // uT (measured 0.7 / CDD 0.5) + + +/* ====================== END FUSION SENSOR PARAMETER ========================*/ static const float SYMMETRY_TOLERANCE = 1e-10f; @@ -54,7 +70,8 @@ static const float SYMMETRY_TOLERANCE = 1e-10f; * ill-conditioning and div by zeros. * Threshhold: 10% of g, in m/s^2 */ -static const float FREE_FALL_THRESHOLD = 0.981f; +static const float NOMINAL_GRAVITY = 9.81f; +static const float FREE_FALL_THRESHOLD = 0.1f * (NOMINAL_GRAVITY); static const float FREE_FALL_THRESHOLD_SQ = FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD; @@ -87,6 +104,9 @@ static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3; static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ = MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG; +static const float W_EPS = 1e-4f; +static const float SQRT_3 = 1.732f; +static const float WVEC_EPS = 1e-4f/SQRT_3; // ----------------------------------------------------------------------- template <typename TYPE, size_t C, size_t R> @@ -173,7 +193,7 @@ Fusion::Fusion() { init(); } -void Fusion::init() { +void Fusion::init(int mode) { mInitState = 0; mGyroRate = 0; @@ -183,6 +203,19 @@ void Fusion::init() { mCount[2] = 0; mData = 0; + mMode = mode; + + if (mMode != FUSION_NOGYRO) { //normal or game rotation + mParam.gyroVar = DEFAULT_GYRO_VAR; + mParam.gyroBiasVar = DEFAULT_GYRO_BIAS_VAR; + mParam.accStdev = DEFAULT_ACC_STDEV; + mParam.magStdev = DEFAULT_MAG_STDEV; + } else { + mParam.gyroVar = GEOMAG_GYRO_VAR; + mParam.gyroBiasVar = GEOMAG_GYRO_BIAS_VAR; + mParam.accStdev = GEOMAG_ACC_STDEV; + mParam.magStdev = GEOMAG_MAG_STDEV; + } } void Fusion::initFusion(const vec4_t& q, float dT) @@ -205,11 +238,11 @@ void Fusion::initFusion(const vec4_t& q, float dT) const float dT3 = dT2*dT; // variance of integrated output at 1/dT Hz (random drift) - const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3; + const float q00 = mParam.gyroVar * dT + 0.33333f * mParam.gyroBiasVar * dT3; // variance of drift rate ramp - const float q11 = biasVAR * dT; - const float q10 = 0.5f * biasVAR * dT2; + const float q11 = mParam.gyroBiasVar * dT; + const float q10 = 0.5f * mParam.gyroBiasVar * dT2; const float q01 = q10; GQGt[0][0] = q00; // rad^2 @@ -223,7 +256,9 @@ void Fusion::initFusion(const vec4_t& q, float dT) } bool Fusion::hasEstimate() const { - return (mInitState == (MAG|ACC|GYRO)); + return ((mInitState & MAG) || (mMode == FUSION_NOMAG)) && + ((mInitState & GYRO) || (mMode == FUSION_NOGYRO)) && + (mInitState & ACC); } bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { @@ -234,6 +269,9 @@ bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { mData[0] += d * (1/length(d)); mCount[0]++; mInitState |= ACC; + if (mMode == FUSION_NOGYRO ) { + mGyroRate = dT; + } } else if (what == MAG) { mData[1] += d * (1/length(d)); mCount[1]++; @@ -242,25 +280,29 @@ bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { mGyroRate = dT; mData[2] += d*dT; mCount[2]++; - if (mCount[2] == 64) { - // 64 samples is good enough to estimate the gyro drift and - // doesn't take too much time. - mInitState |= GYRO; - } + mInitState |= GYRO; } - if (mInitState == (MAG|ACC|GYRO)) { + if (hasEstimate()) { // Average all the values we collected so far mData[0] *= 1.0f/mCount[0]; - mData[1] *= 1.0f/mCount[1]; + if (mMode != FUSION_NOMAG) { + mData[1] *= 1.0f/mCount[1]; + } mData[2] *= 1.0f/mCount[2]; // calculate the MRPs from the data collection, this gives us // a rough estimate of our initial state mat33_t R; - vec3_t up(mData[0]); - vec3_t east(cross_product(mData[1], up)); - east *= 1/length(east); + vec3_t up(mData[0]); + vec3_t east; + + if (mMode != FUSION_NOMAG) { + east = normalize(cross_product(mData[1], up)); + } else { + east = getOrthogonal(up); + } + vec3_t north(cross_product(up, east)); R << east << north << up; const vec4_t q = matrixToQuat(R); @@ -278,21 +320,43 @@ void Fusion::handleGyro(const vec3_t& w, float dT) { predict(w, dT); } -status_t Fusion::handleAcc(const vec3_t& a) { +status_t Fusion::handleAcc(const vec3_t& a, float dT) { + if (!checkInitComplete(ACC, a, dT)) + return BAD_VALUE; + // ignore acceleration data if we're close to free-fall - if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) { + const float l = length(a); + if (l < FREE_FALL_THRESHOLD) { return BAD_VALUE; } - if (!checkInitComplete(ACC, a)) - return BAD_VALUE; + const float l_inv = 1.0f/l; + + if ( mMode == FUSION_NOGYRO ) { + //geo mag + vec3_t w_dummy; + w_dummy = x1; //bias + predict(w_dummy, dT); + } + + if ( mMode == FUSION_NOMAG) { + vec3_t m; + m = getRotationMatrix()*Bm; + update(m, Bm, mParam.magStdev); + } - const float l = 1/length(a); - update(a*l, Ba, accSTDEV*l); + vec3_t unityA = a * l_inv; + const float d = sqrtf(fabsf(l- NOMINAL_GRAVITY)); + const float p = l_inv * mParam.accStdev*expf(d); + + update(unityA, Ba, p); return NO_ERROR; } status_t Fusion::handleMag(const vec3_t& m) { + if (!checkInitComplete(MAG, m)) + return BAD_VALUE; + // the geomagnetic-field should be between 30uT and 60uT // reject if too large to avoid spurious magnetic sources const float magFieldSq = length_squared(m); @@ -304,9 +368,6 @@ status_t Fusion::handleMag(const vec3_t& m) { return BAD_VALUE; } - if (!checkInitComplete(MAG, m)) - return BAD_VALUE; - // Orthogonalize the magnetic field to the gravity field, mapping it into // tangent to Earth. const vec3_t up( getRotationMatrix() * Ba ); @@ -324,10 +385,10 @@ status_t Fusion::handleMag(const vec3_t& m) { // then pass it in as the update. vec3_t north( cross_product(up, east) ); - const float l = 1 / length(north); - north *= l; + const float l_inv = 1 / length(north); + north *= l_inv; - update(north, Bm, magSTDEV*l); + update(north, Bm, mParam.magStdev*l_inv); return NO_ERROR; } @@ -372,8 +433,11 @@ mat34_t Fusion::getF(const vec4_t& q) { void Fusion::predict(const vec3_t& w, float dT) { const vec4_t q = x0; const vec3_t b = x1; - const vec3_t we = w - b; + vec3_t we = w - b; + if (length(we) < WVEC_EPS) { + we = (we[0]>0.f)?WVEC_EPS:-WVEC_EPS; + } // q(k+1) = O(we)*q(k) // -------------------- // @@ -406,7 +470,7 @@ void Fusion::predict(const vec3_t& w, float dT) { const mat33_t wx2(wx*wx); const float lwedT = length(we)*dT; const float hlwedT = 0.5f*lwedT; - const float ilwe = 1/length(we); + const float ilwe = 1.f/length(we); const float k0 = (1-cosf(lwedT))*(ilwe*ilwe); const float k1 = sinf(lwedT); const float k2 = cosf(hlwedT); @@ -422,6 +486,7 @@ void Fusion::predict(const vec3_t& w, float dT) { Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1); x0 = O*q; + if (x0.w < 0) x0 = -x0; @@ -466,15 +531,37 @@ void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) { const vec3_t e(z - Bb); const vec3_t dq(K[0]*e); - const vec3_t db(K[1]*e); q += getF(q)*(0.5f*dq); x0 = normalize_quat(q); - x1 += db; + + if (mMode != FUSION_NOMAG) { + const vec3_t db(K[1]*e); + x1 += db; + } checkState(); } +vec3_t Fusion::getOrthogonal(const vec3_t &v) { + vec3_t w; + if (fabsf(v[0])<= fabsf(v[1]) && fabsf(v[0]) <= fabsf(v[2])) { + w[0]=0.f; + w[1] = v[2]; + w[2] = -v[1]; + } else if (fabsf(v[1]) <= fabsf(v[2])) { + w[0] = v[2]; + w[1] = 0.f; + w[2] = -v[0]; + }else { + w[0] = v[1]; + w[1] = -v[0]; + w[2] = 0.f; + } + return normalize(w); +} + + // ----------------------------------------------------------------------- }; // namespace android diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h index 7062999b75..602779f539 100644 --- a/services/sensorservice/Fusion.h +++ b/services/sensorservice/Fusion.h @@ -27,6 +27,13 @@ namespace android { typedef mat<float, 3, 4> mat34_t; +enum FUSION_MODE{ + FUSION_9AXIS, // use accel gyro mag + FUSION_NOMAG, // use accel gyro (game rotation, gravity) + FUSION_NOGYRO, // use accel mag (geomag rotation) + NUM_FUSION_MODE +}; + class Fusion { /* * the state vector is made of two sub-vector containing respectively: @@ -55,9 +62,9 @@ class Fusion { public: Fusion(); - void init(); + void init(int mode = FUSION_9AXIS); void handleGyro(const vec3_t& w, float dT); - status_t handleAcc(const vec3_t& a); + status_t handleAcc(const vec3_t& a, float dT); status_t handleMag(const vec3_t& m); vec4_t getAttitude() const; vec3_t getBias() const; @@ -65,12 +72,21 @@ public: bool hasEstimate() const; private: + struct Parameter { + float gyroVar; + float gyroBiasVar; + float accStdev; + float magStdev; + } mParam; + mat<mat33_t, 2, 2> Phi; vec3_t Ba, Bm; uint32_t mInitState; float mGyroRate; vec<vec3_t, 3> mData; size_t mCount[3]; + int mMode; + enum { ACC=0x1, MAG=0x2, GYRO=0x4 }; bool checkInitComplete(int, const vec3_t& w, float d = 0); void initFusion(const vec4_t& q0, float dT); @@ -78,6 +94,7 @@ private: void predict(const vec3_t& w, float dT); void update(const vec3_t& z, const vec3_t& Bi, float sigma); static mat34_t getF(const vec4_t& p); + static vec3_t getOrthogonal(const vec3_t &v); }; }; // namespace android diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp index 61118bc54a..a165a5b701 100644 --- a/services/sensorservice/GravitySensor.cpp +++ b/services/sensorservice/GravitySensor.cpp @@ -46,9 +46,9 @@ bool GravitySensor::process(sensors_event_t* outEvent, { if (event.type == SENSOR_TYPE_ACCELEROMETER) { vec3_t g; - if (!mSensorFusion.hasEstimate()) + if (!mSensorFusion.hasEstimate(FUSION_NOMAG)) return false; - const mat33_t R(mSensorFusion.getRotationMatrix()); + const mat33_t R(mSensorFusion.getRotationMatrix(FUSION_NOMAG)); // FIXME: we need to estimate the length of gravity because // the accelerometer may have a small scaling error. This // translates to an offset in the linear-acceleration sensor. @@ -66,11 +66,11 @@ bool GravitySensor::process(sensors_event_t* outEvent, } status_t GravitySensor::activate(void* ident, bool enabled) { - return mSensorFusion.activate(ident, enabled); + return mSensorFusion.activate(FUSION_NOMAG, ident, enabled); } status_t GravitySensor::setDelay(void* ident, int /*handle*/, int64_t ns) { - return mSensorFusion.setDelay(ident, ns); + return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns); } Sensor GravitySensor::getSensor() const { diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp index 6d85cca0f6..d55f336c00 100644 --- a/services/sensorservice/OrientationSensor.cpp +++ b/services/sensorservice/OrientationSensor.cpp @@ -66,11 +66,11 @@ bool OrientationSensor::process(sensors_event_t* outEvent, } status_t OrientationSensor::activate(void* ident, bool enabled) { - return mSensorFusion.activate(ident, enabled); + return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t OrientationSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { - return mSensorFusion.setDelay(ident, ns); + return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } Sensor OrientationSensor::getSensor() const { diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp index cb305ebf8d..238845bd83 100644 --- a/services/sensorservice/RotationVectorSensor.cpp +++ b/services/sensorservice/RotationVectorSensor.cpp @@ -27,9 +27,10 @@ namespace android { // --------------------------------------------------------------------------- -RotationVectorSensor::RotationVectorSensor() +RotationVectorSensor::RotationVectorSensor(int mode) : mSensorDevice(SensorDevice::getInstance()), - mSensorFusion(SensorFusion::getInstance()) + mSensorFusion(SensorFusion::getInstance()), + mMode(mode) { } @@ -37,15 +38,15 @@ bool RotationVectorSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { if (event.type == SENSOR_TYPE_ACCELEROMETER) { - if (mSensorFusion.hasEstimate()) { - const vec4_t q(mSensorFusion.getAttitude()); + if (mSensorFusion.hasEstimate(mMode)) { + const vec4_t q(mSensorFusion.getAttitude(mMode)); *outEvent = event; outEvent->data[0] = q.x; outEvent->data[1] = q.y; outEvent->data[2] = q.z; outEvent->data[3] = q.w; - outEvent->sensor = '_rov'; - outEvent->type = SENSOR_TYPE_ROTATION_VECTOR; + outEvent->sensor = getSensorToken(); + outEvent->type = getSensorType(); return true; } } @@ -53,20 +54,20 @@ bool RotationVectorSensor::process(sensors_event_t* outEvent, } status_t RotationVectorSensor::activate(void* ident, bool enabled) { - return mSensorFusion.activate(ident, enabled); + return mSensorFusion.activate(mMode, ident, enabled); } status_t RotationVectorSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { - return mSensorFusion.setDelay(ident, ns); + return mSensorFusion.setDelay(mMode, ident, ns); } Sensor RotationVectorSensor::getSensor() const { sensor_t hwSensor; - hwSensor.name = "Rotation Vector Sensor"; + hwSensor.name = getSensorName(); hwSensor.vendor = "AOSP"; hwSensor.version = 3; - hwSensor.handle = '_rov'; - hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; + hwSensor.handle = getSensorToken(); + hwSensor.type = getSensorType(); hwSensor.maxRange = 1; hwSensor.resolution = 1.0f / (1<<24); hwSensor.power = mSensorFusion.getPowerUsage(); @@ -75,6 +76,48 @@ Sensor RotationVectorSensor::getSensor() const { return sensor; } +int RotationVectorSensor::getSensorType() const { + switch(mMode) { + case FUSION_9AXIS: + return SENSOR_TYPE_ROTATION_VECTOR; + case FUSION_NOMAG: + return SENSOR_TYPE_GAME_ROTATION_VECTOR; + case FUSION_NOGYRO: + return SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR; + default: + assert(0); + return 0; + } +} + +const char* RotationVectorSensor::getSensorName() const { + switch(mMode) { + case FUSION_9AXIS: + return "Rotation Vector Sensor"; + case FUSION_NOMAG: + return "Game Rotation Vector Sensor"; + case FUSION_NOGYRO: + return "GeoMag Rotation Vector Sensor"; + default: + assert(0); + return NULL; + } +} + +int RotationVectorSensor::getSensorToken() const { + switch(mMode) { + case FUSION_9AXIS: + return '_rov'; + case FUSION_NOMAG: + return '_gar'; + case FUSION_NOGYRO: + return '_geo'; + default: + assert(0); + return 0; + } +} + // --------------------------------------------------------------------------- GyroDriftSensor::GyroDriftSensor() @@ -102,11 +145,11 @@ bool GyroDriftSensor::process(sensors_event_t* outEvent, } status_t GyroDriftSensor::activate(void* ident, bool enabled) { - return mSensorFusion.activate(ident, enabled); + return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t GyroDriftSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { - return mSensorFusion.setDelay(ident, ns); + return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } Sensor GyroDriftSensor::getSensor() const { diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h index bb97fe189e..1fc316be80 100644 --- a/services/sensorservice/RotationVectorSensor.h +++ b/services/sensorservice/RotationVectorSensor.h @@ -35,9 +35,14 @@ namespace android { class RotationVectorSensor : public SensorInterface { SensorDevice& mSensorDevice; SensorFusion& mSensorFusion; + int mMode; + + int getSensorType() const; + const char* getSensorName() const ; + int getSensorToken() const ; public: - RotationVectorSensor(); + RotationVectorSensor(int mode = FUSION_9AXIS); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event); virtual status_t activate(void* ident, bool enabled); @@ -46,6 +51,16 @@ public: virtual bool isVirtual() const { return true; } }; +class GameRotationVectorSensor : public RotationVectorSensor { +public: + GameRotationVectorSensor() : RotationVectorSensor(FUSION_NOMAG) {} +}; + +class GeoMagRotationVectorSensor : public RotationVectorSensor { +public: + GeoMagRotationVectorSensor() : RotationVectorSensor(FUSION_NOGYRO) {} +}; + class GyroDriftSensor : public SensorInterface { SensorDevice& mSensorDevice; SensorFusion& mSensorFusion; diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index 6d93009176..9863f62853 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -25,11 +25,17 @@ ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion) SensorFusion::SensorFusion() : mSensorDevice(SensorDevice::getInstance()), - mEnabled(false), mGyroTime(0) + mAttitude(mAttitudes[FUSION_9AXIS]), + mGyroTime(0), mAccTime(0) { sensor_t const* list; Sensor uncalibratedGyro; ssize_t count = mSensorDevice.getSensorList(&list); + + mEnabled[FUSION_9AXIS] = false; + mEnabled[FUSION_NOMAG] = false; + mEnabled[FUSION_NOGYRO] = false; + if (count > 0) { for (size_t i=0 ; i<size_t(count) ; i++) { if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { @@ -55,81 +61,121 @@ SensorFusion::SensorFusion() // and power/cpu usage. mEstimatedGyroRate = 200; mTargetDelayNs = 1000000000LL/mEstimatedGyroRate; - mFusion.init(); + + for (int i = 0; i<NUM_FUSION_MODE; ++i) { + mFusions[i].init(i); + } } } void SensorFusion::process(const sensors_event_t& event) { + if (event.type == mGyro.getType()) { - if (mGyroTime != 0) { - const float dT = (event.timestamp - mGyroTime) / 1000000000.0f; - mFusion.handleGyro(vec3_t(event.data), dT); + float dT; + if ( event.timestamp - mGyroTime> 0 && + event.timestamp - mGyroTime< (int64_t)(5e7) ) { //0.05sec + + dT = (event.timestamp - mGyroTime) / 1000000000.0f; // here we estimate the gyro rate (useful for debugging) const float freq = 1 / dT; if (freq >= 100 && freq<1000) { // filter values obviously wrong const float alpha = 1 / (1 + dT); // 1s time-constant mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha; } + + const vec3_t gyro(event.data); + for (int i = 0; i<NUM_FUSION_MODE; ++i) { + if (mEnabled[i]) { + // fusion in no gyro mode will ignore + mFusions[i].handleGyro(gyro, dT); + } + } } mGyroTime = event.timestamp; } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) { const vec3_t mag(event.data); - mFusion.handleMag(mag); + for (int i = 0; i<NUM_FUSION_MODE; ++i) { + if (mEnabled[i]) { + mFusions[i].handleMag(mag);// fusion in no mag mode will ignore + } + } } else if (event.type == SENSOR_TYPE_ACCELEROMETER) { - const vec3_t acc(event.data); - mFusion.handleAcc(acc); - mAttitude = mFusion.getAttitude(); + float dT; + if ( event.timestamp - mAccTime> 0 && + event.timestamp - mAccTime< (int64_t)(1e8) ) { //0.1sec + dT = (event.timestamp - mAccTime) / 1000000000.0f; + + const vec3_t acc(event.data); + for (int i = 0; i<NUM_FUSION_MODE; ++i) { + if (mEnabled[i]) { + mFusions[i].handleAcc(acc, dT); + mAttitudes[i] = mFusions[i].getAttitude(); + } + } + } + mAccTime = event.timestamp; } } template <typename T> inline T min(T a, T b) { return a<b ? a : b; } template <typename T> inline T max(T a, T b) { return a>b ? a : b; } -status_t SensorFusion::activate(void* ident, bool enabled) { +status_t SensorFusion::activate(int mode, void* ident, bool enabled) { ALOGD_IF(DEBUG_CONNECTIONS, - "SensorFusion::activate(ident=%p, enabled=%d)", - ident, enabled); + "SensorFusion::activate(mode=%d, ident=%p, enabled=%d)", + mode, ident, enabled); - const ssize_t idx = mClients.indexOf(ident); + const ssize_t idx = mClients[mode].indexOf(ident); if (enabled) { if (idx < 0) { - mClients.add(ident); + mClients[mode].add(ident); } } else { if (idx >= 0) { - mClients.removeItemsAt(idx); + mClients[mode].removeItemsAt(idx); } } - mSensorDevice.activate(ident, mAcc.getHandle(), enabled); - mSensorDevice.activate(ident, mMag.getHandle(), enabled); - mSensorDevice.activate(ident, mGyro.getHandle(), enabled); - - const bool newState = mClients.size() != 0; - if (newState != mEnabled) { - mEnabled = newState; + const bool newState = mClients[mode].size() != 0; + if (newState != mEnabled[mode]) { + mEnabled[mode] = newState; if (newState) { - mFusion.init(); - mGyroTime = 0; + mFusions[mode].init(mode); } } + + mSensorDevice.activate(ident, mAcc.getHandle(), enabled); + if (mode != FUSION_NOMAG) { + mSensorDevice.activate(ident, mMag.getHandle(), enabled); + } + if (mode != FUSION_NOGYRO) { + mSensorDevice.activate(ident, mGyro.getHandle(), enabled); + } + return NO_ERROR; } -status_t SensorFusion::setDelay(void* ident, int64_t ns) { +status_t SensorFusion::setDelay(int mode, void* ident, int64_t ns) { // Call batch with timeout zero instead of setDelay(). + if (ns > (int64_t)5e7) { + ns = (int64_t)(5e7); + } mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0); - mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0); - mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0); + if (mode != FUSION_NOMAG) { + mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0); + } + if (mode != FUSION_NOGYRO) { + mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0); + } return NO_ERROR; } -float SensorFusion::getPowerUsage() const { +float SensorFusion::getPowerUsage(int mode) const { float power = mAcc.getPowerUsage() + - mMag.getPowerUsage() + - mGyro.getPowerUsage(); + ((mode != FUSION_NOMAG) ? mMag.getPowerUsage() : 0) + + ((mode != FUSION_NOGYRO) ? mGyro.getPowerUsage() : 0); return power; } @@ -138,21 +184,55 @@ int32_t SensorFusion::getMinDelay() const { } void SensorFusion::dump(String8& result) { - const Fusion& fusion(mFusion); + const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]); result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, " "q=< %g, %g, %g, %g > (%g), " "b=< %g, %g, %g >\n", - mEnabled ? "enabled" : "disabled", - mClients.size(), + mEnabled[FUSION_9AXIS] ? "enabled" : "disabled", + mClients[FUSION_9AXIS].size(), + mEstimatedGyroRate, + fusion_9axis.getAttitude().x, + fusion_9axis.getAttitude().y, + fusion_9axis.getAttitude().z, + fusion_9axis.getAttitude().w, + length(fusion_9axis.getAttitude()), + fusion_9axis.getBias().x, + fusion_9axis.getBias().y, + fusion_9axis.getBias().z); + + const Fusion& fusion_nomag(mFusions[FUSION_NOMAG]); + result.appendFormat("game fusion(no mag) %s (%zd clients), " + "gyro-rate=%7.2fHz, " + "q=< %g, %g, %g, %g > (%g), " + "b=< %g, %g, %g >\n", + mEnabled[FUSION_NOMAG] ? "enabled" : "disabled", + mClients[FUSION_NOMAG].size(), + mEstimatedGyroRate, + fusion_nomag.getAttitude().x, + fusion_nomag.getAttitude().y, + fusion_nomag.getAttitude().z, + fusion_nomag.getAttitude().w, + length(fusion_nomag.getAttitude()), + fusion_nomag.getBias().x, + fusion_nomag.getBias().y, + fusion_nomag.getBias().z); + + const Fusion& fusion_nogyro(mFusions[FUSION_NOGYRO]); + result.appendFormat("geomag fusion (no gyro) %s (%zd clients), " + "gyro-rate=%7.2fHz, " + "q=< %g, %g, %g, %g > (%g), " + "b=< %g, %g, %g >\n", + mEnabled[FUSION_NOGYRO] ? "enabled" : "disabled", + mClients[FUSION_NOGYRO].size(), mEstimatedGyroRate, - fusion.getAttitude().x, - fusion.getAttitude().y, - fusion.getAttitude().z, - fusion.getAttitude().w, - length(fusion.getAttitude()), - fusion.getBias().x, - fusion.getBias().y, - fusion.getBias().z); + fusion_nogyro.getAttitude().x, + fusion_nogyro.getAttitude().y, + fusion_nogyro.getAttitude().z, + fusion_nogyro.getAttitude().w, + length(fusion_nogyro.getAttitude()), + fusion_nogyro.getBias().x, + fusion_nogyro.getBias().y, + fusion_nogyro.getBias().z); } // --------------------------------------------------------------------------- diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h index 432adbcfd0..ad636d5dad 100644 --- a/services/sensorservice/SensorFusion.h +++ b/services/sensorservice/SensorFusion.h @@ -42,30 +42,52 @@ class SensorFusion : public Singleton<SensorFusion> { Sensor mAcc; Sensor mMag; Sensor mGyro; - Fusion mFusion; - bool mEnabled; + + Fusion mFusions[NUM_FUSION_MODE]; // normal, no_mag, no_gyro + + bool mEnabled[NUM_FUSION_MODE]; + + vec4_t &mAttitude; + vec4_t mAttitudes[NUM_FUSION_MODE]; + + SortedVector<void*> mClients[3]; + float mEstimatedGyroRate; nsecs_t mTargetDelayNs; + nsecs_t mGyroTime; - vec4_t mAttitude; - SortedVector<void*> mClients; + nsecs_t mAccTime; SensorFusion(); public: void process(const sensors_event_t& event); - bool isEnabled() const { return mEnabled; } - bool hasEstimate() const { return mFusion.hasEstimate(); } - mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); } - vec4_t getAttitude() const { return mAttitude; } - vec3_t getGyroBias() const { return mFusion.getBias(); } + bool isEnabled() const { + return mEnabled[FUSION_9AXIS] || + mEnabled[FUSION_NOMAG] || + mEnabled[FUSION_NOGYRO]; + } + + bool hasEstimate(int mode = FUSION_9AXIS) const { + return mFusions[mode].hasEstimate(); + } + + mat33_t getRotationMatrix(int mode = FUSION_9AXIS) const { + return mFusions[mode].getRotationMatrix(); + } + + vec4_t getAttitude(int mode = FUSION_9AXIS) const { + return mAttitudes[mode]; + } + + vec3_t getGyroBias() const { return mFusions[FUSION_9AXIS].getBias(); } float getEstimatedRate() const { return mEstimatedGyroRate; } - status_t activate(void* ident, bool enabled); - status_t setDelay(void* ident, int64_t ns); + status_t activate(int mode, void* ident, bool enabled); + status_t setDelay(int mode, void* ident, int64_t ns); - float getPowerUsage() const; + float getPowerUsage(int mode=FUSION_9AXIS) const; int32_t getMinDelay() const; void dump(String8& result); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 1a486a34c8..8e2109b04c 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -88,11 +88,14 @@ void SensorService::onFirstRef() uint32_t virtualSensorsNeeds = (1<<SENSOR_TYPE_GRAVITY) | (1<<SENSOR_TYPE_LINEAR_ACCELERATION) | - (1<<SENSOR_TYPE_ROTATION_VECTOR); + (1<<SENSOR_TYPE_ROTATION_VECTOR) | + (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) | + (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR); mLastEventSeen.setCapacity(count); for (ssize_t i=0 ; i<count ; i++) { - registerSensor( new HardwareSensor(list[i]) ); + bool useThisSensor=true; + switch (list[i].type) { case SENSOR_TYPE_ACCELEROMETER: hasAccel = true; @@ -110,9 +113,18 @@ void SensorService::onFirstRef() case SENSOR_TYPE_GRAVITY: case SENSOR_TYPE_LINEAR_ACCELERATION: case SENSOR_TYPE_ROTATION_VECTOR: - virtualSensorsNeeds &= ~(1<<list[i].type); + case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: + case SENSOR_TYPE_GAME_ROTATION_VECTOR: + if (IGNORE_HARDWARE_FUSION) { + useThisSensor = false; + } else { + virtualSensorsNeeds &= ~(1<<list[i].type); + } break; } + if (useThisSensor) { + registerSensor( new HardwareSensor(list[i]) ); + } } // it's safe to instantiate the SensorFusion object here @@ -124,26 +136,15 @@ void SensorService::onFirstRef() mUserSensorList = mSensorList; if (hasGyro && hasAccel && hasMag) { - Sensor aSensor; - // Add Android virtual sensors if they're not already // available in the HAL + Sensor aSensor; aSensor = registerVirtualSensor( new RotationVectorSensor() ); if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) { mUserSensorList.add(aSensor); } - aSensor = registerVirtualSensor( new GravitySensor(list, count) ); - if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) { - mUserSensorList.add(aSensor); - } - - aSensor = registerVirtualSensor( new LinearAccelerationSensor(list, count) ); - if (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) { - mUserSensorList.add(aSensor); - } - aSensor = registerVirtualSensor( new OrientationSensor() ); if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) { // if we are doing our own rotation-vector, also add @@ -151,11 +152,46 @@ void SensorService::onFirstRef() mUserSensorList.replaceAt(aSensor, orientationIndex); } + aSensor = registerVirtualSensor( + new LinearAccelerationSensor(list, count) ); + if (virtualSensorsNeeds & + (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) { + mUserSensorList.add(aSensor); + } + // virtual debugging sensors are not added to mUserSensorList registerVirtualSensor( new CorrectedGyroSensor(list, count) ); registerVirtualSensor( new GyroDriftSensor() ); } + if (hasAccel && hasGyro) { + Sensor aSensor; + + aSensor = registerVirtualSensor( + new GravitySensor(list, count) ); + if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) { + mUserSensorList.add(aSensor); + } + + aSensor = registerVirtualSensor( + new GameRotationVectorSensor() ); + if (virtualSensorsNeeds & + (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) { + mUserSensorList.add(aSensor); + } + } + + if (hasAccel && hasMag) { + Sensor aSensor; + + aSensor = registerVirtualSensor( + new GeoMagRotationVectorSensor() ); + if (virtualSensorsNeeds & + (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)) { + mUserSensorList.add(aSensor); + } + } + // debugging sensor list mUserSensorListDebug = mSensorList; diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 9a573ae78c..7d81d6e104 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -46,7 +46,7 @@ #endif // --------------------------------------------------------------------------- - +#define IGNORE_HARDWARE_FUSION false #define DEBUG_CONNECTIONS false // Max size is 100 KB which is enough to accept a batch of about 1000 events. #define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024 diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 49389e062f..2a025b8a93 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -134,7 +134,7 @@ status_t Client::createSurface( sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) : flinger(flinger), client(client), - handle(handle), gbp(gbp), + handle(handle), gbp(gbp), result(NO_ERROR), name(name), w(w), h(h), format(format), flags(flags) { } status_t getResult() const { return result; } diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h index b08a951056..3b75cc05e6 100644 --- a/services/surfaceflinger/DisplayHardware/FloatRect.h +++ b/services/surfaceflinger/DisplayHardware/FloatRect.h @@ -29,7 +29,8 @@ public: float right; float bottom; - inline FloatRect() { } + inline FloatRect() + : left(0), top(0), right(0), bottom(0) { } inline FloatRect(const Rect& other) : left(other.left), top(other.top), right(other.right), bottom(other.bottom) { } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 6ef3295b07..a6bc158e9c 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -66,7 +66,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); - mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); + mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1); } status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { @@ -106,7 +106,7 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& // releaseBuffer call and we should be in the same state we'd be in if we // had released the old buffer first. if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && - item.mBuf != mCurrentBufferSlot) { + item.mSlot != mCurrentBufferSlot) { // Release the previous buffer. err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); @@ -115,7 +115,7 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& return err; } } - mCurrentBufferSlot = item.mBuf; + mCurrentBufferSlot = item.mSlot; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; outFence = item.mFence; outBuffer = mCurrentBuffer; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index ba4c1981af..48971bc2d0 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -92,7 +92,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, mConsumer->setConsumerName(ConsumerBase::mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); - mConsumer->setDefaultMaxBufferCount(2); + sink->setAsyncMode(true); } VirtualDisplaySurface::~VirtualDisplaySurface() { @@ -239,7 +239,6 @@ void VirtualDisplaySurface::onFrameCommitted() { HAL_DATASPACE_UNKNOWN, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, - true /* async*/, outFence), &qbo); if (result == NO_ERROR) { @@ -282,17 +281,20 @@ status_t VirtualDisplaySurface::requestBuffer(int pslot, return NO_ERROR; } -status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { - return mSource[SOURCE_SINK]->setBufferCount(bufferCount); +status_t VirtualDisplaySurface::setMaxDequeuedBufferCount( + int maxDequeuedBuffers) { + return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers); +} + +status_t VirtualDisplaySurface::setAsyncMode(bool async) { + return mSource[SOURCE_SINK]->setAsyncMode(async); } status_t VirtualDisplaySurface::dequeueBuffer(Source source, PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) { LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); - // Don't let a slow consumer block us - bool async = (source == SOURCE_SINK); - status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, + status_t result = mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight, format, usage); if (result < 0) return result; @@ -331,16 +333,15 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, return result; } -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, +status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { if (mDisplayId < 0) - return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage); + return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage); VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); mDbgState = DBG_STATE_GLES; - VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)"); VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); status_t result = NO_ERROR; @@ -442,11 +443,11 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, result = acquireBufferLocked(&item, 0); if (result != NO_ERROR) return result; - VDS_LOGW_IF(item.mBuf != sslot, + VDS_LOGW_IF(item.mSlot != sslot, "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", - item.mBuf, sslot); - mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf); - mFbFence = mSlots[item.mBuf].mFence; + item.mSlot, sslot); + mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot); + mFbFence = mSlots[item.mSlot].mFence; } else { LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES, @@ -460,9 +461,8 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, Rect crop; int scalingMode; uint32_t transform; - bool async; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, - &scalingMode, &transform, &async, &mFbFence); + &scalingMode, &transform, &mFbFence); mFbProducerSlot = pslot; mOutputFence = mFbFence; @@ -472,7 +472,8 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, return NO_ERROR; } -void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) { +status_t VirtualDisplaySurface::cancelBuffer(int pslot, + const sp<Fence>& fence) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); @@ -520,9 +521,8 @@ status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stre return INVALID_OPERATION; } -void VirtualDisplaySurface::allocateBuffers(bool /* async */, - uint32_t /* width */, uint32_t /* height */, PixelFormat /* format */, - uint32_t /* usage */) { +void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */, + uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) { // TODO: Should we actually allocate buffers for a virtual display? } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 6298751f30..d53d43c1d6 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -98,22 +98,23 @@ private: // IGraphicBufferProducer interface, used by the GLES driver. // virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); - virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); + virtual status_t setAsyncMode(bool async); + virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, + uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer); virtual status_t queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int pslot, const sp<Fence>& fence); + virtual status_t cancelBuffer(int pslot, const sp<Fence>& fence); virtual int query(int what, int* value); virtual status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags index 791e0e4084..6c851dd09c 100644 --- a/services/surfaceflinger/EventLog/EventLogTags.logtags +++ b/services/surfaceflinger/EventLog/EventLogTags.logtags @@ -36,6 +36,7 @@ # 60100 - 60199 reserved for surfaceflinger 60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1) +60110 sf_stop_bootanim (time|2|3) # NOTE - the range 1000000-2000000 is reserved for partners and others who # want to define their own log tags without conflicting with the core platform. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5ff79a9e3b..33af4a5029 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -135,9 +135,8 @@ void Layer::onFirstRef() { #ifdef TARGET_DISABLE_TRIPLE_BUFFERING #warning "disabling triple buffering" - mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2); #else - mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3); + mProducer->setMaxDequeuedBufferCount(2); #endif const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index 1ad86a6aca..99efd3905f 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -119,6 +119,7 @@ void MessageQueue::waitMessage() { continue; case Looper::POLL_ERROR: ALOGE("Looper::POLL_ERROR"); + continue; case Looper::POLL_TIMEOUT: // timeout (should not happen) continue; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index fb7af97741..79ef92f568 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -56,13 +56,18 @@ status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return mProducer->requestBuffer(slot, buf); } -status_t MonitoredProducer::setBufferCount(int bufferCount) { - return mProducer->setBufferCount(bufferCount); +status_t MonitoredProducer::setMaxDequeuedBufferCount( + int maxDequeuedBuffers) { + return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers); +} + +status_t MonitoredProducer::setAsyncMode(bool async) { + return mProducer->setAsyncMode(async); } status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, - bool async, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { - return mProducer->dequeueBuffer(slot, fence, async, w, h, format, usage); + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { + return mProducer->dequeueBuffer(slot, fence, w, h, format, usage); } status_t MonitoredProducer::detachBuffer(int slot) { @@ -84,8 +89,8 @@ status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input, return mProducer->queueBuffer(slot, input, output); } -void MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) { - mProducer->cancelBuffer(slot, fence); +status_t MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) { + return mProducer->cancelBuffer(slot, fence); } int MonitoredProducer::query(int what, int* value) { @@ -105,9 +110,9 @@ status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) { return mProducer->setSidebandStream(stream); } -void MonitoredProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, PixelFormat format, uint32_t usage) { - mProducer->allocateBuffers(async, width, height, format, usage); +void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage) { + mProducer->allocateBuffers(width, height, format, usage); } status_t MonitoredProducer::allowAllocation(bool allow) { diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index da95766ceb..3df6f0fb5d 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -35,9 +35,10 @@ public: // From IGraphicBufferProducer virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); + virtual status_t setAsyncMode(bool async); + virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, + uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); @@ -45,13 +46,13 @@ public: const sp<GraphicBuffer>& buffer); virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int slot, const sp<Fence>& fence); + virtual status_t cancelBuffer(int slot, const sp<Fence>& fence); virtual int query(int what, int* value); virtual status_t connect(const sp<IProducerListener>& token, int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 7cd42e4052..27357b91cc 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -148,7 +148,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { return engine; } -RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) { +RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) { } RenderEngine::~RenderEngine() { @@ -316,7 +316,7 @@ class EGLAttributeVector { friend class Adder; KeyedVector<Attribute, EGLint> mList; struct Attribute { - Attribute() {}; + Attribute() : v(0) {}; Attribute(EGLint v) : v(v) { } EGLint v; bool operator < (const Attribute& other) const { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fdc36505cf..285b829e1a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -52,6 +52,7 @@ #include <utils/String8.h> #include <utils/String16.h> #include <utils/StopWatch.h> +#include <utils/Timers.h> #include <utils/Trace.h> #include <private/android_filesystem_config.h> @@ -235,9 +236,8 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, sp<BBinder> token = new DisplayToken(this); Mutex::Autolock _l(mStateLock); - DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL); + DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); info.displayName = displayName; - info.isSecure = secure; mCurrentState.displays.add(token, info); return token; @@ -266,9 +266,8 @@ void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) ALOGW_IF(mBuiltinDisplays[type], "Overwriting display token for display type %d", type); mBuiltinDisplays[type] = new BBinder(); - DisplayDeviceState info(type); // All non-virtual displays are currently considered secure. - info.isSecure = true; + DisplayDeviceState info(type, true); mCurrentState.displays.add(mBuiltinDisplays[type], info); } @@ -304,6 +303,10 @@ void SurfaceFlinger::bootFinished() // formerly we would just kill the process, but we now ask it to exit so it // can choose where to stop the animation. property_set("service.bootanim.exit", "1"); + + const int LOGTAG_SF_STOP_BOOTANIM = 60110; + LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, + ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -3127,8 +3130,12 @@ public: GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) : impl(impl), looper(new Looper(true)), + result(NO_ERROR), exitPending(false), - exitRequested(false) + exitRequested(false), + code(0), + data(NULL), + reply(NULL) {} // Binder thread @@ -3524,11 +3531,22 @@ int SurfaceFlinger::LayerVector::do_compare(const void* lhs, // --------------------------------------------------------------------------- SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() - : type(DisplayDevice::DISPLAY_ID_INVALID), width(0), height(0) { -} - -SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type) - : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0) { + : type(DisplayDevice::DISPLAY_ID_INVALID), + layerStack(DisplayDevice::NO_LAYER_STACK), + orientation(0), + width(0), + height(0), + isSecure(false) { +} + +SurfaceFlinger::DisplayDeviceState::DisplayDeviceState( + DisplayDevice::DisplayType type, bool isSecure) + : type(type), + layerStack(DisplayDevice::NO_LAYER_STACK), + orientation(0), + width(0), + height(0), + isSecure(isSecure) { viewport.makeInvalid(); frame.makeInvalid(); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b3baadd46b..4e0160a1d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -162,7 +162,7 @@ private: struct DisplayDeviceState { DisplayDeviceState(); - DisplayDeviceState(DisplayDevice::DisplayType type); + DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure); bool isValid() const { return type >= 0; } bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; } bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; } diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index ed1f31b554..930e7c764c 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -72,9 +72,9 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, // We call the rejecter here, in case the caller has a reason to // not accept this buffer. This is used by SurfaceFlinger to // reject buffers which have the wrong size - int buf = item.mBuf; - if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { - releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR); + int slot = item.mSlot; + if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR); return BUFFER_REJECTED; } diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index dcde512017..ee4ad4e434 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -24,10 +24,13 @@ #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> +#include <private/gui/LayerState.h> #include <utils/String8.h> #include <ui/DisplayInfo.h> +#include <math.h> + namespace android { // Fill an RGBA_8888 formatted surface with a single color. @@ -38,8 +41,8 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, ASSERT_TRUE(s != NULL); ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, NULL)); uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits); - for (uint32_t y = 0; y < outBuffer.height; y++) { - for (uint32_t x = 0; x < outBuffer.width; x++) { + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { uint8_t* pixel = img + (4 * (y*outBuffer.stride + x)); pixel[0] = r; pixel[1] = g; @@ -76,7 +79,7 @@ public: String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", x, y, r, g, b, pixel[0], pixel[1], pixel[2])); - EXPECT_EQ(String8(), err); + EXPECT_EQ(String8(), err) << err.string(); } } @@ -134,6 +137,8 @@ protected: SurfaceComposerClient::openGlobalTransaction(); + mComposerClient->setDisplayLayerStack(display, 0); + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2)); ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); @@ -249,4 +254,184 @@ TEST_F(LayerUpdateTest, LayerResizeWorks) { } } +TEST_F(LayerUpdateTest, LayerCropWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before crop"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + Rect cropRect(16, 16, 32, 32); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should crop the foreground surface. + SCOPED_TRACE("after crop"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel( 95, 80, 195, 63, 63); + sc->checkPixel( 80, 95, 195, 63, 63); + sc->checkPixel( 96, 96, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerSetLayerWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before setLayer"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should hide the foreground surface beneath the background. + SCOPED_TRACE("after setLayer"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerShowHideWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before hide"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should hide the foreground surface. + SCOPED_TRACE("after hide, before show"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should show the foreground surface. + SCOPED_TRACE("after show"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerSetAlphaWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before setAlpha"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should set foreground to be 75% opaque. + SCOPED_TRACE("after setAlpha"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 162, 63, 96); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerSetLayerStackWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before setLayerStack"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should hide the foreground surface since it goes to a different + // layer stack. + SCOPED_TRACE("after setLayerStack"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerSetFlagsWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before setFlags"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags( + layer_state_t::eLayerHidden, layer_state_t::eLayerHidden)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should hide the foreground surface + SCOPED_TRACE("after setFlags"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + +TEST_F(LayerUpdateTest, LayerSetMatrixWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before setMatrix"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 91, 96, 195, 63, 63); + sc->checkPixel( 96, 101, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, + -M_SQRT1_2, M_SQRT1_2)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + SCOPED_TRACE("after setMatrix"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 91, 96, 195, 63, 63); + sc->checkPixel( 96, 91, 63, 63, 195); + sc->checkPixel(145, 145, 63, 63, 195); + } +} + } diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk deleted file mode 100644 index d81679eab7..0000000000 --- a/services/surfaceflinger/tests/resize/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - resize.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libgui - -LOCAL_MODULE:= test-resize - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp deleted file mode 100644 index 8b051e8114..0000000000 --- a/services/surfaceflinger/tests/resize/resize.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 <cutils/memory.h> - -#include <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> - -#include <gui/Surface.h> -#include <gui/SurfaceComposerClient.h> - -using namespace android; - -namespace android { - -int main(int argc, char** argv) -{ - // set up the thread-pool - sp<ProcessState> proc(ProcessState::self()); - ProcessState::self()->startThreadPool(); - - // create a client to surfaceflinger - sp<SurfaceComposerClient> client = new SurfaceComposerClient(); - - sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"), - 160, 240, PIXEL_FORMAT_RGB_565, 0); - - sp<Surface> surface = surfaceControl->getSurface(); - - SurfaceComposerClient::openGlobalTransaction(); - surfaceControl->setLayer(100000); - SurfaceComposerClient::closeGlobalTransaction(); - - ANativeWindow_Buffer outBuffer; - surface->lock(&outBuffer, NULL); - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height); - surface->unlockAndPost(); - - surface->lock(&outBuffer); - android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height); - surface->unlockAndPost(); - - SurfaceComposerClient::openGlobalTransaction(); - surfaceControl->setSize(320, 240); - SurfaceComposerClient::closeGlobalTransaction(); - - - IPCThreadState::self()->joinThreadPool(); - - return 0; -} diff --git a/services/surfaceflinger/tests/screencap/Android.mk b/services/surfaceflinger/tests/screencap/Android.mk deleted file mode 100644 index 5cdd1a841c..0000000000 --- a/services/surfaceflinger/tests/screencap/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - screencap.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libskia \ - libui \ - libgui - -LOCAL_MODULE:= test-screencap - -LOCAL_MODULE_TAGS := tests - -LOCAL_C_INCLUDES += \ - external/skia/include/core \ - external/skia/include/effects \ - external/skia/include/images \ - external/skia/src/ports \ - external/skia/include/utils - -include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp deleted file mode 100644 index f842fc3ffb..0000000000 --- a/services/surfaceflinger/tests/screencap/screencap.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> - -#include <binder/IMemory.h> -#include <gui/ISurfaceComposer.h> - -#include <SkImageEncoder.h> -#include <SkBitmap.h> - -using namespace android; - -int main(int argc, char** argv) -{ - if (argc != 2) { - printf("usage: %s path\n", argv[0]); - exit(0); - } - - const String16 name("SurfaceFlinger"); - sp<ISurfaceComposer> composer; - getService(name, &composer); - - sp<IMemoryHeap> heap; - uint32_t w, h; - PixelFormat f; - sp<IBinder> display(composer->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - status_t err = composer->captureScreen(display, &heap, &w, &h, &f, 0, 0); - if (err != NO_ERROR) { - fprintf(stderr, "screen capture failed: %s\n", strerror(-err)); - exit(0); - } - - printf("screen capture success: w=%u, h=%u, pixels=%p\n", - w, h, heap->getBase()); - - printf("saving file as PNG in %s ...\n", argv[1]); - - SkBitmap b; - b.setConfig(SkBitmap::kARGB_8888_Config, w, h); - b.setPixels(heap->getBase()); - SkImageEncoder::EncodeFile(argv[1], b, - SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); - - return 0; -} diff --git a/services/surfaceflinger/tests/transform/Android.mk b/services/surfaceflinger/tests/transform/Android.mk deleted file mode 100644 index 6219dae8be..0000000000 --- a/services/surfaceflinger/tests/transform/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - TransformTest.cpp \ - ../../Transform.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - -LOCAL_MODULE:= test-transform - -LOCAL_MODULE_TAGS := tests - -LOCAL_C_INCLUDES += ../.. - -include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/transform/TransformTest.cpp b/services/surfaceflinger/tests/transform/TransformTest.cpp deleted file mode 100644 index e112c4ee00..0000000000 --- a/services/surfaceflinger/tests/transform/TransformTest.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/Errors.h> -#include "../../Transform.h" - -using namespace android; - -int main(int argc, char **argv) -{ - Transform tr90(Transform::ROT_90); - Transform trFH(Transform::FLIP_H); - Transform trFV(Transform::FLIP_V); - - Transform tr90FH(Transform::ROT_90 | Transform::FLIP_H); - Transform tr90FV(Transform::ROT_90 | Transform::FLIP_V); - - tr90.dump("tr90"); - trFH.dump("trFH"); - trFV.dump("trFV"); - - tr90FH.dump("tr90FH"); - tr90FV.dump("tr90FV"); - - (trFH*tr90).dump("trFH*tr90"); - (trFV*tr90).dump("trFV*tr90"); - - (tr90*trFH).dump("tr90*trFH"); - (tr90*trFV).dump("tr90*trFV"); - - return 0; -} |