From edbf3b6af777b721cd2a1ef461947e51e88241e1 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: auto import from //depot/cupcake/@135843 --- libs/surfaceflinger/LayerBase.cpp | 740 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 740 insertions(+) create mode 100644 libs/surfaceflinger/LayerBase.cpp (limited to 'libs/surfaceflinger/LayerBase.cpp') diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp new file mode 100644 index 0000000..0cf53f7 --- /dev/null +++ b/libs/surfaceflinger/LayerBase.cpp @@ -0,0 +1,740 @@ +/* + * 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. + */ + +#define LOG_TAG "SurfaceFlinger" + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "clz.h" +#include "LayerBase.h" +#include "LayerBlur.h" +#include "SurfaceFlinger.h" +#include "DisplayHardware/DisplayHardware.h" + + +// We don't honor the premultiplied alpha flags, which means that +// premultiplied surface may be composed using a non-premultiplied +// equation. We do this because it may be a lot faster on some hardware +// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1 +#define HONOR_PREMULTIPLIED_ALPHA 0 + +namespace android { + +// --------------------------------------------------------------------------- + +const uint32_t LayerBase::typeInfo = 1; +const char* const LayerBase::typeID = "LayerBase"; + +const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2; +const char* const LayerBaseClient::typeID = "LayerBaseClient"; + +// --------------------------------------------------------------------------- + +Vector LayerBase::deletedTextures; + +int32_t LayerBase::sIdentity = 0; + +LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) + : dpy(display), contentDirty(false), + mFlinger(flinger), + mTransformed(false), + mOrientation(0), + mCanUseCopyBit(false), + mTransactionFlags(0), + mPremultipliedAlpha(true), + mIdentity(uint32_t(android_atomic_inc(&sIdentity))), + mInvalidate(0) +{ + const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); + mFlags = hw.getFlags(); +} + +LayerBase::~LayerBase() +{ +} + +const GraphicPlane& LayerBase::graphicPlane(int dpy) const +{ + return mFlinger->graphicPlane(dpy); +} + +GraphicPlane& LayerBase::graphicPlane(int dpy) +{ + return mFlinger->graphicPlane(dpy); +} + +void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) +{ + uint32_t layerFlags = 0; + if (flags & ISurfaceComposer::eHidden) + layerFlags = ISurfaceComposer::eLayerHidden; + + if (flags & ISurfaceComposer::eNonPremultiplied) + mPremultipliedAlpha = false; + + mCurrentState.z = 0; + mCurrentState.w = w; + mCurrentState.h = h; + mCurrentState.alpha = 0xFF; + mCurrentState.flags = layerFlags; + mCurrentState.sequence = 0; + mCurrentState.transform.set(0, 0); + + // drawing state & current state are identical + mDrawingState = mCurrentState; +} + +void LayerBase::commitTransaction(bool skipSize) { + const uint32_t w = mDrawingState.w; + const uint32_t h = mDrawingState.h; + mDrawingState = mCurrentState; + if (skipSize) { + mDrawingState.w = w; + mDrawingState.h = h; + } +} +void LayerBase::forceVisibilityTransaction() { + // this can be called without SurfaceFlinger.mStateLock, but if we + // can atomically increment the sequence number, it doesn't matter. + android_atomic_inc(&mCurrentState.sequence); + requestTransaction(); +} +bool LayerBase::requestTransaction() { + int32_t old = setTransactionFlags(eTransactionNeeded); + return ((old & eTransactionNeeded) == 0); +} +uint32_t LayerBase::getTransactionFlags(uint32_t flags) { + return android_atomic_and(~flags, &mTransactionFlags) & flags; +} +uint32_t LayerBase::setTransactionFlags(uint32_t flags) { + return android_atomic_or(flags, &mTransactionFlags); +} + +void LayerBase::setSizeChanged(uint32_t w, uint32_t h) { +} + +bool LayerBase::setPosition(int32_t x, int32_t y) { + if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) + return false; + mCurrentState.sequence++; + mCurrentState.transform.set(x, y); + requestTransaction(); + return true; +} +bool LayerBase::setLayer(uint32_t z) { + if (mCurrentState.z == z) + return false; + mCurrentState.sequence++; + mCurrentState.z = z; + requestTransaction(); + return true; +} +bool LayerBase::setSize(uint32_t w, uint32_t h) { + if (mCurrentState.w == w && mCurrentState.h == h) + return false; + setSizeChanged(w, h); + mCurrentState.w = w; + mCurrentState.h = h; + requestTransaction(); + return true; +} +bool LayerBase::setAlpha(uint8_t alpha) { + if (mCurrentState.alpha == alpha) + return false; + mCurrentState.sequence++; + mCurrentState.alpha = alpha; + requestTransaction(); + return true; +} +bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) { + // TODO: check the matrix has changed + mCurrentState.sequence++; + mCurrentState.transform.set( + matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy); + requestTransaction(); + return true; +} +bool LayerBase::setTransparentRegionHint(const Region& transparent) { + // TODO: check the region has changed + mCurrentState.sequence++; + mCurrentState.transparentRegion = transparent; + requestTransaction(); + return true; +} +bool LayerBase::setFlags(uint8_t flags, uint8_t mask) { + const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); + if (mCurrentState.flags == newFlags) + return false; + mCurrentState.sequence++; + mCurrentState.flags = newFlags; + requestTransaction(); + return true; +} + +Rect LayerBase::visibleBounds() const +{ + return mTransformedBounds; +} + +void LayerBase::setVisibleRegion(const Region& visibleRegion) { + // always called from main thread + visibleRegionScreen = visibleRegion; +} + +void LayerBase::setCoveredRegion(const Region& coveredRegion) { + // always called from main thread + coveredRegionScreen = coveredRegion; +} + +uint32_t LayerBase::doTransaction(uint32_t flags) +{ + const Layer::State& front(drawingState()); + const Layer::State& temp(currentState()); + + if (temp.sequence != front.sequence) { + // invalidate and recompute the visible regions if needed + flags |= eVisibleRegion; + this->contentDirty = true; + } + + // Commit the transaction + commitTransaction(flags & eRestartTransaction); + return flags; +} + +Point LayerBase::getPhysicalSize() const +{ + const Layer::State& front(drawingState()); + return Point(front.w, front.h); +} + +void LayerBase::validateVisibility(const Transform& planeTransform) +{ + const Layer::State& s(drawingState()); + const Transform tr(planeTransform * s.transform); + const bool transformed = tr.transformed(); + + const Point size(getPhysicalSize()); + uint32_t w = size.x; + uint32_t h = size.y; + tr.transform(mVertices[0], 0, 0); + tr.transform(mVertices[1], 0, h); + tr.transform(mVertices[2], w, h); + tr.transform(mVertices[3], w, 0); + if (UNLIKELY(transformed)) { + // NOTE: here we could also punt if we have too many rectangles + // in the transparent region + if (tr.preserveRects()) { + // transform the transparent region + transparentRegionScreen = tr.transform(s.transparentRegion); + } else { + // transformation too complex, can't do the transparent region + // optimization. + transparentRegionScreen.clear(); + } + } else { + transparentRegionScreen = s.transparentRegion; + } + + // cache a few things... + mOrientation = tr.getOrientation(); + mTransformedBounds = tr.makeBounds(w, h); + mTransformed = transformed; + mLeft = tr.tx(); + mTop = tr.ty(); + + // see if we can/should use 2D h/w with the new configuration + mCanUseCopyBit = false; + copybit_device_t* copybit = mFlinger->getBlitEngine(); + if (copybit) { + const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG); + const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS); + mCanUseCopyBit = true; + if ((mOrientation < 0) && (step > 1)) { + // arbitrary orientations not supported + mCanUseCopyBit = false; + } else if ((mOrientation > 0) && (step > 90)) { + // 90 deg rotations not supported + mCanUseCopyBit = false; + } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) { + // arbitrary scaling not supported + mCanUseCopyBit = false; + } +#if HONOR_PREMULTIPLIED_ALPHA + else if (needsBlending() && mPremultipliedAlpha) { + // pre-multiplied alpha not supported + mCanUseCopyBit = false; + } +#endif + else { + // here, we determined we can use copybit + if (tr.getType() & SkMatrix::kScale_Mask) { + // and we have scaling + if (!transparentRegionScreen.isRect()) { + // we punt because blending is cheap (h/w) and the region is + // complex, which may causes artifacts when copying + // scaled content + transparentRegionScreen.clear(); + } + } + } + } +} + +void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) +{ +} + +void LayerBase::unlockPageFlip( + const Transform& planeTransform, Region& outDirtyRegion) +{ + if ((android_atomic_and(~1, &mInvalidate)&1) == 1) { + outDirtyRegion.orSelf(visibleRegionScreen); + } +} + +void LayerBase::finishPageFlip() +{ +} + +void LayerBase::invalidate() +{ + if ((android_atomic_or(1, &mInvalidate)&1) == 0) { + mFlinger->signalEvent(); + } +} + +void LayerBase::drawRegion(const Region& reg) const +{ + Region::iterator iterator(reg); + if (iterator) { + Rect r; + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + const int32_t fbWidth = hw.getWidth(); + const int32_t fbHeight = hw.getHeight(); + const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 }, + { fbWidth, fbHeight }, { 0, fbHeight } }; + glVertexPointer(2, GL_SHORT, 0, vertices); + while (iterator.iterate(&r)) { + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + } +} + +void LayerBase::draw(const Region& inClip) const +{ + // invalidate the region we'll update + Region clip(inClip); // copy-on-write, so no-op most of the time + + // Remove the transparent area from the clipping region + const State& s = drawingState(); + if (LIKELY(!s.transparentRegion.isEmpty())) { + clip.subtract(transparentRegionScreen); + if (clip.isEmpty()) { + // usually this won't happen because this should be taken care of + // by SurfaceFlinger::computeVisibleRegions() + return; + } + } + + // reset GL state + glEnable(GL_SCISSOR_TEST); + + onDraw(clip); + + /* + glDisable(GL_TEXTURE_2D); + glDisable(GL_DITHER); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glColor4x(0, 0x8000, 0, 0x10000); + drawRegion(transparentRegionScreen); + glDisable(GL_BLEND); + */ +} + +GLuint LayerBase::createTexture() const +{ + GLuint textureName = -1; + glGenTextures(1, &textureName); + glBindTexture(GL_TEXTURE_2D, textureName); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (mFlags & DisplayHardware::SLOW_CONFIG) { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } else { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + return textureName; +} + +void LayerBase::clearWithOpenGL(const Region& clip) const +{ + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + const uint32_t fbHeight = hw.getHeight(); + glColor4x(0,0,0,0); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glDisable(GL_DITHER); + Rect r; + Region::iterator iterator(clip); + if (iterator) { + glEnable(GL_SCISSOR_TEST); + glVertexPointer(2, GL_FIXED, 0, mVertices); + while (iterator.iterate(&r)) { + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + } +} + +void LayerBase::drawWithOpenGL(const Region& clip, + GLint textureName, const GGLSurface& t, int transform) const +{ + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + const uint32_t fbHeight = hw.getHeight(); + const State& s(drawingState()); + + // bind our texture + validateTexture(textureName); + glEnable(GL_TEXTURE_2D); + + // Dithering... + if (s.flags & ISurfaceComposer::eLayerDither) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } + + if (UNLIKELY(s.alpha < 0xFF)) { + // We have an alpha-modulation. We need to modulate all + // texture components by alpha because we're always using + // premultiplied alpha. + + // If the texture doesn't have an alpha channel we can + // use REPLACE and switch to non premultiplied alpha + // blending (SRCA/ONE_MINUS_SRCA). + + GLenum env, src; + if (needsBlending()) { + env = GL_MODULATE; + src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + } else { + env = GL_REPLACE; + src = GL_SRC_ALPHA; + } + const GGLfixed alpha = (s.alpha << 16)/255; + glColor4x(alpha, alpha, alpha, alpha); + glEnable(GL_BLEND); + glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env); + } else { + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor4x(0x10000, 0x10000, 0x10000, 0x10000); + if (needsBlending()) { + GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + glEnable(GL_BLEND); + glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } + } + + if (UNLIKELY(transformed() + || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) + { + //StopWatch watch("GL transformed"); + Region::iterator iterator(clip); + if (iterator) { + // always use high-quality filtering with fast configurations + bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG); + if (!fast && s.flags & ISurfaceComposer::eLayerFilter) { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + const GLfixed texCoords[4][2] = { + { 0, 0 }, + { 0, 0x10000 }, + { 0x10000, 0x10000 }, + { 0x10000, 0 } + }; + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + if (transform == HAL_TRANSFORM_ROT_90) { + glTranslatef(0, 1, 0); + glRotatef(-90, 0, 0, 1); + } + + if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) { + // find the smallest power-of-two that will accommodate our surface + GLuint tw = 1 << (31 - clz(t.width)); + GLuint th = 1 << (31 - clz(t.height)); + if (tw < t.width) tw <<= 1; + if (th < t.height) th <<= 1; + // this divide should be relatively fast because it's + // a power-of-two (optimized path in libgcc) + GLfloat ws = GLfloat(t.width) /tw; + GLfloat hs = GLfloat(t.height)/th; + glScalef(ws, hs, 1.0f); + } + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FIXED, 0, mVertices); + glTexCoordPointer(2, GL_FIXED, 0, texCoords); + + Rect r; + while (iterator.iterate(&r)) { + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + if (!fast && s.flags & ISurfaceComposer::eLayerFilter) { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } else { + Region::iterator iterator(clip); + if (iterator) { + Rect r; + GLint crop[4] = { 0, t.height, t.width, -t.height }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + int x = tx(); + int y = ty(); + y = fbHeight - (y + t.height); + while (iterator.iterate(&r)) { + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawTexiOES(x, y, 0, t.width, t.height); + } + } + } +} + +void LayerBase::validateTexture(GLint textureName) const +{ + glBindTexture(GL_TEXTURE_2D, textureName); + // TODO: reload the texture if needed + // this is currently done in loadTexture() below +} + +void LayerBase::loadTexture(const Region& dirty, + GLint textureName, const GGLSurface& t, + GLuint& textureWidth, GLuint& textureHeight) const +{ + // TODO: defer the actual texture reload until LayerBase::validateTexture + // is called. + + uint32_t flags = mFlags; + glBindTexture(GL_TEXTURE_2D, textureName); + + GLuint tw = t.width; + GLuint th = t.height; + + /* + * In OpenGL ES we can't specify a stride with glTexImage2D (however, + * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of + * stride). + * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we + * need to do something reasonable (here creating a bigger texture). + * + * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); + * + * This situation doesn't happen often, but some h/w have a limitation + * for their framebuffer (eg: must be multiple of 8 pixels), and + * we need to take that into account when using these buffers as + * textures. + * + * This should never be a problem with POT textures + */ + + tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4); + + /* + * round to POT if needed + */ + + GLuint texture_w = tw; + GLuint texture_h = th; + if (!(flags & DisplayHardware::NPOT_EXTENSION)) { + // find the smallest power-of-two that will accommodate our surface + texture_w = 1 << (31 - clz(t.width)); + texture_h = 1 << (31 - clz(t.height)); + if (texture_w < t.width) texture_w <<= 1; + if (texture_h < t.height) texture_h <<= 1; + if (texture_w != tw || texture_h != th) { + // we can't use DIRECT_TEXTURE since we changed the size + // of the texture + flags &= ~DisplayHardware::DIRECT_TEXTURE; + } + } + + if (flags & DisplayHardware::DIRECT_TEXTURE) { + // here we're guaranteed that texture_{w|h} == t{w|h} + if (t.format == GGL_PIXEL_FORMAT_RGB_565) { + glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, + GL_RGB, tw, th, 0, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { + glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, + GL_RGBA, tw, th, 0, + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { + glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, + GL_RGBA, tw, th, 0, + GL_RGBA, GL_UNSIGNED_BYTE, t.data); + } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) { + // TODO: add GL_BGRA extension + } else { + // oops, we don't handle this format, try the regular path + goto regular; + } + textureWidth = tw; + textureHeight = th; + } else { +regular: + Rect bounds(dirty.bounds()); + GLvoid* data = 0; + if (texture_w!=textureWidth || texture_h!=textureHeight) { + // texture size changed, we need to create a new one + + if (!textureWidth || !textureHeight) { + // this is the first time, load the whole texture + if (texture_w==tw && texture_h==th) { + // we can do it one pass + data = t.data; + } else { + // we have to create the texture first because it + // doesn't match the size of the buffer + bounds.set(Rect(tw, th)); + } + } + + if (t.format == GGL_PIXEL_FORMAT_RGB_565) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGB, texture_w, texture_h, 0, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, texture_w, texture_h, 0, + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, texture_w, texture_h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP || + t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) { + // just show the Y plane of YUV buffers + data = t.data; + glTexImage2D(GL_TEXTURE_2D, 0, + GL_LUMINANCE, texture_w, texture_h, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, data); + } else { + // oops, we don't handle this format! + LOGE("layer %p, texture=%d, using format %d, which is not " + "supported by the GL", this, textureName, t.format); + textureName = -1; + } + textureWidth = texture_w; + textureHeight = texture_h; + } + if (!data && textureName>=0) { + if (t.format == GGL_PIXEL_FORMAT_RGB_565) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + t.data + bounds.top*t.width*2); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, + t.data + bounds.top*t.width*2); + } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, bounds.top, t.width, bounds.height(), + GL_RGBA, GL_UNSIGNED_BYTE, + t.data + bounds.top*t.width*4); + } + } + } +} + +bool LayerBase::canUseCopybit() const +{ + return mCanUseCopyBit; +} + +// --------------------------------------------------------------------------- + +LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, + Client* c, int32_t i) + : LayerBase(flinger, display), client(c), + lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ), + mIndex(i) +{ + if (client) { + client->bindLayer(this, i); + + // Initialize this layer's control block + memset(this->lcblk, 0, sizeof(layer_cblk_t)); + this->lcblk->identity = mIdentity; + Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t)); + Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t)); + } +} + +LayerBaseClient::~LayerBaseClient() +{ + if (client) { + client->free(mIndex); + } +} + +int32_t LayerBaseClient::serverIndex() const { + if (client) { + return (client->cid<<16)|mIndex; + } + return 0xFFFF0000 | mIndex; +} + +sp LayerBaseClient::getSurface() const +{ + return new Surface(clientIndex(), mIdentity); +} + + +// --------------------------------------------------------------------------- + +}; // namespace android -- cgit v1.1