从SurfaceFlinger中获取各layer图片的试验可以加深对GraphicBuffer和Layer的理解。
dumpsys SurfaceFlinger中打印的Slot信息中有GraphicBuffer的指针,可以帮助我们了解QueueBufferCore.
这个试验最初的出发点是根据图像的存储内存,再获取到这个数据,通过保存为图片的直观形式展现出来。
其实系统截图命令screencap也是类似的原理和实现(当然,我这里的保存图片就是从screencap里copy出来的方法)
frameworks/base/cmds/screencap/screencap.cpp
里面从surfaceflinger里面获取到了合成完成的GraphicBuffer,即屏幕截图画面
201 spoutBuffer; 202 status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */, 203 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation, 204 &outBuffer); 205 if (result != NO_ERROR) { 206 close(fd); 207 _exit(1); 208 }
再通过lock方法获取到存储地址base
result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
我们的试验中,显示出了GraphicBuffer的binder传送过程,
通过lockAsync方法获取到地址base
status_t res = buf->lockAsync(0x00000003U | 0x00000030U,
newDirtyRegion.bounds(), &vaddr, fenceFd);
有了地址base,就可以使用screencap里面的方法来保存为图片了
217 w = outBuffer->getWidth(); 218 h = outBuffer->getHeight(); 219 s = outBuffer->getStride(); 220 f = outBuffer->getPixelFormat(); 221 d = HAL_DATASPACE_UNKNOWN; 222 size = s * h * bytesPerPixel(f); 223 224 if (png) { 225 const SkImageInfo info = 226 SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d)); 227 SkPixmap pixmap(info, base, s * bytesPerPixel(f)); 228 struct FDWStream final : public SkWStream { 229 size_t fBytesWritten = 0; 230 int fFd; 231 FDWStream(int f) : fFd(f) {} 232 size_t bytesWritten() const override { return fBytesWritten; } 233 bool write(const void* buffer, size_t size) override { 234 fBytesWritten += size; 235 return size == 0 || ::write(fFd, buffer, size) > 0; 236 } 237 } fdStream(fd); 238 (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); 239 if (fn != NULL) { 240 notifyMediaScanner(fn); 241 } 242 } else { 243 uint32_t c = dataSpaceToInt(d); 244 write(fd, &w, 4); 245 write(fd, &h, 4); 246 write(fd, &f, 4); 247 write(fd, &c, 4); 248 size_t Bpp = bytesPerPixel(f); 249 for (size_t y=0 ; yvoid *)((char *)base + s*Bpp); 252 } 253 } 254 close(fd);