Blame vaapi/vaapidisplay.cpp

Packit 1244b8
/*
Packit 1244b8
 * Copyright (C) 2014 Intel Corporation. All rights reserved.
Packit 1244b8
 *
Packit 1244b8
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1244b8
 * you may not use this file except in compliance with the License.
Packit 1244b8
 * You may obtain a copy of the License at
Packit 1244b8
 *
Packit 1244b8
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1244b8
 *
Packit 1244b8
 * Unless required by applicable law or agreed to in writing, software
Packit 1244b8
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1244b8
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1244b8
 * See the License for the specific language governing permissions and
Packit 1244b8
 * limitations under the License.
Packit 1244b8
 */
Packit 1244b8
Packit 1244b8
#ifdef HAVE_CONFIG_H
Packit 1244b8
#include "config.h"
Packit 1244b8
#endif
Packit 1244b8
Packit 1244b8
#include "vaapi/vaapidisplay.h"
Packit 1244b8
#include <stdlib.h>
Packit 1244b8
#include <stdint.h>
Packit 1244b8
#include <unistd.h>
Packit 1244b8
#include <fcntl.h>
Packit 1244b8
#include <list>
Packit 1244b8
#include "common/log.h"
Packit 1244b8
#include "common/lock.h"
Packit 1244b8
#include "vaapi/VaapiUtils.h"
Packit 1244b8
#include <inttypes.h>
Packit 1244b8
Packit 1244b8
using std::list;
Packit 1244b8
/**
Packit 1244b8
1. client and yami shares the same display when it provides both native
Packit 1244b8
   display (x11 Display or drm fd) and display type in setNativeDisplay().
Packit 1244b8
   client owns the native display
Packit 1244b8
2. when client set native display type only, yami will create a native
Packit 1244b8
   display and owns it.
Packit 1244b8
3. when client doesn't set any native display, or set display type to
Packit 1244b8
   NATIVE_DISPLAY_AUTO; yami will try to open a x11 display first. if fail,
Packit 1244b8
   drm display will try next
Packit 1244b8
Packit 1244b8
4. A x11 display is compatible to drm display, while not reverse.
Packit 1244b8
   it means, when there is a VADisplay created from x11 display already ,
Packit 1244b8
   yami will not create a new display when drm display is requested,
Packit 1244b8
   simplely reuse the VADisplay.
Packit 1244b8
*/
Packit 1244b8
Packit 1244b8
//helper function
Packit 1244b8
namespace YamiMediaCodec{
Packit 1244b8
static bool vaInit(VADisplay vaDisplay)
Packit 1244b8
{
Packit 1244b8
   int majorVersion, minorVersion;
Packit 1244b8
   VAStatus vaStatus;
Packit 1244b8
   vaStatus= vaInitialize(vaDisplay, &majorVersion, &minorVersion);
Packit 1244b8
   return checkVaapiStatus(vaStatus, "vaInitialize");
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
class NativeDisplayBase {
Packit 1244b8
  public:
Packit 1244b8
    NativeDisplayBase() :m_handle(0) { };
Packit 1244b8
    virtual ~NativeDisplayBase() {};
Packit 1244b8
    virtual bool initialize(const NativeDisplay& display) = 0;
Packit 1244b8
    virtual bool isCompatible (const NativeDisplay& display) = 0;
Packit 1244b8
    intptr_t nativeHandle() {return m_handle;};
Packit 1244b8
Packit 1244b8
  protected:
Packit 1244b8
    virtual bool acceptValidExternalHandle(const NativeDisplay& display) {
Packit 1244b8
        if (display.handle && display.handle != -1) {
Packit 1244b8
            m_handle = display.handle;
Packit 1244b8
            m_selfCreated = false;
Packit 1244b8
            return true;
Packit 1244b8
        }
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
    intptr_t m_handle;
Packit 1244b8
    bool m_selfCreated;
Packit 1244b8
Packit 1244b8
  private:
Packit 1244b8
    DISALLOW_COPY_AND_ASSIGN(NativeDisplayBase);
Packit 1244b8
};
Packit 1244b8
Packit 1244b8
bool isInvalidDrmHandle(int handle)
Packit 1244b8
{
Packit 1244b8
    return handle == 0 || handle == -1;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
#if defined(__ENABLE_X11__)
Packit 1244b8
class NativeDisplayX11 : public NativeDisplayBase{
Packit 1244b8
  public:
Packit 1244b8
    NativeDisplayX11() :NativeDisplayBase(){ };
Packit 1244b8
    virtual ~NativeDisplayX11() {
Packit 1244b8
        if (m_selfCreated && m_handle)
Packit 1244b8
            XCloseDisplay((Display*)(m_handle));
Packit 1244b8
    };
Packit 1244b8
Packit 1244b8
    virtual bool initialize (const NativeDisplay& display) {
Packit 1244b8
        ASSERT(display.type == NATIVE_DISPLAY_X11 || display.type == NATIVE_DISPLAY_AUTO);
Packit 1244b8
Packit 1244b8
        if (acceptValidExternalHandle(display))
Packit 1244b8
            return true;
Packit 1244b8
Packit 1244b8
        m_handle = (intptr_t)XOpenDisplay(NULL);
Packit 1244b8
        m_selfCreated = true;
Packit 1244b8
        return (Display*)m_handle != NULL;
Packit 1244b8
    };
Packit 1244b8
Packit 1244b8
    virtual bool isCompatible(const NativeDisplay& display) {
Packit 1244b8
        if (display.type == NATIVE_DISPLAY_AUTO)
Packit 1244b8
            return true;
Packit 1244b8
        if (display.type == NATIVE_DISPLAY_DRM) {
Packit 1244b8
            //invalid drm handle means any drm display is acceptable.
Packit 1244b8
            if (isInvalidDrmHandle(display.handle))
Packit 1244b8
                return true;
Packit 1244b8
        }
Packit 1244b8
        if (display.type == NATIVE_DISPLAY_X11 && (!display.handle || display.handle == m_handle))
Packit 1244b8
            return true;
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
};
Packit 1244b8
#endif
Packit 1244b8
class NativeDisplayDrm : public NativeDisplayBase{
Packit 1244b8
  public:
Packit 1244b8
    NativeDisplayDrm() :NativeDisplayBase(){ };
Packit 1244b8
    virtual ~NativeDisplayDrm() {
Packit 1244b8
        if (m_selfCreated && m_handle && m_handle != -1)
Packit 1244b8
            ::close(m_handle);
Packit 1244b8
    };
Packit 1244b8
    virtual bool initialize (const NativeDisplay& display) {
Packit 1244b8
        ASSERT(display.type == NATIVE_DISPLAY_DRM || display.type == NATIVE_DISPLAY_AUTO);
Packit 1244b8
Packit 1244b8
        if (acceptValidExternalHandle(display))
Packit 1244b8
            return true;
Packit 1244b8
Packit 1244b8
        m_handle = -1;
Packit 1244b8
        const char* device_env = getenv("VA_DRM_DEVICE");
Packit 1244b8
        if (device_env)
Packit 1244b8
            m_handle = open(device_env, O_RDWR);
Packit 1244b8
        if (m_handle < 0)
Packit 1244b8
            m_handle = open("/dev/dri/renderD128", O_RDWR);
Packit 1244b8
        if (m_handle < 0)
Packit 1244b8
            m_handle = open("/dev/dri/card0", O_RDWR);
Packit 1244b8
        m_selfCreated = true;
Packit 1244b8
        return m_handle != -1;
Packit 1244b8
    };
Packit 1244b8
Packit 1244b8
    bool isCompatible(const NativeDisplay& display) {
Packit 1244b8
        if (display.type == NATIVE_DISPLAY_AUTO)
Packit 1244b8
            return true;
Packit 1244b8
        if (display.type != NATIVE_DISPLAY_DRM)
Packit 1244b8
            return false;
Packit 1244b8
        if (isInvalidDrmHandle(display.handle) || display.handle == m_handle)
Packit 1244b8
            return true;
Packit 1244b8
        return false;
Packit 1244b8
    }
Packit 1244b8
};
Packit 1244b8
Packit 1244b8
class NativeDisplayVADisplay : public NativeDisplayBase{
Packit 1244b8
  public:
Packit 1244b8
    NativeDisplayVADisplay() :NativeDisplayBase(){ };
Packit 1244b8
    ~NativeDisplayVADisplay() {};
Packit 1244b8
    virtual bool initialize (const NativeDisplay& display) {
Packit 1244b8
        ASSERT(display.type == NATIVE_DISPLAY_VA);
Packit 1244b8
Packit 1244b8
        if (acceptValidExternalHandle(display))
Packit 1244b8
            return true;
Packit 1244b8
        return vaDisplayIsValid((VADisplay)display.handle);
Packit 1244b8
    };
Packit 1244b8
Packit 1244b8
    bool isCompatible(const NativeDisplay& display) {
Packit 1244b8
        if (display.type == NATIVE_DISPLAY_AUTO)
Packit 1244b8
            return true;
Packit 1244b8
        return display.type == NATIVE_DISPLAY_VA && display.handle == m_handle;
Packit 1244b8
    }
Packit 1244b8
};
Packit 1244b8
Packit 1244b8
typedef SharedPtr<NativeDisplayBase> NativeDisplayPtr;
Packit 1244b8
Packit 1244b8
bool VaapiDisplay::isCompatible(const NativeDisplay& other)
Packit 1244b8
{
Packit 1244b8
    return m_nativeDisplay->isCompatible(other);
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
VaapiDisplay::~VaapiDisplay()
Packit 1244b8
{
Packit 1244b8
    if (!DynamicPointerCast<NativeDisplayVADisplay>(m_nativeDisplay)) {
Packit 1244b8
        vaTerminate(m_vaDisplay);
Packit 1244b8
    }
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool VaapiDisplay::setRotation(int degree)
Packit 1244b8
{
Packit 1244b8
    VAStatus vaStatus;
Packit 1244b8
    VADisplayAttribute* attrList = NULL;
Packit 1244b8
    VADisplayAttribute rotate;
Packit 1244b8
    int i, numAttributes;
Packit 1244b8
    rotate.type = VADisplayAttribRotation;
Packit 1244b8
    rotate.value = VA_ROTATION_NONE;
Packit 1244b8
    if (degree == 0) //no need to set rotation when degree is zero
Packit 1244b8
        return true;
Packit 1244b8
    else if (degree == 90)
Packit 1244b8
        rotate.value = VA_ROTATION_90;
Packit 1244b8
    else if (degree == 180)
Packit 1244b8
        rotate.value = VA_ROTATION_180;
Packit 1244b8
    else if (degree == 270)
Packit 1244b8
        rotate.value = VA_ROTATION_270;
Packit 1244b8
Packit 1244b8
    /* should query before set display attributres */
Packit 1244b8
    vaStatus = vaQueryDisplayAttributes(m_vaDisplay, attrList, &numAttributes);
Packit 1244b8
    if (!checkVaapiStatus(vaStatus, "vaQueryDisplayAttributes") || !attrList)
Packit 1244b8
       return false;
Packit 1244b8
Packit 1244b8
    for (i = 0; i < numAttributes; i++) {
Packit 1244b8
        if (attrList[i].type == VADisplayAttribRotation)
Packit 1244b8
            break;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if ((i == numAttributes) || !(attrList[i].flags & VA_DISPLAY_ATTRIB_SETTABLE) )
Packit 1244b8
        return false;
Packit 1244b8
Packit 1244b8
    vaStatus = vaSetDisplayAttributes(m_vaDisplay, &rotate, 1);
Packit 1244b8
    if (!checkVaapiStatus(vaStatus, "vaSetDisplayAttributes"))
Packit 1244b8
        return false;
Packit 1244b8
    return true;
Packit 1244b8
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
const VAImageFormat *
Packit 1244b8
VaapiDisplay::getVaFormat(uint32_t fourcc)
Packit 1244b8
{
Packit 1244b8
    AutoLock locker(m_lock);
Packit 1244b8
    size_t i;
Packit 1244b8
Packit 1244b8
    if (m_vaImageFormats.empty()) {
Packit 1244b8
        VAStatus vaStatus;
Packit 1244b8
        int numImageFormats;
Packit 1244b8
        numImageFormats = vaMaxNumImageFormats(m_vaDisplay);
Packit 1244b8
        if (numImageFormats == 0)
Packit 1244b8
            return NULL;
Packit 1244b8
Packit 1244b8
        m_vaImageFormats.reserve(numImageFormats);
Packit 1244b8
        m_vaImageFormats.resize(numImageFormats);
Packit 1244b8
Packit 1244b8
        vaStatus = vaQueryImageFormats(m_vaDisplay, &m_vaImageFormats[0], &numImageFormats);
Packit 1244b8
        checkVaapiStatus(vaStatus, "vaQueryImageFormats()");
Packit 1244b8
        for (i=0; i< m_vaImageFormats.size(); i++)
Packit 1244b8
            DEBUG_FOURCC("supported image format: ", m_vaImageFormats[i].fourcc);
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    for (i = 0; i < m_vaImageFormats.size(); i++) {
Packit 1244b8
        VAImageFormat vaImageFormat = m_vaImageFormats[i];
Packit 1244b8
        if (vaImageFormat.fourcc == fourcc)
Packit 1244b8
            return &m_vaImageFormats[i];
Packit 1244b8
    }
Packit 1244b8
    return NULL;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
//display cache
Packit 1244b8
class DisplayCache
Packit 1244b8
{
Packit 1244b8
public:
Packit 1244b8
    static SharedPtr<DisplayCache> getInstance();
Packit 1244b8
    DisplayPtr createDisplay(const NativeDisplay& nativeDisplay);
Packit 1244b8
Packit 1244b8
    ~DisplayCache() {}
Packit 1244b8
private:
Packit 1244b8
    DisplayCache() {}
Packit 1244b8
Packit 1244b8
    list<WeakPtr<VaapiDisplay> > m_cache;
Packit 1244b8
    YamiMediaCodec::Lock m_lock;
Packit 1244b8
};
Packit 1244b8
Packit 1244b8
SharedPtr<DisplayCache> DisplayCache::getInstance()
Packit 1244b8
{
Packit 1244b8
    static SharedPtr<DisplayCache> cache;
Packit 1244b8
    if (!cache) {
Packit 1244b8
        SharedPtr<DisplayCache> temp(new DisplayCache);
Packit 1244b8
        cache = temp;
Packit 1244b8
    }
Packit 1244b8
    return cache;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
bool expired(const WeakPtr<VaapiDisplay>& weak)
Packit 1244b8
{
Packit 1244b8
    return !weak.lock();
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
DisplayPtr DisplayCache::createDisplay(const NativeDisplay& nativeDisplay)
Packit 1244b8
{
Packit 1244b8
    NativeDisplayPtr nativeDisplayObj;
Packit 1244b8
    VADisplay vaDisplay = NULL;
Packit 1244b8
    DisplayPtr vaapiDisplay;
Packit 1244b8
    YamiMediaCodec::AutoLock locker(m_lock);
Packit 1244b8
Packit 1244b8
    m_cache.remove_if(expired);
Packit 1244b8
Packit 1244b8
    //lockup first
Packit 1244b8
    list<WeakPtr<VaapiDisplay> >::iterator it;
Packit 1244b8
    for (it = m_cache.begin(); it != m_cache.end(); ++it) {
Packit 1244b8
        vaapiDisplay = (*it).lock();
Packit 1244b8
        if (vaapiDisplay->isCompatible(nativeDisplay)) {
Packit 1244b8
            return vaapiDisplay;
Packit 1244b8
        }
Packit 1244b8
    }
Packit 1244b8
    vaapiDisplay.reset();
Packit 1244b8
Packit 1244b8
    //crate new one
Packit 1244b8
    DEBUG("nativeDisplay: (type : %d), (handle : %" PRIxPTR ")", nativeDisplay.type, nativeDisplay.handle);
Packit 1244b8
Packit 1244b8
    switch (nativeDisplay.type) {
Packit 1244b8
    case NATIVE_DISPLAY_AUTO:
Packit 1244b8
#if defined(__ENABLE_X11__)
Packit 1244b8
    case NATIVE_DISPLAY_X11:
Packit 1244b8
        nativeDisplayObj.reset (new NativeDisplayX11());
Packit 1244b8
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
Packit 1244b8
            vaDisplay = vaGetDisplay((Display*)(nativeDisplayObj->nativeHandle()));
Packit 1244b8
        if (vaDisplay)
Packit 1244b8
            INFO("use vaapi x11 backend");
Packit 1244b8
        if(vaDisplay || nativeDisplay.type == NATIVE_DISPLAY_X11)
Packit 1244b8
            break;
Packit 1244b8
        INFO("try to init va with x11 display (%p) but failed", (Display*)(nativeDisplayObj->nativeHandle()));
Packit 1244b8
        // NATIVE_DISPLAY_AUTO continue, no break
Packit 1244b8
#endif
Packit 1244b8
    case NATIVE_DISPLAY_DRM:
Packit 1244b8
        nativeDisplayObj.reset (new NativeDisplayDrm());
Packit 1244b8
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
Packit 1244b8
#ifndef ANDROID
Packit 1244b8
            vaDisplay = vaGetDisplayDRM(nativeDisplayObj->nativeHandle());
Packit 1244b8
#endif
Packit 1244b8
        INFO("use vaapi drm backend");
Packit 1244b8
        break;
Packit 1244b8
    case NATIVE_DISPLAY_VA:
Packit 1244b8
        nativeDisplayObj.reset (new NativeDisplayVADisplay());
Packit 1244b8
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
Packit 1244b8
            vaDisplay = (VADisplay)nativeDisplayObj->nativeHandle();
Packit 1244b8
        INFO("use vaapi va backend");
Packit 1244b8
        break;
Packit 1244b8
    default:
Packit 1244b8
        break;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if (vaDisplay == NULL) {
Packit 1244b8
        ERROR("vaGetDisplay failed.");
Packit 1244b8
        return vaapiDisplay;
Packit 1244b8
    }
Packit 1244b8
Packit 1244b8
    if (nativeDisplay.type == NATIVE_DISPLAY_VA || vaInit(vaDisplay)) {
Packit 1244b8
        DisplayPtr temp(new VaapiDisplay(nativeDisplayObj, vaDisplay));
Packit 1244b8
        vaapiDisplay = temp;
Packit 1244b8
    }
Packit 1244b8
    if (vaapiDisplay) {
Packit 1244b8
        WeakPtr<VaapiDisplay> weak(vaapiDisplay);
Packit 1244b8
        m_cache.push_back(weak);
Packit 1244b8
    }
Packit 1244b8
    return vaapiDisplay;
Packit 1244b8
}
Packit 1244b8
Packit 1244b8
DisplayPtr VaapiDisplay::create(const NativeDisplay& display)
Packit 1244b8
{
Packit 1244b8
    return DisplayCache::getInstance()->createDisplay(display);
Packit 1244b8
}
Packit 1244b8
} //YamiMediaCodec