lamiastella

replay_renderer.cpp

Dec 16th, 2016
278
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 72.62 KB | None | 0 0
  1. /******************************************************************************
  2.  * The MIT License (MIT)
  3.  *
  4.  * Copyright (c) 2014 Crytek
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7.  * of this software and associated documentation files (the "Software"), to deal
  8.  * in the Software without restriction, including without limitation the rights
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.  * copies of the Software, and to permit persons to whom the Software is
  11.  * furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in
  14.  * all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22.  * THE SOFTWARE.
  23.  ******************************************************************************/
  24.  
  25.  
  26. #include "replay_renderer.h"
  27.  
  28. #include <string.h>
  29. #include <time.h>
  30.  
  31. #include "serialise/string_utils.h"
  32. #include "maths/formatpacking.h"
  33. #include "os/os_specific.h"
  34.  
  35. #include "serialise/serialiser.h"
  36.  
  37. #include "jpeg-compressor/jpgd.h"
  38. #include "jpeg-compressor/jpge.h"
  39. #include "stb/stb_image.h"
  40. #include "stb/stb_image_write.h"
  41.  
  42. /* Removed by Stephan Richter | BEGIN */
  43. //#include "tinyexr/tinyexr.h"
  44. /* Removed by Stephan Richter | END */
  45.  
  46. #include "common/dds_readwrite.h"
  47.  
  48. /* Added by Stephan Richter | BEGIN */
  49.  
  50. /*CHANGED BY MONA*/
  51. /*
  52. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfOutputFile.h"
  53. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfInputFile.h"
  54. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfChannelList.h"
  55. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfStringAttribute.h"
  56. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfMatrixAttribute.h"
  57. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfArray.h"
  58. #include "C:\Users\mona\playing-for-data\renderdoc\renderdoc\3rdparty\openexr\OpenEXR\IlmImf\ImfNamespace.h"
  59.  
  60. */
  61.  
  62.  
  63. ORIGINAL
  64. #include <ImfOutputFile.h>
  65. #include <ImfInputFile.h>
  66. #include <ImfChannelList.h>
  67. #include <ImfStringAttribute.h>
  68. #include <ImfMatrixAttribute.h>
  69. #include <ImfArray.h>
  70. #include <ImfNamespace.h>
  71.  
  72.  
  73. /* NOT ORIGINAL
  74. #include "ImfOutputFile.h"
  75. #include "ImfInputFile.h"
  76. #include "ImfChannelList.h"
  77. #include "ImfStringAttribute.h"
  78. #include "ImfMatrixAttribute.h"
  79. #include "ImfArray.h"
  80. #include "ImfNamespace.h"
  81. */
  82. #include "replay/MurmurHash3.h"
  83. namespace IMF = OPENEXR_IMF_NAMESPACE;
  84.  
  85. /* Added by Stephan Richter | END */
  86.  
  87. float ConvertComponent(ResourceFormat fmt, byte *data)
  88. {
  89.     if(fmt.compByteWidth == 4)
  90.     {
  91.         uint32_t *u32 = (uint32_t *)data;
  92.         int32_t *i32 = (int32_t *)data;
  93.  
  94.         if(fmt.compType == eCompType_Float)
  95.         {
  96.             return *(float *)u32;
  97.         }
  98.         else if(fmt.compType == eCompType_UInt)
  99.         {
  100.             return float(*u32);
  101.         }
  102.         else if(fmt.compType == eCompType_SInt)
  103.         {
  104.             return float(*i32);
  105.         }
  106.     }
  107.     else if(fmt.compByteWidth == 2)
  108.     {
  109.         uint16_t *u16 = (uint16_t *)data;
  110.         int16_t *i16 = (int16_t *)data;
  111.  
  112.         if(fmt.compType == eCompType_Float)
  113.         {
  114.             return ConvertFromHalf(*u16);
  115.         }
  116.         else if(fmt.compType == eCompType_UInt)
  117.         {
  118.             return float(*u16);
  119.         }
  120.         else if(fmt.compType == eCompType_SInt)
  121.         {
  122.             return float(*i16);
  123.         }
  124.         else if(fmt.compType == eCompType_UNorm)
  125.         {
  126.             return float(*u16)/65535.0f;
  127.         }
  128.         else if(fmt.compType == eCompType_SNorm)
  129.         {
  130.             float f = -1.0f;
  131.  
  132.             if(*i16 == -32768)
  133.                 f = -1.0f;
  134.             else
  135.                 f = ((float)*i16) / 32767.0f;
  136.  
  137.             return f;
  138.         }
  139.     }
  140.     else if(fmt.compByteWidth == 1)
  141.     {
  142.         uint8_t *u8 = (uint8_t *)data;
  143.         int8_t *i8 = (int8_t *)data;
  144.        
  145.         if(fmt.compType == eCompType_UInt)
  146.         {
  147.             return float(*u8);
  148.         }
  149.         else if(fmt.compType == eCompType_SInt)
  150.         {
  151.             return float(*i8);
  152.         }
  153.         else if(fmt.compType == eCompType_UNorm)
  154.         {
  155.             if(fmt.srgbCorrected)
  156.                 return SRGB8_lookuptable[*u8];
  157.             else
  158.                 return float(*u8)/255.0f;
  159.         }
  160.         else if(fmt.compType == eCompType_SNorm)
  161.         {
  162.             float f = -1.0f;
  163.  
  164.             if(*i8 == -128)
  165.                 f = -1.0f;
  166.             else
  167.                 f = ((float)*i8) / 127.0f;
  168.  
  169.             return f;
  170.         }
  171.     }
  172.  
  173.     RDCERR("Unexpected format to convert from");
  174.  
  175.     return 0.0f;
  176. }
  177.  
  178. ReplayRenderer::ReplayRenderer()
  179. {
  180.     m_pDevice = NULL;
  181.  
  182.     m_FrameID = 0;
  183.     m_EventID = 100000;
  184.  
  185.     m_DeferredCtx = ResourceId();
  186.     m_FirstDeferredEvent = 0;
  187.     m_LastDeferredEvent = 0;
  188. }
  189.  
  190. ReplayRenderer::~ReplayRenderer()
  191. {
  192.     for(size_t i=0; i < m_Outputs.size(); i++)
  193.         SAFE_DELETE(m_Outputs[i]);
  194.  
  195.     m_Outputs.clear();
  196.  
  197.     for(auto it=m_CustomShaders.begin(); it != m_CustomShaders.end(); ++it)
  198.         m_pDevice->FreeCustomShader(*it);
  199.  
  200.     m_CustomShaders.clear();
  201.  
  202.     for(auto it=m_TargetResources.begin(); it != m_TargetResources.end(); ++it)
  203.         m_pDevice->FreeTargetResource(*it);
  204.  
  205.     m_TargetResources.clear();
  206.    
  207.     if(m_pDevice)
  208.         m_pDevice->Shutdown();
  209.     m_pDevice = NULL;
  210. }
  211.  
  212. bool ReplayRenderer::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv)
  213. {
  214.     if(m_DeferredCtx == ResourceId() && id == ResourceId())
  215.         return true;
  216.  
  217.     m_pDevice->SetContextFilter(id, firstDefEv, lastDefEv);
  218.    
  219.     m_DeferredCtx = id;
  220.     m_FirstDeferredEvent = firstDefEv;
  221.     m_LastDeferredEvent = lastDefEv;
  222.  
  223.     for(size_t i=0; i < m_Outputs.size(); i++)
  224.         m_Outputs[i]->SetContextFilter(id, firstDefEv, lastDefEv);
  225.    
  226.     SetFrameEvent(m_FrameID, m_EventID, true);
  227.  
  228.     return true;
  229. }
  230.  
  231. bool ReplayRenderer::SetFrameEvent(uint32_t frameID, uint32_t eventID)
  232. {
  233.     return SetFrameEvent(frameID, eventID, false);
  234. }
  235.  
  236. /* Added by Stephan Richter | BEGIN */
  237. void ReplayRenderer::SetIDRenderingEvents(uint32_t frameID, uint32_t startEventID, uint32_t endEventID)
  238. {
  239.     m_pDevice->SetIDRenderingEvents(frameID, startEventID, endEventID);
  240. }
  241.  
  242. void ReplayRenderer::SetIDRendering(bool active, ResourceId shaderID)
  243. {
  244.     m_pDevice->SetIDRendering(active, shaderID);
  245. }
  246. /* Added by Stephan Richter | END */
  247.  
  248. bool ReplayRenderer::SetFrameEvent(uint32_t frameID, uint32_t eventID, bool force)
  249. {
  250.     if(m_FrameID != frameID || eventID != m_EventID || force)
  251.     {
  252.         m_FrameID = frameID;
  253.         m_EventID = eventID;
  254.  
  255.         m_pDevice->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw);
  256.  
  257.         FetchPipelineState();
  258.  
  259.         for(size_t i=0; i < m_Outputs.size(); i++)
  260.             m_Outputs[i]->SetFrameEvent(frameID, eventID);
  261.        
  262.         m_pDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw);
  263.     }
  264.  
  265.     return true;
  266. }
  267.  
  268. bool ReplayRenderer::GetD3D11PipelineState(D3D11PipelineState *state)
  269. {
  270.     if(state)
  271.     {
  272.         *state = m_D3D11PipelineState;
  273.         return true;
  274.     }
  275.    
  276.     return false;
  277. }
  278.  
  279. bool ReplayRenderer::GetGLPipelineState(GLPipelineState *state)
  280. {
  281.     if(state)
  282.     {
  283.         *state = m_GLPipelineState;
  284.         return true;
  285.     }
  286.    
  287.     return false;
  288. }
  289.  
  290. bool ReplayRenderer::GetFrameInfo(rdctype::array<FetchFrameInfo> *arr)
  291. {
  292.     if(arr == NULL) return false;
  293.  
  294.     create_array_uninit(*arr, m_FrameRecord.size());
  295.     for(size_t i=0; i < m_FrameRecord.size(); i++)
  296.         arr->elems[i] = m_FrameRecord[i].frameInfo;
  297.  
  298.     return true;
  299. }
  300.  
  301. FetchDrawcall *ReplayRenderer::GetDrawcallByEID(uint32_t eventID, uint32_t defEventID)
  302. {
  303.     uint32_t ev = defEventID > 0 ? defEventID : eventID;
  304.  
  305.     if(ev >= m_Drawcalls.size())
  306.         return NULL;
  307.  
  308.     return m_Drawcalls[ev];
  309. }
  310.  
  311. bool ReplayRenderer::GetDrawcalls(uint32_t frameID, rdctype::array<FetchDrawcall> *draws)
  312. {
  313.     if(frameID >= (uint32_t)m_FrameRecord.size() || draws == NULL)
  314.         return false;
  315.  
  316.     *draws = m_FrameRecord[frameID].m_DrawCallList;
  317.     return true;
  318. }
  319.  
  320. bool ReplayRenderer::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID,
  321.                                    uint32_t *counters, uint32_t numCounters, rdctype::array<CounterResult> *results)
  322. {
  323.     if(frameID >= (uint32_t)m_FrameRecord.size() || results == NULL)
  324.         return false;
  325.  
  326.     vector<uint32_t> counterArray;
  327.     counterArray.reserve(numCounters);
  328.     for(uint32_t i=0; i < numCounters; i++)
  329.         counterArray.push_back(counters[i]);
  330.  
  331.     *results = m_pDevice->FetchCounters(frameID, minEventID, maxEventID, counterArray);
  332.    
  333.     return true;
  334. }
  335.        
  336. bool ReplayRenderer::EnumerateCounters(rdctype::array<uint32_t> *counters)
  337. {
  338.     if(counters == NULL)
  339.         return false;
  340.  
  341.     *counters = m_pDevice->EnumerateCounters();
  342.  
  343.     return true;
  344. }
  345.  
  346. bool ReplayRenderer::DescribeCounter(uint32_t counterID, CounterDescription *desc)
  347. {
  348.     if(desc == NULL)
  349.         return false;
  350.    
  351.     m_pDevice->DescribeCounter(counterID, *desc);
  352.  
  353.     return true;
  354. }
  355.  
  356. bool ReplayRenderer::GetBuffers(rdctype::array<FetchBuffer> *out)
  357. {
  358.     if(m_Buffers.empty())
  359.     {
  360.         vector<ResourceId> ids = m_pDevice->GetBuffers();
  361.  
  362.         m_Buffers.resize(ids.size());
  363.  
  364.         for(size_t i=0; i < ids.size(); i++)
  365.             m_Buffers[i] = m_pDevice->GetBuffer(ids[i]);
  366.     }
  367.  
  368.     if(out)
  369.     {
  370.         *out = m_Buffers;
  371.         return true;
  372.     }
  373.  
  374.     return false;
  375. }
  376.  
  377. /* Added by Stephan Richter | BEGIN */
  378. bool ReplayRenderer::GetPixelShaders(rdctype::array<FetchShader> *out)
  379. {
  380.     if (m_Shaders.empty())
  381.     {
  382.         vector<ResourceId> ids = m_pDevice->GetPixelShaders();
  383.  
  384.         m_Shaders.resize(ids.size());
  385.  
  386.         for (size_t i = 0; i < ids.size(); i++)
  387.         {
  388.             m_Shaders[i] = FetchShader();
  389.             m_Shaders[i].ID = ids[i];
  390.         }          
  391.     }
  392.  
  393.     if (out)
  394.     {
  395.         *out = m_Shaders;
  396.         return true;
  397.     }
  398.  
  399.     return false;
  400. }
  401. /* Added by Stephan Richter | END */
  402.  
  403. bool ReplayRenderer::GetTextures(rdctype::array<FetchTexture> *out)
  404. {
  405.     if(m_Textures.empty())
  406.     {
  407.         vector<ResourceId> ids = m_pDevice->GetTextures();
  408.  
  409.         m_Textures.resize(ids.size());
  410.  
  411.         for(size_t i=0; i < ids.size(); i++)
  412.             m_Textures[i] = m_pDevice->GetTexture(ids[i]);
  413.     }
  414.    
  415.     if(out)
  416.     {
  417.         *out = m_Textures;
  418.         return true;
  419.     }
  420.  
  421.     return false;
  422. }
  423.  
  424. bool ReplayRenderer::GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::str> *arr)
  425. {
  426.     if(arr == NULL || callstack == NULL || callstackLen == 0) return false;
  427.  
  428.     Callstack::StackResolver *resolv = m_pDevice->GetCallstackResolver();
  429.  
  430.     if(resolv == NULL)
  431.     {
  432.         create_array_uninit(*arr, 1);
  433.         arr->elems[0] = "";
  434.         return true;
  435.     }
  436.  
  437.     create_array_uninit(*arr, callstackLen);
  438.     for(size_t i=0; i < callstackLen; i++)
  439.     {
  440.         Callstack::AddressDetails info = resolv->GetAddr(callstack[i]);
  441.         arr->elems[i] = info.formattedString();
  442.     }
  443.  
  444.     return true;
  445. }
  446.  
  447. bool ReplayRenderer::GetDebugMessages(rdctype::array<DebugMessage> *msgs)
  448. {
  449.     if(msgs)
  450.     {
  451.         *msgs = m_pDevice->GetDebugMessages();
  452.         return true;
  453.     }
  454.  
  455.     return false;
  456. }
  457.  
  458. bool ReplayRenderer::GetUsage(ResourceId id, rdctype::array<EventUsage> *usage)
  459. {
  460.     if(usage)
  461.     {
  462.         *usage = m_pDevice->GetUsage(m_pDevice->GetLiveID(id));
  463.         return true;
  464.     }
  465.  
  466.     return false;
  467. }
  468.  
  469. bool ReplayRenderer::GetPostVSData(uint32_t instID, MeshDataStage stage, MeshFormat *data)
  470. {
  471.     if(data == NULL) return false;
  472.  
  473.     FetchDrawcall *draw = GetDrawcallByEID(m_EventID, m_LastDeferredEvent);
  474.    
  475.     MeshFormat ret;
  476.     RDCEraseEl(ret);
  477.  
  478.     if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) return false;
  479.  
  480.     if(instID >= RDCMAX(1U, draw->numInstances)) return false;
  481.  
  482.     *data = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, instID, stage);
  483.  
  484.     return true;
  485. }
  486.  
  487. bool ReplayRenderer::GetMinMax(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval)
  488. {
  489.     PixelValue *a = minval;
  490.     PixelValue *b = maxval;
  491.  
  492.     PixelValue dummy;
  493.  
  494.     if(a == NULL) a = &dummy;
  495.     if(b == NULL) b = &dummy;
  496.  
  497.     return m_pDevice->GetMinMax(m_pDevice->GetLiveID(tex), sliceFace, mip, sample, &a->value_f[0], &b->value_f[0]);
  498. }
  499.  
  500. bool ReplayRenderer::GetHistogram(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], rdctype::array<uint32_t> *histogram)
  501. {
  502.     if(histogram == NULL) return false;
  503.  
  504.     vector<uint32_t> hist;
  505.  
  506.     bool ret = m_pDevice->GetHistogram(m_pDevice->GetLiveID(tex), sliceFace, mip, sample, minval, maxval, channels, hist);
  507.  
  508.     if(ret)
  509.         *histogram = hist;
  510.  
  511.     return ret;
  512. }
  513.  
  514. bool ReplayRenderer::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len, rdctype::array<byte> *data)
  515. {
  516.     if(data == NULL) return false;
  517.  
  518.     *data = m_pDevice->GetBufferData(m_pDevice->GetLiveID(buff), offset, len);
  519.  
  520.     return true;
  521. }
  522.  
  523. bool ReplayRenderer::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, rdctype::array<byte> *data)
  524. {
  525.     if(data == NULL) return false;
  526.  
  527.     size_t sz;
  528.     byte *bytes = m_pDevice->GetTextureData(m_pDevice->GetLiveID(tex), arrayIdx, mip, false, false, 0.0f, 0.0f, sz);
  529.  
  530.     create_array_uninit(*data, sz);
  531.     memcpy(data->elems, bytes, sz);
  532.  
  533.     delete[] bytes;
  534.  
  535.     return true;
  536. }
  537.  
  538. /* Added by Stephan Richter | BEGIN */
  539. bool ReplayRenderer::GetShaderData(ResourceId buff, rdctype::array<byte> *data)
  540. {
  541.     if (data == NULL) return false;
  542.  
  543.     *data = m_pDevice->GetShaderData(m_pDevice->GetLiveID(buff));
  544.  
  545.     return true;
  546. }
  547. /* Added by Stephan Richter | END */
  548.  
  549. bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path)
  550. {
  551.     TextureSave sd = saveData; // mutable copy
  552.     ResourceId liveid = m_pDevice->GetLiveID(sd.id);
  553.     FetchTexture td = m_pDevice->GetTexture(liveid);
  554.  
  555.     bool success = false;
  556.    
  557.     // clamp sample/mip/slice indices
  558.     if(td.msSamp == 1)
  559.     {
  560.         sd.sample.sampleIndex = 0;
  561.         sd.sample.mapToArray = false;
  562.     }
  563.     else
  564.     {
  565.         if(sd.sample.sampleIndex != ~0U)
  566.             sd.sample.sampleIndex = RDCCLAMP(sd.sample.sampleIndex, 0U, td.msSamp);
  567.     }
  568.  
  569.     // don't support cube cruciform for non cubemaps, or
  570.     // cubemap arrays
  571.     if(!td.cubemap || td.arraysize != 6 || td.msSamp != 1)
  572.         sd.slice.cubeCruciform = false;
  573.  
  574.     if(sd.mip != -1)
  575.         sd.mip = RDCCLAMP(sd.mip, 0, (int32_t)td.mips);
  576.     if(sd.slice.sliceIndex != -1)
  577.         sd.slice.sliceIndex = RDCCLAMP(sd.slice.sliceIndex, 0, int32_t(td.arraysize*td.depth));
  578.  
  579.     if(td.arraysize*td.depth*td.msSamp == 1)
  580.     {
  581.         sd.slice.sliceIndex = 0;
  582.         sd.slice.slicesAsGrid = false;
  583.     }
  584.  
  585.     // can't extract a channel that's not in the source texture
  586.     if(sd.channelExtract >= 0 && (uint32_t)sd.channelExtract >= td.format.compCount)
  587.         sd.channelExtract = -1;
  588.  
  589.     sd.slice.sliceGridWidth = RDCMAX(sd.slice.sliceGridWidth, 1);
  590.  
  591.     // store sample count so we know how many 'slices' is one real slice
  592.     // multisampled textures cannot have mips, subresource layout is same as would be for mips:
  593.     // [slice0 sample0], [slice0 sample1], [slice1 sample0], [slice1 sample1]
  594.     uint32_t sampleCount = td.msSamp;
  595.     bool multisampled = td.msSamp > 1;
  596.    
  597.     bool resolveSamples = (sd.sample.sampleIndex == ~0U);
  598.  
  599.     if(resolveSamples)
  600.     {
  601.         td.msSamp = 1;
  602.         sd.sample.mapToArray = false;
  603.         sd.sample.sampleIndex = 0;
  604.     }
  605.  
  606.     // treat any multisampled texture as if it were an array
  607.     // of <sample count> dimension (on top of potential existing array
  608.     // dimension). GetTextureData() uses the same convention.
  609.     if(td.msSamp > 1)
  610.     {
  611.         td.arraysize *= td.msSamp;
  612.         td.msSamp = 1;
  613.     }
  614.    
  615.     if(sd.destType != eFileType_DDS && sd.sample.mapToArray && !sd.slice.slicesAsGrid && sd.slice.sliceIndex == -1)
  616.     {
  617.         sd.sample.mapToArray = false;
  618.         sd.sample.sampleIndex = 0;
  619.     }
  620.  
  621.     // only DDS supports writing multiple mips, fall back to mip 0 if 'all mips' was specified
  622.     if(sd.destType != eFileType_DDS && sd.mip == -1)
  623.         sd.mip = 0;
  624.  
  625.     // only DDS supports writing multiple slices, fall back to slice 0 if 'all slices' was specified
  626.     if(sd.destType != eFileType_DDS && sd.slice.sliceIndex == -1 && !sd.slice.slicesAsGrid && !sd.slice.cubeCruciform)
  627.         sd.slice.sliceIndex = 0;
  628.  
  629.     // fetch source data subresources (typically only one, possibly more
  630.     // if we're writing to DDS (so writing multiple mips/slices) or resolving
  631.     // down a multisampled texture for writing as a single 'image' elsewhere)
  632.     uint32_t sliceOffset = 0;
  633.     uint32_t sliceStride = 1;
  634.     uint32_t numSlices = td.arraysize*td.depth;
  635.  
  636.     uint32_t mipOffset = 0;
  637.     uint32_t numMips = td.mips;
  638.  
  639.     bool singleSlice = (sd.slice.sliceIndex != -1);
  640.  
  641.     // set which slices/mips we need
  642.     if(multisampled)
  643.     {
  644.         bool singleSample = !sd.sample.mapToArray;
  645.        
  646.         // multisampled images have no mips
  647.         mipOffset = 0;
  648.         numMips = 1;
  649.  
  650.         if(singleSlice)
  651.         {
  652.             if(singleSample)
  653.             {
  654.                 // we want a specific sample in a specific real slice
  655.                 sliceOffset = sd.slice.sliceIndex * sampleCount + sd.sample.sampleIndex;
  656.                 numSlices = 1;
  657.             }
  658.             else
  659.             {
  660.                 // we want all the samples (now mapped to slices) in a specific real slice
  661.                 sliceOffset = sd.slice.sliceIndex;
  662.                 numSlices = sampleCount;
  663.             }
  664.         }
  665.         else
  666.         {
  667.             if(singleSample)
  668.             {
  669.                 // we want one sample in every slice, so we have to set the stride to sampleCount
  670.                 // to skip every other sample (mapped to slices), starting from the sample we want
  671.                 // in the first real slice
  672.                 sliceOffset = sd.sample.sampleIndex;
  673.                 sliceStride = sampleCount;
  674.                 numSlices = RDCMAX(1U, td.arraysize / sampleCount);
  675.             }
  676.             else
  677.             {
  678.                 // we want all slices, all samples
  679.                 sliceOffset = 0;
  680.                 numSlices = td.arraysize;
  681.             }
  682.         }
  683.     }
  684.     else
  685.     {
  686.         if(singleSlice)
  687.         {
  688.             numSlices = 1;
  689.             sliceOffset = sd.slice.sliceIndex;
  690.         }
  691.         // otherwise take all slices, as by default
  692.  
  693.         if(sd.mip != -1)
  694.         {
  695.             mipOffset = sd.mip;
  696.             numMips = 1;
  697.         }
  698.         // otherwise take all mips, as by default
  699.     }
  700.    
  701.     vector<byte *> subdata;
  702.    
  703.     bool downcast = false;
  704.  
  705.     // don't support slice mappings for DDS - it supports slices natively
  706.     if(sd.destType == eFileType_DDS)
  707.     {
  708.         sd.slice.cubeCruciform = false;
  709.         sd.slice.slicesAsGrid = false;
  710.     }
  711.  
  712.     // force downcast to be able to do grid mappings
  713.     if(sd.slice.cubeCruciform || sd.slice.slicesAsGrid)
  714.         downcast = true;
  715.    
  716.     // we don't support any file formats that handle these block compression formats
  717.     if(td.format.specialFormat == eSpecial_ETC2 ||
  718.          td.format.specialFormat == eSpecial_EAC ||
  719.          td.format.specialFormat == eSpecial_ASTC)
  720.          downcast = true;
  721.  
  722.     /* Modified by Stephan Richter | BEGIN */
  723.     // for DDS don't downcast, for non-HDR always downcast if we're not already RGBA8 unorm
  724.     // for HDR&EXR we can convert from most regular types as well as 10.10.10.2 and 11.11.10
  725.     if((sd.destType != eFileType_DDS && sd.destType != eFileType_HDR && sd.destType != eFileType_EXR &&
  726.             (td.format.compByteWidth != 1 || td.format.compType != eCompType_UNorm)
  727.          ) ||
  728.          downcast ||
  729.          (sd.destType != eFileType_DDS && td.format.special &&
  730.                td.format.specialFormat != eSpecial_R10G10B10A2 &&
  731.                  td.format.specialFormat != eSpecial_R11G11B10 && td.format.specialFormat != eSpecial_D32S8)
  732.         )
  733.     {
  734.         downcast = true;
  735.         td.format.compByteWidth = 1;
  736.         td.format.compCount = 4;
  737.         td.format.compType = eCompType_UNorm;
  738.         td.format.special = false;
  739.         td.format.specialFormat = eSpecial_Unknown;
  740.     }
  741.     /* Modified by Stephan Richter | END */
  742.  
  743.     uint32_t rowPitch = 0;
  744.     uint32_t slicePitch = 0;
  745.  
  746.     bool blockformat = false;
  747.     int blockSize = 0;
  748.     uint32_t bytesPerPixel = 1;
  749.    
  750.     td.width = RDCMAX(1U, td.width >> mipOffset);
  751.     td.height = RDCMAX(1U, td.height >> mipOffset);
  752.     td.depth = RDCMAX(1U, td.depth >> mipOffset);
  753.  
  754.     if(td.format.specialFormat == eSpecial_BC1 ||
  755.          td.format.specialFormat == eSpecial_BC2 ||
  756.          td.format.specialFormat == eSpecial_BC3 ||
  757.          td.format.specialFormat == eSpecial_BC4 ||
  758.          td.format.specialFormat == eSpecial_BC5 ||
  759.          td.format.specialFormat == eSpecial_BC6 ||
  760.          td.format.specialFormat == eSpecial_BC7)
  761.     {
  762.         blockSize = (td.format.specialFormat == eSpecial_BC1 || td.format.specialFormat == eSpecial_BC4) ? 8 : 16;
  763.         rowPitch = RDCMAX(1U, ((td.width+3)/4)) * blockSize;
  764.         slicePitch = rowPitch * RDCMAX(1U, td.height/4);
  765.         blockformat = true;
  766.     }
  767.     else
  768.     {
  769.         switch(td.format.specialFormat)
  770.         {
  771.             case eSpecial_S8:
  772.                 bytesPerPixel = 1;
  773.                 break;
  774.             case eSpecial_R10G10B10A2:
  775.             case eSpecial_R9G9B9E5:
  776.             case eSpecial_R11G11B10:
  777.             case eSpecial_D24S8:
  778.                 bytesPerPixel = 4;
  779.                 break;
  780.             case eSpecial_R5G6B5:
  781.             case eSpecial_R5G5B5A1:
  782.             case eSpecial_R4G4B4A4:
  783.                 bytesPerPixel = 2;
  784.                 break;
  785.             case eSpecial_D32S8:
  786.                 /* Modified by Stephan Richter | BEGIN */
  787.                 /* Original value was 5. */
  788.                 bytesPerPixel = 8;
  789.                 /* Modified by Stephan Richter | END */
  790.                 break;
  791.             case eSpecial_D16S8:
  792.             case eSpecial_YUV:
  793.                 RDCERR("Unsupported file format %u", td.format.specialFormat);
  794.                 return false;
  795.             default:
  796.                 bytesPerPixel = td.format.compCount*td.format.compByteWidth;
  797.         }
  798.        
  799.         rowPitch = td.width * bytesPerPixel;
  800.         slicePitch = rowPitch * td.height;
  801.     }
  802.  
  803.     // loop over fetching subresources
  804.     for(uint32_t s=0; s < numSlices; s++)
  805.     {
  806.         uint32_t slice = s*sliceStride + sliceOffset;
  807.  
  808.         for(uint32_t m=0; m < numMips; m++)
  809.         {
  810.             uint32_t mip = m + mipOffset;
  811.  
  812.             size_t datasize = 0;
  813.             byte *bytes = m_pDevice->GetTextureData(liveid, slice, mip, resolveSamples, downcast, sd.comp.blackPoint, sd.comp.whitePoint, datasize);
  814.  
  815.             if(bytes == NULL)
  816.             {
  817.                 RDCERR("Couldn't get bytes for mip %u, slice %u", mip, slice);
  818.  
  819.                 for(size_t i=0; i < subdata.size(); i++)
  820.                     delete[] subdata[i];
  821.  
  822.                 return false;
  823.             }
  824.  
  825.             if(td.depth == 1)
  826.             {
  827.                 subdata.push_back(bytes);
  828.                 continue;
  829.             }
  830.  
  831.             uint32_t mipSlicePitch = slicePitch;
  832.            
  833.             uint32_t w = RDCMAX(1U, td.width>>m);
  834.             uint32_t h = RDCMAX(1U, td.height>>m);
  835.             uint32_t d = RDCMAX(1U, td.depth>>m);
  836.  
  837.             if(blockformat)
  838.             {
  839.                 mipSlicePitch = RDCMAX(1U, ((w+3)/4)) * blockSize * RDCMAX(1U, h/4);
  840.             }
  841.             else
  842.             {
  843.                 mipSlicePitch = w * bytesPerPixel * h;
  844.             }
  845.  
  846.             // we don't support slice ranges, only all-or-nothing
  847.             // we're also not dealing with multisampled slices if
  848.             // depth > 1. So if we only want one slice out of a 3D texture
  849.             // then make sure we get it
  850.             if(numSlices == 1)
  851.             {
  852.                 byte *depthslice = new byte[mipSlicePitch];
  853.                 byte *b = bytes + mipSlicePitch*sliceOffset;
  854.                 memcpy(depthslice, b, slicePitch);
  855.                 subdata.push_back(depthslice);
  856.  
  857.                 delete[] bytes;
  858.                 continue;
  859.             }
  860.  
  861.             s += (d-1);
  862.  
  863.             byte *b = bytes;
  864.  
  865.             // add each depth slice as a separate subdata
  866.             for(uint32_t di=0; di < d; di++)
  867.             {
  868.                 byte *depthslice = new byte[mipSlicePitch];
  869.  
  870.                 memcpy(depthslice, b, mipSlicePitch);
  871.  
  872.                 subdata.push_back(depthslice);
  873.  
  874.                 b += mipSlicePitch;
  875.             }
  876.  
  877.             delete[] bytes;
  878.         }
  879.     }
  880.    
  881.     // should have been handled above, but verify incoming data is RGBA8
  882.     if(sd.slice.slicesAsGrid && td.format.compByteWidth == 1 && td.format.compCount == 4)
  883.     {
  884.         uint32_t sliceWidth = td.width;
  885.         uint32_t sliceHeight = td.height;
  886.  
  887.         uint32_t sliceGridHeight = (td.arraysize*td.depth) / sd.slice.sliceGridWidth;
  888.         if((td.arraysize*td.depth) % sd.slice.sliceGridWidth != 0)
  889.             sliceGridHeight++;
  890.  
  891.         td.width *= sd.slice.sliceGridWidth;
  892.         td.height *= sliceGridHeight;
  893.  
  894.         byte *combinedData = new byte[td.width*td.height*td.format.compCount];
  895.  
  896.         memset(combinedData, 0, td.width*td.height*td.format.compCount);
  897.        
  898.         for(size_t i=0; i < subdata.size(); i++)
  899.         {
  900.             uint32_t gridx = (uint32_t)i % sd.slice.sliceGridWidth;
  901.             uint32_t gridy = (uint32_t)i / sd.slice.sliceGridWidth;
  902.  
  903.             uint32_t yoffs = gridy*sliceHeight;
  904.             uint32_t xoffs = gridx*sliceWidth;
  905.  
  906.             for(uint32_t y=0; y < sliceHeight; y++)
  907.             {
  908.                 for(uint32_t x=0; x < sliceWidth; x++)
  909.                 {
  910.                     uint32_t *srcpix = (uint32_t *)&subdata[i][ ( y * sliceWidth + x ) * 4 + 0 ];
  911.                     uint32_t *dstpix = (uint32_t *)&combinedData[ ( (y + yoffs) * td.width + x + xoffs ) * 4 + 0 ];
  912.  
  913.                     *dstpix = *srcpix;
  914.                 }
  915.             }
  916.  
  917.             delete[] subdata[i];
  918.         }
  919.  
  920.         subdata.resize(1);
  921.         subdata[0] = combinedData;
  922.         rowPitch = td.width * 4;
  923.     }
  924.    
  925.     // should have been handled above, but verify incoming data is RGBA8 and 6 slices
  926.     if(sd.slice.cubeCruciform && td.format.compByteWidth == 1 && td.format.compCount == 4 && subdata.size() == 6)
  927.     {
  928.         uint32_t sliceWidth = td.width;
  929.         uint32_t sliceHeight = td.height;
  930.  
  931.         td.width *= 4;
  932.         td.height *= 3;
  933.  
  934.         byte *combinedData = new byte[td.width*td.height*td.format.compCount];
  935.  
  936.         memset(combinedData, 0, td.width*td.height*td.format.compCount);
  937.        
  938.         /*
  939.          Y X=0   1   2   3      
  940.          =     +---+
  941.          0     |+y |
  942.                |[2]|
  943.            +---+---+---+---+
  944.          1 |-x |+z |+x |-z |
  945.            |[1]|[4]|[0]|[5]|
  946.            +---+---+---+---+
  947.          2     |-y |
  948.                |[3]|
  949.                +---+
  950.  
  951.         */
  952.  
  953.         uint32_t gridx[6] = { 2, 0, 1, 1, 1, 3 };
  954.         uint32_t gridy[6] = { 1, 1, 0, 2, 1, 1 };
  955.        
  956.         for(size_t i=0; i < subdata.size(); i++)
  957.         {
  958.             uint32_t yoffs = gridy[i]*sliceHeight;
  959.             uint32_t xoffs = gridx[i]*sliceWidth;
  960.  
  961.             for(uint32_t y=0; y < sliceHeight; y++)
  962.             {
  963.                 for(uint32_t x=0; x < sliceWidth; x++)
  964.                 {
  965.                     uint32_t *srcpix = (uint32_t *)&subdata[i][ ( y * sliceWidth + x ) * 4 + 0 ];
  966.                     uint32_t *dstpix = (uint32_t *)&combinedData[ ( (y + yoffs) * td.width + x + xoffs ) * 4 + 0 ];
  967.  
  968.                     *dstpix = *srcpix;
  969.                 }
  970.             }
  971.  
  972.             delete[] subdata[i];
  973.         }
  974.  
  975.         subdata.resize(1);
  976.         subdata[0] = combinedData;
  977.         rowPitch = td.width * 4;
  978.     }
  979.    
  980.     int numComps = td.format.compCount;
  981.  
  982.     // if we want a grayscale image of one channel, splat it across all channels
  983.     // and set alpha to full
  984.     if(sd.channelExtract >= 0 && td.format.compByteWidth == 1 && (uint32_t)sd.channelExtract < td.format.compCount)
  985.     {
  986.         for(uint32_t y=0; y < td.height; y++)
  987.         {
  988.             for(uint32_t x=0; x < td.width; x++)
  989.             {
  990.                 subdata[0][ ( y * td.width + x ) * 4 + 0 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ];
  991.                 if(td.format.compCount >= 2)
  992.                     subdata[0][ ( y * td.width + x ) * 4 + 1 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ];
  993.                 if(td.format.compCount >= 3)
  994.                     subdata[0][ ( y * td.width + x ) * 4 + 2 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ];
  995.                 if(td.format.compCount >= 4)
  996.                     subdata[0][ ( y * td.width + x ) * 4 + 3 ] = 255;
  997.             }
  998.         }
  999.     }
  1000.    
  1001.     // handle formats that don't support alpha
  1002.     if(numComps == 4 && (sd.destType == eFileType_BMP || sd.destType == eFileType_JPG) )
  1003.     {
  1004.         byte *nonalpha = new byte[td.width*td.height*3];
  1005.  
  1006.         for(uint32_t y=0; y < td.height; y++)
  1007.         {
  1008.             for(uint32_t x=0; x < td.width; x++)
  1009.             {
  1010.                 byte r = subdata[0][ ( y * td.width + x ) * 4 + 0 ];
  1011.                 byte g = subdata[0][ ( y * td.width + x ) * 4 + 1 ];
  1012.                 byte b = subdata[0][ ( y * td.width + x ) * 4 + 2 ];
  1013.                 byte a = subdata[0][ ( y * td.width + x ) * 4 + 3 ];
  1014.  
  1015.                 if(sd.alpha != eAlphaMap_Discard)
  1016.                 {
  1017.                     FloatVector col = sd.alphaCol;
  1018.                     if(sd.alpha == eAlphaMap_BlendToCheckerboard)
  1019.                     {
  1020.                         bool lightSquare = ((x/64) % 2) == ((y/64) % 2);
  1021.                         col = lightSquare ? sd.alphaCol : sd.alphaColSecondary;
  1022.                     }
  1023.  
  1024.                     col.x = powf(col.x, 1.0f/2.2f);
  1025.                     col.y = powf(col.y, 1.0f/2.2f);
  1026.                     col.z = powf(col.z, 1.0f/2.2f);
  1027.  
  1028.                     FloatVector pixel = FloatVector( float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, float(a)/255.0f );
  1029.  
  1030.                     pixel.x = pixel.x * pixel.w + col.x * (1.0f - pixel.w);
  1031.                     pixel.y = pixel.y * pixel.w + col.y * (1.0f - pixel.w);
  1032.                     pixel.z = pixel.z * pixel.w + col.z * (1.0f - pixel.w);
  1033.  
  1034.                     r = byte(pixel.x * 255.0f);
  1035.                     g = byte(pixel.y * 255.0f);
  1036.                     b = byte(pixel.z * 255.0f);
  1037.                 }
  1038.                
  1039.                 nonalpha[ ( y * td.width + x ) * 3 + 0 ] = r;
  1040.                 nonalpha[ ( y * td.width + x ) * 3 + 1 ] = g;
  1041.                 nonalpha[ ( y * td.width + x ) * 3 + 2 ] = b;
  1042.             }
  1043.         }
  1044.  
  1045.         delete[] subdata[0];
  1046.  
  1047.         subdata[0] = nonalpha;
  1048.  
  1049.         numComps = 3;
  1050.         rowPitch = td.width * 3;
  1051.     }
  1052.    
  1053.     // assume that (R,G,0) is better mapping than (Y,A) for 2 component data
  1054.     if(numComps == 2 && (sd.destType == eFileType_BMP || sd.destType == eFileType_JPG ||
  1055.                          sd.destType == eFileType_PNG || sd.destType == eFileType_TGA) )
  1056.     {
  1057.         byte *rg0 = new byte[td.width*td.height*3];
  1058.  
  1059.         for(uint32_t y=0; y < td.height; y++)
  1060.         {
  1061.             for(uint32_t x=0; x < td.width; x++)
  1062.             {
  1063.                 byte r = subdata[0][ ( y * td.width + x ) * 2 + 0 ];
  1064.                 byte g = subdata[0][ ( y * td.width + x ) * 2 + 1 ];
  1065.  
  1066.                 rg0[ ( y * td.width + x ) * 3 + 0 ] = r;
  1067.                 rg0[ ( y * td.width + x ) * 3 + 1 ] = g;
  1068.                 rg0[ ( y * td.width + x ) * 3 + 2 ] = 0;
  1069.             }
  1070.         }
  1071.  
  1072.         delete[] subdata[0];
  1073.  
  1074.         subdata[0] = rg0;
  1075.  
  1076.         numComps = 3;
  1077.         rowPitch = td.width * 2;
  1078.     }
  1079.  
  1080.     /* Modified by Stephan Richter | BEGIN */
  1081.  
  1082.     if (sd.destType == eFileType_EXR)
  1083.     {
  1084.         IMF::Header header(td.width, td.height);
  1085.         IMF::FrameBuffer frameBuffer;
  1086.  
  1087.         if (td.format.special && td.format.specialFormat == eSpecial_D32S8)
  1088.         {
  1089.             float    *rdata = new float[td.width*td.height];
  1090.             uint32_t *gdata = new uint32_t[td.width*td.height];
  1091.            
  1092.             byte *srcData = subdata[0];
  1093.  
  1094.             for (uint32_t y = 0; y < td.height; y++)
  1095.             {
  1096.                 for (uint32_t x = 0; x < td.width; x++)
  1097.                 {
  1098.                     float r    = *(float*)(srcData);
  1099.                     uint32_t g = (uint32_t)(*(srcData+4));
  1100.            
  1101.                     rdata[y*td.width + x] = r;
  1102.                     gdata[y*td.width + x] = g;
  1103.  
  1104.                     srcData += 8;
  1105.                 }
  1106.             }
  1107.  
  1108.            
  1109.             header.channels().insert("D", IMF::Channel(IMF::FLOAT));
  1110.             header.channels().insert("S", IMF::Channel(IMF::UINT));
  1111.            
  1112.             auto slice = IMF::Slice(IMF::FLOAT,         // type
  1113.                 (char *)rdata,      // base
  1114.                 sizeof(*rdata) * 1,     // xStride
  1115.                 sizeof(*rdata) * td.width);
  1116.  
  1117.             frameBuffer.insert("D", slice);
  1118.  
  1119.             frameBuffer.insert("S", IMF::Slice(IMF::UINT,           // type
  1120.                 (char *)gdata,      // base
  1121.                 sizeof(*gdata) * 1,     // xStride
  1122.                 sizeof(*gdata) * td.width));
  1123.  
  1124.             IMF::OutputFile file(path, header);
  1125.             file.setFrameBuffer(frameBuffer);
  1126.             file.writePixels(td.height);
  1127.         }
  1128.         else
  1129.         {
  1130.             float *rdata = new float[td.width*td.height];
  1131.             float *gdata = new float[td.width*td.height];
  1132.             float *bdata = new float[td.width*td.height];
  1133.             float *adata = new float[td.width*td.height];
  1134.  
  1135.             byte *srcData = subdata[0];
  1136.  
  1137.             for (uint32_t y = 0; y < td.height; y++)
  1138.             {
  1139.                 for (uint32_t x = 0; x < td.width; x++)
  1140.                 {
  1141.                     float r = 0.0f;
  1142.                     float g = 0.0f;
  1143.                     float b = 0.0f;
  1144.                     float a = 1.0f;
  1145.  
  1146.                     if (td.format.special && td.format.specialFormat == eSpecial_R10G10B10A2)
  1147.                     {
  1148.                         uint32_t *u32 = (uint32_t *)srcData;
  1149.  
  1150.                         Vec4f vec = ConvertFromR10G10B10A2(*u32);
  1151.  
  1152.                         r = vec.x;
  1153.                         g = vec.y;
  1154.                         b = vec.z;
  1155.                         a = vec.w;
  1156.  
  1157.                         srcData += 4;
  1158.                     }
  1159.                     else if (td.format.special && td.format.specialFormat == eSpecial_R11G11B10)
  1160.                     {
  1161.                         uint32_t *u32 = (uint32_t *)srcData;
  1162.  
  1163.                         Vec3f vec = ConvertFromR11G11B10(*u32);
  1164.  
  1165.                         r = vec.x;
  1166.                         g = vec.y;
  1167.                         b = vec.z;
  1168.                         a = 1.0f;
  1169.  
  1170.                         srcData += 4;
  1171.                     }
  1172.                     else
  1173.                     {
  1174.                         if (td.format.compCount >= 1)
  1175.                             r = ConvertComponent(td.format, srcData + td.format.compByteWidth * 0);
  1176.                         if (td.format.compCount >= 2)
  1177.                             g = ConvertComponent(td.format, srcData + td.format.compByteWidth * 1);
  1178.                         if (td.format.compCount >= 3)
  1179.                             b = ConvertComponent(td.format, srcData + td.format.compByteWidth * 2);
  1180.                         if (td.format.compCount >= 4)
  1181.                             a = ConvertComponent(td.format, srcData + td.format.compByteWidth * 3);
  1182.  
  1183.                         srcData += td.format.compCount * td.format.compByteWidth;
  1184.                     }
  1185.  
  1186.                     rdata[y*td.width + x] = r;
  1187.                     gdata[y*td.width + x] = g;
  1188.                     bdata[y*td.width + x] = b;
  1189.                     adata[y*td.width + x] = a;
  1190.                 }
  1191.             }
  1192.  
  1193.             header.channels().insert("R", IMF::Channel(IMF::FLOAT));
  1194.             header.channels().insert("G", IMF::Channel(IMF::FLOAT));
  1195.             header.channels().insert("B", IMF::Channel(IMF::FLOAT));
  1196.             header.channels().insert("A", IMF::Channel(IMF::FLOAT));
  1197.  
  1198.             frameBuffer.insert("R", IMF::Slice(IMF::FLOAT,          // type
  1199.                 (char *)rdata,      // base
  1200.                 sizeof(*rdata) * 1,     // xStride
  1201.                 sizeof(*rdata) * td.width));
  1202.  
  1203.             frameBuffer.insert("G", IMF::Slice(IMF::FLOAT,          // type
  1204.                 (char *)gdata,      // base
  1205.                 sizeof(*gdata) * 1,     // xStride
  1206.                 sizeof(*gdata) * td.width));
  1207.  
  1208.             frameBuffer.insert("B", IMF::Slice(IMF::FLOAT,          // type
  1209.                 (char *)bdata,      // base
  1210.                 sizeof(*bdata) * 1,     // xStride
  1211.                 sizeof(*bdata) * td.width));
  1212.  
  1213.             frameBuffer.insert("A", IMF::Slice(IMF::FLOAT,          // type
  1214.                 (char *)adata,      // base
  1215.                 sizeof(*adata) * 1,     // xStride
  1216.                 sizeof(*adata) * td.width));
  1217.  
  1218.             IMF::OutputFile file(path, header);
  1219.             file.setFrameBuffer(frameBuffer);
  1220.             file.writePixels(td.height);
  1221.         }
  1222.  
  1223.         success = true;
  1224.         /*const char *err = NULL;
  1225.         int ret = SaveEXRFP(fldata, (int)td.width, (int)td.height, f, &err);
  1226.         success = (ret == 0);
  1227.         if (!success)
  1228.         RDCERR("Error saving EXR file %d: '%s'", ret, err); */
  1229.     }
  1230.     else
  1231.     {
  1232.         FILE *f = FileIO::fopen(path, "wb");
  1233.  
  1234.         if (!f)
  1235.         {
  1236.             success = false;
  1237.         }
  1238.         else
  1239.         {
  1240.             if (sd.destType == eFileType_DDS)
  1241.             {
  1242.                 dds_data ddsData;
  1243.  
  1244.                 ddsData.width = td.width;
  1245.                 ddsData.height = td.height;
  1246.                 ddsData.depth = td.depth;
  1247.                 ddsData.format = td.format;
  1248.                 ddsData.mips = numMips;
  1249.                 ddsData.slices = numSlices / td.depth;
  1250.                 ddsData.subdata = &subdata[0];
  1251.                 ddsData.cubemap = td.cubemap && numSlices == 6;
  1252.  
  1253.                 success = write_dds_to_file(f, ddsData);
  1254.             }
  1255.             else if (sd.destType == eFileType_BMP)
  1256.             {
  1257.                 int ret = stbi_write_bmp_to_file(f, td.width, td.height, numComps, subdata[0]);
  1258.                 success = (ret != 0);
  1259.             }
  1260.             else if (sd.destType == eFileType_PNG)
  1261.             {
  1262.                 int ret = stbi_write_png_to_file(f, td.width, td.height, td.format.compCount, subdata[0], rowPitch);
  1263.                 success = (ret != 0);
  1264.             }
  1265.             else if (sd.destType == eFileType_TGA)
  1266.             {
  1267.                 int ret = stbi_write_tga_to_file(f, td.width, td.height, td.format.compCount, subdata[0]);
  1268.                 success = (ret != 0);
  1269.             }
  1270.             else if (sd.destType == eFileType_JPG)
  1271.             {
  1272.                 jpge::params p;
  1273.                 p.m_quality = sd.jpegQuality;
  1274.  
  1275.                 int len = td.width*td.height*td.format.compCount;
  1276.  
  1277.                 char *jpgdst = new char[len];
  1278.  
  1279.                 success = jpge::compress_image_to_jpeg_file_in_memory(jpgdst, len, td.width, td.height, numComps, subdata[0], p);
  1280.  
  1281.                 if (success)
  1282.                     fwrite(jpgdst, 1, len, f);
  1283.  
  1284.                 delete[] jpgdst;
  1285.             }
  1286.             else if (sd.destType == eFileType_HDR || sd.destType == eFileType_EXR)
  1287.             {
  1288.                 float *fldata = new float[td.width*td.height * 4];
  1289.  
  1290.                 byte *srcData = subdata[0];
  1291.  
  1292.                 for (uint32_t y = 0; y < td.height; y++)
  1293.                 {
  1294.                     for (uint32_t x = 0; x < td.width; x++)
  1295.                     {
  1296.                         float r = 0.0f;
  1297.                         float g = 0.0f;
  1298.                         float b = 0.0f;
  1299.                         float a = 1.0f;
  1300.  
  1301.                         if (td.format.special && td.format.specialFormat == eSpecial_R10G10B10A2)
  1302.                         {
  1303.                             uint32_t *u32 = (uint32_t *)srcData;
  1304.  
  1305.                             Vec4f vec = ConvertFromR10G10B10A2(*u32);
  1306.  
  1307.                             r = vec.x;
  1308.                             g = vec.y;
  1309.                             b = vec.z;
  1310.                             a = vec.w;
  1311.  
  1312.                             srcData += 4;
  1313.                         }
  1314.                         else if (td.format.special && td.format.specialFormat == eSpecial_R11G11B10)
  1315.                         {
  1316.                             uint32_t *u32 = (uint32_t *)srcData;
  1317.  
  1318.                             Vec3f vec = ConvertFromR11G11B10(*u32);
  1319.  
  1320.                             r = vec.x;
  1321.                             g = vec.y;
  1322.                             b = vec.z;
  1323.                             a = 1.0f;
  1324.  
  1325.                             srcData += 4;
  1326.                         }
  1327.                         else if (td.format.special && td.format.specialFormat == eSpecial_D32S8)
  1328.                         {                          
  1329.                             r = *(float*)srcData;
  1330.                             g = float(*(uint8_t*)(srcData+4));
  1331.                             b = 0.0f;
  1332.                             a = 1.0f;
  1333.  
  1334.                             srcData += 8;
  1335.                         }
  1336.                         else
  1337.                         {
  1338.                             if (td.format.compCount >= 1)
  1339.                                 r = ConvertComponent(td.format, srcData + td.format.compByteWidth * 0);
  1340.                             if (td.format.compCount >= 2)
  1341.                                 g = ConvertComponent(td.format, srcData + td.format.compByteWidth * 1);
  1342.                             if (td.format.compCount >= 3)
  1343.                                 b = ConvertComponent(td.format, srcData + td.format.compByteWidth * 2);
  1344.                             if (td.format.compCount >= 4)
  1345.                                 a = ConvertComponent(td.format, srcData + td.format.compByteWidth * 3);
  1346.  
  1347.                             srcData += td.format.compCount * td.format.compByteWidth;
  1348.                         }
  1349.  
  1350.                         // HDR can't represent negative values
  1351.                         if (sd.destType == eFileType_HDR)
  1352.                         {
  1353.                             r = RDCMAX(r, 0.0f);
  1354.                             g = RDCMAX(g, 0.0f);
  1355.                             b = RDCMAX(b, 0.0f);
  1356.                             a = RDCMAX(a, 0.0f);
  1357.                         }
  1358.  
  1359.                         if (sd.channelExtract == 0)
  1360.                         {
  1361.                             g = b = r; a = 1.0f;
  1362.                         }
  1363.                         if (sd.channelExtract == 1)
  1364.                         {
  1365.                             r = b = g; a = 1.0f;
  1366.                         }
  1367.                         if (sd.channelExtract == 2)
  1368.                         {
  1369.                             r = g = b; a = 1.0f;
  1370.                         }
  1371.                         if (sd.channelExtract == 3)
  1372.                         {
  1373.                             r = g = b = a; a = 1.0f;
  1374.                         }
  1375.  
  1376.                         fldata[(y*td.width + x) * 4 + 0] = r;
  1377.                         fldata[(y*td.width + x) * 4 + 1] = g;
  1378.                         fldata[(y*td.width + x) * 4 + 2] = b;
  1379.                         fldata[(y*td.width + x) * 4 + 3] = a;
  1380.                     }
  1381.                 }
  1382.  
  1383.                 if (sd.destType == eFileType_HDR)
  1384.                 {
  1385.                     int ret = stbi_write_hdr_to_file(f, td.width, td.height, 4, fldata);
  1386.                     success = (ret != 0);
  1387.                 }
  1388.                 /*else if(sd.destType == eFileType_EXR)
  1389.                 {
  1390.                 const char *err = NULL;
  1391.                 int ret = SaveEXRFP(fldata, (int)td.width, (int)td.height, f, &err);
  1392.                 success = (ret == 0);
  1393.                 if(!success)
  1394.                 RDCERR("Error saving EXR file %d: '%s'", ret, err);
  1395.                 }*/
  1396.  
  1397.                 delete[] fldata;
  1398.             }
  1399.  
  1400.             FileIO::fclose(f);
  1401.         }
  1402.     }
  1403.     /* Modified by Stephan Richter | END */
  1404.  
  1405.     for(size_t i=0; i < subdata.size(); i++)
  1406.         delete[] subdata[i];
  1407.  
  1408.     return success;
  1409. }
  1410.  
  1411. /* Added by Stephan Richter | BEGIN */
  1412. /* modified version of SaveTexture */
  1413. bool ReplayRenderer::HashTexture(const TextureSave &saveData, const char *path)
  1414. {
  1415.     TextureSave sd = saveData; // mutable copy
  1416.     ResourceId liveid = m_pDevice->GetLiveID(sd.id);
  1417.     FetchTexture td = m_pDevice->GetTexture(liveid);
  1418.  
  1419.     bool success = false;
  1420.  
  1421.     // clamp sample/mip/slice indices
  1422.     if (td.msSamp == 1)
  1423.     {
  1424.         sd.sample.sampleIndex = 0;
  1425.         sd.sample.mapToArray = false;
  1426.     }
  1427.     else
  1428.     {
  1429.         if (sd.sample.sampleIndex != ~0U)
  1430.             sd.sample.sampleIndex = RDCCLAMP(sd.sample.sampleIndex, 0U, td.msSamp);
  1431.     }
  1432.  
  1433.     // don't support cube cruciform for non cubemaps, or
  1434.     // cubemap arrays
  1435.     if (!td.cubemap || td.arraysize != 6 || td.msSamp != 1)
  1436.         sd.slice.cubeCruciform = false;
  1437.  
  1438.     if (sd.mip != -1)
  1439.         sd.mip = RDCCLAMP(sd.mip, 0, (int32_t)td.mips);
  1440.     if (sd.slice.sliceIndex != -1)
  1441.         sd.slice.sliceIndex = RDCCLAMP(sd.slice.sliceIndex, 0, int32_t(td.arraysize*td.depth));
  1442.  
  1443.     if (td.arraysize*td.depth*td.msSamp == 1)
  1444.     {
  1445.         sd.slice.sliceIndex = 0;
  1446.         sd.slice.slicesAsGrid = false;
  1447.     }
  1448.  
  1449.     // can't extract a channel that's not in the source texture
  1450.     if (sd.channelExtract >= 0 && (uint32_t)sd.channelExtract >= td.format.compCount)
  1451.         sd.channelExtract = -1;
  1452.  
  1453.     sd.slice.sliceGridWidth = RDCMAX(sd.slice.sliceGridWidth, 1);
  1454.  
  1455.     // store sample count so we know how many 'slices' is one real slice
  1456.     // multisampled textures cannot have mips, subresource layout is same as would be for mips:
  1457.     // [slice0 sample0], [slice0 sample1], [slice1 sample0], [slice1 sample1]
  1458.     uint32_t sampleCount = td.msSamp;
  1459.     bool multisampled = td.msSamp > 1;
  1460.  
  1461.     bool resolveSamples = (sd.sample.sampleIndex == ~0U);
  1462.  
  1463.     if (resolveSamples)
  1464.     {
  1465.         td.msSamp = 1;
  1466.         sd.sample.mapToArray = false;
  1467.         sd.sample.sampleIndex = 0;
  1468.     }
  1469.  
  1470.     // treat any multisampled texture as if it were an array
  1471.     // of <sample count> dimension (on top of potential existing array
  1472.     // dimension). GetTextureData() uses the same convention.
  1473.     if (td.msSamp > 1)
  1474.     {
  1475.         td.arraysize *= td.msSamp;
  1476.         td.msSamp = 1;
  1477.     }
  1478.  
  1479.     if (sd.destType != eFileType_DDS && sd.sample.mapToArray && !sd.slice.slicesAsGrid && sd.slice.sliceIndex == -1)
  1480.     {
  1481.         sd.sample.mapToArray = false;
  1482.         sd.sample.sampleIndex = 0;
  1483.     }
  1484.  
  1485.     // only DDS supports writing multiple mips, fall back to mip 0 if 'all mips' was specified
  1486.     if (sd.destType != eFileType_DDS && sd.mip == -1)
  1487.         sd.mip = 0;
  1488.  
  1489.     // only DDS supports writing multiple slices, fall back to slice 0 if 'all slices' was specified
  1490.     if (sd.destType != eFileType_DDS && sd.slice.sliceIndex == -1 && !sd.slice.slicesAsGrid && !sd.slice.cubeCruciform)
  1491.         sd.slice.sliceIndex = 0;
  1492.  
  1493.     // fetch source data subresources (typically only one, possibly more
  1494.     // if we're writing to DDS (so writing multiple mips/slices) or resolving
  1495.     // down a multisampled texture for writing as a single 'image' elsewhere)
  1496.     uint32_t sliceOffset = 0;
  1497.     uint32_t sliceStride = 1;
  1498.     uint32_t numSlices = td.arraysize*td.depth;
  1499.  
  1500.     uint32_t mipOffset = 0;
  1501.     uint32_t numMips = td.mips;
  1502.  
  1503.     bool singleSlice = (sd.slice.sliceIndex != -1);
  1504.  
  1505.     // set which slices/mips we need
  1506.     if (multisampled)
  1507.     {
  1508.         bool singleSample = !sd.sample.mapToArray;
  1509.  
  1510.         // multisampled images have no mips
  1511.         mipOffset = 0;
  1512.         numMips = 1;
  1513.  
  1514.         if (singleSlice)
  1515.         {
  1516.             if (singleSample)
  1517.             {
  1518.                 // we want a specific sample in a specific real slice
  1519.                 sliceOffset = sd.slice.sliceIndex * sampleCount + sd.sample.sampleIndex;
  1520.                 numSlices = 1;
  1521.             }
  1522.             else
  1523.             {
  1524.                 // we want all the samples (now mapped to slices) in a specific real slice
  1525.                 sliceOffset = sd.slice.sliceIndex;
  1526.                 numSlices = sampleCount;
  1527.             }
  1528.         }
  1529.         else
  1530.         {
  1531.             if (singleSample)
  1532.             {
  1533.                 // we want one sample in every slice, so we have to set the stride to sampleCount
  1534.                 // to skip every other sample (mapped to slices), starting from the sample we want
  1535.                 // in the first real slice
  1536.                 sliceOffset = sd.sample.sampleIndex;
  1537.                 sliceStride = sampleCount;
  1538.                 numSlices = RDCMAX(1U, td.arraysize / sampleCount);
  1539.             }
  1540.             else
  1541.             {
  1542.                 // we want all slices, all samples
  1543.                 sliceOffset = 0;
  1544.                 numSlices = td.arraysize;
  1545.             }
  1546.         }
  1547.     }
  1548.     else
  1549.     {
  1550.         if (singleSlice)
  1551.         {
  1552.             numSlices = 1;
  1553.             sliceOffset = sd.slice.sliceIndex;
  1554.         }
  1555.         // otherwise take all slices, as by default
  1556.  
  1557.         if (sd.mip != -1)
  1558.         {
  1559.             mipOffset = sd.mip;
  1560.             numMips = 1;
  1561.         }
  1562.         // otherwise take all mips, as by default
  1563.     }
  1564.  
  1565.     vector<byte *> subdata;
  1566.  
  1567.     bool downcast = false;
  1568.  
  1569.     // don't support slice mappings for DDS - it supports slices natively
  1570.     if (sd.destType == eFileType_DDS)
  1571.     {
  1572.         sd.slice.cubeCruciform = false;
  1573.         sd.slice.slicesAsGrid = false;
  1574.     }
  1575.  
  1576.     // force downcast to be able to do grid mappings
  1577.     if (sd.slice.cubeCruciform || sd.slice.slicesAsGrid)
  1578.         downcast = true;
  1579.  
  1580.     // we don't support any file formats that handle these block compression formats
  1581.     if (td.format.specialFormat == eSpecial_ETC2 ||
  1582.         td.format.specialFormat == eSpecial_EAC ||
  1583.         td.format.specialFormat == eSpecial_ASTC)
  1584.         downcast = true;
  1585.  
  1586.     // for DDS don't downcast, for non-HDR always downcast if we're not already RGBA8 unorm
  1587.     // for HDR&EXR we can convert from most regular types as well as 10.10.10.2 and 11.11.10
  1588.     if ((sd.destType != eFileType_DDS && sd.destType != eFileType_HDR && sd.destType != eFileType_EXR &&
  1589.         (td.format.compByteWidth != 1 || td.format.compType != eCompType_UNorm)
  1590.         ) ||
  1591.         downcast ||
  1592.         (sd.destType != eFileType_DDS && td.format.special &&
  1593.         td.format.specialFormat != eSpecial_R10G10B10A2 &&
  1594.         td.format.specialFormat != eSpecial_R11G11B10 && td.format.specialFormat != eSpecial_D32S8)
  1595.         )
  1596.     {
  1597.         downcast = true;
  1598.         td.format.compByteWidth = 1;
  1599.         td.format.compCount = 4;
  1600.         td.format.compType = eCompType_UNorm;
  1601.         td.format.special = false;
  1602.         td.format.specialFormat = eSpecial_Unknown;
  1603.     }
  1604.  
  1605.     uint32_t rowPitch = 0;
  1606.     uint32_t slicePitch = 0;
  1607.  
  1608.     bool blockformat = false;
  1609.     int blockSize = 0;
  1610.     uint32_t bytesPerPixel = 1;
  1611.  
  1612.     td.width = RDCMAX(1U, td.width >> mipOffset);
  1613.     td.height = RDCMAX(1U, td.height >> mipOffset);
  1614.     td.depth = RDCMAX(1U, td.depth >> mipOffset);
  1615.  
  1616.     if (td.format.specialFormat == eSpecial_BC1 ||
  1617.         td.format.specialFormat == eSpecial_BC2 ||
  1618.         td.format.specialFormat == eSpecial_BC3 ||
  1619.         td.format.specialFormat == eSpecial_BC4 ||
  1620.         td.format.specialFormat == eSpecial_BC5 ||
  1621.         td.format.specialFormat == eSpecial_BC6 ||
  1622.         td.format.specialFormat == eSpecial_BC7)
  1623.     {
  1624.         blockSize = (td.format.specialFormat == eSpecial_BC1 || td.format.specialFormat == eSpecial_BC4) ? 8 : 16;
  1625.         rowPitch = RDCMAX(1U, ((td.width + 3) / 4)) * blockSize;
  1626.         slicePitch = rowPitch * RDCMAX(1U, td.height / 4);
  1627.         blockformat = true;
  1628.     }
  1629.     else
  1630.     {
  1631.         switch (td.format.specialFormat)
  1632.         {
  1633.         case eSpecial_S8:
  1634.             bytesPerPixel = 1;
  1635.             break;
  1636.         case eSpecial_R10G10B10A2:
  1637.         case eSpecial_R9G9B9E5:
  1638.         case eSpecial_R11G11B10:
  1639.         case eSpecial_D24S8:
  1640.             bytesPerPixel = 4;
  1641.             break;
  1642.         case eSpecial_R5G6B5:
  1643.         case eSpecial_R5G5B5A1:
  1644.         case eSpecial_R4G4B4A4:
  1645.             bytesPerPixel = 2;
  1646.             break;
  1647.         case eSpecial_D32S8:
  1648.             bytesPerPixel = 8;
  1649.             break;
  1650.         case eSpecial_D16S8:
  1651.         case eSpecial_YUV:
  1652.             RDCERR("Unsupported file format %u", td.format.specialFormat);
  1653.             return false;
  1654.         default:
  1655.             bytesPerPixel = td.format.compCount*td.format.compByteWidth;
  1656.         }
  1657.  
  1658.         rowPitch = td.width * bytesPerPixel;
  1659.         slicePitch = rowPitch * td.height;
  1660.     }
  1661.  
  1662.     // loop over fetching subresources
  1663.     for (uint32_t s = 0; s < numSlices; s++)
  1664.     {
  1665.         uint32_t slice = s*sliceStride + sliceOffset;
  1666.  
  1667.         for (uint32_t m = 0; m < numMips; m++)
  1668.         {
  1669.             uint32_t mip = m + mipOffset;
  1670.  
  1671.             size_t datasize = 0;
  1672.             byte *bytes = m_pDevice->GetTextureData(liveid, slice, mip, resolveSamples, downcast, sd.comp.blackPoint, sd.comp.whitePoint, datasize);
  1673.  
  1674.             if (bytes == NULL)
  1675.             {
  1676.                 RDCERR("Couldn't get bytes for mip %u, slice %u", mip, slice);
  1677.  
  1678.                 for (size_t i = 0; i < subdata.size(); i++)
  1679.                     delete[] subdata[i];
  1680.  
  1681.                 return false;
  1682.             }
  1683.  
  1684.             if (td.depth == 1)
  1685.             {
  1686.                 subdata.push_back(bytes);
  1687.                 continue;
  1688.             }
  1689.  
  1690.             uint32_t mipSlicePitch = slicePitch;
  1691.  
  1692.             uint32_t w = RDCMAX(1U, td.width >> m);
  1693.             uint32_t h = RDCMAX(1U, td.height >> m);
  1694.             uint32_t d = RDCMAX(1U, td.depth >> m);
  1695.  
  1696.             if (blockformat)
  1697.             {
  1698.                 mipSlicePitch = RDCMAX(1U, ((w + 3) / 4)) * blockSize * RDCMAX(1U, h / 4);
  1699.             }
  1700.             else
  1701.             {
  1702.                 mipSlicePitch = w * bytesPerPixel * h;
  1703.             }
  1704.  
  1705.             // we don't support slice ranges, only all-or-nothing
  1706.             // we're also not dealing with multisampled slices if
  1707.             // depth > 1. So if we only want one slice out of a 3D texture
  1708.             // then make sure we get it
  1709.             if (numSlices == 1)
  1710.             {
  1711.                 byte *depthslice = new byte[mipSlicePitch];
  1712.                 byte *b = bytes + mipSlicePitch*sliceOffset;
  1713.                 memcpy(depthslice, b, slicePitch);
  1714.                 subdata.push_back(depthslice);
  1715.  
  1716.                 delete[] bytes;
  1717.                 continue;
  1718.             }
  1719.  
  1720.             s += (d - 1);
  1721.  
  1722.             byte *b = bytes;
  1723.  
  1724.             // add each depth slice as a separate subdata
  1725.             for (uint32_t di = 0; di < d; di++)
  1726.             {
  1727.                 byte *depthslice = new byte[mipSlicePitch];
  1728.  
  1729.                 memcpy(depthslice, b, mipSlicePitch);
  1730.  
  1731.                 subdata.push_back(depthslice);
  1732.  
  1733.                 b += mipSlicePitch;
  1734.             }
  1735.  
  1736.             delete[] bytes;
  1737.         }
  1738.     }
  1739.  
  1740.     // should have been handled above, but verify incoming data is RGBA8
  1741.     if (sd.slice.slicesAsGrid && td.format.compByteWidth == 1 && td.format.compCount == 4)
  1742.     {
  1743.         uint32_t sliceWidth = td.width;
  1744.         uint32_t sliceHeight = td.height;
  1745.  
  1746.         uint32_t sliceGridHeight = (td.arraysize*td.depth) / sd.slice.sliceGridWidth;
  1747.         if ((td.arraysize*td.depth) % sd.slice.sliceGridWidth != 0)
  1748.             sliceGridHeight++;
  1749.  
  1750.         td.width *= sd.slice.sliceGridWidth;
  1751.         td.height *= sliceGridHeight;
  1752.  
  1753.         byte *combinedData = new byte[td.width*td.height*td.format.compCount];
  1754.  
  1755.         memset(combinedData, 0, td.width*td.height*td.format.compCount);
  1756.  
  1757.         for (size_t i = 0; i < subdata.size(); i++)
  1758.         {
  1759.             uint32_t gridx = (uint32_t)i % sd.slice.sliceGridWidth;
  1760.             uint32_t gridy = (uint32_t)i / sd.slice.sliceGridWidth;
  1761.  
  1762.             uint32_t yoffs = gridy*sliceHeight;
  1763.             uint32_t xoffs = gridx*sliceWidth;
  1764.  
  1765.             for (uint32_t y = 0; y < sliceHeight; y++)
  1766.             {
  1767.                 for (uint32_t x = 0; x < sliceWidth; x++)
  1768.                 {
  1769.                     uint32_t *srcpix = (uint32_t *)&subdata[i][(y * sliceWidth + x) * 4 + 0];
  1770.                     uint32_t *dstpix = (uint32_t *)&combinedData[((y + yoffs) * td.width + x + xoffs) * 4 + 0];
  1771.  
  1772.                     *dstpix = *srcpix;
  1773.                 }
  1774.             }
  1775.  
  1776.             delete[] subdata[i];
  1777.         }
  1778.  
  1779.         subdata.resize(1);
  1780.         subdata[0] = combinedData;
  1781.         rowPitch = td.width * 4;
  1782.     }
  1783.  
  1784.     // should have been handled above, but verify incoming data is RGBA8 and 6 slices
  1785.     if (sd.slice.cubeCruciform && td.format.compByteWidth == 1 && td.format.compCount == 4 && subdata.size() == 6)
  1786.     {
  1787.         uint32_t sliceWidth = td.width;
  1788.         uint32_t sliceHeight = td.height;
  1789.  
  1790.         td.width *= 4;
  1791.         td.height *= 3;
  1792.  
  1793.         byte *combinedData = new byte[td.width*td.height*td.format.compCount];
  1794.  
  1795.         memset(combinedData, 0, td.width*td.height*td.format.compCount);
  1796.  
  1797.         /*
  1798.         Y X=0   1   2   3
  1799.         =     +---+
  1800.         0     |+y |
  1801.         |[2]|
  1802.         +---+---+---+---+
  1803.         1 |-x |+z |+x |-z |
  1804.         |[1]|[4]|[0]|[5]|
  1805.         +---+---+---+---+
  1806.         2     |-y |
  1807.         |[3]|
  1808.         +---+
  1809.  
  1810.         */
  1811.  
  1812.         uint32_t gridx[6] = { 2, 0, 1, 1, 1, 3 };
  1813.         uint32_t gridy[6] = { 1, 1, 0, 2, 1, 1 };
  1814.  
  1815.         for (size_t i = 0; i < subdata.size(); i++)
  1816.         {
  1817.             uint32_t yoffs = gridy[i] * sliceHeight;
  1818.             uint32_t xoffs = gridx[i] * sliceWidth;
  1819.  
  1820.             for (uint32_t y = 0; y < sliceHeight; y++)
  1821.             {
  1822.                 for (uint32_t x = 0; x < sliceWidth; x++)
  1823.                 {
  1824.                     uint32_t *srcpix = (uint32_t *)&subdata[i][(y * sliceWidth + x) * 4 + 0];
  1825.                     uint32_t *dstpix = (uint32_t *)&combinedData[((y + yoffs) * td.width + x + xoffs) * 4 + 0];
  1826.  
  1827.                     *dstpix = *srcpix;
  1828.                 }
  1829.             }
  1830.  
  1831.             delete[] subdata[i];
  1832.         }
  1833.  
  1834.         subdata.resize(1);
  1835.         subdata[0] = combinedData;
  1836.         rowPitch = td.width * 4;
  1837.     }
  1838.  
  1839.     int numComps = td.format.compCount;
  1840.  
  1841.     // if we want a grayscale image of one channel, splat it across all channels
  1842.     // and set alpha to full
  1843.     if (sd.channelExtract >= 0 && td.format.compByteWidth == 1 && (uint32_t)sd.channelExtract < td.format.compCount)
  1844.     {
  1845.         for (uint32_t y = 0; y < td.height; y++)
  1846.         {
  1847.             for (uint32_t x = 0; x < td.width; x++)
  1848.             {
  1849.                 subdata[0][(y * td.width + x) * 4 + 0] = subdata[0][(y * td.width + x) * 4 + sd.channelExtract];
  1850.                 if (td.format.compCount >= 2)
  1851.                     subdata[0][(y * td.width + x) * 4 + 1] = subdata[0][(y * td.width + x) * 4 + sd.channelExtract];
  1852.                 if (td.format.compCount >= 3)
  1853.                     subdata[0][(y * td.width + x) * 4 + 2] = subdata[0][(y * td.width + x) * 4 + sd.channelExtract];
  1854.                 if (td.format.compCount >= 4)
  1855.                     subdata[0][(y * td.width + x) * 4 + 3] = 255;
  1856.             }
  1857.         }
  1858.     }
  1859.  
  1860.     // handle formats that don't support alpha
  1861.     if (numComps == 4 && (sd.destType == eFileType_BMP || sd.destType == eFileType_JPG))
  1862.     {
  1863.         byte *nonalpha = new byte[td.width*td.height * 3];
  1864.  
  1865.         for (uint32_t y = 0; y < td.height; y++)
  1866.         {
  1867.             for (uint32_t x = 0; x < td.width; x++)
  1868.             {
  1869.                 byte r = subdata[0][(y * td.width + x) * 4 + 0];
  1870.                 byte g = subdata[0][(y * td.width + x) * 4 + 1];
  1871.                 byte b = subdata[0][(y * td.width + x) * 4 + 2];
  1872.                 byte a = subdata[0][(y * td.width + x) * 4 + 3];
  1873.  
  1874.                 if (sd.alpha != eAlphaMap_Discard)
  1875.                 {
  1876.                     FloatVector col = sd.alphaCol;
  1877.                     if (sd.alpha == eAlphaMap_BlendToCheckerboard)
  1878.                     {
  1879.                         bool lightSquare = ((x / 64) % 2) == ((y / 64) % 2);
  1880.                         col = lightSquare ? sd.alphaCol : sd.alphaColSecondary;
  1881.                     }
  1882.  
  1883.                     col.x = powf(col.x, 1.0f / 2.2f);
  1884.                     col.y = powf(col.y, 1.0f / 2.2f);
  1885.                     col.z = powf(col.z, 1.0f / 2.2f);
  1886.  
  1887.                     FloatVector pixel = FloatVector(float(r) / 255.0f, float(g) / 255.0f, float(b) / 255.0f, float(a) / 255.0f);
  1888.  
  1889.                     pixel.x = pixel.x * pixel.w + col.x * (1.0f - pixel.w);
  1890.                     pixel.y = pixel.y * pixel.w + col.y * (1.0f - pixel.w);
  1891.                     pixel.z = pixel.z * pixel.w + col.z * (1.0f - pixel.w);
  1892.  
  1893.                     r = byte(pixel.x * 255.0f);
  1894.                     g = byte(pixel.y * 255.0f);
  1895.                     b = byte(pixel.z * 255.0f);
  1896.                 }
  1897.  
  1898.                 nonalpha[(y * td.width + x) * 3 + 0] = r;
  1899.                 nonalpha[(y * td.width + x) * 3 + 1] = g;
  1900.                 nonalpha[(y * td.width + x) * 3 + 2] = b;
  1901.             }
  1902.         }
  1903.  
  1904.         delete[] subdata[0];
  1905.  
  1906.         subdata[0] = nonalpha;
  1907.  
  1908.         numComps = 3;
  1909.         rowPitch = td.width * 3;
  1910.     }
  1911.  
  1912.     // assume that (R,G,0) is better mapping than (Y,A) for 2 component data
  1913.     if (numComps == 2 && (sd.destType == eFileType_BMP || sd.destType == eFileType_JPG ||
  1914.         sd.destType == eFileType_PNG || sd.destType == eFileType_TGA))
  1915.     {
  1916.         byte *rg0 = new byte[td.width*td.height * 3];
  1917.  
  1918.         for (uint32_t y = 0; y < td.height; y++)
  1919.         {
  1920.             for (uint32_t x = 0; x < td.width; x++)
  1921.             {
  1922.                 byte r = subdata[0][(y * td.width + x) * 2 + 0];
  1923.                 byte g = subdata[0][(y * td.width + x) * 2 + 1];
  1924.  
  1925.                 rg0[(y * td.width + x) * 3 + 0] = r;
  1926.                 rg0[(y * td.width + x) * 3 + 1] = g;
  1927.                 rg0[(y * td.width + x) * 3 + 2] = 0;
  1928.             }
  1929.         }
  1930.  
  1931.         delete[] subdata[0];
  1932.  
  1933.         subdata[0] = rg0;
  1934.  
  1935.         numComps = 3;
  1936.         rowPitch = td.width * 2;
  1937.     }
  1938.  
  1939.     int stride = 0;
  1940.     if (td.format.special && td.format.specialFormat == eSpecial_R10G10B10A2)
  1941.         stride = 4;
  1942.     else if (td.format.special && td.format.specialFormat == eSpecial_R11G11B10)
  1943.         stride = 4;
  1944.     else
  1945.     {
  1946.         stride = td.format.compCount * td.format.compByteWidth;
  1947.     }  
  1948.        
  1949.     int len = td.height * td.width * stride;
  1950.     uint64_t bigHash[2];   
  1951.     MurmurHash3_x64_128(subdata[0], len, 0, bigHash);
  1952.  
  1953.     FILE* fid = fopen(path, "a");
  1954.     fprintf(fid, "%I64d,%.16I64x.%.16I64x\n", sd.id, bigHash[0], bigHash[1]);
  1955.     fclose(fid);
  1956.        
  1957.     success = true;
  1958.    
  1959.     for (size_t i = 0; i < subdata.size(); i++)
  1960.         delete[] subdata[i];
  1961.  
  1962.     return success;
  1963. }
  1964.  
  1965. bool ReplayRenderer::HashBufferData(ResourceId buffer, const char *path)
  1966. {
  1967.     rdctype::array<byte> data = m_pDevice->GetBufferData(m_pDevice->GetLiveID(buffer), 0, 0);
  1968.    
  1969.     uint64_t bigHash[2];
  1970.     MurmurHash3_x64_128(data.elems, data.count, 0, bigHash);
  1971.  
  1972.     FILE* fid = fopen(path, "a");
  1973.     fprintf(fid, "%I64d,%.16I64x.%.16I64x\n", buffer, bigHash[0], bigHash[1]);
  1974.     fclose(fid);
  1975.  
  1976.     return true;
  1977. }
  1978.  
  1979. bool ReplayRenderer::HashShader(ResourceId buffer, const char *path)
  1980. {
  1981.     rdctype::array<byte> data = m_pDevice->GetShaderData(buffer);
  1982.    
  1983.     uint64_t bigHash[2];
  1984.     MurmurHash3_x64_128(data.elems, data.count, 0, bigHash);
  1985.  
  1986.     FILE* fid = fopen(path, "a");
  1987.     fprintf(fid, "%I64d,%.16I64x.%.16I64x\n", m_pDevice->GetOriginalID(buffer), bigHash[0], bigHash[1]);
  1988.     fclose(fid);
  1989.  
  1990.     return true;
  1991. }
  1992. /* Added by Stephan Richter | END */
  1993.  
  1994. bool ReplayRenderer::PixelHistory(ResourceId target, uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, uint32_t sampleIdx, rdctype::array<PixelModification> *history)
  1995. {
  1996.     bool outofbounds = false;
  1997.    
  1998.     for(size_t t=0; t < m_Textures.size(); t++)
  1999.     {
  2000.         if(m_Textures[t].ID == target)
  2001.         {
  2002.             if(x >= m_Textures[t].width || y >= m_Textures[t].height)
  2003.             {
  2004.                 RDCDEBUG("PixelHistory out of bounds on %llx (%u,%u) vs (%u,%u)", target, x, y, m_Textures[t].width, m_Textures[t].height);
  2005.                 history->count = 0;
  2006.                 history->elems = NULL;
  2007.                 return false;
  2008.             }
  2009.  
  2010.             if(m_Textures[t].msSamp == 1)
  2011.                 sampleIdx = ~0U;
  2012.  
  2013.             slice = RDCCLAMP(slice, 0U, m_Textures[t].arraysize);
  2014.             mip = RDCCLAMP(mip, 0U, m_Textures[t].mips);
  2015.  
  2016.             break;
  2017.         }
  2018.     }
  2019.  
  2020.     auto usage = m_pDevice->GetUsage(m_pDevice->GetLiveID(target));
  2021.  
  2022.     vector<EventUsage> events;
  2023.  
  2024.     for(size_t i=0; i < usage.size(); i++)
  2025.     {
  2026.         if(usage[i].eventID > m_EventID)
  2027.             continue;
  2028.  
  2029.         switch(usage[i].usage)
  2030.         {
  2031.             case eUsage_VertexBuffer:
  2032.             case eUsage_IndexBuffer:
  2033.             case eUsage_VS_Constants:
  2034.             case eUsage_HS_Constants:
  2035.             case eUsage_DS_Constants:
  2036.             case eUsage_GS_Constants:
  2037.             case eUsage_PS_Constants:
  2038.             case eUsage_CS_Constants:
  2039.             case eUsage_VS_Resource:
  2040.             case eUsage_HS_Resource:
  2041.             case eUsage_DS_Resource:
  2042.             case eUsage_GS_Resource:
  2043.             case eUsage_PS_Resource:
  2044.             case eUsage_CS_Resource:
  2045.             case eUsage_CopySrc:
  2046.             case eUsage_ResolveSrc:
  2047.                 // read-only, not a valid pixel history event
  2048.                 continue;
  2049.            
  2050.             case eUsage_None:
  2051.             case eUsage_SO:
  2052.             case eUsage_VS_RWResource:
  2053.             case eUsage_HS_RWResource:
  2054.             case eUsage_DS_RWResource:
  2055.             case eUsage_GS_RWResource:
  2056.             case eUsage_PS_RWResource:
  2057.             case eUsage_CS_RWResource:
  2058.             case eUsage_ColourTarget:
  2059.             case eUsage_DepthStencilTarget:
  2060.             case eUsage_Clear:
  2061.             case eUsage_Copy:
  2062.             case eUsage_CopyDst:
  2063.             case eUsage_Resolve:
  2064.             case eUsage_ResolveDst:
  2065.             case eUsage_GenMips:
  2066.                 // writing - include in pixel history events
  2067.                 break;
  2068.         }
  2069.  
  2070.         events.push_back(usage[i]);
  2071.     }
  2072.    
  2073.     if(events.empty())
  2074.     {
  2075.         RDCDEBUG("Target %llx not written to before %u", target, m_EventID);
  2076.         history->count = 0;
  2077.         history->elems = NULL;
  2078.         return false;
  2079.     }
  2080.  
  2081.     *history = m_pDevice->PixelHistory(m_FrameID, events, m_pDevice->GetLiveID(target), x, y, slice, mip, sampleIdx);
  2082.    
  2083.     SetFrameEvent(m_FrameID, m_EventID, true);
  2084.  
  2085.     return true;
  2086. }
  2087.  
  2088. bool ReplayRenderer::DebugVertex(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace)
  2089. {
  2090.     if(trace == NULL) return false;
  2091.  
  2092.     *trace = m_pDevice->DebugVertex(m_FrameID, m_EventID, vertid, instid, idx, instOffset, vertOffset);
  2093.  
  2094.     SetFrameEvent(m_FrameID, m_EventID, true);
  2095.  
  2096.     return true;
  2097. }
  2098.  
  2099. bool ReplayRenderer::DebugPixel(uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive, ShaderDebugTrace *trace)
  2100. {
  2101.     if(trace == NULL) return false;
  2102.  
  2103.     *trace = m_pDevice->DebugPixel(m_FrameID, m_EventID, x, y, sample, primitive);
  2104.    
  2105.     SetFrameEvent(m_FrameID, m_EventID, true);
  2106.  
  2107.     return true;
  2108. }
  2109.  
  2110. bool ReplayRenderer::DebugThread(uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace)
  2111. {
  2112.     if(trace == NULL) return false;
  2113.  
  2114.     *trace = m_pDevice->DebugThread(m_FrameID, m_EventID, groupid, threadid);
  2115.    
  2116.     SetFrameEvent(m_FrameID, m_EventID, true);
  2117.  
  2118.     return true;
  2119. }
  2120.  
  2121. bool ReplayRenderer::GetCBufferVariableContents(ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array<ShaderVariable> *vars)
  2122. {
  2123.     if(vars == NULL) return false;
  2124.  
  2125.     vector<byte> data;
  2126.     if(buffer != ResourceId())
  2127.         data = m_pDevice->GetBufferData(m_pDevice->GetLiveID(buffer), offs, 0);
  2128.  
  2129.     vector<ShaderVariable> v;
  2130.  
  2131.     m_pDevice->FillCBufferVariables(m_pDevice->GetLiveID(shader), cbufslot, v, data);
  2132.  
  2133.     *vars = v;
  2134.  
  2135.     return true;
  2136. }
  2137.  
  2138. ShaderReflection *ReplayRenderer::GetShaderDetails(ResourceId shader)
  2139. {
  2140.     return m_pDevice->GetShader(m_pDevice->GetLiveID(shader));
  2141. }
  2142.  
  2143. ReplayOutput *ReplayRenderer::CreateOutput(void *wndhandle)
  2144. {
  2145.     ReplayOutput *out = new ReplayOutput(this, wndhandle);
  2146.  
  2147.     m_Outputs.push_back(out);
  2148.  
  2149.     m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw);
  2150.    
  2151.     out->SetFrameEvent(m_FrameID, m_EventID);
  2152.  
  2153.     m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_OnlyDraw);
  2154.  
  2155.     return out;
  2156. }
  2157.  
  2158. void ReplayRenderer::ShutdownOutput(ReplayOutput *output)
  2159. {
  2160.     RDCUNIMPLEMENTED("Shutting down individual outputs");
  2161. }
  2162.  
  2163. void ReplayRenderer::Shutdown()
  2164. {
  2165.     delete this;
  2166. }
  2167.  
  2168. ResourceId ReplayRenderer::BuildTargetShader(const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, rdctype::str *errors)
  2169. {
  2170.     ResourceId id;
  2171.     string errs;
  2172.    
  2173.     switch(type)
  2174.     {
  2175.         case eShaderStage_Vertex:
  2176.         case eShaderStage_Hull:
  2177.         case eShaderStage_Domain:
  2178.         case eShaderStage_Geometry:
  2179.         case eShaderStage_Pixel:
  2180.         case eShaderStage_Compute:
  2181.             break;
  2182.         default:
  2183.             RDCERR("Unexpected type in BuildShader!");
  2184.             return ResourceId();
  2185.     }
  2186.  
  2187.     m_pDevice->BuildTargetShader(source, entry, compileFlags, type, &id, &errs);
  2188.  
  2189.     if(id != ResourceId())
  2190.         m_TargetResources.insert(id);
  2191.    
  2192.     if(errors) *errors = errs;
  2193.  
  2194.     return id;
  2195. }
  2196.  
  2197. ResourceId ReplayRenderer::BuildCustomShader(const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, rdctype::str *errors)
  2198. {
  2199.     ResourceId id;
  2200.     string errs;
  2201.    
  2202.     switch(type)
  2203.     {
  2204.         case eShaderStage_Vertex:
  2205.         case eShaderStage_Hull:
  2206.         case eShaderStage_Domain:
  2207.         case eShaderStage_Geometry:
  2208.         case eShaderStage_Pixel:
  2209.         case eShaderStage_Compute:
  2210.             break;
  2211.         default:
  2212.             RDCERR("Unexpected type in BuildShader!");
  2213.             return ResourceId();
  2214.     }
  2215.  
  2216.     m_pDevice->BuildCustomShader(source, entry, compileFlags, type, &id, &errs);
  2217.  
  2218.     if(id != ResourceId())
  2219.         m_CustomShaders.insert(id);
  2220.    
  2221.     if(errors) *errors = errs;
  2222.  
  2223.     return id;
  2224. }
  2225.  
  2226. bool ReplayRenderer::FreeTargetResource(ResourceId id)
  2227. {
  2228.     m_TargetResources.erase(id);
  2229.     m_pDevice->FreeTargetResource(id);
  2230.  
  2231.     return true;
  2232. }
  2233.  
  2234. bool ReplayRenderer::FreeCustomShader(ResourceId id)
  2235. {
  2236.     m_CustomShaders.erase(id);
  2237.     m_pDevice->FreeCustomShader(id);
  2238.  
  2239.     return true;
  2240. }
  2241.  
  2242. bool ReplayRenderer::ReplaceResource(ResourceId from, ResourceId to)
  2243. {
  2244.     m_pDevice->ReplaceResource(from, to);
  2245.  
  2246.     SetFrameEvent(m_FrameID, m_EventID, true);
  2247.    
  2248.     for(size_t i=0; i < m_Outputs.size(); i++)
  2249.         if(m_Outputs[i]->GetType() != eOutputType_None)
  2250.             m_Outputs[i]->Display();
  2251.  
  2252.     return true;
  2253. }
  2254.  
  2255. bool ReplayRenderer::RemoveReplacement(ResourceId id)
  2256. {
  2257.     m_pDevice->RemoveReplacement(id);
  2258.  
  2259.     SetFrameEvent(m_FrameID, m_EventID, true);
  2260.    
  2261.     for(size_t i=0; i < m_Outputs.size(); i++)
  2262.         if(m_Outputs[i]->GetType() != eOutputType_None)
  2263.             m_Outputs[i]->Display();
  2264.  
  2265.     return true;
  2266. }
  2267.  
  2268. ReplayCreateStatus ReplayRenderer::CreateDevice(const char *logfile)
  2269. {
  2270.     RDCLOG("Creating replay device for %s", logfile);
  2271.  
  2272.     RDCDriver driverType = RDC_Unknown;
  2273.     string driverName = "";
  2274.     auto status = RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, NULL);
  2275.  
  2276.     if(driverType == RDC_Unknown || driverName == "" || status != eReplayCreate_Success)
  2277.     {
  2278.         RDCERR("Couldn't get device type from log");
  2279.         return status;
  2280.     }
  2281.  
  2282.     IReplayDriver *driver = NULL;
  2283.     status = RenderDoc::Inst().CreateReplayDriver(driverType, logfile, &driver);
  2284.  
  2285.     if(driver && status == eReplayCreate_Success)
  2286.     {
  2287.         RDCLOG("Created replay driver.");
  2288.         return PostCreateInit(driver);
  2289.     }
  2290.    
  2291.     RDCERR("Couldn't create a replay device :(.");
  2292.     return status;
  2293. }
  2294.  
  2295. ReplayCreateStatus ReplayRenderer::SetDevice(IReplayDriver *device)
  2296. {
  2297.     if(device)
  2298.     {
  2299.         RDCLOG("Got replay driver.");
  2300.         return PostCreateInit(device);
  2301.     }
  2302.    
  2303.     RDCERR("Given invalid replay driver.");
  2304.     return eReplayCreate_InternalError;
  2305. }
  2306.  
  2307. ReplayCreateStatus ReplayRenderer::PostCreateInit(IReplayDriver *device)
  2308. {
  2309.     m_pDevice = device;
  2310.  
  2311.     m_pDevice->ReadLogInitialisation();
  2312.    
  2313.     FetchPipelineState();
  2314.  
  2315.     vector<FetchFrameRecord> fr = m_pDevice->GetFrameRecord();
  2316.  
  2317.     m_FrameRecord.reserve(fr.size());
  2318.     for(size_t i=0; i < fr.size(); i++)
  2319.     {
  2320.         m_FrameRecord.push_back(FrameRecord());
  2321.         m_FrameRecord.back().frameInfo = fr[i].frameInfo;
  2322.         m_FrameRecord.back().m_DrawCallList = fr[i].drawcallList;
  2323.        
  2324.         SetupDrawcallPointers(fr[i].frameInfo, m_FrameRecord.back().m_DrawCallList, NULL, NULL);
  2325.     }
  2326.  
  2327.     return eReplayCreate_Success;
  2328. }
  2329.  
  2330. FetchDrawcall *ReplayRenderer::SetupDrawcallPointers(FetchFrameInfo frame, rdctype::array<FetchDrawcall> &draws, FetchDrawcall *parent, FetchDrawcall *previous)
  2331. {
  2332.     FetchDrawcall *ret = NULL;
  2333.  
  2334.     for(int32_t i=0; i < draws.count; i++)
  2335.     {
  2336.         FetchDrawcall *draw = &draws[i];
  2337.  
  2338.         draw->parent = parent ? parent->eventID : 0;
  2339.  
  2340.         if(draw->children.count > 0)
  2341.         {
  2342.             ret = previous = SetupDrawcallPointers(frame, draw->children, draw, previous);
  2343.         }
  2344.         else if(draw->flags & (eDraw_PushMarker|eDraw_SetMarker|eDraw_Present|eDraw_MultiDraw))
  2345.         {
  2346.             // don't want to set up previous/next links for markers
  2347.         }
  2348.         else
  2349.         {
  2350.             if(previous != NULL)
  2351.                 previous->next = draw->eventID;
  2352.             draw->previous = previous ? previous->eventID : 0;
  2353.  
  2354.             RDCASSERT(m_Drawcalls.empty() || draw->eventID > m_Drawcalls.back()->eventID || draw->context != frame.immContextId);
  2355.             m_Drawcalls.resize(RDCMAX(m_Drawcalls.size(), size_t(draw->eventID+1)));
  2356.             m_Drawcalls[draw->eventID] = draw;
  2357.  
  2358.             ret = previous = draw;
  2359.         }
  2360.     }
  2361.  
  2362.     return ret;
  2363. }
  2364.  
  2365. void ReplayRenderer::FileChanged()
  2366. {
  2367.     m_pDevice->FileChanged();
  2368. }
  2369.  
  2370. bool ReplayRenderer::HasCallstacks()
  2371. {
  2372.     return m_pDevice->HasCallstacks();
  2373. }
  2374.  
  2375. APIProperties ReplayRenderer::GetAPIProperties()
  2376. {
  2377.     return m_pDevice->GetAPIProperties();
  2378. }
  2379.  
  2380. bool ReplayRenderer::InitResolver()
  2381. {
  2382.     m_pDevice->InitCallstackResolver();
  2383.     return m_pDevice->GetCallstackResolver() != NULL;
  2384. }
  2385.  
  2386. void ReplayRenderer::FetchPipelineState()
  2387. {
  2388.     m_pDevice->SavePipelineState();
  2389.  
  2390.     m_D3D11PipelineState = m_pDevice->GetD3D11PipelineState();
  2391.     m_GLPipelineState = m_pDevice->GetGLPipelineState();
  2392.    
  2393.     {
  2394.         D3D11PipelineState::ShaderStage *stage = &m_D3D11PipelineState.m_VS;
  2395.         for(int i=0; i < 6; i++)
  2396.             if(stage[i].Shader != ResourceId())
  2397.                 stage[i].ShaderDetails = m_pDevice->GetShader(m_pDevice->GetLiveID(stage[i].Shader));
  2398.     }
  2399.    
  2400.     {
  2401.         GLPipelineState::ShaderStage *stage = &m_GLPipelineState.m_VS;
  2402.         for(int i=0; i < 6; i++)
  2403.             if(stage[i].Shader != ResourceId())
  2404.                 stage[i].ShaderDetails = m_pDevice->GetShader(m_pDevice->GetLiveID(stage[i].Shader));
  2405.     }
  2406. }
  2407.  
  2408. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(ReplayRenderer *rend, APIProperties *props)
  2409. { if(props) *props = rend->GetAPIProperties(); }
  2410.  
  2411. extern "C" RENDERDOC_API ReplayOutput* RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, void *handle)
  2412. { return rend->CreateOutput(handle); }
  2413. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend)
  2414. { rend->Shutdown(); }
  2415. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output)
  2416. { rend->ShutdownOutput(output); }
  2417.  
  2418. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_FileChanged(ReplayRenderer *rend)
  2419. { rend->FileChanged(); }
  2420.  
  2421. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend)
  2422. { return rend->HasCallstacks(); }
  2423. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_InitResolver(ReplayRenderer *rend)
  2424. { return rend->InitResolver(); }
  2425.  
  2426. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SetContextFilter(ReplayRenderer *rend, ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv)
  2427. { return rend->SetContextFilter(id, firstDefEv, lastDefEv); }
  2428. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SetFrameEvent(ReplayRenderer *rend, uint32_t frameID, uint32_t eventID)
  2429. { return rend->SetFrameEvent(frameID, eventID); }
  2430. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_SetIDRenderingEvents(ReplayRenderer *rend, uint32_t frameID, uint32_t startEventID, uint32_t endEventID)
  2431. { rend->SetIDRenderingEvents(frameID, startEventID, endEventID); }
  2432. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_SetIDRendering(ReplayRenderer *rend, bool32 active, ResourceId shaderID)
  2433. { rend->SetIDRendering(active, shaderID); }
  2434. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetD3D11PipelineState(ReplayRenderer *rend, D3D11PipelineState *state)
  2435. { return rend->GetD3D11PipelineState(state); }
  2436. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetGLPipelineState(ReplayRenderer *rend, GLPipelineState *state)
  2437. { return rend->GetGLPipelineState(state); }
  2438.  
  2439. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildCustomShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
  2440. {
  2441.     if(shaderID == NULL) return;
  2442.  
  2443.     *shaderID = rend->BuildCustomShader(entry, source, compileFlags, type, errors);
  2444. }
  2445. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeCustomShader(ReplayRenderer *rend, ResourceId id)
  2446. { return rend->FreeCustomShader(id); }
  2447.  
  2448. extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_BuildTargetShader(ReplayRenderer *rend, const char *entry, const char *source, const uint32_t compileFlags, ShaderStageType type, ResourceId *shaderID, rdctype::str *errors)
  2449. {
  2450.     if(shaderID == NULL) return;
  2451.  
  2452.     *shaderID = rend->BuildTargetShader(entry, source, compileFlags, type, errors);
  2453. }
  2454. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_ReplaceResource(ReplayRenderer *rend, ResourceId from, ResourceId to)
  2455. { return rend->ReplaceResource(from, to); }
  2456. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_RemoveReplacement(ReplayRenderer *rend, ResourceId id)
  2457. { return rend->RemoveReplacement(id); }
  2458. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeTargetResource(ReplayRenderer *rend, ResourceId id)
  2459. { return rend->FreeTargetResource(id); }
  2460.  
  2461. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetFrameInfo(ReplayRenderer *rend, rdctype::array<FetchFrameInfo> *frame)
  2462. { return rend->GetFrameInfo(frame); }
  2463. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, rdctype::array<FetchDrawcall> *draws)
  2464. { return rend->GetDrawcalls(frameID, draws); }
  2465. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FetchCounters(ReplayRenderer *rend, uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array<CounterResult> *results)
  2466. { return rend->FetchCounters(frameID, minEventID, maxEventID, counters, numCounters, results); }
  2467. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_EnumerateCounters(ReplayRenderer *rend, rdctype::array<uint32_t> *counters)
  2468. { return rend->EnumerateCounters(counters); }
  2469. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DescribeCounter(ReplayRenderer *rend, uint32_t counterID, CounterDescription *desc)
  2470. { return rend->DescribeCounter(counterID, desc); }
  2471. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetTextures(ReplayRenderer *rend, rdctype::array<FetchTexture> *texs)
  2472. { return rend->GetTextures(texs); }
  2473. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array<FetchBuffer> *bufs)
  2474. { return rend->GetBuffers(bufs); }
  2475. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPixelShaders(ReplayRenderer *rend, rdctype::array<FetchShader> *bufs)
  2476. {
  2477.     return rend->GetPixelShaders(bufs);
  2478. }
  2479. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetResolve(ReplayRenderer *rend, uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::str> *trace)
  2480. { return rend->GetResolve(callstack, callstackLen, trace); }
  2481. extern "C" RENDERDOC_API ShaderReflection* RENDERDOC_CC ReplayRenderer_GetShaderDetails(ReplayRenderer *rend, ResourceId shader)
  2482. { return rend->GetShaderDetails(shader); }
  2483. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDebugMessages(ReplayRenderer *rend, rdctype::array<DebugMessage> *msgs)
  2484. { return rend->GetDebugMessages(msgs); }
  2485.  
  2486. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_PixelHistory(ReplayRenderer *rend, ResourceId target, uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, uint32_t sampleIdx, rdctype::array<PixelModification> *history)
  2487. { return rend->PixelHistory(target, x, y, slice, mip, sampleIdx, history); }
  2488. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DebugVertex(ReplayRenderer *rend, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset, ShaderDebugTrace *trace)
  2489. { return rend->DebugVertex(vertid, instid, idx, instOffset, vertOffset, trace); }
  2490. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DebugPixel(ReplayRenderer *rend, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive, ShaderDebugTrace *trace)
  2491. { return rend->DebugPixel(x, y, sample, primitive, trace); }
  2492. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DebugThread(ReplayRenderer *rend, uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace)
  2493. { return rend->DebugThread(groupid, threadid, trace); }
  2494.  
  2495. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetUsage(ReplayRenderer *rend, ResourceId id, rdctype::array<EventUsage> *usage)
  2496. { return rend->GetUsage(id, usage); }
  2497.  
  2498. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetCBufferVariableContents(ReplayRenderer *rend, ResourceId shader, uint32_t cbufslot, ResourceId buffer, uint32_t offs, rdctype::array<ShaderVariable> *vars)
  2499. { return rend->GetCBufferVariableContents(shader, cbufslot, buffer, offs, vars); }
  2500.  
  2501. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SaveTexture(ReplayRenderer *rend, const TextureSave &saveData, const char *path)
  2502. { return rend->SaveTexture(saveData, path); }
  2503.  
  2504. /* Added by Stephan Richter | BEGIN */
  2505. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HashTexture(ReplayRenderer *rend, const TextureSave &saveData, const char *path)
  2506. {
  2507.     return rend->HashTexture(saveData, path);
  2508. }
  2509. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HashBufferData(ReplayRenderer *rend, ResourceId buff, const char *path)
  2510. {
  2511.     return rend->HashBufferData(buff, path);
  2512. }
  2513. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HashShader(ReplayRenderer *rend, ResourceId buff, const char *path)
  2514. {
  2515.     return rend->HashShader(buff, path);
  2516. }
  2517. /* Added by Stephan Richter | END */
  2518.  
  2519. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, uint32_t instID, MeshDataStage stage, MeshFormat *data)
  2520. { return rend->GetPostVSData(instID, stage, data); }
  2521.  
  2522. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetMinMax(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval)
  2523. { return rend->GetMinMax(tex, sliceFace, mip, sample, minval, maxval); }
  2524. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetHistogram(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool32 channels[4], rdctype::array<uint32_t> *histogram)
  2525. {
  2526.     bool chans[4] = { channels[0] != 0, channels[1] != 0, channels[2] != 0, channels[3] != 0 };
  2527.     return rend->GetHistogram(tex, sliceFace, mip, sample, minval, maxval, chans, histogram);
  2528. }
  2529.  
  2530. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBufferData(ReplayRenderer *rend, ResourceId buff, uint32_t offset, uint32_t len, rdctype::array<byte> *data)
  2531. { return rend->GetBufferData(buff, offset, len, data); }
  2532.  
  2533. extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetTextureData(ReplayRenderer *rend, ResourceId tex, uint32_t arrayIdx, uint32_t mip, rdctype::array<byte> *data)
  2534. { return rend->GetTextureData(tex, arrayIdx, mip, data); }
Add Comment
Please, Sign In to add comment