2009-03-04 03:31:44 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <utils/Errors.h>
|
|
|
|
#include <utils/Log.h>
|
|
|
|
#include <utils/StopWatch.h>
|
|
|
|
|
2009-10-06 00:07:12 +00:00
|
|
|
#include <ui/GraphicBuffer.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <ui/PixelFormat.h>
|
2009-06-24 04:11:43 +00:00
|
|
|
#include <ui/FramebufferNativeWindow.h>
|
2009-11-06 07:08:00 +00:00
|
|
|
#include <ui/Rect.h>
|
|
|
|
#include <ui/Region.h>
|
2009-06-24 04:11:43 +00:00
|
|
|
|
|
|
|
#include <hardware/copybit.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
#include "LayerBuffer.h"
|
|
|
|
#include "SurfaceFlinger.h"
|
|
|
|
#include "DisplayHardware/DisplayHardware.h"
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
|
|
|
|
const char* const LayerBuffer::typeID = "LayerBuffer";
|
2009-10-30 01:29:30 +00:00
|
|
|
gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
|
2009-06-20 00:00:27 +00:00
|
|
|
const sp<Client>& client, int32_t i)
|
2009-03-04 03:31:44 +00:00
|
|
|
: LayerBaseClient(flinger, display, client, i),
|
2009-11-06 07:08:00 +00:00
|
|
|
mNeedsBlending(false), mBlitEngine(0)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerBuffer::~LayerBuffer()
|
|
|
|
{
|
2009-11-06 07:08:00 +00:00
|
|
|
if (mBlitEngine) {
|
|
|
|
copybit_close(mBlitEngine);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-18 02:36:26 +00:00
|
|
|
void LayerBuffer::onFirstRef()
|
|
|
|
{
|
2009-06-24 03:06:46 +00:00
|
|
|
LayerBaseClient::onFirstRef();
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
|
2009-04-18 02:36:26 +00:00
|
|
|
const_cast<LayerBuffer *>(this));
|
2009-10-30 01:29:30 +00:00
|
|
|
|
|
|
|
hw_module_t const* module = (hw_module_t const*)sGrallocModule;
|
|
|
|
if (!module) {
|
|
|
|
// NOTE: technically there is a race here, but it shouldn't
|
|
|
|
// cause any problem since hw_get_module() always returns
|
|
|
|
// the same value.
|
|
|
|
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
|
|
|
|
sGrallocModule = (gralloc_module_t const *)module;
|
|
|
|
}
|
|
|
|
}
|
2009-11-06 07:08:00 +00:00
|
|
|
|
|
|
|
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
|
|
|
|
copybit_open(module, &mBlitEngine);
|
|
|
|
}
|
2009-04-18 02:36:26 +00:00
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-04-18 02:36:26 +00:00
|
|
|
return mSurface;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t LayerBuffer::ditch()
|
|
|
|
{
|
|
|
|
mSurface.clear();
|
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool LayerBuffer::needsBlending() const {
|
|
|
|
return mNeedsBlending;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::setNeedsBlending(bool blending) {
|
|
|
|
mNeedsBlending = blending;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::postBuffer(ssize_t offset)
|
|
|
|
{
|
|
|
|
sp<Source> source(getSource());
|
|
|
|
if (source != 0)
|
|
|
|
source->postBuffer(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::unregisterBuffers()
|
|
|
|
{
|
|
|
|
sp<Source> source(clearSource());
|
|
|
|
if (source != 0)
|
|
|
|
source->unregisterBuffers();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t LayerBuffer::doTransaction(uint32_t flags)
|
|
|
|
{
|
|
|
|
sp<Source> source(getSource());
|
|
|
|
if (source != 0)
|
|
|
|
source->onTransaction(flags);
|
2009-11-19 22:46:26 +00:00
|
|
|
uint32_t res = LayerBase::doTransaction(flags);
|
|
|
|
// we always want filtering for these surfaces
|
|
|
|
if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
|
|
|
|
mUseLinearFiltering = true;
|
|
|
|
}
|
|
|
|
return res;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
|
|
|
|
Region& outDirtyRegion)
|
|
|
|
{
|
|
|
|
// this code-path must be as tight as possible, it's called each time
|
|
|
|
// the screen is composited.
|
|
|
|
sp<Source> source(getSource());
|
|
|
|
if (source != 0)
|
|
|
|
source->onVisibilityResolved(planeTransform);
|
|
|
|
LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::onDraw(const Region& clip) const
|
|
|
|
{
|
|
|
|
sp<Source> source(getSource());
|
|
|
|
if (LIKELY(source != 0)) {
|
|
|
|
source->onDraw(clip);
|
|
|
|
} else {
|
|
|
|
clearWithOpenGL(clip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LayerBuffer::transformed() const
|
|
|
|
{
|
|
|
|
sp<Source> source(getSource());
|
|
|
|
if (LIKELY(source != 0))
|
|
|
|
return source->transformed();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-09-09 06:52:08 +00:00
|
|
|
void LayerBuffer::serverDestroy()
|
|
|
|
{
|
|
|
|
sp<Source> source(clearSource());
|
|
|
|
if (source != 0) {
|
|
|
|
source->destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
/**
|
|
|
|
* This creates a "buffer" source for this surface
|
|
|
|
*/
|
|
|
|
status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
|
|
|
|
{
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
if (mSource != 0)
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
sp<BufferSource> source = new BufferSource(*this, buffers);
|
|
|
|
|
|
|
|
status_t result = source->getStatus();
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
mSource = source;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This creates an "overlay" source for this surface
|
|
|
|
*/
|
|
|
|
sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
|
|
|
|
{
|
|
|
|
sp<OverlayRef> result;
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
if (mSource != 0)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f);
|
|
|
|
if (result != 0) {
|
|
|
|
mSource = source;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<LayerBuffer::Source> LayerBuffer::getSource() const {
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
return mSource;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<LayerBuffer::Source> LayerBuffer::clearSource() {
|
|
|
|
sp<Source> source;
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
source = mSource;
|
|
|
|
mSource.clear();
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
// LayerBuffer::SurfaceLayerBuffer
|
2009-03-04 03:31:44 +00:00
|
|
|
// ============================================================================
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
|
2009-04-18 02:36:26 +00:00
|
|
|
SurfaceID id, const sp<LayerBuffer>& owner)
|
|
|
|
: LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
unregisterBuffers();
|
|
|
|
}
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
|
2009-04-10 21:24:30 +00:00
|
|
|
const ISurface::BufferHeap& buffers)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBuffer> owner(getOwner());
|
|
|
|
if (owner != 0)
|
2009-03-04 03:31:44 +00:00
|
|
|
return owner->registerBuffers(buffers);
|
|
|
|
return NO_INIT;
|
|
|
|
}
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBuffer> owner(getOwner());
|
|
|
|
if (owner != 0)
|
2009-03-04 03:31:44 +00:00
|
|
|
owner->postBuffer(offset);
|
|
|
|
}
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBuffer> owner(getOwner());
|
|
|
|
if (owner != 0)
|
2009-03-04 03:31:44 +00:00
|
|
|
owner->unregisterBuffers();
|
|
|
|
}
|
|
|
|
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
|
2009-03-04 03:31:44 +00:00
|
|
|
uint32_t w, uint32_t h, int32_t format) {
|
|
|
|
sp<OverlayRef> result;
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBuffer> owner(getOwner());
|
|
|
|
if (owner != 0)
|
2009-03-04 03:31:44 +00:00
|
|
|
result = owner->createOverlay(w, h, format);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// LayerBuffer::Buffer
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
|
|
|
|
: mBufferHeap(buffers)
|
|
|
|
{
|
|
|
|
NativeBuffer& src(mNativeBuffer);
|
2009-12-03 00:23:11 +00:00
|
|
|
src.crop.l = 0;
|
|
|
|
src.crop.t = 0;
|
|
|
|
src.crop.r = buffers.w;
|
|
|
|
src.crop.b = buffers.h;
|
|
|
|
|
|
|
|
src.img.w = buffers.hor_stride ?: buffers.w;
|
|
|
|
src.img.h = buffers.ver_stride ?: buffers.h;
|
|
|
|
src.img.format = buffers.format;
|
|
|
|
src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
|
|
|
|
src.img.handle = 0;
|
2009-10-30 01:29:30 +00:00
|
|
|
|
|
|
|
gralloc_module_t const * module = LayerBuffer::getGrallocModule();
|
|
|
|
if (module && module->perform) {
|
|
|
|
int err = module->perform(module,
|
|
|
|
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
|
|
|
|
buffers.heap->heapID(), buffers.heap->getSize(),
|
|
|
|
offset, buffers.heap->base(),
|
|
|
|
&src.img.handle);
|
|
|
|
|
2009-12-03 00:23:11 +00:00
|
|
|
LOGE_IF(err, "CREATE_HANDLE_FROM_BUFFER (heapId=%d, size=%d, "
|
|
|
|
"offset=%ld, base=%p) failed (%s)",
|
|
|
|
buffers.heap->heapID(), buffers.heap->getSize(),
|
|
|
|
offset, buffers.heap->base(), strerror(-err));
|
2009-10-30 01:29:30 +00:00
|
|
|
}
|
2009-12-03 00:23:11 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
LayerBuffer::Buffer::~Buffer()
|
|
|
|
{
|
2009-06-24 23:55:59 +00:00
|
|
|
NativeBuffer& src(mNativeBuffer);
|
2009-10-30 01:29:30 +00:00
|
|
|
if (src.img.handle) {
|
|
|
|
native_handle_delete(src.img.handle);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// LayerBuffer::Source
|
|
|
|
// LayerBuffer::BufferSource
|
|
|
|
// LayerBuffer::OverlaySource
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
LayerBuffer::Source::Source(LayerBuffer& layer)
|
|
|
|
: mLayer(layer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
LayerBuffer::Source::~Source() {
|
|
|
|
}
|
|
|
|
void LayerBuffer::Source::onDraw(const Region& clip) const {
|
|
|
|
}
|
|
|
|
void LayerBuffer::Source::onTransaction(uint32_t flags) {
|
|
|
|
}
|
|
|
|
void LayerBuffer::Source::onVisibilityResolved(
|
|
|
|
const Transform& planeTransform) {
|
|
|
|
}
|
|
|
|
void LayerBuffer::Source::postBuffer(ssize_t offset) {
|
|
|
|
}
|
|
|
|
void LayerBuffer::Source::unregisterBuffers() {
|
|
|
|
}
|
|
|
|
bool LayerBuffer::Source::transformed() const {
|
|
|
|
return mLayer.mTransformed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
|
|
|
|
const ISurface::BufferHeap& buffers)
|
2009-06-24 01:08:22 +00:00
|
|
|
: Source(layer), mStatus(NO_ERROR), mBufferSize(0)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
if (buffers.heap == NULL) {
|
|
|
|
// this is allowed, but in this case, it is illegal to receive
|
|
|
|
// postBuffer(). The surface just erases the framebuffer with
|
|
|
|
// fully transparent pixels.
|
|
|
|
mBufferHeap = buffers;
|
|
|
|
mLayer.setNeedsBlending(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
|
|
|
|
if (err != NO_ERROR) {
|
|
|
|
LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
|
|
|
|
mStatus = err;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PixelFormatInfo info;
|
|
|
|
err = getPixelFormatInfo(buffers.format, &info);
|
|
|
|
if (err != NO_ERROR) {
|
|
|
|
LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
|
|
|
|
buffers.format, strerror(err));
|
|
|
|
mStatus = err;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffers.hor_stride<0 || buffers.ver_stride<0) {
|
|
|
|
LOGE("LayerBuffer::BufferSource: invalid parameters "
|
|
|
|
"(w=%d, h=%d, xs=%d, ys=%d)",
|
|
|
|
buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
|
|
|
|
mStatus = BAD_VALUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-06 07:08:00 +00:00
|
|
|
if (mLayer.mBlitEngine) {
|
|
|
|
// create our temporary buffer and corresponding EGLImageKHR.
|
|
|
|
// note that the size of this buffer doesn't really matter,
|
|
|
|
// the final image will always be drawn with proper aspect ratio.
|
|
|
|
|
|
|
|
int w = buffers.w;
|
|
|
|
int h = buffers.h;
|
|
|
|
mTempGraphicBuffer.clear();
|
|
|
|
mTempGraphicBuffer = new GraphicBuffer(
|
|
|
|
w, h, HAL_PIXEL_FORMAT_RGBX_8888,
|
|
|
|
GraphicBuffer::USAGE_HW_TEXTURE |
|
|
|
|
GraphicBuffer::USAGE_HW_2D);
|
|
|
|
|
|
|
|
if (mTempGraphicBuffer->initCheck() == NO_ERROR) {
|
|
|
|
NativeBuffer& dst(mTempBuffer);
|
|
|
|
dst.img.w = mTempGraphicBuffer->getStride();
|
|
|
|
dst.img.h = mTempGraphicBuffer->getHeight();
|
|
|
|
dst.img.format = mTempGraphicBuffer->getPixelFormat();
|
|
|
|
dst.img.handle = (native_handle_t *)mTempGraphicBuffer->handle;
|
|
|
|
dst.img.base = 0;
|
|
|
|
dst.crop.l = 0;
|
|
|
|
dst.crop.t = 0;
|
|
|
|
dst.crop.r = mTempGraphicBuffer->getWidth();
|
|
|
|
dst.crop.b = mTempGraphicBuffer->getHeight();
|
|
|
|
} else {
|
|
|
|
mTempGraphicBuffer.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
mBufferHeap = buffers;
|
|
|
|
mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
|
|
|
|
mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
|
|
|
|
mLayer.forceVisibilityTransaction();
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerBuffer::BufferSource::~BufferSource()
|
|
|
|
{
|
2009-06-24 01:08:22 +00:00
|
|
|
if (mTexture.name != -1U) {
|
|
|
|
glDeleteTextures(1, &mTexture.name);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2009-10-27 03:12:37 +00:00
|
|
|
if (mTexture.image != EGL_NO_IMAGE_KHR) {
|
|
|
|
EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
|
|
|
|
eglDestroyImageKHR(dpy, mTexture.image);
|
2009-06-25 22:39:25 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
|
|
|
|
{
|
|
|
|
ISurface::BufferHeap buffers;
|
|
|
|
{ // scope for the lock
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mBufferSourceLock);
|
2009-03-04 03:31:44 +00:00
|
|
|
buffers = mBufferHeap;
|
|
|
|
if (buffers.heap != 0) {
|
|
|
|
const size_t memorySize = buffers.heap->getSize();
|
|
|
|
if ((size_t(offset) + mBufferSize) > memorySize) {
|
|
|
|
LOGE("LayerBuffer::BufferSource::postBuffer() "
|
|
|
|
"invalid buffer (offset=%d, size=%d, heap-size=%d",
|
|
|
|
int(offset), int(mBufferSize), int(memorySize));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<Buffer> buffer;
|
|
|
|
if (buffers.heap != 0) {
|
|
|
|
buffer = new LayerBuffer::Buffer(buffers, offset);
|
|
|
|
if (buffer->getStatus() != NO_ERROR)
|
|
|
|
buffer.clear();
|
|
|
|
setBuffer(buffer);
|
|
|
|
mLayer.invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::BufferSource::unregisterBuffers()
|
|
|
|
{
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mBufferSourceLock);
|
2009-03-04 03:31:44 +00:00
|
|
|
mBufferHeap.heap.clear();
|
|
|
|
mBuffer.clear();
|
|
|
|
mLayer.invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
|
|
|
|
{
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mBufferSourceLock);
|
2009-03-04 03:31:44 +00:00
|
|
|
return mBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
|
|
|
|
{
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mBufferSourceLock);
|
2009-03-04 03:31:44 +00:00
|
|
|
mBuffer = buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LayerBuffer::BufferSource::transformed() const
|
|
|
|
{
|
|
|
|
return mBufferHeap.transform ? true : Source::transformed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
|
|
|
|
{
|
2009-06-24 01:08:22 +00:00
|
|
|
sp<Buffer> ourBuffer(getBuffer());
|
|
|
|
if (UNLIKELY(ourBuffer == 0)) {
|
2009-03-04 03:31:44 +00:00
|
|
|
// nothing to do, we don't have a buffer
|
|
|
|
mLayer.clearWithOpenGL(clip);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-24 04:11:43 +00:00
|
|
|
status_t err = NO_ERROR;
|
|
|
|
NativeBuffer src(ourBuffer->getBuffer());
|
2009-09-09 06:52:08 +00:00
|
|
|
const Rect transformedBounds(mLayer.getTransformedBounds());
|
2009-06-26 00:41:12 +00:00
|
|
|
|
2009-10-27 03:12:37 +00:00
|
|
|
if (UNLIKELY(mTexture.name == -1LU)) {
|
|
|
|
mTexture.name = mLayer.createTexture();
|
|
|
|
}
|
2009-06-24 04:11:43 +00:00
|
|
|
|
2009-10-27 03:12:37 +00:00
|
|
|
#if defined(EGL_ANDROID_image_native_buffer)
|
|
|
|
if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
|
2009-11-06 07:08:00 +00:00
|
|
|
copybit_device_t* copybit = mLayer.mBlitEngine;
|
|
|
|
if (copybit) {
|
|
|
|
// create our EGLImageKHR the first time
|
|
|
|
if (mTexture.image == EGL_NO_IMAGE_KHR) {
|
|
|
|
err = NO_MEMORY;
|
|
|
|
if (mTempGraphicBuffer!=0) {
|
|
|
|
err = mLayer.initializeEglImage(
|
|
|
|
mTempGraphicBuffer, &mTexture);
|
|
|
|
// once the EGLImage has been created (whether it fails
|
|
|
|
// or not) we don't need the graphic buffer reference
|
|
|
|
// anymore.
|
|
|
|
mTempGraphicBuffer.clear();
|
|
|
|
}
|
|
|
|
}
|
2009-06-24 04:11:43 +00:00
|
|
|
|
2009-11-06 07:08:00 +00:00
|
|
|
if (err == NO_ERROR) {
|
|
|
|
// NOTE: Assume the buffer is allocated with the proper USAGE flags
|
|
|
|
const NativeBuffer& dst(mTempBuffer);
|
|
|
|
region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
|
|
|
|
err = copybit->stretch(copybit, &dst.img, &src.img,
|
|
|
|
&dst.crop, &src.crop, &clip);
|
2009-11-03 01:48:33 +00:00
|
|
|
|
2009-11-06 07:08:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = INVALID_OPERATION;
|
|
|
|
}
|
2009-06-24 04:11:43 +00:00
|
|
|
}
|
2009-06-25 05:39:26 +00:00
|
|
|
#endif
|
2009-10-27 03:12:37 +00:00
|
|
|
else {
|
|
|
|
err = INVALID_OPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err != NO_ERROR) {
|
2009-10-29 04:00:29 +00:00
|
|
|
// slower fallback
|
2009-06-24 01:08:22 +00:00
|
|
|
GGLSurface t;
|
|
|
|
t.version = sizeof(GGLSurface);
|
|
|
|
t.width = src.crop.r;
|
|
|
|
t.height = src.crop.b;
|
|
|
|
t.stride = src.img.w;
|
|
|
|
t.vstride= src.img.h;
|
|
|
|
t.format = src.img.format;
|
2009-06-24 23:55:59 +00:00
|
|
|
t.data = (GGLubyte*)src.img.base;
|
2009-06-24 01:08:22 +00:00
|
|
|
const Region dirty(Rect(t.width, t.height));
|
2009-10-06 00:07:12 +00:00
|
|
|
mLayer.loadTexture(&mTexture, dirty, t);
|
2009-05-04 21:17:04 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2009-10-27 03:12:37 +00:00
|
|
|
mTexture.transform = mBufferHeap.transform;
|
|
|
|
mLayer.drawWithOpenGL(clip, mTexture);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
|
|
|
|
sp<OverlayRef>* overlayRef,
|
|
|
|
uint32_t w, uint32_t h, int32_t format)
|
|
|
|
: Source(layer), mVisibilityChanged(false),
|
|
|
|
mOverlay(0), mOverlayHandle(0), mOverlayDevice(0)
|
|
|
|
{
|
|
|
|
overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
|
|
|
|
if (overlay_dev == NULL) {
|
|
|
|
// overlays not supported
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mOverlayDevice = overlay_dev;
|
|
|
|
overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
|
|
|
|
if (overlay == NULL) {
|
|
|
|
// couldn't create the overlay (no memory? no more overlays?)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// enable dithering...
|
|
|
|
overlay_dev->setParameter(overlay_dev, overlay,
|
|
|
|
OVERLAY_DITHER, OVERLAY_ENABLE);
|
|
|
|
|
|
|
|
mOverlay = overlay;
|
|
|
|
mWidth = overlay->w;
|
|
|
|
mHeight = overlay->h;
|
|
|
|
mFormat = overlay->format;
|
|
|
|
mWidthStride = overlay->w_stride;
|
|
|
|
mHeightStride = overlay->h_stride;
|
2009-07-21 23:17:59 +00:00
|
|
|
mInitialized = false;
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
mOverlayHandle = overlay->getHandleRef(overlay);
|
|
|
|
|
2009-09-09 06:52:08 +00:00
|
|
|
sp<OverlayChannel> channel = new OverlayChannel( &layer );
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
*overlayRef = new OverlayRef(mOverlayHandle, channel,
|
|
|
|
mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
|
2009-09-16 19:48:52 +00:00
|
|
|
mLayer.mFlinger->signalEvent();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LayerBuffer::OverlaySource::~OverlaySource()
|
|
|
|
{
|
|
|
|
if (mOverlay && mOverlayDevice) {
|
|
|
|
overlay_control_device_t* overlay_dev = mOverlayDevice;
|
|
|
|
overlay_dev->destroyOverlay(overlay_dev, mOverlay);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-21 04:18:04 +00:00
|
|
|
void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
|
|
|
|
{
|
2009-09-16 02:31:28 +00:00
|
|
|
// this would be where the color-key would be set, should we need it.
|
2009-09-02 06:06:45 +00:00
|
|
|
GLclampx red = 0;
|
|
|
|
GLclampx green = 0;
|
2009-09-16 02:31:28 +00:00
|
|
|
GLclampx blue = 0;
|
2009-09-02 06:06:45 +00:00
|
|
|
mLayer.clearWithOpenGL(clip, red, green, blue, 0);
|
2009-07-21 04:18:04 +00:00
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
|
|
|
|
{
|
|
|
|
const Layer::State& front(mLayer.drawingState());
|
|
|
|
const Layer::State& temp(mLayer.currentState());
|
|
|
|
if (temp.sequence != front.sequence) {
|
|
|
|
mVisibilityChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayerBuffer::OverlaySource::onVisibilityResolved(
|
|
|
|
const Transform& planeTransform)
|
|
|
|
{
|
|
|
|
// this code-path must be as tight as possible, it's called each time
|
|
|
|
// the screen is composited.
|
|
|
|
if (UNLIKELY(mOverlay != 0)) {
|
2009-07-21 23:17:59 +00:00
|
|
|
if (mVisibilityChanged || !mInitialized) {
|
2009-03-04 03:31:44 +00:00
|
|
|
mVisibilityChanged = false;
|
2009-07-21 23:17:59 +00:00
|
|
|
mInitialized = true;
|
2009-09-09 06:52:08 +00:00
|
|
|
const Rect bounds(mLayer.getTransformedBounds());
|
2009-03-04 03:31:44 +00:00
|
|
|
int x = bounds.left;
|
|
|
|
int y = bounds.top;
|
|
|
|
int w = bounds.width();
|
|
|
|
int h = bounds.height();
|
|
|
|
|
|
|
|
// we need a lock here to protect "destroy"
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mOverlaySourceLock);
|
2009-03-04 03:31:44 +00:00
|
|
|
if (mOverlay) {
|
|
|
|
overlay_control_device_t* overlay_dev = mOverlayDevice;
|
|
|
|
overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
|
2009-07-21 23:17:59 +00:00
|
|
|
overlay_dev->setParameter(overlay_dev, mOverlay,
|
2009-03-04 03:31:44 +00:00
|
|
|
OVERLAY_TRANSFORM, mLayer.getOrientation());
|
2009-07-21 04:18:04 +00:00
|
|
|
overlay_dev->commit(overlay_dev, mOverlay);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 06:52:08 +00:00
|
|
|
void LayerBuffer::OverlaySource::destroy()
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
// we need a lock here to protect "onVisibilityResolved"
|
2009-09-09 03:02:47 +00:00
|
|
|
Mutex::Autolock _l(mOverlaySourceLock);
|
2009-09-09 06:52:08 +00:00
|
|
|
if (mOverlay && mOverlayDevice) {
|
2009-03-04 03:31:44 +00:00
|
|
|
overlay_control_device_t* overlay_dev = mOverlayDevice;
|
|
|
|
overlay_dev->destroyOverlay(overlay_dev, mOverlay);
|
|
|
|
mOverlay = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
}; // namespace android
|