egl_display.h revision 4774338bd0ad1ebe42c311fd0c72f13786b5c800
1/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 **     http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#ifndef ANDROID_EGL_DISPLAY_H
18#define ANDROID_EGL_DISPLAY_H
19
20
21#include <ctype.h>
22#include <stdint.h>
23#include <stdlib.h>
24
25#include <EGL/egl.h>
26#include <EGL/eglext.h>
27
28#include <cutils/compiler.h>
29#include <utils/SortedVector.h>
30#include <utils/threads.h>
31#include <utils/String8.h>
32
33#include "egldefs.h"
34#include "hooks.h"
35
36// ----------------------------------------------------------------------------
37namespace android {
38// ----------------------------------------------------------------------------
39
40class egl_object_t;
41class egl_context_t;
42class egl_connection_t;
43
44// ----------------------------------------------------------------------------
45
46class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
47    static egl_display_t sDisplay[NUM_DISPLAYS];
48    EGLDisplay getDisplay(EGLNativeDisplayType display);
49    void loseCurrentImpl(egl_context_t * cur_c);
50
51public:
52    enum {
53        NOT_INITIALIZED = 0,
54        INITIALIZED     = 1,
55        TERMINATED      = 2
56    };
57
58    egl_display_t();
59    ~egl_display_t();
60
61    EGLBoolean initialize(EGLint *major, EGLint *minor);
62    EGLBoolean terminate();
63
64    // add object to this display's list
65    void addObject(egl_object_t* object);
66    // remove object from this display's list
67    void removeObject(egl_object_t* object);
68    // add reference to this object. returns true if this is a valid object.
69    bool getObject(egl_object_t* object) const;
70
71    // These notifications allow the display to keep track of how many window
72    // surfaces exist, which it uses to decide whether to hibernate the
73    // underlying EGL implementation. They can be called by any thread without
74    // holding a lock, but must be called via egl_display_ptr to ensure
75    // proper hibernate/wakeup sequencing. If a surface destruction triggers
76    // hibernation, hibernation will be delayed at least until the calling
77    // thread's egl_display_ptr is destroyed.
78    void onWindowSurfaceCreated() {
79        mHibernation.incWakeCount(HibernationMachine::STRONG);
80    }
81    void onWindowSurfaceDestroyed() {
82        mHibernation.decWakeCount(HibernationMachine::STRONG);
83    }
84
85    static egl_display_t* get(EGLDisplay dpy);
86    static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
87
88    EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
89            EGLSurface draw, EGLSurface read, EGLContext ctx,
90            EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx);
91    static void loseCurrent(egl_context_t * cur_c);
92
93    inline bool isReady() const { return (refs > 0); }
94    inline bool isValid() const { return magic == '_dpy'; }
95    inline bool isAlive() const { return isValid(); }
96
97    char const * getVendorString() const { return mVendorString.string(); }
98    char const * getVersionString() const { return mVersionString.string(); }
99    char const * getClientApiString() const { return mClientApiString.string(); }
100    char const * getExtensionString() const { return mExtensionString.string(); }
101
102    inline uint32_t getRefsCount() const { return refs; }
103
104    struct strings_t {
105        char const * vendor;
106        char const * version;
107        char const * clientApi;
108        char const * extensions;
109    };
110
111    struct DisplayImpl {
112        DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { }
113        EGLDisplay  dpy;
114        EGLint      state;
115        strings_t   queryString;
116    };
117
118private:
119    uint32_t        magic;
120
121public:
122    DisplayImpl     disp;
123    bool    finishOnSwap;       // property: debug.egl.finish
124    bool    traceGpuCompletion; // property: debug.egl.traceGpuCompletion
125
126private:
127    friend class egl_display_ptr;
128    bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); }
129    void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); }
130
131            uint32_t                    refs;
132    mutable Mutex                       lock;
133            SortedVector<egl_object_t*> objects;
134            String8 mVendorString;
135            String8 mVersionString;
136            String8 mClientApiString;
137            String8 mExtensionString;
138
139    // HibernationMachine uses its own internal mutex to protect its own data.
140    // The owning egl_display_t's lock may be but is not required to be held
141    // when calling HibernationMachine methods. As a result, nothing in this
142    // class may call back up to egl_display_t directly or indirectly.
143    class HibernationMachine {
144    public:
145        // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt
146        // the next time the wakecount reaches zero. WEAK refs don't affect
147        // whether a hibernation attempt will be made. Use STRONG refs only
148        // for infrequent/heavy changes that are likely to indicate the
149        // EGLDisplay is entering or leaving a long-term idle state.
150        enum WakeRefStrength {
151            WEAK   = 0,
152            STRONG = 1,
153        };
154
155        HibernationMachine(): mWakeCount(0), mHibernating(false),
156                mAttemptHibernation(false), mDpyValid(false),
157#if BOARD_ALLOW_EGL_HIBERNATION
158                mAllowHibernation(true)
159#else
160                mAllowHibernation(false)
161#endif
162        {}
163        ~HibernationMachine() {}
164
165        bool incWakeCount(WakeRefStrength strenth);
166        void decWakeCount(WakeRefStrength strenth);
167
168        void setDisplayValid(bool valid);
169
170    private:
171        Mutex      mLock;
172        int32_t    mWakeCount;
173        bool       mHibernating;
174        bool       mAttemptHibernation;
175        bool       mDpyValid;
176        const bool mAllowHibernation;
177    };
178    HibernationMachine mHibernation;
179};
180
181// ----------------------------------------------------------------------------
182
183// An egl_display_ptr is a kind of smart pointer for egl_display_t objects.
184// It doesn't refcount the egl_display_t, but does ensure that the underlying
185// EGL implementation is "awake" (not hibernating) and ready for use as long
186// as the egl_display_ptr exists.
187class egl_display_ptr {
188public:
189    explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {
190        if (mDpy) {
191            if (CC_UNLIKELY(!mDpy->enter())) {
192                mDpy = NULL;
193            }
194        }
195    }
196
197    // We only really need a C++11 move constructor, not a copy constructor.
198    // A move constructor would save an enter()/leave() pair on every EGL API
199    // call. But enabling -std=c++0x causes lots of errors elsewhere, so I
200    // can't use a move constructor until those are cleaned up.
201    //
202    // egl_display_ptr(egl_display_ptr&& other) {
203    //     mDpy = other.mDpy;
204    //     other.mDpy = NULL;
205    // }
206    //
207    egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {
208        if (mDpy) {
209            mDpy->enter();
210        }
211    }
212
213    ~egl_display_ptr() {
214        if (mDpy) {
215            mDpy->leave();
216        }
217    }
218
219    const egl_display_t* operator->() const { return mDpy; }
220          egl_display_t* operator->()       { return mDpy; }
221
222    const egl_display_t* get() const { return mDpy; }
223          egl_display_t* get()       { return mDpy; }
224
225    operator bool() const { return mDpy != NULL; }
226
227private:
228    egl_display_t* mDpy;
229
230    // non-assignable
231    egl_display_ptr& operator=(const egl_display_ptr&);
232};
233
234// ----------------------------------------------------------------------------
235
236inline egl_display_ptr get_display(EGLDisplay dpy) {
237    return egl_display_ptr(egl_display_t::get(dpy));
238}
239
240// Does not ensure EGL is unhibernated. Use with caution: calls into the
241// underlying EGL implementation are not safe.
242inline egl_display_t* get_display_nowake(EGLDisplay dpy) {
243    return egl_display_t::get(dpy);
244}
245
246// ----------------------------------------------------------------------------
247
248egl_display_ptr validate_display(EGLDisplay dpy);
249egl_display_ptr validate_display_connection(EGLDisplay dpy,
250        egl_connection_t*& cnx);
251EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx);
252EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface);
253
254// ----------------------------------------------------------------------------
255}; // namespace android
256// ----------------------------------------------------------------------------
257
258#endif // ANDROID_EGL_DISPLAY_H
259