diff options
-rw-r--r-- | include/media/hardware/HDCPAPI.h | 85 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.cpp | 48 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 121 |
3 files changed, 192 insertions, 62 deletions
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h new file mode 100644 index 0000000..bb91540 --- /dev/null +++ b/include/media/hardware/HDCPAPI.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef HDCP_API_H_ + +#define HDCP_API_H_ + +#include <utils/Errors.h> + +namespace android { + +struct HDCPModule { + typedef void (*ObserverFunc)(int msg, int ext1, int ext2); + + // The msg argument in calls to the observer notification function. + enum { + // Sent in response to a call to "HDCPModule::initAsync" once + // initialization has either been successfully completed, + // i.e. the HDCP session is now fully setup (AKE, Locality Check, + // SKE and any authentication with repeaters completed) or failed. + // ext1 should be a suitable error code (status_t), ext2 is + // unused. + HDCP_INITIALIZATION_COMPLETE, + + // Sent upon completion of a call to "HDCPModule::shutdownAsync". + // ext1 should be a suitable error code, ext2 is unused. + HDCP_SHUTDOWN_COMPLETE, + }; + + // Module can call the notification function to signal completion/failure + // of asynchronous operations (such as initialization) or out of band + // events. + HDCPModule(ObserverFunc observerNotify); + + virtual ~HDCPModule(); + + // Request to setup an HDCP session with the specified host listening + // on the specified port. + virtual status_t initAsync(const char *host, unsigned port) = 0; + + // Request to shutdown the active HDCP session. + virtual status_t shutdownAsync() = 0; + + // Encrypt a data according to the HDCP spec. The data is to be + // encrypted in-place, only size bytes of data should be read/write, + // even if the size is not a multiple of 128 bit (16 bytes). + // This operation is to be synchronous, i.e. this call does not return + // until outData contains size bytes of encrypted data. + // streamCTR will be assigned by the caller (to 0 for the first PES stream, + // 1 for the second and so on) + // inputCTR will be maintained by the callee for each PES stream. + virtual status_t encrypt( + const void *inData, size_t size, uint32_t streamCTR, + uint64_t *outInputCTR, void *outData) = 0; + +private: + HDCPModule(const HDCPModule &); + HDCPModule &operator=(const HDCPModule &); +}; + +} // namespace android + +// A shared library exporting the following method should be included to +// support HDCP functionality. The shared library must be called +// "libstagefright_hdcp.so", it will be dynamically loaded into the +// mediaserver process. +extern "C" { + extern android::HDCPModule *createHDCPModule(); +} + +#endif // HDCP_API_H_ + diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 1678fe1..75c228d 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -46,8 +46,31 @@ namespace android { -static bool hwcHasVersion(const hwc_composer_device_1_t* hwc, uint32_t version) { - return hwc->common.version >= version; +#define MIN_HWC_HEADER_VERSION 0 + +static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + if (MIN_HWC_HEADER_VERSION == 0 && + (hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK) == 0) { + // legacy version encoding + hwcVersion <<= 16; + } + return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; +} + +static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + if (MIN_HWC_HEADER_VERSION == 0 && + (hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK) == 0) { + // legacy version encoding + hwcVersion <<= 16; + } + return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK; +} + +static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc, + uint32_t version) { + return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK); } // --------------------------------------------------------------------------- @@ -91,8 +114,10 @@ HWComposer::HWComposer( ALOGE_IF(err, "%s device failed to initialize (%s)", HWC_HARDWARE_COMPOSER, strerror(-err)); if (err == 0) { - if (mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) { - ALOGE("%s device version %#x too old, will not be used", + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) || + hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION || + hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) { + ALOGE("%s device version %#x unsupported, will not be used", HWC_HARDWARE_COMPOSER, mHwc->common.version); hwc_close_1(mHwc); mHwc = NULL; @@ -100,6 +125,9 @@ HWComposer::HWComposer( } if (mHwc) { + ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, + (hwcApiVersion(mHwc) >> 24) & 0xff, + (hwcApiVersion(mHwc) >> 16) & 0xff); if (mHwc->registerProcs) { mCBContext->hwc = this; mCBContext->procs.invalidate = &hook_invalidate; @@ -125,12 +153,14 @@ HWComposer::HWComposer( // the number of displays we actually have depends on the // hw composer version - if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_1) { - // 1.1 adds support for multiple displays - mNumDisplays = HWC_NUM_DISPLAY_TYPES; - } else if (mHwc->common.version > HWC_DEVICE_API_VERSION_1_1) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { // 1.2 adds support for virtual displays mNumDisplays = MAX_DISPLAYS; + } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // 1.1 adds support for multiple displays + mNumDisplays = HWC_NUM_DISPLAY_TYPES; + } else { + mNumDisplays = 1; } } } @@ -326,7 +356,7 @@ bool HWComposer::hasGlesComposition(int32_t id) const { status_t HWComposer::commit() { int err = NO_ERROR; if (mHwc) { - if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) { + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // On version 1.0, the OpenGL ES target surface is communicated // by the (dpy, sur) fields and we are guaranteed to have only // a single display. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1162432..cd1b336 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -944,7 +944,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; const size_t cc = curr.size(); - const size_t dc = draw.size(); + size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) @@ -965,27 +965,27 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const wp<IBinder>& display(curr.keyAt(j)); if (state.surface->asBinder() != draw[i].surface->asBinder()) { // changing the surface is like destroying and - // recreating the DisplayDevice - sp<SurfaceTextureClient> stc( - new SurfaceTextureClient(state.surface)); - sp<DisplayDevice> disp = new DisplayDevice(this, - state.type, display, stc, NULL, mEGLConfig); - - disp->setLayerStack(state.layerStack); - disp->setOrientation(state.orientation); - // TODO: take viewport and frame into account - mDisplays.replaceValueFor(display, disp); - } - if (state.layerStack != draw[i].layerStack) { - const sp<DisplayDevice>& disp(getDisplayDevice(display)); - disp->setLayerStack(state.layerStack); + // recreating the DisplayDevice, so we just remove it + // from the drawing state, so that it get re-added + // below. + mDisplays.removeItem(display); + mDrawingState.displays.removeItemsAt(i); + dc--; i--; + // at this point we must loop to the next item + continue; } - if (state.orientation != draw[i].orientation || - state.viewport != draw[i].viewport || - state.frame != draw[i].frame) { - const sp<DisplayDevice>& disp(getDisplayDevice(display)); - disp->setOrientation(state.orientation); - // TODO: take viewport and frame into account + + const sp<DisplayDevice>& disp(getDisplayDevice(display)); + if (disp != NULL) { + if (state.layerStack != draw[i].layerStack) { + disp->setLayerStack(state.layerStack); + } + if (state.orientation != draw[i].orientation || + state.viewport != draw[i].viewport || + state.frame != draw[i].frame) { + disp->setOrientation(state.orientation); + // TODO: take viewport and frame into account + } } } } @@ -995,12 +995,17 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) for (size_t i=0 ; i<cc ; i++) { if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]); - sp<SurfaceTextureClient> stc( - new SurfaceTextureClient(state.surface)); - const wp<IBinder>& display(curr.keyAt(i)); - sp<DisplayDevice> disp = new DisplayDevice(this, - state.type, display, stc, 0, mEGLConfig); - mDisplays.add(display, disp); + if (state.surface != NULL) { + sp<SurfaceTextureClient> stc( + new SurfaceTextureClient(state.surface)); + const wp<IBinder>& display(curr.keyAt(i)); + sp<DisplayDevice> disp = new DisplayDevice(this, + state.type, display, stc, 0, mEGLConfig); + disp->setLayerStack(state.layerStack); + disp->setOrientation(state.orientation); + // TODO: take viewport and frame into account + mDisplays.add(display, disp); + } } } } @@ -1264,15 +1269,13 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) { + const int32_t id = hw->getHwcDisplayId(); HWComposer& hwc(getHwComposer()); - int32_t id = hw->getHwcDisplayId(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); - const bool hasGlesComposition = hwc.hasGlesComposition(id); - const bool hasHwcComposition = hwc.hasHwcComposition(id); - if (cur==end || hasGlesComposition) { - + const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end); + if (hasGlesComposition) { DisplayDevice::makeCurrent(hw, mEGLContext); // set the frame buffer @@ -1280,6 +1283,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const glLoadIdentity(); // Never touch the framebuffer if we don't have any framebuffer layers + const bool hasHwcComposition = hwc.hasHwcComposition(id); if (hasHwcComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance @@ -1296,39 +1300,50 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const drawWormhole(hw, region); } } + } - /* - * and then, render the layers targeted at the framebuffer - */ + /* + * and then, render the layers targeted at the framebuffer + */ - const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); - const size_t count = layers.size(); - const Transform& tr = hw->getTransform(); - for (size_t i=0 ; i<count ; ++i) { + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); + const size_t count = layers.size(); + const Transform& tr = hw->getTransform(); + if (cur != end) { + // we're using h/w composer + for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) { const sp<LayerBase>& layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); - if (cur != end) { - // we're using h/w composer - if (!clip.isEmpty()) { - if (cur->getCompositionType() == HWC_OVERLAY) { - if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) - && layer->isOpaque()) { + if (!clip.isEmpty()) { + switch (cur->getCompositionType()) { + case HWC_OVERLAY: { + if ((cur->getHints() & HWC_HINT_CLEAR_FB) + && i + && layer->isOpaque() + && hasGlesComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared layer->clearWithOpenGL(hw, clip); } - } else { + break; + } + case HWC_FRAMEBUFFER: { layer->draw(hw, clip); + break; } - layer->setAcquireFence(hw, *cur); - } - ++cur; - } else { - // we're not using h/w composer - if (!clip.isEmpty()) { - layer->draw(hw, clip); } } + layer->setAcquireFence(hw, *cur); + } + } else { + // we're not using h/w composer + for (size_t i=0 ; i<count ; ++i) { + const sp<LayerBase>& layer(layers[i]); + const Region clip(dirty.intersect( + tr.transform(layer->visibleRegion))); + if (!clip.isEmpty()) { + layer->draw(hw, clip); + } } } } |