// buffer source stuff
void BufferSourceThread::handleBuffer(sp<GraphicBuffer> &graphic_buffer, uint8_t *buffer, unsigned int count) {
    int size;
    buffer_info_t info;
    int fd = -1;
    char fn[256];

    if (!graphic_buffer.get()) {
        printf("Invalid graphic_buffer!\n");
        return;
    }

    size = calcBufSize((int)graphic_buffer->getPixelFormat(),
                              graphic_buffer->getWidth(),
                              graphic_buffer->getHeight());
    if (size <= 0) {
        printf("Can't get size!\n");
        return;
    }

    if (!buffer) {
        printf("Invalid mapped buffer!\n");
        return;
    }

    info.size = size;
    info.width = graphic_buffer->getWidth();
    info.height = graphic_buffer->getHeight();
    info.format = graphic_buffer->getPixelFormat();
    info.buf = graphic_buffer;

    {
        Mutex::Autolock lock(mReturnedBuffersMutex);
        if (mReturnedBuffers.size() >= kReturnedBuffersMaxCapacity) mReturnedBuffers.removeAt(0);
    }
    mReturnedBuffers.add(info);

    // Do not write buffer to file if we are streaming capture
    // It adds too much latency
    if (!mRestartCapture) {
        fn[0] = 0;
        sprintf(fn, "/sdcard/img%03d.raw", count);
        fd = open(fn, O_CREAT | O_WRONLY | O_TRUNC, 0777);
        if (fd >= 0) {
            if (size != write(fd, buffer, size)) {
                printf("Bad Write int a %s error (%d)%s\n", fn, errno, strerror(errno));
            }
            printf("%s: buffer=%08X, size=%d stored at %s\n",
                        __FUNCTION__, (int)buffer, info.size, fn);
            close(fd);
        } else {
            printf("error opening or creating %s\n", fn);
        }
    }
}
void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
    if (mImage) {
        return;
    }

    mImage = new Image(buffer);

    if (mImage->getTexture()) {
        Caches& caches = Caches::getInstance();

        mTexture = new Texture(caches);
        mTexture->id = mImage->getTexture();
        mTexture->width = buffer->getWidth();
        mTexture->height = buffer->getHeight();

        createEntries(caches, map, count);
    } else {
        ALOGW("Could not create atlas image");

        delete mImage;
        mImage = NULL;
        mTexture = NULL;
    }

    mGenerationId++;
}
status_t SurfaceTexture::convert(sp<GraphicBuffer> &srcBuf, sp<GraphicBuffer> &dstBuf) {
    copybit_image_t dstImg;
    dstImg.w = dstBuf->getWidth();
    dstImg.h = dstBuf->getHeight();
    dstImg.format = dstBuf->getPixelFormat();
    dstImg.handle = (native_handle_t*) dstBuf->getNativeBuffer()->handle;

    copybit_image_t srcImg;
    srcImg.w = srcBuf->getWidth();
    srcImg.h = srcBuf->getHeight();
    srcImg.format = srcBuf->getPixelFormat();
    srcImg.base = NULL;
    srcImg.handle = (native_handle_t*) srcBuf->getNativeBuffer()->handle;

    copybit_rect_t dstCrop;
    dstCrop.l = 0;
    dstCrop.t = 0;
    dstCrop.r = dstBuf->getWidth();
    dstCrop.b = dstBuf->getHeight();

    copybit_rect_t srcCrop;
    srcCrop.l = 0;
    srcCrop.t = 0;
    srcCrop.r = srcBuf->getWidth();
    srcCrop.b = srcBuf->getHeight();

    region_iterator clip(Region(Rect(dstCrop.r, dstCrop.b)));
    mBlitEngine->set_parameter(mBlitEngine, COPYBIT_TRANSFORM, 0);
    mBlitEngine->set_parameter(mBlitEngine, COPYBIT_PLANE_ALPHA, 0xFF);
    mBlitEngine->set_parameter(mBlitEngine, COPYBIT_DITHER, COPYBIT_ENABLE);

    int err = mBlitEngine->stretch(
            mBlitEngine, &dstImg, &srcImg, &dstCrop, &srcCrop, &clip);
    if (err != 0) {
        ALOGE("Error: Blit stretch operation failed, retry once (err:%d)", err);
        // TODO: Bad boy doing hacks here, blit stretch operation should be completely fixed.
        int err = mBlitEngine->stretch(
            mBlitEngine, &dstImg, &srcImg, &dstCrop, &srcCrop, &clip);
        if (err != 0) {
            ALOGE("Error: Blit stretch operation failed (err:%d)", err);
            return UNKNOWN_ERROR;
        }
    }
    return OK;
}
Example #4
0
void RenderEngine::getHwInverseMatrix(const sp<const DisplayDevice>& hw, mat4& inv) {
    // get inversed width/height
    const float iw = 2.0 / hw->getWidth();
    const float ih = 2.0 / hw->getHeight();

    // map to required matrix
    // since in display case, we need only orientation, but not free-form
    // so just use pre-calculated cases in switch

    // setup fixed part first
    inv[0][2] =  0;    inv[0][3] =  0;
    inv[1][2] =  0;    inv[1][3] =  0;
    inv[2][2] = -2;    inv[2][3] =  0;
    inv[3][2] = -1;    inv[3][3] =  1;

    // switch map to set x/y matrix entries
    switch (hw->getHwOrientation()) {
        case DisplayState::eOrientationDefault:
            inv[0][0] =  iw;    inv[0][1] =   0;
            inv[1][0] =   0;    inv[1][1] = -ih;
            inv[2][0] =   0;    inv[2][1] =   0;
            inv[3][0] =  -1;    inv[3][1] =   1;
            break;
        case DisplayState::eOrientation90:
            inv[0][0] =   0;    inv[0][1] = -iw;
            inv[1][0] = -ih;    inv[1][1] =   0;
            inv[2][0] =   0;    inv[2][1] =   0;
            inv[3][0] =   1;    inv[3][1] =   1;
            break;
        case DisplayState::eOrientation180:
            inv[0][0] = -iw;    inv[0][1] =   0;
            inv[1][0] =   0;    inv[1][1] =  ih;
            inv[2][0] =   0;    inv[2][1] =   0;
            inv[3][0] =   1;    inv[3][1] =  -1;
            break;
        case DisplayState::eOrientation270:
            inv[0][0] =   0;    inv[0][1] =  iw;
            inv[1][0] =  ih;    inv[1][1] =   0;
            inv[2][0] =   0;    inv[2][1] =   0;
            inv[3][0] =  -1;    inv[3][1] =  -1;
            break;
        default:
            XLOGW("[%s] unknown orientation:%d, set to default",
                __func__, hw->getHwOrientation());
            inv[0][0] =  iw;    inv[0][1] =   0;
            inv[1][0] =   0;    inv[1][1] = -ih;
            inv[2][0] =   0;    inv[2][1] =   0;
            inv[3][0] =  -1;    inv[3][1] =   1;
    }
}
void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
        GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
{
    const uint32_t fbHeight = hw->getHeight();
    glColor4f(red,green,blue,alpha);

    glDisable(GL_TEXTURE_EXTERNAL_OES);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    LayerMesh mesh;
    computeGeometry(hw, &mesh);

    glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
    glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
}
void LayerBase::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
{
    const Layer::State& s(drawingState());
    const Transform tr(hw->getTransform() * s.transform);
    const uint32_t hw_h = hw->getHeight();
    Rect win(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        win.intersect(s.active.crop, &win);
    }
    if (mesh) {
        tr.transform(mesh->mVertices[0], win.left,  win.top);
        tr.transform(mesh->mVertices[1], win.left,  win.bottom);
        tr.transform(mesh->mVertices[2], win.right, win.bottom);
        tr.transform(mesh->mVertices[3], win.right, win.top);
        for (size_t i=0 ; i<4 ; i++) {
            mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
        }
    }
}
Example #7
0
void LayerScreenshot::computeGeometryOrient(
    const sp<const DisplayDevice>& hw, LayerMesh* mesh, int orient) const
{
    const Layer::State& s(drawingState());

    int hw_w = hw->getWidth();
    int hw_h = hw->getHeight();

    uint32_t flags = Transform::ROT_0;
    switch ((4 - orient) % 4) {
        case DisplayState::eOrientation90:
            flags = Transform::ROT_90;
            break;
        case DisplayState::eOrientation180:
            flags = Transform::ROT_180;
            break;
        case DisplayState::eOrientation270:
            flags = Transform::ROT_270;
            break;
        default:
            XLOGE("[%s] invalid orientation: %d", __func__, orient);
            break;
    }

    Transform orientTransform;
    if (orient & DisplayState::eOrientationSwapMask) {
        orientTransform.set(flags, hw_h, hw_w);
    } else {
        orientTransform.set(flags, hw_w, hw_h);
    }

    const Transform tr(hw->getTransform() * s.transform * orientTransform);

    if (mesh) {
        tr.transform(mesh->mVertices[0], 0, 0);
        tr.transform(mesh->mVertices[1], 0, hw_h);
        tr.transform(mesh->mVertices[2], hw_w, hw_h);
        tr.transform(mesh->mVertices[3], hw_w, 0);
        for (size_t i=0 ; i<4 ; i++) {
            mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
        }
    }
}
Example #8
0
void Layer::drawWithOpenGL(
        const sp<const DisplayDevice>& hw, const Region& clip) const {
    const uint32_t fbHeight = hw->getHeight();
    const State& s(getDrawingState());

    computeGeometry(hw, mMesh);

    /*
     * NOTE: the way we compute the texture coordinates here produces
     * different results than when we take the HWC path -- in the later case
     * the "source crop" is rounded to texel boundaries.
     * This can produce significantly different results when the texture
     * is scaled by a large amount.
     *
     * The GL code below is more logical (imho), and the difference with
     * HWC is due to a limitation of the HWC API to integers -- a question
     * is suspend is whether we should ignore this problem or revert to
     * GL composition when a buffer scaling is applied (maybe with some
     * minimal value)? Or, we could make GL behave like HWC -- but this feel
     * like more of a hack.
     */
    const Rect win(computeBounds());

    float left   = float(win.left)   / float(s.active.w);
    float top    = float(win.top)    / float(s.active.h);
    float right  = float(win.right)  / float(s.active.w);
    float bottom = float(win.bottom) / float(s.active.h);

    // TODO: we probably want to generate the texture coords with the mesh
    // here we assume that we only have 4 vertices
    Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
    texCoords[0] = vec2(left, 1.0f - top);
    texCoords[1] = vec2(left, 1.0f - bottom);
    texCoords[2] = vec2(right, 1.0f - bottom);
    texCoords[3] = vec2(right, 1.0f - top);

    RenderEngine& engine(mFlinger->getRenderEngine());
    engine.setDither(needsDithering());
    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(), s.alpha);
    engine.drawMesh(mMesh);
    engine.disableBlending();
}
void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh) const
{
    const Layer::State& s(getDrawingState());
    const Transform tr(hw->getTransform() * s.transform);
    const uint32_t hw_h = hw->getHeight();
    Rect win(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        win.intersect(s.active.crop, &win);
    }
    // subtract the transparent region and snap to the bounds
    win = reduce(win, s.activeTransparentRegion);

    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
    position[0] = tr.transform(win.left,  win.top);
    position[1] = tr.transform(win.left,  win.bottom);
    position[2] = tr.transform(win.right, win.bottom);
    position[3] = tr.transform(win.right, win.top);
    for (size_t i=0 ; i<4 ; i++) {
        position[i].y = hw_h - position[i].y;
    }
}
void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
    if (mImage) {
        return;
    }

    ATRACE_NAME("AssetAtlas::init");

    mImage = new Image(buffer);
    if (mImage->getTexture()) {
        if (!mTexture) {
            Caches& caches = Caches::getInstance();
            mTexture = new Texture(caches);
            mTexture->wrap(mImage->getTexture(),
                    buffer->getWidth(), buffer->getHeight(), GL_RGBA);
            createEntries(caches, map, count);
        }
    } else {
        ALOGW("Could not create atlas image");
        terminate();
    }
}
Example #11
0
void Layer::drawProtectedImage(const sp<const DisplayDevice>& hw, const Region& clip) const
{
    const State& s(getDrawingState());
    const Transform tr(hw->getTransform() * s.transform);
    const uint32_t hw_h = hw->getHeight();
    Rect win(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        win.intersect(s.active.crop, &win);
    }

    int w = win.getWidth();
    int h = win.getHeight();
    if (w > h) {
        win.left += ((w - h) / 2);
        win.right = win.left + h;
    } else {
        win.top += ((h - w) / 2);
        win.bottom = win.top + w;
    }

    Mesh::VertexArray<vec2> position(mMesh.getPositionArray<vec2>());
    position[0] = tr.transform(win.left,  win.top);
    position[1] = tr.transform(win.left,  win.bottom);
    position[2] = tr.transform(win.right, win.bottom);
    position[3] = tr.transform(win.right, win.top);
    for (size_t i=0 ; i<4 ; i++) {
        position[i].y = hw_h - position[i].y;
    }

    Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
    texCoords[0] = vec2(0, 0);
    texCoords[1] = vec2(0, 1);
    texCoords[2] = vec2(1, 1);
    texCoords[3] = vec2(1, 0);

    RenderEngine& engine(mFlinger->getRenderEngine());
    engine.setupLayerProtectedImage();
    engine.drawMesh(mMesh);
    engine.disableBlending();
}
Example #12
0
int GLWorker::Compositor::Composite(hwc_layer_1 *layers, size_t num_layers,
                                    sp<GraphicBuffer> framebuffer) {
  ATRACE_CALL();
  int ret = 0;
  size_t i;
  std::vector<AutoEGLImageAndGLTexture> layer_textures;
  std::vector<RenderingCommand> commands;

  if (num_layers == 0) {
    return -EALREADY;
  }

  GLint frame_width = framebuffer->getWidth();
  GLint frame_height = framebuffer->getHeight();
  EGLSyncKHR finished_sync;

  AutoEGLImageKHR egl_fb_image(
      eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                        (EGLClientBuffer)framebuffer->getNativeBuffer(),
                        NULL /* no attribs */),
      EGLImageDeleter(egl_display_));

  if (egl_fb_image.get() == EGL_NO_IMAGE_KHR) {
    ALOGE("Failed to make image from target buffer: %s", GetEGLError());
    return -EINVAL;
  }

  GLuint gl_fb_tex;
  glGenTextures(1, &gl_fb_tex);
  AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
  glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
                               (GLeglImageOES)egl_fb_image.get());
  glBindTexture(GL_TEXTURE_2D, 0);

  GLuint gl_fb;
  glGenFramebuffers(1, &gl_fb);
  AutoGLFramebuffer gl_fb_auto(gl_fb);
  glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                         gl_fb_tex, 0);

  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
    ALOGE("Failed framebuffer check for created target buffer: %s",
          GetGLFramebufferError());
    return -EINVAL;
  }

  for (i = 0; i < num_layers; i++) {
    const struct hwc_layer_1 *layer = &layers[i];

    if (ret) {
      if (layer->acquireFenceFd >= 0)
        close(layer->acquireFenceFd);
      continue;
    }

    layer_textures.emplace_back(egl_display_);
    ret = CreateTextureFromHandle(egl_display_, layer->handle,
                                  &layer_textures.back());
    if (!ret) {
      ret = EGLFenceWait(egl_display_, layer->acquireFenceFd);
    }
    if (ret) {
      layer_textures.pop_back();
      ret = -EINVAL;
    }
  }

  if (ret)
    return ret;

  ConstructCommands(layers, num_layers, &commands);

  glViewport(0, 0, frame_width, frame_height);

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_.get());
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4,
                        (void *)(sizeof(float) * 2));
  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);
  glEnable(GL_SCISSOR_TEST);

  for (const RenderingCommand &cmd : commands) {
    if (cmd.texture_count <= 0) {
      continue;
    }

    // TODO(zachr): handle the case of too many overlapping textures for one
    // area by falling back to rendering as many layers as possible using
    // multiple blending passes.
    if (cmd.texture_count > blend_programs_.size()) {
      ALOGE("Too many layers to render in one area");
      continue;
    }

    GLint program = blend_programs_[cmd.texture_count - 1].get();
    glUseProgram(program);
    GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport");
    GLint gl_tex_loc = glGetUniformLocation(program, "uLayerTextures");
    GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop");
    GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha");
    glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width,
                cmd.bounds[1] / (float)frame_height,
                (cmd.bounds[2] - cmd.bounds[0]) / (float)frame_width,
                (cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height);

    for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
      const RenderingCommand::TextureSource &src = cmd.textures[src_index];
      glUniform1f(gl_alpha_loc + src_index, src.alpha);
      glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0],
                  src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0],
                  src.crop_bounds[3] - src.crop_bounds[1]);

      glUniform1i(gl_tex_loc + src_index, src_index);
      glActiveTexture(GL_TEXTURE0 + src_index);
      glBindTexture(GL_TEXTURE_2D,
                    layer_textures[src.texture_index].texture.get());
    }

    glScissor(cmd.bounds[0], cmd.bounds[1], cmd.bounds[2] - cmd.bounds[0],
              cmd.bounds[3] - cmd.bounds[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
      glActiveTexture(GL_TEXTURE0 + src_index);
      glBindTexture(GL_TEXTURE_2D, 0);
    }
  }

  glDisable(GL_SCISSOR_TEST);
  glActiveTexture(GL_TEXTURE0);
  glDisableVertexAttribArray(0);
  glDisableVertexAttribArray(1);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glUseProgram(0);

  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  return ret;
}
            virtual bool reject(const sp<GraphicBuffer>& buf,
                    const BufferQueue::BufferItem& item) {
                if (buf == NULL) {
                    return false;
                }

                uint32_t bufWidth  = buf->getWidth();
                uint32_t bufHeight = buf->getHeight();

                // check that we received a buffer of the right size
                // (Take the buffer's orientation into account)
                if (item.mTransform & Transform::ROT_90) {
                    swap(bufWidth, bufHeight);
                }


                bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
                if (front.active != front.requested) {

                    if (isFixedSize ||
                            (bufWidth == front.requested.w &&
                             bufHeight == front.requested.h))
                    {
                        // Here we pretend the transaction happened by updating the
                        // current and drawing states. Drawing state is only accessed
                        // in this thread, no need to have it locked
                        front.active = front.requested;

                        // We also need to update the current state so that
                        // we don't end-up overwriting the drawing state with
                        // this stale current state during the next transaction
                        //
                        // NOTE: We don't need to hold the transaction lock here
                        // because State::active is only accessed from this thread.
                        current.active = front.active;

                        // recompute visible region
                        recomputeVisibleRegions = true;
                    }

                    ALOGD_IF(DEBUG_RESIZE,
                            "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n"
                            "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                            "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
                            this, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
                            front.active.w, front.active.h,
                            front.active.crop.left,
                            front.active.crop.top,
                            front.active.crop.right,
                            front.active.crop.bottom,
                            front.active.crop.getWidth(),
                            front.active.crop.getHeight(),
                            front.requested.w, front.requested.h,
                            front.requested.crop.left,
                            front.requested.crop.top,
                            front.requested.crop.right,
                            front.requested.crop.bottom,
                            front.requested.crop.getWidth(),
                            front.requested.crop.getHeight());
                }

                if (!isFixedSize) {
                    if (front.active.w != bufWidth ||
                        front.active.h != bufHeight) {
                        // reject this buffer
                        return true;
                    }
                }
                return false;
            }
void Layer::setGeometry(
    const sp<const DisplayDevice>& hw,
        HWComposer::HWCLayerInterface& layer)
{
    layer.setDefaultState();

    // enable this layer
    layer.setSkip(false);

    if (isSecure() && !hw->isSecure()) {
        layer.setSkip(true);
    }

    // this gives us only the "orientation" component of the transform
    const State& s(getDrawingState());
    if (!isOpaque() || s.alpha != 0xFF) {
        layer.setBlending(mPremultipliedAlpha ?
                HWC_BLENDING_PREMULT :
                HWC_BLENDING_COVERAGE);
    }

    // apply the layer's transform, followed by the display's global transform
    // here we're guaranteed that the layer's transform preserves rects
    Rect frame(s.transform.transform(computeBounds()));
    frame.intersect(hw->getViewport(), &frame);
    const Transform& tr(hw->getTransform());
    layer.setFrame(tr.transform(frame));
#ifdef QCOM_BSP
    // set dest_rect to display width and height, if external_only flag
    // for the layer is enabled or if its yuvLayer in extended mode.
    uint32_t x = 0, y = 0;
    uint32_t w = hw->getWidth();
    uint32_t h = hw->getHeight();
    bool extendedMode = SurfaceFlinger::isExtendedMode();
    if(isExtOnly()) {
        // Position: fullscreen for ext_only
        Rect r(0, 0, w, h);
        layer.setFrame(r);
    } else if(hw->getDisplayType() > 0 && (extendedMode && isYuvLayer())) {
        // Need to position the video full screen on external with aspect ratio
        Rect r = getAspectRatio(hw, s.active.w, s.active.h);
        layer.setFrame(r);
    }
#endif
    layer.setCrop(computeCrop(hw));
    layer.setPlaneAlpha(s.alpha);

    /*
     * Transformations are applied in this order:
     * 1) buffer orientation/flip/mirror
     * 2) state transformation (window manager)
     * 3) layer orientation (screen orientation)
     * (NOTE: the matrices are multiplied in reverse order)
     */

    const Transform bufferOrientation(mCurrentTransform);
    Transform transform(tr * s.transform * bufferOrientation);

    if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
        /*
         * the code below applies the display's inverse transform to the buffer
         */
        uint32_t invTransform = hw->getOrientationTransform();
        // calculate the inverse transform
        if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
        }
        // and apply to the current transform
        transform = transform * Transform(invTransform);
    }

    // this gives us only the "orientation" component of the transform
    const uint32_t orientation = transform.getOrientation();
    if (orientation & Transform::ROT_INVALID) {
        // we can only handle simple transformation
        layer.setSkip(true);
    } else {
        layer.setTransform(orientation);
    }
}
            virtual bool reject(const sp<GraphicBuffer>& buf,
                    const IGraphicBufferConsumer::BufferItem& item) {
                if (buf == NULL) {
                    return false;
                }

                uint32_t bufWidth  = buf->getWidth();
                uint32_t bufHeight = buf->getHeight();

                // check that we received a buffer of the right size
                // (Take the buffer's orientation into account)
                if (item.mTransform & Transform::ROT_90) {
                    swap(bufWidth, bufHeight);
                }

                bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
                if (front.active != front.requested) {

                    if (isFixedSize ||
                            (bufWidth == front.requested.w &&
                             bufHeight == front.requested.h))
                    {
                        // Here we pretend the transaction happened by updating the
                        // current and drawing states. Drawing state is only accessed
                        // in this thread, no need to have it locked
                        front.active = front.requested;

                        // We also need to update the current state so that
                        // we don't end-up overwriting the drawing state with
                        // this stale current state during the next transaction
                        //
                        // NOTE: We don't need to hold the transaction lock here
                        // because State::active is only accessed from this thread.
                        current.active = front.active;

                        // recompute visible region
                        recomputeVisibleRegions = true;
                    }

                    ALOGD_IF(DEBUG_RESIZE,
                            "latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
                            "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                            "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
                            bufWidth, bufHeight, item.mTransform, item.mScalingMode,
                            front.active.w, front.active.h,
                            front.active.crop.left,
                            front.active.crop.top,
                            front.active.crop.right,
                            front.active.crop.bottom,
                            front.active.crop.getWidth(),
                            front.active.crop.getHeight(),
                            front.requested.w, front.requested.h,
                            front.requested.crop.left,
                            front.requested.crop.top,
                            front.requested.crop.right,
                            front.requested.crop.bottom,
                            front.requested.crop.getWidth(),
                            front.requested.crop.getHeight());
                }

                if (!isFixedSize) {
                    if (front.active.w != bufWidth ||
                        front.active.h != bufHeight) {
                        // reject this buffer
                        //ALOGD("rejecting buffer: bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
                        //        bufWidth, bufHeight, front.active.w, front.active.h);
                        return true;
                    }
                }

                // if the transparent region has changed (this test is
                // conservative, but that's fine, worst case we're doing
                // a bit of extra work), we latch the new one and we
                // trigger a visible-region recompute.
                if (!front.activeTransparentRegion.isTriviallyEqual(
                        front.requestedTransparentRegion)) {
                    front.activeTransparentRegion = front.requestedTransparentRegion;

                    // We also need to update the current state so that
                    // we don't end-up overwriting the drawing state with
                    // this stale current state during the next transaction
                    //
                    // NOTE: We don't need to hold the transaction lock here
                    // because State::active is only accessed from this thread.
                    current.activeTransparentRegion = front.activeTransparentRegion;

                    // recompute visible region
                    recomputeVisibleRegions = true;
                }

                return false;
            }
void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const
{
    const uint32_t fbHeight = hw->getHeight();
    const State& s(drawingState());

    GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
    if (CC_UNLIKELY(s.alpha < 0xFF)) {
        const GLfloat alpha = s.alpha * (1.0f/255.0f);
        if (mPremultipliedAlpha) {
            glColor4f(alpha, alpha, alpha, alpha);
        } else {
            glColor4f(1, 1, 1, alpha);
        }
        glEnable(GL_BLEND);
        glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    } else {
        glColor4f(1, 1, 1, 1);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        if (!isOpaque()) {
            glEnable(GL_BLEND);
            glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        } else {
            glDisable(GL_BLEND);
        }
    }

    LayerMesh mesh;
    computeGeometry(hw, &mesh);

    // TODO: we probably want to generate the texture coords with the mesh
    // here we assume that we only have 4 vertices

    struct TexCoords {
        GLfloat u;
        GLfloat v;
    };

    Rect win(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        win.intersect(s.active.crop, &win);
    }

    GLfloat left   = GLfloat(win.left)   / GLfloat(s.active.w);
    GLfloat top    = GLfloat(win.top)    / GLfloat(s.active.h);
    GLfloat right  = GLfloat(win.right)  / GLfloat(s.active.w);
    GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);

    TexCoords texCoords[4];
    texCoords[0].u = left;
    texCoords[0].v = top;
    texCoords[1].u = left;
    texCoords[1].v = bottom;
    texCoords[2].u = right;
    texCoords[2].v = bottom;
    texCoords[3].u = right;
    texCoords[3].v = top;
    for (int i = 0; i < 4; i++) {
        texCoords[i].v = 1.0f - texCoords[i].v;
    }

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
    glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
    glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_BLEND);
}
static void
CopyGraphicBuffer(sp<GraphicBuffer>& aSource, sp<GraphicBuffer>& aDestination)
{
  void* srcPtr = nullptr;
  aSource->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &srcPtr);
  void* destPtr = nullptr;
  aDestination->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destPtr);
  MOZ_ASSERT(srcPtr && destPtr);

  // Build PlanarYCbCrData for source buffer.
  PlanarYCbCrData srcData;
  switch (aSource->getPixelFormat()) {
    case HAL_PIXEL_FORMAT_YV12:
      // Android YV12 format is defined in system/core/include/system/graphics.h
      srcData.mYChannel = static_cast<uint8_t*>(srcPtr);
      srcData.mYSkip = 0;
      srcData.mYSize.width = aSource->getWidth();
      srcData.mYSize.height = aSource->getHeight();
      srcData.mYStride = aSource->getStride();
      // 4:2:0.
      srcData.mCbCrSize.width = srcData.mYSize.width / 2;
      srcData.mCbCrSize.height = srcData.mYSize.height / 2;
      srcData.mCrChannel = srcData.mYChannel + (srcData.mYStride * srcData.mYSize.height);
      // Aligned to 16 bytes boundary.
      srcData.mCbCrStride = Align(srcData.mYStride / 2, 16);
      srcData.mCrSkip = 0;
      srcData.mCbChannel = srcData.mCrChannel + (srcData.mCbCrStride * srcData.mCbCrSize.height);
      srcData.mCbSkip = 0;
      break;
    case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
      // Venus formats are doucmented in kernel/include/media/msm_media_info.h:
      srcData.mYChannel = static_cast<uint8_t*>(srcPtr);
      srcData.mYSkip = 0;
      srcData.mYSize.width = aSource->getWidth();
      srcData.mYSize.height = aSource->getHeight();
      // - Y & UV Width aligned to 128
      srcData.mYStride = aSource->getStride();
      srcData.mCbCrSize.width = (srcData.mYSize.width + 1) / 2;
      srcData.mCbCrSize.height = (srcData.mYSize.height + 1) / 2;
      // - Y height aligned to 32
      srcData.mCbChannel = srcData.mYChannel + (srcData.mYStride * Align(srcData.mYSize.height, 32));
      // Interleaved VU plane.
      srcData.mCbSkip = 1;
      srcData.mCrChannel = srcData.mCbChannel + 1;
      srcData.mCrSkip = 1;
      srcData.mCbCrStride = srcData.mYStride;
      break;
    default:
      NS_ERROR("Unsupported input gralloc image type. Should never be here.");
  }
  // Build PlanarYCbCrData for destination buffer.
  PlanarYCbCrData destData;
  destData.mYChannel = static_cast<uint8_t*>(destPtr);
  destData.mYSkip = 0;
  destData.mYSize.width = aDestination->getWidth();
  destData.mYSize.height = aDestination->getHeight();
  destData.mYStride = aDestination->getStride();
  // 4:2:0.
  destData.mCbCrSize.width = destData.mYSize.width / 2;
  destData.mCbCrSize.height = destData.mYSize.height / 2;
  destData.mCrChannel = destData.mYChannel + (destData.mYStride * destData.mYSize.height);
  // Aligned to 16 bytes boundary.
  destData.mCbCrStride = Align(destData.mYStride / 2, 16);
  destData.mCrSkip = 0;
  destData.mCbChannel = destData.mCrChannel + (destData.mCbCrStride * destData.mCbCrSize.height);
  destData.mCbSkip = 0;

  CopyYUV(srcData, destData);

  aSource->unlock();
  aDestination->unlock();
}