{"id":2750,"date":"2020-10-03T18:02:42","date_gmt":"2020-10-03T10:02:42","guid":{"rendered":"http:\/\/blog.coolcoding.cn\/?p=2750"},"modified":"2020-10-03T18:06:17","modified_gmt":"2020-10-03T10:06:17","slug":"%e8%ae%a9renderdoc%e6%89%b9%e9%87%8f%e5%af%bc%e5%87%ba%e7%ba%b9%e7%90%86","status":"publish","type":"post","link":"https:\/\/blog.coolcoding.cn\/?p=2750","title":{"rendered":"\u8ba9RenderDoc\u6279\u91cf\u5bfc\u51fa\u7eb9\u7406"},"content":{"rendered":"\n<p>RenderDoc\u5bfc\u51fa\u7eb9\u7406\u65f6\u53ea\u80fd\u4e00\u5f20\u5f20\u5bfc\u51fa\uff0c\u975e\u5e38\u9ebb\u70e6\uff0c\u6539\u4e00\u4e0bRenderDoc\uff0c\u6548\u679c\u5982\u4e0b<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"691\" height=\"323\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2020\/10\/image.png\" alt=\"\" class=\"wp-image-2751\" srcset=\"https:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2020\/10\/image.png 691w, https:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2020\/10\/image-300x140.png 300w, https:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2020\/10\/image-70x33.png 70w\" sizes=\"(max-width: 691px) 100vw, 691px\" \/><\/figure>\n\n\n\n<p>\u4e00\u3001qrenderdoc\\Windows\\TextureViewer.ui\u4e2d\u8ffd\u52a02\u4e2a\u6309\u94ae<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;item>\n     &lt;widget class=\"QToolButton\" name=\"saveTex\">\n      &lt;property name=\"toolTip\">\n       &lt;string>Save selected Texture&lt;\/string>\n      &lt;\/property>\n      &lt;property name=\"text\">\n       &lt;string\/>\n      &lt;\/property>\n      &lt;property name=\"icon\">\n       &lt;iconset resource=\"..\/Resources\/resources.qrc\">\n        &lt;normaloff>:\/save.png&lt;\/normaloff>:\/save.png&lt;\/iconset>\n      &lt;\/property>\n      &lt;property name=\"autoRaise\">\n       &lt;bool>true&lt;\/bool>\n      &lt;\/property>\n     &lt;\/widget>\n    &lt;\/item>\n&lt;item>\n\n\/\/ \u8ffd\u52a0\u4ee5\u4e0b\u4ee3\u7801\n\n    &lt;widget class=\"QToolButton\" name=\"saveTexs\">\n        &lt;property name=\"toolTip\">\n            &lt;string>Batch Save Textures => d:\\\\capture\\\\ &lt;\/string>\n        &lt;\/property>\n        &lt;property name=\"text\">\n            &lt;string\/>\n        &lt;\/property>\n        &lt;property name=\"icon\">\n            &lt;iconset resource=\"..\/Resources\/resources.qrc\">\n                &lt;normaloff>:\/save2.png&lt;\/normaloff>:\/save2.png&lt;\/iconset>\n        &lt;\/property>\n        &lt;property name=\"autoRaise\">\n            &lt;bool>true&lt;\/bool>\n        &lt;\/property>\n    &lt;\/widget>\n    &lt;\/item>\n    &lt;item>\n     &lt;widget class=\"QToolButton\" name=\"saveAllTex\">\n      &lt;property name=\"toolTip\">\n       &lt;string>Save all Textures => d:\\\\capture\\\\ &lt;\/string>\n      &lt;\/property>\n      &lt;property name=\"text\">\n       &lt;string\/>\n      &lt;\/property>\n      &lt;property name=\"icon\">\n       &lt;iconset resource=\"..\/Resources\/resources.qrc\">\n        &lt;normaloff>:\/save3.png&lt;\/normaloff>:\/save3.png&lt;\/iconset>\n      &lt;\/property>\n      &lt;property name=\"autoRaise\">\n       &lt;bool>true&lt;\/bool>\n      &lt;\/property>\n     &lt;\/widget>\n    &lt;\/item>\n    &lt;item><\/code><\/pre>\n\n\n\n<p>\u4e8c\u3001qrenderdoc\/Code\/Resources.h\u4e2d\u8ffd\u52a02\u4e2a\u56fe\u6807<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  RESOURCE_DEF(save, \"save.png\")                                        \\\n  RESOURCE_DEF(save2, \"save2.png\")                                      \\\n  RESOURCE_DEF(save3, \"save3.png\")                                      \\<\/code><\/pre>\n\n\n\n<p>\u4e09\u3001qrenderdoc\/Resources\/\u76ee\u5f55\u4e2d\u6dfb\u52a0\u51e0\u4e2a\u65b0\u56fe\u6807\uff0csave2.png, save2@2x.png, save3.png, save3@2x.png<\/p>\n\n\n\n<p>\u56db\u3001qrenderdoc\/Resources\/resources.qrc\u4e2d\u8ffd\u52a02\u4e2a\u56fe\u6807<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        &lt;file>save.png&lt;\/file>\n        &lt;file>save2.png&lt;\/file>\n        &lt;file>save3.png&lt;\/file><\/code><\/pre>\n\n\n\n<p>\u4e94\u3001\u5728qrenderdoc\/Windows\/TextureViewer.cpp\u4e2d\u8ffd\u52a0\u4ee3\u7801<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\nstatic TextureSave tmpSaveCfg;\n\nvoid TextureViewer::SaveStageResourcePreviews(ShaderStage stage,\n                                              const rdcarray&lt;ShaderResource> &amp;resourceDetails,\n                                              const rdcarray&lt;Bindpoint> &amp;mapping,\n                                              rdcarray&lt;BoundResourceArray> &amp;ResList,\n                                              int &amp;prevIndex, bool copy,\n                                              bool rw, const QString&amp; savePath)\n{\n  for(int idx=0; idx &lt; mapping.count(); idx++)\n  {\n    const Bindpoint &amp;key = mapping[idx];\n\n    const rdcarray&lt;BoundResource> *resArray = NULL;\n    uint32_t dynamicallyUsedResCount = 1;\n    int32_t firstIndex = 0;\n\n    int residx = ResList.indexOf(key);\n    if(residx >= 0)\n    {\n      resArray = &amp;ResList[residx].resources;\n      dynamicallyUsedResCount = ResList[residx].dynamicallyUsedCount;\n      firstIndex = ResList[residx].firstIndex;\n    }\n\n    int arrayLen = resArray != NULL ? resArray->count() : 1;\n\n    const bool collapseArray = arrayLen > 8 &amp;&amp; (dynamicallyUsedResCount > 20 || m_ShowUnused);\n\n    for(int i = 0; i &lt; arrayLen; i++)\n    {\n      int arrayIdx = firstIndex + i;\n\n      if(resArray &amp;&amp; i >= resArray->count())\n        break;\n\n      if(resArray &amp;&amp; !resArray->at(i).dynamicallyUsed)\n        continue;\n\n      BoundResource res = {};\n\n      if(resArray)\n        res = resArray->at(i);\n\n      Following follow(*this, rw ? FollowType::ReadWrite : FollowType::ReadOnly, stage, idx,\n                       arrayIdx);\n\n      \/\/ show if it's referenced by the shader - regardless of empty or not\n      bool show = key.used || copy;\n\n      \/\/ it's bound, but not referenced, and we have \"show disabled\"\n      show = show || (m_ShowUnused &amp;&amp; res.resourceId != ResourceId());\n\n      \/\/ it's empty, and we have \"show empty\"\n      show = show || (m_ShowEmpty &amp;&amp; res.resourceId == ResourceId());\n\n      \/\/ it's the one we're following\n      show = show || (follow == m_Following);\n\n      if(!show)\n      {\n        continue;\n      }\n      \n      tmpSaveCfg.resourceId = res.resourceId;\n      tmpSaveCfg.destType = FileType::TGA;\n      tmpSaveCfg.channelExtract = -1;\n      tmpSaveCfg.alphaCol = FloatVector(0, 0, 0, 0);\n\n      uint64_t currId = *((uint64_t*)&amp;res.resourceId);\n      QString fn = QString(tr(\"%1\\\\%2.tga\")).arg(savePath).arg(currId);\n\n      bool ret = false;\n      m_Ctx.Replay().BlockInvoke([this, &amp;ret, fn](IReplayController *r) \n      {\n        ret = r->SaveTexture(tmpSaveCfg, fn.toUtf8().data());\n      });\n    }\n  }\n}\n\nstatic uint captureBatch = 0;\n\nvoid TextureViewer::on_saveTexs_clicked()\n{\n  int outIndex = 0;\n  int inIndex = 0;\n\n  bool copy = false, clear = false, compute = false;\n  Following::GetDrawContext(m_Ctx, copy, clear, compute);\n\n  ShaderStage stages[] = {ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain,\n                          ShaderStage::Geometry, ShaderStage::Pixel};\n\n  int count = 5;\n\n  if(compute)\n  {\n    stages[0] = ShaderStage::Compute;\n    count = 1;\n  }\n\n  const rdcarray&lt;ShaderResource> empty;\n\n  QString currDir;\n  for(int i = 0; i &lt; 2048; ++i)\n  {\n    ++captureBatch;\n    currDir = QString(tr(\"d:\\\\capture\\\\cap_%1\")).arg(captureBatch);\n    QDir dir(currDir);\n    if(dir.exists())\n    {\n      continue;\n    }\n\n    dir.mkpath(currDir);\n    break;\n  }\n\n  \/\/ display resources used for all stages\n  for(int i = 0; i &lt; count; i++)\n  {\n    ShaderStage stage = stages[i];\n\n    m_ReadWriteResources[(uint32_t)stage] =\n        Following::GetReadWriteResources(m_Ctx, stage, !m_ShowUnused);\n    m_ReadOnlyResources[(uint32_t)stage] =\n        Following::GetReadOnlyResources(m_Ctx, stage, !m_ShowUnused);\n\n    const ShaderReflection *details = Following::GetReflection(m_Ctx, stage);\n    const ShaderBindpointMapping &amp;mapping = Following::GetMapping(m_Ctx, stage);\n\n    SaveStageResourcePreviews(stage, details != NULL ? details->readOnlyResources : empty,\n                              mapping.readOnlyResources, m_ReadOnlyResources[(uint32_t)stage],\n                              inIndex, copy, false, currDir);\n  }\n}\n\nvoid TextureViewer::on_saveAllTex_clicked()\n{\n  for(const TextureDescription &amp;tex : m_Ctx.GetTextures())\n  {\n    tmpSaveCfg.resourceId = tex.resourceId;\n    tmpSaveCfg.destType = FileType::TGA;\n    tmpSaveCfg.channelExtract = -1;\n    tmpSaveCfg.alphaCol = FloatVector(0, 0, 0, 0);\n\n    QString fn;\n    fn.sprintf(\"d:\\\\capture\\\\%d.tga\", tex.resourceId);\n    \n    QFileInfo qi(fn);\n    QDir dir(qi.absoluteDir());\n    if (!dir.exists())\n    {\n      dir.makeAbsolute();\n    }\n\n    bool ret = false;\n    m_Ctx.Replay().BlockInvoke([this, &amp;ret, fn](IReplayController *r) {\n      ret = r->SaveTexture(tmpSaveCfg, fn.toUtf8().data());\n    });\n  }\n}<\/code><\/pre>\n\n\n\n<p>\u7136\u540e\u5934\u6587\u4ef6\u4e2d\u8ffd\u52a0<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void on_saveTexs_clicked();\nvoid on_saveAllTex_clicked();\n\nvoid SaveStageResourcePreviews(ShaderStage stage, const rdcarray &amp;resourceDetails, const rdcarray &amp;mapping, rdcarray &amp;ResList, int &amp;prevIndex, bool copy, bool rw, const QString&amp; savePath);<\/code><\/pre>\n\n\n\n<p>\u7136\u540e\u6784\u5efa\u540e\uff0c\u70b9\u9ec4\u8272\u6309\u94ae\u53ef\u6279\u91cf\u5bfc\u51fa\u7eb9\u7406\u5230 d:\\capture\\cap_XXX \u76ee\u5f55\u4e2d<br>\u70b9\u7d2b\u8272\u6309\u94ae\u53ef\u5bfc\u51fa\u6240\u6709\u7eb9\u7406\u5230 d:\\capture\\\u76ee\u5f55\u4e2d<br>\u4e5f\u4e0d\u4f1a\u5f39\u51fa\u5bf9\u8bdd\u6846\u4e86\uff0c\u5b9e\u4e43\u6316\u56fe\u5229\u5668<\/p>\n\n\n\n<p><a href=\"http:\/\/blog.coolcoding.cn\/?p=2271\">\u5bfc\u51faMesh\u53ef\u4ee5\u53c2\u8003\u8fd9\u4e2a<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>RenderDoc\u5bfc\u51fa\u7eb9\u7406\u65f6\u53ea\u80fd\u4e00\u5f20\u5f20\u5bfc\u51fa\uff0c\u975e\u5e38\u9ebb\u70e6\uff0c\u6539\u4e00\u4e0bRenderDoc\uff0c\u6548\u679c\u5982\u4e0b \u4e00\u3001qrenderd [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/2750"}],"collection":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2750"}],"version-history":[{"count":3,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/2750\/revisions"}],"predecessor-version":[{"id":2754,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/2750\/revisions\/2754"}],"wp:attachment":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}