| /* |
| // 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 <Hwcomposer.h> |
| #include <Drm.h> |
| #include <DisplayPlane.h> |
| #include <IDisplayDevice.h> |
| #include <HwcLayerList.h> |
| #include <tangier/TngDisplayContext.h> |
| |
| |
| namespace android { |
| namespace intel { |
| |
| TngDisplayContext::TngDisplayContext() |
| : mIMGDisplayDevice(0), |
| mInitialized(false), |
| mCount(0) |
| { |
| CTRACE(); |
| } |
| |
| TngDisplayContext::~TngDisplayContext() |
| { |
| WARN_IF_NOT_DEINIT(); |
| } |
| |
| bool TngDisplayContext::initialize() |
| { |
| CTRACE(); |
| |
| // open frame buffer device |
| gralloc_module_t const* module; |
| int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (hw_module_t const**)&module); |
| if (err) { |
| ETRACE("failed to load gralloc module, error = %d", err); |
| return false; |
| } |
| |
| // init IMG display device |
| err = module->perform(module, GRALLOC_MODULE_GET_DISPLAY_DEVICE_IMG, (void **)&mIMGDisplayDevice); |
| if (err) { |
| ETRACE("failed to get display device, error = %d", err); |
| return false; |
| } |
| |
| mCount = 0; |
| mInitialized = true; |
| return true; |
| } |
| |
| bool TngDisplayContext::commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays) |
| { |
| RETURN_FALSE_IF_NOT_INIT(); |
| mCount = 0; |
| return true; |
| } |
| |
| bool TngDisplayContext::commitContents(hwc_display_contents_1_t *display, HwcLayerList *layerList) |
| { |
| bool ret; |
| |
| RETURN_FALSE_IF_NOT_INIT(); |
| |
| if (!display || !layerList) { |
| ETRACE("invalid parameters"); |
| return false; |
| } |
| |
| IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers; |
| |
| for (size_t i = 0; i < display->numHwLayers; i++) { |
| if (mCount >= MAXIMUM_LAYER_NUMBER) { |
| ETRACE("layer count exceeds the limit"); |
| return false; |
| } |
| |
| // check layer parameters |
| if (!display->hwLayers[i].handle) { |
| continue; |
| } |
| |
| DisplayPlane* plane = layerList->getPlane(i); |
| if (!plane) { |
| continue; |
| } |
| |
| ret = plane->flip(NULL); |
| if (ret == false) { |
| VTRACE("failed to flip plane %d", i); |
| continue; |
| } |
| |
| IMG_hwc_layer_t *imgLayer = &imgLayerList[mCount++]; |
| // update IMG layer |
| imgLayer->psLayer = &display->hwLayers[i]; |
| imgLayer->custom = (unsigned long)plane->getContext(); |
| struct intel_dc_plane_ctx *ctx = |
| (struct intel_dc_plane_ctx *)imgLayer->custom; |
| // update z order |
| Hwcomposer& hwc = Hwcomposer::getInstance(); |
| DisplayPlaneManager *pm = hwc.getPlaneManager(); |
| void *config = pm->getZOrderConfig(); |
| if (config) { |
| memcpy(&ctx->zorder, config, sizeof(ctx->zorder)); |
| } else { |
| memset(&ctx->zorder, 0, sizeof(ctx->zorder)); |
| } |
| |
| VTRACE("count %p, handle %#x, trans %#x, blending %#x" |
| " sourceCrop %f,%f - %fx%f, dst %d,%d - %dx%d, custom %#x", |
| mCount, |
| imgLayer->psLayer->handle, |
| imgLayer->psLayer->transform, |
| imgLayer->psLayer->blending, |
| imgLayer->psLayer->sourceCropf.left, |
| imgLayer->psLayer->sourceCropf.top, |
| imgLayer->psLayer->sourceCropf.right - imgLayer->psLayer->sourceCropf.left, |
| imgLayer->psLayer->sourceCropf.bottom - imgLayer->psLayer->sourceCropf.top, |
| imgLayer->psLayer->displayFrame.left, |
| imgLayer->psLayer->displayFrame.top, |
| imgLayer->psLayer->displayFrame.right - imgLayer->psLayer->displayFrame.left, |
| imgLayer->psLayer->displayFrame.bottom - imgLayer->psLayer->displayFrame.top, |
| imgLayer->custom); |
| } |
| |
| layerList->postFlip(); |
| return true; |
| } |
| |
| bool TngDisplayContext::commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays) |
| { |
| int releaseFenceFd = -1; |
| |
| VTRACE("count = %d", mCount); |
| |
| if (mIMGDisplayDevice && mCount) { |
| int err = mIMGDisplayDevice->post(mIMGDisplayDevice, |
| mImgLayers, |
| mCount, |
| &releaseFenceFd); |
| if (err) { |
| ETRACE("post failed, err = %d", err); |
| return false; |
| } |
| } |
| |
| // close acquire fence |
| for (size_t i = 0; i < numDisplays; i++) { |
| // Wait and close HWC_OVERLAY typed layer's acquire fence |
| hwc_display_contents_1_t* display = displays[i]; |
| if (!display) { |
| continue; |
| } |
| |
| for (size_t j = 0; j < display->numHwLayers-1; j++) { |
| hwc_layer_1_t& layer = display->hwLayers[j]; |
| if (layer.compositionType == HWC_OVERLAY) { |
| if (layer.acquireFenceFd != -1) { |
| // sync_wait(layer.acquireFenceFd, 16ms); |
| close(layer.acquireFenceFd); |
| layer.acquireFenceFd = -1; |
| } |
| } |
| } |
| |
| // Wait and close framebuffer target layer's acquire fence |
| hwc_layer_1_t& fbt = display->hwLayers[display->numHwLayers-1]; |
| if (fbt.acquireFenceFd != -1) { |
| // sync_wait(fbt.acquireFencdFd, 16ms); |
| close(fbt.acquireFenceFd); |
| fbt.acquireFenceFd = -1; |
| } |
| |
| // Wait and close outbuf's acquire fence |
| if (display->outbufAcquireFenceFd != -1) { |
| // sync_wait(display->outbufAcquireFenceFd, 16ms); |
| close(display->outbufAcquireFenceFd); |
| display->outbufAcquireFenceFd = -1; |
| } |
| } |
| |
| // update release fence and retire fence |
| if (mCount > 0) { |
| // For physical displays, dup the releaseFenceFd only for |
| // HWC layers which successfully flipped to display planes |
| IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers; |
| |
| for (unsigned int i = 0; i < mCount; i++) { |
| IMG_hwc_layer_t *imgLayer = &imgLayerList[i]; |
| imgLayer->psLayer->releaseFenceFd = |
| (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1; |
| } |
| } |
| |
| for (size_t i = 0; i < numDisplays; i++) { |
| if (!displays[i]) { |
| continue; |
| } |
| |
| // log for layer fence status |
| for (size_t j = 0; j < displays[i]->numHwLayers; j++) { |
| VTRACE("handle %#p, acquiredFD %d, releaseFD %d", |
| displays[i]->hwLayers[j].handle, |
| displays[i]->hwLayers[j].acquireFenceFd, |
| displays[i]->hwLayers[j].releaseFenceFd); |
| } |
| |
| // retireFence is used for SurfaceFlinger to do DispSync; |
| // dup releaseFenceFd for physical displays and ignore virtual |
| // display; we don't distinguish between release and retire, and all |
| // physical displays are using a single releaseFence; for virtual |
| // display, fencing is handled by the VirtualDisplay class |
| if (i < IDisplayDevice::DEVICE_VIRTUAL) { |
| displays[i]->retireFenceFd = |
| (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1; |
| } |
| } |
| |
| // close original release fence fd |
| if (releaseFenceFd != -1) { |
| close(releaseFenceFd); |
| } |
| return true; |
| } |
| |
| bool TngDisplayContext::compositionComplete() |
| { |
| return true; |
| } |
| |
| bool TngDisplayContext::setCursorPosition(int disp, int x, int y) |
| { |
| DTRACE("setCursorPosition"); |
| struct intel_dc_cursor_ctx ctx; |
| memset(&ctx, 0, sizeof(ctx)); |
| ctx.pipe = disp; |
| if (x < 0) { |
| ctx.pos |= 1 << 15; |
| x = -x; |
| } |
| if (y < 0) { |
| ctx.pos |= 1 << 31; |
| y = -y; |
| } |
| ctx.pos |= (y & 0xfff) << 16 | (x & 0xfff); |
| Drm *drm = Hwcomposer::getInstance().getDrm(); |
| return drm->writeIoctl(DRM_PSB_UPDATE_CURSOR_POS, &ctx, sizeof(ctx)); |
| } |
| |
| void TngDisplayContext::deinitialize() |
| { |
| mIMGDisplayDevice = 0; |
| |
| mCount = 0; |
| mInitialized = false; |
| } |
| |
| |
| } // namespace intel |
| } // namespace android |