diff --git a/external/android-emugl/CMakeLists.txt b/external/android-emugl/CMakeLists.txt index 29edadb..b328b17 100644 --- a/external/android-emugl/CMakeLists.txt +++ b/external/android-emugl/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_C_FLAGS "-Wall") include_directories( + ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/external/android-emugl/shared ${CMAKE_SOURCE_DIR}/external/android-emugl/host/include ${CMAKE_SOURCE_DIR}/external/android-emugl/shared/OpenglCodecCommon diff --git a/external/android-emugl/host/include/OpenglRender/render_api.h b/external/android-emugl/host/include/OpenglRender/render_api.h deleted file mode 100644 index 0bcf485..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright (C) 2011 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. -*/ -#pragma once - -#include "OpenglRender/render_api_functions.h" - -#include - -/* This header and its declarations must be usable from C code. - * - * If RENDER_API_NO_PROTOTYPES is #defined before including this header, only - * the interface function pointer types will be declared, not the prototypes. - * This allows the client to use those names for its function pointer variables. - * - * All interfaces which can fail return an int, with zero indicating failure - * and anything else indicating success. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// Use KHRONOS_APICALL to control visibility, but do not use KHRONOS_APIENTRY -// because we don't need the functions to be __stdcall on Win32. -#define RENDER_APICALL KHRONOS_APICALL -#define RENDER_APIENTRY - -#define RENDER_API_DECLARE(return_type, func_name, signature, callargs) \ - typedef return_type (RENDER_APIENTRY *func_name ## Fn) signature; \ - RENDER_APICALL return_type RENDER_APIENTRY func_name signature; - -typedef void (*emugl_logger_func_t)(const char* fmt, ...); - -typedef struct { - emugl_logger_func_t coarse; - emugl_logger_func_t fine; -} emugl_logger_struct; - -LIST_RENDER_API_FUNCTIONS(RENDER_API_DECLARE) - -#ifdef __cplusplus -} -#endif diff --git a/external/android-emugl/host/include/OpenglRender/render_api_functions.h b/external/android-emugl/host/include/OpenglRender/render_api_functions.h deleted file mode 100644 index 59237a8..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api_functions.h +++ /dev/null @@ -1,39 +0,0 @@ -// Auto-generated with: android/scripts/gen-entries.py --mode=funcargs distrib/android-emugl/host/libs/libOpenglRender/render_api.entries --output=distrib/android-emugl/host/include/OpenglRender/render_api_functions.h -// DO NOT EDIT THIS FILE - -#ifndef RENDER_API_FUNCTIONS_H -#define RENDER_API_FUNCTIONS_H - -#include "OpenglRender/render_api_platform_types.h" - -#include -#include -#include - -#include - -/* list of constants to be passed to setStreamMode */ -#define RENDER_API_STREAM_MODE_DEFAULT 0 -#define RENDER_API_STREAM_MODE_TCP 1 -#define RENDER_API_STREAM_MODE_UNIX 2 -#define RENDER_API_STREAM_MODE_PIPE 3 - -typedef void (*OnPostFn)(void* context, int width, int height, int ydir, - int format, int type, unsigned char* pixels); -typedef void (*emugl_crash_func_t)(const char* format, ...); - -#define LIST_RENDER_API_FUNCTIONS(X) \ - X(int, initLibrary, (), ()) \ - X(int, setStreamMode, (int mode), (mode)) \ - X(int, initOpenGLRenderer, (EGLNativeDisplayType native_display, char* addr, size_t addrLen, emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc), (native_display, addr, addrLen, logfuncs, crashfunc)) \ - X(void, getHardwareStrings, (const char** vendor, const char** renderer, const char** version), (vendor, renderer, version)) \ - X(void, setPostCallback, (OnPostFn onPost, void* onPostContext), (onPost, onPostContext)) \ - X(bool, showOpenGLSubwindow, (FBNativeWindowType window, int wx, int wy, int ww, int wh, int fbw, int fbh, float dpr, float zRot), (window, wx, wy, ww, wh, fbw, fbh, dpr, zRot)) \ - X(bool, destroyOpenGLSubwindow, (), ()) \ - X(void, setOpenGLDisplayRotation, (float zRot), (zRot)) \ - X(void, setOpenGLDisplayTranslation, (float px, float py), (px, py)) \ - X(void, repaintOpenGLDisplay, (), ()) \ - X(int, stopOpenGLRenderer, (), ()) \ - - -#endif // RENDER_API_FUNCTIONS_H diff --git a/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h b/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h deleted file mode 100644 index 12b993f..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright 2011 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. -*/ - -#pragma once - -// Define FBNativeWindowType which corresponds to the type of native -// host UI window handles. - -#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ -#include - -typedef HWND FBNativeWindowType; - -#elif defined(__linux__) - -// Really a Window handle, but we don't want to include the X11 headers here. -#include -typedef uint32_t FBNativeWindowType; - -#elif defined(__APPLE__) - -typedef void* FBNativeWindowType; - -#else -#warning "Unsupported platform" -#endif diff --git a/external/android-emugl/host/include/libOpenglRender/IOStream.h b/external/android-emugl/host/include/libOpenglRender/IOStream.h index 672f5a7..3c28c93 100644 --- a/external/android-emugl/host/include/libOpenglRender/IOStream.h +++ b/external/android-emugl/host/include/libOpenglRender/IOStream.h @@ -23,7 +23,6 @@ class IOStream { public: - IOStream(size_t bufSize) { m_buf = NULL; m_bufsize = bufSize; @@ -31,19 +30,15 @@ public: } virtual void *allocBuffer(size_t minSize) = 0; - virtual int commitBuffer(size_t size) = 0; - virtual const unsigned char *readFully( void *buf, size_t len) = 0; - virtual const unsigned char *read( void *buf, size_t *inout_len) = 0; - virtual int writeFully(const void* buf, size_t len) = 0; + virtual size_t commitBuffer(size_t size) = 0; + virtual const unsigned char *read(void *buf, size_t *inout_len) = 0; virtual void forceStop() = 0; virtual ~IOStream() { - // NOTE: m_buf is 'owned' by the child class thus we expect it to be released by it } unsigned char *alloc(size_t len) { - if (m_buf && len > m_free) { if (flush() < 0) { ERR("Failed to flush in alloc\n"); @@ -70,7 +65,6 @@ public: } int flush() { - if (!m_buf || m_free == m_bufsize) return 0; int stat = commitBuffer(m_bufsize - m_free); @@ -79,12 +73,6 @@ public: return stat; } - const unsigned char *readback(void *buf, size_t len) { - flush(); - return readFully(buf, len); - } - - private: unsigned char *m_buf; size_t m_bufsize; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb7c899..e44ed22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,8 @@ set(SOURCES anbox/common/variable_length_array.h anbox/common/wait_handle.cpp anbox/common/dispatcher.cpp + anbox/common/small_vector.h + anbox/common/type_traits.h anbox/container/service.cpp anbox/container/client.cpp @@ -104,6 +106,8 @@ set(SOURCES anbox/rpc/make_protobuf_object.h anbox/graphics/opengles_message_processor.cpp + anbox/graphics/buffer_queue.cpp + anbox/graphics/buffered_io_stream.cpp anbox/graphics/gl_renderer_server.cpp anbox/graphics/density.h anbox/graphics/rect.cpp @@ -120,16 +124,11 @@ set(SOURCES anbox/graphics/emugl/RenderApi.cpp anbox/graphics/emugl/RenderContext.cpp anbox/graphics/emugl/RenderControl.cpp - anbox/graphics/emugl/RenderServer.cpp anbox/graphics/emugl/RenderThread.cpp anbox/graphics/emugl/RenderThreadInfo.cpp - anbox/graphics/emugl/RenderWindow.cpp - anbox/graphics/emugl/SocketStream.cpp - anbox/graphics/emugl/TcpStream.cpp anbox/graphics/emugl/TextureDraw.cpp anbox/graphics/emugl/TextureResize.cpp anbox/graphics/emugl/TimeUtils.cpp - anbox/graphics/emugl/UnixStream.cpp anbox/graphics/emugl/WindowSurface.cpp anbox/wm/display.cpp diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index e9b71de..e23e6ea 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -128,8 +128,7 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) auto qemu_pipe_connector = std::make_shared( utils::string_format("%s/qemu_pipe", config::socket_path()), rt, - std::make_shared( - rt, renderer->socket_path(), icon_)); + std::make_shared(rt)); auto bridge_connector = std::make_shared( utils::string_format("%s/anbox_bridge", config::socket_path()), rt, diff --git a/src/anbox/common/small_vector.h b/src/anbox/common/small_vector.h new file mode 100644 index 0000000..886620e --- /dev/null +++ b/src/anbox/common/small_vector.h @@ -0,0 +1,383 @@ +// Copyright 2016 The Android Open Source Project +// +// This software is licensed under the terms of the GNU General Public +// License version 2, as published by the Free Software Foundation, and +// may be copied, distributed, and modified under those terms. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#pragma once + +#include "anbox/common/type_traits.h" + +#include +#include +#include +#include + +#include +#include + +// +// SmallVector, SmallFixedVector +// +// This header defines a replacement for a std::vector<> that uses small buffer +// optimization technique - for some preset number of elements |SmallSize| it +// stores them inside of the object, and falls back to the dynamically allocated +// array only if one needs to add more elements. +// This is useful for the performance-critical places where common number of +// processed items is small, but it may still be quite large for a stack array. +// +// SmallFixedVector<> is the class you use to store elements, while +// SmallVector<> is its base class that erases the small size from the type. +// +// NOTE: SmallVector<> cannot guarantee std::vector<>'s iterator invalidation +// rules for move() and swap() operations - std::vector<>s just exchange +// their iterators on swap() and pass the moved ones over, while SmallVector<> +// may leave the iterators pointing to nowhere if they were for the in-place +// array storage. +// +// Currenly only a limited subset of std::vector<>'s operations is implemented, +// but fill free to add the ones you need. +// + +namespace anbox { +namespace common { + +// +// Forward-declare the 'real' small vector class. +template +class SmallFixedVector; + +// +// SmallVector - an interface for a small-buffer-optimized vector. +// It hides the fixed size from its type, so one can use it to pass small +// vectors around and not leak the buffer size to all callers: +// +// void process(SmallVector& data); +// ... +// ... +// SmallFixedVector aLittleBitOfFoos = ...; +// process(aLittleBitOfFoos); +// ... +// SmallFixedVector moreFoos = ...; +// process(moreFoos); +// +template +class SmallVector { + // Make them friends so SmallFixedVector is able to refer to SmallVector's + // protected members in static_assert()s. + template + friend class SmallFixedVector; + + public: + // Common set of type aliases. + using value_type = T; + using iterator = T*; + using const_iterator = const T*; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + + // It's ok to delete SmallVector<> through the base class - dtor() actually + // takes care of all living elements and the allocated memory. + ~SmallVector() { dtor(); } + + // std::vector<> interface operations. + iterator begin() { return mBegin; } + const_iterator begin() const { return mBegin; } + const_iterator cbegin() const { return mBegin; } + + iterator end() { return mEnd; } + const_iterator end() const { return mEnd; } + const_iterator cend() const { return mEnd; } + + size_type size() const { return end() - begin(); } + size_type capacity() const { return mCapacity; } + bool empty() const { return begin() == end(); } + + reference operator[](size_t i) { return *(begin() + i); } + const_reference operator[](size_t i) const { return *(cbegin() + i); } + + pointer data() { return mBegin; } + const_pointer data() const { return mBegin; } + const_pointer cdata() const { return mBegin; } + + template + void emplace_back(Args&&... args) { + grow_for_size(size() + 1); + new (mEnd) T(std::forward(args)...); + ++mEnd; + } + + void push_back(const T& t) { emplace_back(t); } + void push_back(T&& t) { emplace_back(std::move(t)); } + + void clear() { + destruct(begin(), end()); + mEnd = mBegin; + } + + void reserve(size_type newCap) { + if (newCap <= this->capacity()) { + return; + } + set_capacity(newCap); + } + + void resize(size_type newSize) { resize_impl(newSize); } + + // This version of resizing doesn't initialize the newly allocated elements + // Useful for the cases when value-initialization is noticeably slow and + // one wants to directly construct or memcpy the elements into the resized + // place. + void resize_noinit(size_type newSize) { resize_impl(newSize); } + + // Returns if the current vector's buffer is dynamically allocated. + bool isAllocated() const { return this->cbegin() != smallBufferStart(); } + + protected: + // Hide the default constructor so only SmallFixedVector can be + // instantiated. + SmallVector() = default; + + // Destroy all elements in the vector and free the array if it was allocated + // dynamically. + void dtor() { + this->destruct(this->begin(), this->end()); + if (isAllocated()) { + free(this->mBegin); + } + } + + // Just a convenience setter function to init all members at once. + void init(iterator begin, iterator end, size_type capacity) { + this->mBegin = begin; + this->mEnd = end; + this->mCapacity = capacity; + } + + // An implementation of different resizing versions. + template + void resize_impl(size_type newSize) { + if (newSize < this->size()) { + const auto newEnd = this->begin() + newSize; + this->destruct(newEnd, this->end()); + this->mEnd = newEnd; + } else if (newSize > this->size()) { + grow_for_size(newSize); + const auto newEnd = this->begin() + newSize; + if (init) { + std::uninitialized_fill(this->end(), newEnd, T()); + } + this->mEnd = newEnd; + } + } + + // Templated append operation for a range of elements. + template + void insert_back(Iter b, Iter e) { + if (b == e) { + return; + } + const auto newSize = this->size() + (e - b); + grow_for_size(newSize); + this->mEnd = std::uninitialized_copy(b, e, this->mEnd); + } + + // Multiplicative grow for the internal array so it can hold |newSize| + // elements. + // Doesn't change size(), only capacity(). + void grow_for_size(size_type newSize) { + // Grow by 1.5x by default. + if (newSize > capacity()) { + set_capacity(std::max(newSize, capacity() + capacity() / 2)); + } + } + + // Sets the capacity() to be exacly |newCap|. Allocates the array + // dynamically, moves all elements over and (potentially) deallocates the + // old array. + // Doesn't change size(), only capacity(). + void set_capacity(size_type newCap) { + // Here we can only be switching to the dynamic vector, as static one + // always has its capacity on the maximum. + const auto newBegin = (T*)malloc(sizeof(T) * newCap); + if (!newBegin) { + abort(); // what else can we do here? + } + const auto newEnd = + std::uninitialized_copy(std::make_move_iterator(this->begin()), + std::make_move_iterator(this->end()), newBegin); + dtor(); + this->mBegin = newBegin; + this->mEnd = newEnd; + this->mCapacity = newCap; + } + + // A convenience function to call destructor for a range of elements. + static void destruct(T* b, T* e) { + if (!std::is_trivially_destructible::value) { + for (; b != e; ++b) { + b->~T(); + } + } + } + + // By design of the class, SmallFixedVector<> will be inheriting from + // SmallVector<>, so its in-place storage array is going to be the very next + // member after the last one here. + // This function returns that address, and SmallFixedVector<> has a static + // assert to make sure it remains correct. + constexpr const void* smallBufferStart() const { + return (const void*)(&mCapacity + 1); + } + + // Standard set of members for a vector - begin, end and capacity. + // These point to the currently used chunk of memory, no matter if it's a + // heap-allocated one or an in-place array. + iterator mBegin; + iterator mEnd; + size_type mCapacity; +}; + +// The implementation of a SmallVector with a fixed in-place size, |SmallSize|. +template +class SmallFixedVector : public SmallVector { + using base = SmallVector; + + public: + // Grab these from the base class. + using value_type = typename base::value_type; + using iterator = typename base::iterator; + using const_iterator = typename base::const_iterator; + using pointer = typename base::pointer; + using const_pointer = typename base::const_pointer; + using reference = typename base::reference; + using const_reference = typename base::const_reference; + using size_type = typename base::size_type; + + static constexpr size_type kSmallSize = SmallSize; + + // Default constructor - set up an empty vector with capacity at full + // internal array size. + SmallFixedVector() { + // Make sure that the small array starts exactly where base class + // expects it: right after the |mCapacity|. + static_assert(offsetof(base, mCapacity) + sizeof(base::mCapacity) == + offsetof(SmallFixedVector, mData) && + offsetof(Data, array) == 0, + "SmallFixedVector<> class layout is wrong, " + "|mData| needs to follow |mCapacity|"); + + init_inplace(); + } + + // Ctor from a range of iterators + template + SmallFixedVector(Iter b, Iter e) : SmallFixedVector() { + this->insert_back(b, e); + } + + // Ctor from a range - anything that has begin and end. + // Note: template constructor is never a copy/move-ctor. + template ::value && + is_range::value>> + explicit SmallFixedVector(const Range& r) + : SmallFixedVector(std::begin(r), std::end(r)) {} + template ::value && + is_range::value>> + explicit SmallFixedVector(Range&& r) + : SmallFixedVector(std::make_move_iterator(std::begin(r)), + std::make_move_iterator(std::end(r))) {} + template > + SmallFixedVector(std::initializer_list list) + : SmallFixedVector(std::begin(list), std::end(list)) {} + + SmallFixedVector(const SmallFixedVector& other) + : SmallFixedVector(other.begin(), other.end()) {} + + SmallFixedVector(SmallFixedVector&& other) { + if (other.isAllocated()) { + // Just steal the allocated memory from the |other|. + this->mBegin = other.mBegin; + this->mEnd = other.mEnd; + this->mCapacity = other.mCapacity; + other.init_inplace(); + } else { + // Have to move individual elements. + this->mBegin = mData.array; + this->mEnd = std::uninitialized_copy( + std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), this->begin()); + this->mCapacity = kSmallSize; + } + } + + SmallFixedVector& operator=(const SmallFixedVector& other) { + if (&other != this) { + this->clear(); + this->insert_back(other.begin(), other.end()); + } + return *this; + } + + SmallFixedVector& operator=(SmallFixedVector&& other) { + if (other.isAllocated()) { + // Steal it and we're done. + this->dtor(); + this->mBegin = other.mBegin; + this->mEnd = other.mEnd; + this->mCapacity = other.mCapacity; + other.init_inplace(); + return *this; + } + + if (this->isAllocated() && this->mCapacity < other.size()) { + // Not enough dynamic memory, switch to in-place. + this->dtor(); + init_inplace(); + } else { + // This could potentially be improved by move-assigning + // only needed items and destroying the rest, but + // destroy-all+construct-all is just simpler. For PODs it actually + // is even faster as it's always a single memcpy(). + this->destruct(this->begin(), this->end()); + } + + // Move the whole |other| into the pre-cleaned memory + const auto newEnd = std::uninitialized_copy( + std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), this->mBegin); + this->mEnd = newEnd; + // |other| is valid as-is. + return *this; + } + + // Make sure we don't end up trying to move from an interface - it's just + // inefficient with the current code. + SmallFixedVector(base&& other) = delete; + SmallFixedVector& operator=(base&& other) = delete; + + private: + // A shortcut for initialization for in-place storage. + void init_inplace() { this->init(mData.array, mData.array, kSmallSize); } + + // A union with empty constructor and destructor makes sure that the array + // elements are not default-constructed in ctor and not destructed in dtor: + // the class needs to be able manage their lifetime more precisely. + union Data { + alignas(size_type) T array[kSmallSize]; + + Data() {} + ~Data() {} + } mData; +}; + +} // namespace common +} // namespace anbox diff --git a/src/anbox/common/type_traits.h b/src/anbox/common/type_traits.h new file mode 100644 index 0000000..eb7a192 --- /dev/null +++ b/src/anbox/common/type_traits.h @@ -0,0 +1,124 @@ +// Copyright 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. + +#pragma once + +#include +#include + +namespace anbox { +namespace common { + +namespace details { + +// a simple helper class for SFINAE below. +template +struct dummy { + using type = X; +}; + +} // namespaces details + +// add some convenience shortcuts for an overly complex std::enable_if syntax + +// Use 'enable_if' instead of +// 'typename std::enable_if::type' +template +using enable_if = typename std::enable_if::type; + +// Use 'enable_if_c' instead of +// 'typename std::enable_if::type' +template +using enable_if_c = typename std::enable_if::type; + +// Use 'enable_if_convertible' instead of +// 'typename std::enable_if::value, Type>::type' +template +using enable_if_convertible = enable_if>; + +// ----------------------------------------------------------------------------- +// A predicate for checking if some object is callable with a specific +// signature. Examples: +// +// is_callable_as::value == false. +// is_callable_as::value == false. +// is_callable_as::value == true +// +template +struct is_callable_as : std::false_type {}; + +// This specialization is SFINAE-d out if template arguments can't be combined +// into a call expression F(), or if the result of that call is not |R| +template +struct is_callable_as< + F, R(), typename std::enable_if()())>::type, + R>::value>::type> : std::true_type {}; + +// One more specialization, for non empty argument list +template +struct is_callable_as()( + std::declval()...))>::type, + R>::value>::type> : std::true_type {}; +// ----------------------------------------------------------------------------- +// Check if a type |T| is any instantiation of a template |U|. Examples: +// +// is_template_instantiation_of::value == false +// is_template_instantiation_of< +// std::list>, std::vector>::value == false +// is_template_instantiation_of, std::vector>::value == true +// is_template_instantiation_of< +// std::vector>, std::vector>::value == true +// +template class U> +struct is_template_instantiation_of : std::false_type {}; + +template