美文网首页
View体系7:Canvas

View体系7:Canvas

作者: 81bad73e9053 | 来源:发表于2016-11-15 21:29 被阅读192次

    1.Surface.lockCanvas

    draw(Canvas canvas)
    

    与View组件打交道的是Canvas而不是Surface,但是应用进程与SurfaceFlinger的数据中介并不是Canvas而是Surface,这就不可避免的产生了一个问题:Canvas和Surface之间如何协作?ViewRootImpl中取得一个Canvas的方法如下:

    canvas = mSurface.lockCanvas(dirty); 
    

    1.1 lockCanvas

    public Canvas lockCanvas(Rect inOutDirty)throws Surface.OutOfResourcesException, IllegalArgumentException {
        synchronized (mLock) {
            checkNotReleasedLocked();
            if (mLockedObject != 0) { 
                throw new IllegalStateException("Surface was already locked");
            }
            mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
            return mCanvas;
        }
    } 
    
    private static native int nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
            throws OutOfResourcesException; 
    

    1.2 nativeLockCanvas

     //clazz对应java层的Surface
    static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
            jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
        //nativeObject对应C++层的Surface
        sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
        //计算dirtyRegion 
        Rect dirtyRect;
        Rect* dirtyRectPtr = NULL;
    
        if (dirtyRectObj) {
            dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
            dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
            dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
            dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
            dirtyRectPtr = &dirtyRect;
        }
    
        ANativeWindow_Buffer outBuffer;//用于存储UI数据的Buffer
        //通过lock方法为outBuffer赋值
        status_t err = surface->lock(&outBuffer, dirtyRectPtr); 
    
        SkBitmap bitmap;
        ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
        bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
        
        if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
            bitmap.setIsOpaque(true);
        }
        if (outBuffer.width > 0 && outBuffer.height > 0) {
            bitmap.setPixels(outBuffer.bits);//为Bitmap分配可用的数据空间
        } else { 
            bitmap.setPixels(NULL);
        }
        //通过bitmap构造本地canvas对象
        SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
        //将本地canvas对象保存到java层canvas的数据成员变量中
        swapCanvasPtr(env, canvasObj, nativeCanvas);
     
        sp<Surface> lockedSurface(surface);
        lockedSurface->incStrong(&sRefBaseOwner);
        return (int) lockedSurface.get();
    }
    

    1.3

    status_t Surface::lock(
            ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
    {
        if (mLockedBuffer != 0) {
            ALOGE("Surface::lock failed, already locked");
            return INVALID_OPERATION;
        }
    
        if (!mConnectedToCpu) {//step2判断是否已经建立必要的链接
            int err = Surface::connect(NATIVE_WINDOW_API_CPU); 
            //设置内存块的用法
            setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
        }
    
        ANativeWindowBuffer* out;
        int fenceFd = -1;
        //step5:buffer队列中dequeue一个可用的buffer
        status_t err = dequeueBuffer(&out, &fenceFd); 
        if (err == NO_ERROR) {
            //当前要处理的buffer
            sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
            sp<Fence> fence(new Fence(fenceFd)); 
            err = fence->waitForever("Surface::lock"); 
            const Rect bounds(backBuffer->width, backBuffer->height);
    
            Region newDirtyRegion;
            //上一个buffer
            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
            //是否可以从上一次操作中直接copy数据
            const bool canCopyBack = (frontBuffer != 0 &&
                    backBuffer->width  == frontBuffer->width &&
                    backBuffer->height == frontBuffer->height &&
                    backBuffer->format == frontBuffer->format);
    
            if (canCopyBack) { 
                //计算可以从上一次的buffer中copy多少数据
                const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); 
                if (!copyback.isEmpty())
                    copyBlt(backBuffer, frontBuffer, copyback);
            } else { 
                newDirtyRegion.set(bounds);
                mDirtyRegion.clear(); 
                for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
                    mSlots[i].dirtyRegion.clear();
                }
            }
    
    
        
    
            void* vaddr;
            //锁定buffer
            status_t res = backBuffer->lock(
                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                    newDirtyRegion.bounds(), &vaddr); 
    
            if (res != 0) {
                err = INVALID_OPERATION;
            } else {//收尾工作
                mLockedBuffer = backBuffer;
                outBuffer->width  = backBuffer->width;
                outBuffer->height = backBuffer->height;
                outBuffer->stride = backBuffer->stride;
                outBuffer->format = backBuffer->format;
                outBuffer->bits   = vaddr;
            }
        }
        return err;
    } 
    

    当前被lock的buffer最多只能有一个,以mLockedBuffer来表示,这是一个GraphicBuffer类型的强指针变量,每次lock成功之后,它就会被赋值为当前被lock的buffer,而当UI绘图结束并调用unlockAndPost时,这个mLockedBuffer会被清空且另一个变量mPostedBuffer用于记录最近一次post操作,因此在函数的开始需要判断mLockedBuffer是否为空,如果不是就要避免再次锁定一次buffer,直接返回错误。

    1.4 native_window.h

    typedef struct ANativeWindow_Buffer {
        // 宽度,以像素为单位
        int32_t width; 
        // 高度,以像素为单位
        int32_t height; 
        //内存中buffer每一行所占的像素值
        int32_t stride; 
        // 缓冲区格式
        int32_t format; 
        //存储数据的地方
        void* bits; 
        // 保留
        uint32_t reserved[6];
    } ANativeWindow_Buffer;
    

    2.unlockCanvasAndPost

    UI绘图完成后,程序需要将这幅画解锁,并提交给SurfaceFlinger进行渲染,在performDraw完成之后,用unlockCanvasAndPost接口来告知Surface一个完整的绘图操作已经完成。

    2.1 nativeUnlockCanvasAndPost

    static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
            jint nativeObject, jobject canvasObj) {
        sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
       
        // detach the canvas from the surface
        SkCanvas* nativeCanvas = SkNEW(SkCanvas);
        swapCanvasPtr(env, canvasObj, nativeCanvas);
     
        status_t err = surface->unlockAndPost(); 
    }
    

    2.2 unlockAndPost

    status_t Surface::unlockAndPost()
    {
        if (mLockedBuffer == 0) { //当前是否有可用的buffer
            return INVALID_OPERATION;
        }
        //buffer解除锁定
        status_t err = mLockedBuffer->unlock(); 
        //buffer入队
        err = queueBuffer(mLockedBuffer.get(), -1);
        //用变量mPostedBuffer记录刚刚操作过的buffer
        mPostedBuffer = mLockedBuffer;
        mLockedBuffer = 0;//mLockedBuffer清空,保证下一次lock的时候可以正常执行
        return err;
    }
    
    

    相关文章

      网友评论

          本文标题:View体系7:Canvas

          本文链接:https://www.haomeiwen.com/subject/vbylpttx.html