DisplayDevice.cpp revision 385977f6d6c4e76379df384d50695a10cb3757f2
1edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project/*
2edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *
4edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * you may not use this file except in compliance with the License.
6edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * You may obtain a copy of the License at
7edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *
8edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *
10edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * See the License for the specific language governing permissions and
14edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * limitations under the License.
15edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project */
16edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
17edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <stdlib.h>
18edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <stdio.h>
19edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <string.h>
20edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <math.h>
21edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
22edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <cutils/properties.h>
23edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
24076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#include <utils/RefBase.h>
25edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <utils/Log.h>
26edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
27076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#include <ui/PixelFormat.h>
280926f50664c739eaee60341f8e8c694dc9a4f3ebMathias Agopian#include <ui/FramebufferNativeWindow.h>
296cf50a770dabd13cf5b72bb0a6fb9dd002c88db6Mathias Agopian#include <ui/EGLUtils.h>
30edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
31edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <GLES/gl.h>
32076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#include <EGL/egl.h>
33edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <EGL/eglext.h>
34edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
35076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#include <pixelflinger/pixelflinger.h>
36edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
37edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include "DisplayHardware/DisplayHardware.h"
38edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
39076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#include <hardware/gralloc.h>
40edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
411f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian#include "GLExtensions.h"
42a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian#include "HWComposer.h"
43c7d14e247117392fbd44aa454622778a25c076aeMathias Agopian#include "SurfaceFlinger.h"
441f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian
45edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectusing namespace android;
46edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
47edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
48edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectstatic __attribute__((noinline))
49edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid checkGLErrors()
50edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
51cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian    do {
52cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian        // there could be more than one error flag
53cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian        GLenum error = glGetError();
54cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian        if (error == GL_NO_ERROR)
55cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian            break;
56edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        LOGE("GL error 0x%04x", int(error));
57cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian    } while(true);
58edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
59edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
60edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectstatic __attribute__((noinline))
61edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid checkEGLErrors(const char* token)
62edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
63edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    EGLint error = eglGetError();
64cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian    if (error && error != EGL_SUCCESS) {
65cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian        LOGE("%s: EGL error 0x%04x (%s)",
660928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian                token, int(error), EGLUtils::strerror(error));
67cbb288bfe89f585bf48371bd31b2d4aafa32f32eMathias Agopian    }
68edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
69edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
70edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project/*
71edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Initialize the display to the specified values.
72edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *
73edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project */
74edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
75edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source ProjectDisplayHardware::DisplayHardware(
76edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        const sp<SurfaceFlinger>& flinger,
77edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        uint32_t dpy)
781f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    : DisplayHardwareBase(flinger, dpy),
79c7d14e247117392fbd44aa454622778a25c076aeMathias Agopian      mFlinger(flinger), mFlags(0), mHwc(0)
80edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
81edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    init(dpy);
82edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
83edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
84edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source ProjectDisplayHardware::~DisplayHardware()
85edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
86edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    fini();
87edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
88edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
89edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectfloat DisplayHardware::getDpiX() const          { return mDpiX; }
90edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectfloat DisplayHardware::getDpiY() const          { return mDpiY; }
91edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectfloat DisplayHardware::getDensity() const       { return mDensity; }
92edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectfloat DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
93edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectint DisplayHardware::getWidth() const           { return mWidth; }
94edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectint DisplayHardware::getHeight() const          { return mHeight; }
95edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source ProjectPixelFormat DisplayHardware::getFormat() const  { return mFormat; }
96ca99fb8f65f3ea249c56fb6dccefffb54e87696eMathias Agopianuint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
973d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian
983d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopianuint32_t DisplayHardware::getMaxViewportDims() const {
993d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian    return mMaxViewportDims[0] < mMaxViewportDims[1] ?
1003d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian            mMaxViewportDims[0] : mMaxViewportDims[1];
1013d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian}
102edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
1036163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopianstatic status_t selectConfigForPixelFormat(
1046163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        EGLDisplay dpy,
1056163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        EGLint const* attrs,
1066163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        PixelFormat format,
1076163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        EGLConfig* outConfig)
1086163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian{
1096163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    EGLConfig config = NULL;
1106163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    EGLint numConfigs = -1, n=0;
1116163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    eglGetConfigs(dpy, NULL, 0, &numConfigs);
1126163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    EGLConfig* const configs = new EGLConfig[numConfigs];
1136163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
1146163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    for (int i=0 ; i<n ; i++) {
1156163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        EGLint nativeVisualId = 0;
1166163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
1176163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        if (nativeVisualId>0 && format == nativeVisualId) {
1186163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian            *outConfig = configs[i];
1196163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian            delete [] configs;
1206163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian            return NO_ERROR;
1216163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        }
1226163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    }
1236163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    delete [] configs;
1246163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    return NAME_NOT_FOUND;
1256163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian}
1266163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian
1276163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian
128edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::init(uint32_t dpy)
129edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
130076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian    mNativeWindow = new FramebufferNativeWindow();
1310928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
1321f339ff3875afad128a8e16ee6395c5fad295826Mathias Agopian    if (!fbDev) {
1331f339ff3875afad128a8e16ee6395c5fad295826Mathias Agopian        LOGE("Display subsystem failed to initialize. check logs. exiting...");
1341f339ff3875afad128a8e16ee6395c5fad295826Mathias Agopian        exit(0);
1351f339ff3875afad128a8e16ee6395c5fad295826Mathias Agopian    }
1361f339ff3875afad128a8e16ee6395c5fad295826Mathias Agopian
1376163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    int format;
1386163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    ANativeWindow const * const window = mNativeWindow.get();
1396163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    window->query(window, NATIVE_WINDOW_FORMAT, &format);
1401f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mDpiX = mNativeWindow->xdpi;
1411f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mDpiY = mNativeWindow->ydpi;
1421f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mRefreshRate = fbDev->fps;
143076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian
144385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian
145385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian/* FIXME: this is a temporary HACK until we are able to report the refresh rate
146385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian * properly from the HAL. The WindowManagerService now relies on this value.
147385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian */
148385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian#ifndef REFRESH_RATE
149385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian    mRefreshRate = fbDev->fps;
150385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian#else
151385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian    mRefreshRate = REFRESH_RATE;
152385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian#warning "refresh rate set via makefile to REFRESH_RATE"
153385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian#endif
154385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian
1551f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    EGLint w, h, dummy;
1561f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    EGLint numConfigs=0;
1571f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    EGLSurface surface;
1581f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    EGLContext context;
1596163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    EGLBoolean result;
1606163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    status_t err;
1611f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian
162edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    // initialize EGL
163a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian    EGLint attribs[] = {
1646163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
1656163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian            EGL_NONE,               0,
166edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project            EGL_NONE
167edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    };
168a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian
169a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian    // debug: disable h/w rendering
170a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian    char property[PROPERTY_VALUE_MAX];
171a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian    if (property_get("debug.sf.hw", property, NULL) > 0) {
172a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian        if (atoi(property) == 0) {
173a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian            LOGW("H/W composition disabled");
174a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian            attribs[2] = EGL_CONFIG_CAVEAT;
175a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian            attribs[3] = EGL_SLOW_CONFIG;
176a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian        }
177a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian    }
178a5b02e0b4dfc9947e373e17a383b397f6fcb751cMathias Agopian
179edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    // TODO: all the extensions below should be queried through
180edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    // eglGetProcAddress().
181edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
182edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
183edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglInitialize(display, NULL, NULL);
184edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglGetConfigs(display, NULL, 0, &numConfigs);
185076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian
1866163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    EGLConfig config = NULL;
1876163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    err = selectConfigForPixelFormat(display, attribs, format, &config);
1886cf50a770dabd13cf5b72bb0a6fb9dd002c88db6Mathias Agopian    LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
1896cf50a770dabd13cf5b72bb0a6fb9dd002c88db6Mathias Agopian
1900928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    EGLint r,g,b,a;
1910928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
1920928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
1930928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
1940928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian    eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
1950928e31cc7a9ec7367a68796fcaa9c52959216a5Mathias Agopian
1961e16b13857809eaa9bd17fb60ac0a471dc92844bMathias Agopian    if (mNativeWindow->isUpdateOnDemand()) {
19795a666b0e001ebf738418b89d8e8fd50b18110f8Mathias Agopian        mFlags |= PARTIAL_UPDATES;
1981e16b13857809eaa9bd17fb60ac0a471dc92844bMathias Agopian    }
1991e16b13857809eaa9bd17fb60ac0a471dc92844bMathias Agopian
200edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
201edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        if (dummy == EGL_SLOW_CONFIG)
202edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project            mFlags |= SLOW_CONFIG;
203edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    }
204edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
205edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    /*
206edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     * Create our main surface
207edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     */
208edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
209076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian    surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
2101f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
2111f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
212edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
21395a666b0e001ebf738418b89d8e8fd50b18110f8Mathias Agopian    if (mFlags & PARTIAL_UPDATES) {
21495a666b0e001ebf738418b89d8e8fd50b18110f8Mathias Agopian        // if we have partial updates, we definitely don't need to
21595a666b0e001ebf738418b89d8e8fd50b18110f8Mathias Agopian        // preserve the backbuffer, which may be costly.
2160928bee979c8fa157e13e37e52ba9ad94e935237Mathias Agopian        eglSurfaceAttrib(display, surface,
2170928bee979c8fa157e13e37e52ba9ad94e935237Mathias Agopian                EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
2180928bee979c8fa157e13e37e52ba9ad94e935237Mathias Agopian    }
2190928bee979c8fa157e13e37e52ba9ad94e935237Mathias Agopian
220edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
221edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        if (dummy == EGL_BUFFER_PRESERVED) {
222edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project            mFlags |= BUFFER_PRESERVED;
223edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project        }
224edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    }
225edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
226ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner    /* Read density from build-specific ro.sf.lcd_density property
22724e5f5290195e1c02c18730d0639efda65d64914Mathias Agopian     * except if it is overridden by qemu.sf.lcd_density.
228ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner     */
229ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner    if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
230ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner        if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
231ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner            LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
232ae71accf63add81ec3d3cd0269536c24db112cabDavid 'Digit' Turner            strcpy(property, "160");
233694e10ba8778dbb3cda9abe106f73ec0f45c8800David 'Digit' Turner        }
23431469e1069a873993ff43dec803bf5f14fad0fb5David 'Digit' Turner    } else {
23531469e1069a873993ff43dec803bf5f14fad0fb5David 'Digit' Turner        /* for the emulator case, reset the dpi values too */
23631469e1069a873993ff43dec803bf5f14fad0fb5David 'Digit' Turner        mDpiX = mDpiY = atoi(property);
237edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    }
238edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    mDensity = atoi(property) * (1.0f/160.0f);
239edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
240edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
241edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    /*
242edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     * Create our OpenGL ES context
243edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     */
244edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
24567226814e1b6d1c02079635608444e73ec658837Mathias Agopian
24667226814e1b6d1c02079635608444e73ec658837Mathias Agopian    EGLint contextAttributes[] = {
24767226814e1b6d1c02079635608444e73ec658837Mathias Agopian#ifdef EGL_IMG_context_priority
24867226814e1b6d1c02079635608444e73ec658837Mathias Agopian#ifdef HAS_CONTEXT_PRIORITY
24967226814e1b6d1c02079635608444e73ec658837Mathias Agopian#warning "using EGL_IMG_context_priority"
25067226814e1b6d1c02079635608444e73ec658837Mathias Agopian        EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
25167226814e1b6d1c02079635608444e73ec658837Mathias Agopian#endif
25267226814e1b6d1c02079635608444e73ec658837Mathias Agopian#endif
25367226814e1b6d1c02079635608444e73ec658837Mathias Agopian        EGL_NONE, EGL_NONE
25467226814e1b6d1c02079635608444e73ec658837Mathias Agopian    };
25567226814e1b6d1c02079635608444e73ec658837Mathias Agopian    context = eglCreateContext(display, config, NULL, contextAttributes);
25667226814e1b6d1c02079635608444e73ec658837Mathias Agopian
2571f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mDisplay = display;
2581f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mConfig  = config;
2591f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mSurface = surface;
2601f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mContext = context;
2611f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mFormat  = fbDev->format;
2621f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    mPageFlipCount = 0;
2631f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian
264edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    /*
265edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     * Gather OpenGL ES extensions
266edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project     */
267edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
2686163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    result = eglMakeCurrent(display, surface, surface, context);
2696163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    if (!result) {
2706163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        LOGE("Couldn't create a working GLES context. check logs. exiting...");
2716163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian        exit(0);
2726163091a2c366f8311fc3ee627dc7deb9681236eMathias Agopian    }
2731f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian
2741f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    GLExtensions& extensions(GLExtensions::getInstance());
2751f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    extensions.initWithGLStrings(
2761f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            glGetString(GL_VENDOR),
2771f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            glGetString(GL_RENDERER),
2781f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            glGetString(GL_VERSION),
2791f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            glGetString(GL_EXTENSIONS),
2801f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            eglQueryString(display, EGL_VENDOR),
2811f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            eglQueryString(display, EGL_VERSION),
2821f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            eglQueryString(display, EGL_EXTENSIONS));
283edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
284ca99fb8f65f3ea249c56fb6dccefffb54e87696eMathias Agopian    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
2853d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
286ca99fb8f65f3ea249c56fb6dccefffb54e87696eMathias Agopian
287dcaf29af10a3f100f2b8f7a08e9d4b2c656dd1a4Mathias Agopian
2881f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian#ifdef EGL_ANDROID_swap_rectangle
2891f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
2901f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian        if (eglSetSwapRectangleANDROID(display, surface,
2911f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian                0, 0, mWidth, mHeight) == EGL_TRUE) {
2921f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            // This could fail if this extension is not supported by this
2931f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            // specific surface (of config)
2941f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian            mFlags |= SWAP_RECTANGLE;
2951f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian        }
296e049a957ce2a529564a1312dca60e86d0bcb0964Andreas Huber    }
2971f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
2981f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    // choose PARTIAL_UPDATES, which should be more efficient
2991f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    if (mFlags & PARTIAL_UPDATES)
3001f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian        mFlags &= ~SWAP_RECTANGLE;
30154ba51dff21de666c5ae3bf3abd4f0634ebb0676Mathias Agopian#endif
302edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
3031f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("EGL informations:");
3041f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("# of configs : %d", numConfigs);
3051f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("vendor    : %s", extensions.getEglVendor());
3061f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("version   : %s", extensions.getEglVersion());
3071f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("extensions: %s", extensions.getEglExtension());
3081f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
3091f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
3101f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian
3111f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("OpenGL informations:");
3121f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("vendor    : %s", extensions.getVendor());
3131f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("renderer  : %s", extensions.getRenderer());
3141f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("version   : %s", extensions.getVersion());
3151f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("extensions: %s", extensions.getExtension());
3161f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
3173d64e738b91b2a4a9d81fae1991e6f6eae9ac8c8Mathias Agopian    LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
3181f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian    LOGI("flags = %08x", mFlags);
319ca99fb8f65f3ea249c56fb6dccefffb54e87696eMathias Agopian
320edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    // Unbind the context from this thread
321edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
322a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian
323a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian
324a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    // initialize the H/W composer
325c7d14e247117392fbd44aa454622778a25c076aeMathias Agopian    mHwc = new HWComposer(mFlinger);
326a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    if (mHwc->initCheck() == NO_ERROR) {
327a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian        mHwc->setFrameBuffer(mDisplay, mSurface);
328a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    }
329a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian}
330a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian
331a350ff98692b3a50cad5cc93f9f83221242ca86aMathias AgopianHWComposer& DisplayHardware::getHwComposer() const {
332a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    return *mHwc;
333edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
334edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
335edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project/*
336edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Clean up.  Throw out our local state.
337edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project *
338edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * (It's entirely possible we'll never get here, since this is meant
339edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * for real hardware, which doesn't restart.)
340edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project */
341edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
342edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::fini()
343edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
344edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
345edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglTerminate(mDisplay);
346edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
347edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
348edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::releaseScreen() const
349edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
350edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    DisplayHardwareBase::releaseScreen();
351f5f2712854599b4970643c6000fe6ae950a08ba9Antti Hatala    if (mHwc->initCheck() == NO_ERROR) {
352f5f2712854599b4970643c6000fe6ae950a08ba9Antti Hatala        mHwc->release();
353f5f2712854599b4970643c6000fe6ae950a08ba9Antti Hatala    }
354edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
355edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
356edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::acquireScreen() const
357edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
358edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    DisplayHardwareBase::acquireScreen();
359edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
360edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
361edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectuint32_t DisplayHardware::getPageFlipCount() const {
362076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian    return mPageFlipCount;
363edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
364edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
36574faca212e2675aa55a30235c77cb6403471a4b9Mathias Agopianstatus_t DisplayHardware::compositionComplete() const {
36674faca212e2675aa55a30235c77cb6403471a4b9Mathias Agopian    return mNativeWindow->compositionComplete();
36774faca212e2675aa55a30235c77cb6403471a4b9Mathias Agopian}
368edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
36935b48d10bc9e064201d3d54d2d476314684a7a05Mathias Agopianint DisplayHardware::getCurrentBufferIndex() const {
37035b48d10bc9e064201d3d54d2d476314684a7a05Mathias Agopian    return mNativeWindow->getCurrentBufferIndex();
37135b48d10bc9e064201d3d54d2d476314684a7a05Mathias Agopian}
37235b48d10bc9e064201d3d54d2d476314684a7a05Mathias Agopian
373edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::flip(const Region& dirty) const
374edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
375edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    checkGLErrors();
376edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
377edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    EGLDisplay dpy = mDisplay;
378edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    EGLSurface surface = mSurface;
379edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
3805e78e0965169790111f01354e78b0f8d34c94840Mathias Agopian#ifdef EGL_ANDROID_swap_rectangle
381df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian    if (mFlags & SWAP_RECTANGLE) {
382b8a5560e1303cb10f5cd482af466fc04d2bdfcabMathias Agopian        const Region newDirty(dirty.intersect(bounds()));
383b8a5560e1303cb10f5cd482af466fc04d2bdfcabMathias Agopian        const Rect b(newDirty.getBounds());
384df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian        eglSetSwapRectangleANDROID(dpy, surface,
385df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian                b.left, b.top, b.width(), b.height());
386edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    }
3875e78e0965169790111f01354e78b0f8d34c94840Mathias Agopian#endif
3885e78e0965169790111f01354e78b0f8d34c94840Mathias Agopian
38995a666b0e001ebf738418b89d8e8fd50b18110f8Mathias Agopian    if (mFlags & PARTIAL_UPDATES) {
39029d06ac9a45e564b4f935b91067fc92c2d4c193dMathias Agopian        mNativeWindow->setUpdateRectangle(dirty.getBounds());
3911e16b13857809eaa9bd17fb60ac0a471dc92844bMathias Agopian    }
3921e16b13857809eaa9bd17fb60ac0a471dc92844bMathias Agopian
393076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian    mPageFlipCount++;
394a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian
395a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    if (mHwc->initCheck() == NO_ERROR) {
396a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian        mHwc->commit();
397a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    } else {
398a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian        eglSwapBuffers(dpy, surface);
399a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian    }
400edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    checkEGLErrors("eglSwapBuffers");
401edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
402edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    // for debugging
403edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    //glClearColor(1,0,0,0);
404edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    //glClear(GL_COLOR_BUFFER_BIT);
405edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
406edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
407edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectuint32_t DisplayHardware::getFlags() const
408edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
409edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    return mFlags;
410edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
411edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project
412edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectvoid DisplayHardware::makeCurrent() const
413edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{
414edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
415edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project}
4161d21a9cafc534c34a2f28c985c4c7aa176d0e67bErik Gilling
4171d21a9cafc534c34a2f28c985c4c7aa176d0e67bErik Gillingvoid DisplayHardware::dump(String8& res) const
4181d21a9cafc534c34a2f28c985c4c7aa176d0e67bErik Gilling{
4191d21a9cafc534c34a2f28c985c4c7aa176d0e67bErik Gilling    mNativeWindow->dump(res);
4201d21a9cafc534c34a2f28c985c4c7aa176d0e67bErik Gilling}
421