/* // Copyright (c) 2014 Intel Corporation // // 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 <HwcTrace.h> #include <Drm.h> #include <Hwcomposer.h> #include <tangier/TngGrallocBufferMapper.h> #include <common/WsbmWrapper.h> namespace android { namespace intel { TngGrallocBufferMapper::TngGrallocBufferMapper(gralloc_module_t const& module, DataBuffer& buffer) : GrallocBufferMapperBase(buffer), mGrallocModule(module), mBufferObject(0) { CTRACE(); const native_handle_t *h = (native_handle_t *)mHandle; mClonedHandle = native_handle_create(h->numFds, h->numInts); if (mClonedHandle == 0) { ALOGE("%s:Failed to create handle, out of memory!"); return; } for (int i = 0; i < h->numFds; i++) { mClonedHandle->data[i] = (h->data[i] >= 0) ? dup(h->data[i]) : -1; } memcpy(mClonedHandle->data + h->numFds, h->data + h->numFds, h->numInts*sizeof(int)); } TngGrallocBufferMapper::~TngGrallocBufferMapper() { CTRACE(); if (mClonedHandle == 0) return; native_handle_close(mClonedHandle); native_handle_delete(mClonedHandle); } bool TngGrallocBufferMapper::gttMap(void *vaddr, uint32_t size, uint32_t gttAlign, int *offset) { struct psb_gtt_mapping_arg arg; bool ret; ATRACE("vaddr = %p, size = %d", vaddr, size); if (!vaddr || !size || !offset) { VTRACE("invalid parameters"); return false; } arg.type = PSB_GTT_MAP_TYPE_VIRTUAL; arg.page_align = gttAlign; arg.vaddr = (unsigned long)vaddr; arg.size = size; Drm *drm = Hwcomposer::getInstance().getDrm(); ret = drm->writeReadIoctl(DRM_PSB_GTT_MAP, &arg, sizeof(arg)); if (ret == false) { ETRACE("gtt mapping failed"); return false; } VTRACE("offset = %#x", arg.offset_pages); *offset = arg.offset_pages; return true; } bool TngGrallocBufferMapper::gttUnmap(void *vaddr) { struct psb_gtt_mapping_arg arg; bool ret; ATRACE("vaddr = %p", vaddr); if (!vaddr) { ETRACE("invalid parameter"); return false; } arg.type = PSB_GTT_MAP_TYPE_VIRTUAL; arg.vaddr = (unsigned long)vaddr; Drm *drm = Hwcomposer::getInstance().getDrm(); ret = drm->writeIoctl(DRM_PSB_GTT_UNMAP, &arg, sizeof(arg)); if (ret == false) { ETRACE("gtt unmapping failed"); return false; } return true; } bool TngGrallocBufferMapper::map() { void *vaddr[SUB_BUFFER_MAX]; uint32_t size[SUB_BUFFER_MAX]; int gttOffsetInPage = 0; bool ret; int err; int i; CTRACE(); // get virtual address err = mGrallocModule.perform(&mGrallocModule, GRALLOC_MODULE_GET_BUFFER_CPU_ADDRESSES_IMG, (buffer_handle_t)mClonedHandle, vaddr, size); if (err) { ETRACE("failed to map. err = %d", err); return false; } for (i = 0; i < SUB_BUFFER_MAX; i++) { // skip gtt mapping for empty sub buffers if (!vaddr[i] || !size[i]) continue; // map to gtt ret = gttMap(vaddr[i], size[i], 0, >tOffsetInPage); if (!ret) { VTRACE("failed to map %d into gtt", i); break; } mCpuAddress[i] = vaddr[i]; mSize[i] = size[i]; mGttOffsetInPage[i] = gttOffsetInPage; // TODO: set kernel handle mKHandle[i] = 0; } if (i == SUB_BUFFER_MAX) { return true; } // error handling for (i = 0; i < SUB_BUFFER_MAX; i++) { if (mCpuAddress[i]) { gttUnmap(mCpuAddress[i]); } } err = mGrallocModule.perform(&mGrallocModule, GRALLOC_MODULE_PUT_BUFFER_CPU_ADDRESSES_IMG, (buffer_handle_t)mClonedHandle); return false; } bool TngGrallocBufferMapper::unmap() { int i; int err; CTRACE(); for (i = 0; i < SUB_BUFFER_MAX; i++) { if (mCpuAddress[i]) gttUnmap(mCpuAddress[i]); mGttOffsetInPage[i] = 0; mCpuAddress[i] = 0; mSize[i] = 0; } err = mGrallocModule.perform(&mGrallocModule, GRALLOC_MODULE_PUT_BUFFER_CPU_ADDRESSES_IMG, (buffer_handle_t)mClonedHandle); if (err) { ETRACE("failed to unmap. err = %d", err); } return err; } buffer_handle_t TngGrallocBufferMapper::getKHandle(int subIndex) { buffer_handle_t ret = GrallocBufferMapperBase::getKHandle(subIndex); if (subIndex == 0 && ret == 0) { if (mapKhandle()) return mKHandle[subIndex]; } return ret; } bool TngGrallocBufferMapper::mapKhandle() { // TODO: this is a complete hack and temporary workaround // need support from DDK to map khandle void *wsbmBufferObject = 0; int ret = psbWsbmWrapTTMBuffer2((uint64_t)mHandle, &wsbmBufferObject); if (ret != 0) { ETRACE("Wrap ttm buffer failed!"); return false; } ret = psbWsbmCreateFromUB(wsbmBufferObject, mWidth * mHeight, mCpuAddress[0]); if (ret != 0) { ETRACE("Create from UB failed!"); return false; } mKHandle[0] = (buffer_handle_t)(unsigned long)psbWsbmGetKBufHandle(wsbmBufferObject); psbWsbmUnReference(wsbmBufferObject); return true; } buffer_handle_t TngGrallocBufferMapper::getFbHandle(int subIndex) { void *vaddr[SUB_BUFFER_MAX]; uint32_t size[SUB_BUFFER_MAX]; int err; CTRACE(); if (subIndex < 0 || subIndex >= SUB_BUFFER_MAX) { return 0; } // get virtual address err = mGrallocModule.perform(&mGrallocModule, GRALLOC_MODULE_GET_BUFFER_CPU_ADDRESSES_IMG, (buffer_handle_t)mClonedHandle, vaddr, size); if (err) { ETRACE("failed to map. err = %d", err); return 0; } return (buffer_handle_t)vaddr[subIndex]; } void TngGrallocBufferMapper::putFbHandle() { int err = mGrallocModule.perform(&mGrallocModule, GRALLOC_MODULE_PUT_BUFFER_CPU_ADDRESSES_IMG, (buffer_handle_t)mClonedHandle); if (err) { ETRACE("failed to unmap. err = %d", err); } return; } } // namespace intel } // namespace android