diff options
72 files changed, 3101 insertions, 1384 deletions
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c index afa64f8c9d..e34053be2c 100644 --- a/cmds/keystore/keystore.c +++ b/cmds/keystore/keystore.c @@ -493,6 +493,7 @@ static struct user {      {AID_VPN,      AID_SYSTEM, GET},      {AID_WIFI,     AID_SYSTEM, GET},      {AID_ROOT,     AID_SYSTEM, GET}, +    {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW},      {~0,           ~0,         TEST | GET | INSERT | DELETE | EXIST | SAW},  }; diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp index 83cb533170..785e4cc228 100644 --- a/cmds/runtime/main_runtime.cpp +++ b/cmds/runtime/main_runtime.cpp @@ -12,7 +12,7 @@  #include <binder/IPCThreadState.h>  #include <binder/ProcessState.h> -#include <utils/Log.h>   +#include <utils/Log.h>  #include <cutils/zygote.h>  #include <cutils/properties.h> @@ -41,7 +41,7 @@  #undef LOG_TAG  #define LOG_TAG "runtime" -static const char* ZYGOTE_ARGV[] = {  +static const char* ZYGOTE_ARGV[] = {      "--setuid=1000",      "--setgid=1000",      "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003", @@ -68,7 +68,6 @@ extern Condition gEventQCondition;  namespace android { -extern status_t app_init(const char* className);  extern void set_finish_init_func(void (*func)()); @@ -76,7 +75,7 @@ extern void set_finish_init_func(void (*func)());   * This class is used to kill this process (runtime) when the system_server dies.   */  class GrimReaper : public IBinder::DeathRecipient { -public:  +public:      GrimReaper() { }      virtual void binderDied(const wp<IBinder>& who) @@ -170,7 +169,7 @@ LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");  /*   * Post-system-process initialization. - *  + *   * This function continues initialization after the system process   * has been initialized.  It needs to be separate because the system   * initialization needs to care of starting the Android runtime if it is not @@ -210,17 +209,17 @@ static bool contextChecker(  static void boot_init()  {      LOGI("Entered boot_init()!\n"); -     +      sp<ProcessState> proc(ProcessState::self());      LOGD("ProcessState: %p\n", proc.get());      proc->becomeContextManager(contextChecker, NULL); -     +      if (proc->supportsProcesses()) {          LOGI("Binder driver opened.  Multiprocess enabled.\n");      } else {          LOGI("Binder driver not found.  Processes not supported.\n");      } -     +      sp<BServiceManager> sm = new BServiceManager;      proc->setContextObject(sm);  } @@ -258,7 +257,7 @@ static void validateTime()      int res;      time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year      struct timespec ts; -     +      fd = open("/dev/alarm", O_RDWR);      if(fd < 0) {          LOGW("Unable to open alarm driver: %s\n", strerror(errno)); @@ -346,14 +345,14 @@ int main(int argc, char* const argv[])      int ic;      int result = 1;      pid_t systemPid; -     +      sp<ProcessState> proc;  #ifndef HAVE_ANDROID_OS      /* Set stdout/stderr to unbuffered for MinGW/MSYS. */      //setvbuf(stdout, NULL, _IONBF, 0);      //setvbuf(stderr, NULL, _IONBF, 0); -     +      LOGI("commandline args:\n");      for (int i = 0; i < argc; i++)          LOGI("  %2d: '%s'\n", i, argv[i]); @@ -455,7 +454,7 @@ int main(int argc, char* const argv[])  #if 0      // Hack to keep libc from beating the filesystem to death.  It's -    // hitting /etc/localtime frequently,  +    // hitting /etc/localtime frequently,      //      // This statement locks us into Pacific time.  We could do better,      // but there's not much point until we're sure that the library @@ -467,15 +466,15 @@ int main(int argc, char* const argv[])      /* track our progress through the boot sequence */      const int LOG_BOOT_PROGRESS_START = 3000; -    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  +    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,          ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));      validateTime();      proc = ProcessState::self(); -     +      boot_init(); -     +      /* If we are in multiprocess mode, have zygote spawn the system       * server process and call system_init(). If we are running in       * single process mode just call system_init() directly. @@ -488,8 +487,8 @@ int main(int argc, char* const argv[])          property_get("log.redirect-stdio", propBuf, "");          logStdio = (strcmp(propBuf, "true") == 0); -        zygote_run_oneshot((int)(!logStdio),  -                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),  +        zygote_run_oneshot((int)(!logStdio), +                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),                  ZYGOTE_ARGV);          //start_process("/system/bin/mediaserver"); @@ -497,7 +496,7 @@ int main(int argc, char* const argv[])      } else {  #ifndef HAVE_ANDROID_OS          QuickRuntime* runt = new QuickRuntime(); -        runt->start("com/android/server/SystemServer",  +        runt->start("com/android/server/SystemServer",                      false /* spontaneously fork system server from zygote */);  #endif      } @@ -506,11 +505,11 @@ int main(int argc, char* const argv[])      finish_system_init(proc);      run(proc); -     +  bail:      if (proc != NULL) {          proc->setContextObject(NULL);      } -     +      return 0;  } diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index 32c9a1d5a9..bfe13f01bc 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -53,7 +53,8 @@ public:      status_t            setData(const uint8_t* buffer, size_t len); -    status_t            appendFrom(Parcel *parcel, size_t start, size_t len); +    status_t            appendFrom(const Parcel *parcel, +                                   size_t start, size_t len);      bool                hasFileDescriptors() const; diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 585d288ed2..96828c640c 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -127,11 +127,28 @@ public:      // be called from the client.      status_t setDefaultBufferSize(uint32_t w, uint32_t h); -private: +    // getCurrentBuffer returns the buffer associated with the current image. +    sp<GraphicBuffer> getCurrentBuffer() const; + +    // getCurrentTextureTarget returns the texture target of the current +    // texture as returned by updateTexImage(). +    GLenum getCurrentTextureTarget() const; + +    // getCurrentCrop returns the cropping rectangle of the current buffer +    Rect getCurrentCrop() const; + +    // getCurrentTransform returns the transform of the current buffer +    uint32_t getCurrentTransform() const; + +protected:      // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for      // all slots.      void freeAllBuffers(); +    static bool isExternalFormat(uint32_t format); +    static GLenum getTextureTarget(uint32_t format); + +private:      // createImage creates a new EGLImage from a GraphicBuffer.      EGLImageKHR createImage(EGLDisplay dpy, @@ -194,6 +211,10 @@ private:      // reset mCurrentTexture to INVALID_BUFFER_SLOT.      int mCurrentTexture; +    // mCurrentTextureTarget is the GLES texture target to be used with the +    // current texture. +    GLenum mCurrentTextureTarget; +      // mCurrentTextureBuf is the graphic buffer of the current texture. It's      // possible that this buffer is not associated with any buffer slot, so we      // must track it separately in order to properly use @@ -248,12 +269,6 @@ private:      // allocate new GraphicBuffer objects.      sp<IGraphicBufferAlloc> mGraphicBufferAlloc; -    // mAllocdBuffers is mirror of the list of buffers that SurfaceFlinger is -    // referencing. This is kept so that gralloc implementations do not need to -    // properly handle the case where SurfaceFlinger no longer holds a reference -    // to a buffer, but other processes do. -    Vector<sp<GraphicBuffer> > mAllocdBuffers; -      // mFrameAvailableListener is the listener object that will be called when a      // new frame becomes available. If it is not NULL it will be called from      // queueBuffer. @@ -262,7 +277,7 @@ private:      // mMutex is the mutex used to prevent concurrent access to the member      // variables of SurfaceTexture objects. It must be locked whenever the      // member variables are accessed. -    Mutex mMutex; +    mutable Mutex mMutex;  };  // ---------------------------------------------------------------------------- diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index df82bf217f..fe9b04917e 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -27,6 +27,8 @@  namespace android { +class Surface; +  class SurfaceTextureClient      : public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>  { @@ -36,6 +38,7 @@ public:      sp<ISurfaceTexture> getISurfaceTexture() const;  private: +    friend class Surface;      // can't be copied      SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs); @@ -78,6 +81,8 @@ private:      void freeAllBuffers(); +    int getConnectedApi() const; +      enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };      enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };      enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS }; @@ -121,10 +126,25 @@ private:      // a timestamp is auto-generated when queueBuffer is called.      int64_t mTimestamp; +    // mConnectedApi holds the currently connected API to this surface +    int mConnectedApi; + +    // mQueryWidth is the width returned by query(). It is set to width +    // of the last dequeued buffer or to mReqWidth if no buffer was dequeued. +    uint32_t mQueryWidth; + +    // mQueryHeight is the height returned by query(). It is set to height +    // of the last dequeued buffer or to mReqHeight if no buffer was dequeued. +    uint32_t mQueryHeight; + +    // mQueryFormat is the format returned by query(). It is set to the last +    // dequeued format or to mReqFormat if no buffer was dequeued. +    uint32_t mQueryFormat; +      // mMutex is the mutex used to prevent concurrent access to the member      // variables of SurfaceTexture objects. It must be locked whenever the      // member variables are accessed. -    Mutex mMutex; +    mutable Mutex mMutex;  };  }; // namespace android diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h index d996af75a4..01e4bd9ff0 100644 --- a/include/surfaceflinger/IGraphicBufferAlloc.h +++ b/include/surfaceflinger/IGraphicBufferAlloc.h @@ -32,18 +32,10 @@ class IGraphicBufferAlloc : public IInterface  public:      DECLARE_META_INTERFACE(GraphicBufferAlloc); -    /* Create a new GraphicBuffer for the client to use.  The server will -     * maintain a reference to the newly created GraphicBuffer until -     * freeAllGraphicBuffers is called. +    /* Create a new GraphicBuffer for the client to use.       */      virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,              PixelFormat format, uint32_t usage) = 0; - -    /* Free all but one of the GraphicBuffer objects that the server is -     * currently referencing. If bufIndex is not a valid index of the buffers -     * the server is referencing, then all buffers are freed. -     */ -    virtual void freeAllGraphicBuffersExcept(int bufIndex) = 0;  };  // ---------------------------------------------------------------------------- diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h index a1e9e04884..46b1bb7e9f 100644 --- a/include/surfaceflinger/ISurfaceComposerClient.h +++ b/include/surfaceflinger/ISurfaceComposerClient.h @@ -64,7 +64,6 @@ public:       * Requires ACCESS_SURFACE_FLINGER permission       */      virtual sp<ISurface> createSurface( surface_data_t* data, -                                        int pid,                                          const String8& name,                                          DisplayID display,                                          uint32_t w, diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 25b2ebf5a7..c61a5bff2a 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -79,7 +79,6 @@ public:      //! Create a surface      sp<SurfaceControl> createSurface( -            int pid,            // pid of the process the surface is for              const String8& name,// name of the surface              DisplayID display,  // Display to create this surface on              uint32_t w,         // width in pixel @@ -89,7 +88,6 @@ public:      );      sp<SurfaceControl> createSurface( -            int pid,            // pid of the process the surface is for              DisplayID display,  // Display to create this surface on              uint32_t w,         // width in pixel              uint32_t h,         // height in pixel diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h deleted file mode 100644 index 998e35322c..0000000000 --- a/include/tts/TtsEngine.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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 <media/AudioSystem.h> - -// This header defines the interface used by the Android platform -// to access Text-To-Speech functionality in shared libraries that implement -// speech synthesis and the management of resources associated with the -// synthesis. -// An example of the implementation of this interface can be found in -// FIXME: add path+name to implementation of default TTS engine -// Libraries implementing this interface are used in: -//  frameworks/base/tts/jni/android_tts_SpeechSynthesis.cpp - -namespace android { - -#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig" -#define ANDROID_TTS_ENGINE_PROPERTY_PITCH  "pitch" -#define ANDROID_TTS_ENGINE_PROPERTY_RATE   "rate" -#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume" - - -enum tts_synth_status { -    TTS_SYNTH_DONE              = 0, -    TTS_SYNTH_PENDING           = 1 -}; - -enum tts_callback_status { -    TTS_CALLBACK_HALT           = 0, -    TTS_CALLBACK_CONTINUE       = 1 -}; - -// The callback is used by the implementation of this interface to notify its -// client, the Android TTS service, that the last requested synthesis has been -// completed. // TODO reword -// The callback for synthesis completed takes: -// @param [inout] void *&       - The userdata pointer set in the original -//                                 synth call -// @param [in]    uint32_t      - Track sampling rate in Hz -// @param [in]    uint32_t      - The audio format -// @param [in]    int           - The number of channels -// @param [inout] int8_t *&     - A buffer of audio data only valid during the -//                                execution of the callback -// @param [inout] size_t  &     - The size of the buffer -// @param [in] tts_synth_status - indicate whether the synthesis is done, or -//                                 if more data is to be synthesized. -// @return TTS_CALLBACK_HALT to indicate the synthesis must stop, -//         TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if -//            there is more data to produce. -typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t, -        uint32_t, int, int8_t *&, size_t&, tts_synth_status); - -class TtsEngine; -extern "C" TtsEngine* getTtsEngine(); - -enum tts_result { -    TTS_SUCCESS                 = 0, -    TTS_FAILURE                 = -1, -    TTS_FEATURE_UNSUPPORTED     = -2, -    TTS_VALUE_INVALID           = -3, -    TTS_PROPERTY_UNSUPPORTED    = -4, -    TTS_PROPERTY_SIZE_TOO_SMALL = -5, -    TTS_MISSING_RESOURCES       = -6 -}; - -enum tts_support_result { -    TTS_LANG_COUNTRY_VAR_AVAILABLE = 2, -    TTS_LANG_COUNTRY_AVAILABLE = 1, -    TTS_LANG_AVAILABLE = 0, -    TTS_LANG_MISSING_DATA = -1, -    TTS_LANG_NOT_SUPPORTED = -2 -}; - -class TtsEngine -{ -public: -    virtual ~TtsEngine() {} - -    // Initialize the TTS engine and returns whether initialization succeeded. -    // @param synthDoneCBPtr synthesis callback function pointer -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig); - -    // Shut down the TTS engine and releases all associated resources. -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result shutdown(); - -    // Interrupt synthesis and flushes any synthesized data that hasn't been -    // output yet. This will block until callbacks underway are completed. -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result stop(); - -    // Returns the level of support for the language, country and variant. -    // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported, -    //            and the corresponding resources are correctly installed -    //         TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the -    //             corresponding resources are correctly installed, but there is no match for -    //             the specified variant -    //         TTS_LANG_AVAILABLE if the language is supported and the -    //             corresponding resources are correctly installed, but there is no match for -    //             the specified country and variant -    //         TTS_LANG_MISSING_DATA if the required resources to provide any level of support -    //             for the language are not correctly installed -    //         TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine. -    virtual tts_support_result isLanguageAvailable(const char *lang, const char *country, -            const char *variant); - -    // Load the resources associated with the specified language. The loaded -    // language will only be used once a call to setLanguage() with the same -    // language value is issued. Language and country values are coded according to the ISO three -    // letter codes for languages and countries, as can be retrieved from a java.util.Locale -    // instance. The variant value is encoded as the variant string retrieved from a -    // java.util.Locale instance built with that variant data. -    // @param lang pointer to the ISO three letter code for the language -    // @param country pointer to the ISO three letter code for the country -    // @param variant pointer to the variant code -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant); - -    // Load the resources associated with the specified language, country and Locale variant. -    // The loaded language will only be used once a call to setLanguageFromLocale() with the same -    // language value is issued. Language and country values are coded according to the ISO three -    // letter codes for languages and countries, as can be retrieved from a java.util.Locale -    // instance. The variant value is encoded as the variant string retrieved from a -    // java.util.Locale instance built with that variant data. -    // @param lang pointer to the ISO three letter code for the language -    // @param country pointer to the ISO three letter code for the country -    // @param variant pointer to the variant code -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result setLanguage(const char *lang, const char *country, const char *variant); - -    // Retrieve the currently set language, country and variant, or empty strings if none of -    // parameters have been set. Language and country are represented by their 3-letter ISO code -    // @param[out]   pointer to the retrieved 3-letter code language value -    // @param[out]   pointer to the retrieved 3-letter code country value -    // @param[out]   pointer to the retrieved variant value -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result getLanguage(char *language, char *country, char *variant); - -    // Notifies the engine what audio parameters should be used for the synthesis. -    // This is meant to be used as a hint, the engine implementation will set the output values -    // to those of the synthesis format, based on a given hint. -    // @param[inout] encoding in: the desired audio sample format -    //                         out: the format used by the TTS engine -    // @param[inout] rate in: the desired audio sample rate -    //                         out: the sample rate used by the TTS engine -    // @param[inout] channels in: the desired number of audio channels -    //                         out: the number of channels used by the TTS engine -    // @return TTS_SUCCESS, or TTS_FAILURE -    virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate, -            int& channels); - -    // Set a property for the the TTS engine -    // "size" is the maximum size of "value" for properties "property" -    // @param property pointer to the property name -    // @param value    pointer to the property value -    // @param size     maximum size required to store this type of property -    // @return         TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE, -    //                  or TTS_VALUE_INVALID -    virtual tts_result setProperty(const char *property, const char *value, -            const size_t size); - -    // Retrieve a property from the TTS engine -    // @param        property pointer to the property name -    // @param[out]   value    pointer to the retrieved language value -    // @param[inout] iosize   in: stores the size available to store the -    //                          property value. -    //                        out: stores the size required to hold the language -    //                          value if getLanguage() returned -    //                          TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise -    // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, -    //         or TTS_PROPERTY_SIZE_TOO_SMALL -    virtual tts_result getProperty(const char *property, char *value, -            size_t *iosize); - -    // Synthesize the text. -    // As the synthesis is performed, the engine invokes the callback to notify -    // the TTS framework that it has filled the given buffer, and indicates how -    // many bytes it wrote. The callback is called repeatedly until the engine -    // has generated all the audio data corresponding to the text. -    // Note about the format of the input: the text parameter may use the -    // following elements -    // and their respective attributes as defined in the SSML 1.0 specification: -    //    * lang -    //    * say-as: -    //          o interpret-as -    //    * phoneme -    //    * voice: -    //          o gender, -    //          o age, -    //          o variant, -    //          o name -    //    * emphasis -    //    * break: -    //          o strength, -    //          o time -    //    * prosody: -    //          o pitch, -    //          o contour, -    //          o range, -    //          o rate, -    //          o duration, -    //          o volume -    //    * mark -    // Differences between this text format and SSML are: -    //    * full SSML documents are not supported -    //    * namespaces are not supported -    // Text is coded in UTF-8. -    // @param text      the UTF-8 text to synthesize -    // @param userdata  pointer to be returned when the call is invoked -    // @param buffer    the location where the synthesized data must be written -    // @param bufferSize the number of bytes that can be written in buffer -    // @return          TTS_SUCCESS or TTS_FAILURE -    virtual tts_result synthesizeText(const char *text, int8_t *buffer, -            size_t bufferSize, void *userdata); - -}; - -} // namespace android - diff --git a/include/ui/Input.h b/include/ui/Input.h index 0dc29c8e0b..9b92c73c42 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -620,6 +620,11 @@ private:      // Oldest sample to consider when calculating the velocity.      static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms +    // When the total duration of the window of samples being averaged is less +    // than the window size, the resulting velocity is scaled to reduce the impact +    // of overestimation in short traces. +    static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms +      // The minimum duration between samples when estimating velocity.      static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h index 9e2bf37e8f..a8c7ddbd78 100644 --- a/include/utils/AssetManager.h +++ b/include/utils/AssetManager.h @@ -222,6 +222,7 @@ private:      {          String8 path;          FileType type; +        String8 idmap;      };      Asset* openInPathLocked(const char* fileName, AccessMode mode, @@ -262,6 +263,16 @@ private:      void setLocaleLocked(const char* locale);      void updateResourceParamsLocked() const; +    bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, +                               const String8& idmapPath); + +    bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, +                            const String8& idmapPath); + +    Asset* openIdmapLocked(const struct asset_path& ap) const; + +    bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc); +      class SharedZip : public RefBase {      public:          static sp<SharedZip> get(const String8& path); diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 35792dc0c7..173412e415 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -1798,9 +1798,9 @@ public:      ~ResTable();      status_t add(const void* data, size_t size, void* cookie, -                 bool copyData=false); +                 bool copyData=false, const void* idmap = NULL);      status_t add(Asset* asset, void* cookie, -                 bool copyData=false); +                 bool copyData=false, const void* idmap = NULL);      status_t add(ResTable* src);      status_t getError() const; @@ -2046,6 +2046,24 @@ public:      void getLocales(Vector<String8>* locales) const; +    // Generate an idmap. +    // +    // Return value: on success: NO_ERROR; caller is responsible for free-ing +    // outData (using free(3)). On failure, any status_t value other than +    // NO_ERROR; the caller should not free outData. +    status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, +                         void** outData, size_t* outSize) const; + +    enum { +        IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t), +    }; +    // Retrieve idmap meta-data. +    // +    // This function only requires the idmap header (the first +    // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file. +    static bool getIdmapInfo(const void* idmap, size_t size, +                             uint32_t* pOriginalCrc, uint32_t* pOverlayCrc); +  #ifndef HAVE_ANDROID_OS      void print(bool inclValues) const;      static String8 normalizeForOutput(const char* input); @@ -2059,7 +2077,7 @@ private:      struct bag_set;      status_t add(const void* data, size_t size, void* cookie, -                 Asset* asset, bool copyData); +                 Asset* asset, bool copyData, const Asset* idmap);      ssize_t getResourcePackageIndex(uint32_t resID) const;      ssize_t getEntry( @@ -2068,7 +2086,7 @@ private:          const ResTable_type** outType, const ResTable_entry** outEntry,          const Type** outTypeClass) const;      status_t parsePackage( -        const ResTable_package* const pkg, const Header* const header); +        const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);      void print_value(const Package* pkg, const Res_value& value) const; diff --git a/include/utils/Vector.h b/include/utils/Vector.h index 6fd307f3b6..90477b75dd 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -165,6 +165,26 @@ public:       // for debugging only       inline size_t getItemSize() const { return itemSize(); } + +     /* +      * these inlines add some level of compatibility with STL. eventually +      * we should probably turn things around. +      */ +     typedef TYPE* iterator; +     typedef TYPE const* const_iterator; + +     inline iterator begin() { return editArray(); } +     inline iterator end()   { return editArray() + size(); } +     inline const_iterator begin() const { return array(); } +     inline const_iterator end() const   { return array() + size(); } +     inline void reserve(size_t n) { setCapacity(n); } +     inline bool empty() const{ return isEmpty(); } +     inline void push_back(const TYPE& item)  { insertAt(size(), item); } +     inline void push_front(const TYPE& item) { insertAt(0, item); } +     inline iterator erase(iterator pos) { +         return begin() + removeItemsAt(pos-array()); +     } +  protected:      virtual void    do_construct(void* storage, size_t num) const;      virtual void    do_destroy(void* storage, size_t num) const; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 95cfddf758..392193b8d9 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -851,6 +851,9 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,      tr.target.handle = handle;      tr.code = code;      tr.flags = binderFlags; +    tr.cookie = 0; +    tr.sender_pid = 0; +    tr.sender_euid = 0;      const status_t err = data.errorCheck();      if (err == NO_ERROR) { diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index d57f2c9fdc..a0fc4d05bc 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -338,7 +338,7 @@ void Parcel::setDataPosition(size_t pos) const  status_t Parcel::setDataCapacity(size_t size)  { -    if (size > mDataSize) return continueWrite(size); +    if (size > mDataCapacity) return continueWrite(size);      return NO_ERROR;  } @@ -353,12 +353,12 @@ status_t Parcel::setData(const uint8_t* buffer, size_t len)      return err;  } -status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) +status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)  {      const sp<ProcessState> proc(ProcessState::self());      status_t err; -    uint8_t *data = parcel->mData; -    size_t *objects = parcel->mObjects; +    const uint8_t *data = parcel->mData; +    const size_t *objects = parcel->mObjects;      size_t size = parcel->mObjectsSize;      int startPos = mDataPos;      int firstIndex = -1, lastIndex = -2; @@ -386,10 +386,12 @@ status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)      }      int numObjects = lastIndex - firstIndex + 1; -    // grow data -    err = growData(len); -    if (err != NO_ERROR) { -        return err; +    if ((mDataSize+len) > mDataCapacity) { +        // grow data +        err = growData(len); +        if (err != NO_ERROR) { +            return err; +        }      }      // append data @@ -1384,8 +1386,10 @@ status_t Parcel::continueWrite(size_t desired)                  return NO_MEMORY;              }          } else { -            mDataSize = desired; -            LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); +            if (mDataSize > desired) { +                mDataSize = desired; +                LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); +            }              if (mDataPos > desired) {                  mDataPos = desired;                  LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index e05da725c4..0cd51da539 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -32,7 +32,6 @@ namespace android {  enum {      CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, -    FREE_ALL_GRAPHIC_BUFFERS_EXCEPT,  };  class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc> @@ -46,8 +45,7 @@ public:      virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,              PixelFormat format, uint32_t usage) {          Parcel data, reply; -        data.writeInterfaceToken( -                IGraphicBufferAlloc::getInterfaceDescriptor()); +        data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());          data.writeInt32(w);          data.writeInt32(h);          data.writeInt32(format); @@ -58,17 +56,12 @@ public:          if (nonNull) {              graphicBuffer = new GraphicBuffer();              reply.read(*graphicBuffer); +            // reply.readStrongBinder(); +            // here we don't even have to read the BufferReference from +            // the parcel, it'll die with the parcel.          }          return graphicBuffer;      } - -    virtual void freeAllGraphicBuffersExcept(int bufIdx) { -        Parcel data, reply; -        data.writeInterfaceToken( -                IGraphicBufferAlloc::getInterfaceDescriptor()); -        data.writeInt32(bufIdx); -        remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply); -    }  };  IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); @@ -80,6 +73,17 @@ status_t BnGraphicBufferAlloc::onTransact(  {      // codes that don't require permission check +    /* BufferReference just keeps a strong reference to a +     * GraphicBuffer until it is destroyed (that is, until +     * no local or remote process have a reference to it). +     */ +    class BufferReference : public BBinder { +        sp<GraphicBuffer> buffer; +    public: +        BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { } +    }; + +      switch(code) {          case CREATE_GRAPHIC_BUFFER: {              CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); @@ -91,15 +95,16 @@ status_t BnGraphicBufferAlloc::onTransact(              reply->writeInt32(result != 0);              if (result != 0) {                  reply->write(*result); +                // We add a BufferReference to this parcel to make sure the +                // buffer stays alive until the GraphicBuffer object on +                // the other side has been created. +                // This is needed so that the buffer handle can be +                // registered before the buffer is destroyed on implementations +                // that do not use file-descriptors to track their buffers. +                reply->writeStrongBinder( new BufferReference(result) );              }              return NO_ERROR;          } break; -        case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: { -            CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); -            int bufIdx = data.readInt32(); -            freeAllGraphicBuffersExcept(bufIdx); -            return NO_ERROR; -        } break;          default:              return BBinder::onTransact(code, data, reply, flags);      } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 7730eb1fa9..ea38e08a55 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -83,7 +83,6 @@ public:      }      virtual sp<ISurface> createSurface( surface_data_t* params, -                                        int pid,                                          const String8& name,                                          DisplayID display,                                          uint32_t w, @@ -93,7 +92,6 @@ public:      {          Parcel data, reply;          data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); -        data.writeInt32(pid);          data.writeString8(name);          data.writeInt32(display);          data.writeInt32(w); @@ -172,14 +170,13 @@ status_t BnSurfaceComposerClient::onTransact(          case CREATE_SURFACE: {              CHECK_INTERFACE(ISurfaceComposerClient, data, reply);              surface_data_t params; -            int32_t pid = data.readInt32();              String8 name = data.readString8();              DisplayID display = data.readInt32();              uint32_t w = data.readInt32();              uint32_t h = data.readInt32();              PixelFormat format = data.readInt32();              uint32_t flags = data.readInt32(); -            sp<ISurface> s = createSurface(¶ms, pid, name, display, w, h, +            sp<ISurface> s = createSurface(¶ms, name, display, w, h,                      format, flags);              params.writeToParcel(reply);              reply->writeStrongBinder(s->asBinder()); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d3367246a1..a1ff2c1e2f 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -273,7 +273,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays()  }  sp<SurfaceControl> SurfaceComposerClient::createSurface( -        int pid,          DisplayID display,          uint32_t w,          uint32_t h, @@ -286,12 +285,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(      snprintf(buffer, SIZE, "<pid_%d>", getpid());      name.append(buffer); -    return SurfaceComposerClient::createSurface(pid, name, display, +    return SurfaceComposerClient::createSurface(name, display,              w, h, format, flags);  }  sp<SurfaceControl> SurfaceComposerClient::createSurface( -        int pid,          const String8& name,          DisplayID display,          uint32_t w, @@ -302,7 +300,7 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(      sp<SurfaceControl> result;      if (mStatus == NO_ERROR) {          ISurfaceComposerClient::surface_data_t data; -        sp<ISurface> surface = mClient->createSurface(&data, pid, name, +        sp<ISurface> surface = mClient->createSurface(&data, name,                  display, w, h, format, flags);          if (surface != 0) {              result = new SurfaceControl(this, surface, data, w, h, format, flags); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index f4e2a67616..39418f03ad 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -27,6 +27,8 @@  #include <gui/SurfaceTexture.h> +#include <hardware/hardware.h> +  #include <surfaceflinger/ISurfaceComposer.h>  #include <surfaceflinger/SurfaceComposerClient.h>  #include <surfaceflinger/IGraphicBufferAlloc.h> @@ -82,6 +84,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :      mUseDefaultSize(true),      mBufferCount(MIN_BUFFER_SLOTS),      mCurrentTexture(INVALID_BUFFER_SLOT), +    mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),      mCurrentTransform(0),      mCurrentTimestamp(0),      mLastQueued(INVALID_BUFFER_SLOT), @@ -172,7 +175,6 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,              mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;              mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;          } -        mAllocdBuffers.add(graphicBuffer);      }      return graphicBuffer;  } @@ -198,6 +200,7 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) {      if (buffer == NULL) {          return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;      } +      if ((mUseDefaultSize) &&          ((uint32_t(buffer->width) != mDefaultWidth) ||           (uint32_t(buffer->height) != mDefaultHeight))) { @@ -264,9 +267,6 @@ status_t SurfaceTexture::updateTexImage() {      LOGV("SurfaceTexture::updateTexImage");      Mutex::Autolock lock(mMutex); -    // We always bind the texture even if we don't update its contents. -    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); -      // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,      // so this check will fail until a buffer gets queued.      if (mCurrentTexture != mLastQueued) { @@ -284,7 +284,15 @@ status_t SurfaceTexture::updateTexImage() {          while ((error = glGetError()) != GL_NO_ERROR) {              LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);          } -        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); + +        GLenum target = getTextureTarget( +                mSlots[mLastQueued].mGraphicBuffer->format); +        if (target != mCurrentTextureTarget) { +            glDeleteTextures(1, &mTexName); +        } +        glBindTexture(target, mTexName); +        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image); +          bool failed = false;          while ((error = glGetError()) != GL_NO_ERROR) {              LOGE("error binding external texture image %p (slot %d): %#04x", @@ -297,14 +305,53 @@ status_t SurfaceTexture::updateTexImage() {          // Update the SurfaceTexture state.          mCurrentTexture = mLastQueued; +        mCurrentTextureTarget = target;          mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;          mCurrentCrop = mLastQueuedCrop;          mCurrentTransform = mLastQueuedTransform;          mCurrentTimestamp = mLastQueuedTimestamp; +    } else { +        // We always bind the texture even if we don't update its contents. +        glBindTexture(mCurrentTextureTarget, mTexName);      }      return OK;  } +bool SurfaceTexture::isExternalFormat(uint32_t format) +{ +    switch (format) { +    // supported YUV formats +    case HAL_PIXEL_FORMAT_YV12: +    // Legacy/deprecated YUV formats +    case HAL_PIXEL_FORMAT_YCbCr_422_SP: +    case HAL_PIXEL_FORMAT_YCrCb_420_SP: +    case HAL_PIXEL_FORMAT_YCbCr_422_I: +        return true; +    } + +    // Any OEM format needs to be considered +    if (format>=0x100 && format<=0x1FF) +        return true; + +    return false; +} + +GLenum SurfaceTexture::getTextureTarget(uint32_t format) +{ +    GLenum target = GL_TEXTURE_2D; +#if defined(GL_OES_EGL_image_external) +    if (isExternalFormat(format)) { +        target = GL_TEXTURE_EXTERNAL_OES; +    } +#endif +    return target; +} + +GLenum SurfaceTexture::getCurrentTextureTarget() const { +    Mutex::Autolock lock(mMutex); +    return mCurrentTextureTarget; +} +  void SurfaceTexture::getTransformMatrix(float mtx[16]) {      LOGV("SurfaceTexture::getTransformMatrix");      Mutex::Autolock lock(mMutex); @@ -425,19 +472,6 @@ void SurfaceTexture::freeAllBuffers() {              mSlots[i].mEglDisplay = EGL_NO_DISPLAY;          }      } - -    int exceptBuf = -1; -    for (size_t i = 0; i < mAllocdBuffers.size(); i++) { -        if (mAllocdBuffers[i] == mCurrentTextureBuf) { -            exceptBuf = i; -            break; -        } -    } -    mAllocdBuffers.clear(); -    if (exceptBuf >= 0) { -        mAllocdBuffers.add(mCurrentTextureBuf); -    } -    mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);  }  EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, @@ -459,6 +493,22 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,      return image;  } +sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const { +    Mutex::Autolock lock(mMutex); +    return mCurrentTextureBuf; +} + +Rect SurfaceTexture::getCurrentCrop() const { +    Mutex::Autolock lock(mMutex); +    return mCurrentCrop; +} + +uint32_t SurfaceTexture::getCurrentTransform() const { +    Mutex::Autolock lock(mMutex); +    return mCurrentTransform; +} + +  static void mtxMul(float out[16], const float a[16], const float b[16]) {      out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];      out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 29fc4d3edc..f4b24162f0 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -26,8 +26,10 @@ namespace android {  SurfaceTextureClient::SurfaceTextureClient(          const sp<ISurfaceTexture>& surfaceTexture):          mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0), -        mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), -        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() { +        mReqHeight(0), mReqFormat(0), mReqUsage(0), +        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0), +        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0), +        mMutex() {      // Initialize the ANativeWindow function pointers.      ANativeWindow::setSwapInterval  = setSwapInterval;      ANativeWindow::dequeueBuffer    = dequeueBuffer; @@ -101,9 +103,10 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {      }      sp<GraphicBuffer>& gbuf(mSlots[buf]);      if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION || -        gbuf == 0 || gbuf->getWidth() != mReqWidth || -        gbuf->getHeight() != mReqHeight || -        uint32_t(gbuf->getPixelFormat()) != mReqFormat || +        gbuf == 0 || +        (mReqWidth && gbuf->getWidth() != mReqWidth) || +        (mReqHeight && gbuf->getHeight() != mReqHeight) || +        (mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||          (gbuf->getUsage() & mReqUsage) != mReqUsage) {          gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,                  mReqFormat, mReqUsage); @@ -111,6 +114,9 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {              LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");              return NO_MEMORY;          } +        mQueryWidth  = gbuf->width; +        mQueryHeight = gbuf->height; +        mQueryFormat = gbuf->format;      }      *buffer = gbuf.get();      return OK; @@ -159,13 +165,13 @@ int SurfaceTextureClient::query(int what, int* value) {      Mutex::Autolock lock(mMutex);      switch (what) {      case NATIVE_WINDOW_WIDTH: +        *value = mQueryWidth ? mQueryWidth : mReqWidth; +        return NO_ERROR;      case NATIVE_WINDOW_HEIGHT: -        // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't -        // override the size? -        *value = 0; +        *value = mQueryHeight ? mQueryHeight : mReqHeight;          return NO_ERROR;      case NATIVE_WINDOW_FORMAT: -        *value = DEFAULT_FORMAT; +        *value = mQueryFormat ? mQueryFormat : mReqFormat;          return NO_ERROR;      case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:          *value = MIN_UNDEQUEUED_BUFFERS; @@ -260,16 +266,49 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {  int SurfaceTextureClient::connect(int api) {      LOGV("SurfaceTextureClient::connect"); -    // XXX: Implement this! -    return INVALID_OPERATION; +    Mutex::Autolock lock(mMutex); +    int err = NO_ERROR; +    switch (api) { +        case NATIVE_WINDOW_API_EGL: +            if (mConnectedApi) { +                err = -EINVAL; +            } else { +                mConnectedApi = api; +            } +            break; +        default: +            err = -EINVAL; +            break; +    } +    return err;  }  int SurfaceTextureClient::disconnect(int api) {      LOGV("SurfaceTextureClient::disconnect"); -    // XXX: Implement this! -    return INVALID_OPERATION; +    Mutex::Autolock lock(mMutex); +    int err = NO_ERROR; +    switch (api) { +        case NATIVE_WINDOW_API_EGL: +            if (mConnectedApi == api) { +                mConnectedApi = 0; +            } else { +                err = -EINVAL; +            } +            break; +        default: +            err = -EINVAL; +            break; +    } +    return err;  } +int SurfaceTextureClient::getConnectedApi() const +{ +    Mutex::Autolock lock(mMutex); +    return mConnectedApi; +} + +  int SurfaceTextureClient::setUsage(uint32_t reqUsage)  {      LOGV("SurfaceTextureClient::setUsage"); diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 348171dcf3..db781dec0e 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -64,7 +64,7 @@ TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) {      ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(anw.get(), &buf, NULL));  } -TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) { +TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {      sp<ANativeWindow> anw(mSTC);      EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -94,8 +94,8 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) {      EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, anw.get(),              NULL); -    ASSERT_EQ(EGL_NO_SURFACE, eglSurface); -    ASSERT_EQ(EGL_BAD_NATIVE_WINDOW, eglGetError()); +    ASSERT_NE(EGL_NO_SURFACE, eglSurface); +    ASSERT_EQ(EGL_SUCCESS, eglGetError());      eglTerminate(dpy);  } diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index 4184463496..6c713439dc 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -76,7 +76,7 @@ protected:              mComposerClient = new SurfaceComposerClient;              ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); -            mSurfaceControl = mComposerClient->createSurface(getpid(), +            mSurfaceControl = mComposerClient->createSurface(                      String8("Test Surface"), 0,                      getSurfaceWidth(), getSurfaceHeight(),                      PIXEL_FORMAT_RGB_888, 0); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index fd07479a05..440a48b7c0 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -30,7 +30,7 @@ protected:          mComposerClient = new SurfaceComposerClient;          ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); -        mSurfaceControl = mComposerClient->createSurface(getpid(), +        mSurfaceControl = mComposerClient->createSurface(                  String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);          ASSERT_TRUE(mSurfaceControl != NULL); diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index bbe579ea83..a95f432619 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -832,6 +832,7 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const          const Position& oldestPosition =                  oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];          nsecs_t lastDuration = 0; +          while (numTouches-- > 1) {              if (++index == HISTORY_SIZE) {                  index = 0; @@ -858,6 +859,14 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const          // Make sure we used at least one sample.          if (samplesUsed != 0) { +            // Scale the velocity linearly if the window of samples is small. +            nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime; +            if (totalDuration < MIN_WINDOW) { +                float scale = float(totalDuration) / float(MIN_WINDOW); +                accumVx *= scale; +                accumVy *= scale; +            } +              *outVx = accumVx;              *outVy = accumVy;              return true; diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 9d1b8b94ec..93d0d1f8a1 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -27,8 +27,14 @@  namespace android { +#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1)) +#define MIN_HISTORY_DEPTH 20 +  // Must be at least sizeof(InputMessage) + sufficient space for pointer data -static const int DEFAULT_MESSAGE_BUFFER_SIZE = 16384; +static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP( +        sizeof(InputMessage) + MIN_HISTORY_DEPTH +                * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)), +        4096);  // Signal sent by the producer to the consumer to inform it that a new message is  // available to be consumed in the shared memory buffer. diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 6e57d93d8b..e41dd39682 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -37,6 +37,19 @@  #include <errno.h>  #include <assert.h>  #include <strings.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({         \ +    typeof (exp) _rc;                      \ +    do {                                   \ +        _rc = (exp);                       \ +    } while (_rc == -1 && errno == EINTR); \ +    _rc; }) +#endif  using namespace android; @@ -49,6 +62,7 @@ static const char* kDefaultVendor = "default";  static const char* kAssetsRoot = "assets";  static const char* kAppZipName = NULL; //"classes.jar";  static const char* kSystemAssets = "framework/framework-res.apk"; +static const char* kIdmapCacheDir = "resource-cache";  static const char* kExcludeExtension = ".EXCLUDE"; @@ -56,6 +70,35 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d;  static volatile int32_t gCount = 0; +namespace { +    // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap +    String8 idmapPathForPackagePath(const String8& pkgPath) +    { +        const char* root = getenv("ANDROID_DATA"); +        LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set"); +        String8 path(root); +        path.appendPath(kIdmapCacheDir); + +        char buf[256]; // 256 chars should be enough for anyone... +        strncpy(buf, pkgPath.string(), 255); +        buf[255] = '\0'; +        char* filename = buf; +        while (*filename && *filename == '/') { +            ++filename; +        } +        char* p = filename; +        while (*p) { +            if (*p == '/') { +                *p = '@'; +            } +            ++p; +        } +        path.appendPath(filename); +        path.append("@idmap"); + +        return path; +    } +}  /*   * =========================================================================== @@ -123,7 +166,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)              return true;          }      } -     +      LOGV("In %p Asset %s path: %s", this,           ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); @@ -134,9 +177,181 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)          *cookie = (void*)mAssetPaths.size();      } +    // add overlay packages for /system/framework; apps are handled by the +    // (Java) package manager +    if (strncmp(path.string(), "/system/framework/", 18) == 0) { +        // When there is an environment variable for /vendor, this +        // should be changed to something similar to how ANDROID_ROOT +        // and ANDROID_DATA are used in this file. +        String8 overlayPath("/vendor/overlay/framework/"); +        overlayPath.append(path.getPathLeaf()); +        if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) { +            asset_path oap; +            oap.path = overlayPath; +            oap.type = ::getFileType(overlayPath.string()); +            bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay +            if (addOverlay) { +                oap.idmap = idmapPathForPackagePath(overlayPath); + +                if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) { +                    addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap); +                } +            } +            if (addOverlay) { +                mAssetPaths.add(oap); +            } else { +                LOGW("failed to add overlay package %s\n", overlayPath.string()); +            } +        } +    } + +    return true; +} + +bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, +                                      const String8& idmapPath) +{ +    struct stat st; +    if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) { +        if (errno == ENOENT) { +            return true; // non-existing idmap is always stale +        } else { +            LOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno)); +            return false; +        } +    } +    if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) { +        LOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size); +        return false; +    } +    int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY)); +    if (fd == -1) { +        LOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno)); +        return false; +    } +    char buf[ResTable::IDMAP_HEADER_SIZE_BYTES]; +    ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES; +    for (;;) { +        ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft, +                                            bytesLeft)); +        if (r < 0) { +            TEMP_FAILURE_RETRY(close(fd)); +            return false; +        } +        bytesLeft -= r; +        if (bytesLeft == 0) { +            break; +        } +    } +    TEMP_FAILURE_RETRY(close(fd)); + +    uint32_t cachedOriginalCrc, cachedOverlayCrc; +    if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES, +                                &cachedOriginalCrc, &cachedOverlayCrc)) { +        return false; +    } + +    uint32_t actualOriginalCrc, actualOverlayCrc; +    if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) { +        return false; +    } +    if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) { +        return false; +    } +    return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc; +} + +bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, +                                        uint32_t* pCrc) +{ +    asset_path ap; +    ap.path = zipPath; +    const ZipFileRO* zip = getZipFileLocked(ap); +    if (zip == NULL) { +        return false; +    } +    const ZipEntryRO entry = zip->findEntryByName(entryFilename); +    if (entry == NULL) { +        return false; +    } +    if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) { +        return false; +    }      return true;  } +bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, +                                         const String8& idmapPath) +{ +    LOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n", +         __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string()); +    ResTable tables[2]; +    const String8* paths[2] = { &originalPath, &overlayPath }; +    uint32_t originalCrc, overlayCrc; +    bool retval = false; +    ssize_t offset = 0; +    int fd = 0; +    uint32_t* data = NULL; +    size_t size; + +    for (int i = 0; i < 2; ++i) { +        asset_path ap; +        ap.type = kFileTypeRegular; +        ap.path = *paths[i]; +        Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); +        if (ass == NULL) { +            LOGW("failed to find resources.arsc in %s\n", ap.path.string()); +            goto error; +        } +        tables[i].add(ass, (void*)1, false); +    } + +    if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) { +        LOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string()); +        goto error; +    } +    if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) { +        LOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string()); +        goto error; +    } + +    if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc, +                              (void**)&data, &size) != NO_ERROR) { +        LOGW("failed to generate idmap data for file %s\n", idmapPath.string()); +        goto error; +    } + +    // This should be abstracted (eg replaced by a stand-alone +    // application like dexopt, triggered by something equivalent to +    // installd). +    fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644)); +    if (fd == -1) { +        LOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno)); +        goto error_free; +    } +    for (;;) { +        ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size)); +        if (written < 0) { +            LOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(), +                 strerror(errno)); +            goto error_close; +        } +        size -= (size_t)written; +        offset += written; +        if (size == 0) { +            break; +        } +    } + +    retval = true; +error_close: +    TEMP_FAILURE_RETRY(close(fd)); +error_free: +    free(data); +error: +    return retval; +} +  bool AssetManager::addDefaultAssets()  {      const char* root = getenv("ANDROID_ROOT"); @@ -405,6 +620,7 @@ const ResTable* AssetManager::getResTable(bool required) const          ResTable* sharedRes = NULL;          bool shared = true;          const asset_path& ap = mAssetPaths.itemAt(i); +        Asset* idmap = openIdmapLocked(ap);          LOGV("Looking for resource asset in '%s'\n", ap.path.string());          if (ap.type != kFileTypeDirectory) {              if (i == 0) { @@ -434,7 +650,7 @@ const ResTable* AssetManager::getResTable(bool required) const                      // can quickly copy it out for others.                      LOGV("Creating shared resources for %s", ap.path.string());                      sharedRes = new ResTable(); -                    sharedRes->add(ass, (void*)(i+1), false); +                    sharedRes->add(ass, (void*)(i+1), false, idmap);                      sharedRes = const_cast<AssetManager*>(this)->                          mZipSet.setZipResourceTable(ap.path, sharedRes);                  } @@ -458,7 +674,7 @@ const ResTable* AssetManager::getResTable(bool required) const                  rt->add(sharedRes);              } else {                  LOGV("Parsing resources for %s", ap.path.string()); -                rt->add(ass, (void*)(i+1), !shared); +                rt->add(ass, (void*)(i+1), !shared, idmap);              }              if (!shared) { @@ -499,6 +715,21 @@ void AssetManager::updateResourceParamsLocked() const      res->setParameters(mConfig);  } +Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const +{ +    Asset* ass = NULL; +    if (ap.idmap.size() != 0) { +        ass = const_cast<AssetManager*>(this)-> +            openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER); +        if (ass) { +            LOGV("loading idmap %s\n", ap.idmap.string()); +        } else { +            LOGW("failed to load idmap %s\n", ap.idmap.string()); +        } +    } +    return ass; +} +  const ResTable& AssetManager::getResources(bool required) const  {      const ResTable* rt = getResTable(required); diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp index d5dd126065..b54fb9dd73 100644 --- a/libs/utils/Looper.cpp +++ b/libs/utils/Looper.cpp @@ -662,7 +662,8 @@ void Looper::wakeAndLock() {  #endif  void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) { -    sendMessageAtTime(LLONG_MIN, handler, message); +    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); +    sendMessageAtTime(now, handler, message);  }  void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler, diff --git a/libs/utils/README b/libs/utils/README index 36a706d5c0..01741e0930 100644 --- a/libs/utils/README +++ b/libs/utils/README @@ -1,4 +1,6 @@  Android Utility Function Library +================================ +  If you need a feature that is native to Linux but not present on other  platforms, construct a platform-dependent implementation that shares @@ -12,3 +14,276 @@ The ultimate goal is *not* to create a super-duper platform abstraction  layer.  The goal is to provide an optimized solution for Linux with  reasonable implementations for other platforms. + + +Resource overlay +================ + + +Introduction +------------ + +Overlay packages are special .apk files which provide no code but +additional resource values (and possibly new configurations) for +resources in other packages. When an application requests resources, +the system will return values from either the application's original +package or any associated overlay package. Any redirection is completely +transparent to the calling application. + +Resource values have the following precedence table, listed in +descending precedence. + + * overlay package, matching config (eg res/values-en-land) + + * original package, matching config + + * overlay package, no config (eg res/values) + + * original package, no config + +During compilation, overlay packages are differentiated from regular +packages by passing the -o flag to aapt. + + +Background +---------- + +This section provides generic background material on resources in +Android. + + +How resources are bundled in .apk files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Android .apk files are .zip files, usually housing .dex code, +certificates and resources, though packages containing resources but +no code are possible. Resources can be divided into the following +categories; a `configuration' indicates a set of phone language, display +density, network operator, etc. + + * assets: uncompressed, raw files packaged as part of an .apk and +           explicitly referenced by filename. These files are +           independent of configuration. + + * res/drawable: bitmap or xml graphics. Each file may have different +                 values depending on configuration. + + * res/values: integers, strings, etc. Each resource may have different +               values depending on configuration. + +Resource meta information and information proper is stored in a binary +format in a named file resources.arsc, bundled as part of the .apk. + +Resource IDs and lookup +~~~~~~~~~~~~~~~~~~~~~~~ +During compilation, the aapt tool gathers application resources and +generates a resources.arsc file. Each resource name is assigned an +integer ID 0xppttiii (translated to a symbolic name via R.java), where + + * pp: corresponds to the package namespace (details below). + + * tt: corresponds to the resource type (string, int, etc). Every +       resource of the same type within the same package has the same +       tt value, but depending on available types, the actual numerical +       value may be different between packages. + + * iiii: sequential number, assigned in the order resources are found. + +Resource values are specified paired with a set of configuration +constraints (the default being the empty set), eg res/values-sv-port +which imposes restrictions on language (Swedish) and display orientation +(portrait). During lookup, every constraint set is matched against the +current configuration, and the value corresponding to the best matching +constraint set is returned (ResourceTypes.{h,cpp}). + +Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility +is governed by AssetManager.cpp, which tracks loaded resources per +process. + +Assets are looked up by path and filename in AssetManager.cpp. The path +to resources in res/drawable are located by ResourceTypes.cpp and then +handled like assets by AssetManager.cpp. Other resources are handled +solely by ResourceTypes.cpp. + +Package ID as namespace +~~~~~~~~~~~~~~~~~~~~~~~ +The pp part of a resource ID defines a namespace. Android currently +defines two namespaces: + + * 0x01: system resources (pre-installed in framework-res.apk) + + * 0x7f: application resources (bundled in the application .apk) + +ResourceTypes.cpp supports package IDs between 0x01 and 0x7f +(inclusive); values outside this range are invalid. + +Each running (Dalvik) process is assigned a unique instance of +AssetManager, which in turn keeps a forest structure of loaded +resource.arsc files. Normally, this forest is structured as follows, +where mPackageMap is the internal vector employed in ResourceTypes.cpp. + +mPackageMap[0x00] -> system package +mPackageMap[0x01] -> NULL +mPackageMap[0x02] -> NULL +... +mPackageMap[0x7f - 2] -> NULL +mPackageMap[0x7f - 1] -> application package + + + +The resource overlay extension +------------------------------ + +The resource overlay mechanism aims to (partly) shadow and extend +existing resources with new values for defined and new configurations. +Technically, this is achieved by adding resource-only packages (called +overlay packages) to existing resource namespaces, like so: + +mPackageMap[0x00] -> system package -> system overlay package +mPackageMap[0x01] -> NULL +mPackageMap[0x02] -> NULL +... +mPackageMap[0x7f - 2] -> NULL +mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2 + +The use of overlay resources is completely transparent to +applications; no additional resource identifiers are introduced, only +configuration/value pairs. Any number of overlay packages may be loaded +at a time; overlay packages are agnostic to what they target -- both +system and application resources are fair game. + +The package targeted by an overlay package is called the target or +original package. + +Resource overlay operates on symbolic resources names. Hence, to +override the string/str1 resources in a package, the overlay package +would include a resource also named string/str1. The end user does not +have to worry about the numeric resources IDs assigned by aapt, as this +is resolved automatically by the system. + +As of this writing, the use of resource overlay has not been fully +explored. Until it has, only OEMs are trusted to use resource overlay. +For this reason, overlay packages must reside in /system/overlay. + + +Resource ID mapping +~~~~~~~~~~~~~~~~~~~ +Resource identifiers must be coherent within the same namespace (ie +PackageGroup in ResourceTypes.cpp). Calling applications will refer to +resources using the IDs defined in the original package, but there is no +guarantee aapt has assigned the same ID to the corresponding resource in +an overlay package. To translate between the two, a resource ID mapping +{original ID -> overlay ID} is created during package installation +(PackageManagerService.java) and used during resource lookup. The +mapping is stored in /data/resource-cache, with a @idmap file name +suffix. + +The idmap file format is documented in a separate section, below. + + +Package management +~~~~~~~~~~~~~~~~~~ +Packages are managed by the PackageManagerService. Addition and removal +of packages are monitored via the inotify framework, exposed via +android.os.FileObserver. + +During initialization of a Dalvik process, ActivityThread.java requests +the process' AssetManager (by proxy, via AssetManager.java and JNI) +to load a list of packages. This list includes overlay packages, if +present. + +When a target package or a corresponding overlay package is installed, +the target package's process is stopped and a new idmap is generated. +This is similar to how applications are stopped when their packages are +upgraded. + + +Creating overlay packages +------------------------- + +Overlay packages should contain no code, define (some) resources with +the same type and name as in the original package, and be compiled with +the -o flag passed to aapt. + +The aapt -o flag instructs aapt to create an overlay package. +Technically, this means the package will be assigned package id 0x00. + +There are no restrictions on overlay packages names, though the naming +convention <original.package.name>.overlay.<name> is recommended. + + +Example overlay package +~~~~~~~~~~~~~~~~~~~~~~~ + +To overlay the resource bool/b in package com.foo.bar, to be applied +when the display is in landscape mode, create a new package with +no source code and a single .xml file under res/values-land, with +an entry for bool/b. Compile with aapt -o and place the results in +/system/overlay by adding the following to Android.mk: + +LOCAL_AAPT_FLAGS := -o com.foo.bar +LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay + + +The ID map (idmap) file format +------------------------------ + +The idmap format is designed for lookup performance. However, leading +and trailing undefined overlay values are discarded to reduce the memory +footprint. + + +idmap grammar +~~~~~~~~~~~~~ +All atoms (names in square brackets) are uint32_t integers. The +idmap-magic constant spells "idmp" in ASCII. Offsets are given relative +to the data_header, not to the beginning of the file. + +map          := header data +header       := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg> +idmap-magic  := <0x706d6469> +data         := data_header type_block+ +data_header  := <m> header_block{m} +header_block := <0> | <type_block_offset> +type_block   := <n> <id_offset> entry{n} +entry        := <resource_id_in_target_package> + + +idmap example +~~~~~~~~~~~~~ +Given a pair of target and overlay packages with CRC sums 0x216a8fe2 +and 0x6b9beaec, each defining the following resources + +Name          Target package  Overlay package +string/str0   0x7f010000      - +string/str1   0x7f010001      0x7f010000 +string/str2   0x7f010002      - +string/str3   0x7f010003      0x7f010001 +string/str4   0x7f010004      - +bool/bool0    0x7f020000      - +integer/int0  0x7f030000      0x7f020000 +integer/int1  0x7f030001      - + +the corresponding resource map is + +0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \ +0x00000004 0x00000000 0x00000009 0x00000003 \ +0x00000001 0x7f010000 0x00000000 0x7f010001 \ +0x00000001 0x00000000 0x7f020000 + +or, formatted differently + +0x706d6469  # magic: all idmap files begin with this constant +0x216a8fe2  # CRC32 of the resources.arsc file in the original package +0x6b9beaec  # CRC32 of the resources.arsc file in the overlay package +0x00000003  # header; three types (string, bool, integer) in the target package +0x00000004  #   header_block for type 0 (string) is located at offset 4 +0x00000000  #   no bool type exists in overlay package -> no header_block +0x00000009  #   header_block for type 2 (integer) is located at offset 9 +0x00000003  # header_block for string; overlay IDs span 3 elements +0x00000001  #   the first string in target package is entry 1 == offset +0x7f010000  #   target 0x7f01001 -> overlay 0x7f010000 +0x00000000  #   str2 not defined in overlay package +0x7f010001  #   target 0x7f010003 -> overlay 0x7f010001 +0x00000001  # header_block for integer; overlay IDs span 1 element +0x00000000  #   offset == 0 +0x7f020000  #   target 0x7f030000 -> overlay 0x7f020000 diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index ac9cdf9f9f..784c9d284d 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -63,6 +63,10 @@ namespace android {  #endif  #endif +#define IDMAP_MAGIC         0x706d6469 +// size measured in sizeof(uint32_t) +#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t)) +  static void printToLogFunc(void* cookie, const char* txt)  {      LOGV("%s", txt); @@ -214,6 +218,81 @@ static void deserializeInternal(const void* inData, Res_png_9patch* outData) {      outData->colors = (uint32_t*) data;  } +static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes) +{ +    if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) { +        LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes); +        return false; +    } +    if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess +        LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n", +             *map, htodl(IDMAP_MAGIC)); +        return false; +    } +    return true; +} + +static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue) +{ +    // see README for details on the format of map +    if (!assertIdmapHeader(map, sizeBytes)) { +        return UNKNOWN_ERROR; +    } +    map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment +    // size of data block, in uint32_t +    const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t); +    const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id +    const uint32_t entry = Res_GETENTRY(key); +    const uint32_t typeCount = *map; + +    if (type > typeCount) { +        LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount); +        return UNKNOWN_ERROR; +    } +    if (typeCount > size) { +        LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size); +        return UNKNOWN_ERROR; +    } +    const uint32_t typeOffset = map[type]; +    if (typeOffset == 0) { +        *outValue = 0; +        return NO_ERROR; +    } +    if (typeOffset + 1 > size) { +        LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n", +             typeOffset, size); +        return UNKNOWN_ERROR; +    } +    const uint32_t entryCount = map[typeOffset]; +    const uint32_t entryOffset = map[typeOffset + 1]; +    if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) { +        *outValue = 0; +        return NO_ERROR; +    } +    const uint32_t index = typeOffset + 2 + entry - entryOffset; +    if (index > size) { +        LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size); +        *outValue = 0; +        return NO_ERROR; +    } +    *outValue = map[index]; + +    return NO_ERROR; +} + +static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId) +{ +    if (!assertIdmapHeader(map, mapSize)) { +        return UNKNOWN_ERROR; +    } +    const uint32_t* p = map + IDMAP_HEADER_SIZE + 1; +    while (*p == 0) { +        ++p; +    } +    *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff; +    return NO_ERROR; +} +  Res_png_9patch* Res_png_9patch::deserialize(const void* inData)  {      if (sizeof(void*) != sizeof(int32_t)) { @@ -1290,7 +1369,13 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const  struct ResTable::Header  { -    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { } +    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL), +        resourceIDMap(NULL), resourceIDMapSize(0) { } + +    ~Header() +    { +        free(resourceIDMap); +    }      ResTable* const                 owner;      void*                           ownedData; @@ -1301,6 +1386,8 @@ struct ResTable::Header      void*                           cookie;      ResStringPool                   values; +    uint32_t*                       resourceIDMap; +    size_t                          resourceIDMapSize;  };  struct ResTable::Type @@ -1716,12 +1803,13 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const      return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;  } -status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData) +status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData, +                       const void* idmap)  { -    return add(data, size, cookie, NULL, copyData); +    return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap));  } -status_t ResTable::add(Asset* asset, void* cookie, bool copyData) +status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap)  {      const void* data = asset->getBuffer(true);      if (data == NULL) { @@ -1729,7 +1817,7 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData)          return UNKNOWN_ERROR;      }      size_t size = (size_t)asset->getLength(); -    return add(data, size, cookie, asset, copyData); +    return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap));  }  status_t ResTable::add(ResTable* src) @@ -1757,19 +1845,30 @@ status_t ResTable::add(ResTable* src)  }  status_t ResTable::add(const void* data, size_t size, void* cookie, -                       Asset* asset, bool copyData) +                       Asset* asset, bool copyData, const Asset* idmap)  {      if (!data) return NO_ERROR;      Header* header = new Header(this);      header->index = mHeaders.size();      header->cookie = cookie; +    if (idmap != NULL) { +        const size_t idmap_size = idmap->getLength(); +        const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true); +        header->resourceIDMap = (uint32_t*)malloc(idmap_size); +        if (header->resourceIDMap == NULL) { +            delete header; +            return (mError = NO_MEMORY); +        } +        memcpy((void*)header->resourceIDMap, idmap_data, idmap_size); +        header->resourceIDMapSize = idmap_size; +    }      mHeaders.add(header);      const bool notDeviceEndian = htods(0xf0) != 0xf0;      LOAD_TABLE_NOISY( -        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n", -             data, size, cookie, asset, copyData)); +        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d " +             "idmap=%p\n", data, size, cookie, asset, copyData, idmap));      if (copyData || notDeviceEndian) {          header->ownedData = malloc(size); @@ -1836,7 +1935,16 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,                       dtohl(header->header->packageCount));                  return (mError=BAD_TYPE);              } -            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) { +            uint32_t idmap_id = 0; +            if (idmap != NULL) { +                uint32_t tmp; +                if (getIdmapPackageId(header->resourceIDMap, +                                      header->resourceIDMapSize, +                                      &tmp) == NO_ERROR) { +                    idmap_id = tmp; +                } +            } +            if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {                  return mError;              }              curPackage++; @@ -1858,6 +1966,7 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,      if (mError != NO_ERROR) {          LOGW("No string values found in resource table!");      } +      TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));      return mError;  } @@ -2002,17 +2111,38 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag      size_t ip = grp->packages.size();      while (ip > 0) {          ip--; +        int T = t; +        int E = e;          const Package* const package = grp->packages[ip]; +        if (package->header->resourceIDMap) { +            uint32_t overlayResID = 0x0; +            status_t retval = idmapLookup(package->header->resourceIDMap, +                                          package->header->resourceIDMapSize, +                                          resID, &overlayResID); +            if (retval == NO_ERROR && overlayResID != 0x0) { +                // for this loop iteration, this is the type and entry we really want +                LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID); +                T = Res_GETTYPE(overlayResID); +                E = Res_GETENTRY(overlayResID); +            } else { +                // resource not present in overlay package, continue with the next package +                continue; +            } +        }          const ResTable_type* type;          const ResTable_entry* entry;          const Type* typeClass; -        ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass); +        ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);          if (offset <= 0) { -            if (offset < 0) { +            // No {entry, appropriate config} pair found in package. If this +            // package is an overlay package (ip != 0), this simply means the +            // overlay package did not specify a default. +            // Non-overlay packages are still required to provide a default. +            if (offset < 0 && ip == 0) {                  LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n", -                        resID, t, e, ip, (int)offset); +                        resID, T, E, ip, (int)offset);                  rc = offset;                  goto out;              } @@ -2044,13 +2174,16 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag          if (outSpecFlags != NULL) {              if (typeClass->typeSpecFlags != NULL) { -                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]); +                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);              } else {                  *outSpecFlags = -1;              }          } -         -        if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) { + +        if (bestPackage != NULL && +            (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) { +            // Discard thisConfig not only if bestItem is more specific, but also if the two configs +            // are identical (diff == 0), or overlay packages will not take effect.              continue;          } @@ -2250,21 +2383,45 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,      TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID)); +    ResTable_config bestConfig; +    memset(&bestConfig, 0, sizeof(bestConfig)); +      // Now collect all bag attributes from all packages.      size_t ip = grp->packages.size();      while (ip > 0) {          ip--; +        int T = t; +        int E = e;          const Package* const package = grp->packages[ip]; +        if (package->header->resourceIDMap) { +            uint32_t overlayResID = 0x0; +            status_t retval = idmapLookup(package->header->resourceIDMap, +                                          package->header->resourceIDMapSize, +                                          resID, &overlayResID); +            if (retval == NO_ERROR && overlayResID != 0x0) { +                // for this loop iteration, this is the type and entry we really want +                LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID); +                T = Res_GETTYPE(overlayResID); +                E = Res_GETENTRY(overlayResID); +            } else { +                // resource not present in overlay package, continue with the next package +                continue; +            } +        }          const ResTable_type* type;          const ResTable_entry* entry;          const Type* typeClass; -        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e); -        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass); +        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E); +        ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);          LOGV("Resulting offset=%d\n", offset);          if (offset <= 0) { -            if (offset < 0) { +            // No {entry, appropriate config} pair found in package. If this +            // package is an overlay package (ip != 0), this simply means the +            // overlay package did not specify a default. +            // Non-overlay packages are still required to provide a default. +            if (offset < 0 && ip == 0) {                  if (set) free(set);                  return offset;              } @@ -2277,6 +2434,15 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,              continue;          } +        if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) { +            continue; +        } +        bestConfig = type->config; +        if (set) { +            free(set); +            set = NULL; +        } +          const uint16_t entrySize = dtohs(entry->size);          const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)              ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0; @@ -2288,43 +2454,41 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,          TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",                           entrySize, parent, count)); -        if (set == NULL) { -            // If this map inherits from another, we need to start -            // with its parent's values.  Otherwise start out empty. -            TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", -                         entrySize, parent)); -            if (parent) { -                const bag_entry* parentBag; -                uint32_t parentTypeSpecFlags = 0; -                const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags); -                const size_t NT = ((NP >= 0) ? NP : 0) + N; -                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT); -                if (set == NULL) { -                    return NO_MEMORY; -                } -                if (NP > 0) { -                    memcpy(set+1, parentBag, NP*sizeof(bag_entry)); -                    set->numAttrs = NP; -                    TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP)); -                } else { -                    TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n")); -                    set->numAttrs = 0; -                } -                set->availAttrs = NT; -                set->typeSpecFlags = parentTypeSpecFlags; +        // If this map inherits from another, we need to start +        // with its parent's values.  Otherwise start out empty. +        TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", +                           entrySize, parent)); +        if (parent) { +            const bag_entry* parentBag; +            uint32_t parentTypeSpecFlags = 0; +            const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags); +            const size_t NT = ((NP >= 0) ? NP : 0) + N; +            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT); +            if (set == NULL) { +                return NO_MEMORY; +            } +            if (NP > 0) { +                memcpy(set+1, parentBag, NP*sizeof(bag_entry)); +                set->numAttrs = NP; +                TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));              } else { -                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N); -                if (set == NULL) { -                    return NO_MEMORY; -                } +                TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));                  set->numAttrs = 0; -                set->availAttrs = N; -                set->typeSpecFlags = 0;              } +            set->availAttrs = NT; +            set->typeSpecFlags = parentTypeSpecFlags; +        } else { +            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N); +            if (set == NULL) { +                return NO_MEMORY; +            } +            set->numAttrs = 0; +            set->availAttrs = N; +            set->typeSpecFlags = 0;          }          if (typeClass->typeSpecFlags != NULL) { -            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]); +            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);          } else {              set->typeSpecFlags = -1;          } @@ -3870,7 +4034,7 @@ ssize_t ResTable::getEntry(  }  status_t ResTable::parsePackage(const ResTable_package* const pkg, -                                const Header* const header) +                                const Header* const header, uint32_t idmap_id)  {      const uint8_t* base = (const uint8_t*)pkg;      status_t err = validate_chunk(&pkg->header, sizeof(*pkg), @@ -3904,8 +4068,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,      Package* package = NULL;      PackageGroup* group = NULL; -    uint32_t id = dtohl(pkg->id); -    if (id != 0 && id < 256) { +    uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id); +    // If at this point id == 0, pkg is an overlay package without a +    // corresponding idmap. During regular usage, overlay packages are +    // always loaded alongside their idmaps, but during idmap creation +    // the package is temporarily loaded by itself. +    if (id < 256) {          package = new Package(this, header, pkg);          if (package == NULL) { @@ -3958,7 +4126,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,              return (mError=err);          }      } else { -        LOG_ALWAYS_FATAL("Skins not supported!"); +        LOG_ALWAYS_FATAL("Package id out of range");          return NO_ERROR;      } @@ -4112,6 +4280,136 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,      return NO_ERROR;  } +status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, +                               void** outData, size_t* outSize) const +{ +    // see README for details on the format of map +    if (mPackageGroups.size() == 0) { +        return UNKNOWN_ERROR; +    } +    if (mPackageGroups[0]->packages.size() == 0) { +        return UNKNOWN_ERROR; +    } + +    Vector<Vector<uint32_t> > map; +    const PackageGroup* pg = mPackageGroups[0]; +    const Package* pkg = pg->packages[0]; +    size_t typeCount = pkg->types.size(); +    // starting size is header + first item (number of types in map) +    *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t); +    const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name); +    const uint32_t pkg_id = pkg->package->id << 24; + +    for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) { +        ssize_t offset = -1; +        const Type* typeConfigs = pkg->getType(typeIndex); +        ssize_t mapIndex = map.add(); +        if (mapIndex < 0) { +            return NO_MEMORY; +        } +        Vector<uint32_t>& vector = map.editItemAt(mapIndex); +        for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) { +            uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) +                | (0x00ff0000 & ((typeIndex+1)<<16)) +                | (0x0000ffff & (entryIndex)); +            resource_name resName; +            if (!this->getResourceName(resID, &resName)) { +                return UNKNOWN_ERROR; +            } + +            const String16 overlayType(resName.type, resName.typeLen); +            const String16 overlayName(resName.name, resName.nameLen); +            uint32_t overlayResID = overlay.identifierForName(overlayName.string(), +                                                              overlayName.size(), +                                                              overlayType.string(), +                                                              overlayType.size(), +                                                              overlayPackage.string(), +                                                              overlayPackage.size()); +            if (overlayResID != 0) { +                // overlay package has package ID == 0, use original package's ID instead +                overlayResID |= pkg_id; +            } +            vector.push(overlayResID); +            if (overlayResID != 0 && offset == -1) { +                offset = Res_GETENTRY(resID); +            } +#if 0 +            if (overlayResID != 0) { +                LOGD("%s/%s 0x%08x -> 0x%08x\n", +                     String8(String16(resName.type)).string(), +                     String8(String16(resName.name)).string(), +                     resID, overlayResID); +            } +#endif +        } + +        if (offset != -1) { +            // shave off leading and trailing entries which lack overlay values +            vector.removeItemsAt(0, offset); +            vector.insertAt((uint32_t)offset, 0, 1); +            while (vector.top() == 0) { +                vector.pop(); +            } +            // reserve space for number and offset of entries, and the actual entries +            *outSize += (2 + vector.size()) * sizeof(uint32_t); +        } else { +            // no entries of current type defined in overlay package +            vector.clear(); +            // reserve space for type offset +            *outSize += 1 * sizeof(uint32_t); +        } +    } + +    if ((*outData = malloc(*outSize)) == NULL) { +        return NO_MEMORY; +    } +    uint32_t* data = (uint32_t*)*outData; +    *data++ = htodl(IDMAP_MAGIC); +    *data++ = htodl(originalCrc); +    *data++ = htodl(overlayCrc); +    const size_t mapSize = map.size(); +    *data++ = htodl(mapSize); +    size_t offset = mapSize; +    for (size_t i = 0; i < mapSize; ++i) { +        const Vector<uint32_t>& vector = map.itemAt(i); +        const size_t N = vector.size(); +        if (N == 0) { +            *data++ = htodl(0); +        } else { +            offset++; +            *data++ = htodl(offset); +            offset += N; +        } +    } +    for (size_t i = 0; i < mapSize; ++i) { +        const Vector<uint32_t>& vector = map.itemAt(i); +        const size_t N = vector.size(); +        if (N == 0) { +            continue; +        } +        *data++ = htodl(N - 1); // do not count the offset (which is vector's first element) +        for (size_t j = 0; j < N; ++j) { +            const uint32_t& overlayResID = vector.itemAt(j); +            *data++ = htodl(overlayResID); +        } +    } + +    return NO_ERROR; +} + +bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, +                            uint32_t* pOriginalCrc, uint32_t* pOverlayCrc) +{ +    const uint32_t* map = (const uint32_t*)idmap; +    if (!assertIdmapHeader(map, sizeBytes)) { +        return false; +    } +    *pOriginalCrc = map[1]; +    *pOverlayCrc = map[2]; +    return true; +} + +  #ifndef HAVE_ANDROID_OS  #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string()) diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index 7d72729e1e..0747efb186 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -13,8 +13,8 @@ LOCAL_SRC_FILES:= 	       \  	EGL/hooks.cpp 	       \  	EGL/Loader.cpp 	       \  # -LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf -LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport + +LOCAL_SHARED_LIBRARIES += libcutils libutils libGLESv2_dbg  LOCAL_LDLIBS := -lpthread -ldl  LOCAL_MODULE:= libEGL  LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 6474c87bbd..aabba28bbb 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -46,6 +46,7 @@  #include "egl_impl.h"  #include "Loader.h"  #include "glesv2dbg.h" +#include "egl_tls.h"  #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r) @@ -58,7 +59,7 @@ namespace android {  static char const * const gVendorString     = "Android";  static char const * const gVersionString    = "1.4 Android META-EGL";  static char const * const gClientApiString  = "OpenGL ES"; -static char const * const gExtensionString  =  +static char const * const gExtensionString  =          "EGL_KHR_image "          "EGL_KHR_image_base "          "EGL_KHR_image_pixmap " @@ -221,18 +222,15 @@ struct egl_surface_t : public egl_object_t  struct egl_context_t : public egl_object_t  {      typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref; -     +      egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, -            int impl, egl_connection_t const* cnx, int version)  -    : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),  -      impl(impl), cnx(cnx), version(version), dbg(NULL) +            int impl, egl_connection_t const* cnx, int version) +    : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0), +      impl(impl), cnx(cnx), version(version)      {      }      ~egl_context_t()      { -        if (dbg) -            DestroyDbgContext(dbg); -        dbg = NULL;      }      EGLDisplay                  dpy;      EGLContext                  context; @@ -242,7 +240,6 @@ struct egl_context_t : public egl_object_t      int                         impl;      egl_connection_t const*     cnx;      int                         version; -    DbgContext *                dbg;  };  struct egl_image_t : public egl_object_t @@ -277,15 +274,6 @@ typedef egl_context_t::Ref  ContextRef;  typedef egl_image_t::Ref    ImageRef;  typedef egl_sync_t::Ref     SyncRef; -struct tls_t -{ -    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { } -    EGLint      error; -    EGLContext  ctx; -    EGLBoolean  logCallWithNoContext; -}; - -  // ----------------------------------------------------------------------------  static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; @@ -323,7 +311,7 @@ static void initEglTraceLevel() {      int propertyLevel = atoi(value);      int applicationLevel = gEGLApplicationTraceLevel;      gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel; -     +      property_get("debug.egl.debug_proc", value, "");      long pid = getpid();      char procPath[128] = {}; @@ -336,14 +324,20 @@ static void initEglTraceLevel() {          {              if (!strcmp(value, cmdline))                  gEGLDebugLevel = 1; -        }     +        }          fclose(file);      } -     +      if (gEGLDebugLevel > 0)      {          property_get("debug.egl.debug_port", value, "5039"); -        StartDebugServer(atoi(value)); +        const unsigned short port = (unsigned short)atoi(value); +        property_get("debug.egl.debug_forceUseFile", value, "0"); +        const bool forceUseFile = (bool)atoi(value); +        property_get("debug.egl.debug_maxFileSize", value, "8"); +        const unsigned int maxFileSize = atoi(value) << 20; +        property_get("debug.egl.debug_filePath", value, "/data/local/tmp/dump.gles2dbg"); +        StartDebugServer(port, forceUseFile, maxFileSize, value);      }  } @@ -586,7 +580,7 @@ static inline NATIVE* egl_to_native_cast(EGL arg) {  }  static inline -egl_surface_t* get_surface(EGLSurface surface) {    +egl_surface_t* get_surface(EGLSurface surface) {      return egl_to_native_cast<egl_surface_t>(surface);  } @@ -595,11 +589,6 @@ egl_context_t* get_context(EGLContext context) {      return egl_to_native_cast<egl_context_t>(context);  } -DbgContext * getDbgContextThreadSpecific() -{ -    return get_context(getContext())->dbg; -} -  static inline  egl_image_t* get_image(EGLImageKHR image) {      return egl_to_native_cast<egl_image_t>(image); @@ -1143,16 +1132,6 @@ EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,          EGLConfig iConfig = dp->configs[intptr_t(config)].config;          EGLint format; -        // for now fail if the window is not a Surface. -        int type = -1; -        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window); -        if ((anw->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0) || -                (type == NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT)) { -            LOGE("native window is a SurfaceTextureClient (currently " -                    "unsupported)"); -            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); -        } -          // set the native window's buffers format to match this config          if (cnx->egl.eglGetConfigAttrib(iDpy,                  iConfig, EGL_NATIVE_VISUAL_ID, &format)) { @@ -1442,10 +1421,12 @@ EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,          loseCurrent(cur_c);          if (ctx != EGL_NO_CONTEXT) { -            if (!c->dbg && gEGLDebugLevel > 0) -                c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]);              setGLHooksThreadSpecific(c->cnx->hooks[c->version]);              setContext(ctx); +            tls_t * const tls = getTLS(); +            if (!tls->dbg && gEGLDebugLevel > 0) +                tls->dbg = CreateDbgContext(gEGLThreadLocalStorageKey, c->version, +                                            c->cnx->hooks[c->version]);              _c.acquire();              _r.acquire();              _d.acquire(); diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk index fc40799724..9f6e68c4da 100644 --- a/opengl/libs/GLES2_dbg/Android.mk +++ b/opengl/libs/GLES2_dbg/Android.mk @@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \      src/server.cpp \      src/vertex.cpp -LOCAL_C_INCLUDES :=	\ +LOCAL_C_INCLUDES := \      $(LOCAL_PATH) \      $(LOCAL_PATH)/../ \      external/stlport/stlport \ @@ -21,7 +21,8 @@ LOCAL_C_INCLUDES :=	\  #LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG  LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI - +LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-2.3.0-lite liblzf +LOCAL_SHARED_LIBRARIES := libcutils libutils libstlport  ifeq ($(TARGET_ARCH),arm)  	LOCAL_CFLAGS += -fstrict-aliasing  endif @@ -43,4 +44,6 @@ endif  LOCAL_MODULE:= libGLESv2_dbg  LOCAL_MODULE_TAGS := optional -include $(BUILD_STATIC_LIBRARY) +include $(BUILD_SHARED_LIBRARY) + +include $(LOCAL_PATH)/test/Android.mk diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py index 66c110f4a1..96cde57bc1 100755 --- a/opengl/libs/GLES2_dbg/generate_api_cpp.py +++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py @@ -26,36 +26,36 @@ def RemoveAnnotation(line):          return line.replace(annotation, "*")      else:          return line -     +  def generate_api(lines):      externs = []      i = 0      # these have been hand written -    skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"] -     +    skipFunctions = ["glDrawArrays", "glDrawElements"] +      # these have an EXTEND_Debug_* macro for getting data -    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource", -"glTexImage2D", "glTexSubImage2D"] -     +    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels", +"glShaderSource", "glTexImage2D", "glTexSubImage2D"] +      # these also needs to be forwarded to DbgContext -    contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",  +    contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",  "glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",] -     +      for line in lines:          if line.find("API_ENTRY(") >= 0: # a function prototype              returnType = line[0: line.find(" API_ENTRY(")]              functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name              parameterList = line[line.find(")(") + 2: line.find(") {")] -             +              #if line.find("*") >= 0:              #    extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)              #    externs.append(extern)              #    continue -             +              if functionName in skipFunctions:                  sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))                  continue -                 +              parameters = parameterList.split(',')              paramIndex = 0              if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer @@ -65,21 +65,21 @@ def generate_api(lines):                      sys.stderr.write("%s should be hand written\n" % (extern))                      print "// FIXME: this function has pointers, it should be hand written"                      externs.append(extern) -                 +              print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))              print "    glesv2debugger::Message msg;" -     +              if parameterList == "void":                  parameters = []              arguments = ""              paramNames = []              inout = ""              getData = "" -             +              callerMembers = ""              setCallerMembers = ""              setMsgParameters = "" -             +              for parameter in parameters:                  const = parameter.find("const")                  parameter = parameter.replace("const", "") @@ -107,17 +107,17 @@ def generate_api(lines):                          annotation = "strlen(%s)" % (paramName)                      else:                          count = int(annotation) -             +                      setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)                      if paramType.find("void") >= 0:                          getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)                      else:                          getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)                      paramType += "*" -                else:      +                else:                      if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:                          setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName) -                    else:  +                    else:                          setMsgParameters += "    msg.set_arg%d(%s);\n" % (paramIndex, paramName)                  if paramIndex < len(parameters) - 1:                          arguments += ', ' @@ -127,7 +127,7 @@ def generate_api(lines):                  paramIndex += 1                  callerMembers += "        %s %s;\n" % (paramType, paramName)                  setCallerMembers += "    caller.%s = %s;\n" % (paramName, paramName) -             +              print "    struct : public FunctionCall {"              print callerMembers              print "        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {" @@ -141,6 +141,11 @@ def generate_api(lines):              if inout in ["out", "inout"]:                  print "            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"                  print "        " + getData +            if functionName in extendFunctions: +                print "\ +#ifdef EXTEND_AFTER_CALL_Debug_%s\n\ +            EXTEND_AFTER_CALL_Debug_%s;\n\ +#endif" % (functionName, functionName)              if functionName in contextFunctions:                  print "            getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)              if returnType == "void": @@ -151,13 +156,16 @@ def generate_api(lines):      } caller;"""              print setCallerMembers              print setMsgParameters -     +              if line.find("*") >= 0 or line.find(":") >= 0:                  print "    // FIXME: check for pointer usage"              if inout in ["in", "inout"]:                  print getData              if functionName in extendFunctions: -                print "    EXTEND_Debug_%s;" % (functionName)  +                print "\ +#ifdef EXTEND_Debug_%s\n\ +    EXTEND_Debug_%s;\n\ +#endif" % (functionName, functionName)              print "    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\                  % (functionName)              if returnType != "void": @@ -166,8 +174,8 @@ def generate_api(lines):                  else:                      print "    return reinterpret_cast<%s>(ret);" % (returnType)              print "}\n" -                         -             + +      print "// FIXME: the following functions should be written by hand"      for extern in externs:          print extern @@ -189,18 +197,23 @@ if __name__ == "__main__":   ** See the License for the specific language governing permissions and   ** limitations under the License.   */ -  +  // auto generated by generate_api_cpp.py +#include <utils/Debug.h> +  #include "src/header.h"  #include "src/api.h" -template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; } -template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; } -"""     +template<typename T> static int ToInt(const T & t) +{ +    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int)); +    return (int &)t; +} +"""      lines = open("gl2_api_annotated.in").readlines()      generate_api(lines)      #lines = open("gl2ext_api.in").readlines()      #generate_api(lines) -             + diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py index eac2292a82..ee4208dd3d 100755 --- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py +++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py @@ -177,7 +177,6 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &  {      LOGD("GenerateCall function=%u", cmd.function());      const int * ret = prevRet; // only some functions have return value -    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;      nsecs_t c0 = systemTime(timeMode);      switch (cmd.function()) {""") diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py index 466c447cff..535b13e185 100755 --- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py +++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py @@ -25,7 +25,7 @@ def generate_egl_entries(output, lines, i):              line = line.split(",")[1].strip() #extract EGL function name              output.write("        %s = %d;\n" % (line, i))              i += 1 -    return i     +    return i  def generate_gl_entries(output,lines,i): @@ -70,41 +70,43 @@ message Message  """)      i = 0; -     +      lines = open("gl2_api_annotated.in").readlines()      i = generate_gl_entries(output, lines, i)      output.write("        // end of GL functions\n") -     +      #lines = open("gl2ext_api.in").readlines()      #i = generate_gl_entries(output, lines, i)      #output.write("        // end of GL EXT functions\n") -     +      lines = open("../EGL/egl_entries.in").readlines()      i = generate_egl_entries(output, lines, i)      output.write("        // end of GL EXT functions\n") -     +      output.write("        ACK = %d;\n" % (i))      i += 1 -     +      output.write("        NEG = %d;\n" % (i))      i += 1 -     +      output.write("        CONTINUE = %d;\n" % (i))      i += 1 -     +      output.write("        SKIP = %d;\n" % (i))      i += 1 -     +      output.write("        SETPROP = %d;\n" % (i))      i += 1 -     +      output.write("""    }      required Function function = 2 [default = NEG]; // type/function of message      enum Type      {          BeforeCall = 0;          AfterCall = 1; -        Response = 2; // currently used for misc messages +        AfterGeneratedCall = 2; +        Response = 3; // currently used for misc messages +        CompleteCall = 4; // BeforeCall and AfterCall merged      }      required Type type = 3;      required bool expect_response = 4; @@ -116,7 +118,7 @@ message Message      optional int32 arg4 = 16;      optional int32 arg5 = 17;      optional int32 arg6 = 18; -    optional int32 arg7 = 19; +    optional int32 arg7 = 19; // glDrawArrays/Elements sets this to active number of attributes      optional int32 arg8 = 20;      optional bytes data = 10; // variable length data used for GL call @@ -125,16 +127,22 @@ message Message          ReferencedImage = 0; // for image sourced from ReadPixels          NonreferencedImage = 1; // for image sourced from ReadPixels      }; -    optional DataType data_type = 23; // most data types can be inferred from function -    optional int32 pixel_format = 24; // used for image data if format and type  -    optional int32 pixel_type = 25;   //     cannot be determined from arg  -     +    // most data types can be inferred from function +    optional DataType data_type = 23; +    // these are used for image data when they cannot be determined from args +    optional int32 pixel_format = 24; +    optional int32 pixel_type = 25; +    optional int32 image_width = 26; +    optional int32 image_height = 27; +      optional float time = 11; // duration of previous GL call (ms)      enum Prop      { -        Capture = 0; // arg0 = true | false +        CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels          TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h          ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false +        CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels +        GLConstant = 4; // arg0 = GLenum, arg1 = constant; send GL impl. constants      };      optional Prop prop = 21; // used with SETPROP, value in arg0      optional float clock = 22; // wall clock in seconds @@ -142,6 +150,6 @@ message Message  """)      output.close() -     +      os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")      os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"') diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp index 130ca7e048..c4835478d2 100644 --- a/opengl/libs/GLES2_dbg/src/api.cpp +++ b/opengl/libs/GLES2_dbg/src/api.cpp @@ -16,11 +16,16 @@  // auto generated by generate_api_cpp.py +#include <utils/Debug.h> +  #include "src/header.h"  #include "src/api.h" -template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; } -template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; } +template<typename T> static int ToInt(const T & t) +{ +    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int)); +    return (int &)t; +}  void Debug_glActiveTexture(GLenum texture)  { @@ -592,6 +597,9 @@ void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, G          const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {              _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); +#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D +            EXTEND_AFTER_CALL_Debug_glCopyTexImage2D; +#endif              return 0;          }      } caller; @@ -613,7 +621,9 @@ void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, G      msg.set_arg6(height);      msg.set_arg7(border); +#ifdef EXTEND_Debug_glCopyTexImage2D      EXTEND_Debug_glCopyTexImage2D; +#endif      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);  } @@ -632,6 +642,9 @@ void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint          const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {              _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D +            EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D; +#endif              return 0;          }      } caller; @@ -653,7 +666,9 @@ void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint      msg.set_arg6(width);      msg.set_arg7(height); +#ifdef EXTEND_Debug_glCopyTexSubImage2D      EXTEND_Debug_glCopyTexSubImage2D; +#endif      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);  } @@ -2164,6 +2179,49 @@ void Debug_glPolygonOffset(GLfloat factor, GLfloat units)      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);  } +void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +{ +    glesv2debugger::Message msg; +    struct : public FunctionCall { +        GLint x; +        GLint y; +        GLsizei width; +        GLsizei height; +        GLenum format; +        GLenum type; +        GLvoid* pixels; + +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            _c->glReadPixels(x, y, width, height, format, type, pixels); +#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels +            EXTEND_AFTER_CALL_Debug_glReadPixels; +#endif +            return 0; +        } +    } caller; +    caller.x = x; +    caller.y = y; +    caller.width = width; +    caller.height = height; +    caller.format = format; +    caller.type = type; +    caller.pixels = pixels; + +    msg.set_arg0(x); +    msg.set_arg1(y); +    msg.set_arg2(width); +    msg.set_arg3(height); +    msg.set_arg4(format); +    msg.set_arg5(type); +    msg.set_arg6(ToInt(pixels)); + +    // FIXME: check for pointer usage +#ifdef EXTEND_Debug_glReadPixels +    EXTEND_Debug_glReadPixels; +#endif +    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels); +} +  void Debug_glReleaseShaderCompiler(void)  {      glesv2debugger::Message msg; @@ -2297,6 +2355,9 @@ void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, c          const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {              _c->glShaderSource(shader, count, string, length); +#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource +            EXTEND_AFTER_CALL_Debug_glShaderSource; +#endif              return 0;          }      } caller; @@ -2311,7 +2372,9 @@ void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, c      msg.set_arg3(ToInt(length));      // FIXME: check for pointer usage +#ifdef EXTEND_Debug_glShaderSource      EXTEND_Debug_glShaderSource; +#endif      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);  } @@ -2472,6 +2535,9 @@ void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsize          const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {              _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); +#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D +            EXTEND_AFTER_CALL_Debug_glTexImage2D; +#endif              return 0;          }      } caller; @@ -2496,7 +2562,9 @@ void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsize      msg.set_arg8(ToInt(pixels));      // FIXME: check for pointer usage +#ifdef EXTEND_Debug_glTexImage2D      EXTEND_Debug_glTexImage2D; +#endif      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);  } @@ -2616,6 +2684,9 @@ void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoff          const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {              _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); +#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D +            EXTEND_AFTER_CALL_Debug_glTexSubImage2D; +#endif              return 0;          }      } caller; @@ -2640,7 +2711,9 @@ void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoff      msg.set_arg8(ToInt(pixels));      // FIXME: check for pointer usage +#ifdef EXTEND_Debug_glTexSubImage2D      EXTEND_Debug_glTexSubImage2D; +#endif      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);  } diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h index b9fc341e3e..0b227bc66c 100644 --- a/opengl/libs/GLES2_dbg/src/api.h +++ b/opengl/libs/GLES2_dbg/src/api.h @@ -16,19 +16,29 @@  #define EXTEND_Debug_glCopyTexImage2D \      DbgContext * const dbg = getDbgContextThreadSpecific(); \ -    GLint readFormat, readType; \ -    dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \ -    dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \ -    unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \ -    void * readData = dbg->GetReadPixelsBuffer(readSize); \ -    dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \ +    void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \ +    /* pick easy format for client to convert */ \ +    dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \      dbg->CompressReadPixelBuffer(msg.mutable_data()); \      msg.set_data_type(msg.ReferencedImage); \ -    msg.set_pixel_format(readFormat); \ -    msg.set_pixel_type(readType); +    msg.set_pixel_format(GL_RGBA); \ +    msg.set_pixel_type(GL_UNSIGNED_BYTE);  #define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D +#define EXTEND_AFTER_CALL_Debug_glReadPixels \ +    { \ +        DbgContext * const dbg = getDbgContextThreadSpecific(); \ +        if (dbg->IsReadPixelBuffer(pixels)) { \ +            dbg->CompressReadPixelBuffer(msg.mutable_data()); \ +            msg.set_data_type(msg.ReferencedImage); \ +        } else { \ +            const unsigned int size = width * height * GetBytesPerPixel(format, type); \ +            dbg->Compress(pixels, size, msg.mutable_data()); \ +            msg.set_data_type(msg.NonreferencedImage); \ +        } \ +    } +  #define EXTEND_Debug_glShaderSource \      std::string * const data = msg.mutable_data(); \      for (unsigned i = 0; i < count; i++) \ diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp index 9992f05fe6..6b72751bd0 100644 --- a/opengl/libs/GLES2_dbg/src/caller.cpp +++ b/opengl/libs/GLES2_dbg/src/caller.cpp @@ -105,7 +105,6 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &  {      LOGD("GenerateCall function=%u", cmd.function());      const int * ret = prevRet; // only some functions have return value -    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;      nsecs_t c0 = systemTime(timeMode);      switch (cmd.function()) {    case glesv2debugger::Message_Function_glActiveTexture:          dbg->hooks->gl.glActiveTexture( @@ -772,7 +771,7 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &      msg.set_time((systemTime(timeMode) - c0) * 1e-6f);      msg.set_context_id(reinterpret_cast<int>(dbg));      msg.set_function(cmd.function()); -    msg.set_type(glesv2debugger::Message_Type_AfterCall); +    msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);      return ret;  } diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h index 54477575aa..e8111b3292 100644 --- a/opengl/libs/GLES2_dbg/src/caller.h +++ b/opengl/libs/GLES2_dbg/src/caller.h @@ -138,7 +138,9 @@ static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,          const glesv2debugger::Message & cmd,          glesv2debugger::Message & msg, const int * const prevRet)  { -    assert(0); +    GLint params = -1; +    dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), ¶ms); +    msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));      return prevRet;  } @@ -146,7 +148,10 @@ static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,          const glesv2debugger::Message & cmd,          glesv2debugger::Message & msg, const int * const prevRet)  { -    assert(0); +    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize()); +    GLsizei length = -1; +    dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer()); +    msg.mutable_data()->append(dbg->GetBuffer(), length);      return prevRet;  } @@ -162,7 +167,9 @@ static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,                                          const glesv2debugger::Message & cmd,                                          glesv2debugger::Message & msg, const int * const prevRet)  { -    assert(0); +    GLint params = -1; +    dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), ¶ms); +    msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));      return prevRet;  } @@ -170,7 +177,10 @@ static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,          const glesv2debugger::Message & cmd,          glesv2debugger::Message & msg, const int * const prevRet)  { -    assert(0); +    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize()); +    GLsizei length = -1; +    dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer()); +    msg.mutable_data()->append(dbg->GetBuffer(), length);      return prevRet;  } diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp index cc7336cf31..7f5b27b393 100644 --- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp +++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp @@ -15,6 +15,7 @@   */  #include "header.h" +#include "egl_tls.h"  extern "C"  { @@ -24,11 +25,23 @@ extern "C"  namespace android  { +pthread_key_t dbgEGLThreadLocalStorageKey = -1; + +DbgContext * getDbgContextThreadSpecific() +{ +    tls_t* tls = (tls_t*)pthread_getspecific(dbgEGLThreadLocalStorageKey); +    return tls->dbg; +} +  DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks, -                       const unsigned MAX_VERTEX_ATTRIBS) +                       const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat, +                       const GLenum readType)          : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)          , version(version), hooks(hooks)          , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS) +        , readFormat(readFormat), readType(readType) +        , readBytesPerPixel(GetBytesPerPixel(readFormat, readType)) +        , captureSwap(0), captureDraw(0)          , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])          , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)          , program(0), maxAttrib(0) @@ -47,13 +60,35 @@ DbgContext::~DbgContext()      free(lzf_ref[1]);  } -DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks) +DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey, +                              const unsigned version, const gl_hooks_t * const hooks)  { +    dbgEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;      assert(version < 2);      assert(GL_NO_ERROR == hooks->gl.glGetError());      GLint MAX_VERTEX_ATTRIBS = 0;      hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS); -    return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS); +    GLint readFormat, readType; +    hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); +    hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); +    DbgContext * const dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType); + +    glesv2debugger::Message msg, cmd; +    msg.set_context_id(reinterpret_cast<int>(dbg)); +    msg.set_expect_response(false); +    msg.set_type(msg.Response); +    msg.set_function(msg.SETPROP); +    msg.set_prop(msg.GLConstant); +    msg.set_arg0(GL_MAX_VERTEX_ATTRIBS); +    msg.set_arg1(MAX_VERTEX_ATTRIBS); +    Send(msg, cmd); + +    GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0; +    hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS); +    msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); +    msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS); +    Send(msg, cmd); +    return dbg;  }  void DestroyDbgContext(DbgContext * const dbg) @@ -113,6 +148,7 @@ void DbgContext::Compress(const void * in_data, unsigned int in_len,  {      if (!lzf_buf)          lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); +    assert(lzf_buf);      const uint32_t totalDecompSize = in_len;      outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));      for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) { @@ -130,13 +166,46 @@ void DbgContext::Compress(const void * in_data, unsigned int in_len,      }  } +unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen, +                                       unsigned int * const outLen) +{ +    assert(inLen > 4 * 3); +    if (inLen < 4 * 3) +        return NULL; +    *outLen = *(uint32_t *)in; +    unsigned char * const out = (unsigned char *)malloc(*outLen); +    unsigned int outPos = 0; +    const unsigned char * const end = (const unsigned char *)in + inLen; +    for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) { +        const uint32_t chunkOut = *(uint32_t *)inData; +        inData += 4; +        const uint32_t chunkIn = *(uint32_t *)inData; +        inData += 4; +        if (chunkIn > 0) { +            assert(inData + chunkIn <= end); +            assert(outPos + chunkOut <= *outLen); +            outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut); +            inData += chunkIn; +        } else { +            assert(inData + chunkOut <= end); +            assert(outPos + chunkOut <= *outLen); +            memcpy(out + outPos, inData, chunkOut); +            inData += chunkOut; +            outPos += chunkOut; +        } +    } +    return out; +} +  void * DbgContext::GetReadPixelsBuffer(const unsigned size)  {      if (lzf_refBufSize < size + 8) {          lzf_refBufSize = size + 8;          lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize); +        assert(lzf_ref[0]);          memset(lzf_ref[0], 0, lzf_refBufSize);          lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize); +        assert(lzf_ref[1]);          memset(lzf_ref[1], 0, lzf_refBufSize);      }      if (lzf_refSize != size) // need to clear unused ref to maintain consistency @@ -151,6 +220,7 @@ void * DbgContext::GetReadPixelsBuffer(const unsigned size)  void DbgContext::CompressReadPixelBuffer(std::string * const outStr)  { +    assert(lzf_ref[0] && lzf_ref[1]);      unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];      unsigned * const src = lzf_ref[lzf_readIndex];      for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++) @@ -158,13 +228,34 @@ void DbgContext::CompressReadPixelBuffer(std::string * const outStr)      Compress(ref, lzf_refSize, outStr);  } +char * DbgContext::GetBuffer() +{ +    if (!lzf_buf) +        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); +    assert(lzf_buf); +    return lzf_buf; +} + +unsigned int DbgContext::GetBufferSize() +{ +    if (!lzf_buf) +        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); +    assert(lzf_buf); +    if (lzf_buf) +        return LZF_CHUNK_SIZE; +    else +        return 0; +} +  void DbgContext::glUseProgram(GLuint program)  {      while (GLenum error = hooks->gl.glGetError()) -        LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error); - +        LOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X", +             program, error);      this->program = program; - +    maxAttrib = 0; +    if (program == 0) +        return;      GLint activeAttributes = 0;      hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);      maxAttrib = 0; @@ -202,9 +293,9 @@ void DbgContext::glUseProgram(GLuint program)              maxAttrib = slot;      }      delete name; -      while (GLenum error = hooks->gl.glGetError()) -        LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error); +        LOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X", +             program, error);  }  static bool HasNonVBOAttribs(const DbgContext * const ctx) @@ -254,14 +345,16 @@ void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,  void DbgContext::glEnableVertexAttribArray(GLuint index)  { -    assert(index < MAX_VERTEX_ATTRIBS); +    if (index >= MAX_VERTEX_ATTRIBS) +        return;      vertexAttribs[index].enabled = true;      hasNonVBOAttribs = HasNonVBOAttribs(this);  }  void DbgContext::glDisableVertexAttribArray(GLuint index)  { -    assert(index < MAX_VERTEX_ATTRIBS); +    if (index >= MAX_VERTEX_ATTRIBS) +        return;      vertexAttribs[index].enabled = false;      hasNonVBOAttribs = HasNonVBOAttribs(this);  } diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp index 046c954000..50f70f7dff 100644 --- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp +++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp @@ -436,6 +436,8 @@ bool Message_Type_IsValid(int value) {      case 0:      case 1:      case 2: +    case 3: +    case 4:        return true;      default:        return false; @@ -445,7 +447,9 @@ bool Message_Type_IsValid(int value) {  #ifndef _MSC_VER  const Message_Type Message::BeforeCall;  const Message_Type Message::AfterCall; +const Message_Type Message::AfterGeneratedCall;  const Message_Type Message::Response; +const Message_Type Message::CompleteCall;  const Message_Type Message::Type_MIN;  const Message_Type Message::Type_MAX;  const int Message::Type_ARRAYSIZE; @@ -472,6 +476,8 @@ bool Message_Prop_IsValid(int value) {      case 0:      case 1:      case 2: +    case 3: +    case 4:        return true;      default:        return false; @@ -479,9 +485,11 @@ bool Message_Prop_IsValid(int value) {  }  #ifndef _MSC_VER -const Message_Prop Message::Capture; +const Message_Prop Message::CaptureDraw;  const Message_Prop Message::TimeMode;  const Message_Prop Message::ExpectResponse; +const Message_Prop Message::CaptureSwap; +const Message_Prop Message::GLConstant;  const Message_Prop Message::Prop_MIN;  const Message_Prop Message::Prop_MAX;  const int Message::Prop_ARRAYSIZE; @@ -506,6 +514,8 @@ const int Message::kDataFieldNumber;  const int Message::kDataTypeFieldNumber;  const int Message::kPixelFormatFieldNumber;  const int Message::kPixelTypeFieldNumber; +const int Message::kImageWidthFieldNumber; +const int Message::kImageHeightFieldNumber;  const int Message::kTimeFieldNumber;  const int Message::kPropFieldNumber;  const int Message::kClockFieldNumber; @@ -545,6 +555,8 @@ void Message::SharedCtor() {    data_type_ = 0;    pixel_format_ = 0;    pixel_type_ = 0; +  image_width_ = 0; +  image_height_ = 0;    time_ = 0;    prop_ = 0;    clock_ = 0; @@ -606,6 +618,8 @@ void Message::Clear() {    if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {      pixel_format_ = 0;      pixel_type_ = 0; +    image_width_ = 0; +    image_height_ = 0;      time_ = 0;      prop_ = 0;      clock_ = 0; @@ -790,7 +804,7 @@ bool Message::MergePartialFromCodedStream(            DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<                     float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(                   input, &time_))); -          _set_bit(18); +          _set_bit(20);          } else {            goto handle_uninterpreted;          } @@ -905,7 +919,7 @@ bool Message::MergePartialFromCodedStream(            DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<                     float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(                   input, &clock_))); -          _set_bit(20); +          _set_bit(22);          } else {            goto handle_uninterpreted;          } @@ -960,6 +974,38 @@ bool Message::MergePartialFromCodedStream(          } else {            goto handle_uninterpreted;          } +        if (input->ExpectTag(208)) goto parse_image_width; +        break; +      } +       +      // optional int32 image_width = 26; +      case 26: { +        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == +            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { +         parse_image_width: +          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< +                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( +                 input, &image_width_))); +          _set_bit(18); +        } else { +          goto handle_uninterpreted; +        } +        if (input->ExpectTag(216)) goto parse_image_height; +        break; +      } +       +      // optional int32 image_height = 27; +      case 27: { +        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == +            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { +         parse_image_height: +          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< +                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( +                 input, &image_height_))); +          _set_bit(19); +        } else { +          goto handle_uninterpreted; +        }          if (input->ExpectAtEnd()) return true;          break;        } @@ -1035,7 +1081,7 @@ void Message::SerializeWithCachedSizes(    }    // optional float time = 11; -  if (_has_bit(18)) { +  if (_has_bit(20)) {      ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);    } @@ -1065,13 +1111,13 @@ void Message::SerializeWithCachedSizes(    }    // optional .com.android.glesv2debugger.Message.Prop prop = 21; -  if (_has_bit(19)) { +  if (_has_bit(21)) {      ::google::protobuf::internal::WireFormatLite::WriteEnum(        21, this->prop(), output);    }    // optional float clock = 22; -  if (_has_bit(20)) { +  if (_has_bit(22)) {      ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);    } @@ -1091,6 +1137,16 @@ void Message::SerializeWithCachedSizes(      ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);    } +  // optional int32 image_width = 26; +  if (_has_bit(18)) { +    ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output); +  } +   +  // optional int32 image_height = 27; +  if (_has_bit(19)) { +    ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output); +  } +    }  int Message::ByteSize() const { @@ -1222,6 +1278,20 @@ int Message::ByteSize() const {            this->pixel_type());      } +    // optional int32 image_width = 26; +    if (has_image_width()) { +      total_size += 2 + +        ::google::protobuf::internal::WireFormatLite::Int32Size( +          this->image_width()); +    } +     +    // optional int32 image_height = 27; +    if (has_image_height()) { +      total_size += 2 + +        ::google::protobuf::internal::WireFormatLite::Int32Size( +          this->image_height()); +    } +          // optional float time = 11;      if (has_time()) {        total_size += 1 + 4; @@ -1312,12 +1382,18 @@ void Message::MergeFrom(const Message& from) {        set_pixel_type(from.pixel_type());      }      if (from._has_bit(18)) { -      set_time(from.time()); +      set_image_width(from.image_width());      }      if (from._has_bit(19)) { -      set_prop(from.prop()); +      set_image_height(from.image_height());      }      if (from._has_bit(20)) { +      set_time(from.time()); +    } +    if (from._has_bit(21)) { +      set_prop(from.prop()); +    } +    if (from._has_bit(22)) {        set_clock(from.clock());      }    } @@ -1355,6 +1431,8 @@ void Message::Swap(Message* other) {      std::swap(data_type_, other->data_type_);      std::swap(pixel_format_, other->pixel_format_);      std::swap(pixel_type_, other->pixel_type_); +    std::swap(image_width_, other->image_width_); +    std::swap(image_height_, other->image_height_);      std::swap(time_, other->time_);      std::swap(prop_, other->prop_);      std::swap(clock_, other->clock_); diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h index b2ec5a0ac3..5c946644a1 100644 --- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h +++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h @@ -236,11 +236,13 @@ const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX +  enum Message_Type {    Message_Type_BeforeCall = 0,    Message_Type_AfterCall = 1, -  Message_Type_Response = 2 +  Message_Type_AfterGeneratedCall = 2, +  Message_Type_Response = 3, +  Message_Type_CompleteCall = 4  };  bool Message_Type_IsValid(int value);  const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall; -const Message_Type Message_Type_Type_MAX = Message_Type_Response; +const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;  const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;  enum Message_DataType { @@ -253,13 +255,15 @@ const Message_DataType Message_DataType_DataType_MAX = Message_DataType_Nonrefer  const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;  enum Message_Prop { -  Message_Prop_Capture = 0, +  Message_Prop_CaptureDraw = 0,    Message_Prop_TimeMode = 1, -  Message_Prop_ExpectResponse = 2 +  Message_Prop_ExpectResponse = 2, +  Message_Prop_CaptureSwap = 3, +  Message_Prop_GLConstant = 4  };  bool Message_Prop_IsValid(int value); -const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture; -const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse; +const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw; +const Message_Prop Message_Prop_Prop_MAX = Message_Prop_GLConstant;  const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;  // =================================================================== @@ -510,7 +514,9 @@ class Message : public ::google::protobuf::MessageLite {    typedef Message_Type Type;    static const Type BeforeCall = Message_Type_BeforeCall;    static const Type AfterCall = Message_Type_AfterCall; +  static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;    static const Type Response = Message_Type_Response; +  static const Type CompleteCall = Message_Type_CompleteCall;    static inline bool Type_IsValid(int value) {      return Message_Type_IsValid(value);    } @@ -535,9 +541,11 @@ class Message : public ::google::protobuf::MessageLite {      Message_DataType_DataType_ARRAYSIZE;    typedef Message_Prop Prop; -  static const Prop Capture = Message_Prop_Capture; +  static const Prop CaptureDraw = Message_Prop_CaptureDraw;    static const Prop TimeMode = Message_Prop_TimeMode;    static const Prop ExpectResponse = Message_Prop_ExpectResponse; +  static const Prop CaptureSwap = Message_Prop_CaptureSwap; +  static const Prop GLConstant = Message_Prop_GLConstant;    static inline bool Prop_IsValid(int value) {      return Message_Prop_IsValid(value);    } @@ -679,6 +687,20 @@ class Message : public ::google::protobuf::MessageLite {    inline ::google::protobuf::int32 pixel_type() const;    inline void set_pixel_type(::google::protobuf::int32 value); +  // optional int32 image_width = 26; +  inline bool has_image_width() const; +  inline void clear_image_width(); +  static const int kImageWidthFieldNumber = 26; +  inline ::google::protobuf::int32 image_width() const; +  inline void set_image_width(::google::protobuf::int32 value); +   +  // optional int32 image_height = 27; +  inline bool has_image_height() const; +  inline void clear_image_height(); +  static const int kImageHeightFieldNumber = 27; +  inline ::google::protobuf::int32 image_height() const; +  inline void set_image_height(::google::protobuf::int32 value); +      // optional float time = 11;    inline bool has_time() const;    inline void clear_time(); @@ -723,6 +745,8 @@ class Message : public ::google::protobuf::MessageLite {    int data_type_;    ::google::protobuf::int32 pixel_format_;    ::google::protobuf::int32 pixel_type_; +  ::google::protobuf::int32 image_width_; +  ::google::protobuf::int32 image_height_;    float time_;    int prop_;    float clock_; @@ -730,7 +754,7 @@ class Message : public ::google::protobuf::MessageLite {    friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();    friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto(); -  ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32]; +  ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];    // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?    inline bool _has_bit(int index) const { @@ -1070,52 +1094,84 @@ inline void Message::set_pixel_type(::google::protobuf::int32 value) {    pixel_type_ = value;  } +// optional int32 image_width = 26; +inline bool Message::has_image_width() const { +  return _has_bit(18); +} +inline void Message::clear_image_width() { +  image_width_ = 0; +  _clear_bit(18); +} +inline ::google::protobuf::int32 Message::image_width() const { +  return image_width_; +} +inline void Message::set_image_width(::google::protobuf::int32 value) { +  _set_bit(18); +  image_width_ = value; +} + +// optional int32 image_height = 27; +inline bool Message::has_image_height() const { +  return _has_bit(19); +} +inline void Message::clear_image_height() { +  image_height_ = 0; +  _clear_bit(19); +} +inline ::google::protobuf::int32 Message::image_height() const { +  return image_height_; +} +inline void Message::set_image_height(::google::protobuf::int32 value) { +  _set_bit(19); +  image_height_ = value; +} +  // optional float time = 11;  inline bool Message::has_time() const { -  return _has_bit(18); +  return _has_bit(20);  }  inline void Message::clear_time() {    time_ = 0; -  _clear_bit(18); +  _clear_bit(20);  }  inline float Message::time() const {    return time_;  }  inline void Message::set_time(float value) { -  _set_bit(18); +  _set_bit(20);    time_ = value;  }  // optional .com.android.glesv2debugger.Message.Prop prop = 21;  inline bool Message::has_prop() const { -  return _has_bit(19); +  return _has_bit(21);  }  inline void Message::clear_prop() {    prop_ = 0; -  _clear_bit(19); +  _clear_bit(21);  }  inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {    return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);  }  inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {    GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value)); -  _set_bit(19); +  _set_bit(21);    prop_ = value;  }  // optional float clock = 22;  inline bool Message::has_clock() const { -  return _has_bit(20); +  return _has_bit(22);  }  inline void Message::clear_clock() {    clock_ = 0; -  _clear_bit(20); +  _clear_bit(22);  }  inline float Message::clock() const {    return clock_;  }  inline void Message::set_clock(float value) { -  _set_bit(20); +  _set_bit(22);    clock_ = value;  } diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp index 3a20e21ba2..eb28d06076 100644 --- a/opengl/libs/GLES2_dbg/src/egl.cpp +++ b/opengl/libs/GLES2_dbg/src/egl.cpp @@ -18,6 +18,7 @@  EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)  { +    DbgContext * const dbg = getDbgContextThreadSpecific();      glesv2debugger::Message msg;      struct : public FunctionCall {          EGLDisplay dpy; @@ -33,7 +34,21 @@ EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)      msg.set_arg0(reinterpret_cast<int>(dpy));      msg.set_arg1(reinterpret_cast<int>(draw)); - +    if (dbg->captureSwap > 0) { +        dbg->captureSwap--; +        int viewport[4] = {}; +        dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); +        void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] * +                        dbg->readBytesPerPixel); +        dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], +                                    viewport[3], dbg->readFormat, dbg->readType, pixels); +        dbg->CompressReadPixelBuffer(msg.mutable_data()); +        msg.set_data_type(msg.ReferencedImage); +        msg.set_pixel_format(dbg->readFormat); +        msg.set_pixel_type(dbg->readType); +        msg.set_image_width(viewport[2]); +        msg.set_image_height(viewport[3]); +    }      int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);      return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));  } diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h index 9218da5b31..f2b1fa6635 100644 --- a/opengl/libs/GLES2_dbg/src/header.h +++ b/opengl/libs/GLES2_dbg/src/header.h @@ -14,6 +14,9 @@   ** limitations under the License.   */ +#ifndef ANDROID_GLES2_DBG_HEADER_H +#define ANDROID_GLES2_DBG_HEADER_H +  #include <stdlib.h>  #include <ctype.h>  #include <string.h> @@ -24,9 +27,7 @@  #include <cutils/log.h>  #include <utils/Timers.h> -#include <../../../libcore/include/StaticAssert.h> -#define EGL_TRACE 1  #include "hooks.h"  #include "glesv2dbg.h" @@ -39,8 +40,6 @@  using namespace android;  using namespace com::android; -#define API_ENTRY(_api) Debug_##_api -  #ifndef __location__  #define __HIERALLOC_STRING_0__(s)   #s  #define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s) @@ -74,9 +73,10 @@ struct GLFunctionBitfield {  };  struct DbgContext { -private:      static const unsigned int LZF_CHUNK_SIZE = 256 * 1024; -    char * lzf_buf; // malloc / free; for lzf chunk compression + +private: +    char * lzf_buf; // malloc / free; for lzf chunk compression and other uses      // used as buffer and reference frame for ReadPixels; malloc/free      unsigned * lzf_ref [2]; @@ -84,9 +84,14 @@ private:      unsigned lzf_refSize, lzf_refBufSize; // bytes  public: -    const unsigned version; // 0 is GLES1, 1 is GLES2 +    const unsigned int version; // 0 is GLES1, 1 is GLES2      const gl_hooks_t * const hooks; -    const unsigned MAX_VERTEX_ATTRIBS; +    const unsigned int MAX_VERTEX_ATTRIBS; +    const GLenum readFormat, readType; // implementation supported glReadPixels +    const unsigned int readBytesPerPixel; + +    unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels +    unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels      GLFunctionBitfield expectResponse; @@ -119,16 +124,21 @@ public:      unsigned maxAttrib; // number of slots used by program      DbgContext(const unsigned version, const gl_hooks_t * const hooks, -               const unsigned MAX_VERTEX_ATTRIBS); +               const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat, +               const GLenum readType);      ~DbgContext();      void Fetch(const unsigned index, std::string * const data) const;      void Compress(const void * in_data, unsigned in_len, std::string * const outStr); +    static unsigned char * Decompress(const void * in, const unsigned int inLen, +                                      unsigned int * const outLen); // malloc/free      void * GetReadPixelsBuffer(const unsigned size);      bool IsReadPixelBuffer(const void * const ptr)  {          return ptr == lzf_ref[lzf_readIndex];      }      void CompressReadPixelBuffer(std::string * const outStr); +    char * GetBuffer(); // allocates lzf_buf if NULL +    unsigned int GetBufferSize(); // allocates lzf_buf if NULL      void glUseProgram(GLuint program);      void glEnableVertexAttribArray(GLuint index); @@ -141,9 +151,7 @@ public:      void glDeleteBuffers(GLsizei n, const GLuint *buffers);  }; -  DbgContext * getDbgContextThreadSpecific(); -#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();  struct FunctionCall {      virtual const int * operator()(gl_hooks_t::gl_t const * const _c, @@ -152,7 +160,6 @@ struct FunctionCall {  };  // move these into DbgContext as static -extern bool capture;  extern int timeMode; // SYSTEM_TIME_  extern int clientSock, serverSock; @@ -169,3 +176,5 @@ void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd);  const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,                           glesv2debugger::Message & msg, const int * const prevRet);  }; // namespace android { + +#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp index 7039c84850..0c711bf200 100644 --- a/opengl/libs/GLES2_dbg/src/server.cpp +++ b/opengl/libs/GLES2_dbg/src/server.cpp @@ -28,7 +28,8 @@ namespace android  {  int serverSock = -1, clientSock = -1; - +FILE * file = NULL; +unsigned int MAX_FILE_SIZE = 0;  int timeMode = SYSTEM_TIME_THREAD;  static void Die(const char * msg) @@ -38,18 +39,25 @@ static void Die(const char * msg)      exit(1);  } -void StartDebugServer(unsigned short port) +void StartDebugServer(const unsigned short port, const bool forceUseFile, +                      const unsigned int maxFileSize, const char * const filePath)  { +    MAX_FILE_SIZE = maxFileSize; +      LOGD("GLESv2_dbg: StartDebugServer"); -    if (serverSock >= 0) +    if (serverSock >= 0 || file)          return;      LOGD("GLESv2_dbg: StartDebugServer create socket");      struct sockaddr_in server = {}, client = {};      /* Create the TCP socket */ -    if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { -        Die("Failed to create socket"); +    if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { +        file = fopen(filePath, "wb"); +        if (!file) +            Die("Failed to create socket and file"); +        else +            return;      }      /* Construct the server sockaddr_in structure */      server.sin_family = AF_INET;                  /* Internet/IP */ @@ -92,13 +100,17 @@ void StopDebugServer()          close(serverSock);          serverSock = -1;      } - +    if (file) { +        fclose(file); +        file = NULL; +    }  }  void Receive(glesv2debugger::Message & cmd)  { +    if (clientSock < 0) +        return;      unsigned len = 0; -      int received = recv(clientSock, &len, 4, MSG_WAITALL);      if (received < 0)          Die("Failed to receive response length"); @@ -106,7 +118,6 @@ void Receive(glesv2debugger::Message & cmd)          LOGD("received %dB: %.8X", received, len);          Die("Received length mismatch, expected 4");      } -    len = ntohl(len);      static void * buffer = NULL;      static unsigned bufferSize = 0;      if (bufferSize < len) { @@ -125,6 +136,8 @@ void Receive(glesv2debugger::Message & cmd)  bool TryReceive(glesv2debugger::Message & cmd)  { +    if (clientSock < 0) +        return false;      fd_set readSet;      FD_ZERO(&readSet);      FD_SET(clientSock, &readSet); @@ -146,14 +159,34 @@ bool TryReceive(glesv2debugger::Message & cmd)  float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)  { +    // TODO: use per DbgContext send/receive buffer and async socket +    //  instead of mutex and blocking io; watch out for large messages      static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -    pthread_mutex_lock(&mutex); // TODO: this is just temporary +    struct Autolock { +        Autolock() { +            pthread_mutex_lock(&mutex); +        } +        ~Autolock() { +            pthread_mutex_unlock(&mutex); +        } +    } autolock;      if (msg.function() != glesv2debugger::Message_Function_ACK)          assert(msg.has_context_id() && msg.context_id() != 0);      static std::string str;      msg.SerializeToString(&str); -    uint32_t len = htonl(str.length()); +    const uint32_t len = str.length(); +    if (clientSock < 0) { +        if (file) { +            fwrite(&len, sizeof(len), 1, file); +            fwrite(str.data(), len, 1, file); +            if (ftell(file) >= MAX_FILE_SIZE) { +                fclose(file); +                Die("MAX_FILE_SIZE reached"); +            } +        } +        return 0; +    }      int sent = -1;      sent = send(clientSock, &len, sizeof(len), 0);      if (sent != sizeof(len)) { @@ -161,36 +194,37 @@ float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)          Die("Failed to send message length");      }      nsecs_t c0 = systemTime(timeMode); -    sent = send(clientSock, str.c_str(), str.length(), 0); +    sent = send(clientSock, str.data(), str.length(), 0);      float t = (float)ns2ms(systemTime(timeMode) - c0);      if (sent != str.length()) {          LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);          Die("Failed to send message");      } - +    // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument. +    // mean while, if server is sending a SETPROP then don't try to receive, +    //  because server will not be processing received command +    if (msg.function() == msg.SETPROP) +        return t;      // try to receive commands even though not expecting response, -    // since client can send SETPROP commands anytime +    //  since client can send SETPROP and other commands anytime      if (!msg.expect_response()) {          if (TryReceive(cmd)) { -            LOGD("Send: TryReceived");              if (glesv2debugger::Message_Function_SETPROP == cmd.function()) -                LOGD("Send: received SETPROP"); +                LOGD("Send: TryReceived SETPROP");              else -                LOGD("Send: received something else"); +                LOGD("Send: TryReceived %u", cmd.function());          }      } else          Receive(cmd); - -    pthread_mutex_unlock(&mutex);      return t;  }  void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)  {      switch (cmd.prop()) { -    case glesv2debugger::Message_Prop_Capture: -        LOGD("SetProp Message_Prop_Capture %d", cmd.arg0()); -        capture = cmd.arg0(); +    case glesv2debugger::Message_Prop_CaptureDraw: +        LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0()); +        dbg->captureDraw = cmd.arg0();          break;      case glesv2debugger::Message_Prop_TimeMode:          LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0()); @@ -200,6 +234,10 @@ void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)          LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());          dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());          break; +    case glesv2debugger::Message_Prop_CaptureSwap: +        LOGD("SetProp CaptureSwap %d", cmd.arg0()); +        dbg->captureSwap = cmd.arg0(); +        break;      default:          assert(0);      } @@ -213,12 +251,17 @@ int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,      glesv2debugger::Message cmd;      msg.set_context_id(reinterpret_cast<int>(dbg));      msg.set_type(glesv2debugger::Message_Type_BeforeCall); -    const bool expectResponse = dbg->expectResponse.Bit(function); +    bool expectResponse = dbg->expectResponse.Bit(function);      msg.set_expect_response(expectResponse);      msg.set_function(function); -    if (!expectResponse) -        cmd.set_function(glesv2debugger::Message_Function_CONTINUE); + +    // when not exectResponse, set cmd to CONTINUE then SKIP +    // cmd will be overwritten by received command +    cmd.set_function(glesv2debugger::Message_Function_CONTINUE); +    cmd.set_expect_response(expectResponse); +    glesv2debugger::Message_Function oldCmd = cmd.function();      Send(msg, cmd); +    expectResponse = cmd.expect_response();      while (true) {          msg.Clear();          nsecs_t c0 = systemTime(timeMode); @@ -233,22 +276,34 @@ int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,              msg.set_function(function);              msg.set_type(glesv2debugger::Message_Type_AfterCall);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(glesv2debugger::Message_Function_SKIP); +                cmd.set_expect_response(false); +            } +            oldCmd = cmd.function();              Send(msg, cmd); +            expectResponse = cmd.expect_response();              break;          case glesv2debugger::Message_Function_SKIP:              return const_cast<int *>(ret);          case glesv2debugger::Message_Function_SETPROP:              SetProp(dbg, cmd); -            Receive(cmd); +            expectResponse = cmd.expect_response(); +            if (!expectResponse) // SETPROP is "out of band" +                cmd.set_function(oldCmd); +            else +                Receive(cmd);              break;          default:              ret = GenerateCall(dbg, cmd, msg, ret);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(cmd.SKIP); +                cmd.set_expect_response(expectResponse); +            } +            oldCmd = cmd.function();              Send(msg, cmd); +            expectResponse = cmd.expect_response();              break;          }      } diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp index 471e5adf91..029ee3bf50 100644 --- a/opengl/libs/GLES2_dbg/src/vertex.cpp +++ b/opengl/libs/GLES2_dbg/src/vertex.cpp @@ -21,74 +21,13 @@ namespace android  bool capture; // capture after each glDraw*  } -void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) -{ -    DbgContext * const dbg = getDbgContextThreadSpecific(); -    glesv2debugger::Message msg, cmd; -    msg.set_context_id(reinterpret_cast<int>(dbg)); -    msg.set_type(glesv2debugger::Message_Type_BeforeCall); -    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels); -    msg.set_expect_response(expectResponse); -    msg.set_function(glesv2debugger::Message_Function_glReadPixels); -    msg.set_arg0(x); -    msg.set_arg1(y); -    msg.set_arg2(width); -    msg.set_arg3(height); -    msg.set_arg4(format); -    msg.set_arg5(type); -    msg.set_arg6(reinterpret_cast<int>(pixels)); - -    const unsigned size = width * height * GetBytesPerPixel(format, type); -    if (!expectResponse) -        cmd.set_function(glesv2debugger::Message_Function_CONTINUE); -    Send(msg, cmd); -    float t = 0; -    while (true) { -        msg.Clear(); -        nsecs_t c0 = systemTime(timeMode); -        switch (cmd.function()) { -        case glesv2debugger::Message_Function_CONTINUE: -            dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels); -            msg.set_time((systemTime(timeMode) - c0) * 1e-6f); -            msg.set_context_id(reinterpret_cast<int>(dbg)); -            msg.set_function(glesv2debugger::Message_Function_glReadPixels); -            msg.set_type(glesv2debugger::Message_Type_AfterCall); -            msg.set_expect_response(expectResponse); -            if (dbg->IsReadPixelBuffer(pixels)) { -                dbg->CompressReadPixelBuffer(msg.mutable_data()); -                msg.set_data_type(msg.ReferencedImage); -            } else { -                dbg->Compress(pixels, size, msg.mutable_data()); -                msg.set_data_type(msg.NonreferencedImage); -            } -            if (!expectResponse) -                cmd.set_function(glesv2debugger::Message_Function_SKIP); -            Send(msg, cmd); -            break; -        case glesv2debugger::Message_Function_SKIP: -            return; -        case glesv2debugger::Message_Function_SETPROP: -            SetProp(dbg, cmd); -            Receive(cmd); -            break; -        default: -            GenerateCall(dbg, cmd, msg, NULL); -            msg.set_expect_response(expectResponse); -            if (!expectResponse) -                cmd.set_function(cmd.SKIP); -            Send(msg, cmd); -            break; -        } -    } -} -  void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)  {      DbgContext * const dbg = getDbgContextThreadSpecific();      glesv2debugger::Message msg, cmd;      msg.set_context_id(reinterpret_cast<int>(dbg));      msg.set_type(glesv2debugger::Message_Type_BeforeCall); -    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays); +    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);      msg.set_expect_response(expectResponse);      msg.set_function(glesv2debugger::Message_Function_glDrawArrays);      msg.set_arg0(mode); @@ -103,11 +42,12 @@ void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)      }      void * pixels = NULL; -    GLint readFormat = 0, readType = 0;      int viewport[4] = {}; -    if (!expectResponse) -        cmd.set_function(glesv2debugger::Message_Function_CONTINUE); +    cmd.set_function(glesv2debugger::Message_Function_CONTINUE); +    cmd.set_expect_response(expectResponse); +    glesv2debugger::Message_Function oldCmd = cmd.function();      Send(msg, cmd); +    expectResponse = cmd.expect_response();      while (true) {          msg.Clear();          nsecs_t c0 = systemTime(timeMode); @@ -119,33 +59,47 @@ void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)              msg.set_function(glesv2debugger::Message_Function_glDrawArrays);              msg.set_type(glesv2debugger::Message_Type_AfterCall);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(glesv2debugger::Message_Function_SKIP); +                cmd.set_expect_response(false); +            } +            oldCmd = cmd.function();              Send(msg, cmd); -            if (capture) { +            expectResponse = cmd.expect_response(); +            // TODO: pack glReadPixels data with vertex data instead of +            //  relying on sperate call for transport, this would allow +            //  auto generated message loop using EXTEND_Debug macro +            if (dbg->captureDraw > 0) { +                dbg->captureDraw--;                  dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); -                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); -                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);  //                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",  //                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);                  pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] * -                                                  GetBytesPerPixel(readFormat, readType)); +                                                  dbg->readBytesPerPixel);                  Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], -                                   readFormat, readType, pixels); +                                   dbg->readFormat, dbg->readType, pixels);              }              break;          case glesv2debugger::Message_Function_SKIP:              return;          case glesv2debugger::Message_Function_SETPROP:              SetProp(dbg, cmd); -            Receive(cmd); +            expectResponse = cmd.expect_response(); +            if (!expectResponse) // SETPROP is "out of band" +                cmd.set_function(oldCmd); +            else +                Receive(cmd);              break;          default:              GenerateCall(dbg, cmd, msg, NULL);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(cmd.SKIP); +                cmd.set_expect_response(expectResponse); +            } +            oldCmd = cmd.function();              Send(msg, cmd); +            expectResponse = cmd.expect_response();              break;          }      } @@ -169,7 +123,7 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*      glesv2debugger::Message msg, cmd;      msg.set_context_id(reinterpret_cast<int>(dbg));      msg.set_type(glesv2debugger::Message_Type_BeforeCall); -    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements); +    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);      msg.set_expect_response(expectResponse);      msg.set_function(glesv2debugger::Message_Function_glDrawElements);      msg.set_arg0(mode); @@ -195,11 +149,12 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*          assert(0);      void * pixels = NULL; -    GLint readFormat = 0, readType = 0;      int viewport[4] = {}; -    if (!expectResponse) -        cmd.set_function(glesv2debugger::Message_Function_CONTINUE); +    cmd.set_function(glesv2debugger::Message_Function_CONTINUE); +    cmd.set_expect_response(expectResponse); +    glesv2debugger::Message_Function oldCmd = cmd.function();      Send(msg, cmd); +    expectResponse = cmd.expect_response();      while (true) {          msg.Clear();          nsecs_t c0 = systemTime(timeMode); @@ -211,33 +166,45 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*              msg.set_function(glesv2debugger::Message_Function_glDrawElements);              msg.set_type(glesv2debugger::Message_Type_AfterCall);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(glesv2debugger::Message_Function_SKIP); +                cmd.set_expect_response(false); +            } +            oldCmd = cmd.function();              Send(msg, cmd); -            if (capture) { +            expectResponse = cmd.expect_response(); +            // TODO: pack glReadPixels data with vertex data instead of +            //  relying on sperate call for transport, this would allow +            //  auto generated message loop using EXTEND_Debug macro +            if (dbg->captureDraw > 0) { +                dbg->captureDraw--;                  dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); -                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); -                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); -//                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X", -//                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);                  pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] * -                                                  GetBytesPerPixel(readFormat, readType)); +                                                  dbg->readBytesPerPixel);                  Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], -                                   readFormat, readType, pixels); +                                   dbg->readFormat, dbg->readType, pixels);              }              break;          case glesv2debugger::Message_Function_SKIP:              return;          case glesv2debugger::Message_Function_SETPROP:              SetProp(dbg, cmd); -            Receive(cmd); +            expectResponse = cmd.expect_response(); +            if (!expectResponse) // SETPROP is "out of band" +                cmd.set_function(oldCmd); +            else +                Receive(cmd);              break;          default:              GenerateCall(dbg, cmd, msg, NULL);              msg.set_expect_response(expectResponse); -            if (!expectResponse) +            if (!expectResponse) {                  cmd.set_function(cmd.SKIP); +                cmd.set_expect_response(expectResponse); +            } +            oldCmd = cmd.function();              Send(msg, cmd); +            expectResponse = cmd.expect_response();              break;          }      } diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk new file mode 100644 index 0000000000..14a84b447f --- /dev/null +++ b/opengl/libs/GLES2_dbg/test/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := \ +    $(LOCAL_PATH) \ +    $(LOCAL_PATH)/../src \ +    $(LOCAL_PATH)/../../ \ +    external/gtest/include \ +    external/stlport/stlport \ +    external/protobuf/src \ +    bionic \ +    external \ +# + +LOCAL_SRC_FILES:= \ +    test_main.cpp \ +    test_server.cpp \ +    test_socket.cpp \ +# + +LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2_dbg libstlport +LOCAL_STATIC_LIBRARIES := libgtest libprotobuf-cpp-2.3.0-lite liblzf +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE:= libGLESv2_dbg_test + +ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) +    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER +endif +ifneq ($(TARGET_SIMULATOR),true) +    LOCAL_C_INCLUDES += bionic/libc/private +endif + +LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\" +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CFLAGS += -fvisibility=hidden + +include $(BUILD_EXECUTABLE) + diff --git a/opengl/libs/GLES2_dbg/test/test_main.cpp b/opengl/libs/GLES2_dbg/test/test_main.cpp new file mode 100644 index 0000000000..058bea4d6f --- /dev/null +++ b/opengl/libs/GLES2_dbg/test/test_main.cpp @@ -0,0 +1,234 @@ +/* + ** 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. + */ + +#include "header.h" +#include "gtest/gtest.h" +#include "hooks.h" + +namespace +{ + +// The fixture for testing class Foo. +class DbgContextTest : public ::testing::Test +{ +protected: +    android::DbgContext dbg; +    gl_hooks_t hooks; + +    DbgContextTest() +            : dbg(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE) { +        // You can do set-up work for each test here. +        hooks.gl.glGetError = GetError; +    } + +    static GLenum GetError() { +        return GL_NO_ERROR; +    } + +    virtual ~DbgContextTest() { +        // You can do clean-up work that doesn't throw exceptions here. +    } + +    // If the constructor and destructor are not enough for setting up +    // and cleaning up each test, you can define the following methods: + +    virtual void SetUp() { +        // Code here will be called immediately after the constructor (right +        // before each test). +    } + +    virtual void TearDown() { +        // Code here will be called immediately after each test (right +        // before the destructor). +    } +}; + +TEST_F(DbgContextTest, GetReadPixelBuffer) +{ +    const unsigned int bufferSize = 512; +    // test that it's allocating two buffers and swapping them +    void * const buffer0 = dbg.GetReadPixelsBuffer(bufferSize); +    ASSERT_NE((void *)NULL, buffer0); +    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) { +        EXPECT_EQ(0, ((unsigned int *)buffer0)[i]) +        << "GetReadPixelsBuffer should allocate and zero"; +        ((unsigned int *)buffer0)[i] = i * 13; +    } + +    void * const buffer1 = dbg.GetReadPixelsBuffer(bufferSize); +    ASSERT_NE((void *)NULL, buffer1); +    EXPECT_NE(buffer0, buffer1); +    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) { +        EXPECT_EQ(0, ((unsigned int *)buffer1)[i]) +        << "GetReadPixelsBuffer should allocate and zero"; +        ((unsigned int *)buffer1)[i] = i * 17; +    } + +    void * const buffer2 = dbg.GetReadPixelsBuffer(bufferSize); +    EXPECT_EQ(buffer2, buffer0); +    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) +        EXPECT_EQ(i * 13, ((unsigned int *)buffer2)[i]) +        << "GetReadPixelsBuffer should swap buffers"; + +    void * const buffer3 = dbg.GetReadPixelsBuffer(bufferSize); +    EXPECT_EQ(buffer3, buffer1); +    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) +        EXPECT_EQ(i * 17, ((unsigned int *)buffer3)[i]) +        << "GetReadPixelsBuffer should swap buffers"; + +    void * const buffer4 = dbg.GetReadPixelsBuffer(bufferSize); +    EXPECT_NE(buffer3, buffer4); +    EXPECT_EQ(buffer0, buffer2); +    EXPECT_EQ(buffer1, buffer3); +    EXPECT_EQ(buffer2, buffer4); + +    // it reallocs as necessary; 0 size may result in NULL +    for (unsigned int i = 0; i < 42; i++) { +        void * const buffer = dbg.GetReadPixelsBuffer(((i & 7)) << 20); +        EXPECT_NE((void *)NULL, buffer) +        << "should be able to get a variety of reasonable sizes"; +        EXPECT_TRUE(dbg.IsReadPixelBuffer(buffer)); +    } +} + +TEST_F(DbgContextTest, CompressReadPixelBuffer) +{ +    const unsigned int bufferSize = dbg.LZF_CHUNK_SIZE * 4 + 33; +    std::string out; +    unsigned char * buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        buffer[i] = i * 13; +    dbg.CompressReadPixelBuffer(&out); +    uint32_t decompSize = 0; +    ASSERT_LT(12, out.length()); // at least written chunk header +    ASSERT_EQ(bufferSize, *(uint32_t *)out.data()) +    << "total decompressed size should be as requested in GetReadPixelsBuffer"; +    for (unsigned int i = 4; i < out.length();) { +        const uint32_t outSize = *(uint32_t *)(out.data() + i); +        i += 4; +        const uint32_t inSize = *(uint32_t *)(out.data() + i); +        i += 4; +        if (inSize == 0) +            i += outSize; // chunk not compressed +        else +            i += inSize; // skip the actual compressed chunk +        decompSize += outSize; +    } +    ASSERT_EQ(bufferSize, decompSize); +    decompSize = 0; + +    unsigned char * decomp = dbg.Decompress(out.data(), out.length(), &decompSize); +    ASSERT_EQ(decompSize, bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        EXPECT_EQ((unsigned char)(i * 13), decomp[i]) << "xor with 0 ref is identity"; +    free(decomp); + +    buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        buffer[i] = i * 13; +    out.clear(); +    dbg.CompressReadPixelBuffer(&out); +    decompSize = 0; +    decomp = dbg.Decompress(out.data(), out.length(), &decompSize); +    ASSERT_EQ(decompSize, bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        EXPECT_EQ(0, decomp[i]) << "xor with same ref is 0"; +    free(decomp); + +    buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        buffer[i] = i * 19; +    out.clear(); +    dbg.CompressReadPixelBuffer(&out); +    decompSize = 0; +    decomp = dbg.Decompress(out.data(), out.length(), &decompSize); +    ASSERT_EQ(decompSize, bufferSize); +    for (unsigned int i = 0; i < bufferSize; i++) +        EXPECT_EQ((unsigned char)(i * 13) ^ (unsigned char)(i * 19), decomp[i]) +        << "xor ref"; +    free(decomp); +} + +TEST_F(DbgContextTest, UseProgram) +{ +    static const GLuint _program = 74568; +    static const struct Attribute { +        const char * name; +        GLint location; +        GLint size; +        GLenum type; +    } _attributes [] = { +        {"aaa", 2, 2, GL_FLOAT_VEC2}, +        {"bb", 6, 2, GL_FLOAT_MAT2}, +        {"c", 1, 1, GL_FLOAT}, +    }; +    static const unsigned int _attributeCount = sizeof(_attributes) / sizeof(*_attributes); +    struct GL { +        static void GetProgramiv(GLuint program, GLenum pname, GLint* params) { +            EXPECT_EQ(_program, program); +            ASSERT_NE((GLint *)NULL, params); +            switch (pname) { +            case GL_ACTIVE_ATTRIBUTES: +                *params = _attributeCount; +                return; +            case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: +                *params = 4; // includes NULL terminator +                return; +            default: +                ADD_FAILURE() << "not handled pname: " << pname; +            } +        } + +        static GLint GetAttribLocation(GLuint program, const GLchar* name) { +            EXPECT_EQ(_program, program); +            for (unsigned int i = 0; i < _attributeCount; i++) +                if (!strcmp(name, _attributes[i].name)) +                    return _attributes[i].location; +            ADD_FAILURE() << "unknown attribute name: " << name; +            return -1; +        } + +        static void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, +                                    GLsizei* length, GLint* size, GLenum* type, GLchar* name) { +            EXPECT_EQ(_program, program); +            ASSERT_LT(index, _attributeCount); +            const Attribute & att = _attributes[index]; +            ASSERT_GE(bufsize, strlen(att.name) + 1); +            ASSERT_NE((GLint *)NULL, size); +            ASSERT_NE((GLenum *)NULL, type); +            ASSERT_NE((GLchar *)NULL, name); +            strcpy(name, att.name); +            if (length) +                *length = strlen(name) + 1; +            *size = att.size; +            *type = att.type; +        } +    }; +    hooks.gl.glGetProgramiv = GL::GetProgramiv; +    hooks.gl.glGetAttribLocation = GL::GetAttribLocation; +    hooks.gl.glGetActiveAttrib = GL::GetActiveAttrib; +    dbg.glUseProgram(_program); +    EXPECT_EQ(10, dbg.maxAttrib); +    dbg.glUseProgram(0); +    EXPECT_EQ(0, dbg.maxAttrib); +} +}  // namespace + +int main(int argc, char **argv) +{ +    ::testing::InitGoogleTest(&argc, argv); +    return RUN_ALL_TESTS(); +} diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp new file mode 100644 index 0000000000..b6401e0c79 --- /dev/null +++ b/opengl/libs/GLES2_dbg/test/test_server.cpp @@ -0,0 +1,251 @@ +/* + ** 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. + */ + +#include "header.h" +#include "gtest/gtest.h" +#include "egl_tls.h" +#include "hooks.h" + +namespace android +{ +extern FILE * file; +extern unsigned int MAX_FILE_SIZE; +extern pthread_key_t dbgEGLThreadLocalStorageKey; +}; + +// tmpfile fails, so need to manually make a writable file first +static const char * filePath = "/data/local/tmp/dump.gles2dbg"; + +class ServerFileTest : public ::testing::Test +{ +protected: +    ServerFileTest() { } + +    virtual ~ServerFileTest() { } + +    virtual void SetUp() { +        MAX_FILE_SIZE = 8 << 20; +        ASSERT_EQ((FILE *)NULL, file); +        file = fopen("/data/local/tmp/dump.gles2dbg", "wb+"); +        ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: " +        << filePath; +    } + +    virtual void TearDown() { +        ASSERT_NE((FILE *)NULL, file); +        fclose(file); +        file = NULL; +    } + +    void Read(glesv2debugger::Message & msg) const { +        msg.Clear(); +        uint32_t len = 0; +        ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file)); +        ASSERT_GT(len, 0u); +        char * buffer = new char [len]; +        ASSERT_EQ(len, fread(buffer, 1, len, file)); +        msg.ParseFromArray(buffer, len); +        delete buffer; +    } + +    void CheckNoAvailable() { +        const long pos = ftell(file); +        fseek(file, 0, SEEK_END); +        EXPECT_EQ(pos, ftell(file)) << "check no available"; +    } +}; + +TEST_F(ServerFileTest, Send) +{ +    glesv2debugger::Message msg, cmd, read; +    msg.set_context_id(1); +    msg.set_function(msg.glFinish); +    msg.set_expect_response(false); +    msg.set_type(msg.BeforeCall); +    rewind(file); +    android::Send(msg, cmd); +    rewind(file); +    Read(read); +    EXPECT_EQ(msg.context_id(), read.context_id()); +    EXPECT_EQ(msg.function(), read.function()); +    EXPECT_EQ(msg.expect_response(), read.expect_response()); +    EXPECT_EQ(msg.type(), read.type()); +} + +TEST_F(ServerFileTest, CreateDbgContext) +{ +    gl_hooks_t hooks; +    struct Constant { +        GLenum pname; +        GLint param; +    }; +    static const Constant constants [] = { +        {GL_MAX_VERTEX_ATTRIBS, 16}, +        {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32}, +        {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA}, +        {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE}, +    }; +    struct HookMock { +        static void GetIntegerv(GLenum pname, GLint* params) { +            ASSERT_TRUE(params != NULL); +            for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++) +                if (pname == constants[i].pname) { +                    *params = constants[i].param; +                    return; +                } +            FAIL() << "GetIntegerv unknown pname: " << pname; +        } +        static GLenum GetError() { +            return GL_NO_ERROR; +        } +    }; +    hooks.gl.glGetError = HookMock::GetError; +    hooks.gl.glGetIntegerv = HookMock::GetIntegerv; +    DbgContext * const dbg = CreateDbgContext(-1, 1, &hooks); +    ASSERT_TRUE(dbg != NULL); +    EXPECT_TRUE(dbg->vertexAttribs != NULL); + +    rewind(file); +    glesv2debugger::Message read; +    for (unsigned int i = 0; i < 2; i++) { +        Read(read); +        EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id()); +        EXPECT_FALSE(read.expect_response()); +        EXPECT_EQ(read.Response, read.type()); +        EXPECT_EQ(read.SETPROP, read.function()); +        EXPECT_EQ(read.GLConstant, read.prop()); +        GLint expectedConstant = 0; +        HookMock::GetIntegerv(read.arg0(), &expectedConstant); +        EXPECT_EQ(expectedConstant, read.arg1()); +    } +    CheckNoAvailable(); +    DestroyDbgContext(dbg); +} + +void * glNoop() +{ +    return 0; +} + +class ServerFileContextTest : public ServerFileTest +{ +protected: +    tls_t tls; +    gl_hooks_t hooks; + +    ServerFileContextTest() { } + +    virtual ~ServerFileContextTest() { } + +    virtual void SetUp() { +        ServerFileTest::SetUp(); + +        if (dbgEGLThreadLocalStorageKey == -1) +            pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL); +        ASSERT_NE(-1, dbgEGLThreadLocalStorageKey); +        tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE); +        ASSERT_NE((void *)NULL, tls.dbg); +        pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls); +        for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++) +            ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop); +    } + +    virtual void TearDown() { +        ServerFileTest::TearDown(); +    } +}; + +TEST_F(ServerFileContextTest, MessageLoop) +{ +    static const int arg0 = 45; +    static const float arg7 = -87.2331f; +    static const int arg8 = -3; +    static const int * ret = reinterpret_cast<int *>(870); + +    struct Caller : public FunctionCall { +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            msg.set_arg0(arg0); +            msg.set_arg7((int &)arg7); +            msg.set_arg8(arg8); +            return ret; +        } +    } caller; +    const int contextId = reinterpret_cast<int>(tls.dbg); +    glesv2debugger::Message msg, read; + +    EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish)); + +    rewind(file); +    Read(read); +    EXPECT_EQ(contextId, read.context_id()); +    EXPECT_EQ(read.glFinish, read.function()); +    EXPECT_EQ(false, read.expect_response()); +    EXPECT_EQ(read.BeforeCall, read.type()); + +    Read(read); +    EXPECT_EQ(contextId, read.context_id()); +    EXPECT_EQ(read.glFinish, read.function()); +    EXPECT_EQ(false, read.expect_response()); +    EXPECT_EQ(read.AfterCall, read.type()); +    EXPECT_TRUE(read.has_time()); +    EXPECT_EQ(arg0, read.arg0()); +    const int readArg7 = read.arg7(); +    EXPECT_EQ(arg7, (float &)readArg7); +    EXPECT_EQ(arg8, read.arg8()); + +    const long pos = ftell(file); +    fseek(file, 0, SEEK_END); +    EXPECT_EQ(pos, ftell(file)) +    << "should only write the BeforeCall and AfterCall messages"; +} + +TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray) +{ +    Debug_glEnableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index + +    glesv2debugger::Message read; +    rewind(file); +    Read(read); +    EXPECT_EQ(read.glEnableVertexAttribArray, read.function()); +    EXPECT_EQ(tls.dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0()); +    Read(read); + +    rewind(file); +    Debug_glDisableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index +    rewind(file); +    Read(read); +    Read(read); + +    for (unsigned int i = 0; i < tls.dbg->MAX_VERTEX_ATTRIBS; i += 5) { +        rewind(file); +        Debug_glEnableVertexAttribArray(i); +        EXPECT_TRUE(tls.dbg->vertexAttribs[i].enabled); +        rewind(file); +        Read(read); +        EXPECT_EQ(read.glEnableVertexAttribArray, read.function()); +        EXPECT_EQ(i, read.arg0()); +        Read(read); + +        rewind(file); +        Debug_glDisableVertexAttribArray(i); +        EXPECT_FALSE(tls.dbg->vertexAttribs[i].enabled); +        rewind(file); +        Read(read); +        EXPECT_EQ(read.glDisableVertexAttribArray, read.function()); +        EXPECT_EQ(i, read.arg0()); +        Read(read); +    } +} diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp new file mode 100644 index 0000000000..617292e280 --- /dev/null +++ b/opengl/libs/GLES2_dbg/test/test_socket.cpp @@ -0,0 +1,474 @@ +/* + ** 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. + */ + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include "header.h" +#include "gtest/gtest.h" +#include "egl_tls.h" +#include "hooks.h" + +namespace android +{ +extern int serverSock, clientSock; +extern pthread_key_t dbgEGLThreadLocalStorageKey; +}; + +void * glNoop(); + +class SocketContextTest : public ::testing::Test +{ +protected: +    tls_t tls; +    gl_hooks_t hooks; +    int sock; +    char * buffer; +    unsigned int bufferSize; + +    SocketContextTest() : sock(-1) { +    } + +    virtual ~SocketContextTest() { +    } + +    virtual void SetUp() { +        if (dbgEGLThreadLocalStorageKey == -1) +            pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL); +        ASSERT_NE(-1, dbgEGLThreadLocalStorageKey); +        tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE); +        ASSERT_TRUE(tls.dbg != NULL); +        pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls); +        for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++) +            ((void **)&hooks)[i] = (void *)glNoop; + +        int socks[2] = {-1, -1}; +        ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks)); +        clientSock = socks[0]; +        sock = socks[1]; + +        bufferSize = 128; +        buffer = new char [128]; +        ASSERT_NE((char *)NULL, buffer); +    } + +    virtual void TearDown() { +        close(sock); +        close(clientSock); +        clientSock = -1; +        delete buffer; +    } + +    void Write(glesv2debugger::Message & msg) const { +        msg.set_context_id((int)tls.dbg); +        msg.set_type(msg.Response); +        ASSERT_TRUE(msg.has_context_id()); +        ASSERT_TRUE(msg.has_function()); +        ASSERT_TRUE(msg.has_type()); +        ASSERT_TRUE(msg.has_expect_response()); +        static std::string str; +        msg.SerializeToString(&str); +        const uint32_t len = str.length(); +        ASSERT_EQ(sizeof(len), send(sock, &len, sizeof(len), 0)); +        ASSERT_EQ(str.length(), send(sock, str.data(), str.length(), 0)); +    } + +    void Read(glesv2debugger::Message & msg) { +        int available = 0; +        ASSERT_EQ(0, ioctl(sock, FIONREAD, &available)); +        ASSERT_GT(available, 0); +        uint32_t len = 0; +        ASSERT_EQ(sizeof(len), recv(sock, &len, sizeof(len), 0)); +        if (len > bufferSize) { +            bufferSize = len; +            buffer = new char[bufferSize]; +            ASSERT_TRUE(buffer != NULL); +        } +        ASSERT_EQ(len, recv(sock, buffer, len, 0)); +        msg.Clear(); +        msg.ParseFromArray(buffer, len); +        ASSERT_TRUE(msg.has_context_id()); +        ASSERT_TRUE(msg.has_function()); +        ASSERT_TRUE(msg.has_type()); +        ASSERT_TRUE(msg.has_expect_response()); +    } + +    void CheckNoAvailable() { +        int available = 0; +        ASSERT_EQ(0, ioctl(sock, FIONREAD, &available)); +        ASSERT_EQ(available, 0); +    } +}; + +TEST_F(SocketContextTest, MessageLoopSkip) +{ +    static const int arg0 = 45; +    static const float arg7 = -87.2331f; +    static const int arg8 = -3; +    static const int * ret = (int *)870; + +    struct Caller : public FunctionCall { +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            msg.set_arg0(arg0); +            msg.set_arg7((int &)arg7); +            msg.set_arg8(arg8); +            return ret; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    tls.dbg->expectResponse.Bit(msg.glFinish, true); + +    cmd.set_function(cmd.SKIP); +    cmd.set_expect_response(false); +    Write(cmd); + +    EXPECT_NE(ret, MessageLoop(caller, msg, msg.glFinish)); + +    Read(read); +    EXPECT_EQ(read.glFinish, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); +    EXPECT_NE(arg0, read.arg0()); +    EXPECT_NE((int &)arg7, read.arg7()); +    EXPECT_NE(arg8, read.arg8()); + +    CheckNoAvailable(); +} + +TEST_F(SocketContextTest, MessageLoopContinue) +{ +    static const int arg0 = GL_FRAGMENT_SHADER; +    static const int ret = -342; +    struct Caller : public FunctionCall { +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            msg.set_ret(ret); +            return (int *)ret; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    tls.dbg->expectResponse.Bit(msg.glCreateShader, true); + +    cmd.set_function(cmd.CONTINUE); +    cmd.set_expect_response(false); // MessageLoop should automatically skip after continue +    Write(cmd); + +    msg.set_arg0(arg0); +    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateShader)); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); +    EXPECT_EQ(arg0, read.arg0()); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.AfterCall, read.type()); +    EXPECT_EQ(ret, read.ret()); + +    CheckNoAvailable(); +} + +TEST_F(SocketContextTest, MessageLoopGenerateCall) +{ +    static const int ret = -342; +    static unsigned int createShader, createProgram; +    createShader = 0; +    createProgram = 0; +    struct Caller : public FunctionCall { +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            const int r = (int)_c->glCreateProgram(); +            msg.set_ret(r); +            return (int *)r; +        } +        static GLuint CreateShader(const GLenum type) { +            createShader++; +            return type; +        } +        static GLuint CreateProgram() { +            createProgram++; +            return ret; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    hooks.gl.glCreateShader = caller.CreateShader; +    hooks.gl.glCreateProgram = caller.CreateProgram; +    tls.dbg->expectResponse.Bit(msg.glCreateProgram, true); + +    cmd.set_function(cmd.glCreateShader); +    cmd.set_arg0(GL_FRAGMENT_SHADER); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.Clear(); +    cmd.set_function(cmd.CONTINUE); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.set_function(cmd.glCreateShader); +    cmd.set_arg0(GL_VERTEX_SHADER); +    cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards +    Write(cmd); + +    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram)); + +    Read(read); +    EXPECT_EQ(read.glCreateProgram, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.AfterGeneratedCall, read.type()); +    EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret()); + +    Read(read); +    EXPECT_EQ(read.glCreateProgram, read.function()); +    EXPECT_EQ(read.AfterCall, read.type()); +    EXPECT_EQ(ret, read.ret()); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.AfterGeneratedCall, read.type()); +    EXPECT_EQ(GL_VERTEX_SHADER, read.ret()); + +    EXPECT_EQ(2, createShader); +    EXPECT_EQ(1, createProgram); + +    CheckNoAvailable(); +} + +TEST_F(SocketContextTest, MessageLoopSetProp) +{ +    static const int ret = -342; +    static unsigned int createShader, createProgram; +    createShader = 0; +    createProgram = 0; +    struct Caller : public FunctionCall { +        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { +            const int r = (int)_c->glCreateProgram(); +            msg.set_ret(r); +            return (int *)r; +        } +        static GLuint CreateShader(const GLenum type) { +            createShader++; +            return type; +        } +        static GLuint CreateProgram() { +            createProgram++; +            return ret; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    hooks.gl.glCreateShader = caller.CreateShader; +    hooks.gl.glCreateProgram = caller.CreateProgram; +    tls.dbg->expectResponse.Bit(msg.glCreateProgram, false); + +    cmd.set_function(cmd.SETPROP); +    cmd.set_prop(cmd.ExpectResponse); +    cmd.set_arg0(cmd.glCreateProgram); +    cmd.set_arg1(true); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.Clear(); +    cmd.set_function(cmd.glCreateShader); +    cmd.set_arg0(GL_FRAGMENT_SHADER); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.set_function(cmd.SETPROP); +    cmd.set_prop(cmd.CaptureDraw); +    cmd.set_arg0(819); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.Clear(); +    cmd.set_function(cmd.CONTINUE); +    cmd.set_expect_response(true); +    Write(cmd); + +    cmd.set_function(cmd.glCreateShader); +    cmd.set_arg0(GL_VERTEX_SHADER); +    cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards +    Write(cmd); + +    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram)); + +    EXPECT_TRUE(tls.dbg->expectResponse.Bit(msg.glCreateProgram)); +    EXPECT_EQ(819, tls.dbg->captureDraw); + +    Read(read); +    EXPECT_EQ(read.glCreateProgram, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.AfterGeneratedCall, read.type()); +    EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret()); + +    Read(read); +    EXPECT_EQ(read.glCreateProgram, read.function()); +    EXPECT_EQ(read.AfterCall, read.type()); +    EXPECT_EQ(ret, read.ret()); + +    Read(read); +    EXPECT_EQ(read.glCreateShader, read.function()); +    EXPECT_EQ(read.AfterGeneratedCall, read.type()); +    EXPECT_EQ(GL_VERTEX_SHADER, read.ret()); + +    EXPECT_EQ(2, createShader); +    EXPECT_EQ(1, createProgram); + +    CheckNoAvailable(); +} + +TEST_F(SocketContextTest, TexImage2D) +{ +    static const GLenum _target = GL_TEXTURE_2D; +    static const GLint _level = 1, _internalformat = GL_RGBA; +    static const GLsizei _width = 2, _height = 2; +    static const GLint _border = 333; +    static const GLenum _format = GL_RGB, _type = GL_UNSIGNED_SHORT_5_6_5; +    static const short _pixels [_width * _height] = {11, 22, 33, 44}; +    static unsigned int texImage2D; +    texImage2D = 0; + +    struct Caller { +        static void TexImage2D(GLenum target, GLint level, GLint internalformat, +                               GLsizei width, GLsizei height, GLint border, +                               GLenum format, GLenum type, const GLvoid* pixels) { +            EXPECT_EQ(_target, target); +            EXPECT_EQ(_level, level); +            EXPECT_EQ(_internalformat, internalformat); +            EXPECT_EQ(_width, width); +            EXPECT_EQ(_height, height); +            EXPECT_EQ(_border, border); +            EXPECT_EQ(_format, format); +            EXPECT_EQ(_type, type); +            EXPECT_EQ(0, memcmp(_pixels, pixels, sizeof(_pixels))); +            texImage2D++; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    hooks.gl.glTexImage2D = caller.TexImage2D; +    tls.dbg->expectResponse.Bit(msg.glTexImage2D, false); + +    Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border, +                       _format, _type, _pixels); +    EXPECT_EQ(1, texImage2D); + +    Read(read); +    EXPECT_EQ(read.glTexImage2D, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); +    EXPECT_EQ(_target, read.arg0()); +    EXPECT_EQ(_level, read.arg1()); +    EXPECT_EQ(_internalformat, read.arg2()); +    EXPECT_EQ(_width, read.arg3()); +    EXPECT_EQ(_height, read.arg4()); +    EXPECT_EQ(_border, read.arg5()); +    EXPECT_EQ(_format, read.arg6()); +    EXPECT_EQ(_type, read.arg7()); + +    EXPECT_TRUE(read.has_data()); +    uint32_t dataLen = 0; +    const unsigned char * data = tls.dbg->Decompress(read.data().data(), +                                 read.data().length(), &dataLen); +    EXPECT_EQ(sizeof(_pixels), dataLen); +    if (sizeof(_pixels) == dataLen) +        EXPECT_EQ(0, memcmp(_pixels, data, sizeof(_pixels))); + +    Read(read); +    EXPECT_EQ(read.glTexImage2D, read.function()); +    EXPECT_EQ(read.AfterCall, read.type()); + +    CheckNoAvailable(); +} + +TEST_F(SocketContextTest, CopyTexImage2D) +{ +    static const GLenum _target = GL_TEXTURE_2D; +    static const GLint _level = 1, _internalformat = GL_RGBA; +    static const GLint _x = 9, _y = 99; +    static const GLsizei _width = 2, _height = 3; +    static const GLint _border = 333; +    static const int _pixels [_width * _height] = {11, 22, 33, 44, 55, 66}; +    static unsigned int copyTexImage2D, readPixels; +    copyTexImage2D = 0, readPixels = 0; + +    struct Caller { +        static void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, +                                   GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { +            EXPECT_EQ(_target, target); +            EXPECT_EQ(_level, level); +            EXPECT_EQ(_internalformat, internalformat); +            EXPECT_EQ(_x, x); +            EXPECT_EQ(_y, y); +            EXPECT_EQ(_width, width); +            EXPECT_EQ(_height, height); +            EXPECT_EQ(_border, border); +            copyTexImage2D++; +        } +        static void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, +                               GLenum format, GLenum type, GLvoid* pixels) { +            EXPECT_EQ(_x, x); +            EXPECT_EQ(_y, y); +            EXPECT_EQ(_width, width); +            EXPECT_EQ(_height, height); +            EXPECT_EQ(GL_RGBA, format); +            EXPECT_EQ(GL_UNSIGNED_BYTE, type); +            ASSERT_TRUE(pixels != NULL); +            memcpy(pixels, _pixels, sizeof(_pixels)); +            readPixels++; +        } +    } caller; +    glesv2debugger::Message msg, read, cmd; +    hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D; +    hooks.gl.glReadPixels = caller.ReadPixels; +    tls.dbg->expectResponse.Bit(msg.glCopyTexImage2D, false); + +    Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height, +                           _border); +    ASSERT_EQ(1, copyTexImage2D); +    ASSERT_EQ(1, readPixels); + +    Read(read); +    EXPECT_EQ(read.glCopyTexImage2D, read.function()); +    EXPECT_EQ(read.BeforeCall, read.type()); +    EXPECT_EQ(_target, read.arg0()); +    EXPECT_EQ(_level, read.arg1()); +    EXPECT_EQ(_internalformat, read.arg2()); +    EXPECT_EQ(_x, read.arg3()); +    EXPECT_EQ(_y, read.arg4()); +    EXPECT_EQ(_width, read.arg5()); +    EXPECT_EQ(_height, read.arg6()); +    EXPECT_EQ(_border, read.arg7()); + +    EXPECT_TRUE(read.has_data()); +    EXPECT_EQ(read.ReferencedImage, read.data_type()); +    EXPECT_EQ(GL_RGBA, read.pixel_format()); +    EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type()); +    uint32_t dataLen = 0; +    unsigned char * const data = tls.dbg->Decompress(read.data().data(), +                                 read.data().length(), &dataLen); +    ASSERT_EQ(sizeof(_pixels), dataLen); +    for (unsigned i = 0; i < sizeof(_pixels) / sizeof(*_pixels); i++) +        EXPECT_EQ(_pixels[i], ((const int *)data)[i]) << "xor with 0 ref is identity"; +    free(data); + +    Read(read); +    EXPECT_EQ(read.glCopyTexImage2D, read.function()); +    EXPECT_EQ(read.AfterCall, read.type()); + +    CheckNoAvailable(); +} diff --git a/opengl/libs/egl_tls.h b/opengl/libs/egl_tls.h new file mode 100644 index 0000000000..087989a06e --- /dev/null +++ b/opengl/libs/egl_tls.h @@ -0,0 +1,40 @@ +/* + ** 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. + */ + +#ifndef ANDROID_EGL_TLS_H +#define ANDROID_EGL_TLS_H + +#include <EGL/egl.h> + +#include "glesv2dbg.h" + +namespace android +{ +struct tls_t { +    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) { } +    ~tls_t() { +        if (dbg) +            DestroyDbgContext(dbg); +    } + +    EGLint      error; +    EGLContext  ctx; +    EGLBoolean  logCallWithNoContext; +    DbgContext* dbg; +}; +} + +#endif diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h index 8029dcedf9..ee2c0112dd 100644 --- a/opengl/libs/glesv2dbg.h +++ b/opengl/libs/glesv2dbg.h @@ -13,20 +13,27 @@   ** See the License for the specific language governing permissions and   ** limitations under the License.   */ -  +  #ifndef _GLESV2_DBG_H_  #define _GLESV2_DBG_H_ +#include <pthread.h> +  namespace android  { -    struct DbgContext; -     -    DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks); -    void DestroyDbgContext(DbgContext * const dbg); -     -    void StartDebugServer(unsigned short port); // create and bind socket if haven't already -    void StopDebugServer(); // close socket if open -     +struct DbgContext; + +DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey, +                              const unsigned version, const gl_hooks_t * const hooks); + +void DestroyDbgContext(DbgContext * const dbg); + +// create and bind socket if haven't already, if failed to create socket or +//  forceUseFile, then open /data/local/tmp/dump.gles2dbg, exit when size reached +void StartDebugServer(const unsigned short port, const bool forceUseFile, +                      const unsigned int maxFileSize, const char * const filePath); +void StopDebugServer(); // close socket if open +  }; // namespace android  #endif // #ifndef _GLESV2_DBG_H_ diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index 6c1a231853..31f41906ff 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -21,7 +21,7 @@ mkdir -p out/android/util  echo "package android.graphics;" > out/android/graphics/Canvas.java  echo "public interface Canvas {}" >> out/android/graphics/Canvas.java -echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java +echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java  # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java  echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java  echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index 9d8c5a0616..9fa2b7418c 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -58,7 +58,7 @@ public class JniCodeEmitter {          } else if (baseType.equals("void")) {              // nothing.          } else { -            throw new RuntimeException("Uknown primitive basetype " + baseType); +            throw new RuntimeException("Unknown primitive basetype " + baseType);          }          return jniName;      } @@ -200,15 +200,9 @@ public class JniCodeEmitter {                  if (emitExceptionCheck) {                      out.println(iii + indent + "_exception = 1;");                  } -                out.println(iii + indent + -                            (mUseCPlusPlus ? "_env" : "(*_env)") + -                            "->ThrowNew(" + -                            (mUseCPlusPlus ? "" : "_env, ") + -                            "IAEClass, " + -                            "\"" + -                            (isBuffer ? -                             "remaining()" : "length - " + offset) + -                            " < needed\");"); +                out.println(iii + indent + "jniThrowException(_env, " + +                        "\"java/lang/IllegalArgumentException\", " + +                        "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");");                  out.println(iii + indent + "goto exit;");                  needsExit = true;                  out.println(iii + "}"); @@ -302,7 +296,7 @@ public class JniCodeEmitter {          }          return false;      } -     +      String isRequiresFunc(CFunc cfunc) {          String[] checks = mChecker.getChecks(cfunc.getName());          int index = 1; @@ -329,109 +323,94 @@ public class JniCodeEmitter {          }          return null;      } -     +      void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,              boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { -                String[] checks = mChecker.getChecks(cfunc.getName()); - -                boolean lastWasIfcheck = false; - -                int index = 1; -                if (checks != null) { -                    while (index < checks.length) { -                        if (checks[index].startsWith("check")) { -                            if (lastWasIfcheck) { -                                printIfcheckPostamble(out, isBuffer, emitExceptionCheck, -                                                      offset, remaining, iii); -                            } -                            lastWasIfcheck = false; -                            if (cname != null && !cname.equals(checks[index + 1])) { -                                index += 3; -                                continue; -                            } -                            out.println(iii + "if (" + remaining + " < " + -                                        checks[index + 2] + -                                        ") {"); -                            if (emitExceptionCheck) { -                                out.println(iii + indent + "_exception = 1;"); -                            } -                    String exceptionClassName = "IAEClass"; +        String[] checks = mChecker.getChecks(cfunc.getName()); + +        boolean lastWasIfcheck = false; + +        int index = 1; +        if (checks != null) { +            while (index < checks.length) { +                if (checks[index].startsWith("check")) { +                    if (lastWasIfcheck) { +                        printIfcheckPostamble(out, isBuffer, emitExceptionCheck, +                                offset, remaining, iii); +                    } +                    lastWasIfcheck = false; +                    if (cname != null && !cname.equals(checks[index + 1])) { +                        index += 3; +                        continue; +                    } +                    out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); +                    if (emitExceptionCheck) { +                        out.println(iii + indent + "_exception = 1;"); +                    } +                    String exceptionClassName = "java/lang/IllegalArgumentException";                      // If the "check" keyword was of the form                      // "check_<class name>", use the class name in the                      // exception to be thrown                      int underscore = checks[index].indexOf('_');                      if (underscore >= 0) { -                    exceptionClassName = checks[index].substring(underscore + 1) + "Class"; -                    } -                            out.println(iii + indent + -                                        (mUseCPlusPlus ? "_env" : "(*_env)") + -                                        "->ThrowNew(" + -                                        (mUseCPlusPlus ? "" : "_env, ") + -                        exceptionClassName + ", " + -                                        "\"" + -                                        (isBuffer ? -                                         "remaining()" : "length - " + offset) + -                                        " < " + checks[index + 2] + -                                        "\");"); - -                            out.println(iii + indent + "goto exit;"); -                            needsExit = true; -                            out.println(iii + "}"); - -                            index += 3; -                        } else if (checks[index].equals("ifcheck")) { -                            String[] matches = checks[index + 4].split(","); - -                            if (!lastWasIfcheck) { -                                out.println(iii + "int _needed;"); -                                out.println(iii + -                                            "switch (" + -                                            checks[index + 3] + -                                            ") {"); -                            } - -                            for (int i = 0; i < matches.length; i++) { -                                out.println("#if defined(" + matches[i] + ")"); -                                out.println(iii + -                                            "    case " + -                                            matches[i] + -                                            ":"); -                                out.println("#endif // defined(" + matches[i] + ")"); -                            } -                            out.println(iii + -                                        "        _needed = " + -                                        checks[index + 2] + -                                        ";"); -                            out.println(iii + -                                        "        break;"); - -                            lastWasIfcheck = true; -                            index += 5; -                        } else if (checks[index].equals("return")) { -                            // ignore -                            index += 2; -                        } else if (checks[index].equals("unsupported")) { -                            // ignore -                            index += 1; -                        } else if (checks[index].equals("requires")) { -                            // ignore -                            index += 2; -                        } else if (checks[index].equals("nullAllowed")) { -                            // ignore -                            index += 1; +                        String abbr = checks[index].substring(underscore + 1); +                        if (abbr.equals("AIOOBE")) { +                            exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";                          } else { -                            System.out.println("Error: unknown keyword \"" + -                                               checks[index] + "\""); -                            System.exit(0); +                            throw new RuntimeException("unknown exception abbreviation: " + abbr);                          }                      } -                } +                    out.println(iii + indent + "jniThrowException(_env, " + +                            "\"" + exceptionClassName + "\", " + +                            "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");"); + +                    out.println(iii + indent + "goto exit;"); +                    needsExit = true; +                    out.println(iii + "}"); + +                    index += 3; +                } else if (checks[index].equals("ifcheck")) { +                    String[] matches = checks[index + 4].split(","); + +                    if (!lastWasIfcheck) { +                        out.println(iii + "int _needed;"); +                        out.println(iii + "switch (" + checks[index + 3] + ") {"); +                    } + +                    for (int i = 0; i < matches.length; i++) { +                        out.println("#if defined(" + matches[i] + ")"); +                        out.println(iii + "    case " + matches[i] + ":"); +                        out.println("#endif // defined(" + matches[i] + ")"); +                    } +                    out.println(iii + "        _needed = " + checks[index + 2] + ";"); +                    out.println(iii + "        break;"); -                if (lastWasIfcheck) { -                    printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); +                    lastWasIfcheck = true; +                    index += 5; +                } else if (checks[index].equals("return")) { +                    // ignore +                    index += 2; +                } else if (checks[index].equals("unsupported")) { +                    // ignore +                    index += 1; +                } else if (checks[index].equals("requires")) { +                    // ignore +                    index += 2; +                } else if (checks[index].equals("nullAllowed")) { +                    // ignore +                    index += 1; +                } else { +                    System.out.println("Error: unknown keyword \"" + checks[index] + "\""); +                    System.exit(0);                  }              } +        } + +        if (lastWasIfcheck) { +            printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); +        } +    }      boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {          if (nonPrimitiveArgs.size() > 0) { @@ -817,7 +796,7 @@ public class JniCodeEmitter {          boolean isUnsupported = isUnsupportedFunc(cfunc);          if (isUnsupported) {              out.println(indent + -                        "_env->ThrowNew(UOEClass,"); +                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");              out.println(indent +                          "    \"" + cfunc.getName() + "\");");              if (!isVoid) { @@ -828,13 +807,13 @@ public class JniCodeEmitter {              out.println();              return;          } -         +          String requiresExtension = isRequiresFunc(cfunc);          if (requiresExtension != null) {              out.println(indent +                          "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");              out.println(indent + indent + -                        "_env->ThrowNew(UOEClass,"); +                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");              out.println(indent + indent +                          "    \"" + cfunc.getName() + "\");");              if (isVoid) { @@ -945,7 +924,8 @@ public class JniCodeEmitter {                  CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));                  String decl = type.getDeclaration();                  out.println(indent + "if (!" + cname + ") {"); -                out.println(indent + "    _env->ThrowNew(IAEClass, \"" + cname + " == null\");"); +                out.println(indent + "    jniThrowException(_env, " + +                        "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");");                  out.println(indent + "    goto exit;");                  needsExit = true;                  out.println(indent + "}"); @@ -978,13 +958,9 @@ public class JniCodeEmitter {                      if (emitExceptionCheck) {                          out.println(indent + indent + "_exception = 1;");                      } -                    out.println(indent + "    " + -                                (mUseCPlusPlus ? "_env" : "(*_env)") + -                                "->ThrowNew(" + -                                (mUseCPlusPlus ? "" : "_env, ") + -                                "IAEClass, " + -                                "\"" + cname + -                                " == null\");"); +                    out.println(indent + "    jniThrowException(_env, " + +                            "\"java/lang/IllegalArgumentException\", " + +                            "\"" + cname + " == null\");");                      out.println(indent + "    goto exit;");                      needsExit = true;                      out.println(indent + "}"); @@ -993,12 +969,8 @@ public class JniCodeEmitter {                      if (emitExceptionCheck) {                          out.println(indent + indent + "_exception = 1;");                      } -                    out.println(indent + "    " + -                                (mUseCPlusPlus ? "_env" : "(*_env)") + -                                "->ThrowNew(" + -                                (mUseCPlusPlus ? "" : "_env, ") + -                                "IAEClass, " + -                                "\"" + offset + " < 0\");"); +                    out.println(indent + "    jniThrowException(_env, " + +                            "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");");                      out.println(indent + "    goto exit;");                      needsExit = true;                      out.println(indent + "}"); diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp index 294d1ce82e..5d418d7c40 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -27,10 +29,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID;  static jmethodID getBaseArrayOffsetID; @@ -41,7 +39,7 @@ static jfieldID elementSizeShiftID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -63,26 +61,6 @@ nativeClassInitBuffer(JNIEnv *_env)  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -103,13 +81,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -122,4 +100,3 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp index e1c09f4614..35a3c333a6 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -40,10 +42,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID;  static jmethodID getBaseArrayOffsetID; @@ -54,7 +52,7 @@ static jfieldID elementSizeShiftID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -75,26 +73,6 @@ nativeClassInitBuffer(JNIEnv *_env)          _env->GetFieldID(bufferClass, "_elementSizeShift", "I");  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -115,13 +93,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -140,7 +118,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {          jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);          buf += position << elementSizeShift;      } else { -        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); +        jniThrowException(_env, "java/lang/IllegalArgumentException", +                          "Must use a native order direct Buffer");      }      return (void*) buf;  } @@ -153,4 +132,3 @@ getNumCompressedTextureFormats() {  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp index 2548b32a24..9b29a44109 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -36,10 +38,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID;  static jmethodID getBaseArrayOffsetID; @@ -50,7 +48,7 @@ static jfieldID elementSizeShiftID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -72,26 +70,6 @@ nativeClassInitBuffer(JNIEnv *_env)  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -112,13 +90,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -138,9 +116,9 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {          jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);          buf += position << elementSizeShift;      } else { -        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); +        jniThrowException(_env, "java/lang/IllegalArgumentException", +                          "Must use a native order direct Buffer");      }      return (void*) buf;  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp index 4c297f7869..823079f39f 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -34,10 +36,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID;  static jmethodID getBaseArrayOffsetID; @@ -48,7 +46,7 @@ static jfieldID elementSizeShiftID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -70,26 +68,6 @@ nativeClassInitBuffer(JNIEnv *_env)  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -110,13 +88,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -136,10 +114,10 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {          jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);          buf += position << elementSizeShift;      } else { -        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); +        jniThrowException(_env, "java/lang/IllegalArgumentException", +                          "Must use a native order direct Buffer");      }      return (void*) buf;  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp index e451e9ad90..13a2577c28 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -27,10 +29,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID;  static jmethodID getBaseArrayOffsetID; @@ -41,7 +39,7 @@ static jfieldID elementSizeShiftID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -63,26 +61,6 @@ nativeClassInitBuffer(JNIEnv *_env)  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -103,13 +81,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -129,7 +107,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {          jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);          buf += position << elementSizeShift;      } else { -        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); +        jniThrowException(_env, "java/lang/IllegalArgumentException", +                          "Must use a native order direct Buffer");      }      return (void*) buf;  } @@ -147,4 +126,3 @@ static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp index d92f515983..ce6ab24044 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp @@ -1,27 +1,19 @@ -#include <string.h> +#include <stdlib.h>  /* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */ -static -jstring -android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) { +static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {      GLint infoLen = 0; -    jstring _result = 0; -    char* buf = 0;      glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen); -    if (infoLen) { -        char* buf = (char*) malloc(infoLen); -        if (buf == 0) { -            _env->ThrowNew(IAEClass, "out of memory"); -            goto exit; -        } -        glGetProgramInfoLog(shader, infoLen, NULL, buf); -        _result = _env->NewStringUTF(buf); -    } else { -        _result = _env->NewStringUTF(""); +    if (!infoLen) { +        return _env->NewStringUTF("");      } -exit: -    if (buf) { -            free(buf); +    char* buf = (char*) malloc(infoLen); +    if (buf == NULL) { +        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); +        return NULL;      } -    return _result; -}
\ No newline at end of file +    glGetProgramInfoLog(shader, infoLen, NULL, buf); +    jstring result = _env->NewStringUTF(buf); +    free(buf); +    return result; +} diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp index 5441d66817..dd656b60c1 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp @@ -1,27 +1,19 @@ -#include <string.h> +#include <stdlib.h>  /* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */ -static -jstring -android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) { +static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {      GLint infoLen = 0; -    jstring _result = 0; -    char* buf = 0;      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); -    if (infoLen) { -        char* buf = (char*) malloc(infoLen); -        if (buf == 0) { -            _env->ThrowNew(IAEClass, "out of memory"); -            goto exit; -        } -        glGetShaderInfoLog(shader, infoLen, NULL, buf); -        _result = _env->NewStringUTF(buf); -    } else { -        _result = _env->NewStringUTF(""); +    if (!infoLen) { +        return _env->NewStringUTF("");      } -exit: -    if (buf) { -            free(buf); +    char* buf = (char*) malloc(infoLen); +    if (buf == NULL) { +        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); +        return NULL;      } -    return _result; -}
\ No newline at end of file +    glGetShaderInfoLog(shader, infoLen, NULL, buf); +    jstring result = _env->NewStringUTF(buf); +    free(buf); +    return result; +} diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.cpp b/opengl/tools/glgen/stubs/gles11/glGetString.cpp index a400859f77..239fe4ac2e 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetString.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetString.cpp @@ -1,11 +1,5 @@ -#include <string.h>
 -
  /* const GLubyte * glGetString ( GLenum name ) */
 -static
 -jstring
 -android_glGetString
 -  (JNIEnv *_env, jobject _this, jint name) {
 -    const char * chars = (const char *)glGetString((GLenum)name);
 -    jstring output = _env->NewStringUTF(chars);
 -    return output;
 +static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
 +    const char* chars = (const char*) glGetString((GLenum) name);
 +    return _env->NewStringUTF(chars);
  }
 diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp index c2741089a6..125fd0ff19 100644 --- a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp +++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp @@ -6,7 +6,7 @@ android_glShaderSource      (JNIEnv *_env, jobject _this, jint shader, jstring string) {      if (!string) { -        _env->ThrowNew(IAEClass, "string == null"); +        jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");          return;      } diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index c2464b0562..f7315eefdd 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -1,21 +1,23 @@  **  ** 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  +** 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  +**     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  +** 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 source file is automatically generated +#include "jni.h" +#include "JNIHelp.h"  #include <android_runtime/AndroidRuntime.h>  #include <utils/misc.h> @@ -63,10 +65,6 @@ static int initialized = 0;  static jclass nioAccessClass;  static jclass bufferClass; -static jclass OOMEClass; -static jclass UOEClass; -static jclass IAEClass; -static jclass AIOOBEClass;  static jclass G11ImplClass;  static jmethodID getBasePointerID;  static jmethodID getBaseArrayID; @@ -84,7 +82,7 @@ static jfieldID have_OES_texture_cube_mapID;  /* Cache method IDs each time the class is loaded. */  static void -nativeClassInitBuffer(JNIEnv *_env) +nativeClassInit(JNIEnv *_env, jclass glImplClass)  {      jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");      nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); @@ -114,26 +112,6 @@ nativeClassInitBuffer(JNIEnv *_env)          _env->GetFieldID(bufferClass, "_elementSizeShift", "I");  } -static void -nativeClassInit(JNIEnv *_env, jclass glImplClass) -{ -    nativeClassInitBuffer(_env); - -    jclass IAEClassLocal = -        _env->FindClass("java/lang/IllegalArgumentException"); -    jclass OOMEClassLocal = -         _env->FindClass("java/lang/OutOfMemoryError"); -    jclass UOEClassLocal = -         _env->FindClass("java/lang/UnsupportedOperationException"); -    jclass AIOOBEClassLocal = -         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); - -    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); -    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); -    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); -    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); -} -  static void *  getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)  { @@ -154,7 +132,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)          *array = NULL;          return (void *) (jint) pointer;      } -     +      *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,              getBaseArrayID, buffer);      if (*array == NULL) { @@ -163,7 +141,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)      offset = _env->CallStaticIntMethod(nioAccessClass,              getBaseArrayOffsetID, buffer);      data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); -     +      return (void *) ((char *) data + offset);  } @@ -207,7 +185,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {                  releasePointer(_env, array, buf, 0);              }          } else { -            _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); +            jniThrowException(_env, "java/lang/IllegalArgumentException", +                              "Must use a native order direct Buffer");          }      }      return buf; @@ -250,7 +229,7 @@ nextExtension(const GLubyte* pExtensions) {          }      }  } -     +  static bool  checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {      for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) { @@ -279,4 +258,3 @@ supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) {  }  // -------------------------------------------------------------------------- - diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl index 372710625e..cd730aa95b 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl +++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl @@ -18,7 +18,7 @@  package com.google.android.gles_jni; -import android.app.ActivityThread; +import android.app.AppGlobals;  import android.content.pm.ApplicationInfo;  import android.content.pm.IPackageManager;  import android.os.Build; @@ -64,7 +64,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack {      private static boolean allowIndirectBuffers(String appName) {          boolean result = false;          int version = 0; -        IPackageManager pm = ActivityThread.getPackageManager(); +        IPackageManager pm = AppGlobals.getPackageManager();          try {              ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);              if (applicationInfo != null) { diff --git a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp index a400859f77..cd6e3f3957 100644 --- a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp +++ b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp @@ -1,11 +1,5 @@ -#include <string.h>
 -
  /* const GLubyte * glGetString ( GLenum name ) */
 -static
 -jstring
 -android_glGetString
 -  (JNIEnv *_env, jobject _this, jint name) {
 -    const char * chars = (const char *)glGetString((GLenum)name);
 -    jstring output = _env->NewStringUTF(chars);
 -    return output;
 +static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {
 +    const char* chars = (const char*) glGetString((GLenum) name);
 +    return _env->NewStringUTF(chars);
  }
 diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 64cff965b1..a774841ddb 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -93,7 +93,11 @@ int DisplayHardware::getWidth() const           { return mWidth; }  int DisplayHardware::getHeight() const          { return mHeight; }  PixelFormat DisplayHardware::getFormat() const  { return mFormat; }  uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } -uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; } + +uint32_t DisplayHardware::getMaxViewportDims() const { +    return mMaxViewportDims[0] < mMaxViewportDims[1] ? +            mMaxViewportDims[0] : mMaxViewportDims[1]; +}  void DisplayHardware::init(uint32_t dpy)  { @@ -228,7 +232,7 @@ void DisplayHardware::init(uint32_t dpy)              eglQueryString(display, EGL_EXTENSIONS));      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); -    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims); +    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);  #ifdef EGL_ANDROID_swap_rectangle @@ -260,7 +264,7 @@ void DisplayHardware::init(uint32_t dpy)      LOGI("version   : %s", extensions.getVersion());      LOGI("extensions: %s", extensions.getExtension());      LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); -    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); +    LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);      LOGI("flags = %08x", mFlags);      // Unbind the context from this thread diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index ee7a2af80e..cdf89fd0ba 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -108,7 +108,7 @@ private:      PixelFormat     mFormat;      uint32_t        mFlags;      mutable uint32_t mPageFlipCount; -    GLint           mMaxViewportDims; +    GLint           mMaxViewportDims[2];      GLint           mMaxTextureSize;      HWComposer*     mHwc; diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 90865da80b..59b7e5a741 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -38,23 +38,10 @@  #include "SurfaceFlinger.h"  // ---------------------------------------------------------------------------- -// the sim build doesn't have gettid - -#ifndef HAVE_GETTID -# define gettid getpid -#endif - -// ----------------------------------------------------------------------------  namespace android { -static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep"; -static char const * kWakeFileName = "/sys/power/wait_for_fb_wake"; -static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep"; -static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake"; - -// This dir exists if the framebuffer console is present, either built into -// the kernel or loaded as a module. -static char const * const kFbconSysDir = "/sys/class/graphics/fbcon"; +static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep"; +static char const * const kWakeFileName  = "/sys/power/wait_for_fb_wake";  // ---------------------------------------------------------------------------- @@ -122,237 +109,13 @@ status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const  status_t DisplayHardwareBase::DisplayEventThread::readyToRun()  { -    if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) { -        if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) { -            LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName); -            return NO_INIT; -        } -        kSleepFileName = kOldSleepFileName; -        kWakeFileName = kOldWakeFileName; -    }      return NO_ERROR;  }  status_t DisplayHardwareBase::DisplayEventThread::initCheck() const  { -    return (((access(kSleepFileName, R_OK) == 0 && -            access(kWakeFileName, R_OK) == 0) || -            (access(kOldSleepFileName, R_OK) == 0 && -            access(kOldWakeFileName, R_OK) == 0)) && -            access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT; -} - -// ---------------------------------------------------------------------------- - -pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0; - -DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread( -        const sp<SurfaceFlinger>& flinger) -    : DisplayEventThreadBase(flinger), consoleFd(-1) -{    -    sSignalCatcherPid = 0; - -    // create a new console -    char const * const ttydev = "/dev/tty0"; -    int fd = open(ttydev, O_RDWR | O_SYNC); -    if (fd<0) { -        LOGE("Can't open %s", ttydev); -        this->consoleFd = -errno; -        return; -    } - -    // to make sure that we are in text mode -    int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT); -    if (res<0) { -        LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)", -                fd, res, strerror(errno)); -    } -     -    // get the current console -    struct vt_stat vs; -    res = ioctl(fd, VT_GETSTATE, &vs); -    if (res<0) { -        LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)", -                fd, res, strerror(errno)); -        this->consoleFd = -errno; -        return; -    } - -    // switch to console 7 (which is what X normaly uses) -    int vtnum = 7; -    do { -        res = ioctl(fd, VT_ACTIVATE, (void*)vtnum); -    } while(res < 0 && errno == EINTR); -    if (res<0) { -        LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d", -                fd, errno, strerror(errno), vtnum); -        this->consoleFd = -errno; -        return; -    } - -    do { -        res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum); -    } while(res < 0 && errno == EINTR); -    if (res<0) { -        LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d", -                fd, res, errno, strerror(errno), vtnum); -        this->consoleFd = -errno; -        return; -    } - -    // open the new console -    close(fd); -    fd = open(ttydev, O_RDWR | O_SYNC); -    if (fd<0) { -        LOGE("Can't open new console %s", ttydev); -        this->consoleFd = -errno; -        return; -    } - -    /* disable console line buffer, echo, ... */ -    struct termios ttyarg; -    ioctl(fd, TCGETS , &ttyarg); -    ttyarg.c_iflag = 0; -    ttyarg.c_lflag = 0; -    ioctl(fd, TCSETS , &ttyarg); - -    // set up signals so we're notified when the console changes -    // we can't use SIGUSR1 because it's used by the java-vm -    vm.mode = VT_PROCESS; -    vm.waitv = 0; -    vm.relsig = SIGUSR2; -    vm.acqsig = SIGUNUSED; -    vm.frsig = 0; - -    struct sigaction act; -    sigemptyset(&act.sa_mask); -    act.sa_handler = sigHandler; -    act.sa_flags = 0; -    sigaction(vm.relsig, &act, NULL); - -    sigemptyset(&act.sa_mask); -    act.sa_handler = sigHandler; -    act.sa_flags = 0; -    sigaction(vm.acqsig, &act, NULL); - -    sigset_t mask; -    sigemptyset(&mask); -    sigaddset(&mask, vm.relsig); -    sigaddset(&mask, vm.acqsig); -    sigprocmask(SIG_BLOCK, &mask, NULL); - -    // switch to graphic mode -    res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS); -    LOGW_IF(res<0, -            "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res); - -    this->prev_vt_num = vs.v_active; -    this->vt_num = vtnum; -    this->consoleFd = fd; -} - -DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread() -{    -    if (this->consoleFd >= 0) { -        int fd = this->consoleFd; -        int prev_vt_num = this->prev_vt_num; -        int res; -        ioctl(fd, KDSETMODE, (void*)KD_TEXT); -        do { -            res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num); -        } while(res < 0 && errno == EINTR); -        do { -            res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num); -        } while(res < 0 && errno == EINTR); -        close(fd);     -        char const * const ttydev = "/dev/tty0"; -        fd = open(ttydev, O_RDWR | O_SYNC); -        ioctl(fd, VT_DISALLOCATE, 0); -        close(fd); -    } -} - -status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun() -{ -    if (this->consoleFd >= 0) { -        sSignalCatcherPid = gettid(); -         -        sigset_t mask; -        sigemptyset(&mask); -        sigaddset(&mask, vm.relsig); -        sigaddset(&mask, vm.acqsig); -        sigprocmask(SIG_BLOCK, &mask, NULL); - -        int res = ioctl(this->consoleFd, VT_SETMODE, &vm); -        if (res<0) { -            LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)", -                    this->consoleFd, errno, strerror(errno)); -        } -        return NO_ERROR; -    } -    return this->consoleFd; -} - -void DisplayHardwareBase::ConsoleManagerThread::requestExit() -{ -    Thread::requestExit(); -    if (sSignalCatcherPid != 0) { -        // wake the thread up -        kill(sSignalCatcherPid, SIGINT); -        // wait for it... -    } -} - -void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig) -{ -    // resend the signal to our signal catcher thread -    LOGW("received signal %d in thread %d, resending to %d", -            sig, gettid(), sSignalCatcherPid); - -    // we absolutely need the delays below because without them -    // our main thread never gets a chance to handle the signal. -    usleep(10000); -    kill(sSignalCatcherPid, sig); -    usleep(10000); -} - -status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const -{ -    int fd = this->consoleFd; -    int err = ioctl(fd, VT_RELDISP, (void*)1); -    LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)", -        fd, errno, strerror(errno)); -    return (err<0) ? (-errno) : status_t(NO_ERROR); -} - -bool DisplayHardwareBase::ConsoleManagerThread::threadLoop() -{ -    sigset_t mask; -    sigemptyset(&mask); -    sigaddset(&mask, vm.relsig); -    sigaddset(&mask, vm.acqsig); - -    int sig = 0; -    sigwait(&mask, &sig); - -    if (sig == vm.relsig) { -        sp<SurfaceFlinger> flinger = mFlinger.promote(); -        //LOGD("About to give-up screen, flinger = %p", flinger.get()); -        if (flinger != 0) -            flinger->screenReleased(0); -    } else if (sig == vm.acqsig) { -        sp<SurfaceFlinger> flinger = mFlinger.promote(); -        //LOGD("Screen about to return, flinger = %p", flinger.get()); -        if (flinger != 0)  -            flinger->screenAcquired(0); -    } -     -    return true; -} - -status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const -{ -    return consoleFd >= 0 ? NO_ERROR : NO_INIT; +    return ((access(kSleepFileName, R_OK) == 0 && +            access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;  }  // ---------------------------------------------------------------------------- @@ -362,10 +125,6 @@ DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,      : mCanDraw(true), mScreenAcquired(true)  {      mDisplayEventThread = new DisplayEventThread(flinger); -    if (mDisplayEventThread->initCheck() != NO_ERROR) { -        // fall-back on the console -        mDisplayEventThread = new ConsoleManagerThread(flinger); -    }  }  DisplayHardwareBase::~DisplayHardwareBase() diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index fa6a0c4bc5..30eb258779 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -73,24 +73,6 @@ private:          virtual status_t initCheck() const;      }; -    class ConsoleManagerThread : public DisplayEventThreadBase  -    { -        int consoleFd; -        int vt_num; -        int prev_vt_num; -        vt_mode vm; -        static void sigHandler(int sig); -        static pid_t sSignalCatcherPid; -    public: -                ConsoleManagerThread(const sp<SurfaceFlinger>& flinger); -        virtual ~ConsoleManagerThread(); -        virtual bool threadLoop(); -        virtual status_t readyToRun(); -        virtual void requestExit(); -        virtual status_t releaseScreen() const; -        virtual status_t initCheck() const; -    }; -      sp<DisplayEventThreadBase>  mDisplayEventThread;      mutable int                 mCanDraw;      mutable int                 mScreenAcquired; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ea283c606a..7506f298f2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1241,8 +1241,10 @@ int SurfaceFlinger::setOrientation(DisplayID dpy,      return orientation;  } -sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, -        const String8& name, ISurfaceComposerClient::surface_data_t* params, +sp<ISurface> SurfaceFlinger::createSurface( +        ISurfaceComposerClient::surface_data_t* params, +        const String8& name, +        const sp<Client>& client,          DisplayID d, uint32_t w, uint32_t h, PixelFormat format,          uint32_t flags)  { @@ -2414,12 +2416,12 @@ ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {      return -1;  }  sp<ISurface> Client::createSurface( -        ISurfaceComposerClient::surface_data_t* params, int pid, +        ISurfaceComposerClient::surface_data_t* params,          const String8& name,          DisplayID display, uint32_t w, uint32_t h, PixelFormat format,          uint32_t flags)  { -    return mFlinger->createSurface(this, pid, name, params, +    return mFlinger->createSurface(params, name, this,              display, w, h, format, flags);  }  status_t Client::destroySurface(SurfaceID sid) { @@ -2523,7 +2525,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const  }  sp<ISurface> UserClient::createSurface( -        ISurfaceComposerClient::surface_data_t* params, int pid, +        ISurfaceComposerClient::surface_data_t* params,          const String8& name,          DisplayID display, uint32_t w, uint32_t h, PixelFormat format,          uint32_t flags) { @@ -2553,22 +2555,9 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h          LOGE("createGraphicBuffer: unable to create GraphicBuffer");          return 0;      } -    Mutex::Autolock _l(mLock); -    mBuffers.add(graphicBuffer);      return graphicBuffer;  } -void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) { -    Mutex::Autolock _l(mLock); -    if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) { -        sp<GraphicBuffer> b(mBuffers[bufIdx]); -        mBuffers.clear(); -        mBuffers.add(b); -    } else { -        mBuffers.clear(); -    } -} -  // ---------------------------------------------------------------------------  GraphicPlane::GraphicPlane() diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0964848edf..1b36d1cd67 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -75,7 +75,7 @@ private:      virtual sp<IMemoryHeap> getControlBlock() const;      virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;      virtual sp<ISurface> createSurface( -            surface_data_t* params, int pid, const String8& name, +            surface_data_t* params, const String8& name,              DisplayID display, uint32_t w, uint32_t h,PixelFormat format,              uint32_t flags);      virtual status_t destroySurface(SurfaceID surfaceId); @@ -107,7 +107,7 @@ private:      virtual sp<IMemoryHeap> getControlBlock() const;      virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;      virtual sp<ISurface> createSurface( -            surface_data_t* params, int pid, const String8& name, +            surface_data_t* params, const String8& name,              DisplayID display, uint32_t w, uint32_t h,PixelFormat format,              uint32_t flags);      virtual status_t destroySurface(SurfaceID surfaceId); @@ -125,14 +125,8 @@ class GraphicBufferAlloc : public BnGraphicBufferAlloc  public:      GraphicBufferAlloc();      virtual ~GraphicBufferAlloc(); -      virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,          PixelFormat format, uint32_t usage); -    virtual void freeAllGraphicBuffersExcept(int bufIdx); - -private: -    Vector<sp<GraphicBuffer> > mBuffers; -    Mutex mLock;  };  // --------------------------------------------------------------------------- @@ -238,9 +232,10 @@ private:      friend class Layer;      friend class LayerDim; -    sp<ISurface> createSurface(const sp<Client>& client, -            int pid, const String8& name, +    sp<ISurface> createSurface(              ISurfaceComposerClient::surface_data_t* params, +            const String8& name, +            const sp<Client>& client,              DisplayID display, uint32_t w, uint32_t h, PixelFormat format,              uint32_t flags);  |