/* * Copyright (C) Allwinner Tech All Rights Reserved * * 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 #include #include #include #include #include #include #include #include #include #include #include "../hwc.h" #include "sunxi_tr.h" /* sync with submit thread ,may need 2 (waite sync afrer sbumit), * may 3(wait sync befor submit) */ typedef struct { unsigned long clienId; int timeout; int trErrCnt; }tr_per_disp_t; static int trfd = -1; static int sw_sync_fd = -1; static unsigned sw_sync_count = 0; static unsigned inc_count = 0; static int trCacheCnt = 0; int trBitMap; tr_per_disp_t *tr_disp; static pthread_mutex_t trCacheMutex; char thread_name[32]; int priority; static pthread_t thread_id; static struct listnode SubmitHead; static Mutex *rotate_mutex; static Condition *rotate_cond; typedef struct rotate_info { struct listnode node; int waite_fence; int dst_waite_fence; unsigned int syncCount; unsigned int gsyncCount; Layer_t *layer2; Display_t *disp; }rotate_info_t; #define TR_CACHE_SHRINK_NUM 16 static struct listnode rcacheList; static int rcache_cout; static pthread_mutex_t rchaceMutex; #ifndef USE_IOMMU bool mustconfig = 1; #else bool mustconfig = 0; #endif rotate_info_t* trlistCacheGet(void) { rotate_info_t *tr_info = NULL; struct listnode *node = NULL; pthread_mutex_lock(&rchaceMutex); if (rcache_cout > 0) { rcache_cout--; node = list_head(&rcacheList); list_remove(node); list_init(node); tr_info = node_to_item(node, rotate_info_t, node); } pthread_mutex_unlock(&rchaceMutex); if (tr_info != NULL) goto deal; tr_info = (rotate_info_t *)hwc_malloc(sizeof(rotate_info_t)); if (tr_info == NULL){ ALOGE("%s:malloc tr_info err...",__FUNCTION__); return NULL; } deal: memset(tr_info, 0, sizeof(tr_info)); tr_info->dst_waite_fence = -1; tr_info->waite_fence = -1; tr_info->layer2 = NULL; list_init(&tr_info->node); return tr_info; } void trlistCachePut(rotate_info_t *tr_info) { if (tr_info->waite_fence >= 0) { close(tr_info->waite_fence); tr_info->waite_fence = -1;; } if (tr_info->dst_waite_fence >= 0) { close(tr_info->dst_waite_fence); tr_info->dst_waite_fence = -1; } list_remove(&tr_info->node); list_init(&tr_info->node); tr_info->layer2 = NULL; pthread_mutex_lock(&rchaceMutex); if (rcache_cout > TR_CACHE_SHRINK_NUM) { hwc_free(tr_info); pthread_mutex_unlock(&rchaceMutex); return; } rcache_cout++; list_add_tail(&rcacheList, &tr_info->node); pthread_mutex_unlock(&rchaceMutex); } void* rotateThreadLoop(void *list); static inline int trFormatToHal(unsigned char tr) { switch(tr) { case TR_FORMAT_YUV420_SP_VUVU: return HAL_PIXEL_FORMAT_YCrCb_420_SP; case TR_FORMAT_YUV420_P: return HAL_PIXEL_FORMAT_YV12; case TR_FORMAT_YUV420_SP_UVUV: return HAL_PIXEL_FORMAT_AW_NV12; case TR_FORMAT_ABGR_8888: return HAL_PIXEL_FORMAT_RGBA_8888; case TR_FORMAT_XBGR_8888: return HAL_PIXEL_FORMAT_RGBX_8888; case TR_FORMAT_ARGB_8888: return HAL_PIXEL_FORMAT_BGRA_8888; case TR_FORMAT_XRGB_8888: return HAL_PIXEL_FORMAT_BGRX_8888; case TR_FORMAT_BGR_888: return HAL_PIXEL_FORMAT_RGB_888; case TR_FORMAT_BGR_565: return DISP_FORMAT_RGB_565; default : return TR_FORMAT_YUV420_P; } } static inline tr_pixel_format halToTRFormat(int halFformat) { switch(halFformat) { case HAL_PIXEL_FORMAT_YCrCb_420_SP: return TR_FORMAT_YUV420_SP_VUVU; case HAL_PIXEL_FORMAT_YV12: return TR_FORMAT_YUV420_P; case HAL_PIXEL_FORMAT_AW_NV12: return TR_FORMAT_YUV420_SP_UVUV; case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_BGRX_8888: return TR_FORMAT_ARGB_8888; case HAL_PIXEL_FORMAT_RGB_888: return TR_FORMAT_RGB_888; case HAL_PIXEL_FORMAT_RGB_565: return TR_FORMAT_RGB_565; default : return TR_FORMAT_YUV420_P; } } int hwc_rotate_query(unsigned long tr_handle) { unsigned long arg[4] = {0}; int ret = -1; arg[0] = tr_handle; ret = ioctl(trfd, TR_QUERY, (unsigned long)arg); return ret; } bool hwc_rotate_request(unsigned long *clinet) { unsigned long arg[4] = {0}; int ret; arg[0] = (unsigned long)clinet; ret = ioctl(trfd, TR_REQUEST, (unsigned long)&arg); if(ret < 0) { ALOGE("request ratate module err"); return 0; } return 1; } bool hwc_rotate_commit(unsigned long client, tr_info *tr_info) { unsigned long arg[4] = {0}; int ret = -1; arg[0] = client; arg[1] = (unsigned long)tr_info; ret = ioctl(trfd, TR_COMMIT, (unsigned long)arg); if (ret < 0) { ALOGE("commit rotate err"); return 0; } return !ret; } void hwc_rotate_release(unsigned long client) { unsigned long arg[4] = {0}; int ret = -1; arg[0] = client; ret = ioctl(trfd, TR_RELEASE, (unsigned long)arg); if (ret < 0) { ALOGD("release rotate err"); } } bool hwc_rotate_settimeout(unsigned long client, unsigned long ms_time) { unsigned long arg[4] = {0}; int ret = -1; arg[0] = client; arg[1] = ms_time; ret = ioctl(trfd, TR_SET_TIMEOUT, (unsigned long)arg); return !ret; } int rotateDeviceInit(void) { trfd = open("/dev/transform", O_RDWR); if (trfd < 0) { ALOGE("Failed to open transform device"); return -1; } tr_disp = (tr_per_disp_t *)hwc_malloc(sizeof(tr_per_disp_t)); if(tr_disp == NULL) { close(trfd); trfd = -1; ALOGE("Failed to alloc client for hwc"); return -1; } sw_sync_fd = sw_sync_timeline_create(); if (sw_sync_fd < 0) { close(trfd); trfd = -1; hwc_free(tr_disp); tr_disp = NULL; ALOGE("Failed to init sy_sync for hwc"); return -1; } rotate_mutex = new Mutex(); rotate_cond = new Condition(); pthread_mutex_init(&rchaceMutex, 0); list_init(&rcacheList); rcache_cout = 0; list_init(&SubmitHead); pthread_create(&thread_id, NULL, rotateThreadLoop, &SubmitHead); pthread_mutex_init(&trCacheMutex, 0); return 0; } int rotateDeviceDeInit(int num) { if(trfd < 0) { return 0; } while(num--) { if(tr_disp->clienId != 0) hwc_rotate_release(tr_disp->clienId); } pthread_join(thread_id, NULL); delete(rotate_mutex); delete(rotate_cond); close(sw_sync_fd); close(trfd); trfd = -1; hwc_free(tr_disp); tr_disp = NULL; return 0; } static inline tr_mode toTrMode(unsigned int mode) { tr_mode ret = TR_ROT_0; switch(mode) { case HAL_TRANSFORM_FLIP_H: ret = TR_HFLIP; break; case HAL_TRANSFORM_FLIP_V: ret = TR_VFLIP; break; case HAL_TRANSFORM_ROT_90: ret = TR_ROT_90; break; case HAL_TRANSFORM_ROT_180: ret = TR_ROT_180; break; case HAL_TRANSFORM_ROT_270: ret = TR_ROT_270; break; case (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90): ret = TR_VFLIP_ROT_90; break; case (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90): ret = TR_HFLIP_ROT_90; break; default: ret = TR_ROT_0; } return ret; } int culateTimeout(Layer_t *layer) { private_handle_t *handle; handle = (private_handle_t *)layer->buffer; unsigned int dst = handle->width * handle->height; if (dst > 2073600) { return 100; } if (dst > 1024000) { return 50; } return 32; } void trCachePut(Layer_t *layer) { tr_cache_Array *cache; cache = (tr_cache_Array *)layer->trcache; if (cache == NULL) return; pthread_mutex_lock(&trCacheMutex); cache->ref--; if (cache->ref > 0) { pthread_mutex_unlock(&trCacheMutex); return ; } pthread_mutex_unlock(&trCacheMutex); for (int i = 0; i < NOMORL_CACHE_N; i++) { close(cache->array[i].share_fd); if(cache->array[i].releasefd >=0) close(cache->array[i].releasefd); } hwc_free(cache); layer->trcache = NULL; } void* trCacheGet(Layer_t *layer) { tr_cache_Array *cache; cache = (tr_cache_Array *)layer->trcache; if (cache == NULL) return NULL; cache->ref++; return (void*)cache; } tr_cache_t* acquireLastValid(Layer_t *layer) { tr_cache_Array *aCache = (tr_cache_Array *)layer->trcache; int i = 0; tr_cache_t *ccache = NULL; unsigned int last = 0; for (i = 0; i < NOMORL_CACHE_N; i++) { if (aCache->array[i].sync_cnt > last && aCache->array[i].valid) { ccache = &aCache->array[i]; last = aCache->array[i].sync_cnt; } } return ccache; } tr_cache_t* dequeueTrBuffer(Layer_t *layer, rotate_info_t *rt_info) { tr_cache_t *ccache = NULL; tr_cache_Array *aCache = (tr_cache_Array *)layer->trcache; int i; unsigned int little = rt_info->gsyncCount; ccache = &aCache->array[rt_info->gsyncCount%NOMORL_CACHE_N]; /* if (ccache->sync_cnt + NOMORL_CACHE_N >= syncCount) { no think roll 828 days will roll.... for (i = 0; i < NOMORL_CACHE_N; i++) { if (aCache->array[i].sync_cnt < little) { ccache = &aCache->array[i]; little = aCache->array[i].sync_cnt; } } } */ if (ccache->releasefd >= 0) { if (sync_wait((int)ccache->releasefd, 3000)) { ALOGE("dequeueTrBuffer waite aquire fence err %d current:%u disp:%u", ccache->releasefd, rt_info->gsyncCount,rt_info->disp->commitThread->diplayCount); /* dump fence */ } close(ccache->releasefd); ccache->releasefd = -1; } return ccache; } void* dequeueTrCache(Layer_t *layer) { private_handle_t *handle; handle = (private_handle_t *)layer->buffer; tr_cache_Array *aCache = NULL, *yuCache = NULL; int size, i, allin; size = HWC_ALIGN(handle->width, ROTATE_ALIGN) * HWC_ALIGN(handle->height, ROTATE_ALIGN) * getBitsPerPixel(layer) / 8; size = HWC_ALIGN(size, 4096); if (layer->trcache != NULL) { yuCache =(tr_cache_Array *) layer->trcache; if (yuCache->size >= size) return layer->trcache; trCachePut(layer); } aCache = (tr_cache_Array *)hwc_malloc(sizeof(tr_cache_Array)); if (aCache == NULL) { ALOGE("malloc cache array err"); return NULL; } ALOGV("layer:%p: %p:size:%d x %d size:%d",layer, aCache,handle->width, handle->height, size); memset(aCache, 0, sizeof(tr_cache_Array)); for (i= 0; i < NOMORL_CACHE_N; i++) { aCache->array[i].share_fd= ionAllocBuffer(size, mustconfig, layerIsProtected(layer)); if (aCache->array[i].share_fd < 0) goto err; aCache->array[i].sync_cnt = -NOMORL_CACHE_N; aCache->array[i].releasefd = -1; } aCache->ref = 1; aCache->size = size; return (void *)aCache; err: for (i= 0; i < NOMORL_CACHE_N; i++) { if(aCache->array[i].share_fd >= 0) close(aCache->array[i].share_fd); } hwc_free(aCache); ALOGE("dequeueTrCache err for ion err"); return NULL; } void trResetErr(void) { if (trfd < 0) return; tr_disp->trErrCnt = 0; } bool trHarewareRistrict(Layer_t *layer) { private_handle_t *handle; handle = (private_handle_t *)layer->buffer; int stride0; if (handle == NULL) return false; /* just for yuv stride*/ if (((long long)handle->width) * handle->height > 1100 * 1950) return false; stride0 = HWC_ALIGN(handle->width, handle->aw_byte_align[0]); switch(handle->format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_BGRX_8888: stride0 = HWC_ALIGN(handle->width * 4, handle->aw_byte_align[0]); if (stride0 % 4) return false; break; case HAL_PIXEL_FORMAT_RGB_565: stride0 = HWC_ALIGN(handle->width * 2, handle->aw_byte_align[0]); if (stride0 % 2) return false; break; case HAL_PIXEL_FORMAT_YV12: //if (stride0%4) return false; break; case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_AW_NV12: //if (stride0%2) return false; break; case HAL_PIXEL_FORMAT_RGB_888: stride0 = HWC_ALIGN(handle->width * 3, handle->aw_byte_align[0]); /* display use info->fb.crop.x and x is pixel , * so if rotate, but the blank is the begin, * but not pixel's allign, */ if (stride0%3) return false; break; default: return false; } return true; } bool supportTR(Display_t *display, Layer_t *layer) { if (trfd < 0) return false; if (tr_disp->trErrCnt > 3) { ALOGV("display:%d rotate has 3 contig err", display->displayId); return false; } if (!trHarewareRistrict(layer)) return false; layer->trcache = dequeueTrCache(layer); return layer->trcache != NULL; } bool layerToTrinfo(Layer_t *layer, tr_info *tr_inf, tr_cache_t *bCache) { private_handle_t *handle; handle = (private_handle_t *)layer->buffer; int i = 0; int cnt = getPlanFormat(layer); memset(tr_inf, 0, sizeof(tr_info)); tr_inf->src_frame.fmt = halToTRFormat(handle->format); unsigned int w_stride, h_stride; unsigned long addr = 0; tr_inf->mode = toTrMode(layer->transform); int wScale[3] = { 1,2,2}; int hScale[3] = {1,2,2}; int bpp[3] = { 4, 2, 1}; addr = ionGetPhyAddress(handle->share_fd); if (addr == 0 && mustconfig) { ALOGD("%p: %d get ion addr err....",handle, handle->share_fd); return 0; } switch(handle->format) { case HAL_PIXEL_FORMAT_YV12: bpp[1] = 1; bpp[0] = 1; break; case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_AW_NV12: bpp[1] = 2; bpp[0] = 1; break; case HAL_PIXEL_FORMAT_RGB_888: bpp[0] = 3; default: ALOGV("RGB"); } i = 0; while (i < cnt) { tr_inf->src_frame.haddr[i] = 0; tr_inf->src_frame.laddr[i] = addr; /* rotate is piexl cal * pitch[0] = info->src_frame.pitch[0] * ycnt; * pitch[1] = info->src_frame.pitch[1] * ucnt; * pitch[2] = info->src_frame.pitch[2] * ucnt; */ tr_inf->src_frame.pitch[i] = HWC_ALIGN(handle->width * bpp[i] / wScale[i], handle->aw_byte_align[i]) / bpp[i]; tr_inf->src_frame.height[i] = handle->height/hScale[i]; addr += tr_inf->src_frame.pitch[i] * bpp[i] * tr_inf->src_frame.height[i]; i++; } if (cnt == 3) {//YV12 tr_inf->src_frame.laddr[2] = tr_inf->src_frame.laddr[0] + tr_inf->src_frame.pitch[0] * tr_inf->src_frame.height[0]; tr_inf->src_frame.laddr[1] = tr_inf->src_frame.laddr[2] + tr_inf->src_frame.pitch[2] * tr_inf->src_frame.height[2]; } tr_inf->src_frame.fd = -1; /* tr_inf->src_frame.fd = handle->share_fd;*/ tr_inf->src_rect.x = 0; tr_inf->src_rect.y = 0; tr_inf->src_rect.w = HWC_ALIGN(handle->width * bpp[0], handle->aw_byte_align[0])/ bpp[0]; tr_inf->src_rect.h = handle->height; addr = ionGetPhyAddress(bCache->share_fd); if (addr == 0 && mustconfig) { ALOGD("get ion addr err...."); return 0; } tr_inf->dst_frame.fmt = halToTRFormat(handle->format); if (cnt != 1) { /* yuv only support TR_FORMAT_YUV420_P output*/ tr_inf->dst_frame.fmt = TR_FORMAT_YUV420_P; } tr_inf->dst_rect.x = 0; tr_inf->dst_rect.y = 0; if (layer->transform & HAL_TRANSFORM_ROT_90) { w_stride =handle->height; h_stride = handle->width; } else { w_stride = handle->width; h_stride = handle->height; } w_stride = HWC_ALIGN(w_stride * bpp[0], ROTATE_ALIGN) / bpp[0]; h_stride = HWC_ALIGN(h_stride * bpp[0], ROTATE_ALIGN) / bpp[0]; tr_inf->dst_frame.pitch[0] = w_stride; tr_inf->dst_frame.height[0] = h_stride; if (cnt != 1) { tr_inf->dst_frame.pitch[1] = w_stride/2; tr_inf->dst_frame.height[1] = h_stride/2; tr_inf->dst_frame.pitch[2] = w_stride/2; tr_inf->dst_frame.height[2] = h_stride/2; } tr_inf->dst_rect.w = w_stride; tr_inf->dst_rect.h = h_stride; tr_inf->dst_frame.haddr[0] = 0; tr_inf->dst_frame.haddr[1] = 0; tr_inf->dst_frame.haddr[2] = 0; tr_inf->dst_frame.laddr[0] = addr; /*YUV format we only support YV12 --> TR_FORMAT_YUV420_P*/ /*tr_info->dst_frame.laddr[0] --> Y*/ /*tr_info->dst_frame.laddr[1] --> U*/ /*tr_info->dst_frame.laddr[2] --> V*/ if (cnt != 1) { tr_inf->dst_frame.laddr[2] = tr_inf->dst_frame.laddr[0] + tr_inf->dst_frame.pitch[0] * tr_inf->dst_frame.height[0]; tr_inf->dst_frame.laddr[1] = tr_inf->dst_frame.laddr[2] + tr_inf->dst_frame.pitch[2] * tr_inf->dst_frame.height[2]; } /* tr_inf->dst_frame.fd = bCache->share_fd; */ tr_inf->dst_frame.fd = -1; return 1; } int trAflterDeal(Layer_t *layer, tr_cache_t *bCache, tr_info *trInfo) { private_handle_t *handle; handle = (private_handle_t *)layer->buffer; close(handle->share_fd); handle->share_fd = dup(bCache->share_fd); handle->aw_byte_align[0] = ROTATE_ALIGN; handle->aw_byte_align[1] = ROTATE_ALIGN / 2; handle->aw_byte_align[2] = ROTATE_ALIGN / 2; if (trInfo->dst_frame.fmt == TR_FORMAT_YUV420_P) handle->format = HAL_PIXEL_FORMAT_YV12; return 0; } int submitTransformLayer(rotate_info_t *rt_info, unsigned int syncCount) { ATRACE_CALL(); Layer_t *layer; private_handle_t *handle; layer = rt_info->layer2; handle = (private_handle_t *)layer->buffer; tr_cache_t *bCache = NULL; tr_info trInfo; int timeout = 0, ret = -1, i = 0; bool last = 1; /* if 2 screen use the same tr layer, we must reduce this case */ if (tr_disp->clienId == 0) { if(!hwc_rotate_request(&tr_disp->clienId)) { tr_disp->trErrCnt = 99; return -1; } } /* maybe crach for aCache== NULL, but amost impossible ,so no care*/ bCache = dequeueTrBuffer(layer, rt_info); if (!layerToTrinfo(layer, &trInfo, bCache)) { goto last; } timeout = culateTimeout(layer); if (tr_disp->timeout != timeout) { hwc_rotate_settimeout(tr_disp->clienId, timeout); tr_disp->timeout = timeout; } //ALOGD("before rotate:%u %d x %d ",syncCount,handle->width, handle->height); if (!hwc_rotate_commit(tr_disp->clienId, &trInfo)) { bCache->valid = 0; tr_disp->trErrCnt++; } i = (timeout * 1000/16);//video 30 fps while (ret != 0 && i > 0) { ret = hwc_rotate_query(tr_disp->clienId); if (ret == -1) { break; } usleep(16); i--; } if (i <= 0 || ret == -1) { ALOGD("rotate timeout or err:%d %d ", i, ret); tr_disp->trErrCnt++; bCache->valid = 0; goto last; } bCache->valid = 1; last = 0; bCache->sync_cnt = syncCount; bCache->releasefd = dup(rt_info->dst_waite_fence); tr_disp->trErrCnt = 0;; last: //ALOGD("after rotate:%u ",syncCount); if (last) bCache = acquireLastValid(layer); if (!bCache) { tr_disp->trErrCnt = 4; /* here will screen display err */ return -1; } trAflterDeal(layer, bCache, &trInfo); return 0; } int get_rotate_fence_fd(Layer_t *layer2, Display_t *disp, int releasefence, unsigned int syncCount) { char name[20]; int count; int fence_fd = -1; rotate_info_t *tr_info; tr_info = trlistCacheGet(); if (tr_info == NULL) return -1; count = sprintf(name, "tr_fence_%u\n", sw_sync_count); name[count+1] ='0'; tr_info->syncCount = ++sw_sync_count; fence_fd = sw_sync_fence_create(sw_sync_fd, name, tr_info->syncCount); tr_info->waite_fence = layer2->acquireFence; layer2->acquireFence = dup(fence_fd); tr_info->layer2 = layer2; tr_info->dst_waite_fence = dup(releasefence); tr_info->gsyncCount = syncCount; tr_info->disp = disp; layer2->ref++; if (inc_count + 2 < tr_info->syncCount) ALOGV("hw rotate so slowly:%u %u", tr_info->syncCount, inc_count); rotate_mutex->lock(); list_add_tail(&SubmitHead, &tr_info->node); rotate_cond->signal(); rotate_mutex->unlock(); return fence_fd; } void deal_rotate_fence(rotate_info_t *tr_info) { inc_count++; if (inc_count != tr_info->syncCount) ALOGD("some wrong about rotate fence:%d %d...", inc_count, tr_info->syncCount); sw_sync_timeline_inc(sw_sync_fd, 1); } void* rotateThreadLoop(void *list) { struct listnode comHead, *commitHead, *node, *node2, *node3, *rotate_list; rotate_info_t *tr_info; rotate_list = (struct listnode*)list; commitHead = &comHead; list_init(commitHead); ALOGD("new a rotate thread to commit the display"); setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); while(1) { rotate_mutex->lock(); if (list_empty(rotate_list)) rotate_cond->wait(*rotate_mutex); commitHead->next = rotate_list->next; rotate_list->next->prev = commitHead; commitHead->prev = rotate_list->prev; rotate_list->prev->next = commitHead; list_init(rotate_list); rotate_mutex->unlock(); list_for_each_safe(node, node2, commitHead) { tr_info = node_to_item(node, rotate_info_t, node); if (tr_info->waite_fence >= 0) { if (sync_wait((int)tr_info->waite_fence, 3000)) { ALOGE("rotateThreadLoop waite aquire fence err %d", tr_info->waite_fence); /* dump fence */ } } submitTransformLayer(tr_info, tr_info->gsyncCount); deal_rotate_fence(tr_info); layerCachePut(tr_info->layer2); trlistCachePut(tr_info); } list_init(commitHead); } }