void VRendererNodeCommon::OnHandleCallback(IVisCallbackDataObject_cl *pData) { if (pData->m_pSender == &Vision::Callbacks.OnBeforeVideoChanged) { if (GetFinalTargetContext() != NULL && RendersIntoBackBuffer() && IsInitialized()) { m_pDeinitDuringVideoResize = new VScopedRendererNodeDeinit(this); } } else if (pData->m_pSender == &Vision::Callbacks.OnVideoChanged) { V_SAFE_DELETE(m_pDeinitDuringVideoResize); } #if defined(_VISION_WIN32) && defined(_VR_DX9) else if (pData->m_pSender == &Vision::Callbacks.OnEnterForeground) { if(IsInitialized()) { InitializePostProcessors(); } } #endif else if (pData->m_pSender == &Vision::Callbacks.OnUpdateSceneFinished) { UpdateTimeOfDay(); } }
void VRendererNodeCommon::InitializePostProcessors() { VASSERT_MSG(IsInitialized(), "The renderer node must be initialized before initializing the post processors."); ANALYSIS_IGNORE_WARNING_BLOCK_START(6385); ANALYSIS_IGNORE_WARNING_BLOCK_START(6211); // Increment the update counter to enable modifying the post processors without recursing m_iPostProcessorUpdateCounter++; VType* pCopyPostProcessorType = GetDefaultCopyPostprocessorType(); bool bInvalidPostProcessorActive = false; do { bInvalidPostProcessorActive = false; DeInitializePostProcessors(); VPostProcessingBaseComponent* pSimpleCopy = NULL; // Collect post processor components VMemoryTempBuffer<256> tempBuffer((Components().Count() + 1) * sizeof(VPostProcessingBaseComponent*)); VPostProcessingBaseComponent** postProcessors = reinterpret_cast<VPostProcessingBaseComponent**>(tempBuffer.GetBuffer()); int iPostProcessorIndex = 0; for(int iComponentIndex = 0; iComponentIndex < Components().Count(); iComponentIndex++) { if(VPostProcessingBaseComponent* pPostProcessor = vdynamic_cast<VPostProcessingBaseComponent*>(Components().GetAt(iComponentIndex))) { // Don't take the auto added copy PP into consideration, we'll handle that separately if(pCopyPostProcessorType != NULL && pPostProcessor->IsOfType(pCopyPostProcessorType)) { pSimpleCopy = pPostProcessor; continue; } // HS#10443: Skip post-processors which do nothing - needs testing whether this works cleanly when the identity state changes if(!pPostProcessor->IsActive() /*!pPostProcessor->IsIdentity()*/) { continue; } postProcessors[iPostProcessorIndex] = pPostProcessor; iPostProcessorIndex++; } } int iNumPostProcessors = iPostProcessorIndex; qsort(postProcessors, iNumPostProcessors, sizeof(VPostProcessingBaseComponent*), ComparePostProcessorsByPriority); int iCopyPPIndex = iNumPostProcessors; // Scan backwards through post processors to find one which can take over the responsibility // of copying the scene to the final target context // // This post processor must: // - come after the MSAA resolve step // - render an opaque full screen quad // - not have any postprocessor afterwards that reads the accumulation buffer bool bUsesOffscreenRenderTarget = !m_bUsesDirectRenderToFinalTargetContext; for(int i = iNumPostProcessors - 1; i >= 0; i--) { if(postProcessors[i]->GetPriority() < VIS_RENDERCONTEXTPRIORITY_POSTPROCESSOR_RESOLVED) { bUsesOffscreenRenderTarget = true; break; } const unsigned int flags = postProcessors[i]->GetBufferUsageFlags(); // Post processors that use their own render target can't be used for copying to the back buffer if((flags & VPostProcessingBaseComponent::USES_CUSTOM_RENDERTARGET) != 0) { bUsesOffscreenRenderTarget = true; break; } // Check first if the post processors draws an opaque full screen quad, because // a PP that draws a full screen quad AND samples the accumulation buffer // is still suitable for copying the accumulation buffer into the final target context (such as tonemapping). if((flags & VPostProcessingBaseComponent::DRAWS_FULLSCREEN_QUAD) != 0 && (flags & VPostProcessingBaseComponent::USES_BLENDING) == 0) { iCopyPPIndex = i; break; } if(flags & VPostProcessingBaseComponent::SAMPLES_ACCUMULATION_BUFFER) { bUsesOffscreenRenderTarget = true; break; } } VASSERT_MSG(bUsesOffscreenRenderTarget != m_bUsesDirectRenderToFinalTargetContext, "Renderer node indicated that it renders directly to the renderer node's final target context, but post-processors require an offscreen render target!"); // If no suitable post processor was found, we need to make sure the scene is copied bool bNeedsManualCopyToTarget = (iCopyPPIndex == iNumPostProcessors) && bUsesOffscreenRenderTarget; // If we don't use an offscreen RT, we don't have a copy PP if (!bUsesOffscreenRenderTarget) iCopyPPIndex = -1; if(bNeedsManualCopyToTarget) { if (pCopyPostProcessorType != NULL) { if(pSimpleCopy == NULL) { pSimpleCopy = (VPostProcessingBaseComponent*)pCopyPostProcessorType->CreateInstance(); VASSERT(pSimpleCopy != NULL); AddComponent(pSimpleCopy); } postProcessors[iNumPostProcessors] = pSimpleCopy; iNumPostProcessors++; } } else if(pSimpleCopy != NULL) { // Remove existing copy PP if not needed RemoveComponent(pSimpleCopy); } m_assignedContexts.EnsureCapacity(iNumPostProcessors); // Create a target context for each post processor for(iPostProcessorIndex = 0; iPostProcessorIndex < iNumPostProcessors; iPostProcessorIndex++) { VPostProcessingBaseComponent* pPostProcessor = postProcessors[iPostProcessorIndex]; pPostProcessor->m_iTargetIndex = iPostProcessorIndex; const VisRenderContext_cl* pFinalTargetContext = GetFinalTargetContext(); bool bRenderIntoFinalTargetContext = (iPostProcessorIndex >= iCopyPPIndex); int iPosX, iPosY, iWidth, iHeight; float zMin, zMax; if(bRenderIntoFinalTargetContext) { pFinalTargetContext->GetViewport(iPosX, iPosY, iWidth, iHeight, zMin, zMax); } else { GetReferenceContext()->GetViewport(iPosX, iPosY, iWidth, iHeight, zMin, zMax); } VisRenderContext_cl* pContext = new VisRenderContext_cl(pFinalTargetContext->GetCamera(), 90.0f, 90.0f, iWidth, iHeight, 0.0f, 0.0f, pFinalTargetContext->GetRenderFlags()); pContext->SetRenderFilterMask(pFinalTargetContext->GetRenderFilterMask()); pContext->SetViewport(iPosX, iPosY, iWidth, iHeight, zMin, zMax); pContext->SetViewProperties(pFinalTargetContext->GetViewProperties()); pContext->SetName(pPostProcessor->GetTypeId()->m_lpszClassName); pContext->SetVisibilityCollector(pFinalTargetContext->GetVisibilityCollector(), false); pContext->SetPriority(pPostProcessor->GetPriority()); pContext->SetUserData(pPostProcessor); pContext->SetRenderLoop(new PostProcessRenderLoop_cl(pPostProcessor)); if(bRenderIntoFinalTargetContext) { pContext->SetRenderAndDepthStencilTargets(pFinalTargetContext); if (bUsesOffscreenRenderTarget) { // If possible, try to give the post processors that render directly into the final target context a useful depth-stencil target. // This is only possible if the final target context has MSAA disabled. bool bCanReplaceDST = false; if(pFinalTargetContext->RendersIntoBackBuffer()) { #if !defined(_VISION_ANDROID) && !defined(_VISION_TIZEN) && !defined(_VISION_NACL) // On Android, the back buffer context uses a fixed FBO, so we can't replace the DST. bCanReplaceDST = Vision::Video.GetCurrentConfig()->m_eMultiSample == VVIDEO_MULTISAMPLE_OFF; #endif } else if(pFinalTargetContext->GetRenderTarget(0) != NULL) { bCanReplaceDST = static_cast<VisRenderableTexture_cl*>(pFinalTargetContext->GetRenderTarget(0))->GetConfig()->m_iMultiSampling <= 1; } int iRefWidth, iRefHeight, iFinalWidth, iFinalHeight; pFinalTargetContext->GetSize(iFinalWidth, iFinalHeight); GetReferenceContext()->GetSize(iRefWidth, iRefHeight); if(iRefWidth != iFinalWidth || iRefHeight != iFinalHeight) { bCanReplaceDST = false; } if(bCanReplaceDST) { pContext->SetDepthStencilTarget(static_cast<VisRenderableTexture_cl*>(GetPostProcessDepthStencilTarget(VRTV_RESOLVED))); } else { hkvLog::Warning("Could not attach a depth-stencil target to the context of the \"%s\" post processor - depth testing will not work correctly.", pPostProcessor->GetTypeId()->m_lpszClassName); } } } else { VRenderTargetVersion_e targetVersion = (pPostProcessor->GetPriority() <= VIS_RENDERCONTEXTPRIORITY_POSTPROCESSOR_RESOLVED) ? VRTV_MSAA : VRTV_RESOLVED; if((pPostProcessor->GetBufferUsageFlags() & VPostProcessingBaseComponent::USES_CUSTOM_RENDERTARGET) == 0) { pContext->SetRenderTarget(0, static_cast<VisRenderableTexture_cl*>(GetPostProcessColorTarget(targetVersion))); pContext->SetDepthStencilTarget(static_cast<VisRenderableTexture_cl*>(GetPostProcessDepthStencilTarget(targetVersion))); } } m_assignedContexts.Add(pContext); pPostProcessor->InitializePostProcessor(); // Validity can only be determined after initialization, so deactivate the invalid postprocessor and retry the entire context setup if(!pPostProcessor->IsValid()) { // the post-processor will have deactivated itself by now pPostProcessor->SetActive(false); bInvalidPostProcessorActive = true; } } } while ( bInvalidPostProcessorActive ); m_bPostProcessorAssignmentDirty = false; m_iPostProcessorUpdateCounter--; VisRenderContext_cl::ElementManagerDeleteAllUnRef(); ANALYSIS_IGNORE_WARNING_BLOCK_END; ANALYSIS_IGNORE_WARNING_BLOCK_END; }
void IVRendererNode::InitializeRenderer() { VASSERT_MSG(GetFinalTargetContext() != NULL, "The final target context must be set before initialization."); }