/*
// 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