add DeviceInfo

Change-Id: I4c122278a7e88b6f47c4dd3c5fc553df7d3c900d
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index ae5fa6c..2dfd199 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -39,6 +39,7 @@
     DamageAccumulator.cpp \
     DeferredDisplayList.cpp \
     DeferredLayerUpdater.cpp \
+    DeviceInfo.cpp \
     DisplayList.cpp \
     DisplayListCanvas.cpp \
     Dither.cpp \
@@ -204,6 +205,7 @@
     unit_tests/CanvasStateTests.cpp \
     unit_tests/ClipAreaTests.cpp \
     unit_tests/DamageAccumulatorTests.cpp \
+    unit_tests/DeviceInfoTests.cpp \
     unit_tests/FatVectorTests.cpp \
     unit_tests/LayerUpdateQueueTests.cpp \
     unit_tests/LinearAllocatorTests.cpp \
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
new file mode 100644
index 0000000..03b1706
--- /dev/null
+++ b/libs/hwui/DeviceInfo.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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 <DeviceInfo.h>
+
+#include "Extensions.h"
+
+#include <GLES2/gl2.h>
+
+#include <thread>
+#include <mutex>
+
+namespace android {
+namespace uirenderer {
+
+static DeviceInfo* sDeviceInfo = nullptr;
+static std::once_flag sInitializedFlag;
+
+const DeviceInfo* DeviceInfo::get() {
+    return sDeviceInfo;
+}
+
+void DeviceInfo::initialize() {
+    std::call_once(sInitializedFlag, []() {
+        sDeviceInfo = new DeviceInfo();
+        sDeviceInfo->load();
+    });
+}
+
+void DeviceInfo::load() {
+    mExtensions.load();
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
new file mode 100644
index 0000000..f576a4f
--- /dev/null
+++ b/libs/hwui/DeviceInfo.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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 DEVICEINFO_H
+#define DEVICEINFO_H
+
+#include "Extensions.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+class DeviceInfo {
+    PREVENT_COPY_AND_ASSIGN(DeviceInfo);
+public:
+    // returns nullptr if DeviceInfo is not initialized yet
+    // Note this does not have a memory fence so it's up to the caller
+    // to use one if required. Normally this should not be necessary
+    static const DeviceInfo* get();
+
+    // only call this after GL has been initialized, or at any point if compiled
+    // with HWUI_NULL_GPU
+    static void initialize();
+
+    const Extensions& extensions() const { return mExtensions; }
+
+    int maxTextureSize() const { return mMaxTextureSize; }
+
+private:
+    DeviceInfo() {}
+    ~DeviceInfo() {}
+
+    void load();
+
+    Extensions mExtensions;
+    int mMaxTextureSize;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* DEVICEINFO_H */
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 6dd29ad..e257715 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -35,8 +35,8 @@
 #endif
 
 
-Extensions::Extensions() {
-    StringCollection extensions((const char*) glGetString(GL_EXTENSIONS));
+void Extensions::load() {
+    auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
     mHasNPot = extensions.has("GL_OES_texture_npot");
     mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
     mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 6689b88..8ccfabd 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -19,6 +19,9 @@
 
 #include <cutils/compiler.h>
 
+#include <string>
+#include <unordered_set>
+
 namespace android {
 namespace uirenderer {
 
@@ -26,9 +29,9 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-class ANDROID_API Extensions {
+class Extensions {
 public:
-    Extensions();
+    void load();
 
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 485759b..78df297 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -17,15 +17,14 @@
 #include "EglManager.h"
 
 #include "Caches.h"
+#include "DeviceInfo.h"
 #include "Properties.h"
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
 #include "utils/StringUtils.h"
-
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <EGL/eglext.h>
-
 #include <string>
 
 #define GLES_VERSION 2
@@ -129,12 +128,14 @@
     createContext();
     createPBufferSurface();
     makeCurrent(mPBufferSurface);
+    DeviceInfo::initialize();
     mRenderThread.renderState().onGLContextCreated();
     initAtlas();
 }
 
 void EglManager::initExtensions() {
-    StringCollection extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+    auto extensions = StringUtils::split(
+            eglQueryString(mEglDisplay, EGL_EXTENSIONS));
     EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age");
     EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
     LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
diff --git a/libs/hwui/unit_tests/DeviceInfoTests.cpp b/libs/hwui/unit_tests/DeviceInfoTests.cpp
new file mode 100644
index 0000000..c3c68ae
--- /dev/null
+++ b/libs/hwui/unit_tests/DeviceInfoTests.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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 "DeviceInfo.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(DeviceInfo, basic) {
+    const DeviceInfo* di = DeviceInfo::get();
+    EXPECT_EQ(nullptr, di) << "DeviceInfo was already initialized?";
+    DeviceInfo::initialize();
+    di = DeviceInfo::get();
+    ASSERT_NE(nullptr, di) << "DeviceInfo initialization failed";
+    EXPECT_EQ(2048, di->maxTextureSize()) << "Max texture size didn't match";
+}
diff --git a/libs/hwui/unit_tests/StringUtilsTests.cpp b/libs/hwui/unit_tests/StringUtilsTests.cpp
index 5174ae9..6b2e265 100644
--- a/libs/hwui/unit_tests/StringUtilsTests.cpp
+++ b/libs/hwui/unit_tests/StringUtilsTests.cpp
@@ -16,13 +16,13 @@
 
 #include <gtest/gtest.h>
 
-#include "utils/StringUtils.h"
+#include <utils/StringUtils.h>
 
-namespace android {
-namespace uirenderer {
+using namespace android;
+using namespace android::uirenderer;
 
 TEST(StringUtils, simpleBuildSet) {
-    StringCollection collection("a b c");
+    auto collection = StringUtils::split("a b c");
 
     EXPECT_TRUE(collection.has("a"));
     EXPECT_TRUE(collection.has("b"));
@@ -31,11 +31,8 @@
 }
 
 TEST(StringUtils, advancedBuildSet) {
-    StringCollection collection("GL_ext1 GL_ext2 GL_ext3");
+    auto collection = StringUtils::split("GL_ext1 GL_ext2 GL_ext3");
 
     EXPECT_TRUE(collection.has("GL_ext1"));
     EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
 }
-
-};
-};
diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp
index a1df0e7..ccddd3c 100644
--- a/libs/hwui/utils/StringUtils.cpp
+++ b/libs/hwui/utils/StringUtils.cpp
@@ -14,26 +14,24 @@
  * limitations under the License.
  */
 
-#include "StringUtils.h"
+#include <utils/StringUtils.h>
 
 namespace android {
 namespace uirenderer {
 
-StringCollection::StringCollection(const char* spacedList) {
+unordered_string_set&& StringUtils::split(const char* spacedList) {
+    unordered_string_set set;
     const char* current = spacedList;
     const char* head = current;
     do {
         head = strchr(current, ' ');
         std::string s(current, head ? head - current : strlen(current));
         if (s.length()) {
-            mSet.insert(s);
+            set.insert(std::move(s));
         }
         current = head + 1;
     } while (head);
-}
-
-bool StringCollection::has(const char* s) {
-    return mSet.find(std::string(s)) != mSet.end();
+    return std::move(set);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index ef2a6d5..28b3d63 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -22,12 +22,16 @@
 namespace android {
 namespace uirenderer {
 
-class StringCollection {
+class unordered_string_set : public std::unordered_set<std::string> {
 public:
-    StringCollection(const char* spacedList);
-    bool has(const char* string);
-private:
-    std::unordered_set<std::string> mSet;
+    bool has(const char* str) {
+        return find(std::string(str)) != end();
+    }
+};
+
+class StringUtils {
+public:
+    static unordered_string_set&& split(const char* spacedList);
 };
 
 } /* namespace uirenderer */