1b166940edca6e312463461438e2aa66e9852c26aBenoit Goby/* 2b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved. 3b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * 4b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * Not a Contribution, Apache license notifications and license are retained 5b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * for attribution purposes only. 6b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * 7b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * Licensed under the Apache License, Version 2.0 (the "License"); 8b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * you may not use this file except in compliance with the License. 9b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * You may obtain a copy of the License at 10b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * 11b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * http://www.apache.org/licenses/LICENSE-2.0 12b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * 13b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * Unless required by applicable law or agreed to in writing, software 14b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * distributed under the License is distributed on an "AS IS" BASIS, 15b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * See the License for the specific language governing permissions and 17b166940edca6e312463461438e2aa66e9852c26aBenoit Goby * limitations under the License. 18b166940edca6e312463461438e2aa66e9852c26aBenoit Goby */ 19b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 20b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#ifndef HWC_MDP_COMP 21b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#define HWC_MDP_COMP 22b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 23b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#include <hwc_utils.h> 24b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#include <idle_invalidator.h> 25b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#include <cutils/properties.h> 26b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#include <overlay.h> 27b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 28b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#define DEFAULT_IDLE_TIME 2000 29b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#define MAX_PIPES_PER_MIXER 4 30b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 31b166940edca6e312463461438e2aa66e9852c26aBenoit Gobynamespace overlay { 32b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyclass Rotator; 33b166940edca6e312463461438e2aa66e9852c26aBenoit Goby}; 34b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 35b166940edca6e312463461438e2aa66e9852c26aBenoit Gobynamespace qhwc { 36b166940edca6e312463461438e2aa66e9852c26aBenoit Gobynamespace ovutils = overlay::utils; 37b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 38b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyclass MDPComp { 39b166940edca6e312463461438e2aa66e9852c26aBenoit Gobypublic: 40b166940edca6e312463461438e2aa66e9852c26aBenoit Goby explicit MDPComp(int); 41b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MDPComp(){}; 42b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /*sets up mdp comp for the current frame */ 43b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list); 44b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* draw */ 45b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0; 46b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* dumpsys */ 47b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void dump(android::String8& buf); 48b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 49b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static MDPComp* getObject(const int& width, const int dpy); 50b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* Handler to invoke frame redraw on Idle Timer expiry */ 51b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static void timeout_handler(void *udata); 52b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* Initialize MDP comp*/ 53b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool init(hwc_context_t *ctx); 54b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static void resetIdleFallBack() { sIdleFallBack = false; } 55b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 56b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyprotected: 57b166940edca6e312463461438e2aa66e9852c26aBenoit Goby enum ePipeType { 58b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB, 59b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG, 60b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MDPCOMP_OV_DMA = ovutils::OV_MDP_PIPE_DMA, 61b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MDPCOMP_OV_ANY, 62b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 63b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 64b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* mdp pipe data */ 65b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct MdpPipeInfo { 66b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int zOrder; 67b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MdpPipeInfo(){}; 68b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 69b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 70b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* per layer data */ 71b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct PipeLayerPair { 72b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MdpPipeInfo *pipeInfo; 73b166940edca6e312463461438e2aa66e9852c26aBenoit Goby overlay::Rotator* rot; 74b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int listIndex; 75b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 76b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 77b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* per frame data */ 78b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct FrameInfo { 79b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* maps layer list to mdp list */ 80b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int layerCount; 81b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int layerToMDP[MAX_NUM_LAYERS]; 82b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 83b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* maps mdp list to layer list */ 84b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int mdpCount; 85b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct PipeLayerPair mdpToLayer[MAX_PIPES_PER_MIXER]; 86b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 87b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* layer composing on FB? */ 88b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int fbCount; 89b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isFBComposed[MAX_NUM_LAYERS]; 90b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 91b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool needsRedraw; 92b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int fbZ; 93b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 94b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* c'tor */ 95b166940edca6e312463461438e2aa66e9852c26aBenoit Goby FrameInfo(); 96b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* clear old frame data */ 97b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void reset(const int& numLayers); 98b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void map(); 99b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 100b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 101b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* cached data */ 102b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct LayerCache { 103b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int layerCount; 104b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int mdpCount; 105b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int cacheCount; 106b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int fbZ; 107b166940edca6e312463461438e2aa66e9852c26aBenoit Goby buffer_handle_t hnd[MAX_NUM_LAYERS]; 108b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 109b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* c'tor */ 110b166940edca6e312463461438e2aa66e9852c26aBenoit Goby LayerCache(); 111b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* clear caching info*/ 112b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void reset(); 113b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void cacheAll(hwc_display_contents_1_t* list); 114b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void updateCounts(const FrameInfo&); 115b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 116b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 117b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* No of pipes needed for Framebuffer */ 118b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesForFB() = 0; 119b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* calculates pipes needed for the panel */ 120b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesNeeded(hwc_context_t *ctx, 121b166940edca6e312463461438e2aa66e9852c26aBenoit Goby hwc_display_contents_1_t* list) = 0; 122b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* allocates pipe from pipe book */ 123b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool allocLayerPipes(hwc_context_t *ctx, 124b166940edca6e312463461438e2aa66e9852c26aBenoit Goby hwc_display_contents_1_t* list) = 0; 125b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* configures MPD pipes */ 126b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, 127b166940edca6e312463461438e2aa66e9852c26aBenoit Goby PipeLayerPair& pipeLayerPair) = 0; 128b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 129b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* set/reset flags for MDPComp */ 130b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void setMDPCompLayerFlags(hwc_context_t *ctx, 131b166940edca6e312463461438e2aa66e9852c26aBenoit Goby hwc_display_contents_1_t* list); 132b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* allocate MDP pipes from overlay */ 133b166940edca6e312463461438e2aa66e9852c26aBenoit Goby ovutils::eDest getMdpPipe(hwc_context_t *ctx, ePipeType type); 134b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 135b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks for conditions where mdpcomp is not possible */ 136b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isFrameDoable(hwc_context_t *ctx); 137b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks for conditions where RGB layers cannot be bypassed */ 138b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isFullFrameDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list); 139b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks if full MDP comp can be done */ 140b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); 141b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* check if we can use layer cache to do at least partial MDP comp */ 142b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); 143b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks for conditions where only video can be bypassed */ 144b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isOnlyVideoDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list); 145b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks for conditions where YUV layers cannot be bypassed */ 146b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer); 147b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 148b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* set up Border fill as Base pipe */ 149b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool setupBasePipe(hwc_context_t*); 150b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* Is debug enabled */ 151b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool isDebug() { return sDebugLogs ? true : false; }; 152b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* Is feature enabled */ 153b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool isEnabled() { return sEnabled; }; 154b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* checks for mdp comp dimension limitation */ 155b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer); 156b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* tracks non updating layers*/ 157b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list); 158b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* optimize layers for mdp comp*/ 159b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void batchLayers(); 160b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* gets available pipes for mdp comp */ 161b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int getAvailablePipes(hwc_context_t* ctx); 162b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* updates cache map with YUV info */ 163b166940edca6e312463461438e2aa66e9852c26aBenoit Goby void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list); 164b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list); 165b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list); 166b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 167b166940edca6e312463461438e2aa66e9852c26aBenoit Goby int mDpy; 168b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool sEnabled; 169b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool sDebugLogs; 170b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static bool sIdleFallBack; 171b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static int sMaxPipesPerMixer; 172b166940edca6e312463461438e2aa66e9852c26aBenoit Goby static IdleInvalidator *idleInvalidator; 173b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct FrameInfo mCurrentFrame; 174b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct LayerCache mCachedFrame; 175b166940edca6e312463461438e2aa66e9852c26aBenoit Goby}; 176b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 177b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyclass MDPCompLowRes : public MDPComp { 178b166940edca6e312463461438e2aa66e9852c26aBenoit Gobypublic: 179b166940edca6e312463461438e2aa66e9852c26aBenoit Goby explicit MDPCompLowRes(int dpy):MDPComp(dpy){}; 180b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MDPCompLowRes(){}; 181b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); 182b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 183b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyprivate: 184b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct MdpPipeInfoLowRes : public MdpPipeInfo { 185b166940edca6e312463461438e2aa66e9852c26aBenoit Goby ovutils::eDest index; 186b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MdpPipeInfoLowRes() {}; 187b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 188b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 189b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesForFB() { return 1; }; 190b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* configure's overlay pipes for the frame */ 191b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, 192b166940edca6e312463461438e2aa66e9852c26aBenoit Goby PipeLayerPair& pipeLayerPair); 193b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 194b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* allocates pipes to selected candidates */ 195b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool allocLayerPipes(hwc_context_t *ctx, 196b166940edca6e312463461438e2aa66e9852c26aBenoit Goby hwc_display_contents_1_t* list); 197b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 198b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesNeeded(hwc_context_t *ctx, hwc_display_contents_1_t* list); 199b166940edca6e312463461438e2aa66e9852c26aBenoit Goby}; 200b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 201b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyclass MDPCompHighRes : public MDPComp { 202b166940edca6e312463461438e2aa66e9852c26aBenoit Gobypublic: 203b166940edca6e312463461438e2aa66e9852c26aBenoit Goby explicit MDPCompHighRes(int dpy):MDPComp(dpy){}; 204b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MDPCompHighRes(){}; 205b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); 206b166940edca6e312463461438e2aa66e9852c26aBenoit Gobyprivate: 207b166940edca6e312463461438e2aa66e9852c26aBenoit Goby struct MdpPipeInfoHighRes : public MdpPipeInfo { 208b166940edca6e312463461438e2aa66e9852c26aBenoit Goby ovutils::eDest lIndex; 209b166940edca6e312463461438e2aa66e9852c26aBenoit Goby ovutils::eDest rIndex; 210b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual ~MdpPipeInfoHighRes() {}; 211b166940edca6e312463461438e2aa66e9852c26aBenoit Goby }; 212b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 213b166940edca6e312463461438e2aa66e9852c26aBenoit Goby bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer, 214b166940edca6e312463461438e2aa66e9852c26aBenoit Goby MdpPipeInfoHighRes& pipe_info, ePipeType type); 215b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 216b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesForFB() { return 2; }; 217b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* configure's overlay pipes for the frame */ 218b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, 219b166940edca6e312463461438e2aa66e9852c26aBenoit Goby PipeLayerPair& pipeLayerPair); 220b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 221b166940edca6e312463461438e2aa66e9852c26aBenoit Goby /* allocates pipes to selected candidates */ 222b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual bool allocLayerPipes(hwc_context_t *ctx, 223b166940edca6e312463461438e2aa66e9852c26aBenoit Goby hwc_display_contents_1_t* list); 224b166940edca6e312463461438e2aa66e9852c26aBenoit Goby 225b166940edca6e312463461438e2aa66e9852c26aBenoit Goby virtual int pipesNeeded(hwc_context_t *ctx, hwc_display_contents_1_t* list); 226b166940edca6e312463461438e2aa66e9852c26aBenoit Goby}; 227b166940edca6e312463461438e2aa66e9852c26aBenoit Goby}; //namespace 228b166940edca6e312463461438e2aa66e9852c26aBenoit Goby#endif 229