diff options
author | David 'Digit' Turner <digit@google.com> | 2014-02-27 14:44:51 +0100 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2014-03-11 18:03:08 +0100 |
commit | 0863e159faa8c8bf7c47deb92a109961e8653e52 (patch) | |
tree | a2815aa64c73aae43ab7e54e02bcc0d72bb5a316 | |
parent | bfc6160fecf9af96c659ab2474098275af9f042c (diff) | |
download | sdk-0863e159faa8c8bf7c47deb92a109961e8653e52.zip sdk-0863e159faa8c8bf7c47deb92a109961e8653e52.tar.gz sdk-0863e159faa8c8bf7c47deb92a109961e8653e52.tar.bz2 |
emulator/opengl: Remove android::Vector<> usage.
This remove the use of android::Vector<> by providing an
alternative vector implementation (emugl::PodVector<>) which
is heavily based on the emulator version under
external/qemu/android/base/containers/PodVector.h.
Ultimately the GPU emulation libraries will move under
external/qemu/, and the code will be changed to use
android::base::PodVector<> instead of emugl::PodVector<>.
Change-Id: I9836ed961795c0791115c61e731d15d17f036972
7 files changed, 582 insertions, 8 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp index a054562..a03f8c9 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp @@ -204,9 +204,7 @@ bool ProgramData::attachShader(GLuint shader) return false; } } - // AKA m_shaders.push_back(), but that has an ambiguous call to insertAt() - // due to the default parameters. This is the desired insertAt() overload. - m_shaders.insertAt(shader, m_shaders.size(), 1); + m_shaders.append(shader); return true; } @@ -215,7 +213,7 @@ bool ProgramData::detachShader(GLuint shader) size_t n = m_shaders.size(); for (size_t i = 0; i < n; i++) { if (m_shaders[i] == shader) { - m_shaders.removeAt(i); + m_shaders.remove(i); return true; } } diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h index 02278a2..713e17e 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h @@ -16,6 +16,10 @@ #ifndef _GL_SHARED_GROUP_H_ #define _GL_SHARED_GROUP_H_ +#include "emugl/common/mutex.h" +#include "emugl/common/pod_vector.h" +#include "emugl/common/smart_ptr.h" + #define GL_API #ifndef ANDROID #define GL_APIENTRY @@ -34,14 +38,12 @@ #include <utils/List.h> #include <utils/String8.h> #include "FixedBuffer.h" -#include "emugl/common/mutex.h" -#include "emugl/common/smart_ptr.h" struct BufferData { BufferData(); BufferData(GLsizeiptr size, void * data); GLsizeiptr m_size; - FixedBuffer m_fixedBuffer; + FixedBuffer m_fixedBuffer; }; class ProgramData { @@ -61,7 +63,7 @@ private: bool m_initialized; bool m_locShiftWAR; - android::Vector<GLuint> m_shaders; + emugl::PodVector<GLuint> m_shaders; public: enum { diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk index 6a6c169..5f8fecb 100644 --- a/emulator/opengl/shared/emugl/common/Android.mk +++ b/emulator/opengl/shared/emugl/common/Android.mk @@ -7,6 +7,7 @@ LOCAL_PATH := $(call my-dir) commonSources := \ lazy_instance.cpp \ + pod_vector.cpp \ smart_ptr.cpp \ sockets.cpp \ thread_store.cpp \ @@ -27,6 +28,7 @@ $(call emugl-end-module) host_commonSources := \ lazy_instance_unittest.cpp \ + pod_vector_unittest.cpp \ mutex_unittest.cpp \ smart_ptr_unittest.cpp \ thread_store_unittest.cpp \ diff --git a/emulator/opengl/shared/emugl/common/pod_vector.cpp b/emulator/opengl/shared/emugl/common/pod_vector.cpp new file mode 100644 index 0000000..3fe8f15 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/pod_vector.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2014 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 "emugl/common/pod_vector.h" + +#include <stdlib.h> +#include <string.h> + +#define USE_MALLOC_USABLE_SIZE 0 + +namespace emugl { + +static inline void swapPointers(char** p1, char** p2) { + char* tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +PodVectorBase::PodVectorBase(const PodVectorBase& other) { + initFrom(other.begin(), other.byteSize()); +} + +PodVectorBase& PodVectorBase::operator=(const PodVectorBase& other) { + initFrom(other.begin(), other.byteSize()); + return *this; +} + +PodVectorBase::~PodVectorBase() { + if (mBegin) { + // Sanity. + ::memset(mBegin, 0xee, byteSize()); + ::free(mBegin); + mBegin = NULL; + mEnd = NULL; + mLimit = NULL; + } +} + +void PodVectorBase::initFrom(const void* from, size_t fromLen) { + if (!fromLen || !from) { + mBegin = NULL; + mEnd = NULL; + mLimit = NULL; + } else { + mBegin = static_cast<char*>(::malloc(fromLen)); + mEnd = mLimit = mBegin + fromLen; + ::memcpy(mBegin, from, fromLen); + } +} + +void PodVectorBase::assignFrom(const PodVectorBase& other) { + resize(other.byteSize(), 1U); + ::memmove(begin(), other.begin(), byteSize()); +} + +void PodVectorBase::resize(size_t newSize, size_t itemSize) { + const size_t kMaxSize = maxItemCapacity(itemSize); + size_t oldCapacity = itemCapacity(itemSize); + const size_t kMinCapacity = 256 / itemSize; + + if (newSize < oldCapacity) { + // Only shrink if the new size is really small. + if (newSize < oldCapacity / 2 && oldCapacity > kMinCapacity) { + reserve(newSize, itemSize); + } + } else if (newSize > oldCapacity) { + size_t newCapacity = oldCapacity; + while (newCapacity < newSize) { + size_t newCapacity2 = newCapacity + (newCapacity >> 2) + 8; + if (newCapacity2 < newCapacity || newCapacity > kMaxSize) { + newCapacity = kMaxSize; + } else { + newCapacity = newCapacity2; + } + } + reserve(newCapacity, itemSize); + } + mEnd = mBegin + newSize * itemSize; +} + +void PodVectorBase::reserve(size_t newSize, size_t itemSize) { + const size_t kMaxSize = maxItemCapacity(itemSize); + if (newSize == 0) { + ::free(mBegin); + mBegin = NULL; + mEnd = NULL; + mLimit = NULL; + return; + } + + size_t oldByteSize = byteSize(); + size_t newByteCapacity = newSize * itemSize; + char* newBegin = static_cast<char*>(::realloc(mBegin, newByteCapacity)); + mBegin = newBegin; + mEnd = newBegin + oldByteSize; +#if USE_MALLOC_USABLE_SIZE + size_t usableSize = malloc_usable_size(mBegin); + if (usableSize > newByteCapacity) { + newByteCapacity = usableSize - (usableSize % itemSize); + } +#endif + mLimit = newBegin + newByteCapacity; + // Sanity. + if (newByteCapacity > oldByteSize) { + ::memset(mBegin + oldByteSize, 0, newByteCapacity - oldByteSize); + } +} + +void PodVectorBase::removeAt(size_t itemPos, size_t itemSize) { + size_t count = itemCount(itemSize); + if (itemPos < count) { + size_t pos = itemPos * itemSize; + ::memmove(mBegin + pos, + mBegin + pos + itemSize, + byteSize() - pos - itemSize); + resize(count - 1U, itemSize); + } +} + +void* PodVectorBase::insertAt(size_t itemPos, size_t itemSize) { + size_t count = this->itemCount(itemSize); + resize(count + 1, itemSize); + size_t pos = itemPos * itemSize; + if (itemPos < count) { + ::memmove(mBegin + pos + itemSize, + mBegin + pos, + count * itemSize - pos); + // Sanity to avoid copying pointers and other bad stuff. + ::memset(mBegin + pos, 0, itemSize); + } + return mBegin + pos; +} + +void PodVectorBase::swapAll(PodVectorBase* other) { + swapPointers(&mBegin, &other->mBegin); + swapPointers(&mEnd, &other->mEnd); + swapPointers(&mLimit, &other->mLimit); +} + +} // namespace emugl diff --git a/emulator/opengl/shared/emugl/common/pod_vector.h b/emulator/opengl/shared/emugl/common/pod_vector.h new file mode 100644 index 0000000..22a8a1d --- /dev/null +++ b/emulator/opengl/shared/emugl/common/pod_vector.h @@ -0,0 +1,267 @@ +// Copyright (C) 2014 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 EMUGL_COMMON_POD_VECTOR_H +#define EMUGL_COMMON_POD_VECTOR_H + + +#include <stddef.h> + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS 1 +#endif +#include <stdint.h> + +#ifndef SIZE_MAX +#error "You must define __STDC_LIMIT_MACROS before including <stddint.h>" +#endif + +namespace emugl { + +// A PodVector is a templated vector-like type that is used to store +// POD-struct compatible items only. This allows the implementation to +// use ::memmove() to move items, and also malloc_usable_size() to +// determine the best capacity. +// +// std::vector<> is capable of doing this in theory, using horrible +// templating tricks that make error messages very difficult to +// understand. +// +// Note that a PodVector can be used to store items that contain pointers, +// as long as these do not point to items in the same container. +// +// The PodVector provides methods that also follow the std::vector<> +// conventions, i.e. push_back() is an alias for append(). +// + +// NOTE: This is a re-implementation of +// external/qemu/android/base/containers/PodVector.h for emugl. + +// PodVectorBase is a base, non-templated, implementation class that all +// PodVector instances derive from. This is used to reduce template +// specialization. Do not use directly, i..e it's an implementation detail. +class PodVectorBase { +protected: + PodVectorBase() : mBegin(NULL), mEnd(NULL), mLimit(NULL) {} + explicit PodVectorBase(const PodVectorBase& other); + PodVectorBase& operator=(const PodVectorBase& other); + ~PodVectorBase(); + + bool empty() const { return mEnd == mBegin; } + + size_t byteSize() const { return mEnd - mBegin; } + + size_t byteCapacity() const { return mLimit - mBegin; } + + void* begin() { return mBegin; } + const void* begin() const { return mBegin; } + void* end() { return mEnd; } + const void* end() const { return mEnd; } + + void* itemAt(size_t pos, size_t itemSize) { + const size_t kMaxCapacity = SIZE_MAX / itemSize; + return mBegin + pos * itemSize; + } + + const void* itemAt(size_t pos, size_t itemSize) const { + const size_t kMaxCapacity = SIZE_MAX / itemSize; + return mBegin + pos * itemSize; + } + + void assignFrom(const PodVectorBase& other); + + inline size_t itemCount(size_t itemSize) const { + return byteSize() / itemSize; + } + + inline size_t itemCapacity(size_t itemSize) const { + return byteCapacity() / itemSize; + } + + inline size_t maxItemCapacity(size_t itemSize) const { + return SIZE_MAX / itemSize; + } + + void resize(size_t newSize, size_t itemSize); + void reserve(size_t newSize, size_t itemSize); + + void removeAt(size_t index, size_t itemSize); + void* insertAt(size_t index, size_t itemSize); + void swapAll(PodVectorBase* other); + + char* mBegin; + char* mEnd; + char* mLimit; + +private: + void initFrom(const void* from, size_t fromLen); +}; + + +// A PodVector<T> holds a vector (dynamically resizable array) or items +// that must be POD-struct compatible (i.e. they cannot have constructors, +// destructors, or virtual members). This allows the implementation to be +// small, fast and efficient, memory-wise. +// +// If you want to implement a vector of C++ objects, consider using +// std::vector<> instead, but keep in mind that this implies a non-trivial +// cost when appending, inserting, removing items in the collection. +// +template <typename T> +class PodVector : public PodVectorBase { +public: + // Default constructor for an empty PodVector<T> + PodVector() : PodVectorBase() {} + + // Copy constructor. This copies all items from |other| into + // the new instance with ::memmove(). + PodVector(const PodVector& other) : PodVectorBase(other) {} + + // Assignment operator. + PodVector& operator=(const PodVector& other) { + this->assignFrom(other); + return *this; + } + + // Destructor, this simply releases the internal storage block that + // holds all the items, but doesn't touch them otherwise. + ~PodVector() {} + + // Return true iff the PodVector<T> instance is empty, i.e. does not + // have any items. + bool empty() const { return PodVectorBase::empty(); } + + // Return the number of items in the current PodVector<T> instance. + size_t size() const { return PodVectorBase::itemCount(sizeof(T)); } + + // Return the current capacity in the current PodVector<T> instance. + // Do not use directly, except if you know what you're doing. Try to + // use resize() or reserve() instead. + size_t capacity() const { + return PodVectorBase::itemCapacity(sizeof(T)); + } + + // Return the maximum capacity of any PodVector<T> instance. + static inline size_t maxCapacity() { return SIZE_MAX / sizeof(T); } + + // Resize the vector to ensure it can hold |newSize| + // items. This may or may not call reserve() under the hood. + // It's a fatal error to try to resize above maxCapacity(). + void resize(size_t newSize) { + PodVectorBase::resize(newSize, sizeof(T)); + } + + // Resize the vector's storage array to ensure that it can hold at + // least |newSize| items. It's a fatal error to try to resize above + // maxCapacity(). + void reserve(size_t newSize) { + PodVectorBase::reserve(newSize, sizeof(T)); + } + + // Return a pointer to the first item in the vector. This is only + // valid until the next call to any function that changes the size + // or capacity of the vector. Can be NULL if the vector is empty. + T* begin() { + return reinterpret_cast<T*>(PodVectorBase::begin()); + } + + // Return a constant pointer to the first item in the vector. This is + // only valid until the next call to any function that changes the + // size of capacity of the vector. + const T* begin() const { + return reinterpret_cast<T*>(PodVectorBase::begin()); + } + + // Return a pointer past the last item in the vector. I.e. if the + // result is not NULL, then |result - 1| points to the last item. + // Can be NULL if the vector is empty. + T* end() { + return reinterpret_cast<T*>(PodVectorBase::end()); + } + + // Return a constant pointer past the last item in the vector. I.e. if + // the result is not NULL, then |result - 1| points to the last item. + // Can be NULL if the vector is empty. + const T* end() const { + return reinterpret_cast<T*>(PodVectorBase::end()); + } + + // Returns a reference to the item a position |index| in the vector. + // It may be a fatal error to access an out-of-bounds position. + T& operator[](size_t index) { + return *reinterpret_cast<T*>( + PodVectorBase::itemAt(index, sizeof(T))); + } + + const T& operator[](size_t index) const { + return *reinterpret_cast<const T*>( + PodVectorBase::itemAt(index, sizeof(T))); + } + + // Increase the vector's size by 1, then move all items past a given + // position to the right. Return the position of the insertion point + // to let the caller copy the content it desires there. It's preferrable + // to use insert() directly, which will do the item copy for you. + T* emplace(size_t index) { + return reinterpret_cast<T*>( + PodVectorBase::insertAt(index, sizeof(T))); + } + + // Insert an item at a given position. |index| is the insertion position + // which must be between 0 and size() included, or a fatal error may + // occur. |item| is a reference to an item to copy into the array, + // byte-by-byte. + void insert(size_t index, const T& item) { + *(this->emplace(index)) = item; + } + + // Prepend an item at the start of a vector. This moves all vector items + // to the right, and is thus costly. |item| is a reference to an item + // to copy to the start of the vector. + void prepend(const T& item) { + *(this->emplace(0U)) = item; + } + + // Append an item at the end of a vector. Specialized version of insert() + // which always uses size() as the insertion position. + void append(const T& item) { + *(this->emplace(this->size())) = item; + } + + // Remove the item at a given position. |index| is the position of the + // item to delete. It must be between 0 and size(), included, or + // a fatal error may occur. Deleting the item at position size() + // doesn't do anything. + void remove(size_t index) { + PodVectorBase::removeAt(index, sizeof(T)); + } + + void swap(PodVector* other) { + PodVectorBase::swapAll(other); + } + + // Compatibility methods for std::vector<> + void push_back(const T& item) { append(item); } + void pop() { remove(0U); } + + typedef T* iterator; + typedef const T* const_iterator; +}; + +} // namespace emugl + +#endif // EMUGL_COMMON_POD_VECTOR_H diff --git a/emulator/opengl/shared/emugl/common/pod_vector_unittest.cpp b/emulator/opengl/shared/emugl/common/pod_vector_unittest.cpp new file mode 100644 index 0000000..9ce509a --- /dev/null +++ b/emulator/opengl/shared/emugl/common/pod_vector_unittest.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2014 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 "emugl/common/pod_vector.h" + +#include <gtest/gtest.h> + +namespace emugl { + +static int hashIndex(size_t n) { + return static_cast<int>(((n >> 14) * 13773) + (n * 51)); +} + +TEST(PodVector, Empty) { + PodVector<int> v; + EXPECT_TRUE(v.empty()); + EXPECT_EQ(0U, v.size()); +} + +TEST(PodVector, AppendOneItem) { + PodVector<int> v; + v.append(10234); + EXPECT_FALSE(v.empty()); + EXPECT_EQ(1U, v.size()); + EXPECT_EQ(10234, v[0]); +} + +TEST(PodVector, AppendLotsOfItems) { + PodVector<int> v; + const size_t kMaxCount = 10000; + for (size_t n = 0; n < kMaxCount; ++n) { + v.append(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v.size()); + for (size_t n = 0; n < kMaxCount; ++n) { + EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n; + } +} + +TEST(PodVector, RemoveFrontItems) { + PodVector<int> v; + const size_t kMaxCount = 100; + for (size_t n = 0; n < kMaxCount; ++n) { + v.append(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v.size()); + for (size_t n = 0; n < kMaxCount; ++n) { + EXPECT_EQ(hashIndex(n), v[0]) << "At index " << n; + v.remove(0U); + EXPECT_EQ(kMaxCount - n - 1U, v.size()) << "At index " << n; + } +} + +TEST(PodVector, PrependItems) { + PodVector<int> v; + const size_t kMaxCount = 100; + for (size_t n = 0; n < kMaxCount; ++n) { + v.prepend(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v.size()); + for (size_t n = 0; n < kMaxCount; ++n) { + EXPECT_EQ(hashIndex(kMaxCount - n - 1), v[n]) << "At index " << n; + } +} + +TEST(PodVector, ResizeExpands) { + PodVector<int> v; + const size_t kMaxCount = 100; + const size_t kMaxCount2 = 10000; + for (size_t n = 0; n < kMaxCount; ++n) { + v.append(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v.size()); + v.resize(kMaxCount2); + EXPECT_EQ(kMaxCount2, v.size()); + for (size_t n = 0; n < kMaxCount; ++n) { + EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n; + } +} + +TEST(PodVector, ResizeTruncates) { + PodVector<int> v; + const size_t kMaxCount = 10000; + const size_t kMaxCount2 = 10; + for (size_t n = 0; n < kMaxCount; ++n) { + v.append(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v.size()); + v.resize(kMaxCount2); + EXPECT_EQ(kMaxCount2, v.size()); + for (size_t n = 0; n < kMaxCount2; ++n) { + EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n; + } +} + + +TEST(PodVector, AssignmentOperator) { + PodVector<int> v1; + const size_t kMaxCount = 10000; + for (size_t n = 0; n < kMaxCount; ++n) { + v1.append(hashIndex(n)); + } + EXPECT_EQ(kMaxCount, v1.size()); + + PodVector<int> v2; + v2 = v1; + + v1.reserve(0); + + EXPECT_EQ(kMaxCount, v2.size()); + for (size_t n = 0; n < kMaxCount; ++n) { + EXPECT_EQ(hashIndex(n), v2[n]) << "At index " << n; + } +} + +} // namespace emugl diff --git a/emulator/opengl/shared/emugl/common/scoped_pointer_vector.h b/emulator/opengl/shared/emugl/common/scoped_pointer_vector.h new file mode 100644 index 0000000..3d263e9 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/scoped_pointer_vector.h @@ -0,0 +1,27 @@ +// Copyright (C) 2014 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 EMUGL_COMMON_SCOPED_POINTER_VECTOR_H +#define EMUGL_COMMON_SCOPED_POINTER_VECTOR_H + +namespace emugl { + +template <class T> +class ScopedPointerVector { + ScopedPointerVector +}; + +} // namespace emugl + +#endif // EMUGL_COMMON_SCOPED_POINTER_VECTOR_H |