// 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; }
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]; } } }
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]; } } }
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(); } }
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(); }
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(); }