转载请注明出处:www.olinone.com/

前言

PAG采用自研TGFX特效烘托引擎,笼统分离了接口及渠道完成类,能够扩展支撑多种图形烘托库,比方OpenGL、Metal等

TGFX引擎是怎么完成纹路制作?本文根据OpenGL图形库分析讲解TGFX烘托结构分层及具体架构设计。开端之前,先提一个问题:

制作一个Texture纹路目标,一般需要阅历哪些进程?

烘托流程

通常情况下,制作一个Texture纹路目标到方针Layer上,能够笼统为以下几个阶段:

1. 获取上下文: 经过EGL获取Context制作上下文,供给与烘托设备交互的能力,比方缓冲区交流、Canvas及Paint交互等

2. 定义着色器: 根据OpenGL的着色器语言(GLSL)编写着色器代码,编写自定义极点着色器和片段着色器代码,编译、链接加载和运用它们

3. 绑定数据源: 根据烘托坐标系几何计算绑定极点数据,加载并绑定纹路目标给GPU,设置烘托方针、混合形式等

4. 烘托履行: 提交烘托命令给烘托线程,转化为底层图形API调用、并履行实践的烘托操作

PAG动效框架源码笔记 (四)渲染框架

关于OpenGL完好的烘托流程,网上有比较多的资料介绍,在此不再赘述,有兴趣的同学能够参考 OpenGL ES Pipeline

结构层级

TGFX结构大致可分为三大块:

1. Drawable上下文: 根据EGL创立OpenGL上下文,供给与烘托设备交互的能力

2. Canvas接口: 定义画布Canvas及画笔Paint,对外供给烘托接口、记录烘托状况以及创立制作任务等

3. DrawOp履行: 定义并装载着色器函数,绑定数据源,履行实践烘托操作

为了支撑多渠道,TGFX定义了一套完好的结构基类,完成结构与渠道的物理隔离,比方矩阵目标Matrix、坐标Rect等,使用上层负责渠道目标与TFGX目标的映射转化

- (void)setMatrix:(CGAffineTransform)value {
  pag::Matrix matrix = {};
  matrix.setAffine(value.a, value.b, value.c, value.d, value.tx, value.ty);
  _pagLayer->setMatrix(matrix);
}

Drawable上下文

PAG经过笼统Drawable目标,封装了制作所需的上下文,其首要包含以下几个目标

1. Device(设备): 作为硬件设备层,负责与烘托设备交互,比方创立维护EAGLContext等

2. Window(窗口): 拥有一个Surface,负责图形库与制作方针的绑定,比方将的opengl的renderBuffer绑定到CAEAGLLayer上;

3. Surface(外表): 创立canvas画布供给可制作区域,对外供给flush制作接口;当窗口尺度发生改变时,surface会创立新的canvas

4. Canvas(画布): 作为实践可制作区域,供给制作api,进行实践的绘图操作,比方制作一个image或者shape等

PAG动效框架源码笔记 (四)渲染框架

具体代码如下:

1、Device创立Context
std::shared_ptr<GLDevice> GLDevice::Make(void* sharedContext) {
  if (eaglShareContext != nil) {
    eaglContext = [[EAGLContext alloc] initWithAPI:[eaglShareContext API]
                                        sharegroup:[eaglShareContext sharegroup]];
  } else {
    // 创立Context
    eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    if (eaglContext == nil) {
      eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    }
  }
  auto device = EAGLDevice::Wrap(eaglContext, false);
  return device;
}
std::shared_ptr<EAGLDevice> EAGLDevice::Wrap(EAGLContext* eaglContext, bool isAdopted) {
  auto oldEAGLContext = [[EAGLContext currentContext] retain];
  if (oldEAGLContext != eaglContext) {
    auto result = [EAGLContext setCurrentContext:eaglContext];
    if (!result) {
      return nullptr;
    }
  }
  auto device = std::shared_ptr<EAGLDevice>(new EAGLDevice(eaglContext),
                                            EAGLDevice::NotifyReferenceReachedZero);
  if (oldEAGLContext != eaglContext) {
    [EAGLContext setCurrentContext:oldEAGLContext];
  }
  return device;
}
// 获取Context
bool EAGLDevice::makeCurrent(bool force) {
  oldContext = [[EAGLContext currentContext] retain];
  if (oldContext == _eaglContext) {
    return true;
  }
  if (![EAGLContext setCurrentContext:_eaglContext]) {
    oldContext = nil;
    return false;
  }
  return true;
}
2、Window创立Surface,绑定RenderBuffer
std::shared_ptr<Surface> EAGLWindow::onCreateSurface(Context* context) {
  auto gl = GLFunctions::Get(context);
  ...
  gl->genFramebuffers(1, &frameBufferID);
  gl->bindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
  gl->genRenderbuffers(1, &colorBuffer);
  gl->bindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
  gl->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
  auto eaglContext = static_cast<EAGLDevice*>(context->device())->eaglContext();
  // 绑定到CAEAGLLayer上
  [eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
  ...
  GLFrameBufferInfo glInfo = {};
  glInfo.id = frameBufferID;
  glInfo.format = GL_RGBA8;
  BackendRenderTarget renderTarget = {glInfo, static_cast<int>(width), static_cast<int>(height)};
  // 创立Surface
  return Surface::MakeFrom(context, renderTarget, ImageOrigin::BottomLeft);
}
// 经过renderTarget持有context、frameBufferID及Size
std::shared_ptr<Surface> Surface::MakeFrom(Context* context,
                                           const BackendRenderTarget& renderTarget,
                                           ImageOrigin origin, const SurfaceOptions* options) {
  auto rt = RenderTarget::MakeFrom(context, renderTarget, origin);
  return MakeFrom(std::move(rt), options);
}
3、Surface创立Canvas及flush制作
Canvas* Surface::getCanvas() {
  // 尺度改变时会清空偏重新创立canvas
  if (canvas == nullptr) {
    canvas = new Canvas(this);
  }
  return canvas;
}
bool Surface::flush(BackendSemaphore* signalSemaphore) {
  auto semaphore = Semaphore::Wrap(signalSemaphore);
  // drawingManager创立tasks,装载制作pipiline
  renderTarget->getContext()->drawingManager()->newTextureResolveRenderTask(this);
  auto result = renderTarget->getContext()->drawingManager()->flush(semaphore.get());
  return result;
}
4、烘托流程
bool PAGSurface::draw(RenderCache* cache, std::shared_ptr<Graphic> graphic,
                      BackendSemaphore* signalSemaphore, bool autoClear) {
  // 获取context上下文                    
  auto context = lockContext(true);
  // 获取surface
  auto surface = drawable->getSurface(context);
  // 经过canvas画布
  auto canvas = surface->getCanvas();
  // 履行实践制作
  onDraw(graphic, surface, cache);
  // 调用flush
  surface->flush();
  // glfinish
  context->submit();
  // 绑定GL_RENDERBUFFER
  drawable->present(context);
  // 开释context上下文
  unlockContext();
  return true;
}

Canvas接口

Canvas API首要包含画布操作及目标制作两大类:

画布操作包含Matrix矩阵改变、Blend融合形式、画布裁切等设置,经过对canvasState画布状况的操作完成制作上下文的切换

目标制作包含Path、Shape、Image以及Glyph等目标的制作,结合Paint画笔完成纹路、文本、图形、蒙版等多种形式的制作及烘托

class Canvas {
 	// 画布操作
  void setMatrix(const Matrix& matrix);
  void setAlpha(float newAlpha);
  void setBlendMode(BlendMode blendMode);
  // 制作API
  void drawRect(const Rect& rect, const Paint& paint);
  void drawPath(const Path& path, const Paint& paint);
  void drawShape(std::shared_ptr<Shape> shape, const Paint& paint);
  void drawImage(std::shared_ptr<Image> image, const Matrix& matrix, const Paint* paint = nullptr);
  void drawGlyphs(const GlyphID glyphIDs[], const Point positions[], size_t glyphCount,
                  const Font& font, const Paint& paint);
};
// CanvasState记录当前画布的状况,包含Alph、blend形式、改变矩阵等
struct CanvasState {
  float alpha = 1.0f;
  BlendMode blendMode = BlendMode::SrcOver;
  Matrix matrix = Matrix::I();
  Path clip = {};
  uint32_t clipID = kDefaultClipID;
};
// 经过save及restore完成制作状况的切换
void Canvas::save() {
  auto canvasState = std::make_shared<CanvasState>();
  *canvasState = *state;
  savedStateList.push_back(canvasState);
}
void Canvas::restore() {
  if (savedStateList.empty()) {
    return;
  }
  state = savedStateList.back();
  savedStateList.pop_back();
}

DrawOp履行

DrawOp负责实践的制作逻辑,比方OpenGL着色器函数的创立装配、极点及纹路数据的创立及绑定等

TGFX笼统了FillRectOp矩形制作Op,能够掩盖绝大多数场景的制作需求

当然,其还支撑其它类型的制作Op,比方ClearOp清屏、TriangulatingPathOp三角图形制作Op等

class DrawOp : public Op {
  // DrawOp经过Pipiline完成多个_colors纹路目标及_masks蒙版的制作
  std::vector<std::unique_ptr<FragmentProcessor>> _colors;
  std::vector<std::unique_ptr<FragmentProcessor>> _masks;
};
// 矩形实践制作履行者
class FillRectOp : public DrawOp {
  FillRectOp(std::optional<Color> color, const Rect& rect, const Matrix& viewMatrix,
             const Matrix& localMatrix);
  void onPrepare(Gpu* gpu) override;
  void onExecute(OpsRenderPass* opsRenderPass) override;
};

总结

本文结合OpenGL讲解了TGFX烘托引擎的大约结构结构,让各位有了一个开始认知

接下来将结合image纹路制作介绍TGFX烘托引擎具体的制作烘托流程,欢迎我们关注点赞!