diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/Android.mk | 3 | ||||
-rw-r--r-- | libs/gui/CpuConsumer.cpp | 231 | ||||
-rw-r--r-- | libs/gui/tests/Android.mk | 29 | ||||
-rw-r--r-- | libs/gui/tests/CpuConsumer_test.cpp | 579 | ||||
-rw-r--r-- | libs/utils/ZipFileRO.cpp | 4 |
5 files changed, 843 insertions, 3 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index 8bda3aa..a3a715a 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -21,7 +21,8 @@ LOCAL_SRC_FILES:= \ LayerState.cpp \ Surface.cpp \ SurfaceComposerClient.cpp \ - DummyConsumer.cpp + DummyConsumer.cpp \ + CpuConsumer.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp new file mode 100644 index 0000000..48a54c7 --- /dev/null +++ b/libs/gui/CpuConsumer.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "CpuConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Log.h> + +#include <gui/CpuConsumer.h> + +#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +// Get an ID that's unique within this process. +static int32_t createProcessUniqueId() { + static volatile int32_t globalCounter = 0; + return android_atomic_inc(&globalCounter); +} + +CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) : + mMaxLockedBuffers(maxLockedBuffers), + mCurrentLockedBuffers(0) +{ + mName = String8::format("cc-unnamed-%d-%d", getpid(), + createProcessUniqueId()); + + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mBufferPointers[i] = NULL; + } + + mBufferQueue = new BufferQueue(true); + + wp<BufferQueue::ConsumerListener> listener; + sp<BufferQueue::ConsumerListener> proxy; + listener = static_cast<BufferQueue::ConsumerListener*>(this); + proxy = new BufferQueue::ProxyConsumerListener(listener); + + status_t err = mBufferQueue->consumerConnect(proxy); + if (err != NO_ERROR) { + ALOGE("CpuConsumer: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + } else { + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); + mBufferQueue->setConsumerName(mName); + } +} + +CpuConsumer::~CpuConsumer() +{ + Mutex::Autolock _l(mMutex); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + freeBufferLocked(i); + } + mBufferQueue->consumerDisconnect(); + mBufferQueue.clear(); +} + +void CpuConsumer::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + mName = name; + mBufferQueue->setConsumerName(name); +} + +status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { + status_t err; + + if (!nativeBuffer) return BAD_VALUE; + if (mCurrentLockedBuffers == mMaxLockedBuffers) { + return INVALID_OPERATION; + } + + BufferQueue::BufferItem b; + + Mutex::Autolock _l(mMutex); + + err = mBufferQueue->acquireBuffer(&b); + if (err != OK) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + return BAD_VALUE; + } else { + CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + return err; + } + } + + int buf = b.mBuf; + + if (b.mGraphicBuffer != NULL) { + if (mBufferPointers[buf] != NULL) { + CC_LOGE("Reallocation of buffer %d while in consumer use!", buf); + mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + return BAD_VALUE; + } + mBufferSlot[buf] = b.mGraphicBuffer; + } + + err = mBufferSlot[buf]->lock( + GraphicBuffer::USAGE_SW_READ_OFTEN, + b.mCrop, + &mBufferPointers[buf]); + + if (mBufferPointers[buf] != NULL && err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), + err); + return err; + } + + nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]); + nativeBuffer->width = mBufferSlot[buf]->getWidth(); + nativeBuffer->height = mBufferSlot[buf]->getHeight(); + nativeBuffer->format = mBufferSlot[buf]->getPixelFormat(); + nativeBuffer->stride = mBufferSlot[buf]->getStride(); + + nativeBuffer->crop = b.mCrop; + nativeBuffer->transform = b.mTransform; + nativeBuffer->scalingMode = b.mScalingMode; + nativeBuffer->timestamp = b.mTimestamp; + nativeBuffer->frameNumber = b.mFrameNumber; + + mCurrentLockedBuffers++; + + return OK; +} + +status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { + Mutex::Autolock _l(mMutex); + int buf = 0; + status_t err; + + void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); + for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { + if (bufPtr == mBufferPointers[buf]) break; + } + if (buf == BufferQueue::NUM_BUFFER_SLOTS) { + CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); + return BAD_VALUE; + } + + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + return err; + } + err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + if (err == BufferQueue::STALE_BUFFER_SLOT) { + freeBufferLocked(buf); + } else if (err != OK) { + CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__, + buf); + return err; + } + + mCurrentLockedBuffers--; + + return OK; +} + +void CpuConsumer::setFrameAvailableListener( + const sp<FrameAvailableListener>& listener) { + CC_LOGV("setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = listener; +} + + +void CpuConsumer::onFrameAvailable() { + CC_LOGV("onFrameAvailable"); + sp<FrameAvailableListener> listener; + { // scope for the lock + Mutex::Autolock _l(mMutex); + listener = mFrameAvailableListener; + } + + if (listener != NULL) { + CC_LOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +void CpuConsumer::onBuffersReleased() { + CC_LOGV("onBuffersReleased"); + + Mutex::Autolock lock(mMutex); + + uint32_t mask = 0; + mBufferQueue->getReleasedBuffers(&mask); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + if (mask & (1 << i)) { + freeBufferLocked(i); + } + } + +} + +status_t CpuConsumer::freeBufferLocked(int buf) { + status_t err = OK; + + if (mBufferPointers[buf] != NULL) { + CC_LOGW("Buffer %d freed while locked by consumer", buf); + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + } + mCurrentLockedBuffers--; + } + mBufferSlot[buf] = NULL; + return err; +} + +} // namespace android diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 741534b..3a8e356 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -31,6 +31,35 @@ LOCAL_C_INCLUDES := \ # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) +include $(CLEAR_VARS) + +LOCAL_MODULE := CpuConsumer_test + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + CpuConsumer_test.cpp + +LOCAL_SHARED_LIBRARIES := \ + libEGL \ + libGLESv2 \ + libbinder \ + libcutils \ + libgui \ + libstlport \ + libui \ + libutils \ + +LOCAL_C_INCLUDES := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + +# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +# to integrate with auto-test framework. +include $(BUILD_NATIVE_TEST) + # Include subdirectory makefiles # ============================================================ diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp new file mode 100644 index 0000000..7ad60e8 --- /dev/null +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "CpuConsumer_test" +//#define LOG_NDEBUG 0 +//#define LOG_NNDEBUG 0 + +#ifdef LOG_NNDEBUG +#define ALOGVV(...) ALOGV(__VA_ARGS__) +#else +#define ALOGVV(...) ((void)0) +#endif + +#include <gtest/gtest.h> +#include <gui/CpuConsumer.h> +#include <gui/SurfaceTextureClient.h> +#include <ui/GraphicBuffer.h> +#include <utils/String8.h> +#include <utils/Thread.h> +#include <utils/Mutex.h> +#include <utils/Condition.h> + +#include <ui/FramebufferNativeWindow.h> + +namespace android { + +struct CpuConsumerTestParams { + uint32_t width; + uint32_t height; + int maxLockedBuffers; + PixelFormat format; +}; + +::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) { + return os << "[ (" << p.width << ", " << p.height << "), B:" + << p.maxLockedBuffers << ", F:0x" + << ::std::hex << p.format << "]"; +} + +class CpuConsumerTest : public ::testing::TestWithParam<CpuConsumerTestParams> { +protected: + + virtual void SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + CpuConsumerTestParams params = GetParam(); + ALOGV("** Starting test %s (%d x %d, %d, 0x%x)", + test_info->name(), + params.width, params.height, + params.maxLockedBuffers, params.format); + mCC = new CpuConsumer(params.maxLockedBuffers); + String8 name("CpuConsumer_Under_Test"); + mCC->setName(name); + mSTC = new SurfaceTextureClient(mCC->getProducerInterface()); + mANW = mSTC; + } + + virtual void TearDown() { + mANW.clear(); + mSTC.clear(); + mCC.clear(); + } + + class FrameWaiter : public CpuConsumer::FrameAvailableListener { + public: + FrameWaiter(): + mPendingFrames(0) { + } + + void waitForFrame() { + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + mCondition.wait(mMutex); + } + mPendingFrames--; + } + + virtual void onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mCondition.signal(); + } + + int mPendingFrames; + Mutex mMutex; + Condition mCondition; + }; + + // Note that SurfaceTexture will lose the notifications + // onBuffersReleased and onFrameAvailable as there is currently + // no way to forward the events. This DisconnectWaiter will not let the + // disconnect finish until finishDisconnect() is called. It will + // also block until a disconnect is called + class DisconnectWaiter : public BufferQueue::ConsumerListener { + public: + DisconnectWaiter () : + mWaitForDisconnect(false), + mPendingFrames(0) { + } + + void waitForFrame() { + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + mFrameCondition.wait(mMutex); + } + mPendingFrames--; + } + + virtual void onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mFrameCondition.signal(); + } + + virtual void onBuffersReleased() { + Mutex::Autolock lock(mMutex); + while (!mWaitForDisconnect) { + mDisconnectCondition.wait(mMutex); + } + } + + void finishDisconnect() { + Mutex::Autolock lock(mMutex); + mWaitForDisconnect = true; + mDisconnectCondition.signal(); + } + + private: + Mutex mMutex; + + bool mWaitForDisconnect; + Condition mDisconnectCondition; + + int mPendingFrames; + Condition mFrameCondition; + }; + + sp<CpuConsumer> mCC; + sp<SurfaceTextureClient> mSTC; + sp<ANativeWindow> mANW; +}; + +#define ASSERT_NO_ERROR(err, msg) \ + ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err) + +void checkPixel(const CpuConsumer::LockedBuffer &buf, + uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) { + // Ignores components that don't exist for given pixel + switch(buf.format) { + case HAL_PIXEL_FORMAT_RAW_SENSOR: { + String8 msg; + uint16_t *bPtr = (uint16_t*)buf.data; + bPtr += y * buf.stride + x; + // GRBG Bayer mosaic; only check the matching channel + switch( ((y & 1) << 1) | (x & 1) ) { + case 0: // G + case 3: // G + EXPECT_EQ(g, *bPtr); + break; + case 1: // R + EXPECT_EQ(r, *bPtr); + break; + case 2: // B + EXPECT_EQ(b, *bPtr); + break; + } + break; + } + default: { + ADD_FAILURE() << "Unknown format for check:" << buf.format; + break; + } + } +} + +// Fill a YV12 buffer with a multi-colored checkerboard pattern +void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) { + const int blockWidth = w > 16 ? w / 16 : 1; + const int blockHeight = h > 16 ? h / 16 : 1; + const int yuvTexOffsetY = 0; + int yuvTexStrideY = stride; + int yuvTexOffsetV = yuvTexStrideY * h; + int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; + int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; + int yuvTexStrideU = yuvTexStrideV; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + int parityX = (x / blockWidth) & 1; + int parityY = (y / blockHeight) & 1; + unsigned char intensity = (parityX ^ parityY) ? 63 : 191; + buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; + if (x < w / 2 && y < h / 2) { + buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; + if (x * 2 < w / 2 && y * 2 < h / 2) { + buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = + buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = + buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = + buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = + intensity; + } + } + } + } +} + +// Fill a RAW sensor buffer with a multi-colored checkerboard pattern. +// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern +// of [ R, B; G, W] +void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { + ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride); + // Blocks need to be even-width/height, aim for 8-wide otherwise + const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; + const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; + for (int y = 0; y < h; y+=2) { + uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y; + uint16_t *bPtr2 = bPtr1 + stride; + for (int x = 0; x < w; x+=2) { + int blockX = (x / blockWidth ) & 1; + int blockY = (y / blockHeight) & 1; + unsigned short r = (blockX == blockY) ? 1000 : 200; + unsigned short g = blockY ? 1000: 200; + unsigned short b = blockX ? 1000: 200; + // GR row + *bPtr1++ = g; + *bPtr1++ = r; + // BG row + *bPtr2++ = b; + *bPtr2++ = g; + } + } + +} + +void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { + uint32_t w = buf.width; + uint32_t h = buf.height; + const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; + const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; + const int blockRows = h / blockHeight; + const int blockCols = w / blockWidth; + + // Top-left square is red + checkPixel(buf, 0, 0, 1000, 200, 200); + checkPixel(buf, 1, 0, 1000, 200, 200); + checkPixel(buf, 0, 1, 1000, 200, 200); + checkPixel(buf, 1, 1, 1000, 200, 200); + + // One-right square is blue + checkPixel(buf, blockWidth, 0, 200, 200, 1000); + checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000); + checkPixel(buf, blockWidth, 1, 200, 200, 1000); + checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000); + + // One-down square is green + checkPixel(buf, 0, blockHeight, 200, 1000, 200); + checkPixel(buf, 1, blockHeight, 200, 1000, 200); + checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200); + checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200); + + // One-diag square is white + checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000); + checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000); + checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000); + checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000); + + // Test bottom-right pixel + const int maxBlockX = ((w-1) / blockWidth) & 0x1; + const int maxBlockY = ((w-1) / blockHeight) & 0x1; + unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200; + unsigned short maxG = maxBlockY ? 1000: 200; + unsigned short maxB = maxBlockX ? 1000: 200; + checkPixel(buf, w-1, h-1, maxR, maxG, maxB); +} + +// Fill a YV12 buffer with red outside a given rectangle and green inside it. +void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, + const android_native_rect_t& rect) { + const int yuvTexOffsetY = 0; + int yuvTexStrideY = stride; + int yuvTexOffsetV = yuvTexStrideY * h; + int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; + int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; + int yuvTexStrideU = yuvTexStrideV; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + bool inside = rect.left <= x && x < rect.right && + rect.top <= y && y < rect.bottom; + buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64; + if (x < w / 2 && y < h / 2) { + bool inside = rect.left <= 2*x && 2*x < rect.right && + rect.top <= 2*y && 2*y < rect.bottom; + buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16; + buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = + inside ? 16 : 255; + } + } + } +} + +void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { + const size_t PIXEL_SIZE = 4; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + off_t offset = (y * stride + x) * PIXEL_SIZE; + for (int c = 0; c < 4; c++) { + int parityX = (x / (1 << (c+2))) & 1; + int parityY = (y / (1 << (c+2))) & 1; + buf[offset + c] = (parityX ^ parityY) ? 231 : 35; + } + } + } +} + +void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, + uint8_t g, uint8_t b, uint8_t a) { + const size_t PIXEL_SIZE = 4; + for (int y = 0; y < h; y++) { + for (int x = 0; x < h; x++) { + off_t offset = (y * stride + x) * PIXEL_SIZE; + buf[offset + 0] = r; + buf[offset + 1] = g; + buf[offset + 2] = b; + buf[offset + 3] = 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_set_buffers_geometry(anw.get(), + params.width, params.height, params.format); + ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); + + err = native_window_set_usage(anw.get(), + GRALLOC_USAGE_SW_WRITE_OFTEN); + ASSERT_NO_ERROR(err, "set_usage error: "); + + int minUndequeuedBuffers; + err = anw.get()->query(anw.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers); + ASSERT_NO_ERROR(err, "query error: "); + + ALOGVV("Setting buffer count to %d", + maxBufferSlack + 1 + minUndequeuedBuffers); + err = native_window_set_buffer_count(anw.get(), + maxBufferSlack + 1 + minUndequeuedBuffers); + ASSERT_NO_ERROR(err, "set_buffer_count error: "); + +} + +// Produce one frame of image data; assumes format and resolution configuration +// is already done. +void produceOneFrame(const sp<ANativeWindow>& anw, + const CpuConsumerTestParams& params, + int64_t timestamp, uint32_t *stride) { + status_t err; + ANativeWindowBuffer* anb; + ALOGVV("Dequeue buffer from %p", anw.get()); + err = anw->dequeueBuffer(anw.get(), &anb); + ASSERT_NO_ERROR(err, "dequeueBuffer error: "); + + ASSERT_TRUE(anb != NULL); + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + + ALOGVV("Lock buffer from %p", anw.get()); + err = anw->lockBuffer(anw.get(), buf->getNativeBuffer()); + ASSERT_NO_ERROR(err, "lockBuffer error: "); + + *stride = buf->getStride(); + uint8_t* img = NULL; + + ALOGVV("Lock buffer from %p for write", anw.get()); + err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + ASSERT_NO_ERROR(err, "lock error: "); + + switch (params.format) { + case HAL_PIXEL_FORMAT_YV12: + fillYV12Buffer(img, params.width, params.height, *stride); + break; + case HAL_PIXEL_FORMAT_RAW_SENSOR: + fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); + break; + default: + FAIL() << "Unknown pixel format under test!"; + break; + } + ALOGVV("Unlock buffer from %p", anw.get()); + err = buf->unlock(); + ASSERT_NO_ERROR(err, "unlock error: "); + + ALOGVV("Set timestamp to %p", anw.get()); + err = native_window_set_buffers_timestamp(anw.get(), timestamp); + ASSERT_NO_ERROR(err, "set_buffers_timestamp error: "); + + ALOGVV("Queue buffer to %p", anw.get()); + err = anw->queueBuffer(anw.get(), buf->getNativeBuffer()); + ASSERT_NO_ERROR(err, "queueBuffer error:"); +}; + +TEST_P(CpuConsumerTest, FromCpuSingle) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1)); + + // Produce + + const int64_t time = 12345678L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, + &stride)); + + // Consume + + CpuConsumer::LockedBuffer b; + err = mCC->lockNextBuffer(&b); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b.data != NULL); + EXPECT_EQ(params.width, b.width); + EXPECT_EQ(params.height, b.height); + EXPECT_EQ(params.format, b.format); + EXPECT_EQ(stride, b.stride); + EXPECT_EQ(time, b.timestamp); + + checkBayerRawBuffer(b); + mCC->unlockBuffer(b); +} + +TEST_P(CpuConsumerTest, FromCpuManyInQueue) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + const int numInQueue = 5; + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue)); + + // Produce + + const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L}; + uint32_t stride[numInQueue]; + + for (int i = 0; i < numInQueue; i++) { + ALOGV("Producing frame %d", i); + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i], + &stride[i])); + } + + // Consume + + for (int i = 0; i < numInQueue; i++) { + ALOGV("Consuming frame %d", i); + CpuConsumer::LockedBuffer b; + err = mCC->lockNextBuffer(&b); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b.data != NULL); + EXPECT_EQ(params.width, b.width); + EXPECT_EQ(params.height, b.height); + EXPECT_EQ(params.format, b.format); + EXPECT_EQ(stride[i], b.stride); + EXPECT_EQ(time[i], b.timestamp); + + checkBayerRawBuffer(b); + + mCC->unlockBuffer(b); + } +} + +TEST_P(CpuConsumerTest, FromCpuLockMax) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + // Produce + + const int64_t time = 1234L; + uint32_t stride; + + for (int i = 0; i < params.maxLockedBuffers + 1; i++) { + ALOGV("Producing frame %d", i); + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, + &stride)); + } + + // Consume + + CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers]; + for (int i = 0; i < params.maxLockedBuffers; i++) { + ALOGV("Locking frame %d", i); + err = mCC->lockNextBuffer(&b[i]); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b[i].data != NULL); + EXPECT_EQ(params.width, b[i].width); + EXPECT_EQ(params.height, b[i].height); + EXPECT_EQ(params.format, b[i].format); + EXPECT_EQ(stride, b[i].stride); + EXPECT_EQ(time, b[i].timestamp); + + checkBayerRawBuffer(b[i]); + } + + ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); + CpuConsumer::LockedBuffer bTooMuch; + err = mCC->lockNextBuffer(&bTooMuch); + ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks"; + + ALOGV("Unlocking frame 0"); + err = mCC->unlockBuffer(b[0]); + ASSERT_NO_ERROR(err, "Could not unlock buffer 0: "); + + ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers); + err = mCC->lockNextBuffer(&bTooMuch); + ASSERT_NO_ERROR(err, "Did not allow new lock after unlock"); + + ASSERT_TRUE(bTooMuch.data != NULL); + EXPECT_EQ(params.width, bTooMuch.width); + EXPECT_EQ(params.height, bTooMuch.height); + EXPECT_EQ(params.format, bTooMuch.format); + EXPECT_EQ(stride, bTooMuch.stride); + EXPECT_EQ(time, bTooMuch.timestamp); + + checkBayerRawBuffer(bTooMuch); + + ALOGV("Unlocking extra buffer"); + err = mCC->unlockBuffer(bTooMuch); + ASSERT_NO_ERROR(err, "Could not unlock extra buffer: "); + + ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1); + err = mCC->lockNextBuffer(&b[0]); + ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow"; + + for (int i = 1; i < params.maxLockedBuffers; i++) { + mCC->unlockBuffer(b[i]); + } + + delete[] b; + +} + +CpuConsumerTestParams rawTestSets[] = { + { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR} +}; + +INSTANTIATE_TEST_CASE_P(RawTests, + CpuConsumerTest, + ::testing::ValuesIn(rawTestSets)); + +} // namespace android diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index cad7720..db17546 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -118,7 +118,7 @@ ZipFileRO::~ZipFileRO() { */ int ZipFileRO::entryToIndex(const ZipEntryRO entry) const { - long ent = ((long) entry) - kZipEntryAdj; + long ent = ((intptr_t) entry) - kZipEntryAdj; if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) { ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent); return -1; @@ -459,7 +459,7 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const for (int ent = 0; ent < mHashTableSize; ent++) { if (mHashTable[ent].name != NULL) { if (idx-- == 0) - return (ZipEntryRO) (ent + kZipEntryAdj); + return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj); } } |