{"id":948,"date":"2023-06-08T15:16:39","date_gmt":"2023-06-08T07:16:39","guid":{"rendered":"http:\/\/www.olinone.com\/?p=948"},"modified":"2023-06-08T15:28:17","modified_gmt":"2023-06-08T07:28:17","slug":"pag%e5%8a%a8%e6%95%88%e6%a1%86%e6%9e%b6%e6%ba%90%e7%a0%81%e7%ac%94%e8%ae%b0-%ef%bc%88%e4%ba%94%ef%bc%89%e6%b8%b2%e6%9f%93%e6%b5%81%e7%a8%8b","status":"publish","type":"post","link":"http:\/\/www.olinone.com\/?p=948","title":{"rendered":"PAG\u52a8\u6548\u6846\u67b6\u6e90\u7801\u7b14\u8bb0 \uff08\u4e94\uff09\u6e32\u67d3\u6d41\u7a0b"},"content":{"rendered":"<p class=\"md-end-block md-p\"><span class=\"md-plain md-expand\">\u8f6c\u8f7d\u8bf7\u6ce8\u660e\u51fa\u5904\uff1a<\/span><span class=\"md-link md-pair-s\" spellcheck=\"false\"><a href=\"http:\/\/www.olinone.com\/\">http:\/\/www.olinone.com\/<\/a><\/span><\/p>\n<h3 class=\"md-end-block md-heading\"><span class=\"md-plain\">\u524d\u8a00<\/span><\/h3>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u4e0a\u4e00\u7ae0\u4ecb\u7ecd\u4e86TGFX\u6e32\u67d3\u6846\u67b6\u7684\u5927\u81f4\u7ed3\u6784\uff0c\u672c\u7ae0\u57fa\u4e8eOpenGL\u4ecb\u7ecdTGFX\u7ed8\u5236Texture\u7eb9\u7406\u8be6\u7ec6\u7684\u6e32\u67d3\u6d41\u7a0b<\/span><\/p>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u7ed8\u5236Texture\u7eb9\u7406\uff0c\u6e32\u67d3\u5f15\u64ce\u4e3b\u8981\u5305\u62ec\u4e24\u4e2a\u6d41\u7a0b\uff1aGLSL\u7740\u8272\u5668\u4ee3\u7801\u7684\u88c5\u8f7d\u53ca\u6570\u636e\u5bf9\u8c61\u7684\u7ed1\u5b9a\u64cd\u4f5c<\/span><\/p>\n<h3 class=\"md-end-block md-heading\"><span class=\"md-plain\">\u7740\u8272\u5668\u4ee3\u7801\uff08GLSL\uff09<\/span><\/h3>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u6e32\u67d3\u4e00\u4e2a\u7eb9\u7406\uff0cTGFX \u9700\u8981\u6784\u5efa\u9876\u70b9\u7740\u8272\u5668\uff08Vertex Shader\uff09\u548c\u7247\u6bb5\u7740\u8272\u5668\uff08Frament Shader\uff09\u4e24\u4e2a\u7740\u8272\u5668\uff0c\u5176\u4ee3\u7801\u5206\u522b\u5982\u4e0b<\/span><\/p>\n<pre class=\"lang:default highlight:0 decode:true \">#version 100\r\nprecision mediump float;\r\nuniform vec4 tgfx_RTAdjust; \/\/ \u5750\u6807\u7cfb\u6620\u5c04\u77e9\u9635\r\nuniform mat3 uCoordTransformMatrix_0_Stage0; \r\n\r\nattribute vec2 aPosition;\r\nattribute vec2 localCoord;\r\nattribute vec4 inColor;\r\n\r\nvarying vec2 vTransformedCoords_0_Stage0;\r\nvarying vec4 vColor_Stage0;\r\n\r\nvoid main() {\r\n    \/\/ Geometry Processor QuadPerEdgeAAGeometryProcessor\r\n    \/\/ \u77e9\u9635\u53d8\u5316\uff0c\u6bd4\u5982\u7f29\u653e\u3001\u504f\u79fb\uff0c\u66f4\u9002\u5408GPU\u5e76\u884c\u8ba1\u7b97\r\n    vTransformedCoords_0_Stage0 = (uCoordTransformMatrix_0_Stage0 * vec3(localCoord, 1)).xy;\r\n    vColor_Stage0 = inColor;\r\n    \/\/ \u5750\u6807\u7cfb\u8f6c\u5316\r\n    gl_Position = vec4(aPosition.xy * tgfx_RTAdjust.xz + tgfx_RTAdjust.yw, 0, 1); \r\n}<\/pre>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u9876\u70b9\u7740\u8272\u5668\u9700\u8981\u8ba1\u7b97\u6bcf\u4e2a\u9876\u70b9\u5728\u6e32\u67d3\u5750\u6807\u7cfb\u4e2d\u7684\u5750\u6807\uff0c\u540c\u65f6\u5c06\u7eb9\u7406\u6570\u636e\u8f93\u51fa\u7ed9\u7247\u6bb5\u7740\u8272\u5668<\/span><\/p>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u4e3a\u4e86\u4f18\u5316\u8ba1\u7b97\u6027\u80fd\uff0cTGFX\u6ca1\u6709\u5728CPU\u9636\u6bb5\u5904\u7406\u77e9\u9635\u53d8\u5316\u548c\u5750\u6807\u6620\u5c04\uff0c\u800c\u662f\u4ea4\u7531GPU\u6765\u5904\u7406\uff08 GPU\u66f4\u9002\u5408\u77e9\u9635\u8ba1\u7b97\uff09\uff1b\u540c\u65f6\uff0c\u7531GPU\u5904\u7406\u5750\u6807\u7cfb\u6620\u5c04\u53ef\u4ee5\u66f4\u7075\u6d3b\u9002\u914d\u4e0d\u540c\u5e73\u53f0\u4e0d\u540c\u5750\u6807\u7cfb<\/span><\/p>\n<pre class=\"lang:default highlight:0 decode:true \">#version 100\r\nprecision mediump float;\r\nuniform mat3 uMat3ColorConversion_Stage1; \/\/ \u989c\u8272\u7a7a\u95f4\u8f6c\u5316\u77e9\u9635\r\nuniform vec2 uAlphaStart_Stage1; \/\/ Alpha\u533a\u57df\u504f\u79fb\u91cf\r\nuniform sampler2D uTextureSampler_0_Stage1;\r\nuniform sampler2D uTextureSampler_1_Stage1;\r\n\r\nvarying highp vec2 vTransformedCoords_0_Stage0;\r\nvarying highp vec4 vColor_Stage0;\r\n\r\nvoid main() {\r\n    vec4 outputColor_Stage0;\r\n    vec4 outputCoverage_Stage0;\r\n    { \/\/ Stage 0 QuadPerEdgeAAGeometryProcessor\r\n        outputCoverage_Stage0 = vec4(1.0);\r\n        outputColor_Stage0 = vColor_Stage0;\r\n    }\r\n    vec4 output_Stage1;\r\n    { \/\/ Stage 1 XfermodeFragmentProcessor - dst\r\n        vec4 child;\r\n        {\r\n            \/\/ Child Index 0 (mangle: _c0): YUVTextureEffect\r\n            \/\/ yuv\u53d6\u503c\uff0c\u5149\u6805\u5316\u540e\u6bcf\u4e2a\u70b9\u5750\u6807\u90fd\u4e0d\u4e00\u6837\r\n            vec3 yuv;\r\n            yuv.x = texture2D(uTextureSampler_0_Stage1, vTransformedCoords_0_Stage0).rrra.r;\r\n            yuv.yz = texture2D(uTextureSampler_1_Stage1, vTransformedCoords_0_Stage0).rgrg.ra;\r\n            yuv.x -= (16.0 \/ 255.0);\r\n            yuv.yz -= vec2(0.5, 0.5);\r\n            \/\/ yuv\u6570\u636e\u8f6crgb\r\n            vec3 rgb = clamp(uMat3ColorConversion_Stage1 * yuv, 0.0, 1.0); \r\n            \/\/ \u901a\u8fc7RGB\u989c\u8272\u533a\u57df\u504f\u79fb\u8ba1\u7b97Alpha\u533a\u57df\uff0c\u6bd4\u5982\u5de6rgb\u53f3alpha\uff0c\u6574\u4f53+0.5\r\n            vec2 alphaVertexColor = vTransformedCoords_0_Stage0 + uAlphaStart_Stage1; \r\n            float yuv_a = texture2D(uTextureSampler_0_Stage1, alphaVertexColor).rrra.r;\r\n            \/\/ \u4e3a\u907f\u514d\u56e0\u538b\u7f29\u8bef\u5dee\u3001\u7cbe\u5ea6\u7b49\u539f\u56e0\u9020\u6210\u4e0d\u900f\u660e\u53d8\u6210\u90e8\u5206\u900f\u660e\uff08\u6bd4\u5982255\u53d8\u6210254\uff09\uff0c\r\n            \/\/ \u4e0b\u9762\u8fdb\u884c\u4e86\u51cf1.0\/255.0\u7684\u7cbe\u5ea6\u4fee\u6b63\u3002\r\n            yuv_a = (yuv_a - 16.0\/255.0) \/ (219.0\/255.0 - 1.0\/255.0);\r\n            yuv_a = clamp(yuv_a, 0.0, 1.0); \r\n            child = vec4(rgb * yuv_a, yuv_a) * vec4(1.0);\r\n        }\r\n        \/\/ Compose Xfer Mode: DstIn\r\n        output_Stage1 = child * outputColor_Stage0.a; \/\/ blend\u6df7\u5408\u6a21\u5f0f\r\n    }\r\n    { \/\/ Xfer Processor EmptyXferProcessor\r\n        gl_FragColor = output_Stage1 * outputCoverage_Stage0;\r\n    }\r\n}<\/pre>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u7247\u6bb5\u7740\u8272\u5668\u51b3\u5b9a\u4e86\u5149\u6805\u5316\u540e\u6bcf\u4e2a\u70b9\u50cf\u7d20\u7684\u6700\u7ec8\u989c\u8272\uff0cTGFX\u9700\u8981\u5904\u7406\u7eb9\u7406RGBA\u8ba1\u7b97\u3001Mask\u8499\u7248\u906e\u7f69\u4ee5\u53ca\u591a\u56fe\u5c42\u7684blend\u6df7\u5408\u8ba1\u7b97\u7b49<\/span><\/p>\n<h3 class=\"md-end-block md-heading\"><span class=\"md-plain\">\u6e32\u67d3\u6d41\u7a0b<\/span><\/h3>\n<h4 class=\"md-end-block md-heading\"><span class=\"md-plain\">1\u3001\u4efb\u52a1\u521b\u5efa<\/span><\/h4>\n<pre class=\"lang:default highlight:0 decode:true \">void Canvas::drawImage(std::shared_ptr&lt;Image&gt; image, const Paint* paint) {\r\n \t\/\/ Mipmap\u7eb9\u7406\u6620\u5c04\u5904\u7406\r\n  auto mipMapMode = image-&gt;hasMipmaps() ? tgfx::MipMapMode::Linear : tgfx::MipMapMode::None;\r\n  tgfx::SamplingOptions sampling(tgfx::FilterMode::Linear, mipMapMode);\r\n  drawImage(std::move(image), sampling, paint);\r\n}\r\n\r\nvoid Canvas::drawImage(std::shared_ptr&lt;Image&gt; image, SamplingOptions sampling, const Paint* paint) {\r\n  ...\r\n  \/\/ \u8bb0\u5f55Canvas\u5f53\u524d\u72b6\u6001\r\n  auto oldMatrix = getMatrix();\r\n  ...\r\n  \/\/ \u7ed8\u5236image(\u5305\u542b\u89e3\u7801\u540e\u7684texture\u7eb9\u7406)\r\n  drawImage(std::move(image), sampling, paint);\r\n  \/\/ \u8fd8\u539fCanvas\u4e0a\u4e0b\u6587\r\n  setMatrix(oldMatrix);\r\n}\r\n\r\nvoid Canvas::drawImage(std::shared_ptr&lt;Image&gt; image, SamplingOptions sampling, const Paint&amp; paint) {\r\n  ...\r\n  \/\/ \u7eb9\u7406\u5904\u7406\uff0c\u5e8f\u5217\u5e27\u5de6rgb\u53f3alpha\u6570\u636e\r\n  auto processor = image-&gt;asFragmentProcessor(getContext(), surface-&gt;options()-&gt;flags(), sampling);\r\n  ...\r\n  \/\/ \u521b\u5efa\u753b\u7b14Paint\r\n  if (!PaintToGLPaintWithImage(getContext(), surface-&gt;options()-&gt;flags(), paint, state-&gt;alpha, std::move(processor), image-&gt;isAlphaOnly(), &amp;glPaint)) {\r\n    return;\r\n  }\r\n  \/\/ \u521b\u5efa\u77e9\u5f62\u586b\u5145\u7ed8\u5236Operation\r\n  auto op = FillRectOp::Make(glPaint.color, localBounds, state-&gt;matrix);\r\n  \/\/ \u7ed1\u5b9aPaint\u5230Op\u4e0a\uff0c\u63d0\u4ea4\u7ed8\u5236Task\r\n  draw(std::move(op), std::move(glPaint), true);\r\n}\r\n\r\n\/\/ \u521b\u5efaPaint\r\nstatic bool PaintToGLPaint(Context* context, uint32_t surfaceFlags, const Paint&amp; paint, float alpha, std::unique_ptr&lt;FragmentProcessor&gt; shaderProcessor, GpuPaint* glPaint) {\r\n  ...\r\n  \/\/ \u7ed8\u5236\u4e32\u884cPipeline\r\n  \/\/ \u7eb9\u7406\r\n  shaderFP = shader-&gt;asFragmentProcessor(args);\r\n  if (shaderFP) {\r\n    glPaint-&gt;colorFragmentProcessors.emplace_back(std::move(shaderFP));\r\n  } \r\n  \/\/ \u6ee4\u955c\r\n  if (auto colorFilter = paint.getColorFilter()) {\r\n    if (auto processor = colorFilter-&gt;asFragmentProcessor()) {\r\n      glPaint-&gt;colorFragmentProcessors.emplace_back(std::move(processor));\r\n    } \r\n  }\r\n  \/\/ \u8499\u7248\u906e\u7f69\r\n  if (auto maskFilter = paint.getMaskFilter()) {\r\n    if (auto processor = maskFilter-&gt;asFragmentProcessor(args)) {\r\n      glPaint-&gt;coverageFragmentProcessors.emplace_back(std::move(processor));\r\n    }\r\n  }\r\n  return true;\r\n}\r\n\r\n\/\/ \u7ed1\u5b9aPaint\u5230\u7ed8\u5236Operation\u4e2d\uff0c\u63d0\u4ea4\u5230\u7ed8\u5236OperationQueue\r\nvoid Canvas::draw(std::unique_ptr&lt;DrawOp&gt; op, GpuPaint paint, bool aa) {\r\n  ...\r\n  \/\/ Canvas\u88c1\u5207\r\n  auto masks = std::move(paint.coverageFragmentProcessors);\r\n  Rect scissorRect = Rect::MakeEmpty();\r\n  auto clipMask = getClipMask(op-&gt;bounds(), &amp;scissorRect);\r\n  if (clipMask) {\r\n    masks.push_back(std::move(clipMask));\r\n  }\r\n  op-&gt;setScissorRect(scissorRect);\r\n  BlendModeCoeff first;\r\n  BlendModeCoeff second;\r\n  \/\/ blend\u6df7\u5408\u6a21\u5f0f\r\n  if (BlendModeAsCoeff(state-&gt;blendMode, &amp;first, &amp;second)) {\r\n    op-&gt;setBlendFactors(std::make_pair(first, second));\r\n  } else {\r\n    op-&gt;setXferProcessor(PorterDuffXferProcessor::Make(state-&gt;blendMode));\r\n    op-&gt;setRequireDstTexture(!getContext()-&gt;caps()-&gt;frameBufferFetchSupport);\r\n  }\r\n  op-&gt;setAA(aaType);\r\n  \/\/ \u7eb9\u7406\u56fe\u5c42\r\n  op-&gt;setColors(std::move(paint.colorFragmentProcessors));\r\n  \/\/ \u8499\u7248\u56fe\u5c42\r\n  op-&gt;setMasks(std::move(masks));\r\n  surface-&gt;aboutToDraw(false);\r\n  \/\/ \u52a0\u5165\u5230\u7ed8\u5236\u961f\u5217\u4e2d\r\n  drawContext-&gt;addOp(std::move(op));\r\n}\r\n\r\nvoid SurfaceDrawContext::addOp(std::unique_ptr&lt;Op&gt; op) {\r\n  getOpsTask()-&gt;addOp(std::move(op));\r\n}<\/pre>\n<h4 class=\"md-end-block md-heading\"><span class=\"md-plain\">2\u3001Flush\u7ed8\u5236<\/span><\/h4>\n<pre class=\"lang:default highlight:0 decode:true \">bool DrawingManager::flush(Semaphore* signalSemaphore) {\r\n  ...\r\n  \/\/ \u904d\u5386\u6267\u884c\r\n  std::for_each(tasks.begin(), tasks.end(), [gpu](std::shared_ptr&lt;RenderTask&gt;&amp; task) { task-&gt;execute(gpu); });\r\n  return context-&gt;caps()-&gt;semaphoreSupport &amp;&amp; gpu-&gt;insertSemaphore(signalSemaphore);\r\n}\r\n\r\nbool OpsTask::execute(Gpu* gpu) {\r\n  \/\/ \u5148prepare\r\n  std::for_each(ops.begin(), ops.end(), [gpu](auto&amp; op) { op-&gt;prepare(gpu); });\r\n  \/\/ \u518dexecute\r\n  opsRenderPass-&gt;begin();\r\n  auto tempOps = std::move(ops);\r\n  for (auto&amp; op : tempOps) {\r\n    op-&gt;execute(opsRenderPass);\r\n  }\r\n  opsRenderPass-&gt;end();\r\n  \/\/ \u63d0\u4ea4\r\n  gpu-&gt;submit(opsRenderPass);\r\n  return true;\r\n}<\/pre>\n<h4 class=\"md-end-block md-heading\"><span class=\"md-plain\">3\u3001\u7ed8\u5236\u9884\u5904\u7406<\/span><\/h4>\n<pre class=\"lang:default highlight:0 decode:true \">\/\/ \u9876\u70b9\u7740\u8272\u5668\u6570\u636e\u6784\u9020\r\nvoid FillRectOp::onPrepare(Gpu* gpu) {\r\n  \/\/ \u6570\u636e\u6784\u9020\uff08CPU\uff09\uff0c\u5305\u542b\u753b\u5e03\u3001\u7eb9\u7406\u4ee5\u53caRGB\u533a\u57df\u6570\u636e\r\n  auto data = vertices();\r\n  \/\/ \u7ed1\u5b9a\u6570\u636e\u5230GPU\r\n  vertexBuffer = GpuBuffer::Make(gpu-&gt;context(), BufferType::Vertex, data.data(), data.size() * sizeof(float));\r\n  \/\/ \u81ea\u5b9a\u4e49\u7ed8\u5236\u987a\u5e8findex\r\n  if (aa == AAType::Coverage) {\r\n    indexBuffer = gpu-&gt;context()-&gt;resourceProvider()-&gt;aaQuadIndexBuffer();\r\n  } else {\r\n    indexBuffer = gpu-&gt;context()-&gt;resourceProvider()-&gt;nonAAQuadIndexBuffer();\r\n  }\r\n}\r\n\r\nstd::shared_ptr&lt;GpuBuffer&gt; GpuBuffer::Make(Context* context, BufferType bufferType, const void* buffer, size_t size) {\r\n  ...\r\n  auto glBuffer = std::static_pointer_cast&lt;GLBuffer&gt;(context-&gt;resourceCache()-&gt;findScratchResource(scratchKey));\r\n\t...\r\n\t\/\/ GPU\u6570\u636e\u7ed1\u5b9a\r\n  gl-&gt;bindBuffer(target, glBuffer-&gt;_bufferID);\r\n  \/\/ GPU\u6570\u636e\u8d4b\u503c\r\n  gl-&gt;bufferData(target, static_cast&lt;GLsizeiptr&gt;(size), buffer, GL_STATIC_DRAW);\r\n  return glBuffer;\r\n}<\/pre>\n<h4 class=\"md-end-block md-heading\"><span class=\"md-plain\">4\u3001\u7ed8\u5236\u6267\u884c<\/span><\/h4>\n<pre class=\"lang:default highlight:0 decode:true \">void FillRectOp::onExecute(OpsRenderPass* opsRenderPass) {\r\n  \/\/ \u7740\u8272\u5668\u4ee3\u7801\u5b9a\u4e49\r\n  auto info = createProgram(opsRenderPass, QuadPerEdgeAAGeometryProcessor::Make(opsRenderPass-&gt;renderTarget()-&gt;width(), opsRenderPass-&gt;renderTarget()-&gt;height(), aa, !colors.empty()));\r\n  \/\/ \u7740\u8272\u5668\u4ee3\u7801\u88c5\u8f7d\u53ca\u6570\u636e\u7ed1\u5b9a\r\n  opsRenderPass-&gt;bindPipelineAndScissorClip(info, scissorRect());\r\n  \/\/ \u7ed1\u5b9a\u9876\u70b9\u53ca\u81ea\u5b9a\u4e49\u7ed8\u5236\u987a\u5e8f\u6570\u636e\r\n  opsRenderPass-&gt;bindBuffers(indexBuffer, vertexBuffer);\r\n  if (needsIndexBuffer()) {\r\n    \/\/ \u81ea\u5b9a\u4e49\u987a\u5e8f\u7ed8\u5236\r\n    opsRenderPass-&gt;drawIndexed(PrimitiveType::Triangles, 0, static_cast&lt;int&gt;(rects.size()) * numIndicesPerQuad);\r\n  } else {\r\n    \/\/ \u9ed8\u8ba4\u987a\u5e8f\u7ed8\u5236\r\n    opsRenderPass-&gt;draw(PrimitiveType::TriangleStrip, 0, 4);\r\n  }\r\n}\r\n\r\n\/\/ \u7740\u8272\u5668\u4ee3\u7801\u751f\u6210\uff0c\u5305\u62ec\u9876\u70b9\u548c\u7247\u6bb5\u7740\u8272\u5668\u4ee3\u7801\r\nProgramInfo DrawOp::createProgram(OpsRenderPass* opsRenderPass,\r\n                                  std::unique_ptr&lt;GeometryProcessor&gt; gp) {\r\n  auto numColorProcessors = _colors.size();\r\n  \/\/ \u7247\u6bb5\u7740\u8272\u5668\u51fd\u6570\u4ee3\u7801Pipeline\u7ec4\u88c5\r\n  std::vector&lt;std::unique_ptr&lt;FragmentProcessor&gt;&gt; fragmentProcessors = {};\r\n  fragmentProcessors.resize(numColorProcessors + _masks.size());\r\n  \/\/ \u7eb9\u7406\r\n  std::move(_colors.begin(), _colors.end(), fragmentProcessors.begin());\r\n  \/\/ \u8499\u7248\r\n  std::move(_masks.begin(), _masks.end(),\r\n            fragmentProcessors.begin() + static_cast&lt;int&gt;(numColorProcessors));\r\n\t...\r\n  ProgramInfo info;\r\n  \/\/ blend\u6a21\u5f0f\r\n  info.blendFactors = _blendFactors;\r\n  info.pipeline = std::make_unique&lt;Pipeline&gt;(std::move(fragmentProcessors), numColorProcessors, std::move(_xferProcessor), dstTexture, dstTextureOffset, &amp;swizzle);\r\n  info.pipeline-&gt;setRequiresBarrier(dstTexture != nullptr &amp;&amp; dstTexture == opsRenderPass-&gt;renderTargetTexture());\r\n  \/\/ \u9876\u70b9\u7740\u8272\u5668\u51fd\u6570\u4ee3\u7801\r\n  info.geometryProcessor = std::move(gp);\r\n  return info;\r\n}\r\n\r\n\/\/ \u7740\u8272\u5668\u4ee3\u7801\u88c5\u8f7d\uff0c\u5305\u62ec\u7f16\u8bd1\u3001\u94fe\u63a5\u53caUniform\u6570\u636e\u7ed1\u5b9a\r\nbool GLOpsRenderPass::onBindPipelineAndScissorClip(const ProgramInfo&amp; info, const Rect&amp; drawBounds) {\r\n  GLProgramCreator creator(info.geometryProcessor.get(), info.pipeline.get());\r\n  \/\/ Program\u51fd\u6570\u521b\u5efa\uff0c\u5148\u7f13\u5b58\uff0c\u6ca1\u6709\u518d\u65b0\u5efa\r\n  _program = static_cast&lt;GLProgram*&gt;(_context-&gt;programCache()-&gt;getProgram(&amp;creator));\r\n  auto glRT = static_cast&lt;GLRenderTarget*&gt;(_renderTarget.get());\r\n  auto* program = static_cast&lt;GLProgram*&gt;(_program);\r\n  \/\/ \u7ed1\u5b9a\u51fd\u6570\r\n  gl-&gt;useProgram(program-&gt;programID());\r\n  gl-&gt;bindFramebuffer(GL_FRAMEBUFFER, glRT-&gt;getFrameBufferID());\r\n  gl-&gt;viewport(0, 0, glRT-&gt;width(), glRT-&gt;height());\r\n  \/\/ GL\u88c1\u5207\r\n  UpdateScissor(_context, drawBounds);\r\n  \/\/ GL\u6df7\u5408\u6a21\u5f0f\r\n  UpdateBlend(_context, info.blendFactors);\r\n\t\/\/ \u7ed1\u5b9a\u6570\u636e\uff0c\u5305\u62ecUniform\u53c2\u6570\u548c\u7eb9\u7406\u6570\u636e\r\n  program-&gt;updateUniformsAndTextureBindings(glRT, *info.geometryProcessor, *info.pipeline);\r\n  return true;\r\n}\r\n\r\n\/\/ \u521b\u5efaProgram\u51fd\u6570\r\nstd::unique_ptr&lt;GLProgram&gt; GLProgramBuilder::CreateProgram(Context* context, const GeometryProcessor* geometryProcessor, const Pipeline* pipeline) {\r\n  GLProgramBuilder builder(context, geometryProcessor, pipeline);\r\n  if (!builder.emitAndInstallProcessors()) {\r\n    return nullptr;\r\n  }\r\n  return builder.finalize();\r\n}\r\n\r\nbool ProgramBuilder::emitAndInstallProcessors() {\r\n  \/\/ \u751f\u6210\u9876\u70b9\u7740\u8272\u5668\u4ee3\u7801\r\n  emitAndInstallGeoProc(&amp;inputColor, &amp;inputCoverage);\r\n  \/\/ \u751f\u6210\u7247\u6bb5\u7740\u8272\u5668\u4ee3\u7801\r\n  emitAndInstallFragProcessors(&amp;inputColor, &amp;inputCoverage);\r\n  \/\/ \u56fe\u5c42\u53e0\u52a0\u6df7\u5408\u4ee3\u7801\r\n  emitAndInstallXferProc(inputColor, inputCoverage);\r\n  emitFSOutputSwizzle();\r\n  return checkSamplerCounts();\r\n}\r\n\r\nstd::unique_ptr&lt;GLProgram&gt; GLProgramBuilder::finalize() {\r\n \t...\r\n \t\/\/ Vertex Shader\u4ee3\u7801\r\n  auto vertex = vertexShaderBuilder()-&gt;shaderString();\r\n  \/\/ Frament Shader\u4ee3\u7801\r\n  auto fragment = fragmentShaderBuilder()-&gt;shaderString();\r\n  \/\/ \u521b\u5efaProgram\uff0c\u7f16\u8bd1\u3001\u94fe\u63a5\r\n  auto programID = CreateGLProgram(context, vertex, fragment);\r\n  \/\/ GPU\u9876\u70b9\u7740\u8272\u5668\u53c2\u6570\u7ed1\u5b9a\r\n  computeCountsAndStrides(programID);\r\n  \/\/ \u83b7\u53d6Program Uniform\u4f4d\u7f6e\r\n  resolveProgramResourceLocations(programID);\r\n  return createProgram(programID);\r\n}\r\n\r\nstd::unique_ptr&lt;GLProgram&gt; GLProgramBuilder::createProgram(unsigned programID) {\r\n  auto program = new GLProgram(context, uniformHandles, programID, _uniformHandler.uniforms, std::move(glGeometryProcessor), std::move(xferProcessor), std::move(fragmentProcessors), attributes, vertexStride);\r\n  \/\/ GPU Uniform\u53c2\u6570\u7ed1\u5b9a\r\n  program-&gt;setupSamplerUniforms(_uniformHandler.samplers);\r\n  return std::unique_ptr&lt;GLProgram&gt;(program);\r\n}\r\n\r\n\/\/ \u63d0\u4ea4\u7ed8\u5236\r\nvoid GLOpsRenderPass::draw(const std::function&lt;void()&gt;&amp; func) {\r\n\t\/\/ GPU\u9876\u70b9\u7740\u8272\u5668\u53c2\u6570\u8d4b\u503c\r\n  gl-&gt;bindBuffer(GL_ARRAY_BUFFER, std::static_pointer_cast&lt;GLBuffer&gt;(_vertexBuffer)-&gt;bufferID());\r\n  auto* program = static_cast&lt;GLProgram*&gt;(_program);\r\n  for (const auto&amp; attribute : program-&gt;vertexAttributes()) {\r\n    const AttribLayout&amp; layout = GetAttribLayout(attribute.gpuType);\r\n    gl-&gt;vertexAttribPointer(static_cast&lt;unsigned&gt;(attribute.location), layout.count, layout.type, layout.normalized, program-&gt;vertexStride(), reinterpret_cast&lt;void*&gt;(attribute.offset));\r\n    gl-&gt;enableVertexAttribArray(static_cast&lt;unsigned&gt;(attribute.location));\r\n  }\r\n  \/\/ \u7ed8\u5236\r\n  func();\r\n\t...\r\n}<\/pre>\n<h3 class=\"md-end-block md-heading\"><span class=\"md-plain\">\u603b\u7ed3<\/span><\/h3>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u4e3a\u4e86\u652f\u6301\u591a\u5e73\u53f0\u4e0d\u540c\u5bf9\u8c61\uff08\u7eb9\u7406\u3001\u56fe\u5f62\u7b49\uff09\u7ed8\u5236\uff0cTGFX\u62bd\u8c61\u5c01\u88c5\u4e86\u4e00\u5957\u5b8c\u6574\u7684GLSL\u4ee3\u7801\u751f\u6210\u6a21\u7248\uff0c\u5404\u5e73\u53f0\u7ee7\u627f\u6a21\u7248\u7236\u7c7b\u8d1f\u8d23\u903b\u8f91\u5b9e\u73b0\uff0c\u540e\u7eed\u53ef\u4ee5\u9488\u5bf9iOS\u5e73\u53f0\u63d0\u4f9bMetal\u7ed8\u5236\u5b9e\u73b0<\/span><\/p>\n<pre class=\"lang:default highlight:0 decode:true \">class ProgramCreator {\r\n public:\r\n  virtual ~ProgramCreator() = default;\r\n  virtual void computeUniqueKey(Context* context, BytesKey* uniqueKey) const = 0;\r\n  virtual std::unique_ptr&lt;Program&gt; createProgram(Context* context) const = 0;\r\n};\r\n\r\nclass GLProgramCreator : public ProgramCreator {\r\n public:\r\n  GLProgramCreator(const GeometryProcessor* geometryProcessor, const Pipeline* pipeline);\r\n  void computeUniqueKey(Context* context, BytesKey* uniqueKey) const override;\r\n  std::unique_ptr&lt;Program&gt; createProgram(Context* context) const override;\r\n};\r\n\r\nstd::unique_ptr&lt;Program&gt; GLProgramCreator::createProgram(Context* context) const {\r\n  return GLProgramBuilder::CreateProgram(context, geometryProcessor, pipeline);\r\n}<\/pre>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u81f3\u6b64\uff0c PAG\u52a8\u6548\u6846\u67b6\u6e90\u7801\u5c31\u5168\u90e8\u8bb2\u89e3\u5b8c\u6210<\/span><\/p>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u6846\u67b6\u4e2d\u8fd8\u6709\u5927\u91cf\u672c\u6587\u672a\u63d0\u5230\u7684\u5185\u5bb9\uff0c\u6bd4\u5982\u6ee4\u955c\u3001\u6587\u672c\u3001\u56fe\u5f62\u7ed8\u5236\u7b49\u7b49\uff0c\u6709\u5174\u8da3\u7684\u540c\u5b66\u5efa\u8bae\u9605\u8bfb\u6e90\u7801<\/span><\/p>\n<p class=\"md-end-block md-p\"><span class=\"md-plain\">\u76f8\u4fe1\u672a\u6765\u884c\u4e1a\u5185\u4f1a\u6709\u5927\u91cf\u7c7b\u4f3c\u7684\u89e3\u51b3\u65b9\u6848\uff0c\u6bd4\u5982\u57fa\u4e8eMP4\u65b9\u6848\u7684\u591a\u56fe\u5c42\u7ed8\u5236\u6846\u67b6\u7b49<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u8f6c\u8f7d\u8bf7\u6ce8\u660e\u51fa\u5904\uff1ahttp:\/\/www.olinone.com\/ \u524d\u8a00 \u4e0a\u4e00\u7ae0\u4ecb\u7ecd\u4e86TGFX\u6e32\u67d3\u6846\u67b6\u7684\u5927\u81f4\u7ed3\u6784\uff0c\u2026 <span class=\"read-more\"><a href=\"http:\/\/www.olinone.com\/?p=948\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/posts\/948"}],"collection":[{"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.olinone.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=948"}],"version-history":[{"count":9,"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/posts\/948\/revisions"}],"predecessor-version":[{"id":958,"href":"http:\/\/www.olinone.com\/index.php?rest_route=\/wp\/v2\/posts\/948\/revisions\/958"}],"wp:attachment":[{"href":"http:\/\/www.olinone.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=948"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.olinone.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=948"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.olinone.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=948"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}