blob: 9882975b6f94320aa1235735b830eb84b201447b [file] [log] [blame]
Naseer Ahmed29a26812012-06-14 00:56:20 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
Saurabh Shah56f610d2012-08-07 15:27:06 -07003 * Copyright (C) 2012, The Linux Foundation All rights reserved.
Naseer Ahmed29a26812012-06-14 00:56:20 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Naseer Ahmed758bfc52012-11-28 17:02:08 -050018#include <sys/ioctl.h>
Naseer Ahmed5b6708a2012-08-02 13:46:08 -070019#include <EGL/egl.h>
Saurabh Shahfc2acbe2012-08-17 19:47:52 -070020#include <cutils/properties.h>
21#include <gralloc_priv.h>
22#include <fb_priv.h>
Naseer Ahmed758bfc52012-11-28 17:02:08 -050023#include <overlay.h>
Naseer Ahmed29a26812012-06-14 00:56:20 -070024#include "hwc_utils.h"
Naseer Ahmed54821fe2012-11-28 18:44:38 -050025#include "hwc_mdpcomp.h"
Saurabh Shahcf053c62012-12-13 12:32:55 -080026#include "hwc_fbupdate.h"
Naseer Ahmeda87da602012-07-01 23:54:19 -070027#include "mdp_version.h"
Saurabh Shah56f610d2012-08-07 15:27:06 -070028#include "external.h"
Saurabh Shah56f610d2012-08-07 15:27:06 -070029#include "QService.h"
Naseer Ahmed72cf9762012-07-21 12:17:13 -070030
Naseer Ahmed29a26812012-06-14 00:56:20 -070031namespace qhwc {
Naseer Ahmed72cf9762012-07-21 12:17:13 -070032
33// Opens Framebuffer device
34static void openFramebufferDevice(hwc_context_t *ctx)
35{
36 hw_module_t const *module;
37 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
38 framebuffer_open(module, &(ctx->mFbDev));
Saurabh Shah3e858eb2012-09-17 16:53:21 -070039 private_module_t* m = reinterpret_cast<private_module_t*>(
40 ctx->mFbDev->common.module);
41 //xres, yres may not be 32 aligned
Naseer Ahmed54821fe2012-11-28 18:44:38 -050042 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = m->finfo.line_length /
43 (m->info.xres/8);
Saurabh Shah3e858eb2012-09-17 16:53:21 -070044 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres;
45 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres;
46 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi;
47 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ctx->mFbDev->ydpi;
48 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
49 1000000000l / ctx->mFbDev->fps;
50 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = openFb(HWC_DISPLAY_PRIMARY);
Naseer Ahmed72cf9762012-07-21 12:17:13 -070051 }
52}
53
Naseer Ahmed29a26812012-06-14 00:56:20 -070054void initContext(hwc_context_t *ctx)
55{
Naseer Ahmed72cf9762012-07-21 12:17:13 -070056 openFramebufferDevice(ctx);
Saurabh Shahc4d034f2012-09-27 15:55:15 -070057 overlay::Overlay::initOverlay();
Naseer Ahmed758bfc52012-11-28 17:02:08 -050058 ctx->mOverlay = overlay::Overlay::getInstance();
Saurabh Shah56f610d2012-08-07 15:27:06 -070059 ctx->mQService = qService::QService::getInstance(ctx);
Naseer Ahmed96c4c952012-07-25 18:27:14 -070060 ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
61 ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
62 ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
Saurabh Shahcf053c62012-12-13 12:32:55 -080063 //Is created and destroyed only once for primary
64 //For external it could get created and destroyed multiple times depending
65 //on what external we connect to.
66 ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
67 IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
68 HWC_DISPLAY_PRIMARY);
Naseer Ahmed72cf9762012-07-21 12:17:13 -070069 ctx->mExtDisplay = new ExternalDisplay(ctx);
Naseer Ahmede78f0522012-12-07 18:24:28 -050070 for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++)
71 ctx->mLayerCache[i] = new LayerCache();
Saurabh Shahcbf7ccc2012-12-19 16:45:51 -080072 ctx->mMDPComp = MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres);
Naseer Ahmed54821fe2012-11-28 18:44:38 -050073 MDPComp::init(ctx);
Naseer Ahmed72cf9762012-07-21 12:17:13 -070074
Naseer Ahmedff4f0252012-10-01 13:03:01 -040075 pthread_mutex_init(&(ctx->vstate.lock), NULL);
76 pthread_cond_init(&(ctx->vstate.cond), NULL);
77 ctx->vstate.enable = false;
78
Naseer Ahmed72cf9762012-07-21 12:17:13 -070079 ALOGI("Initializing Qualcomm Hardware Composer");
Naseer Ahmed96c4c952012-07-25 18:27:14 -070080 ALOGI("MDP version: %d", ctx->mMDP.version);
Naseer Ahmed29a26812012-06-14 00:56:20 -070081}
82
83void closeContext(hwc_context_t *ctx)
84{
Naseer Ahmed758bfc52012-11-28 17:02:08 -050085 if(ctx->mOverlay) {
86 delete ctx->mOverlay;
87 ctx->mOverlay = NULL;
Naseer Ahmed29a26812012-06-14 00:56:20 -070088 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -070089
Naseer Ahmed72cf9762012-07-21 12:17:13 -070090 if(ctx->mFbDev) {
91 framebuffer_close(ctx->mFbDev);
92 ctx->mFbDev = NULL;
Saurabh Shah3e858eb2012-09-17 16:53:21 -070093 close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd);
94 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
Naseer Ahmed29a26812012-06-14 00:56:20 -070095 }
Naseer Ahmed72cf9762012-07-21 12:17:13 -070096
97 if(ctx->mExtDisplay) {
98 delete ctx->mExtDisplay;
99 ctx->mExtDisplay = NULL;
100 }
Naseer Ahmedff4f0252012-10-01 13:03:01 -0400101
Saurabh Shahcf053c62012-12-13 12:32:55 -0800102 for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
103 if(ctx->mFBUpdate[i]) {
104 delete ctx->mFBUpdate[i];
105 ctx->mFBUpdate[i] = NULL;
106 }
107 }
108
Saurabh Shahcbf7ccc2012-12-19 16:45:51 -0800109 if(ctx->mMDPComp) {
110 delete ctx->mMDPComp;
111 ctx->mMDPComp = NULL;
112 }
113
Naseer Ahmedff4f0252012-10-01 13:03:01 -0400114 pthread_mutex_destroy(&(ctx->vstate.lock));
115 pthread_cond_destroy(&(ctx->vstate.cond));
Naseer Ahmed29a26812012-06-14 00:56:20 -0700116}
117
Naseer Ahmed1d183f52012-11-26 12:35:16 -0500118
119void dumpsys_log(android::String8& buf, const char* fmt, ...)
Naseer Ahmed29a26812012-06-14 00:56:20 -0700120{
Naseer Ahmed1d183f52012-11-26 12:35:16 -0500121 va_list varargs;
122 va_start(varargs, fmt);
123 buf.appendFormatV(fmt, varargs);
124 va_end(varargs);
Naseer Ahmed29a26812012-06-14 00:56:20 -0700125}
126
Naseer Ahmed018e5452012-12-03 14:46:15 -0500127static inline bool isAlphaScaled(hwc_layer_1_t const* layer) {
128 int dst_w, dst_h, src_w, src_h;
129
130 hwc_rect_t displayFrame = layer->displayFrame;
131 hwc_rect_t sourceCrop = layer->sourceCrop;
132
133 dst_w = displayFrame.right - displayFrame.left;
134 dst_h = displayFrame.bottom - displayFrame.top;
135
136 src_w = sourceCrop.right - sourceCrop.left;
137 src_h = sourceCrop.bottom - sourceCrop.top;
138
139 if(((src_w != dst_w) || (src_h != dst_h))) {
140 if(layer->blending != HWC_BLENDING_NONE)
141 return true;
142 }
143 return false;
144}
145
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700146void setListStats(hwc_context_t *ctx,
147 const hwc_display_contents_1_t *list, int dpy) {
148
149 ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
150 ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
Saurabh Shahc4d034f2012-09-27 15:55:15 -0700151 ctx->listStats[dpy].yuvCount = 0;
152 ctx->listStats[dpy].yuvIndex = -1;
153 ctx->listStats[dpy].skipCount = 0;
Naseer Ahmed018e5452012-12-03 14:46:15 -0500154 ctx->listStats[dpy].needsAlphaScale = false;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700155
156 for (size_t i = 0; i < list->numHwLayers; i++) {
Naseer Ahmed018e5452012-12-03 14:46:15 -0500157 hwc_layer_1_t const* layer = &list->hwLayers[i];
158 private_handle_t *hnd = (private_handle_t *)layer->handle;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700159
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700160 if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
161 continue;
162 //We disregard FB being skip for now! so the else if
Saurabh Shah35712cb2012-09-14 10:28:18 -0700163 } else if (isSkipLayer(&list->hwLayers[i])) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700164 ctx->listStats[dpy].skipCount++;
165 }
166
Naseer Ahmed018e5452012-12-03 14:46:15 -0500167 if(!ctx->listStats[dpy].needsAlphaScale)
168 ctx->listStats[dpy].needsAlphaScale = isAlphaScaled(layer);
169
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700170 if (UNLIKELY(isYuvBuffer(hnd))) {
171 ctx->listStats[dpy].yuvCount++;
172 ctx->listStats[dpy].yuvIndex = i;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700173 }
174 }
Naseer Ahmed29a26812012-06-14 00:56:20 -0700175}
176
Naseer Ahmed018e5452012-12-03 14:46:15 -0500177
Saurabh Shah541b59d2012-10-11 11:08:12 -0700178static inline void calc_cut(float& leftCutRatio, float& topCutRatio,
179 float& rightCutRatio, float& bottomCutRatio, int orient) {
Saurabh Shah27c1d652012-08-14 19:30:28 -0700180 if(orient & HAL_TRANSFORM_FLIP_H) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700181 swap(leftCutRatio, rightCutRatio);
Saurabh Shah27c1d652012-08-14 19:30:28 -0700182 }
183 if(orient & HAL_TRANSFORM_FLIP_V) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700184 swap(topCutRatio, bottomCutRatio);
Saurabh Shah27c1d652012-08-14 19:30:28 -0700185 }
186 if(orient & HAL_TRANSFORM_ROT_90) {
187 //Anti clock swapping
Saurabh Shah541b59d2012-10-11 11:08:12 -0700188 float tmpCutRatio = leftCutRatio;
189 leftCutRatio = topCutRatio;
190 topCutRatio = rightCutRatio;
191 rightCutRatio = bottomCutRatio;
192 bottomCutRatio = tmpCutRatio;
Saurabh Shah27c1d652012-08-14 19:30:28 -0700193 }
194}
195
Naseer Ahmed54821fe2012-11-28 18:44:38 -0500196bool isSecuring(hwc_context_t* ctx) {
197 if((ctx->mMDP.version < qdutils::MDSS_V5) &&
198 (ctx->mMDP.version > qdutils::MDP_V3_0) &&
199 ctx->mSecuring) {
200 return true;
201 }
202 return false;
203}
204
205
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700206//Crops source buffer against destination and FB boundaries
207void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
Saurabh Shah27c1d652012-08-14 19:30:28 -0700208 const int fbWidth, const int fbHeight, int orient) {
209 int& crop_l = crop.left;
210 int& crop_t = crop.top;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700211 int& crop_r = crop.right;
212 int& crop_b = crop.bottom;
213 int crop_w = crop.right - crop.left;
214 int crop_h = crop.bottom - crop.top;
215
Saurabh Shah27c1d652012-08-14 19:30:28 -0700216 int& dst_l = dst.left;
217 int& dst_t = dst.top;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700218 int& dst_r = dst.right;
219 int& dst_b = dst.bottom;
Saurabh Shah27c1d652012-08-14 19:30:28 -0700220 int dst_w = abs(dst.right - dst.left);
221 int dst_h = abs(dst.bottom - dst.top);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700222
Saurabh Shah541b59d2012-10-11 11:08:12 -0700223 float leftCutRatio = 0.0f, rightCutRatio = 0.0f, topCutRatio = 0.0f,
224 bottomCutRatio = 0.0f;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700225
Saurabh Shah27c1d652012-08-14 19:30:28 -0700226 if(dst_l < 0) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700227 leftCutRatio = (float)(0.0f - dst_l) / (float)dst_w;
Saurabh Shah27c1d652012-08-14 19:30:28 -0700228 dst_l = 0;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700229 }
230 if(dst_r > fbWidth) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700231 rightCutRatio = (float)(dst_r - fbWidth) / (float)dst_w;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700232 dst_r = fbWidth;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700233 }
Saurabh Shah27c1d652012-08-14 19:30:28 -0700234 if(dst_t < 0) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700235 topCutRatio = (float)(0 - dst_t) / (float)dst_h;
Saurabh Shah27c1d652012-08-14 19:30:28 -0700236 dst_t = 0;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700237 }
238 if(dst_b > fbHeight) {
Saurabh Shah541b59d2012-10-11 11:08:12 -0700239 bottomCutRatio = (float)(dst_b - fbHeight) / (float)dst_h;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700240 dst_b = fbHeight;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700241 }
Saurabh Shah27c1d652012-08-14 19:30:28 -0700242
Saurabh Shah541b59d2012-10-11 11:08:12 -0700243 calc_cut(leftCutRatio, topCutRatio, rightCutRatio, bottomCutRatio, orient);
244 crop_l += crop_w * leftCutRatio;
245 crop_t += crop_h * topCutRatio;
246 crop_r -= crop_w * rightCutRatio;
247 crop_b -= crop_h * bottomCutRatio;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700248}
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700249
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700250bool isExternalActive(hwc_context_t* ctx) {
251 return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
Saurabh Shahfc2acbe2012-08-17 19:47:52 -0700252}
253
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700254int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700255 int ret = 0;
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700256 struct mdp_buf_sync data;
Naseer Ahmedb1c76322012-10-17 00:32:50 -0400257 int acquireFd[MAX_NUM_LAYERS];
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700258 int count = 0;
259 int releaseFd = -1;
260 int fbFd = -1;
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500261 bool swapzero = false;
Saurabh Shahc4d034f2012-09-27 15:55:15 -0700262 data.flags = MDP_BUF_SYNC_FLAG_WAIT;
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700263 data.acq_fen_fd = acquireFd;
264 data.rel_fen_fd = &releaseFd;
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500265 char property[PROPERTY_VALUE_MAX];
266 if(property_get("debug.egl.swapinterval", property, "1") > 0) {
267 if(atoi(property) == 0)
268 swapzero = true;
269 }
270
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700271 //Accumulate acquireFenceFds
272 for(uint32_t i = 0; i < list->numHwLayers; i++) {
Saurabh Shah3e858eb2012-09-17 16:53:21 -0700273 if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
274 list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
Naseer Ahmed54821fe2012-11-28 18:44:38 -0500275 list->hwLayers[i].acquireFenceFd != -1 ){
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500276 if(UNLIKELY(swapzero))
277 acquireFd[count++] = -1;
278 else
279 acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700280 }
281 }
282
Kinjal Bhavsar40a1cc52012-10-10 15:52:03 -0700283 data.acq_fen_fd_cnt = count;
284 fbFd = ctx->dpyAttr[dpy].fd;
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700285
Kinjal Bhavsar40a1cc52012-10-10 15:52:03 -0700286 //Waits for acquire fences, returns a release fence
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500287 if(LIKELY(!swapzero))
288 ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
Kinjal Bhavsar40a1cc52012-10-10 15:52:03 -0700289 if(ret < 0) {
290 ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
291 strerror(errno));
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700292 }
Kinjal Bhavsar40a1cc52012-10-10 15:52:03 -0700293
294 for(uint32_t i = 0; i < list->numHwLayers; i++) {
295 if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
296 list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET)) {
297 //Close the acquireFenceFds
298 if(list->hwLayers[i].acquireFenceFd > 0) {
299 close(list->hwLayers[i].acquireFenceFd);
300 list->hwLayers[i].acquireFenceFd = -1;
301 }
302 //Populate releaseFenceFds.
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500303 if(UNLIKELY(swapzero))
304 list->hwLayers[i].releaseFenceFd = -1;
305 else
306 list->hwLayers[i].releaseFenceFd = dup(releaseFd);
Kinjal Bhavsar40a1cc52012-10-10 15:52:03 -0700307 }
308 }
Naseer Ahmed94baddc2012-12-17 18:51:01 -0500309 if(UNLIKELY(swapzero)){
310 list->retireFenceFd = -1;
311 close(releaseFd);
312 } else {
313 list->retireFenceFd = releaseFd;
314 }
Kinjal Bhavsar2dd04a82012-09-18 18:27:59 -0700315 return ret;
316}
317
Naseer Ahmedb1c76322012-10-17 00:32:50 -0400318void LayerCache::resetLayerCache(int num) {
319 for(uint32_t i = 0; i < MAX_NUM_LAYERS; i++) {
320 hnd[i] = NULL;
321 }
322 numHwLayers = num;
323}
324
325void LayerCache::updateLayerCache(hwc_display_contents_1_t* list) {
326
327 int numFbLayers = 0;
328 int numCacheableLayers = 0;
329
330 canUseLayerCache = false;
331 //Bail if geometry changed or num of layers changed
332 if(list->flags & HWC_GEOMETRY_CHANGED ||
333 list->numHwLayers != numHwLayers ) {
334 resetLayerCache(list->numHwLayers);
335 return;
336 }
337
338 for(uint32_t i = 0; i < list->numHwLayers; i++) {
339 //Bail on skip layers
340 if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
341 resetLayerCache(list->numHwLayers);
342 return;
343 }
344
345 if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER) {
346 numFbLayers++;
347 if(hnd[i] == NULL) {
348 hnd[i] = list->hwLayers[i].handle;
349 } else if (hnd[i] ==
350 list->hwLayers[i].handle) {
351 numCacheableLayers++;
352 } else {
353 hnd[i] = NULL;
354 return;
355 }
356 } else {
357 hnd[i] = NULL;
358 }
359 }
360 if(numFbLayers == numCacheableLayers)
361 canUseLayerCache = true;
362
363 //XXX: The marking part is separate, if MDP comp wants
364 // to use it in the future. Right now getting MDP comp
365 // to use this is more trouble than it is worth.
366 markCachedLayersAsOverlay(list);
367}
368
369void LayerCache::markCachedLayersAsOverlay(hwc_display_contents_1_t* list) {
370 //This optimization only works if ALL the layer handles
371 //that were on the framebuffer didn't change.
372 if(canUseLayerCache){
373 for(uint32_t i = 0; i < list->numHwLayers; i++) {
374 if (list->hwLayers[i].handle &&
375 list->hwLayers[i].handle == hnd[i] &&
376 list->hwLayers[i].compositionType != HWC_FRAMEBUFFER_TARGET)
377 {
378 list->hwLayers[i].compositionType = HWC_OVERLAY;
379 }
380 }
381 }
382
383}
384
Naseer Ahmed29a26812012-06-14 00:56:20 -0700385};//namespace