am 8e4f3c76: am 646e0d5a: Merge "Some webcams output rtp streams but never send any rtcp data in violation of the specs. Attempt to use fake timestamps to be able to play these..." into gingerbread
Merge commit '8e4f3c76dd7f5596fa2fe10bdf008d4c02353160'
* commit '8e4f3c76dd7f5596fa2fe10bdf008d4c02353160':
Some webcams output rtp streams but never send any rtcp data in violation of
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
new file mode 100644
index 0000000..4fbff2a
--- /dev/null
+++ b/include/binder/CursorWindow.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID__DATABASE_WINDOW_H
+#define _ANDROID__DATABASE_WINDOW_H
+
+#include <cutils/log.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+#include <utils/RefBase.h>
+
+#define DEFAULT_WINDOW_SIZE 4096
+#define MAX_WINDOW_SIZE (1024 * 1024)
+#define WINDOW_ALLOCATION_SIZE 4096
+
+#define ROW_SLOT_CHUNK_NUM_ROWS 16
+
+// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
+// with an offset after the rows that points to the next chunk
+#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_WINDOW() if (false)
+#define LOG_WINDOW(...)
+
+#else
+
+#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
+#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)
+
+#endif
+
+
+// When defined to true strings are stored as UTF8, otherwise they're UTF16
+#define WINDOW_STORAGE_UTF8 1
+
+// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
+#define WINDOW_STORAGE_INLINE_NUMERICS 1
+
+namespace android {
+
+typedef struct
+{
+ uint32_t numRows;
+ uint32_t numColumns;
+} window_header_t;
+
+typedef struct
+{
+ uint32_t offset;
+} row_slot_t;
+
+typedef struct
+{
+ uint8_t type;
+ union {
+ double d;
+ int64_t l;
+ struct {
+ uint32_t offset;
+ uint32_t size;
+ } buffer;
+ } data;
+} __attribute__((packed)) field_slot_t;
+
+#define FIELD_TYPE_NULL 0
+#define FIELD_TYPE_INTEGER 1
+#define FIELD_TYPE_FLOAT 2
+#define FIELD_TYPE_STRING 3
+#define FIELD_TYPE_BLOB 4
+
+/**
+ * This class stores a set of rows from a database in a buffer. The begining of the
+ * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
+ * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
+ * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
+ * field_slot_t per column, which has the size, offset, and type of the data for that field.
+ * Note that the data types come from sqlite3.h.
+ */
+class CursorWindow
+{
+public:
+ CursorWindow(size_t maxSize);
+ CursorWindow(){}
+ bool setMemory(const sp<IMemory>&);
+ ~CursorWindow();
+
+ bool initBuffer(bool localOnly);
+ sp<IMemory> getMemory() {return mMemory;}
+
+ size_t size() {return mSize;}
+ uint8_t * data() {return mData;}
+ uint32_t getNumRows() {return mHeader->numRows;}
+ uint32_t getNumColumns() {return mHeader->numColumns;}
+ void freeLastRow() {
+ if (mHeader->numRows > 0) {
+ mHeader->numRows--;
+ }
+ }
+ bool setNumColumns(uint32_t numColumns)
+ {
+ uint32_t cur = mHeader->numColumns;
+ if (cur > 0 && cur != numColumns) {
+ LOGE("Trying to go from %d columns to %d", cur, numColumns);
+ return false;
+ }
+ mHeader->numColumns = numColumns;
+ return true;
+ }
+
+ int32_t freeSpace();
+
+ void clear();
+
+ /**
+ * Allocate a row slot and its directory. The returned
+ * pointer points to the begining of the row's directory
+ * or NULL if there wasn't room. The directory is
+ * initialied with NULL entries for each field.
+ */
+ field_slot_t * allocRow();
+
+ /**
+ * Allocate a portion of the window. Returns the offset
+ * of the allocation, or 0 if there isn't enough space.
+ * If aligned is true, the allocation gets 4 byte alignment.
+ */
+ uint32_t alloc(size_t size, bool aligned = false);
+
+ uint32_t read_field_slot(int row, int column, field_slot_t * slot);
+
+ /**
+ * Copy data into the window at the given offset.
+ */
+ void copyIn(uint32_t offset, uint8_t const * data, size_t size);
+ void copyIn(uint32_t offset, int64_t data);
+ void copyIn(uint32_t offset, double data);
+
+ void copyOut(uint32_t offset, uint8_t * data, size_t size);
+ int64_t copyOutLong(uint32_t offset);
+ double copyOutDouble(uint32_t offset);
+
+ bool putLong(unsigned int row, unsigned int col, int64_t value);
+ bool putDouble(unsigned int row, unsigned int col, double value);
+ bool putNull(unsigned int row, unsigned int col);
+
+ bool getLong(unsigned int row, unsigned int col, int64_t * valueOut);
+ bool getDouble(unsigned int row, unsigned int col, double * valueOut);
+ bool getNull(unsigned int row, unsigned int col, bool * valueOut);
+
+ uint8_t * offsetToPtr(uint32_t offset) {return mData + offset;}
+
+ row_slot_t * allocRowSlot();
+
+ row_slot_t * getRowSlot(int row);
+
+ /**
+ * return NULL if Failed to find rowSlot or
+ * Invalid rowSlot
+ */
+ field_slot_t * getFieldSlotWithCheck(int row, int column);
+ field_slot_t * getFieldSlot(int row, int column)
+ {
+ int fieldDirOffset = getRowSlot(row)->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+ }
+
+private:
+ uint8_t * mData;
+ size_t mSize;
+ size_t mMaxSize;
+ window_header_t * mHeader;
+ sp<IMemory> mMemory;
+
+ /**
+ * Offset of the lowest unused data byte in the array.
+ */
+ uint32_t mFreeOffset;
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 1a1821c..ac69a06 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -43,6 +43,7 @@
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
ePushBuffers = 0x00000200,
+ eOpaque = 0x00000400,
eFXSurfaceNormal = 0x00000000,
eFXSurfaceBlur = 0x00010000,
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 22684db..cef439c 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -94,7 +94,7 @@
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
- friend class Camera;
+ friend class CameraService;
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
@@ -173,11 +173,12 @@
* (eventually this should go away and be replaced by proper APIs)
*/
// camera and camcorder need access to the ISurface binder interface for preview
- friend class Camera;
+ friend class CameraService;
friend class MediaRecorder;
// MediaPlayer needs access to ISurface for display
friend class MediaPlayer;
friend class IOMX;
+ friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
@@ -314,4 +315,3 @@
}; // namespace android
#endif // ANDROID_SF_SURFACE_H
-
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index a3e85a9..c446633 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -72,6 +72,9 @@
GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
uint32_t stride, native_handle_t* handle, bool keepOwnership);
+ // create a buffer from an existing android_native_buffer_t
+ GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership);
+
// return status
status_t initCheck() const;
@@ -137,6 +140,10 @@
GraphicBufferMapper& mBufferMapper;
ssize_t mInitCheck;
int mIndex;
+
+ // If we're wrapping another buffer then this reference will make sure it
+ // doesn't get freed.
+ sp<android_native_buffer_t> mWrappedBuffer;
};
}; // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 3599163..63185d3 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -389,6 +389,14 @@
*/
virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
+ /* Transfers touch focus from the window associated with one channel to the
+ * window associated with the other channel.
+ *
+ * Returns true on success. False if the window did not actually have touch focus.
+ */
+ virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) = 0;
+
/* Registers or unregister input channels that may be used as targets for input events.
* If monitor is true, the channel will receive a copy of all input events.
*
@@ -445,6 +453,9 @@
virtual void setFocusedApplication(const InputApplication* inputApplication);
virtual void setInputDispatchMode(bool enabled, bool frozen);
+ virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel);
+
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
@@ -746,6 +757,9 @@
// Clears the current state.
void clear();
+ // Copies pointer-related parts of the input state to another instance.
+ void copyPointerStateTo(InputState& other) const;
+
private:
struct KeyMemento {
int32_t deviceId;
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index 3b975b4..e1ee8eb 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -37,6 +37,11 @@
}
return *instance;
}
+
+ static bool hasInstance() {
+ Mutex::Autolock _l(sLock);
+ return sInstance != 0;
+ }
protected:
~Singleton() { };
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 13dc500..f9d9f25 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -16,6 +16,7 @@
sources := \
Binder.cpp \
BpBinder.cpp \
+ CursorWindow.cpp \
IInterface.cpp \
IMemory.cpp \
IPCThreadState.cpp \
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
new file mode 100644
index 0000000..bdd4dd6
--- /dev/null
+++ b/libs/binder/CursorWindow.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2006-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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CursorWindow"
+
+#include <utils/Log.h>
+#include <binder/CursorWindow.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+namespace android {
+
+CursorWindow::CursorWindow(size_t maxSize) :
+ mMaxSize(maxSize)
+{
+}
+
+bool CursorWindow::setMemory(const sp<IMemory>& memory)
+{
+ mMemory = memory;
+ mData = (uint8_t *) memory->pointer();
+ if (mData == NULL) {
+ return false;
+ }
+ mHeader = (window_header_t *) mData;
+
+ // Make the window read-only
+ ssize_t size = memory->size();
+ mSize = size;
+ mMaxSize = size;
+ mFreeOffset = size;
+LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData);
+ return true;
+}
+
+bool CursorWindow::initBuffer(bool localOnly)
+{
+ //TODO Use a non-memory dealer mmap region for localOnly
+
+ sp<MemoryHeapBase> heap;
+ heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");
+ if (heap != NULL) {
+ mMemory = new MemoryBase(heap, 0, mMaxSize);
+ if (mMemory != NULL) {
+ mData = (uint8_t *) mMemory->pointer();
+ if (mData) {
+ mHeader = (window_header_t *) mData;
+ mSize = mMaxSize;
+
+ // Put the window into a clean state
+ clear();
+ LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData);
+ return true;
+ }
+ }
+ LOGE("CursorWindow heap allocation failed");
+ return false;
+ } else {
+ LOGE("failed to create the CursorWindow heap");
+ return false;
+ }
+}
+
+CursorWindow::~CursorWindow()
+{
+ // Everything that matters is a smart pointer
+}
+
+void CursorWindow::clear()
+{
+ mHeader->numRows = 0;
+ mHeader->numColumns = 0;
+ mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE;
+ // Mark the first chunk's next 'pointer' as null
+ *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0;
+}
+
+int32_t CursorWindow::freeSpace()
+{
+ int32_t freeSpace = mSize - mFreeOffset;
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+ return freeSpace;
+}
+
+field_slot_t * CursorWindow::allocRow()
+{
+ // Fill in the row slot
+ row_slot_t * rowSlot = allocRowSlot();
+ if (rowSlot == NULL) {
+ return NULL;
+ }
+
+ // Allocate the slots for the field directory
+ size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t);
+ uint32_t fieldDirOffset = alloc(fieldDirSize);
+ if (!fieldDirOffset) {
+ mHeader->numRows--;
+ LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows);
+ return NULL;
+ }
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset);
+ memset(fieldDir, 0x0, fieldDirSize);
+
+LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset);
+ rowSlot->offset = fieldDirOffset;
+
+ return fieldDir;
+}
+
+uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned)
+{
+ int32_t size;
+ uint32_t padding;
+ if (aligned) {
+ // 4 byte alignment
+ padding = 4 - (mFreeOffset & 0x3);
+ } else {
+ padding = 0;
+ }
+
+ size = requestedSize + padding;
+
+ if (size > freeSpace()) {
+ LOGV("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size,
+ freeSpace(), mHeader->numRows);
+ // Only grow the window if the first row doesn't fit
+ if (mHeader->numRows > 1) {
+ LOGV("not growing since there are already %d row(s), max size %d", mHeader->numRows,
+ mMaxSize);
+ return 0;
+ }
+
+ // Find a new size that will fit the allocation
+ int allocated = mSize - freeSpace();
+ int newSize = mSize + WINDOW_ALLOCATION_SIZE;
+ while (size > (newSize - allocated)) {
+ newSize += WINDOW_ALLOCATION_SIZE;
+ if (newSize > mMaxSize) {
+ LOGE("Attempting to grow window beyond max size (%d)", mMaxSize);
+ return 0;
+ }
+ }
+LOG_WINDOW("found size %d", newSize);
+ mSize = newSize;
+ }
+
+ uint32_t offset = mFreeOffset + padding;
+ mFreeOffset += size;
+ return offset;
+}
+
+row_slot_t * CursorWindow::getRowSlot(int row)
+{
+ LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+ int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+ for (int i = 0; i < chunkNum; i++) {
+ rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset)));
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+ LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+}
+
+row_slot_t * CursorWindow::allocRowSlot()
+{
+ int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos);
+ for (int i = 0; i < chunkNum; i++) {
+ uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset));
+LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset);
+ if (nextChunkOffset == 0) {
+ // Allocate a new row chunk
+ nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true);
+ if (nextChunkOffset == 0) {
+ return NULL;
+ }
+ rowChunk = offsetToPtr(nextChunkOffset);
+LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk);
+ *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData;
+ // Mark the new chunk's next 'pointer' as null
+ *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0;
+ } else {
+LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset);
+ rowChunk = offsetToPtr(nextChunkOffset);
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ }
+ mHeader->numRows++;
+
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+}
+
+field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ return NULL;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return NULL;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return NULL;
+ }
+ int fieldDirOffset = rowSlot->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+}
+
+uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ return -1;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return -1;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return -1;
+ }
+LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset);
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset);
+LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type);
+
+ // Copy the data to the out param
+ slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset;
+ slotOut->data.buffer.size = fieldDir[column].data.buffer.size;
+ slotOut->type = fieldDir[column].type;
+ return 0;
+}
+
+void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(mData + offset, data, size);
+}
+
+void CursorWindow::copyIn(uint32_t offset, int64_t data)
+{
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t));
+}
+
+void CursorWindow::copyIn(uint32_t offset, double data)
+{
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(double));
+}
+
+void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(data, mData + offset, size);
+}
+
+int64_t CursorWindow::copyOutLong(uint32_t offset)
+{
+ int64_t value;
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(&value, mData + offset, sizeof(int64_t));
+ return value;
+}
+
+double CursorWindow::copyOutDouble(uint32_t offset)
+{
+ double value;
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(&value, mData + offset, sizeof(double));
+ return value;
+}
+
+bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.l = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(int64_t);
+#endif
+ fieldSlot->type = FIELD_TYPE_INTEGER;
+ return true;
+}
+
+bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.d = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(double);
+#endif
+ fieldSlot->type = FIELD_TYPE_FLOAT;
+ return true;
+}
+
+bool CursorWindow::putNull(unsigned int row, unsigned int col)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ fieldSlot->type = FIELD_TYPE_NULL;
+ fieldSlot->data.buffer.offset = 0;
+ fieldSlot->data.buffer.size = 0;
+ return true;
+}
+
+bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.l;
+#else
+ *valueOut = copyOutLong(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.d;
+#else
+ *valueOut = copyOutDouble(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ if (fieldSlot->type != FIELD_TYPE_NULL) {
+ *valueOut = false;
+ } else {
+ *valueOut = true;
+ }
+ return true;
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 4bc5d9e..8f583f0 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -380,11 +380,6 @@
{
SharedBufferStack& stack( *mSharedStack );
- if (stack.head == tail && stack.available == mNumBuffers) {
- LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
- tail, stack.head, stack.available, stack.queued);
- }
-
RWLock::AutoRLock _rd(mLock);
const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index d44aab9..0994980 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -364,6 +364,13 @@
height = surface->mHeight;
format = surface->mFormat;
flags = surface->mFlags;
+ } else if (surface != 0 && surface->mSurface != 0) {
+ LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
+ "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
+ "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
+ surface->mSurface.get(), surface->mIdentity, surface->mWidth,
+ surface->mHeight, surface->mFormat, surface->mFlags,
+ surface->mInitCheck);
}
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
parcel->writeInt32(identity);
@@ -438,21 +445,15 @@
mSharedBufferClient = new SharedBufferClient(
mClient.getSharedClient(), token, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(token);
+ } else {
+ LOGW("Not initializing the shared buffer client because token = %d",
+ token);
}
}
}
Surface::~Surface()
{
- // this is a client-side operation, the surface is destroyed, unmap
- // its buffers in this process.
- size_t size = mBuffers.size();
- for (size_t i=0 ; i<size ; i++) {
- if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
- getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
- }
- }
-
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mBuffers.clear();
@@ -1011,7 +1012,20 @@
int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
{
- return buffer->getIndex();
+ int idx = buffer->getIndex();
+ if (idx < 0) {
+ // The buffer doesn't have an index set. See if the handle the same as
+ // one of the buffers for which we do know the index. This can happen
+ // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+ // was dequeued from an ANativeWindow.
+ for (int i = 0; i < mBuffers.size(); i++) {
+ if (buffer->handle == mBuffers[i]->handle) {
+ idx = mBuffers[i]->getIndex();
+ break;
+ }
+ }
+ }
+ return idx;
}
status_t Surface::getBufferLocked(int index,
@@ -1025,7 +1039,6 @@
// free the current buffer
sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
if (currentBuffer != 0) {
- getBufferMapper().unregisterBuffer(currentBuffer->handle);
currentBuffer.clear();
}
@@ -1033,7 +1046,7 @@
LOGE_IF(buffer==0,
"ISurface::getBuffer(%d, %08x) returned NULL",
index, usage);
- if (buffer != 0) { // this should never happen by construction
+ if (buffer != 0) { // this should always happen by construction
LOGE_IF(buffer->handle == NULL,
"Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
"returned a buffer with a null handle",
@@ -1041,13 +1054,8 @@
err = mSharedBufferClient->getStatus();
LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
if (!err && buffer->handle != NULL) {
- err = getBufferMapper().registerBuffer(buffer->handle);
- LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
- err, strerror(-err));
- if (err == NO_ERROR) {
- currentBuffer = buffer;
- currentBuffer->setIndex(index);
- }
+ currentBuffer = buffer;
+ currentBuffer->setIndex(index);
} else {
err = err<0 ? err : status_t(NO_MEMORY);
}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 519c277..436e064 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -77,6 +77,19 @@
handle = inHandle;
}
+GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
+{
+ width = buffer->width;
+ height = buffer->height;
+ stride = buffer->stride;
+ format = buffer->format;
+ usage = buffer->usage;
+ handle = buffer->handle;
+}
+
GraphicBuffer::~GraphicBuffer()
{
if (handle) {
@@ -87,12 +100,14 @@
void GraphicBuffer::free_handle()
{
if (mOwner == ownHandle) {
+ mBufferMapper.unregisterBuffer(handle);
native_handle_close(handle);
native_handle_delete(const_cast<native_handle*>(handle));
} else if (mOwner == ownData) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
}
+ mWrappedBuffer = 0;
}
status_t GraphicBuffer::initCheck() const {
@@ -253,6 +268,11 @@
}
mOwner = ownHandle;
+
+ if (handle != 0) {
+ mBufferMapper.registerBuffer(handle);
+ }
+
return NO_ERROR;
}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 6ba19d7..84c3db8 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -2612,6 +2612,82 @@
}
}
+bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) {
+#if DEBUG_FOCUS
+ LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
+ fromChannel->getName().string(), toChannel->getName().string());
+#endif
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ const InputWindow* fromWindow = getWindowLocked(fromChannel);
+ const InputWindow* toWindow = getWindowLocked(toChannel);
+ if (! fromWindow || ! toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Cannot transfer focus because from or to window not found.");
+#endif
+ return false;
+ }
+ if (fromWindow == toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Trivial transfer to same window.");
+#endif
+ return true;
+ }
+
+ bool found = false;
+ for (size_t i = 0; i < mTouchState.windows.size(); i++) {
+ const TouchedWindow& touchedWindow = mTouchState.windows[i];
+ if (touchedWindow.window == fromWindow) {
+ int32_t oldTargetFlags = touchedWindow.targetFlags;
+ BitSet32 pointerIds = touchedWindow.pointerIds;
+
+ mTouchState.windows.removeAt(i);
+
+ int32_t newTargetFlags = 0;
+ if (oldTargetFlags & InputTarget::FLAG_FOREGROUND) {
+ newTargetFlags |= InputTarget::FLAG_FOREGROUND;
+ if (toWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) {
+ newTargetFlags |= InputTarget::FLAG_SPLIT;
+ }
+ }
+ mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+
+ found = true;
+ break;
+ }
+ }
+
+ if (! found) {
+#if DEBUG_FOCUS
+ LOGD("Focus transfer failed because from window did not have focus.");
+#endif
+ return false;
+ }
+
+ ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
+ ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
+ if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
+ sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+
+ fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+ synthesizeCancelationEventsForConnectionLocked(fromConnection,
+ InputState::CANCEL_POINTER_EVENTS,
+ "transferring touch focus from this window to another window");
+ }
+
+#if DEBUG_FOCUS
+ logDispatchStateLocked();
+#endif
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+ return true;
+}
+
void InputDispatcher::logDispatchStateLocked() {
String8 dump;
dumpDispatchStateLocked(dump);
@@ -3338,6 +3414,24 @@
mMotionMementos.clear();
}
+void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+ for (size_t j = 0; j < other.mMotionMementos.size(); ) {
+ const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+ if (memento.deviceId == otherMemento.deviceId
+ && memento.source == otherMemento.source) {
+ other.mMotionMementos.removeAt(j);
+ } else {
+ j += 1;
+ }
+ }
+ other.mMotionMementos.push(memento);
+ }
+ }
+}
+
bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
CancelationOptions options) {
switch (options) {
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 8345cc3..91e7df3 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -317,6 +317,12 @@
mStringPoolSize =
(mHeader->header.size-mHeader->stringsStart)/charSize;
} else {
+ // check invariant: styles starts before end of data
+ if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ LOGW("Bad style block: style block starts at %d past data size of %d\n",
+ (int)mHeader->stylesStart, (int)mHeader->header.size);
+ return (mError=BAD_TYPE);
+ }
// check invariant: styles follow the strings
if (mHeader->stylesStart <= mHeader->stringsStart) {
LOGW("Bad style block: style block starts at %d, before strings at %d\n",
@@ -1878,6 +1884,12 @@
outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
outName->name = grp->basePackage->keyStrings.stringAt(
dtohl(entry->key.index), &outName->nameLen);
+
+ // If we have a bad index for some reason, we should abort.
+ if (outName->type == NULL || outName->name == NULL) {
+ return false;
+ }
+
return true;
}
@@ -2609,6 +2621,24 @@
*outType = *defType;
}
*outName = String16(p, end-p);
+ if(**outPackage == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource package cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outType == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource type cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outName == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource id cannot be an empty string";
+ }
+ return false;
+ }
return true;
}
@@ -4127,13 +4157,16 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
- resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen),
- dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+ resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ } else {
+ printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
+ }
}
}
for (size_t configIndex=0; configIndex<NTC; configIndex++) {
@@ -4340,11 +4373,14 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" resource 0x%08x %s:%s/%s: ", resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" resource 0x%08x %s:%s/%s: ", resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ } else {
+ printf(" INVALID RESOURCE 0x%08x: ", resID);
+ }
if ((thisOffset&0x3) != 0) {
printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
continue;
@@ -4402,18 +4438,19 @@
print_value(pkg, value);
} else if (bagPtr != NULL) {
const int N = dtohl(bagPtr->count);
- const ResTable_map* mapPtr = (const ResTable_map*)
- (((const uint8_t*)ent) + esize);
+ const uint8_t* baseMapPtr = (const uint8_t*)ent;
+ size_t mapOffset = esize;
+ const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
printf(" Parent=0x%08x, Count=%d\n",
dtohl(bagPtr->parent.ident), N);
- for (int i=0; i<N; i++) {
+ for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
printf(" #%i (Key=0x%08x): ",
i, dtohl(mapPtr->name.ident));
value.copyFrom_dtoh(mapPtr->value);
print_value(pkg, value);
const size_t size = dtohs(mapPtr->value.size);
- mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
- + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
+ mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
+ mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
}
}
}
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 460b74f..239dc05 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -1969,7 +1969,7 @@
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
// TODO: eglSwapInterval()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 2d1a278..bc944a0 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -59,6 +59,8 @@
"EGL_KHR_image "
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
+ "EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_fence_sync "
"EGL_ANDROID_image_native_buffer "
"EGL_ANDROID_swap_rectangle "
;
@@ -243,9 +245,23 @@
EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
};
+struct egl_sync_t : public egl_object_t
+{
+ typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
+
+ egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync)
+ : dpy(dpy), context(context), sync(sync)
+ {
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLSyncKHR sync;
+};
+
typedef egl_surface_t::Ref SurfaceRef;
typedef egl_context_t::Ref ContextRef;
typedef egl_image_t::Ref ImageRef;
+typedef egl_sync_t::Ref SyncRef;
struct tls_t
{
@@ -483,6 +499,11 @@
return egl_to_native_cast<egl_image_t>(image);
}
+static inline
+egl_sync_t* get_sync(EGLSyncKHR sync) {
+ return egl_to_native_cast<egl_sync_t>(sync);
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp)
@@ -1790,6 +1811,111 @@
return EGL_TRUE;
}
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 5
+// ----------------------------------------------------------------------------
+
+
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
+{
+ EGLContext ctx = eglGetCurrentContext();
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_NO_SYNC_KHR;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+ EGLSyncKHR result = EGL_NO_SYNC_KHR;
+ if (c->cnx->egl.eglCreateSyncKHR) {
+ EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
+ dp->disp[c->impl].dpy, type, attrib_list);
+ if (sync == EGL_NO_SYNC_KHR)
+ return sync;
+ result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
+ }
+ return (EGLSyncKHR)result;
+}
+
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglDestroySyncKHR) {
+ return c->cnx->egl.eglDestroySyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglClientWaitSyncKHR) {
+ return c->cnx->egl.eglClientWaitSyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglGetSyncAttribKHR) {
+ return c->cnx->egl.eglGetSyncAttribKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+ }
+
+ return EGL_FALSE;
+}
// ----------------------------------------------------------------------------
// ANDROID extensions
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 5d89287..63c3c19 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -51,6 +51,13 @@
EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+/* EGL_EGLEXT_VERSION 5 */
+
+EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR)
+EGL_ENTRY(EGLint, eglClientWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)
+EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLint *)
+
/* ANDROID extensions */
EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 18dd483..fee4609 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -39,6 +39,8 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
+#define DEBUG_CALL_GL_API 0
+
#if USE_FAST_TLS_KEY
#ifdef HAVE_ARM_TLS_REGISTER
@@ -74,10 +76,24 @@
#define API_ENTRY(_api) _api
+#if DEBUG_CALL_GL_API
+
#define CALL_GL_API(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- _c->_api(__VA_ARGS__)
-
+ _c->_api(__VA_ARGS__); \
+ GLenum status = GL_NO_ERROR; \
+ while ((status = glGetError()) != GL_NO_ERROR) { \
+ LOGD("[" #_api "] 0x%x", status); \
+ }
+
+#else
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ _c->_api(__VA_ARGS__);
+
+#endif
+
#define CALL_GL_API_RETURN(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
return _c->_api(__VA_ARGS__)
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
new file mode 100644
index 0000000..37647ca
--- /dev/null
+++ b/opengl/tests/gl_perf/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl2_perf.cpp \
+ filltest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl2_perf
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
new file mode 100644
index 0000000..a069f67
--- /dev/null
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -0,0 +1,298 @@
+/*
+ * 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 "fragment_shaders.cpp"
+
+FILE * fOut = NULL;
+void ptSwap();
+
+static char gCurrentTestName[1024];
+static uint32_t gWidth = 0;
+static uint32_t gHeight = 0;
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ LOGE("after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+enum {
+ A_POS,
+ A_COLOR,
+ A_TEX0,
+ A_TEX1
+};
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader v");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader p");
+
+ glBindAttribLocation(program, A_POS, "a_pos");
+ glBindAttribLocation(program, A_COLOR, "a_color");
+ glBindAttribLocation(program, A_TEX0, "a_tex0");
+ glBindAttribLocation(program, A_TEX1, "a_tex1");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ LOGE("Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ checkGlError("createProgram");
+ glUseProgram(program);
+ return program;
+}
+
+uint64_t getTime() {
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+uint64_t gTime;
+void startTimer() {
+ gTime = getTime();
+}
+
+
+static void endTimer(int count) {
+ uint64_t t2 = getTime();
+ double delta = ((double)(t2 - gTime)) / 1000000000;
+ double pixels = (gWidth * gHeight) * count;
+ double mpps = pixels / delta / 1000000;
+ double dc60 = ((double)count) / delta / 60;
+
+ if (fOut) {
+ fprintf(fOut, "%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
+ fflush(fOut);
+ } else {
+ printf("%s, %f, %f\n", gCurrentTestName, mpps, dc60);
+ }
+ LOGI("%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
+}
+
+
+static const char gVertexShader[] =
+ "attribute vec4 a_pos;\n"
+ "attribute vec4 a_color;\n"
+ "attribute vec2 a_tex0;\n"
+ "attribute vec2 a_tex1;\n"
+ "varying vec4 v_color;\n"
+ "varying vec2 v_tex0;\n"
+ "varying vec2 v_tex1;\n"
+ "uniform vec2 u_texOff;\n"
+
+ "void main() {\n"
+ " v_color = a_color;\n"
+ " v_tex0 = a_tex0;\n"
+ " v_tex1 = a_tex1;\n"
+ " v_tex0.x += u_texOff.x;\n"
+ " v_tex1.y += u_texOff.y;\n"
+ " gl_Position = a_pos;\n"
+ "}\n";
+
+static void setupVA() {
+ static const float vtx[] = {
+ -1.0f,-1.0f,
+ 1.0f,-1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f };
+ static const float color[] = {
+ 1.0f,0.0f,1.0f,1.0f,
+ 0.0f,0.0f,1.0f,1.0f,
+ 1.0f,1.0f,0.0f,1.0f,
+ 1.0f,1.0f,1.0f,1.0f };
+ static const float tex0[] = {
+ 0.0f,0.0f,
+ 1.0f,0.0f,
+ 0.0f,1.0f,
+ 1.0f,1.0f };
+ static const float tex1[] = {
+ 1.0f,0.0f,
+ 1.0f,1.0f,
+ 0.0f,1.0f,
+ 0.0f,0.0f };
+
+ glEnableVertexAttribArray(A_POS);
+ glEnableVertexAttribArray(A_COLOR);
+ glEnableVertexAttribArray(A_TEX0);
+ glEnableVertexAttribArray(A_TEX1);
+
+ glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx);
+ glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color);
+ glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0);
+ glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1);
+}
+
+static void randUniform(int pgm, const char *var) {
+ int loc = glGetUniformLocation(pgm, var);
+ if (loc >= 0) {
+ float x = ((float)rand()) / RAND_MAX;
+ float y = ((float)rand()) / RAND_MAX;
+ float z = ((float)rand()) / RAND_MAX;
+ float w = ((float)rand()) / RAND_MAX;
+ glUniform4f(loc, x, y, z, w);
+ }
+}
+
+static void doLoop(bool warmup, int pgm, uint32_t passCount) {
+ if (warmup) {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ ptSwap();
+ glFinish();
+ return;
+ }
+
+ startTimer();
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ for (uint32_t ct=0; ct < passCount; ct++) {
+ int loc = glGetUniformLocation(pgm, "u_texOff");
+ glUniform2f(loc, ((float)ct) / passCount, ((float)ct) / 2.f / passCount);
+
+ randUniform(pgm, "u_color");
+ randUniform(pgm, "u_0");
+ randUniform(pgm, "u_1");
+ randUniform(pgm, "u_2");
+ randUniform(pgm, "u_3");
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ ptSwap();
+ glFinish();
+ endTimer(passCount);
+}
+
+
+static uint32_t rgb(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint32_t ret = 0xff000000;
+ ret |= r & 0xff;
+ ret |= (g & 0xff) << 8;
+ ret |= (b & 0xff) << 16;
+ return ret;
+}
+
+void genTextures() {
+ uint32_t *m = (uint32_t *)malloc(1024*1024*4);
+ for (int y=0; y < 1024; y++){
+ for (int x=0; x < 1024; x++){
+ m[y*1024 + x] = rgb(x, (((x+y) & 0xff) == 0x7f) * 0xff, y);
+ }
+ }
+ glBindTexture(GL_TEXTURE_2D, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ for (int y=0; y < 16; y++){
+ for (int x=0; x < 16; x++){
+ m[y*16 + x] = rgb(x << 4, (((x+y) & 0xf) == 0x7) * 0xff, y << 4);
+ }
+ }
+ glBindTexture(GL_TEXTURE_2D, 2);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ free(m);
+}
+
+static void doSingleTest(uint32_t pgmNum, int tex) {
+ const char *pgmTxt = gFragmentTests[pgmNum]->txt;
+ int pgm = createProgram(gVertexShader, pgmTxt);
+ if (!pgm) {
+ printf("error running test\n");
+ return;
+ }
+ int loc = glGetUniformLocation(pgm, "u_tex0");
+ if (loc >= 0) glUniform1i(loc, 0);
+ loc = glGetUniformLocation(pgm, "u_tex1");
+ if (loc >= 0) glUniform1i(loc, 1);
+
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glActiveTexture(GL_TEXTURE0);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ glDisable(GL_BLEND);
+ //sprintf(str2, "%i, %i, %i, %i, %i, 0",
+ //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+ //doLoop(true, pgm, w, h, str2);
+ //doLoop(false, pgm, w, h, str2);
+
+ glEnable(GL_BLEND);
+ sprintf(gCurrentTestName, "%s, %i, %i, 1", gFragmentTests[pgmNum]->name, pgmNum, tex);
+ doLoop(true, pgm, 100);
+ doLoop(false, pgm, 100);
+}
+
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
new file mode 100644
index 0000000..3f8faca
--- /dev/null
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <string.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Timers.h>
+#include <EGL/egl.h>
+#include <utils/Log.h>
+
+
+using namespace android;
+
+
+#include "fill_common.cpp"
+
+
+bool doTest(uint32_t w, uint32_t h) {
+ gWidth = w;
+ gHeight = h;
+ setupVA();
+ genTextures();
+
+ printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+
+ for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+ doSingleTest(num, 2);
+ if (gFragmentTests[num]->texCount) {
+ doSingleTest(num, 1);
+ }
+ }
+
+ exit(0);
+ return true;
+}
diff --git a/opengl/tests/gl_perf/fragment_shaders.cpp b/opengl/tests/gl_perf/fragment_shaders.cpp
new file mode 100644
index 0000000..79d5ead
--- /dev/null
+++ b/opengl/tests/gl_perf/fragment_shaders.cpp
@@ -0,0 +1,139 @@
+
+typedef struct FragmentTestRec {
+ const char * name;
+ uint32_t texCount;
+ const char * txt;
+} FragmentTest;
+
+static FragmentTest fpFill = {
+ "Solid color", 0,
+
+ "precision mediump float;\n"
+ "uniform vec4 u_color;\n"
+ "void main() {\n"
+ " gl_FragColor = u_color;\n"
+ "}\n"
+};
+
+static FragmentTest fpGradient = {
+ "Solid gradient", 0,
+
+ "precision mediump float;\n"
+ "varying lowp vec4 v_color;\n"
+ "void main() {\n"
+ " gl_FragColor = v_color;\n"
+ "}\n"
+};
+
+static FragmentTest fpCopyTex = {
+ "Texture copy", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(u_tex0, v_tex0);\n"
+ "}\n"
+};
+
+static FragmentTest fpCopyTexGamma = {
+ "Texture copy with gamma", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " t.rgb = pow(t.rgb, vec3(1.4, 1.4, 1.4));\n"
+ " gl_FragColor = t;\n"
+ "}\n"
+};
+
+static FragmentTest fpTexSpec = {
+ "Texture spec", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " float simSpec = dot(gl_FragCoord.xyz, gl_FragCoord.xyz);\n"
+ " simSpec = pow(clamp(simSpec, 0.1, 1.0), 40.0);\n"
+ " gl_FragColor = t + vec4(simSpec, simSpec, simSpec, simSpec);\n"
+ "}\n"
+};
+
+static FragmentTest fpDepTex = {
+ "Dependent Lookup", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " t += texture2D(u_tex0, t.xy);\n"
+ " gl_FragColor = t;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateConstantTex = {
+ "Texture modulate constant", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "uniform vec4 u_color;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= u_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateVaryingTex = {
+ "Texture modulate gradient", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "varying lowp vec4 v_color;\n"
+ "uniform sampler2D u_tex0;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= v_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateVaryingConstantTex = {
+ "Texture modulate gradient constant", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "varying lowp vec4 v_color;\n"
+ "uniform sampler2D u_tex0;\n"
+ "uniform vec4 u_color;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= v_color;\n"
+ " c *= u_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest *gFragmentTests[] = {
+ &fpFill,
+ &fpGradient,
+ &fpCopyTex,
+ &fpCopyTexGamma,
+ &fpTexSpec,
+ &fpDepTex,
+ &fpModulateConstantTex,
+ &fpModulateVaryingTex,
+ &fpModulateVaryingConstantTex,
+
+};
+
+static const size_t gFragmentTestCount = sizeof(gFragmentTests) / sizeof(gFragmentTests[0]);
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
new file mode 100644
index 0000000..9dfcf1c
--- /dev/null
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+bool doTest(uint32_t w, uint32_t h);
+
+static EGLDisplay dpy;
+static EGLSurface surface;
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLint w, h;
+
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+ if (returnValue) {
+ printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+ return 0;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 0;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 0;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ glViewport(0, 0, w, h);
+
+ for (;;) {
+ doTest(w, h);
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+ }
+
+ return 0;
+}
+
+void ptSwap() {
+ eglSwapBuffers(dpy, surface);
+}
+
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
new file mode 100644
index 0000000..dd75a74
--- /dev/null
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -0,0 +1,54 @@
+#########################################################################
+# OpenGL ES Perf App
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GLPerf
+
+LOCAL_JNI_SHARED_LIBRARIES := libglperf
+
+# Run on Eclair
+LOCAL_SDK_VERSION := 7
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+# Optional tag would mean it doesn't get installed by default
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+ gl_code.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libEGL \
+ libGLESv2
+
+LOCAL_MODULE := libglperf
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl_perfapp/AndroidManifest.xml b/opengl/tests/gl_perfapp/AndroidManifest.xml
new file mode 100644
index 0000000..305d95f
--- /dev/null
+++ b/opengl/tests/gl_perfapp/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.glperf"
+ android:versionName="1.0.0" android:versionCode="10000" >
+ <uses-sdk android:targetSdkVersion="7" android:minSdkVersion="7" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/glperf_activity">
+ <activity android:name="GLPerfActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
new file mode 100644
index 0000000..f993371
--- /dev/null
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -0,0 +1,103 @@
+// OpenGL ES 2.0 code
+
+#include <nativehelper/jni.h>
+#define LOG_TAG "GLPerf gl_code.cpp"
+#include <utils/Log.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Timers.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "../../gl_perf/fill_common.cpp"
+
+
+//////////////////////////
+
+// Width and height of the screen
+
+uint32_t w;
+uint32_t h;
+
+// The stateClock starts at zero and increments by 1 every time we draw a frame. It is used to control which phase of the test we are in.
+
+int stateClock;
+const int doLoopStates = 2;
+const int doSingleTestStates = 2;
+bool done;
+
+// Saves the parameters of the test (so we can print them out when we finish the timing.)
+
+
+int pgm;
+
+void ptSwap() {
+}
+
+void doTest() {
+ uint32_t testNum = stateClock >> 2;
+ int texSize = ((stateClock >> 1) & 0x1) + 1;
+
+ if (testNum >= gFragmentTestCount) {
+ LOGI("done\n");
+ if (fOut) {
+ fclose(fOut);
+ fOut = NULL;
+ }
+ done = true;
+ return;
+ }
+
+ // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
+
+// for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+ doSingleTest(testNum, texSize);
+}
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
+};
+
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ gWidth = width;
+ gHeight = height;
+ if (!done) {
+ stateClock = 0;
+ done = false;
+ setupVA();
+ genTextures();
+ const char* fileName = "/sdcard/glperf.csv";
+ if (fOut != NULL) {
+ LOGI("Closing partially written output.n");
+ fclose(fOut);
+ fOut = NULL;
+ }
+ LOGI("Writing to: %s\n",fileName);
+ fOut = fopen(fileName, "w");
+ if (fOut == NULL) {
+ LOGE("Could not open: %s\n", fileName);
+ }
+
+ LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+ if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
+{
+ if (! done) {
+ if (stateClock > 0 && ((stateClock & 1) == 0)) {
+ //endTimer(100);
+ }
+ doTest();
+ stateClock++;
+ } else {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ }
+}
diff --git a/opengl/tests/gl_perfapp/res/values/strings.xml b/opengl/tests/gl_perfapp/res/values/strings.xml
new file mode 100644
index 0000000..dc21075
--- /dev/null
+++ b/opengl/tests/gl_perfapp/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="glperf_activity">GLPerf</string>
+
+</resources>
+
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java
new file mode 100644
index 0000000..e3f3abf
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class GLPerfActivity extends Activity {
+
+ GLPerfView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mView = new GLPerfView(getApplication());
+ setContentView(mView);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java
new file mode 100644
index 0000000..89a0e54
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+
+// Wrapper for native library
+
+public class GLPerfLib {
+
+ static {
+ System.loadLibrary("glperf");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+ public static native void init(int width, int height);
+ public static native void step();
+}
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java
new file mode 100644
index 0000000..4ce4a4d
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GLPerfView extends GLSurfaceView {
+ private static String TAG = "GLPerfView";
+
+ public GLPerfView(Context context) {
+ super(context);
+ init(false, 0, 0);
+ }
+
+ public GLPerfView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ private void init(boolean translucent, int depth, int stencil) {
+ setEGLContextFactory(new ContextFactory());
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8,8,8,8, depth, stencil) :
+ new ConfigChooser(5,6,5,0, depth, stencil));
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+ // printConfigs(egl, display, configs);
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ EGLConfig closestConfig = null;
+ int closestDistance = 1000;
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+ if (d >= mDepthSize && s>= mStencilSize) {
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+ int distance = Math.abs(r - mRedSize)
+ + Math.abs(g - mGreenSize)
+ + Math.abs(b - mBlueSize)
+ + Math.abs(a - mAlphaSize);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestConfig = config;
+ }
+ }
+ }
+ return closestConfig;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+ public void onDrawFrame(GL10 gl) {
+ GLPerfLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLPerfLib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+}
+
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
new file mode 100644
index 0000000..500abf3
--- /dev/null
+++ b/opengl/tests/testFramerate/Android.mk
@@ -0,0 +1,19 @@
+#########################################################################
+# Test framerate and look for hiccups
+#########################################################################
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestFramerate
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testFramerate/AndroidManifest.xml b/opengl/tests/testFramerate/AndroidManifest.xml
new file mode 100644
index 0000000..e04342c
--- /dev/null
+++ b/opengl/tests/testFramerate/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testframerate">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+
+ <application
+ android:label="@string/testFramerate_activity">
+ <activity android:name="TestFramerateActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testFramerate/res/values/strings.xml b/opengl/tests/testFramerate/res/values/strings.xml
new file mode 100644
index 0000000..e6b3088
--- /dev/null
+++ b/opengl/tests/testFramerate/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="testFramerate_activity">TestFramerate</string>
+
+</resources>
+
diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java
new file mode 100644
index 0000000..cbe279b
--- /dev/null
+++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testframerate;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class TestFramerateActivity extends Activity {
+
+ TestFramerateView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestFramerateView(getApplication());
+ setContentView(mView);
+ mView.setFocusableInTouchMode(true);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java
new file mode 100644
index 0000000..f3fb5de
--- /dev/null
+++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testframerate;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.SystemProperties;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+class TestFramerateView extends GLSurfaceView {
+ private static String TAG = "TestFramerateView";
+
+ public TestFramerateView(Context context) {
+ super(context);
+ setEGLContextClientVersion(2);
+ setRenderer(new Renderer());
+ }
+
+ private long mLastTime_us = 0;
+ private long mNumShortFramesElapsed = 0;
+ private void registerTime(long now_us) {
+ long longFrameTime_ms = Integer.parseInt(SystemProperties.get("debug.longframe_ms", "16"));
+ long elapsedTime_us = now_us - mLastTime_us;
+ float fps = 1000000.f / elapsedTime_us;
+ if (mLastTime_us > 0 && elapsedTime_us > longFrameTime_ms*1000) {
+ Log.v(TAG, "Long frame: " + elapsedTime_us/1000.f + " ms (" + fps + " fps)");
+ if (mNumShortFramesElapsed > 0) {
+ Log.v(TAG, " Short frames since last long frame: " + mNumShortFramesElapsed);
+ mNumShortFramesElapsed = 0;
+ }
+ } else {
+ ++mNumShortFramesElapsed;
+ }
+
+ mLastTime_us = now_us;
+ }
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ public Renderer() {
+ }
+
+
+ public void onDrawFrame(GL10 gl) {
+ long now_us = System.nanoTime() / 1000;
+ registerTime(now_us);
+
+ float red = (now_us % 1000000) / 1000000.f;
+ float green = (now_us % 2000000) / 2000000.f;
+ float blue = (now_us % 3000000) / 3000000.f;
+ GLES20.glClearColor(red, green, blue, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ }
+}
diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk
new file mode 100644
index 0000000..96417c7
--- /dev/null
+++ b/opengl/tests/testLatency/Android.mk
@@ -0,0 +1,20 @@
+#########################################################################
+# Test end-to-end latency.
+#########################################################################
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SDK_VERSION := 8
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestLatency
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testLatency/AndroidManifest.xml b/opengl/tests/testLatency/AndroidManifest.xml
new file mode 100644
index 0000000..741266e
--- /dev/null
+++ b/opengl/tests/testLatency/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testlatency">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+
+ <application
+ android:label="@string/testLatency_activity">
+ <activity android:name="TestLatencyActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testLatency/res/values/strings.xml b/opengl/tests/testLatency/res/values/strings.xml
new file mode 100644
index 0000000..0309991
--- /dev/null
+++ b/opengl/tests/testLatency/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="testLatency_activity">TestLatency</string>
+
+</resources>
+
diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java
new file mode 100644
index 0000000..ed993cb
--- /dev/null
+++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testlatency;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class TestLatencyActivity extends Activity {
+
+ TestLatencyView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestLatencyView(getApplication());
+ setContentView(mView);
+ mView.setFocusableInTouchMode(true);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java
new file mode 100644
index 0000000..d62bf17
--- /dev/null
+++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testlatency;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestLatencyView extends GLSurfaceView {
+ private static String TAG = "TestLatencyiew";
+ private float mX;
+ private float mY;
+ private float mDX;
+ private float mDY;
+ private long mT;
+ private long mDT;
+
+ public TestLatencyView(Context context) {
+ super(context);
+ setEGLContextClientVersion(2);
+ setRenderer(new Renderer());
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ float x = event.getX();
+ float y = event.getY();
+ long t = event.getEventTime();
+ synchronized(this) {
+ mDT = t - mT;
+ mT = t;
+ mDX = x - mX;
+ mX = x;
+ mDY = y - mY;
+ mY = y;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private float mScaleX, mScaleY, mOffsetX, mOffsetY;
+ private final float MS_PER_FRAME = 1000 / 60;
+ public Renderer() {
+ mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
+ .order(ByteOrder.nativeOrder()).asFloatBuffer();
+ }
+
+
+ public void onDrawFrame(GL10 gl) {
+ GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
+ GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+ GLES20.glUseProgram(mProgram);
+ checkGlError("glUseProgram");
+
+ float x, y, dx, dy;
+ long t, dt;
+ synchronized(TestLatencyView.this) {
+ x = mX;
+ y = mY;
+ dx = mDX;
+ dy = mDY;
+ dt = mDT;
+ }
+
+ if (dt > 0) {
+ dx = dx * MS_PER_FRAME / dt;
+ dy = dy * MS_PER_FRAME / dt;
+ }
+
+ GLES20.glEnableVertexAttribArray(mvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+ GLES20.glEnableVertexAttribArray(mvColorHandle);
+ checkGlError("glEnableVertexAttribArray");
+ for(int step = 0; step < 8; step++) {
+ float sx = (x + dx * step) * mScaleX + mOffsetX;
+ float sy = (y + dy * step) * mScaleY + mOffsetY;
+ int cbase = step * 4;
+
+ for (int i = 0; i < mTriangleVerticesData.length; i += 6) {
+ mTriangleVerticesData2[i] = sx + mTriangleVerticesData[i];
+ mTriangleVerticesData2[i+1] = -sy + mTriangleVerticesData[i+1];
+ mTriangleVerticesData2[i+2] = mColors[cbase];
+ mTriangleVerticesData2[i+3] = mColors[cbase+1];
+ mTriangleVerticesData2[i+4] = mColors[cbase+2];
+ mTriangleVerticesData2[i+5] = mColors[cbase+3];
+ }
+ mTriangleVertices.position(0);
+ mTriangleVertices.put(mTriangleVerticesData2).position(0);
+
+ GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
+ checkGlError("glVertexAttribPointer mvPosition");
+ mTriangleVertices.put(mTriangleVerticesData2).position(2);
+ GLES20.glVertexAttribPointer(mvColorHandle, 4, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
+ checkGlError("glVertexAttribPointer mvColor");
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+ checkGlError("glDrawArrays");
+ }
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ mScaleX = 2.0f / width;
+ mScaleY = 2.0f / height;
+ mOffsetX = -1f;
+ mOffsetY = -1f;
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ mProgram = createProgram(mVertexShader, mFragmentShader);
+ if (mProgram == 0) {
+ return;
+ }
+ mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
+ checkGlError("glGetAttribLocation");
+ if (mvPositionHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for vPosition");
+ }
+ mvColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
+ checkGlError("glGetAttribLocation");
+ if (mvColorHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for vColor");
+ }
+ }
+
+ private int loadShader(int shaderType, String source) {
+ int shader = GLES20.glCreateShader(shaderType);
+ if (shader != 0) {
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":");
+ Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+ }
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ if (vertexShader == 0) {
+ return 0;
+ }
+
+ int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ if (pixelShader == 0) {
+ return 0;
+ }
+
+ int program = GLES20.glCreateProgram();
+ if (program != 0) {
+ GLES20.glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader vertexShader");
+ GLES20.glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader pixelShader");
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+ }
+
+ private void checkGlError(String op) {
+ int error;
+ while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+ Log.e(TAG, op + ": glError " + error);
+ throw new RuntimeException(op + ": glError " + error);
+ }
+ }
+
+ // X, Y, R G B A
+ private final float[] mTriangleVerticesData = {
+ -0.025f, 0.3f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f , 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.025f, 0.3f, 1.0f, 1.0f, 255.0f, 1.0f
+ };
+
+ // Color cascade:
+ private final float[] mColors = {
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ 0.5f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.5f, 0.0f, 1.0f,
+ 0.5f, 0.5f, 0.0f, 1.0f,
+
+ 0.0f, 0.0f, 0.5f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f
+ };
+
+ private float[] mTriangleVerticesData2 = new float[mTriangleVerticesData.length];
+ private FloatBuffer mTriangleVertices;
+
+ private final String mVertexShader = "attribute vec4 aPosition;\n"
+ + "attribute vec4 aColor;\n"
+ + "varying vec4 vColor;\n"
+ + "void main() {\n"
+ + " gl_Position = aPosition;\n"
+ + " vColor = aColor;\n"
+ + "}\n";
+
+ private final String mFragmentShader = "precision mediump float;\n"
+ + "varying vec4 vColor;\n"
+ + "void main() {\n"
+ + " gl_FragColor = vColor;\n"
+ + "}\n";
+
+ private int mProgram;
+ private int mvPositionHandle;
+ private int mvColorHandle;
+
+ }
+}
+
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
new file mode 100644
index 0000000..ab37809
--- /dev/null
+++ b/opengl/tests/testViewport/Android.mk
@@ -0,0 +1,26 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestViewport
+
+# Set a specific SDK version so we can run on Froyo.
+
+LOCAL_SDK_VERSION := 8
+
+include $(BUILD_PACKAGE)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testViewport/AndroidManifest.xml b/opengl/tests/testViewport/AndroidManifest.xml
new file mode 100644
index 0000000..90a9d2d
--- /dev/null
+++ b/opengl/tests/testViewport/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/test_activity">
+ <activity android:name="TestActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testViewport/README b/opengl/tests/testViewport/README
new file mode 100644
index 0000000..c06abc9
--- /dev/null
+++ b/opengl/tests/testViewport/README
@@ -0,0 +1,28 @@
+Repro steps:
+
+build, install and run the attached test program TestViewport.apk
+
+Run on Sapphire with Froyo.
+
+The program clears the screen to blue, then draws a full screen white quad that
+is alligned to the screen.
+(Therefore the whole screen should appear to be white.)
+
+
+Note that screen is all white.
+
+Rotate screen 90 degrees.
+
+Expected: screen is still all white.
+
+Actual: screen is blue with offset white rectangle.
+
+This bug only happens on Sapphire, it works correctly on Passion.
+
+What happens:
+
+I think the bug is that the gl.glViewport() call in onSurfaceChanged() is
+being ignored by the OpenGL driver.
+
+NOTE: If a gl.glViewport call is added at the beginning of the onDrawFrame()
+call (which means it is called before every draw), the program runs correctly.
diff --git a/opengl/tests/testViewport/res/values/strings.xml b/opengl/tests/testViewport/res/values/strings.xml
new file mode 100644
index 0000000..f4b8bbb
--- /dev/null
+++ b/opengl/tests/testViewport/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="test_activity">Test Viewport</string>
+
+</resources>
+
diff --git a/opengl/tests/testViewport/src/com/android/test/TestActivity.java b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
new file mode 100644
index 0000000..cc7e450
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+ private final static String TAG = "TestActivity";
+ TestView mView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestView(getApplication());
+ mView.setFocusableInTouchMode(true);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testViewport/src/com/android/test/TestView.java b/opengl/tests/testViewport/src/com/android/test/TestView.java
new file mode 100644
index 0000000..23cc37d
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestView.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.FloatBuffer;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestView extends GLSurfaceView {
+ TestView(Context context) {
+ super(context);
+ init();
+ }
+
+ public TestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setRenderer(new Renderer());
+ setRenderMode(RENDERMODE_WHEN_DIRTY);
+ }
+
+ /** A grid is a topologically rectangular array of vertices.
+ *
+ * The vertex and index data are held in VBO objects because on most
+ * GPUs VBO objects are the fastest way of rendering static vertex
+ * and index data.
+ *
+ */
+
+ private static class Grid {
+ // Size of vertex data elements in bytes:
+ final static int FLOAT_SIZE = 4;
+ final static int CHAR_SIZE = 2;
+
+ // Vertex structure:
+ // float x, y, z;
+
+ final static int VERTEX_SIZE = 3 * FLOAT_SIZE;
+
+ private int mVertexBufferObjectId;
+ private int mElementBufferObjectId;
+
+ // These buffers are used to hold the vertex and index data while
+ // constructing the grid. Once createBufferObjects() is called
+ // the buffers are nulled out to save memory.
+
+ private ByteBuffer mVertexByteBuffer;
+ private FloatBuffer mVertexBuffer;
+ private CharBuffer mIndexBuffer;
+
+ private int mW;
+ private int mH;
+ private int mIndexCount;
+
+ public Grid(int w, int h) {
+ if (w < 0 || w >= 65536) {
+ throw new IllegalArgumentException("w");
+ }
+ if (h < 0 || h >= 65536) {
+ throw new IllegalArgumentException("h");
+ }
+ if (w * h >= 65536) {
+ throw new IllegalArgumentException("w * h >= 65536");
+ }
+
+ mW = w;
+ mH = h;
+ int size = w * h;
+
+ mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
+ .order(ByteOrder.nativeOrder());
+ mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
+
+ int quadW = mW - 1;
+ int quadH = mH - 1;
+ int quadCount = quadW * quadH;
+ int indexCount = quadCount * 6;
+ mIndexCount = indexCount;
+ mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
+ .order(ByteOrder.nativeOrder()).asCharBuffer();
+
+ /*
+ * Initialize triangle list mesh.
+ *
+ * [0]-----[ 1] ...
+ * | / |
+ * | / |
+ * | / |
+ * [w]-----[w+1] ...
+ * | |
+ *
+ */
+
+ {
+ int i = 0;
+ for (int y = 0; y < quadH; y++) {
+ for (int x = 0; x < quadW; x++) {
+ char a = (char) (y * mW + x);
+ char b = (char) (y * mW + x + 1);
+ char c = (char) ((y + 1) * mW + x);
+ char d = (char) ((y + 1) * mW + x + 1);
+
+ mIndexBuffer.put(i++, a);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, b);
+
+ mIndexBuffer.put(i++, b);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, d);
+ }
+ }
+ }
+
+ }
+
+ public void set(int i, int j, float x, float y, float z) {
+ if (i < 0 || i >= mW) {
+ throw new IllegalArgumentException("i");
+ }
+ if (j < 0 || j >= mH) {
+ throw new IllegalArgumentException("j");
+ }
+
+ int index = mW * j + i;
+
+ mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
+ mVertexBuffer.put(x);
+ mVertexBuffer.put(y);
+ mVertexBuffer.put(z);
+ }
+
+ public void createBufferObjects(GL gl) {
+ // Generate a the vertex and element buffer IDs
+ int[] vboIds = new int[2];
+ GL11 gl11 = (GL11) gl;
+ gl11.glGenBuffers(2, vboIds, 0);
+ mVertexBufferObjectId = vboIds[0];
+ mElementBufferObjectId = vboIds[1];
+
+ // Upload the vertex data
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ mVertexByteBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ mIndexBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
+
+ // We don't need the in-memory data any more
+ mVertexBuffer = null;
+ mVertexByteBuffer = null;
+ mIndexBuffer = null;
+ }
+
+ public void draw(GL10 gl) {
+ GL11 gl11 = (GL11) gl;
+
+ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
+ gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private static final String TAG = "Renderer";
+ private Grid mGrid;
+
+ public void onDrawFrame(GL10 gl) {
+ gl.glClearColor(0,0,1,1);
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
+ mGrid.draw(gl);
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ gl.glViewport(0, 0, width, height);
+ gl.glMatrixMode(GL11.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glOrthof(0, width, height, 0, -1, 1);
+ gl.glMatrixMode(GL11.GL_MODELVIEW);
+ createGrid(gl, width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ private void createGrid(GL10 gl, float w, float h) {
+ mGrid = new Grid(2, 2);
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ float x = w * i;
+ float y = h * j;
+ float z = 0.0f;
+ mGrid.set(i,j, x, y, z);
+ }
+ }
+ mGrid.createBufferObjects(gl);
+ }
+ }
+}
+
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a14bfb5..e4825d0 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -5,6 +5,7 @@
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
+ DisplayHardware/HWComposer.cpp \
BlurFilter.cpp.arm \
GLExtensions.cpp \
Layer.cpp \
@@ -21,7 +22,7 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
ifeq ($(TARGET_BOARD_PLATFORM), omap3)
- LOCAL_CFLAGS += -DNO_RGBX_8888
+ LOCAL_CFLAGS += -DNO_RGBX_8888 -DHAS_PUSH_BUFFERS
endif
# need "-lrt" on Linux simulator to pick up clock_gettime
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 0515110..bd348bf 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -36,11 +36,11 @@
#include "DisplayHardware/DisplayHardware.h"
-#include <hardware/copybit.h>
#include <hardware/overlay.h>
#include <hardware/gralloc.h>
#include "GLExtensions.h"
+#include "HWComposer.h"
using namespace android;
@@ -76,7 +76,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0)
+ mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -262,6 +262,17 @@
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+
+ // initialize the H/W composer
+ mHwc = new HWComposer();
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->setFrameBuffer(mDisplay, mSurface);
+ }
+}
+
+HWComposer& DisplayHardware::getHwComposer() const {
+ return *mHwc;
}
/*
@@ -281,6 +292,9 @@
void DisplayHardware::releaseScreen() const
{
DisplayHardwareBase::releaseScreen();
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->release();
+ }
}
void DisplayHardware::acquireScreen() const
@@ -321,7 +335,12 @@
}
mPageFlipCount++;
- eglSwapBuffers(dpy, surface);
+
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->commit();
+ } else {
+ eglSwapBuffers(dpy, surface);
+ }
checkEGLErrors("eglSwapBuffers");
// for debugging
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 2d7900c..75b55df 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -34,12 +34,11 @@
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
-struct framebuffer_device_t;
-struct copybit_image_t;
namespace android {
class FramebufferNativeWindow;
+class HWComposer;
class DisplayHardware : public DisplayHardwareBase
{
@@ -80,6 +79,9 @@
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+ // Hardware Composer
+ HWComposer& getHwComposer() const;
status_t compositionComplete() const;
@@ -110,6 +112,8 @@
GLint mMaxViewportDims;
GLint mMaxTextureSize;
+ HWComposer* mHwc;
+
sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
new file mode 100644
index 0000000..4af274b
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+#include <hardware/hardware.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "HWComposer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer()
+ : mModule(0), mHwc(0), mList(0), mCapacity(0),
+ mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+{
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
+ LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ err = hwc_open(mModule, &mHwc);
+ LOGE_IF(err, "%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ }
+}
+
+HWComposer::~HWComposer() {
+ free(mList);
+ if (mHwc) {
+ hwc_close(mHwc);
+ }
+}
+
+status_t HWComposer::initCheck() const {
+ return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
+ mDpy = (hwc_display_t)dpy;
+ mSur = (hwc_surface_t)sur;
+}
+
+status_t HWComposer::createWorkList(size_t numLayers) {
+ if (mHwc) {
+ if (!mList || mCapacity < numLayers) {
+ free(mList);
+ size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
+ mList = (hwc_layer_list_t*)malloc(size);
+ mCapacity = numLayers;
+ }
+ mList->flags = HWC_GEOMETRY_CHANGED;
+ mList->numHwLayers = numLayers;
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::prepare() const {
+ int err = mHwc->prepare(mHwc, mList);
+ return (status_t)err;
+}
+
+status_t HWComposer::commit() const {
+ int err = mHwc->set(mHwc, mDpy, mSur, mList);
+ if (mList) {
+ mList->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
+ return (status_t)err;
+}
+
+status_t HWComposer::release() const {
+ int err = mHwc->set(mHwc, NULL, NULL, NULL);
+ return (status_t)err;
+}
+
+size_t HWComposer::getNumLayers() const {
+ return mList ? mList->numHwLayers : 0;
+}
+
+hwc_layer_t* HWComposer::getLayers() const {
+ return mList ? mList->hwLayers : 0;
+}
+
+void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
+ if (mHwc && mList) {
+ result.append("Hardware Composer state:\n");
+
+ snprintf(buffer, SIZE, " numHwLayers=%u, flags=%08x\n",
+ mList->numHwLayers, mList->flags);
+ result.append(buffer);
+
+ for (size_t i=0 ; i<mList->numHwLayers ; i++) {
+ const hwc_layer_t& l(mList->hwLayers[i]);
+ snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d]\n",
+ l.compositionType ? "OVERLAY" : "FB",
+ l.hints, l.flags, l.transform, l.blending,
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom);
+ result.append(buffer);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
new file mode 100644
index 0000000..5a9e9eb
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SF_HWCOMPOSER_H
+#define ANDROID_SF_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class HWComposer
+{
+public:
+
+ HWComposer();
+ ~HWComposer();
+
+ status_t initCheck() const;
+
+ // tells the HAL what the framebuffer is
+ void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
+
+ // create a work list for numLayers layer
+ status_t createWorkList(size_t numLayers);
+
+ // Asks the HAL what it can do
+ status_t prepare() const;
+
+ // commits the list
+ status_t commit() const;
+
+ // release hardware resources
+ status_t release() const;
+
+ size_t getNumLayers() const;
+ hwc_layer_t* getLayers() const;
+
+ // for debugging
+ void dump(String8& out, char* scratch, size_t SIZE) const;
+
+private:
+ hw_module_t const* mModule;
+ hwc_composer_device_t* mHwc;
+ hwc_layer_list_t* mList;
+ size_t mCapacity;
+ hwc_display_t mDpy;
+ hwc_surface_t mSur;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a060d31..1b06843 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -35,6 +35,7 @@
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
#define DEBUG_RESIZE 0
@@ -170,7 +171,8 @@
mReqHeight = h;
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
- mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
+ (flags & ISurfaceComposer::eOpaque) == 0;
// we use the red index
int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
@@ -181,6 +183,62 @@
return NO_ERROR;
}
+void Layer::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = 0;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // we can't do alpha-fade with the hwc HAL
+ const State& s(drawingState());
+ if (s.alpha < 0xFF) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ // we can only handle simple transformation
+ if (mOrientation & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ hwcl->transform = mOrientation;
+
+ if (needsBlending()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
+}
+
+void Layer::setPerFrameData(hwc_layer_t* hwcl) {
+ sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+ if (buffer == NULL) {
+ // this situation can happen if we ran out of memory for instance.
+ // not much we can do. continue to use whatever texture was bound
+ // to this context.
+ hwcl->handle = NULL;
+ return;
+ }
+ hwcl->handle = const_cast<native_handle_t*>(buffer->handle);
+ // TODO: set the crop value properly
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+}
+
void Layer::reloadTexture(const Region& dirty)
{
sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
@@ -321,6 +379,7 @@
Mutex::Autolock _l(mLock);
// zero means default
+ const bool fixedSize = reqWidth && reqHeight;
if (!reqFormat) reqFormat = mFormat;
if (!reqWidth) reqWidth = mWidth;
if (!reqHeight) reqHeight = mHeight;
@@ -334,6 +393,7 @@
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mReqFormat = reqFormat;
+ mFixedSize = fixedSize;
lcblk->reallocateAllExcept(index);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 263c372..caa6d17 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -68,6 +68,8 @@
bool isFixedSize() const;
// LayerBase interface
+ virtual void setGeometry(hwc_layer_t* hwcl);
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
virtual void drawForSreenShot() const;
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 069b85a..8ab5a10 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -309,6 +309,15 @@
}
}
+void LayerBase::setGeometry(hwc_layer_t* hwcl) {
+ hwcl->flags |= HWC_SKIP_LAYER;
+}
+
+void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->handle = NULL;
+}
+
void LayerBase::draw(const Region& clip) const
{
// reset GL state
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index d688f65..bdee05b 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -35,6 +35,8 @@
#include <pixelflinger/pixelflinger.h>
+#include <hardware/hwcomposer.h>
+
#include "Transform.h"
namespace android {
@@ -108,6 +110,10 @@
virtual const char* getTypeId() const { return "LayerBase"; }
+ virtual void setGeometry(hwc_layer_t* hwcl);
+
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
+
/**
* draw - performs some global clipping optimizations
* and calls onDraw().
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a919ddf..97365aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -53,6 +53,7 @@
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -78,12 +79,14 @@
mReadFramebuffer("android.permission.READ_FRAME_BUFFER"),
mDump("android.permission.DUMP"),
mVisibleRegionsDirty(false),
+ mHwWorkListDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugBackground(0),
+ mDebugDisableHWC(0),
mDebugInSwapBuffers(0),
mLastSwapBufferTime(0),
mDebugInTransaction(0),
@@ -165,7 +168,7 @@
{
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
- LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mBootFinished = true;
property_set("ctl.stop", "bootanim");
}
@@ -201,10 +204,10 @@
mServerHeap = new MemoryHeapBase(4096,
MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
+
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
-
+
new(mServerCblk) surface_flinger_cblk_t;
// initialize primary screen
@@ -233,7 +236,7 @@
// Initialize OpenGL|ES
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_SCISSOR_TEST);
glShadeModel(GL_FLAT);
@@ -267,7 +270,7 @@
// start boot animation
property_set("ctl.start", "bootanim");
-
+
return NO_ERROR;
}
@@ -370,6 +373,11 @@
// post surfaces (if needed)
handlePageFlip();
+ if (UNLIKELY(mHwWorkListDirty)) {
+ // build the h/w work list
+ handleWorkList();
+ }
+
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
// repaint the framebuffer (if needed)
@@ -384,13 +392,12 @@
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
- // release the clients before we flip ('cause flip might block)
- logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
- unlockClients();
-
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
+ logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
+ unlockClients();
+
logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
@@ -455,6 +462,7 @@
handleTransactionLocked(transactionFlags, ditchedLayers);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
+ mHwWorkListDirty = true;
// here the transaction has been committed
}
@@ -462,6 +470,7 @@
* Clean-up all layers that went away
* (do this without the lock held)
*/
+
const size_t count = ditchedLayers.size();
for (size_t i=0 ; i<count ; i++) {
if (ditchedLayers[i] != 0) {
@@ -665,7 +674,7 @@
// Update aboveOpaqueLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
-
+
// Store the visible region is screen space
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
@@ -695,8 +704,8 @@
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
- LayerVector& currentLayers = const_cast<LayerVector&>(
- mDrawingState.layersSortedByZ);
+ LayerVector& currentLayers(
+ const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -719,6 +728,7 @@
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
+ mHwWorkListDirty = true;
}
unlockPageFlip(currentLayers);
@@ -749,6 +759,24 @@
}
}
+void SurfaceFlinger::handleWorkList()
+{
+ mHwWorkListDirty = false;
+ HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
+ const size_t count = currentLayers.size();
+ hwc.createWorkList(count);
+ hwc_layer_t* const cur(hwc.getLayers());
+ for (size_t i=0 ; cur && i<count ; i++) {
+ currentLayers[i]->setGeometry(&cur[i]);
+ if (mDebugDisableHWC) {
+ cur[i].compositionType = HWC_FRAMEBUFFER;
+ cur[i].flags |= HWC_SKIP_LAYER;
+ }
+ }
+ }
+}
void SurfaceFlinger::handleRepaint()
{
@@ -769,8 +797,8 @@
glLoadIdentity();
uint32_t flags = hw.getFlags();
- if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
- (flags & DisplayHardware::BUFFER_PRESERVED))
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
{
// we can redraw only what's dirty, but since SWAP_RECTANGLE only
// takes a rectangle, we must make sure to update that whole
@@ -813,9 +841,73 @@
// draw something...
drawWormhole();
}
+
+ status_t err = NO_ERROR;
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
+ size_t count = layers.size();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ HWComposer& hwc(hw.getHwComposer());
+ hwc_layer_t* const cur(hwc.getLayers());
+
+ LOGE_IF(cur && hwc.getNumLayers() != count,
+ "HAL number of layers (%d) doesn't match surfaceflinger (%d)",
+ hwc.getNumLayers(), count);
+
+ // just to be extra-safe, use the smallest count
+ if (hwc.initCheck() == NO_ERROR) {
+ count = count < hwc.getNumLayers() ? count : hwc.getNumLayers();
+ }
+
+ /*
+ * update the per-frame h/w composer data for each layer
+ * and build the transparent region of the FB
+ */
+ Region transparent;
+ if (cur) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->setPerFrameData(&cur[i]);
+ if (cur[i].hints & HWC_HINT_CLEAR_FB) {
+ if (!(layer->needsBlending())) {
+ transparent.orSelf(layer->visibleRegionScreen);
+ }
+ }
+ }
+ err = hwc.prepare();
+ LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ }
+
+ /*
+ * clear the area of the FB that need to be transparent
+ */
+ transparent.andSelf(dirty);
+ if (!transparent.isEmpty()) {
+ glClearColor(0,0,0,0);
+ Region::const_iterator it = transparent.begin();
+ Region::const_iterator const end = transparent.end();
+ const int32_t height = hw.getHeight();
+ while (it != end) {
+ const Rect& r(*it++);
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+
+ /*
+ * and then, render the layers targeted at the framebuffer
+ */
+ for (size_t i=0 ; i<count ; i++) {
+ if (cur) {
+ if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
+ !(cur[i].flags & HWC_SKIP_LAYER)) {
+ // skip layers handled by the HAL
+ continue;
+ }
+ }
+
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) {
@@ -1054,7 +1146,7 @@
if (android_atomic_dec(&mTransactionCount) == 1) {
signalEvent();
- // if there is a transaction with a resize, wait for it to
+ // if there is a transaction with a resize, wait for it to
// take effect before returning.
Mutex::Autolock _l(mStateLock);
while (mResizeTransationPending) {
@@ -1098,7 +1190,7 @@
return NO_ERROR;
}
-int SurfaceFlinger::setOrientation(DisplayID dpy,
+int SurfaceFlinger::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -1131,14 +1223,17 @@
int(w), int(h));
return surfaceHandle;
}
-
+
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
sp<Layer> normalLayer;
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
+#if HAS_PUSH_BUFFERS
if (UNLIKELY(flags & ePushBuffers)) {
layer = createPushBuffersSurface(client, d, w, h, flags);
- } else {
+ } else
+#endif
+ {
normalLayer = createNormalSurface(client, d, w, h, flags, format);
layer = normalLayer;
}
@@ -1157,7 +1252,7 @@
ssize_t token = addClientLayer(client, layer);
surfaceHandle = layer->getSurface();
- if (surfaceHandle != 0) {
+ if (surfaceHandle != 0) {
params->token = token;
params->identity = surfaceHandle->getIdentity();
params->width = w;
@@ -1241,7 +1336,7 @@
/*
* called by the window manager, when a surface should be marked for
* destruction.
- *
+ *
* The surface is removed from the current and drawing lists, but placed
* in the purgatory queue, so it's not destroyed right-away (we need
* to wait for all client's references to go away first).
@@ -1262,7 +1357,7 @@
status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
{
// called by ~ISurface() when all references are gone
-
+
class MessageDestroySurface : public MessageBase {
SurfaceFlinger* flinger;
sp<LayerBaseClient> layer;
@@ -1275,9 +1370,9 @@
layer.clear(); // clear it outside of the lock;
Mutex::Autolock _l(flinger->mStateLock);
/*
- * remove the layer from the current list -- chances are that it's
- * not in the list anyway, because it should have been removed
- * already upon request of the client (eg: window manager).
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
* However, a buggy client could have not done that.
* Since we know we don't have any more clients, we don't need
* to use the purgatory.
@@ -1392,7 +1487,7 @@
}
const bool locked(retry >= 0);
if (!locked) {
- snprintf(buffer, SIZE,
+ snprintf(buffer, SIZE,
"SurfaceFlinger appears to be unresponsive, "
"dumping anyways (no locks held)\n");
result.append(buffer);
@@ -1434,6 +1529,13 @@
result.append(buffer);
}
+ HWComposer& hwc(hw.getHwComposer());
+ snprintf(buffer, SIZE, " h/w composer %s and %s\n",
+ hwc.initCheck()==NO_ERROR ? "present" : "not present",
+ mDebugDisableHWC ? "disabled" : "enabled");
+ result.append(buffer);
+ hwc.dump(result, buffer, SIZE);
+
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
@@ -1508,6 +1610,11 @@
n = data.readInt32();
mDebugBackground = n ? 1 : 0;
return NO_ERROR;
+ case 1008: // toggle use of hw composer
+ n = data.readInt32();
+ mDebugDisableHWC = n ? 1 : 0;
+ mHwWorkListDirty = true;
+ // fall-through...
case 1004:{ // repaint everything
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
@@ -2077,12 +2184,15 @@
{
int32_t name = NAME_NOT_FOUND;
sp<Layer> layer(mFlinger->getLayer(sur));
- if (layer == 0) return name;
+ if (layer == 0) {
+ return name;
+ }
// if this layer already has a token, just return it
name = layer->getToken();
- if ((name >= 0) && (layer->getClient() == this))
+ if ((name >= 0) && (layer->getClient() == this)) {
return name;
+ }
name = 0;
do {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f85a22b..3470d87 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -305,6 +305,7 @@
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
+ void handleWorkList();
void handleRepaint();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
@@ -387,6 +388,7 @@
Region mInvalidRegion;
Region mWormholeRegion;
bool mVisibleRegionsDirty;
+ bool mHwWorkListDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mFreezeCount;
@@ -397,6 +399,7 @@
// don't use a lock for these, we don't care
int mDebugRegion;
int mDebugBackground;
+ int mDebugDisableHWC;
volatile nsecs_t mDebugInSwapBuffers;
nsecs_t mLastSwapBufferTime;
volatile nsecs_t mDebugInTransaction;