BVB Source Codes

CRYENGINE Show GeomCacheManager.cpp Source code

Return Download CRYENGINE: download GeomCacheManager.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // ------------------------------------------------------------------------
  4. //  File name:   GeomCacheManager.cpp
  5. //  Created:     20/7/2012 by Axel Gneiting
  6. //  Description: Manages geometry cache instances and streaming
  7. // -------------------------------------------------------------------------
  8. //
  9. ////////////////////////////////////////////////////////////////////////////
  10.  
  11. #include "StdAfx.h"
  12.  
  13. #if defined(USE_GEOM_CACHES)
  14.  
  15.         #include "GeomCacheManager.h"
  16.         #include "GeomCache.h"
  17.         #include "GeomCacheRenderNode.h"
  18.         #include <CryMath/Cry_Color.h>
  19.  
  20.         #include <CryThreading/IJobManager_JobDelegator.h>
  21.  
  22. DECLARE_JOB("GeomCacheDecomp", TGeomCacheDecompressJob, CGeomCacheManager::DecompressFrame_JobEntry);
  23. DECLARE_JOB("GeomCacheIFrameDecode", TGeomCacheIFrameDecodeJob, CGeomCacheManager::DecodeIFrame_JobEntry)
  24. DECLARE_JOB("GeomCacheBFrameDecode", TGeomCacheBFrameDecodeJob, CGeomCacheManager::DecodeBFrame_JobEntry)
  25. DECLARE_JOB("GeomCacheFill", TGeomCacheFillRenderNodeAsyncJob, CGeomCacheManager::FillRenderNodeAsync_JobEntry);
  26.  
  27. namespace
  28. {
  29. const uint kMinBufferSizeInMiB = 8;
  30. const uint kMaxBufferSizeInMiB = 2048;
  31. }
  32.  
  33. CGeomCacheManager::CGeomCacheManager()
  34.         : m_pPoolBaseAddress(NULL)
  35.         , m_pPool(NULL)
  36.         , m_poolSize(0)
  37.         , m_lastRequestStream(0)
  38.         , m_numMissedFrames(0)
  39.         , m_numStreamAborts(0)
  40.         , m_numErrorAborts(0)
  41.         , m_numDecompressStreamAborts(0)
  42.         , m_numReadStreamAborts(0)
  43.         , m_numFailedAllocs(0)
  44. {
  45.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_GeomCache, 0, "Geometry cache streaming pool");
  46.  
  47.         ChangeBufferSize(GetCVars()->e_GeomCacheBufferSize);
  48.  
  49.         ICVar* pGeomCacheBufferSizeCVar = gEnv->pConsole->GetCVar("e_GeomCacheBufferSize");
  50.         if (pGeomCacheBufferSizeCVar)
  51.         {
  52.                 pGeomCacheBufferSizeCVar->SetOnChangeCallback(&CGeomCacheManager::OnChangeBufferSize);
  53.         }
  54. }
  55.  
  56. CGeomCacheManager::~CGeomCacheManager()
  57. {
  58.         Reset();
  59.         UnloadGeomCaches();
  60.  
  61.         #if !defined(DEDICATED_SERVER)
  62.         m_pPool->Release();
  63.         m_pPool = NULL;
  64.  
  65.         CryGetIMemoryManager()->FreePages(m_pPoolBaseAddress, m_poolSize);
  66.         #endif
  67. }
  68.  
  69. void CGeomCacheManager::Reset()
  70. {
  71.         const uint numStreams = m_streamInfos.size();
  72.         for (uint i = 0; i < numStreams; ++i)
  73.         {
  74.                 SGeomCacheStreamInfo* pStreamInfo = m_streamInfos[i];
  75.                 AbortStreamAndWait(*pStreamInfo);
  76.                 delete pStreamInfo;
  77.         }
  78.  
  79.         stl::free_container(m_streamInfos);
  80.  
  81.         GetMeshManager().Reset();
  82. }
  83.  
  84. void CGeomCacheManager::StopCacheStreamsAndWait(CGeomCache* pGeomCache)
  85. {
  86.         const uint numStreams = m_streamInfos.size();
  87.         for (uint i = 0; i < numStreams; ++i)
  88.         {
  89.                 SGeomCacheStreamInfo* pStreamInfo = m_streamInfos[i];
  90.                 if (pStreamInfo->m_pGeomCache == pGeomCache)
  91.                 {
  92.                         AbortStreamAndWait(*pStreamInfo);
  93.                 }
  94.         }
  95. }
  96.  
  97. CGeomCache* CGeomCacheManager::FindGeomCacheByFilename(const char* filename)
  98. {
  99.         return stl::find_in_map(m_nameToGeomCacheMap, CONST_TEMP_STRING(filename), NULL);
  100. }
  101.  
  102. CGeomCache* CGeomCacheManager::LoadGeomCache(const char* szFileName)
  103. {
  104.         LOADING_TIME_PROFILE_SECTION;
  105.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "Geometry Caches");
  106.  
  107.         // Normalize file name
  108.         char sFilename[_MAX_PATH];
  109.  
  110.         // Remap %level% alias if needed an unify filename
  111.         int nAliasNameLen = sizeof("%level%") - 1;
  112.         if (strncmp(szFileName, "%level%", nAliasNameLen) == 0)
  113.         {
  114.                 cry_strcpy(sFilename, Get3DEngine()->GetLevelFilePath(szFileName + nAliasNameLen));
  115.         }
  116.         else
  117.         {
  118.                 cry_strcpy(sFilename, szFileName);
  119.         }
  120.         std::replace(sFilename, sFilename + strlen(sFilename), '\\', '/'); // To Unix Path
  121.  
  122.         // Try to find existing object for that file
  123.         CGeomCache* pGeomCache = stl::find_in_map(m_nameToGeomCacheMap, CONST_TEMP_STRING(sFilename), NULL);
  124.         if (pGeomCache)
  125.         {
  126.                 return pGeomCache;
  127.         }
  128.  
  129.         // Load geom cache
  130.         pGeomCache = new CGeomCache(sFilename);
  131.         m_nameToGeomCacheMap[sFilename] = pGeomCache;
  132.         return pGeomCache;
  133. }
  134.  
  135. void CGeomCacheManager::UnloadGeomCaches()
  136. {
  137.         for (TGeomCacheMap::iterator iter = m_nameToGeomCacheMap.begin(); iter != m_nameToGeomCacheMap.end(); ++iter)
  138.         {
  139.                 delete iter->second;
  140.         }
  141.  
  142.         stl::free_container(m_nameToGeomCacheMap);
  143. }
  144.  
  145. void CGeomCacheManager::DeleteGeomCache(CGeomCache* pGeomCache)
  146. {
  147.         const char* pFilename = pGeomCache->GetFilePath();
  148.         m_nameToGeomCacheMap.erase(pFilename);
  149.         delete pGeomCache;
  150. }
  151.  
  152. void CGeomCacheManager::RegisterForStreaming(CGeomCacheRenderNode* pRenderNode)
  153. {
  154.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  155.  
  156.         if (!pRenderNode)
  157.         {
  158.                 return;
  159.         }
  160.  
  161.         for (uint i = 0; i < m_streamInfos.size(); ++i)
  162.         {
  163.                 const SGeomCacheStreamInfo* pStreamInfo = m_streamInfos[i];
  164.                 if (pStreamInfo->m_pRenderNode == pRenderNode)
  165.                 {
  166.                         return;
  167.                 }
  168.         }
  169.  
  170.         CGeomCache* pGeomCache = static_cast<CGeomCache*>(pRenderNode->GetGeomCache());
  171.         pGeomCache->IncreaseNumStreams();
  172.  
  173.         const uint numFrames = pGeomCache->GetNumFrames();
  174.  
  175.         SGeomCacheStreamInfo* pStreamInfo = new SGeomCacheStreamInfo(pRenderNode, pGeomCache, numFrames);
  176.         m_streamInfos.push_back(pStreamInfo);
  177.  
  178.         // If cache is too short we need to allocate double the amount of frame data. Otherwise we can't loop without aborts,
  179.         // because IssueDiskReadRequest prevents the same frame info from being used twice.
  180.         const uint preferredDiskRequestSize = (size_t)std::max(0, GetCVars()->e_GeomCachePreferredDiskRequestSize * 1024);
  181.         const uint64 compressedAnimationDataSize = pGeomCache->GetCompressedAnimationDataSize();
  182.  
  183.         const float maxBufferAheadTime = std::max(1.0f, GetCVars()->e_GeomCacheMaxBufferAheadTime);
  184.         const float duration = pGeomCache->GetDuration();
  185.  
  186.         const bool bNeedDoubleFrameData = (compressedAnimationDataSize < (preferredDiskRequestSize * 2)) || (duration < (maxBufferAheadTime * 2));
  187.  
  188.         const uint numFrameData = bNeedDoubleFrameData ? (numFrames * 2) : numFrames;
  189.         pStreamInfo->m_frameData.resize(numFrameData);
  190.         ReinitializeStreamFrameData(*pStreamInfo, 0, numFrameData - 1);
  191. }
  192.  
  193. void CGeomCacheManager::OnChangeBufferSize(ICVar* pCVar)
  194. {
  195.         GetGeomCacheManager()->ChangeBufferSize(pCVar->GetIVal());
  196. }
  197.  
  198. void CGeomCacheManager::ChangeBufferSize(const uint newSizeInMiB)
  199. {
  200.         const uint numStreams = m_streamInfos.size();
  201.         for (uint i = 0; i < numStreams; ++i)
  202.         {
  203.                 SGeomCacheStreamInfo* pStreamInfo = m_streamInfos[i];
  204.                 AbortStreamAndWait(*pStreamInfo);
  205.         }
  206.  
  207.         #if !defined(DEDICATED_SERVER)
  208.         SAFE_RELEASE(m_pPool);
  209.         if (m_pPoolBaseAddress)
  210.         {
  211.                 CryGetIMemoryManager()->FreePages(m_pPoolBaseAddress, m_poolSize);
  212.         }
  213.  
  214.         const int geomCacheBufferSize = clamp_tpl(newSizeInMiB, kMinBufferSizeInMiB, kMaxBufferSizeInMiB);
  215.         GetCVars()->e_GeomCacheBufferSize = geomCacheBufferSize;
  216.  
  217.         const uint kMiBtoBytesFactor = 1024 * 1024;
  218.         m_poolSize = geomCacheBufferSize * kMiBtoBytesFactor;
  219.  
  220.         m_pPoolBaseAddress = CryGetIMemoryManager()->AllocPages(m_poolSize);
  221.         m_pPool = gEnv->pSystem->GetIMemoryManager()->CreateGeneralMemoryHeap(m_pPoolBaseAddress, m_poolSize, "GEOMCACHE_POOL");
  222.         #endif
  223. }
  224.  
  225. void CGeomCacheManager::ReinitializeStreamFrameData(SGeomCacheStreamInfo& streamInfo, uint startFrame, uint endFrame)
  226. {
  227.         const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  228.  
  229.         const uint frameDataSize = streamInfo.m_frameData.size();
  230.         startFrame = std::min(frameDataSize - 1, startFrame);
  231.         endFrame = std::min(frameDataSize - 1, endFrame);
  232.  
  233.         for (uint i = startFrame; i <= endFrame; ++i)
  234.         {
  235.                 SGeomCacheStreamInfo::SFrameData& frameData = streamInfo.m_frameData[i];
  236.  
  237.                 frameData.m_bDecompressJobLaunched = false;
  238.                 frameData.m_pDecompressHandle = NULL;
  239.  
  240.                 const GeomCacheFile::EFrameType frameType = pGeomCache->GetFrameType(i);
  241.  
  242.                 if (frameType == GeomCacheFile::eFrameType_IFrame)
  243.                 {
  244.                         frameData.m_decodeDependencyCounter = 1;
  245.                 }
  246.                 else if (frameType == GeomCacheFile::eFrameType_BFrame)
  247.                 {
  248.                         assert(i > 0);
  249.  
  250.                         if (pGeomCache->GetFrameType(i - 1) == GeomCacheFile::eFrameType_IFrame)
  251.                         {
  252.                                 frameData.m_decodeDependencyCounter = 3;
  253.                         }
  254.                         else
  255.                         {
  256.                                 frameData.m_decodeDependencyCounter = 2;
  257.                         }
  258.                 }
  259.         }
  260. }
  261.  
  262. void CGeomCacheManager::UnRegisterForStreaming(CGeomCacheRenderNode* pRenderNode, bool bWaitForJobs)
  263. {
  264.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  265.  
  266.         TStreamInfosIter iter = m_streamInfos.begin();
  267.         while (iter != m_streamInfos.end())
  268.         {
  269.                 SGeomCacheStreamInfo* pStreamInfo = *iter;
  270.                 if (pStreamInfo->m_pRenderNode == pRenderNode)
  271.                 {
  272.                         if (pStreamInfo->m_pNewestReadRequestHandle || pStreamInfo->m_pOldestDecompressHandle)
  273.                         {
  274.                                 gEnv->pLog->LogWarning("Unregistering stream %s while still active", pStreamInfo->m_pRenderNode->GetName());
  275.                         }
  276.  
  277.                         if (!bWaitForJobs)
  278.                         {
  279.                                 AbortStream(*pStreamInfo);
  280.                         }
  281.                         else
  282.                         {
  283.                                 AbortStreamAndWait(*pStreamInfo);
  284.                         }
  285.  
  286.                         m_streamInfosAbortList.push_back(pStreamInfo);
  287.                         iter = m_streamInfos.erase(iter);
  288.                 }
  289.                 else
  290.                 {
  291.                         ++iter;
  292.                 }
  293.         }
  294.  
  295.         RetireRemovedStreams();
  296. }
  297.  
  298. void CGeomCacheManager::StreamingUpdate()
  299. {
  300.         FUNCTION_PROFILER_3DENGINE;
  301.  
  302.         const bool bCachesActive = GetCVars()->e_GeomCaches != 0;
  303.  
  304.         RetireRemovedStreams();
  305.  
  306.         const uint numStreams = m_streamInfos.size();
  307.         for (uint i = 0; i < numStreams; ++i)
  308.         {
  309.                 SGeomCacheStreamInfo& streamInfo = *m_streamInfos[i];
  310.  
  311.                 if (streamInfo.m_fillRenderNodeJobState.IsRunning())
  312.                 {
  313.                         FRAME_PROFILER("CGeomCacheManager::StreamingUpdate_WaitForLastFillJob", GetSystem(), PROFILE_3DENGINE);
  314.                         gEnv->pJobManager->WaitForJob(streamInfo.m_fillRenderNodeJobState);
  315.                 }
  316.  
  317.                 // Update wanted playback frame
  318.                 CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  319.                 const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  320.                 streamInfo.m_wantedPlaybackTime = pRenderNode->GetPlaybackTime();
  321.                 streamInfo.m_wantedFloorFrame = pGeomCache->GetFloorFrameIndex(streamInfo.m_wantedPlaybackTime);
  322.                 streamInfo.m_wantedCeilFrame = pGeomCache->GetCeilFrameIndex(streamInfo.m_wantedPlaybackTime);
  323.                 streamInfo.m_bLooping = streamInfo.m_pRenderNode->IsLooping();
  324.  
  325.                 if (!streamInfo.m_bLooping)
  326.                 {
  327.                         const uint numFrames = streamInfo.m_numFrames;
  328.                         streamInfo.m_wantedFloorFrame = std::min((uint)streamInfo.m_wantedFloorFrame, numFrames - 1);
  329.                         streamInfo.m_wantedCeilFrame = std::min((uint)streamInfo.m_wantedCeilFrame, numFrames - 1);
  330.                 }
  331.  
  332.                 assert(streamInfo.m_wantedFloorFrame + 1 == streamInfo.m_wantedCeilFrame
  333.                        || streamInfo.m_wantedFloorFrame == streamInfo.m_wantedCeilFrame);
  334.  
  335.                 // Update bbox for this frame
  336.                 pRenderNode->UpdateBBox();
  337.  
  338.                 // Abort stream and trash it if it's not valid anymore
  339.                 ValidateStream(streamInfo);
  340.  
  341.                 // Try to trash as many aborted handles as possible
  342.                 RetireAbortedHandles(streamInfo);
  343.  
  344.                 // Retire handles that are not needed anymore
  345.                 RetireHandles(streamInfo);
  346.         }
  347.  
  348.         if (bCachesActive)
  349.         {
  350.                 const CTimeValue currentFrameTime = GetTimer()->GetFrameStartTime();
  351.                 LaunchStreamingJobs(numStreams, currentFrameTime);
  352.         }
  353.  
  354.         // Start disk read requests alternating between geom cache render nodes until no more
  355.         // can be issued (buffers full, max read ahead time reached, no free request object)
  356.         bool bMoreRequests = true;
  357.         while (bMoreRequests && bCachesActive)
  358.         {
  359.                 bMoreRequests = false;
  360.                 uint nextRequestStream = m_lastRequestStream + 1;
  361.  
  362.                 for (uint i = 0; i < numStreams; ++i)
  363.                 {
  364.                         const uint requestStream = (nextRequestStream + i) % numStreams;
  365.  
  366.                         SGeomCacheStreamInfo& streamInfo = *m_streamInfos[i];
  367.                         const CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  368.                         const bool bIsStreaming = pRenderNode->IsStreaming();
  369.                         const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  370.                         const bool bPlaybackFromMemory = pGeomCache->PlaybackFromMemory();
  371.                         const float playbackFrame = streamInfo.m_wantedPlaybackTime;
  372.                         const float displayedFrame = streamInfo.m_displayedFrameTime;
  373.  
  374.                         if (!bPlaybackFromMemory && (bIsStreaming || (displayedFrame != playbackFrame)))
  375.                         {
  376.                                 const bool bRequestIssued = IssueDiskReadRequest(streamInfo);
  377.  
  378.                                 if (bRequestIssued)
  379.                                 {
  380.                                         m_lastRequestStream = requestStream;
  381.                                 }
  382.  
  383.                                 bMoreRequests |= bRequestIssued;
  384.                         }
  385.                 }
  386.         }
  387.  
  388.         #ifndef _RELEASE
  389.         for (uint i = 0; i < numStreams; ++i)
  390.         {
  391.                 SGeomCacheStreamInfo& streamInfo = *m_streamInfos[i];
  392.                 streamInfo.m_pRenderNode->DebugRender();
  393.         }
  394.         #endif
  395. }
  396.  
  397. void CGeomCacheManager::LaunchStreamingJobs(const uint numStreams, const CTimeValue currentFrameTime)
  398. {
  399.         FUNCTION_PROFILER_3DENGINE;
  400.  
  401.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  402.  
  403.         // Launch streaming jobs
  404.         for (uint i = 0; i < numStreams; ++i)
  405.         {
  406.                 SGeomCacheStreamInfo* pStreamInfo = m_streamInfos[i];
  407.                 CGeomCacheRenderNode* pRenderNode = pStreamInfo->m_pRenderNode;
  408.                 const CGeomCache* pGeomCache = pStreamInfo->m_pGeomCache;
  409.  
  410.                 if (!pGeomCache)
  411.                 {
  412.                         continue;
  413.                 }
  414.  
  415.                 const bool bIsStreaming = pRenderNode->IsStreaming();
  416.                 const float playbackFrameTime = pStreamInfo->m_wantedPlaybackTime;
  417.                 const float displayedFrameTime = pStreamInfo->m_displayedFrameTime;
  418.  
  419.                 LaunchDecompressJobs(pStreamInfo, currentFrameTime);
  420.  
  421.                 const bool bSameFrame = playbackFrameTime == displayedFrameTime;
  422.                 if (!bSameFrame || pStreamInfo->m_sameFrameFillCount < 2)
  423.                 {
  424.                         pRenderNode->StartAsyncUpdate();
  425.                         TGeomCacheFillRenderNodeAsyncJob fillRenderNodeAsyncJob(pStreamInfo);
  426.                         fillRenderNodeAsyncJob.SetClassInstance(this);
  427.                         fillRenderNodeAsyncJob.RegisterJobState(&pStreamInfo->m_fillRenderNodeJobState);
  428.                         fillRenderNodeAsyncJob.SetPriorityLevel(JobManager::eHighPriority);
  429.                         fillRenderNodeAsyncJob.Run();
  430.                 }
  431.         }
  432. }
  433.  
  434. void CGeomCacheManager::RetireRemovedStreams()
  435. {
  436.         FUNCTION_PROFILER_3DENGINE;
  437.  
  438.         TStreamInfosIter iter = m_streamInfosAbortList.begin();
  439.  
  440.         while (iter != m_streamInfosAbortList.end())
  441.         {
  442.                 SGeomCacheStreamInfo* pStreamInfo = *iter;
  443.  
  444.                 gEnv->GetJobManager()->WaitForJob(pStreamInfo->m_fillRenderNodeJobState);
  445.                 RetireAbortedHandles(*pStreamInfo);
  446.  
  447.                 if (pStreamInfo->m_fillRenderNodeJobState.IsRunning()
  448.                     || pStreamInfo->m_pReadAbortListHead || pStreamInfo->m_pDecompressAbortListHead)
  449.                 {
  450.                         ++iter;
  451.                 }
  452.                 else
  453.                 {
  454.                         // Nothing left running, we can finally delete the stream
  455.                         CGeomCache* pGeomCache = pStreamInfo->m_pGeomCache;
  456.                         pGeomCache->DecreaseNumStreams();
  457.  
  458.                         pStreamInfo->m_pRenderNode->ClearFillData();
  459.  
  460.                         delete pStreamInfo;
  461.                         iter = m_streamInfosAbortList.erase(iter);
  462.                 }
  463.         }
  464.  
  465.         for (TGeomCacheMap::iterator iter = m_nameToGeomCacheMap.begin(); iter != m_nameToGeomCacheMap.end(); ++iter)
  466.         {
  467.                 CGeomCache* pGeomCache = iter->second;
  468.                 if (pGeomCache->GetNumStreams() == 0)
  469.                 {
  470.                         pGeomCache->UnloadData();
  471.                 }
  472.         }
  473. }
  474.  
  475. void CGeomCacheManager::ValidateStream(SGeomCacheStreamInfo& streamInfo)
  476. {
  477.         FUNCTION_PROFILER_3DENGINE;
  478.  
  479.         const CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  480.         const bool bIsStreaming = pRenderNode->IsStreaming();
  481.         const float wantedPlaybackTime = streamInfo.m_wantedPlaybackTime;
  482.         const float displayedFrameTime = streamInfo.m_displayedFrameTime;
  483.  
  484.         if (!pRenderNode->IsStreaming() && (displayedFrameTime == wantedPlaybackTime) && streamInfo.m_sameFrameFillCount >= 2)
  485.         {
  486.                 AbortStream(streamInfo);
  487.                 return;
  488.         }
  489.  
  490.         // Abort if there was an error in the stream. Also set the render node to not play back in this case.
  491.         if (streamInfo.m_pOldestReadRequestHandle && streamInfo.m_pOldestReadRequestHandle->m_error != 0)
  492.         {
  493.                 ++m_numStreamAborts;
  494.                 ++m_numErrorAborts;
  495.                 gEnv->pLog->LogError("Error in cache stream %s", streamInfo.m_pRenderNode->GetName());
  496.                 AbortStream(streamInfo);
  497.                 streamInfo.m_pRenderNode->StopStreaming();
  498.                 return;
  499.         }
  500.  
  501.         const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  502.         const float currentCacheStreamingTime = streamInfo.m_pRenderNode->GetStreamingTime();
  503.         const uint wantedFloorFrame = pGeomCache->GetFloorFrameIndex(currentCacheStreamingTime);
  504.  
  505.         // Check if stream is invalid
  506.         bool bAbort = false;
  507.  
  508.         if (streamInfo.m_pOldestDecompressHandle)
  509.         {
  510.                 if ((streamInfo.m_pOldestDecompressHandle->m_startFrame > wantedFloorFrame)
  511.                     || (streamInfo.m_pNewestDecompressHandle->m_endFrame < wantedFloorFrame))
  512.                 {
  513.                         gEnv->pLog->LogWarning("Aborting cache stream %s (decompress stream: [%u, %u], wanted frame: %u)", streamInfo.m_pRenderNode->GetName(),
  514.                                                streamInfo.m_pOldestDecompressHandle->m_startFrame, streamInfo.m_pNewestDecompressHandle->m_endFrame, wantedFloorFrame);
  515.                         ++m_numDecompressStreamAborts;
  516.                         bAbort = true;
  517.                 }
  518.         }
  519.         else if (streamInfo.m_pOldestReadRequestHandle)
  520.         {
  521.                 if (streamInfo.m_pOldestReadRequestHandle->m_startFrame > wantedFloorFrame)
  522.                 {
  523.                         gEnv->pLog->LogWarning("Aborting cache stream %s (read stream start: %u, wanted frame: %u)", streamInfo.m_pRenderNode->GetName(),
  524.                                                streamInfo.m_pOldestReadRequestHandle->m_startFrame, wantedFloorFrame);
  525.                         ++m_numReadStreamAborts;
  526.                         bAbort = true;
  527.                 }
  528.         }
  529.  
  530.         if (bAbort)
  531.         {
  532.                 ++m_numStreamAborts;
  533.                 AbortStream(streamInfo);
  534.         }
  535. }
  536.  
  537. void CGeomCacheManager::AbortStream(SGeomCacheStreamInfo& streamInfo)
  538. {
  539.         FUNCTION_PROFILER_3DENGINE;
  540.  
  541.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  542.  
  543.         streamInfo.m_bAbort = true;
  544.  
  545.         {
  546.                 FRAME_PROFILER("CGeomCacheManager::AbortStream_LockFillRenderNode", GetSystem(), PROFILE_3DENGINE);
  547.                 streamInfo.m_abortCS.Lock();
  548.         }
  549.  
  550.         if (streamInfo.m_pNewestReadRequestHandle)
  551.         {
  552.                 FRAME_PROFILER("CGeomCacheManager::AbortStream_AbortReads", GetSystem(), PROFILE_3DENGINE);
  553.  
  554.                 assert(streamInfo.m_pOldestReadRequestHandle != NULL);
  555.  
  556.                 // Abort read requests if possible
  557.                 for (SGeomCacheReadRequestHandle* pCurrentReadRequestHandle = streamInfo.m_pOldestReadRequestHandle;
  558.                      pCurrentReadRequestHandle; pCurrentReadRequestHandle = static_cast<SGeomCacheReadRequestHandle*>(pCurrentReadRequestHandle->m_pNext))
  559.                 {
  560.                         if (pCurrentReadRequestHandle->m_pReadStream)
  561.                         {
  562.                                 pCurrentReadRequestHandle->m_pReadStream->TryAbort();
  563.                         }
  564.                 }
  565.  
  566.                 // Put all handles in the read request list on the abort list
  567.                 assert(streamInfo.m_pNewestReadRequestHandle->m_pNext == NULL);
  568.                 streamInfo.m_pNewestReadRequestHandle->m_pNext = streamInfo.m_pReadAbortListHead;
  569.                 streamInfo.m_pReadAbortListHead = streamInfo.m_pOldestReadRequestHandle;
  570.  
  571.                 // Mark read request list as empty
  572.                 streamInfo.m_pOldestReadRequestHandle = NULL;
  573.                 streamInfo.m_pNewestReadRequestHandle = NULL;
  574.         }
  575.  
  576.         if (streamInfo.m_pOldestDecompressHandle)
  577.         {
  578.                 FRAME_PROFILER("CGeomCacheManager::AbortStream_AbortDecompress", GetSystem(), PROFILE_3DENGINE);
  579.  
  580.                 assert(streamInfo.m_pOldestDecompressHandle != NULL);
  581.  
  582.                 // Put all handles in the decompress list on the abort list
  583.                 assert(streamInfo.m_pNewestDecompressHandle->m_pNext == NULL);
  584.                 streamInfo.m_pNewestDecompressHandle->m_pNext = streamInfo.m_pDecompressAbortListHead;
  585.                 streamInfo.m_pDecompressAbortListHead = streamInfo.m_pOldestDecompressHandle;
  586.  
  587.                 // Mark read decompress list as empty
  588.                 streamInfo.m_pNewestDecompressHandle = NULL;
  589.                 streamInfo.m_pOldestDecompressHandle = NULL;
  590.         }
  591.  
  592.         assert(streamInfo.m_pOldestDecompressHandle == NULL
  593.                && streamInfo.m_pNewestDecompressHandle == NULL);
  594.  
  595.         streamInfo.m_numFramesMissed = 0;
  596.         streamInfo.m_bAbort = false;
  597.         streamInfo.m_bLooping = false;
  598.         streamInfo.m_abortCS.Unlock();
  599. }
  600.  
  601. void CGeomCacheManager::AbortStreamAndWait(SGeomCacheStreamInfo& streamInfo)
  602. {
  603.         FUNCTION_PROFILER_3DENGINE;
  604.  
  605.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  606.  
  607.         AbortStream(streamInfo);
  608.  
  609.         gEnv->pJobManager->WaitForJob(streamInfo.m_fillRenderNodeJobState);
  610.  
  611.         CryMutex dummyCS;
  612.  
  613.         // Wait for all read requests to finish
  614.         for (SGeomCacheReadRequestHandle* pCurrentAbortedHandle = streamInfo.m_pReadAbortListHead;
  615.              pCurrentAbortedHandle; pCurrentAbortedHandle = static_cast<SGeomCacheReadRequestHandle*>(pCurrentAbortedHandle->m_pNext))
  616.         {
  617.                 CryAutoLock<CryMutex> lock(dummyCS);
  618.                 while (pCurrentAbortedHandle->m_numJobReferences > 0)
  619.                 {
  620.                         pCurrentAbortedHandle->m_jobReferencesCV.Wait(dummyCS);
  621.                 }
  622.  
  623.                 if (pCurrentAbortedHandle->m_pReadStream)
  624.                 {
  625.                         pCurrentAbortedHandle->m_pReadStream->Wait();
  626.                 }
  627.         }
  628.  
  629.         for (SGeomCacheBufferHandle* pCurrentAbortedHandle = streamInfo.m_pDecompressAbortListHead;
  630.              pCurrentAbortedHandle; pCurrentAbortedHandle = pCurrentAbortedHandle->m_pNext)
  631.         {
  632.                 CryAutoLock<CryMutex> lock(dummyCS);
  633.                 while (pCurrentAbortedHandle->m_numJobReferences > 0)
  634.                 {
  635.                         pCurrentAbortedHandle->m_jobReferencesCV.Wait(dummyCS);
  636.                 }
  637.         }
  638.  
  639.         // And finally retire their handles
  640.         RetireAbortedHandles(streamInfo);
  641.  
  642.         assert(streamInfo.m_pReadAbortListHead == NULL);
  643. }
  644.  
  645. void CGeomCacheManager::RetireAbortedHandles(SGeomCacheStreamInfo& streamInfo)
  646. {
  647.         FUNCTION_PROFILER_3DENGINE;
  648.  
  649.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  650.  
  651.         SGeomCacheReadRequestHandle* pNextReadRequestAbortHandle = NULL;
  652.         for (SGeomCacheReadRequestHandle* pCurrentAbortedHandle = streamInfo.m_pReadAbortListHead;
  653.              pCurrentAbortedHandle; pCurrentAbortedHandle = pNextReadRequestAbortHandle)
  654.         {
  655.                 // If jobs are still running, wait till next frame
  656.                 if (pCurrentAbortedHandle->m_numJobReferences > 0 || (pCurrentAbortedHandle->m_pReadStream && !pCurrentAbortedHandle->m_pReadStream->IsFinished()))
  657.                 {
  658.                         break;
  659.                 }
  660.  
  661.                 // Remove from abort list
  662.                 pNextReadRequestAbortHandle = static_cast<SGeomCacheReadRequestHandle*>(pCurrentAbortedHandle->m_pNext);
  663.                 streamInfo.m_pReadAbortListHead = pNextReadRequestAbortHandle;
  664.  
  665.                 // And finally retire handle
  666.                 RetireBufferHandle(pCurrentAbortedHandle);
  667.         }
  668.  
  669.         SGeomCacheBufferHandle* pNextDecompressAbortHandle = NULL;
  670.         for (SGeomCacheBufferHandle* pCurrentAbortedHandle = streamInfo.m_pDecompressAbortListHead;
  671.              pCurrentAbortedHandle; pCurrentAbortedHandle = pNextDecompressAbortHandle)
  672.         {
  673.                 // If jobs are still running, wait till next frame
  674.                 if (pCurrentAbortedHandle->m_numJobReferences > 0)
  675.                 {
  676.                         break;
  677.                 }
  678.  
  679.                 // Remove from abort list
  680.                 pNextDecompressAbortHandle = pCurrentAbortedHandle->m_pNext;
  681.                 streamInfo.m_pDecompressAbortListHead = pNextDecompressAbortHandle;
  682.  
  683.                 // And finally retire handle
  684.                 RetireDecompressHandle(streamInfo, pCurrentAbortedHandle);
  685.         }
  686. }
  687.  
  688. bool CGeomCacheManager::IssueDiskReadRequest(SGeomCacheStreamInfo& streamInfo)
  689. {
  690.         FUNCTION_PROFILER_3DENGINE;
  691.  
  692.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  693.  
  694.         // Constants
  695.         const CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  696.         const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  697.         const bool bIsStreaming = pRenderNode->IsStreaming();
  698.  
  699.         const float currentCacheStreamingTime = streamInfo.m_pRenderNode->GetStreamingTime();
  700.         const uint wantedFloorFrame = pGeomCache->GetFloorFrameIndex(currentCacheStreamingTime);
  701.         const uint wantedCeilFrame = pGeomCache->GetCeilFrameIndex(currentCacheStreamingTime);
  702.         const float minBufferAheadTime = std::max(0.1f, GetCVars()->e_GeomCacheMinBufferAheadTime);
  703.         const float maxBufferAheadTime = std::max(1.0f, GetCVars()->e_GeomCacheMaxBufferAheadTime);
  704.         const float cacheMinBufferAhead = currentCacheStreamingTime + minBufferAheadTime;
  705.         const float cacheMaxBufferAhead = currentCacheStreamingTime + maxBufferAheadTime;
  706.  
  707.         const bool bLooping = streamInfo.m_bLooping;
  708.         const uint numFrames = streamInfo.m_numFrames;
  709.  
  710.         const uint preferredDiskRequestSize = (size_t)std::max(0, GetCVars()->e_GeomCachePreferredDiskRequestSize * 1024);
  711.  
  712.         // Compute frame range that we want to read from disk
  713.         uint frameRangeBegin = pGeomCache->GetPrevIFrame(wantedFloorFrame);
  714.         uint frameRangeEnd = pGeomCache->GetNextIFrame(bIsStreaming ? pGeomCache->GetCeilFrameIndex(cacheMaxBufferAhead) : wantedFloorFrame);
  715.  
  716.         // Avoid reading an entire block if we are not streaming and time is precisely at an index frame.
  717.         // This primarily helps when streaming in the first frame after a render node is created.
  718.         if (!bIsStreaming && (wantedFloorFrame == wantedCeilFrame) &&
  719.             pGeomCache->GetFrameType(wantedFloorFrame) == GeomCacheFile::eFrameType_IFrame)
  720.         {
  721.                 frameRangeBegin = wantedFloorFrame;
  722.                 frameRangeEnd = frameRangeBegin;
  723.         }
  724.  
  725.         // Make sure not to re-request frames that are already in the decode buffer
  726.         if (streamInfo.m_pNewestDecompressHandle)
  727.         {
  728.                 uint decodedFramesEnd = streamInfo.m_pNewestDecompressHandle->m_endFrame;
  729.                 frameRangeBegin = std::max(decodedFramesEnd + 1, frameRangeBegin);
  730.         }
  731.  
  732.         // Read request params and handle to be filled
  733.         StreamReadParams params;
  734.         SGeomCacheReadRequestHandle* pRequestHandle;
  735.  
  736.         {
  737.                 assert(!streamInfo.m_pOldestReadRequestHandle || streamInfo.m_pNewestReadRequestHandle);
  738.                 if (streamInfo.m_pNewestReadRequestHandle)
  739.                 {
  740.                         uint streamEndFrame = streamInfo.m_pNewestReadRequestHandle->m_endFrame;
  741.  
  742.                         // Check if we already requested up to frameRangeEnd
  743.                         if (streamInfo.m_pNewestReadRequestHandle->m_endFrame >= frameRangeEnd)
  744.                         {
  745.                                 return false;
  746.                         }
  747.  
  748.                         frameRangeBegin = streamEndFrame + 1;
  749.                 }
  750.  
  751.                 const float frameRangeBeginTime = pGeomCache->GetFrameTime(frameRangeBegin);
  752.                 if (frameRangeBeginTime > cacheMinBufferAhead)
  753.                 {
  754.                         return false;
  755.                 }
  756.  
  757.                 if (!bLooping && frameRangeEnd >= (numFrames - 1))
  758.                 {
  759.                         frameRangeEnd = numFrames - 1;
  760.                 }
  761.  
  762.                 if (frameRangeBegin > frameRangeEnd)
  763.                 {
  764.                         return false;
  765.                 }
  766.  
  767.                 if ((frameRangeEnd - frameRangeBegin + 1) > numFrames)
  768.                 {
  769.                         frameRangeEnd = frameRangeBegin + numFrames - 1;
  770.                 }
  771.  
  772.                 pGeomCache->ValidateReadRange(frameRangeBegin, frameRangeEnd);
  773.  
  774.                 // Now that we have a final range of unread frames, make a read request
  775.                 uint requestSize = 0;
  776.                 for (uint currentFrame = frameRangeBegin; currentFrame <= frameRangeEnd; ++currentFrame)
  777.                 {
  778.                         requestSize += pGeomCache->GetFrameSize(currentFrame);
  779.  
  780.                         // Stop if size has reached preferred request size and current frame is an index frame
  781.                         if (requestSize >= preferredDiskRequestSize && pGeomCache->GetFrameType(currentFrame) == GeomCacheFile::eFrameType_IFrame && frameRangeBegin != currentFrame)
  782.                         {
  783.                                 frameRangeEnd = currentFrame;
  784.                                 break;
  785.                         }
  786.                 }
  787.  
  788.                 assert(requestSize > 0);
  789.  
  790.                 // Allocate new request handle & buffer space
  791.                 pRequestHandle = NewReadRequestHandle(requestSize, streamInfo);
  792.                 if (!pRequestHandle)
  793.                 {
  794.                         return false;
  795.                 }
  796.  
  797.                 // Init handle
  798.                 pRequestHandle->m_startFrame = frameRangeBegin;
  799.                 pRequestHandle->m_endFrame = frameRangeEnd;
  800.  
  801.                 // Add request handle to stream linked list
  802.                 if (streamInfo.m_pNewestReadRequestHandle)
  803.                 {
  804.                         streamInfo.m_pNewestReadRequestHandle->m_pNext = pRequestHandle;
  805.                         streamInfo.m_pNewestReadRequestHandle = pRequestHandle;
  806.                 }
  807.                 else
  808.                 {
  809.                         streamInfo.m_pOldestReadRequestHandle = pRequestHandle;
  810.                         streamInfo.m_pNewestReadRequestHandle = pRequestHandle;
  811.                 }
  812.  
  813.                 const float timeLeft = std::max(pGeomCache->GetFrameTime(frameRangeBegin) - currentCacheStreamingTime
  814.                                                 - static_cast<float>(GetCVars()->e_GeomCacheDecodeAheadTime), 0.0f);
  815.  
  816.                 // Fill read request params
  817.                 params.nOffset = static_cast<uint>(pGeomCache->GetFrameOffset(frameRangeBegin));
  818.                 params.nSize = requestSize;
  819.                 params.pBuffer = pRequestHandle->m_pBuffer;
  820.                 params.ePriority = estpAboveNormal;
  821.                 params.nLoadTime = static_cast<uint>(timeLeft * 1000);
  822.                 params.nPerceptualImportance = 255;
  823.                 params.nFlags = IStreamEngine::FLAGS_NO_SYNC_CALLBACK;
  824.         }
  825.  
  826.         // Issue request
  827.         CryInterlockedIncrement(&pRequestHandle->m_numJobReferences);
  828.         pRequestHandle->m_pReadStream = GetSystem()->GetStreamEngine()->StartRead(
  829.           eStreamTaskTypeGeomCache, pGeomCache->GetFilePath(), pRequestHandle, &params);
  830.  
  831.         // This can happen if streaming system is already shutting down. There will be no callback in this case, so decrement m_numJobReferences.
  832.         if (pRequestHandle->m_pReadStream == NULL)
  833.         {
  834.                 if (CryInterlockedDecrement(&pRequestHandle->m_numJobReferences) == 0)
  835.                 {
  836.                         pRequestHandle->m_jobReferencesCV.Notify();
  837.                 }
  838.         }
  839.  
  840.         return true;
  841. }
  842.  
  843. void CGeomCacheManager::LaunchDecompressJobs(SGeomCacheStreamInfo* pStreamInfo, const CTimeValue currentFrameTime)
  844. {
  845.         FUNCTION_PROFILER_3DENGINE;
  846.  
  847.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  848.  
  849.         const CGeomCacheRenderNode* pRenderNode = pStreamInfo->m_pRenderNode;
  850.         const CGeomCache* pGeomCache = pStreamInfo->m_pGeomCache;
  851.         const GeomCacheFile::EBlockCompressionFormat blockCompressionFormat = pGeomCache->GetBlockCompressionFormat();
  852.         const float currentCacheStreamingTime = pStreamInfo->m_pRenderNode->GetStreamingTime();
  853.         const uint wantedFloorFrame = pGeomCache->GetFloorFrameIndex(currentCacheStreamingTime);
  854.         const uint numStreamFrames = pStreamInfo->m_numFrames;
  855.         const uint frameDataSize = pStreamInfo->m_frameData.size();
  856.  
  857.         // Need to check if there are still jobs running for the same render node on the stream abort list
  858.         for (TStreamInfosIter iter = m_streamInfosAbortList.begin(); iter != m_streamInfosAbortList.end(); ++iter)
  859.         {
  860.                 SGeomCacheStreamInfo* pCurrentStreamInfo = *iter;
  861.                 if (pStreamInfo->m_pRenderNode == pCurrentStreamInfo->m_pRenderNode)
  862.                 {
  863.                         return;
  864.                 }
  865.         }
  866.  
  867.         // Wait until abort list has been processed before spawning new jobs
  868.         if (pStreamInfo->m_pDecompressAbortListHead || pStreamInfo->m_pReadAbortListHead)
  869.         {
  870.                 return;
  871.         }
  872.  
  873.         for (SGeomCacheReadRequestHandle* pReadRequestHandle = pStreamInfo->m_pOldestReadRequestHandle; pReadRequestHandle;
  874.              pReadRequestHandle = static_cast<SGeomCacheReadRequestHandle*>(pReadRequestHandle->m_pNext))
  875.         {
  876.                 if (pReadRequestHandle->m_frameTime == currentFrameTime)
  877.                 {
  878.                         // Don't decode frames that were read in the same render frame
  879.                         return;
  880.                 }
  881.  
  882.                 if (pStreamInfo->m_bAbort)
  883.                 {
  884.                         return;
  885.                 }
  886.  
  887.                 if (pReadRequestHandle->m_error)
  888.                 {
  889.                         return;
  890.                 }
  891.  
  892.                 if (pReadRequestHandle->m_state != SGeomCacheReadRequestHandle::eRRHS_FinishedRead)
  893.                 {
  894.                         return;
  895.                 }
  896.  
  897.                 // Stop decoding after e_GeomCacheDecodeAheadTime
  898.                 const float blockDeltaFromPlaybackTime = (pGeomCache->GetFrameTime(pReadRequestHandle->m_startFrame) - currentCacheStreamingTime);
  899.                 const float decodeAheadTime = GetCVars()->e_GeomCacheDecodeAheadTime;
  900.                 if (blockDeltaFromPlaybackTime > decodeAheadTime)
  901.                 {
  902.                         return;
  903.                 }
  904.  
  905.                 const uint startFrame = pReadRequestHandle->m_startFrame;
  906.                 const uint endFrame = pReadRequestHandle->m_endFrame;
  907.  
  908.                 // Need to check if stream is already referencing same frames when looping
  909.                 if (pStreamInfo->m_pOldestDecompressHandle && pStreamInfo->m_bLooping)
  910.                 {
  911.                         const uint checkRangeStart = pStreamInfo->m_pOldestDecompressHandle->m_startFrame;
  912.                         const uint checkRangeEnd = pStreamInfo->m_pNewestDecompressHandle->m_endFrame;
  913.  
  914.                         const uint startRangeMod = checkRangeStart % frameDataSize;
  915.                         const uint endRangeMod = checkRangeEnd % frameDataSize;
  916.                         const uint startFrameMod = startFrame % frameDataSize;
  917.                         // Check range must be extended to next index frame because retiring of stream begin could otherwise overwrite frame data
  918.                         const uint endFrameMod = pGeomCache->GetNextIFrame(endFrame) % frameDataSize;
  919.  
  920.                         const bool bRangeWraps = endRangeMod < startRangeMod;
  921.                         const bool bFramesWrap = endFrameMod < startFrameMod;
  922.  
  923.                         // check all four different cases for range overlapping
  924.                         if ((bRangeWraps && bFramesWrap)
  925.                             || (bRangeWraps && !bFramesWrap && (startFrameMod <= endRangeMod || endFrameMod >= startRangeMod))
  926.                             || (!bRangeWraps && bFramesWrap && (startRangeMod <= endFrameMod || endRangeMod >= startFrameMod))
  927.                             || (!bRangeWraps && !bFramesWrap && (startFrameMod <= endRangeMod && startRangeMod <= endFrameMod)))
  928.                         {
  929.                                 return;
  930.                         }
  931.                 }
  932.  
  933.                 // Determine size for decompression buffer
  934.                 const uint numFrames = (endFrame - startFrame) + 1;
  935.                 const uint32 decompressBlockSize = GeomCacheDecoder::GetDecompressBufferSize(pReadRequestHandle->m_pBuffer, numFrames);
  936.  
  937.                 SGeomCacheBufferHandle* pNewDecompressBufferHandle = NewBufferHandle<SGeomCacheBufferHandle>(decompressBlockSize, *pStreamInfo);
  938.                 if (!pNewDecompressBufferHandle)
  939.                 {
  940.                         // Could not allocate space for decompression
  941.                         return;
  942.                 }
  943.  
  944.                 // Zero frame headers
  945.                 memset(pNewDecompressBufferHandle->m_pBuffer, 0, sizeof(SGeomCacheFrameHeader) * numFrames);
  946.  
  947.                 pReadRequestHandle->m_state = SGeomCacheReadRequestHandle::eRRHS_Decompressing;
  948.                 pNewDecompressBufferHandle->m_startFrame = startFrame;
  949.                 pNewDecompressBufferHandle->m_endFrame = endFrame;
  950.  
  951.                 for (uint i = startFrame; i <= endFrame; ++i)
  952.                 {
  953.                         const uint frameIndex = i % frameDataSize;
  954.                         assert(!pStreamInfo->m_frameData[frameIndex].m_pDecompressHandle);
  955.                         pStreamInfo->m_frameData[frameIndex].m_pDecompressHandle = pNewDecompressBufferHandle;
  956.                 }
  957.  
  958.                 // Add to decompress request handle linked list
  959.                 {
  960.                         assert(!pStreamInfo->m_pOldestDecompressHandle || pStreamInfo->m_pNewestDecompressHandle);
  961.  
  962.                         // Add request handle to stream linked list
  963.                         if (pStreamInfo->m_pNewestDecompressHandle)
  964.                         {
  965.                                 pStreamInfo->m_pNewestDecompressHandle->m_pNext = pNewDecompressBufferHandle;
  966.                                 pStreamInfo->m_pNewestDecompressHandle = pNewDecompressBufferHandle;
  967.                         }
  968.                         else
  969.                         {
  970.                                 pStreamInfo->m_pOldestDecompressHandle = pNewDecompressBufferHandle;
  971.                                 pStreamInfo->m_pNewestDecompressHandle = pNewDecompressBufferHandle;
  972.                         }
  973.                 }
  974.  
  975.                 for (uint i = 0; i < numFrames; ++i)
  976.                 {
  977.                         const uint frameIndex = startFrame + i;
  978.  
  979.                         // For b frames we need to make sure that jobs for previous frames were launched. Otherwise m_numJobReferences will
  980.                         // never reach zero, because the frame decode job has a dependency job that was never launched.
  981.                         if (pGeomCache->GetFrameType(frameIndex) == GeomCacheFile::eFrameType_IFrame
  982.                             || pStreamInfo->m_frameData[(frameIndex - 1) % frameDataSize].m_bDecompressJobLaunched)
  983.                         {
  984.                                 CryInterlockedIncrement(&pReadRequestHandle->m_numJobReferences);
  985.                                 CryInterlockedIncrement(&pNewDecompressBufferHandle->m_numJobReferences);
  986.                                 CryInterlockedIncrement(&pNewDecompressBufferHandle->m_numJobReferences);
  987.  
  988.                                 pStreamInfo->m_frameData[frameIndex % frameDataSize].m_bDecompressJobLaunched = true;
  989.                                 TGeomCacheDecompressJob decompressJob(pStreamInfo, i, pNewDecompressBufferHandle, pReadRequestHandle);
  990.                                 decompressJob.SetClassInstance(this);
  991.                                 decompressJob.SetPriorityLevel(JobManager::eStreamPriority);
  992.                                 decompressJob.Run();
  993.                         }
  994.                 }
  995.         }
  996. }
  997.  
  998. void CGeomCacheManager::DecompressFrame_JobEntry(SGeomCacheStreamInfo* pStreamInfo, const uint blockIndex,
  999.                                                  SGeomCacheBufferHandle* pDecompressHandle, SGeomCacheReadRequestHandle* pReadRequestHandle)
  1000. {
  1001.         FUNCTION_PROFILER_3DENGINE;
  1002.  
  1003.         const CGeomCacheRenderNode* pRenderNode = pStreamInfo->m_pRenderNode;
  1004.         const CGeomCache* pGeomCache = pStreamInfo->m_pGeomCache;
  1005.         const uint frameIndex = pDecompressHandle->m_startFrame + blockIndex;
  1006.  
  1007.         if (!pStreamInfo->m_bAbort && !pStreamInfo->m_pDecompressAbortListHead)
  1008.         {
  1009.                 const GeomCacheFile::EBlockCompressionFormat blockCompressionFormat = pGeomCache->GetBlockCompressionFormat();
  1010.                 const uint numFrames = pReadRequestHandle->m_endFrame - pReadRequestHandle->m_startFrame + 1;
  1011.  
  1012.                 SGeomCacheFrameHeader* pHeader = GetFrameDecompressHeader(pStreamInfo, frameIndex);
  1013.                 if (!pHeader || pHeader->m_state != SGeomCacheFrameHeader::eFHS_Uninitialized)
  1014.                 {
  1015.                         CryFatalError("Trying to access uninitialized data while decoding an index frame");
  1016.                 }
  1017.  
  1018.                 if (!GeomCacheDecoder::DecompressBlocks(blockCompressionFormat, pDecompressHandle->m_pBuffer,
  1019.                                                         pReadRequestHandle->m_pBuffer, blockIndex, 1, numFrames))
  1020.                 {
  1021.                         // Decompress block size failed: Flag error
  1022.                         pReadRequestHandle->m_error = 1;
  1023.                 }
  1024.         }
  1025.  
  1026.         if (CryInterlockedDecrement(&pReadRequestHandle->m_numJobReferences) == 0)
  1027.         {
  1028.                 pReadRequestHandle->m_state = SGeomCacheReadRequestHandle::eRRHS_Done;
  1029.                 pReadRequestHandle->m_jobReferencesCV.Notify();
  1030.         }
  1031.  
  1032.         if (CryInterlockedDecrement(&pDecompressHandle->m_numJobReferences) == 0)
  1033.         {
  1034.                 pDecompressHandle->m_jobReferencesCV.Notify();
  1035.         }
  1036.  
  1037.         const int newDependencyCounter = CryInterlockedDecrement(GetDependencyCounter(pStreamInfo, frameIndex));
  1038.  
  1039.         if (newDependencyCounter < 0 || newDependencyCounter > 2)
  1040.         {
  1041.                 CryFatalError("Invalid dependency counter");
  1042.         }
  1043.         else if (newDependencyCounter == 0)
  1044.         {
  1045.                 SDecodeFrameJobData jobData;
  1046.                 jobData.m_frameIndex = frameIndex;
  1047.                 jobData.m_pGeomCache = pGeomCache;
  1048.                 jobData.m_pStreamInfo = pStreamInfo;
  1049.                 LaunchDecodeJob(jobData);
  1050.         }
  1051. }
  1052.  
  1053. void CGeomCacheManager::LaunchDecodeJob(SDecodeFrameJobData jobData)
  1054. {
  1055.         const GeomCacheFile::EFrameType frameType = jobData.m_pGeomCache->GetFrameType(jobData.m_frameIndex);
  1056.  
  1057.         switch (frameType)
  1058.         {
  1059.         case GeomCacheFile::eFrameType_IFrame:
  1060.                 {
  1061.                         TGeomCacheIFrameDecodeJob decodeJob(jobData);
  1062.                         decodeJob.SetClassInstance(this);
  1063.                         decodeJob.SetPriorityLevel(JobManager::eStreamPriority);
  1064.                         decodeJob.Run();
  1065.                         break;
  1066.                 }
  1067.         case GeomCacheFile::eFrameType_BFrame:
  1068.                 {
  1069.                         TGeomCacheBFrameDecodeJob decodeJob(jobData);
  1070.                         decodeJob.SetClassInstance(this);
  1071.                         decodeJob.SetPriorityLevel(JobManager::eStreamPriority);
  1072.                         decodeJob.Run();
  1073.                         break;
  1074.                 }
  1075.         }
  1076. }
  1077.  
  1078. void CGeomCacheManager::DecodeIFrame_JobEntry(SDecodeFrameJobData jobData)
  1079. {
  1080.         FUNCTION_PROFILER_3DENGINE;
  1081.  
  1082.         if (!jobData.m_pStreamInfo->m_bAbort && !jobData.m_pStreamInfo->m_pDecompressAbortListHead)
  1083.         {
  1084.                 char* pFrameData = GetFrameDecompressData(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1085.                 GeomCacheDecoder::DecodeIFrame(jobData.m_pGeomCache, pFrameData);
  1086.  
  1087.                 SGeomCacheFrameHeader* pHeader = GetFrameDecompressHeader(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1088.  
  1089.                 if (pHeader->m_state != SGeomCacheFrameHeader::eFHS_Undecoded)
  1090.                 {
  1091.                         CryFatalError("Trying to access uninitialized data while decoding an index frame");
  1092.                 }
  1093.  
  1094.                 pHeader->m_state = SGeomCacheFrameHeader::eFHS_Decoded;
  1095.         }
  1096.  
  1097.         SGeomCacheBufferHandle* pHandle = GetFrameDecompressHandle(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1098.         if (CryInterlockedDecrement(&pHandle->m_numJobReferences) == 0)
  1099.         {
  1100.                 pHandle->m_jobReferencesCV.Notify();
  1101.         }
  1102.  
  1103.         // Decrement dependency counter of first b frame after previous index frame and launch job if ready
  1104.         const uint prevIFrame = jobData.m_pGeomCache->GetPrevIFrame(jobData.m_frameIndex);
  1105.         if (prevIFrame < jobData.m_frameIndex)
  1106.         {
  1107.                 const uint bFrameIndex = prevIFrame + 1;
  1108.                 if (jobData.m_pGeomCache->GetFrameType(bFrameIndex) == GeomCacheFile::eFrameType_BFrame)
  1109.                 {
  1110.                         const int newDependencyCounter = CryInterlockedDecrement(GetDependencyCounter(jobData.m_pStreamInfo, bFrameIndex));
  1111.  
  1112.                         if (newDependencyCounter < 0 || newDependencyCounter > 2)
  1113.                         {
  1114.                                 CryFatalError("Invalid dependency counter");
  1115.                         }
  1116.                         else if (newDependencyCounter == 0)
  1117.                         {
  1118.                                 SDecodeFrameJobData bFrameJobState = jobData;
  1119.                                 bFrameJobState.m_frameIndex = bFrameIndex;
  1120.                                 LaunchDecodeJob(bFrameJobState);
  1121.                         }
  1122.                 }
  1123.         }
  1124.  
  1125.         // Decrement dependency counter of b frame right after index frame and launch job if ready
  1126.         const uint numFrames = jobData.m_pStreamInfo->m_numFrames;
  1127.         if ((jobData.m_frameIndex % numFrames) + 1 < numFrames)
  1128.         {
  1129.                 const uint bFrameIndex = jobData.m_frameIndex + 1;
  1130.                 if (jobData.m_pGeomCache->GetFrameType(bFrameIndex) == GeomCacheFile::eFrameType_BFrame)
  1131.                 {
  1132.                         const int newDependencyCounter = CryInterlockedDecrement(GetDependencyCounter(jobData.m_pStreamInfo, bFrameIndex));
  1133.  
  1134.                         if (newDependencyCounter < 0 || newDependencyCounter > 2)
  1135.                         {
  1136.                                 CryFatalError("Invalid dependency counter");
  1137.                         }
  1138.                         else if (newDependencyCounter == 0)
  1139.                         {
  1140.                                 SDecodeFrameJobData bFrameJobState = jobData;
  1141.                                 bFrameJobState.m_frameIndex = bFrameIndex;
  1142.                                 LaunchDecodeJob(bFrameJobState);
  1143.                         }
  1144.                 }
  1145.         }
  1146. }
  1147.  
  1148. void CGeomCacheManager::DecodeBFrame_JobEntry(SDecodeFrameJobData jobData)
  1149. {
  1150.         FUNCTION_PROFILER_3DENGINE;
  1151.  
  1152.         const uint prevIFrame = jobData.m_pGeomCache->GetPrevIFrame(jobData.m_frameIndex);
  1153.         const uint nextIFrame = jobData.m_pGeomCache->GetNextIFrame(jobData.m_frameIndex);
  1154.  
  1155.         if (!jobData.m_pStreamInfo->m_bAbort && !jobData.m_pStreamInfo->m_pDecompressAbortListHead)
  1156.         {
  1157.                 char* pFrameData = GetFrameDecompressData(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1158.  
  1159.                 // For frames that have 0 influence for motion the predictor will still read data
  1160.                 // from the prev frame pointers, so just set it to the current frame's data.
  1161.                 char* pPrevFramesData[2] = { pFrameData, pFrameData };
  1162.                 if (jobData.m_pGeomCache->NeedsPrevFrames(jobData.m_frameIndex))
  1163.                 {
  1164.                         pPrevFramesData[0] = GetFrameDecompressData(jobData.m_pStreamInfo, jobData.m_frameIndex - 2);
  1165.                         pPrevFramesData[1] = GetFrameDecompressData(jobData.m_pStreamInfo, jobData.m_frameIndex - 1);
  1166.                 }
  1167.  
  1168.                 SGeomCacheFrameHeader* pPrevIFrameHeader = GetFrameDecompressHeader(jobData.m_pStreamInfo, prevIFrame);
  1169.                 SGeomCacheFrameHeader* pNextIFrameHeader = GetFrameDecompressHeader(jobData.m_pStreamInfo, nextIFrame);
  1170.  
  1171.                 if (pPrevIFrameHeader->m_state != SGeomCacheFrameHeader::eFHS_Decoded
  1172.                     || pNextIFrameHeader->m_state != SGeomCacheFrameHeader::eFHS_Decoded)
  1173.                 {
  1174.                         CryFatalError("Trying to access invalid data while decoding a b frame");
  1175.                 }
  1176.  
  1177.                 char* pFloorIndexFrameData = GetFrameDecompressData(jobData.m_pStreamInfo, prevIFrame);
  1178.                 char* pCeilIndexFrameData = GetFrameDecompressData(jobData.m_pStreamInfo, nextIFrame);
  1179.  
  1180.                 GeomCacheDecoder::DecodeBFrame(jobData.m_pGeomCache, pFrameData, pPrevFramesData, pFloorIndexFrameData, pCeilIndexFrameData);
  1181.  
  1182.                 SGeomCacheFrameHeader* pHeader = GetFrameDecompressHeader(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1183.  
  1184.                 if (pHeader->m_state != SGeomCacheFrameHeader::eFHS_Undecoded)
  1185.                 {
  1186.                         CryFatalError("Trying to access invalid data while decoding a b frame");
  1187.                 }
  1188.  
  1189.                 pHeader->m_state = SGeomCacheFrameHeader::eFHS_Decoded;
  1190.         }
  1191.  
  1192.         SGeomCacheBufferHandle* pHandle = GetFrameDecompressHandle(jobData.m_pStreamInfo, jobData.m_frameIndex);
  1193.         if (CryInterlockedDecrement(&pHandle->m_numJobReferences) == 0)
  1194.         {
  1195.                 pHandle->m_jobReferencesCV.Notify();
  1196.         }
  1197.  
  1198.         // Decrement dependency counter of b frame right after frame and launch job if ready
  1199.         const uint numFrames = jobData.m_pStreamInfo->m_numFrames;
  1200.         if ((jobData.m_frameIndex % numFrames) + 1 < numFrames)
  1201.         {
  1202.                 const uint bFrameIndex = jobData.m_frameIndex + 1;
  1203.                 if (jobData.m_pGeomCache->GetFrameType(bFrameIndex) == GeomCacheFile::eFrameType_BFrame)
  1204.                 {
  1205.                         const int newDependencyCounter = CryInterlockedDecrement(GetDependencyCounter(jobData.m_pStreamInfo, bFrameIndex));
  1206.  
  1207.                         if (newDependencyCounter < 0 || newDependencyCounter > 2)
  1208.                         {
  1209.                                 CryFatalError("Invalid dependency counter");
  1210.                         }
  1211.                         else if (newDependencyCounter == 0)
  1212.                         {
  1213.                                 SDecodeFrameJobData bFrameJobState = jobData;
  1214.                                 bFrameJobState.m_frameIndex = bFrameIndex;
  1215.                                 LaunchDecodeJob(bFrameJobState);
  1216.                         }
  1217.                 }
  1218.         }
  1219. }
  1220.  
  1221. void CGeomCacheManager::FillRenderNodeAsync_JobEntry(SGeomCacheStreamInfo* pStreamInfo)
  1222. {
  1223.         FUNCTION_PROFILER_3DENGINE;
  1224.  
  1225.         // Prevent the stream from aborting while filling the render buffer
  1226.         CryAutoLock<CryCriticalSection> abortLock(pStreamInfo->m_abortCS);
  1227.  
  1228.         CGeomCacheRenderNode* pRenderNode = pStreamInfo->m_pRenderNode;
  1229.         const CGeomCache* pGeomCache = pStreamInfo->m_pGeomCache;
  1230.  
  1231.         if (pStreamInfo->m_bAbort || pStreamInfo->m_pDecompressAbortListHead)
  1232.         {
  1233.                 // End job if abort flag was raised
  1234.                 pRenderNode->SkipFrameFill();
  1235.                 return;
  1236.         }
  1237.  
  1238.         const uint floorPlaybackFrame = pStreamInfo->m_wantedFloorFrame;
  1239.         const uint ceilPlaybackFrame = pStreamInfo->m_wantedCeilFrame;
  1240.         bool bFrameFilled = false;
  1241.  
  1242.         const char* pFloorFrameData = NULL;
  1243.         const char* pCeilFrameData = NULL;
  1244.  
  1245.         if (!pGeomCache->PlaybackFromMemory())
  1246.         {
  1247.                 SGeomCacheFrameHeader* pFloorHeader = GetFrameDecompressHeader(pStreamInfo, floorPlaybackFrame);
  1248.                 SGeomCacheFrameHeader* pCeilHeader = GetFrameDecompressHeader(pStreamInfo, ceilPlaybackFrame);
  1249.  
  1250.                 if (pFloorHeader && pFloorHeader->m_state == SGeomCacheFrameHeader::eFHS_Decoded && pCeilHeader && pCeilHeader->m_state == SGeomCacheFrameHeader::eFHS_Decoded)
  1251.                 {
  1252.                         pFloorFrameData = GetFrameDecompressData(pStreamInfo, floorPlaybackFrame);
  1253.                         pCeilFrameData = GetFrameDecompressData(pStreamInfo, ceilPlaybackFrame);
  1254.                 }
  1255.         }
  1256.         else
  1257.         {
  1258.                 pFloorFrameData = pGeomCache->GetFrameData(floorPlaybackFrame % pGeomCache->GetNumFrames());
  1259.                 pCeilFrameData = pGeomCache->GetFrameData(ceilPlaybackFrame % pGeomCache->GetNumFrames());
  1260.         }
  1261.  
  1262.         if (pFloorFrameData && pCeilFrameData)
  1263.         {
  1264.                 const float floorFrameTime = pGeomCache->GetFrameTime(floorPlaybackFrame);
  1265.                 const float ceilFrameTime = pGeomCache->GetFrameTime(ceilPlaybackFrame);
  1266.                 const float wantedPlaybackTime = pStreamInfo->m_wantedPlaybackTime;
  1267.  
  1268.                 assert(wantedPlaybackTime >= floorFrameTime && wantedPlaybackTime <= ceilFrameTime);
  1269.  
  1270.                 float lerpFactor = 0.0f;
  1271.                 if (ceilFrameTime != floorFrameTime)
  1272.                 {
  1273.                         lerpFactor = (wantedPlaybackTime - floorFrameTime) / (ceilFrameTime - floorFrameTime);
  1274.                 }
  1275.  
  1276.                 assert(lerpFactor >= 0.0f && lerpFactor <= 1.0f);
  1277.  
  1278.                 // m_displayedFrameTime == -1.0f means uninitialized cache. Treat as same frame, because we only want to fill twice on load.
  1279.                 const bool bSameFrame = (pStreamInfo->m_displayedFrameTime == pStreamInfo->m_wantedPlaybackTime) || (pStreamInfo->m_displayedFrameTime == -1.0f);
  1280.  
  1281.                 if (bSameFrame)
  1282.                 {
  1283.                         CryInterlockedIncrement(&pStreamInfo->m_sameFrameFillCount);
  1284.                 }
  1285.                 else
  1286.                 {
  1287.                         pStreamInfo->m_sameFrameFillCount = 0;
  1288.                 }
  1289.  
  1290.                 if (!pRenderNode->FillFrameAsync(pFloorFrameData, pCeilFrameData, lerpFactor))
  1291.                         pRenderNode->SkipFrameFill();
  1292.  
  1293.                 pStreamInfo->m_displayedFrameTime = pStreamInfo->m_wantedPlaybackTime;
  1294.                 bFrameFilled = true;
  1295.         }
  1296.         else
  1297.         {
  1298.                 pRenderNode->SkipFrameFill();
  1299.         }
  1300.  
  1301.         if (!bFrameFilled && pRenderNode->IsStreaming())
  1302.         {
  1303.                 // If this happens, then we don't have the necessary data in the decompression
  1304.                 // buffer and the geom cache render node wasn't updated
  1305.                 ++pStreamInfo->m_numFramesMissed;
  1306.                 ++m_numMissedFrames;
  1307.         }
  1308. }
  1309.  
  1310. template<class TBufferHandleType> TBufferHandleType* CGeomCacheManager::NewBufferHandle(const uint32 size, SGeomCacheStreamInfo& streamInfo)
  1311. {
  1312.         if (gEnv->mMainThreadId != CryGetCurrentThreadId())
  1313.         {
  1314.                 CryFatalError("CGeomCacheManager::NewBufferHandle must be called from main thread");
  1315.         }
  1316.  
  1317.         char* pBlock = NULL;
  1318.  
  1319.         size_t pointerSize = (sizeof(SGeomCacheBufferHandle*) + 15) & ~15;
  1320.  
  1321.         #if !defined(DEDICATED_SERVER)
  1322.         // Try to allocate requested size in the buffer, otherwise return NULL
  1323.         {
  1324.                 FRAME_PROFILER("CGeomCacheManager::NewBufferHandle_Malloc", GetSystem(), PROFILE_3DENGINE);
  1325.                 pBlock = reinterpret_cast<char*>(m_pPool->Memalign(16, pointerSize + size, "geom cache block"));
  1326.         }
  1327.         #endif
  1328.  
  1329.         if (!pBlock)
  1330.         {
  1331.                 ++m_numFailedAllocs;
  1332.                 return NULL;
  1333.         }
  1334.  
  1335.         // Remove from free list
  1336.         TBufferHandleType* pNewRequest = new TBufferHandleType();
  1337.  
  1338.         // Initialize and return request handle
  1339.         *alias_cast<TBufferHandleType**>(pBlock) = pNewRequest;
  1340.         pNewRequest->m_pBuffer = pBlock + pointerSize;
  1341.         pNewRequest->m_bufferSize = size;
  1342.         pNewRequest->m_frameTime = GetTimer()->GetFrameStartTime();
  1343.         pNewRequest->m_pStream = &streamInfo;
  1344.  
  1345.         return pNewRequest;
  1346. }
  1347.  
  1348. SGeomCacheReadRequestHandle* CGeomCacheManager::NewReadRequestHandle(const uint32 size, SGeomCacheStreamInfo& streamInfo)
  1349. {
  1350.         FUNCTION_PROFILER_3DENGINE;
  1351.  
  1352.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  1353.  
  1354.         SGeomCacheBufferHandle* pNewHandle = NewBufferHandle<SGeomCacheReadRequestHandle>(size, streamInfo);
  1355.         SGeomCacheReadRequestHandle* pReadRequestHandle = static_cast<SGeomCacheReadRequestHandle*>(pNewHandle);
  1356.  
  1357.         if (pReadRequestHandle)
  1358.         {
  1359.                 pReadRequestHandle->m_state = SGeomCacheReadRequestHandle::eRRHS_Reading;
  1360.                 pReadRequestHandle->m_error = 0L;
  1361.                 pReadRequestHandle->m_pReadStream = NULL;
  1362.         }
  1363.  
  1364.         return pReadRequestHandle;
  1365. }
  1366.  
  1367. void CGeomCacheManager::RetireHandles(SGeomCacheStreamInfo& streamInfo)
  1368. {
  1369.         FUNCTION_PROFILER_3DENGINE;
  1370.  
  1371.         CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  1372.         const CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  1373.         const float currentCacheStreamingTime = streamInfo.m_pRenderNode->GetStreamingTime();
  1374.         const uint wantedFloorFrame = pGeomCache->GetFloorFrameIndex(currentCacheStreamingTime);
  1375.  
  1376.         SGeomCacheBufferHandle* pNextReadRequestHandle = streamInfo.m_pOldestReadRequestHandle;
  1377.         while (pNextReadRequestHandle)
  1378.         {
  1379.                 SGeomCacheReadRequestHandle* pCurrentReadRequestHandle = static_cast<SGeomCacheReadRequestHandle*>(pNextReadRequestHandle);
  1380.                 pNextReadRequestHandle = pCurrentReadRequestHandle->m_pNext;
  1381.  
  1382.                 const uint handleEndFrame = pCurrentReadRequestHandle->m_endFrame;
  1383.  
  1384.                 if (pCurrentReadRequestHandle->m_numJobReferences == 0 &&
  1385.                     ((handleEndFrame + 2) < wantedFloorFrame || pCurrentReadRequestHandle->m_state == SGeomCacheReadRequestHandle::eRRHS_Done))
  1386.                 {
  1387.                         RetireOldestReadRequestHandle(streamInfo);
  1388.                 }
  1389.                 else
  1390.                 {
  1391.                         break;
  1392.                 }
  1393.         }
  1394.  
  1395.         SGeomCacheBufferHandle* pNextDecompressHandle = streamInfo.m_pOldestDecompressHandle;
  1396.         while (pNextDecompressHandle)
  1397.         {
  1398.                 SGeomCacheBufferHandle* pCurrentDecompressHandle = pNextDecompressHandle;
  1399.                 pNextDecompressHandle = pCurrentDecompressHandle->m_pNext;
  1400.  
  1401.                 const uint handleEndFrame = pCurrentDecompressHandle->m_endFrame;
  1402.  
  1403.                 // We also wait for the jobs of the next frame because of b frame -> index frame back references
  1404.                 if (((handleEndFrame + 2) < wantedFloorFrame) && (pCurrentDecompressHandle->m_numJobReferences == 0)
  1405.                     && !(pCurrentDecompressHandle->m_pNext && pCurrentDecompressHandle->m_pNext->m_numJobReferences > 0))
  1406.                 {
  1407.                         RetireOldestDecompressHandle(streamInfo);
  1408.                 }
  1409.                 else
  1410.                 {
  1411.                         break;
  1412.                 }
  1413.         }
  1414. }
  1415.  
  1416. void CGeomCacheManager::RetireOldestReadRequestHandle(SGeomCacheStreamInfo& streamInfo)
  1417. {
  1418.         FUNCTION_PROFILER_3DENGINE;
  1419.  
  1420.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  1421.  
  1422.         SGeomCacheReadRequestHandle* pOldestHandle;
  1423.  
  1424.         pOldestHandle = streamInfo.m_pOldestReadRequestHandle;
  1425.  
  1426.         if (pOldestHandle == streamInfo.m_pNewestReadRequestHandle)
  1427.         {
  1428.                 assert(pOldestHandle->m_pNext == NULL);
  1429.                 streamInfo.m_pOldestReadRequestHandle = NULL;
  1430.                 streamInfo.m_pNewestReadRequestHandle = NULL;
  1431.         }
  1432.         else
  1433.         {
  1434.                 streamInfo.m_pOldestReadRequestHandle = static_cast<SGeomCacheReadRequestHandle*>(pOldestHandle->m_pNext);
  1435.         }
  1436.  
  1437.         assert(pOldestHandle);
  1438.         if (pOldestHandle)
  1439.         {
  1440.                 if (pOldestHandle->m_numJobReferences > 0)
  1441.                 {
  1442.                         CryFatalError("Trying to retire handle with non zero job count");
  1443.                 }
  1444.  
  1445.                 RetireBufferHandle(pOldestHandle);
  1446.         }
  1447. }
  1448.  
  1449. void CGeomCacheManager::RetireOldestDecompressHandle(SGeomCacheStreamInfo& streamInfo)
  1450. {
  1451.         FUNCTION_PROFILER_3DENGINE;
  1452.  
  1453.         SGeomCacheBufferHandle* pOldestHandle = NULL;
  1454.  
  1455.         // Unlink from stream linked list
  1456.         {
  1457.                 pOldestHandle = streamInfo.m_pOldestDecompressHandle;
  1458.  
  1459.                 assert(pOldestHandle);
  1460.                 if (!pOldestHandle)
  1461.                 {
  1462.                         return;
  1463.                 }
  1464.  
  1465.                 if (pOldestHandle == streamInfo.m_pNewestDecompressHandle)
  1466.                 {
  1467.                         assert(pOldestHandle->m_pNext == NULL);
  1468.                         streamInfo.m_pOldestDecompressHandle = NULL;
  1469.                         streamInfo.m_pNewestDecompressHandle = NULL;
  1470.                 }
  1471.                 else
  1472.                 {
  1473.                         streamInfo.m_pOldestDecompressHandle = pOldestHandle->m_pNext;
  1474.                 }
  1475.         }
  1476.  
  1477.         if (pOldestHandle)
  1478.         {
  1479.                 RetireDecompressHandle(streamInfo, pOldestHandle);
  1480.         }
  1481. }
  1482.  
  1483. void CGeomCacheManager::RetireDecompressHandle(SGeomCacheStreamInfo& streamInfo, SGeomCacheBufferHandle* pHandle)
  1484. {
  1485.         CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  1486.  
  1487.         const uint frameDataSize = streamInfo.m_frameData.size();
  1488.         uint reinitializeStart = pGeomCache->GetPrevIFrame(pHandle->m_startFrame) % frameDataSize;
  1489.         uint reinitializeEnd = pHandle->m_endFrame % frameDataSize;
  1490.  
  1491.         if (!pHandle->m_pNext && (reinitializeEnd != (frameDataSize - 1)))
  1492.         {
  1493.                 // If this was the last handle in stream or the next handle start frame is not right after the current handles end frame
  1494.                 // we need to reinitialize until the next index frame because index frame jobs will decrement dependency
  1495.                 // counters from b frames ahead of time.
  1496.  
  1497.                 reinitializeEnd = pGeomCache->GetNextIFrame(reinitializeEnd) + 1;
  1498.         }
  1499.  
  1500.         ReinitializeStreamFrameData(streamInfo, reinitializeStart, reinitializeEnd);
  1501.         RetireBufferHandle(pHandle);
  1502. }
  1503.  
  1504. template<class TBufferHandleType> void CGeomCacheManager::RetireBufferHandle(TBufferHandleType* pHandle)
  1505. {
  1506.         FUNCTION_PROFILER_3DENGINE;
  1507.  
  1508.         if (gEnv->mMainThreadId != CryGetCurrentThreadId())
  1509.         {
  1510.                 CryFatalError("CGeomCacheManager::RetireBufferHandle must be called from main thread");
  1511.         }
  1512.  
  1513.         if (pHandle->m_numJobReferences)
  1514.         {
  1515.                 CryFatalError("Trying to retire handle with jobs still running");
  1516.         }
  1517.  
  1518.         {
  1519.                 FRAME_PROFILER("CGeomCacheManager::RetireBufferHandle_Free", GetSystem(), PROFILE_3DENGINE);
  1520.                 size_t pointerSize = (sizeof(SGeomCacheBufferHandle*) + 15) & ~15;
  1521.                 m_pPool->Free(pHandle->m_pBuffer - pointerSize);
  1522.         }
  1523.  
  1524.         delete pHandle;
  1525. }
  1526.  
  1527. float CGeomCacheManager::GetPrecachedTime(const IGeomCacheRenderNode* pRenderNode)
  1528. {
  1529.         assert(gEnv->mMainThreadId == CryGetCurrentThreadId());
  1530.  
  1531.         for (uint i = 0; i < m_streamInfos.size(); ++i)
  1532.         {
  1533.                 SGeomCacheStreamInfo& streamInfo = *m_streamInfos[i];
  1534.                 if (streamInfo.m_pRenderNode == pRenderNode)
  1535.                 {
  1536.                         const float playbackTime = pRenderNode->GetPlaybackTime();
  1537.  
  1538.                         if (streamInfo.m_pNewestDecompressHandle)
  1539.                         {
  1540.                                 CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  1541.  
  1542.                                 const uint frame = streamInfo.m_pNewestDecompressHandle->m_startFrame;
  1543.                                 const float frameTime = pGeomCache->GetFrameTime(frame);
  1544.  
  1545.                                 if (playbackTime <= frameTime)
  1546.                                 {
  1547.                                         return frameTime - playbackTime;
  1548.                                 }
  1549.                         }
  1550.  
  1551.                         break;
  1552.                 }
  1553.         }
  1554.  
  1555.         return 0.0f;
  1556. }
  1557.  
  1558. SGeomCacheBufferHandle* CGeomCacheManager::GetFrameDecompressHandle(SGeomCacheStreamInfo* pStreamInfo, const uint frameIndex)
  1559. {
  1560.         const uint frameDataSize = pStreamInfo->m_frameData.size();
  1561.         return pStreamInfo->m_frameData[frameIndex % frameDataSize].m_pDecompressHandle;
  1562. }
  1563.  
  1564. SGeomCacheFrameHeader* CGeomCacheManager::GetFrameDecompressHeader(SGeomCacheStreamInfo* pStreamInfo, const uint frameIndex)
  1565. {
  1566.         SGeomCacheBufferHandle* pHandle = GetFrameDecompressHandle(pStreamInfo, frameIndex);
  1567.  
  1568.         if (!pHandle)
  1569.         {
  1570.                 return NULL;
  1571.         }
  1572.  
  1573.         const uint frameOffset = frameIndex - pHandle->m_startFrame;
  1574.         SGeomCacheFrameHeader* pHeader = reinterpret_cast<SGeomCacheFrameHeader*>(
  1575.           pHandle->m_pBuffer + (frameOffset * sizeof(SGeomCacheFrameHeader)));
  1576.         return pHeader;
  1577. }
  1578.  
  1579. char* CGeomCacheManager::GetFrameDecompressData(SGeomCacheStreamInfo* pStreamInfo, const uint frameIndex)
  1580. {
  1581.         SGeomCacheFrameHeader* pHeader = GetFrameDecompressHeader(pStreamInfo, frameIndex);
  1582.         SGeomCacheBufferHandle* pHandle = GetFrameDecompressHandle(pStreamInfo, frameIndex);
  1583.  
  1584.         if (!pHandle || !pHeader)
  1585.         {
  1586.                 return NULL;
  1587.         }
  1588.  
  1589.         return pHandle->m_pBuffer + pHeader->m_offset;
  1590. }
  1591.  
  1592. int* CGeomCacheManager::GetDependencyCounter(SGeomCacheStreamInfo* pStreamInfo, const uint frameIndex)
  1593. {
  1594.         const uint frameDataSize = pStreamInfo->m_frameData.size();
  1595.         return &pStreamInfo->m_frameData[frameIndex % frameDataSize].m_decodeDependencyCounter;
  1596. }
  1597.  
  1598.         #ifndef _RELEASE
  1599. namespace
  1600. {
  1601. void Draw2DBox(float x, float y, float width, float height, const ColorB& color, float screenHeight, float screenWidth, IRenderAuxGeom* pAuxRenderer)
  1602. {
  1603.         float position[4][2] = {
  1604.                 { x - 1.0f,         y - 1.0f          },
  1605.                 { x - 1.0f,         y + height + 1.0f },
  1606.                 { x + width + 1.0f, y + height + 1.0f },
  1607.                 { x + width + 1.0f, y - 1.0f          }
  1608.         };
  1609.  
  1610.         Vec3 positions[4] = {
  1611.                 Vec3(position[0][0] / screenWidth, position[0][1] / screenHeight, 0.0f),
  1612.                 Vec3(position[1][0] / screenWidth, position[1][1] / screenHeight, 0.0f),
  1613.                 Vec3(position[2][0] / screenWidth, position[2][1] / screenHeight, 0.0f),
  1614.                 Vec3(position[3][0] / screenWidth, position[3][1] / screenHeight, 0.0f)
  1615.         };
  1616.  
  1617.         vtx_idx const indices[6] = { 0, 1, 2, 0, 2, 3 };
  1618.  
  1619.         pAuxRenderer->DrawTriangles(positions, 4, indices, 6, color);
  1620. }
  1621.  
  1622. void Draw2DBoxOutLine(float x, float y, float width, float height, const ColorB& color, float screenHeight, float screenWidth, IRenderAuxGeom* pAuxRenderer)
  1623. {
  1624.         float position[4][2] = {
  1625.                 { x - 1.0f,         y - 1.0f          },
  1626.                 { x - 1.0f,         y + height + 1.0f },
  1627.                 { x + width + 1.0f, y + height + 1.0f },
  1628.                 { x + width + 1.0f, y - 1.0f          }
  1629.         };
  1630.  
  1631.         Vec3 positions[4] = {
  1632.                 Vec3(position[0][0] / screenWidth, position[0][1] / screenHeight, 0.0f),
  1633.                 Vec3(position[1][0] / screenWidth, position[1][1] / screenHeight, 0.0f),
  1634.                 Vec3(position[2][0] / screenWidth, position[2][1] / screenHeight, 0.0f),
  1635.                 Vec3(position[3][0] / screenWidth, position[3][1] / screenHeight, 0.0f)
  1636.         };
  1637.  
  1638.         pAuxRenderer->DrawLine(positions[0], color, positions[1], color);
  1639.         pAuxRenderer->DrawLine(positions[1], color, positions[2], color);
  1640.         pAuxRenderer->DrawLine(positions[2], color, positions[3], color);
  1641.         pAuxRenderer->DrawLine(positions[3], color, positions[0], color);
  1642. }
  1643.  
  1644. void DrawStream(const char* pBase, const size_t poolSize, const SGeomCacheBufferHandle* pFirstHandle, const ColorF& color, const float boxLeft, const float boxTop,
  1645.                 const float boxWidth, const float boxHeight, const float screenWidth, const float screenHeight, IRenderAuxGeom* pRenderAuxGeom)
  1646. {
  1647.         const float bufferSize = (float)poolSize;
  1648.         for (const SGeomCacheBufferHandle* pCurrentHandle = pFirstHandle; pCurrentHandle; pCurrentHandle = pCurrentHandle->m_pNext)
  1649.         {
  1650.                 ColorF blockColor = color;
  1651.  
  1652.                 const float offset = (float)(pCurrentHandle->m_pBuffer - pBase);
  1653.                 const float size = (float)pCurrentHandle->m_bufferSize;
  1654.  
  1655.                 const float left = boxWidth * (offset / bufferSize);
  1656.                 const float width = boxWidth * (size / bufferSize);
  1657.  
  1658.                 Draw2DBox(boxLeft + left + 1, boxTop + 1, width - 3, boxHeight - 2, blockColor, screenHeight, screenWidth, pRenderAuxGeom);
  1659.         }
  1660. }
  1661. }
  1662.  
  1663. void CGeomCacheManager::DrawDebugInfo()
  1664. {
  1665.         IRenderAuxGeom* const pRenderAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom();
  1666.  
  1667.         const SAuxGeomRenderFlags oldFlags = pRenderAuxGeom->GetRenderFlags();
  1668.  
  1669.         SAuxGeomRenderFlags flags(e_Def2DPublicRenderflags);
  1670.         flags.SetDepthTestFlag(e_DepthTestOff);
  1671.         flags.SetDepthWriteFlag(e_DepthWriteOff);
  1672.         flags.SetCullMode(e_CullModeNone);
  1673.         flags.SetAlphaBlendMode(e_AlphaNone);
  1674.         pRenderAuxGeom->SetRenderFlags(flags);
  1675.  
  1676.         const float screenHeight = (float)gEnv->pRenderer->GetHeight();
  1677.         const float screenWidth = (float)gEnv->pRenderer->GetWidth();
  1678.  
  1679.         const float topOffset = screenHeight * 0.01f;
  1680.         const float sideOffset = screenWidth * 0.01f;
  1681.  
  1682.         const float bufferBoxTop = 2.0f + 8.0f * topOffset;
  1683.         const float bufferBoxHeight = screenHeight * 0.05f;
  1684.         const float bufferBoxLeft = sideOffset;
  1685.         const float bufferBoxWidth = screenWidth * 0.5f;
  1686.  
  1687.         float streamInfosTop = bufferBoxTop + bufferBoxHeight + 2.0f * topOffset;
  1688.         const float streamInfoSpacing = 20.0f;
  1689.         const float streamInfoBoxSize = 10.0f;
  1690.  
  1691.         uint numActiveStreams = 0;
  1692.         uint numFramesMissed = 0;
  1693.  
  1694.         const uint kNumColors = 8;
  1695.         ColorF colors[kNumColors] = { Col_Red, Col_Green, Col_Yellow, Col_Blue, Col_Aquamarine, Col_Thistle, Col_Tan, Col_Salmon };
  1696.  
  1697.         uint colorIndex = 0;
  1698.         const uint numStreams = m_streamInfos.size();
  1699.         for (uint i = 0; i < numStreams; ++i)
  1700.         {
  1701.                 SGeomCacheStreamInfo& streamInfo = *m_streamInfos[i];
  1702.                 CGeomCacheRenderNode* pRenderNode = streamInfo.m_pRenderNode;
  1703.                 CGeomCache* pGeomCache = streamInfo.m_pGeomCache;
  1704.                 const char* pName = streamInfo.m_pRenderNode->GetName();
  1705.                 const char* pFilter = GetCVars()->e_GeomCacheDebugFilter->GetString();
  1706.  
  1707.                 const bool bDisplay = ((GetCVars()->e_GeomCacheDebug != 2) || (pRenderNode->IsStreaming() || streamInfo.m_pOldestDecompressHandle || streamInfo.m_pNewestReadRequestHandle))
  1708.                                       && strstr(pName, GetCVars()->e_GeomCacheDebugFilter->GetString()) != NULL;
  1709.  
  1710.                 if (bDisplay)
  1711.                 {
  1712.                         ColorF& color = colors[colorIndex % kNumColors];
  1713.  
  1714.                         DrawStream(reinterpret_cast<char*>(m_pPoolBaseAddress), m_poolSize, streamInfo.m_pOldestDecompressHandle, color, bufferBoxLeft, bufferBoxTop,
  1715.                                    bufferBoxWidth, bufferBoxHeight, screenWidth, screenHeight, pRenderAuxGeom);
  1716.                         DrawStream(reinterpret_cast<char*>(m_pPoolBaseAddress), m_poolSize, streamInfo.m_pDecompressAbortListHead, color, bufferBoxLeft, bufferBoxTop,
  1717.                                    bufferBoxWidth, bufferBoxHeight, screenWidth, screenHeight, pRenderAuxGeom);
  1718.                         DrawStream(reinterpret_cast<char*>(m_pPoolBaseAddress), m_poolSize, streamInfo.m_pOldestReadRequestHandle, color, bufferBoxLeft, bufferBoxTop,
  1719.                                    bufferBoxWidth, bufferBoxHeight, screenWidth, screenHeight, pRenderAuxGeom);
  1720.                         DrawStream(reinterpret_cast<char*>(m_pPoolBaseAddress), m_poolSize, streamInfo.m_pReadAbortListHead, color, bufferBoxLeft, bufferBoxTop,
  1721.                                    bufferBoxWidth, bufferBoxHeight, screenWidth, screenHeight, pRenderAuxGeom);
  1722.  
  1723.                         const float currentTop = streamInfosTop + streamInfoSpacing * 2.5f * numActiveStreams;
  1724.                         Draw2DBox(sideOffset, currentTop, streamInfoBoxSize, streamInfoBoxSize, color, screenHeight, screenWidth, pRenderAuxGeom);
  1725.  
  1726.                         const float wantedPlaybackTime = streamInfo.m_wantedPlaybackTime;
  1727.                         const uint wantedFloorFrame = streamInfo.m_wantedFloorFrame;
  1728.                         const uint wantedCeilFrame = streamInfo.m_wantedCeilFrame;
  1729.                         const int oldestDiskFrame = streamInfo.m_pOldestReadRequestHandle ? streamInfo.m_pOldestReadRequestHandle->m_startFrame : -1;
  1730.                         const int newestDiskFrame = streamInfo.m_pNewestReadRequestHandle ? streamInfo.m_pNewestReadRequestHandle->m_endFrame : -1;
  1731.                         const int oldestDecompressFrame = streamInfo.m_pOldestDecompressHandle ? streamInfo.m_pOldestDecompressHandle->m_startFrame : -1;
  1732.                         const int newestDecompressFrame = streamInfo.m_pNewestDecompressHandle ? streamInfo.m_pNewestDecompressHandle->m_endFrame : -1;
  1733.  
  1734.                         IGeomCache::SStatistics stats = pGeomCache->GetStatistics();
  1735.  
  1736.                         const char* pCompressionMethod = "Store";
  1737.                         if (pGeomCache->GetBlockCompressionFormat() == GeomCacheFile::eBlockCompressionFormat_Deflate)
  1738.                         {
  1739.                                 pCompressionMethod = "Deflate";
  1740.                         }
  1741.                         else if (pGeomCache->GetBlockCompressionFormat() == GeomCacheFile::eBlockCompressionFormat_LZ4HC)
  1742.                         {
  1743.                                 pCompressionMethod = "LZ4 HC";
  1744.                         }
  1745.  
  1746.                         IRenderAuxText::Draw2dLabel(sideOffset + streamInfoSpacing, currentTop - 5.0f, 1.5f, Col_White, false, "%s - %.3gs %s- %.3g MiB/s - %s - %d frames missed",
  1747.                                                      streamInfo.m_pRenderNode->GetName(), pGeomCache->GetDuration(), streamInfo.m_bLooping ? "looping " : "", stats.m_averageAnimationDataRate, pCompressionMethod, streamInfo.m_numFramesMissed);
  1748.                         IRenderAuxText::Draw2dLabel(sideOffset + streamInfoSpacing, streamInfoSpacing + currentTop - 5.0f, 1.5f, Col_White, false,
  1749.                                                      "Frame: [%04u, %04u], Disk Frames: [%04u, %04u], Decompress Frames: [%04u, %04u], Playback time: %g", wantedFloorFrame, wantedCeilFrame,
  1750.                                                      oldestDiskFrame, newestDiskFrame, oldestDecompressFrame, newestDecompressFrame, wantedPlaybackTime);
  1751.  
  1752.                         ++numActiveStreams;
  1753.                         ++colorIndex;
  1754.                 }
  1755.         }
  1756.  
  1757.         const uint numAbortedStreams = m_streamInfosAbortList.size();
  1758.         IRenderAuxText::Draw2dLabel(sideOffset, topOffset, 1.5f, Col_Yellow, false, "%u Geometry Cache(s) active", numActiveStreams);
  1759.         IRenderAuxText::Draw2dLabel(sideOffset, 3.5f * topOffset, 1.5f, (m_numMissedFrames > 0) ? Col_Red : Col_Green, false, "%u Frames missed", m_numMissedFrames);
  1760.         IRenderAuxText::Draw2dLabel(sideOffset + 160.0f, 3.5f * topOffset, 1.5f, (m_numStreamAborts > 0) ? Col_Red : Col_Green, false, "%u Stream aborts (err: %u, decomp: %u, read: %u)",
  1761.                                      m_numStreamAborts, m_numErrorAborts, m_numDecompressStreamAborts, m_numReadStreamAborts);
  1762.         IRenderAuxText::Draw2dLabel(sideOffset + 520.0f, 3.5f * topOffset, 1.5f, (m_numFailedAllocs > 0) ? Col_Yellow : Col_Green, false, "%u Failed alloc(s)", m_numFailedAllocs);
  1763.         IRenderAuxText::Draw2dLabel(sideOffset + 670.0f, 3.5f * topOffset, 1.5f, (numAbortedStreams > 0) ? Col_Yellow : Col_Green, false, "%u Aborted stream(s)", numAbortedStreams);
  1764.  
  1765.         IRenderAuxText::Draw2dLabel(sideOffset, 6.0f * topOffset, 1.25f, Col_White, false, "Geom Cache Buffer:");
  1766.         Draw2DBoxOutLine(bufferBoxLeft, bufferBoxTop, bufferBoxWidth, bufferBoxHeight, Col_White, screenHeight, screenWidth, pRenderAuxGeom);
  1767.  
  1768.         pRenderAuxGeom->SetRenderFlags(oldFlags);
  1769. }
  1770.         #endif
  1771.  
  1772. #endif
  1773.  
downloadGeomCacheManager.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top