//============================================================================================================================== bool DeferredShader::Initialize() { ConstantBuffer<cbPackBuffer> packCB(m_pD3DSystem); packCB.Initialize(PAD16(sizeof(cbPackBuffer))); m_pPackCB = packCB.Buffer(); ConstantBuffer<cbMatrixBuffer> matrixCB(m_pD3DSystem); matrixCB.Initialize(PAD16(sizeof(cbMatrixBuffer))); m_pMatrixCB = matrixCB.Buffer(); ConstantBuffer<cbMatrixBuffer2> matrix2CB(m_pD3DSystem); matrix2CB.Initialize(PAD16(sizeof(cbMatrixBuffer2))); m_pMatrix2CB = matrix2CB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("DeferredShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); LoadVertexShader("DeferredShaderVS"); LoadPixelShader("DeferredShaderPS"); LoadPixelShader("DeferredShaderWireframePS"); AssignVertexShaderLayout("DeferredShader"); return true; }
//============================================================================================================================== bool OBJMeshShader::Initialize() { ConstantBuffer<ZShadeSandboxLighting::cbMaterialShadingBuffer> objShadingCB(m_pD3DSystem); objShadingCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbMaterialShadingBuffer))); m_pShadingCB = objShadingCB.Buffer(); ConstantBuffer<cbMatrixBuffer> matrixBufferCB(m_pD3DSystem); matrixBufferCB.Initialize(PAD16(sizeof(cbMatrixBuffer))); m_pMatrixCB = matrixBufferCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbLightBuffer> lightCB(m_pD3DSystem); lightCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbLightBuffer))); m_pLightCB = lightCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbSunLightBuffer> sunCB(m_pD3DSystem); sunCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbSunLightBuffer))); m_pSunCB = sunCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("OBJMeshShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); LoadVertexShader("OBJMeshVS"); LoadPixelShader("OBJMeshPS"); LoadPixelShader("OBJMeshWireframePS"); AssignVertexShaderLayout("OBJMeshShader"); return true; }
void Render(const Vect2 &pos, const Vect2 &size) { Texture *texture = bitmapImage.GetTexture(); if(texture) { if(bUseColorKey) { Shader *lastPixelShader = GetCurrentPixelShader(); DWORD alpha = ((opacity*255/100)&0xFF); DWORD outputColor = (alpha << 24) | color&0xFFFFFF; LoadPixelShader(colorKeyShader); float fSimilarity = float(keySimilarity)*0.01f; float fBlend = float(keyBlend)*0.01f; colorKeyShader->SetColor(colorKeyShader->GetParameter(2), keyColor); colorKeyShader->SetFloat(colorKeyShader->GetParameter(3), fSimilarity); colorKeyShader->SetFloat(colorKeyShader->GetParameter(4), fBlend); DrawSprite(texture, outputColor, pos.x, pos.y, pos.x+size.x, pos.y+size.y); LoadPixelShader(lastPixelShader); } else { DWORD alpha = ((opacity*255/100)&0xFF); DWORD outputColor = (alpha << 24) | color&0xFFFFFF; DrawSprite(texture, outputColor, pos.x, pos.y, pos.x+size.x, pos.y+size.y); } } }
void DeviceSource::Render(const Vect2 &pos, const Vect2 &size) { if(texture && bReadyToDraw) { Shader *oldShader = GetCurrentPixelShader(); if(colorConvertShader) { LoadPixelShader(colorConvertShader); if(bUseChromaKey) { float fSimilarity = float(keySimilarity)/1000.0f; float fBlendVal = float(max(keyBlend, 1)/1000.0f); float fSpillVal = (float(max(keySpillReduction, 1))/1000.0f); Vect2 pixelSize = 1.0f/GetSize(); colorConvertShader->SetColor (colorConvertShader->GetParameterByName(TEXT("keyBaseColor")), Color4(keyBaseColor)); colorConvertShader->SetColor (colorConvertShader->GetParameterByName(TEXT("chromaKey")), Color4(keyChroma)); colorConvertShader->SetVector2(colorConvertShader->GetParameterByName(TEXT("pixelSize")), pixelSize); colorConvertShader->SetFloat (colorConvertShader->GetParameterByName(TEXT("keySimilarity")), fSimilarity); colorConvertShader->SetFloat (colorConvertShader->GetParameterByName(TEXT("keyBlend")), fBlendVal); colorConvertShader->SetFloat (colorConvertShader->GetParameterByName(TEXT("keySpill")), fSpillVal); } } bool bFlip = bFlipVertical; if(colorType != DeviceOutputType_RGB) bFlip = !bFlip; float x, x2; if(bFlipHorizontal) { x2 = pos.x; x = x2+size.x; } else { x = pos.x; x2 = x+size.x; } float fOpacity = float(opacity)*0.01f; DWORD opacity255 = DWORD(fOpacity*255.0f); if(bFlip) DrawSprite(texture, (opacity255<<24) | 0xFFFFFF, x, pos.y, x2, pos.y+size.y); else DrawSprite(texture, (opacity255<<24) | 0xFFFFFF, x, pos.y+size.y, x2, pos.y); if(colorConvertShader) LoadPixelShader(oldShader); } }
//============================================================================================================================== bool AmbientLightDeferredShader::Initialize() { ConstantBuffer<cbDeferredLightBuffer> lightCB(m_pD3DSystem); lightCB.Initialize(PAD16(sizeof(cbDeferredLightBuffer))); m_pLightCB = lightCB.Buffer(); LoadVertexShader("AmbientLightDeferredVS"); LoadPixelShader("AmbientLightDeferredPS"); LoadPixelShader("AmbientLightDeferredWireframePS"); return true; }
//============================================================================================================================== bool DebugGBufferDeferredShader::Initialize() { ConstantBuffer<cbInvMatrixBuffer> matrixCB(m_pD3DSystem); matrixCB.Initialize(PAD16(sizeof(cbInvMatrixBuffer))); m_pMatrixCB = matrixCB.Buffer(); LoadVertexShader("DebugGBufferDeferredVS"); LoadPixelShader("DebugGBufferDeferredPS"); LoadPixelShader("DebugGBufferDepthDeferredPS"); LoadPixelShader("DebugGBufferDeferredWireframePS"); return true; }
// 初期化をする Shader *Shader_Initialize() { Shader *self = new Shader(); self->depthmap_vs = LoadVertexShader("shader/depthmap.vs.vso"); self->depthmap_ps = LoadPixelShader("shader/depthmap.ps.pso"); self->phong_vs = LoadVertexShader("shader/phong.vs.vso"); self->phong_ps = LoadPixelShader("shader/phong.ps.pso"); self->active_pass = -1; self->depthmap_screen = create_depthmap_buffer(); return self; }
void OBS::DrawPreview(const Vect2 &renderFrameSize, const Vect2 &renderFrameOffset, const Vect2 &renderFrameCtrlSize, int curRenderTarget, PreviewDrawType type) { LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); Ortho(0.0f, renderFrameCtrlSize.x, renderFrameCtrlSize.y, 0.0f, -100.0f, 100.0f); if(type != Preview_Projector && (renderFrameCtrlSize.x != oldRenderFrameCtrlWidth || renderFrameCtrlSize.y != oldRenderFrameCtrlHeight)) { // User is drag resizing the window. We don't recreate the swap chains so our coordinates are wrong SetViewport(0.0f, 0.0f, (float)oldRenderFrameCtrlWidth, (float)oldRenderFrameCtrlHeight); } else SetViewport(0.0f, 0.0f, renderFrameCtrlSize.x, renderFrameCtrlSize.y); // Draw background (Black if fullscreen/projector, window colour otherwise) if(type == Preview_Fullscreen || type == Preview_Projector) ClearColorBuffer(0x000000); else ClearColorBuffer(GetSysColor(COLOR_BTNFACE)); if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); DrawSprite(transitionTexture, 0xFFFFFFFF, renderFrameOffset.x, renderFrameOffset.y, renderFrameOffset.x + renderFrameSize.x, renderFrameOffset.y + renderFrameSize.y); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } DrawSprite(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, renderFrameOffset.x, renderFrameOffset.y, renderFrameOffset.x + renderFrameSize.x, renderFrameOffset.y + renderFrameSize.y); }
//============================================================================================================================== bool TerrainTessellationQuadShadowShader::Initialize() { ConstantBuffer<cTessellationBuffer> tessellationCB(m_pD3DSystem); tessellationCB.Initialize(PAD16(sizeof(cTessellationBuffer))); m_pTessellationCB = tessellationCB.Buffer(); ConstantBuffer<cDomainConstBuffer> domainCB(m_pD3DSystem); domainCB.Initialize(PAD16(sizeof(cDomainConstBuffer))); m_pDomainCB = domainCB.Buffer(); ConstantBuffer<cMatrixBuffer> matrixBufferCB(m_pD3DSystem); matrixBufferCB.Initialize(PAD16(sizeof(cMatrixBuffer))); m_pMatrixBufferCB = matrixBufferCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("TerrainTessellationQuadShadowShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_tex, 2); LoadVertexShader("TerrainTessellationQuadVS"); LoadHullShader("TerrainTessellationQuadShadowHS"); LoadDomainShader("TerrainTessellationQuadDS"); LoadPixelShader("TerrainTessellationShadowPS"); AssignVertexShaderLayout("TerrainTessellationQuadShadowShader"); return true; }
void D3D10System::UnloadAllData() { LoadVertexShader(NULL); LoadPixelShader(NULL); LoadVertexBuffer(NULL); for(UINT i=0; i<8; i++) { LoadSamplerState(NULL, i); LoadTexture(NULL, i); } UINT zeroVal = 0; LPVOID nullBuff[8]; float bla[4] = {1.0f, 1.0f, 1.0f, 1.0f}; zero(nullBuff, sizeof(nullBuff)); d3d->VSSetConstantBuffers(0, 1, (ID3D10Buffer**)nullBuff); d3d->PSSetConstantBuffers(0, 1, (ID3D10Buffer**)nullBuff); d3d->OMSetDepthStencilState(NULL, 0); d3d->PSSetSamplers(0, 1, (ID3D10SamplerState**)nullBuff); d3d->OMSetBlendState(NULL, bla, 0xFFFFFFFF); d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)nullBuff, NULL); d3d->IASetVertexBuffers(0, 8, (ID3D10Buffer**)nullBuff, &zeroVal, &zeroVal); d3d->PSSetShaderResources(0, 8, (ID3D10ShaderResourceView**)nullBuff); d3d->IASetInputLayout(NULL); d3d->PSSetShader(NULL); d3d->VSSetShader(NULL); d3d->RSSetState(NULL); }
// Initialises the given render method (vertex + pixel shader), returns true on success bool LoadMethod( int method ) { // If the vertex shader for this method has not already been initialised if (!renderMethods[method].vertexShader) { // Load the vertex shader file specified above, storing resultant DirectX data if (!LoadVertexShader( renderMethods[method].vertexShaderFile, &renderMethods[method].vertexShader, &renderMethods[method].vertexConsts )) { return false; } } if (!renderMethods[method].pixelShader) { // Load the vertex shader file specified above, storing resultant DirectX data if (!LoadPixelShader( renderMethods[method].pixelShaderFile, &renderMethods[method].pixelShader, &renderMethods[method].pixelConsts )) { return false; } } if (!renderMethods[method].vertexDecl) { if (FAILED(g_pd3dDevice->CreateVertexDeclaration( renderMethods[method].vertexElts, &renderMethods[method].vertexDecl ))) { return false; } } return true; }
HRESULT CDirect3D::LoadPixelShader(const char * shader, double scalex, double scaley, bool forced) { if(!psEnabled) { RENDER_SetForceUpdate(false); psActive = false; return E_FAIL; } #if C_D3DSHADERS // See if the shader is already running if((!psEffect) || (strcmp(pshader+8, shader))) { // This is called in main thread to test if pixelshader needs to be changed if((scalex == 0) && (scaley == 0)) return S_OK; RENDER_SetForceUpdate(false); safe_strncpy(pshader+8, shader, 22); pshader[29] = '\0'; #if D3D_THREAD Wait(false); thread_command = D3D_LOADPS; LeaveCriticalSection(&cs); SDL_SemPost(thread_sem); if(FAILED(Wait(true))) return E_FAIL; #else if(FAILED(LoadPixelShader())) return E_FAIL; #endif } else { #if LOG_D3D LOG_MSG("D3D:Shader %s is already loaded", shader); #endif return E_FAIL; } if (psEffect) { #if LOG_D3D LOG_MSG("D3D:Shader scale: %.2f", psEffect->getScale()); #endif // Compare optimal scaling factor bool dblgfx=((scalex < scaley ? scalex : scaley) >= psEffect->getScale()); if(dblgfx || forced) { LOG_MSG("D3D:Pixel shader %s active", shader); RENDER_SetForceUpdate(psEffect->getForceUpdate()); psActive = true; return S_OK; } else { LOG_MSG("D3D:Pixel shader not needed"); psActive = false; return E_FAIL; } } else psActive = false; #endif // C_D3DSHADERS return S_OK; }
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int grhandle, pshandle ; VERTEX2DSHADER Vert[ 6 ] ; // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1; // 画像の読み込み grhandle = LoadGraph( "Test1.bmp" ); // ピクセルシェーダーバイナリコードの読み込み pshandle = LoadPixelShader( "SamplePS.pso" ) ; // 頂点データの準備 Vert[ 0 ].pos = VGet( 0.0f, 0.0f, 0.0f ) ; Vert[ 1 ].pos = VGet( 128.0f, 0.0f, 0.0f ) ; Vert[ 2 ].pos = VGet( 0.0f, 512.0f, 0.0f ) ; Vert[ 3 ].pos = VGet( 128.0f, 512.0f, 0.0f ) ; Vert[ 0 ].dif = GetColorU8( 255,255,255,255 ) ; Vert[ 0 ].spc = GetColorU8( 0,0,0,0 ) ; Vert[ 0 ].u = 0.0f ; Vert[ 0 ].v = 0.0f ; Vert[ 1 ].u = 1.0f ; Vert[ 1 ].v = 0.0f ; Vert[ 2 ].u = 0.0f ; Vert[ 2 ].v = 1.0f ; Vert[ 3 ].u = 1.0f ; Vert[ 3 ].v = 1.0f ; Vert[ 0 ].su = 0.0f ; Vert[ 0 ].sv = 0.0f ; Vert[ 1 ].su = 1.0f ; Vert[ 1 ].sv = 0.0f ; Vert[ 2 ].su = 0.0f ; Vert[ 2 ].sv = 1.0f ; Vert[ 3 ].su = 1.0f ; Vert[ 3 ].sv = 1.0f ; Vert[ 0 ].rhw = 1.0f ; Vert[ 1 ].rhw = 1.0f ; Vert[ 2 ].rhw = 1.0f ; Vert[ 3 ].rhw = 1.0f ; Vert[ 4 ] = Vert[ 2 ] ; Vert[ 5 ] = Vert[ 1 ] ; // 使用するテクスチャをセット SetUseTextureToShader( 0, grhandle ) ; // 使用するピクセルシェーダーをセット SetUsePixelShader( pshandle ) ; // 描画 DrawPrimitive2DToShader( Vert, 6, DX_PRIMTYPE_TRIANGLELIST ) ; // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End(); // ソフトの終了 return 0; }
void AllignedQuadEffect::Init() { LoadVertexShader( "H:/Projects VS C++/My VoxelEngine/VoxelGame 0.09/MyFramework/AllignedQuadEffect.hlsl" ); LoadPixelShader( "H:/Projects VS C++/My VoxelEngine/VoxelGame 0.09/MyFramework/AllignedQuadEffect.hlsl" ); D3DXHANDLE hMyTexture = m_pixelShaderConstantTable->GetConstantByName( nullptr, "myTexture" ); UINT count; m_pixelShaderConstantTable->GetConstantDesc( hMyTexture, &m_myTextureConstantDesk, &count ); }
//============================================================================================================================== bool OBJMeshShader::Initialize() { ConstantBuffer<cbOBJShadingConst> objShadingCB(m_pD3DSystem); objShadingCB.Initialize(PAD16(sizeof(cbOBJShadingConst))); m_pOBJShadingCB = objShadingCB.Buffer(); ConstantBuffer<cbMatrixBuffer> matrixBufferCB(m_pD3DSystem); matrixBufferCB.Initialize(PAD16(sizeof(cbMatrixBuffer))); m_pMatrixBufferCB = matrixBufferCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("OBJMeshShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); LoadVertexShader("OBJMeshVS"); LoadPixelShader("OBJMeshPS"); LoadPixelShader("OBJMeshWireframePS"); AssignVertexShaderLayout("OBJMeshShader"); return true; }
//============================================================================================================================== bool TriMaterialTessellationShader::Initialize() { ConstantBuffer<cTessellationBuffer> tessellationCB(m_pD3DSystem); tessellationCB.Initialize(PAD16(sizeof(cTessellationBuffer))); m_pTessellationCB = tessellationCB.Buffer(); ConstantBuffer<Const_Per_Frame> perFrameCB(m_pD3DSystem); perFrameCB.Initialize(PAD16(sizeof(Const_Per_Frame))); m_pPerFrameCB = perFrameCB.Buffer(); ConstantBuffer<Const_Per_Object> perObjectCB(m_pD3DSystem); perObjectCB.Initialize(PAD16(sizeof(Const_Per_Object))); m_pPerObjectCB = perObjectCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbLightBuffer> lightCB(m_pD3DSystem); lightCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbLightBuffer))); m_pLightCB = lightCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbSunLightBuffer> sunCB(m_pD3DSystem); sunCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbSunLightBuffer))); m_pSunCB = sunCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("TriMaterialTessellationShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); LoadVertexShader("MaterialTessellationShaderVS"); LoadHullShader("TriMaterialTessellationShaderHS"); LoadDomainShader("TriMaterialTessellationShaderDS"); LoadPixelShader("MaterialTessellationShaderPS"); LoadPixelShader("MaterialTessellationShaderWireframePS"); AssignVertexShaderLayout("TriMaterialTessellationShader"); bFlipHorizontally = false; bFlipVertically = false; return true; }
// ステージの初期化処理 void Stage_Initialize( void ) { // ステージモデルの読み込み stg.ModelHandle = MV1LoadModel( "ColTestStage.mqo" ) ; // モデル全体のコリジョン情報のセットアップ MV1SetupCollInfo( stg.ModelHandle, -1 ) ; // 作成する画像のフォーマットを不動小数点型で1チャンネル、16ビットにする SetDrawValidFloatTypeGraphCreateFlag( TRUE ) ; SetCreateDrawValidGraphChannelNum( 1 ) ; SetCreateGraphColorBitDepth( 16 ) ; // 影用深度記録画像の作成 DepthBufferGraphHandle = MakeScreen( 4096, 4096, FALSE ) ; // 設定を元に戻す SetDrawValidFloatTypeGraphCreateFlag( FALSE ) ; SetCreateDrawValidGraphChannelNum( 4 ) ; SetCreateGraphColorBitDepth( 32 ) ; // 深度記録画像描画用の頂点シェーダーを読み込む Skin4_DepthShadow_Step1_VertexShader = LoadVertexShader( "SkinMesh4_DepthShadow_Step1VS.vso" ) ; Normal_DepthShadow_Step1_VertexShader = LoadVertexShader( "NormalMesh_DepthShadow_Step1VS.vso" ) ; // 深度記録画像描画用のピクセルシェーダーを読み込む DepthShadow_Step1_PixelShader = LoadPixelShader( "DepthShadow_Step1PS.pso" ) ; // 深度記録画像を使ったディレクショナルライト一つの描画用頂点シェーダーを読み込む Skin4_DirLight_DepthShadow_Step2_VertexShader = LoadVertexShader( "SkinMesh4_DirLight_DepthShadow_Step2VS.vso" ) ; Normal_DirLight_DepthShadow_Step2_VertexShader = LoadVertexShader( "NormalMesh_DirLight_DepthShadow_Step2VS.vso" ) ; // 深度記録画像を使ったディレクショナルライト一つの描画用ピクセルシェーダーを読み込む DirLight_DepthShadow_Step2_PixelShader = LoadPixelShader( "DirLight_DepthShadow_Step2PS.pso" ) ; }
//============================================================================= // draw //============================================================================= void GameScore::Draw(void) { auto graphic_device = GET_GRAPHIC_DEVICE(); auto basic_vs = graphic_device->LoadVertexShader("resources/shader/basic.vsc"); auto basic_ps = graphic_device->LoadPixelShader("resources/shader/basic.psc"); //スコア数字の描画 for (int j = 0; j < (unsigned int)TEAM::MAX; j++) { for (int i = 0; i < SCORE_DIGIT; i++) { basic_vs->SetValue("_world_matrix", (f32*)&num_object_[j][i]->GetMatrix(), sizeof(float4x4)); basic_ps->SetTexture("_texture_sampler", num_object_[j][i]->GetTexture(digit_num_[j][i])); num_object_[j][i]->Draw(); } } }
//============================================================================================================================== bool ShadowMapBuildShader::Initialize() { ConstantBuffer<cbShadowMapConst> shadowMapCB(m_pD3DSystem); shadowMapCB.Initialize(PAD16(sizeof(cbShadowMapConst))); m_pShadowMapCB = shadowMapCB.Buffer(); ClearInputLayout(); //SetInputLayoutDesc("ShadowMapBuildShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos, 1); SetInputLayoutDesc("ShadowMapBuildShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); LoadVertexShader("ShadowMapBuilderVS"); LoadPixelShader("ShadowMapBuilderPS"); AssignVertexShaderLayout("ShadowMapBuildShader"); return true; }
int CDirect3D::Start(void) { #if LOG_D3D LOG_MSG("D3D:Worker thread %u starting", SDL_ThreadID()); #endif SDL_SemPost(thread_ack); EnterCriticalSection(&cs); while(thread_run) { HRESULT hr; D3D_state tmp = thread_command; LeaveCriticalSection(&cs); if(tmp == D3D_IDLE) { SDL_SemWait(thread_sem); EnterCriticalSection(&cs); continue; } switch(tmp) { case D3D_LOADPS: hr = LoadPixelShader(); break; case D3D_LOCK: hr = LockTexture(); break; case D3D_UNLOCK: (UnlockTexture() ? hr = S_OK : hr = E_FAIL); break; default: hr = S_OK; break; } EnterCriticalSection(&cs); thread_hr = hr; thread_command = D3D_IDLE; if(wait) { LeaveCriticalSection(&cs); SDL_SemPost(thread_ack); EnterCriticalSection(&cs); } } #if LOG_D3D LOG_MSG("D3D:Thread %u is finishing...", SDL_ThreadID()); #endif LeaveCriticalSection(&cs); return 0; }
//============================================================================================================================== bool TerrainTessellationQuadSSAOShader::Initialize() { ConstantBuffer<cTessellationBuffer> tessellationCB(m_pD3DSystem); tessellationCB.Initialize(PAD16(sizeof(cTessellationBuffer))); m_pTessellationCB = tessellationCB.Buffer(); ConstantBuffer<cDomainConstBuffer> domainCB(m_pD3DSystem); domainCB.Initialize(PAD16(sizeof(cDomainConstBuffer))); m_pDomainCB = domainCB.Buffer(); ConstantBuffer<cMatrixBuffer> matrixBufferCB(m_pD3DSystem); matrixBufferCB.Initialize(PAD16(sizeof(cMatrixBuffer))); m_pMatrixBufferCB = matrixBufferCB.Buffer(); ConstantBuffer<cShadingConstBuffer> shadingCB(m_pD3DSystem); shadingCB.Initialize(PAD16(sizeof(cShadingConstBuffer))); m_pShadingCB = shadingCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbLightBuffer> lightCB(m_pD3DSystem); lightCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbLightBuffer))); m_pLightCB = lightCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbSunLightBuffer> sunCB(m_pD3DSystem); sunCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbSunLightBuffer))); m_pSunCB = sunCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("TerrainTessellationQuadSSAOShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_tex, 2); LoadVertexShader("TerrainTessellationQuadVS"); LoadHullShader("TerrainTessellationQuadShadowHS"); LoadDomainShader("TerrainTessellationQuadDS"); LoadPixelShader("TerrainTessellationNormalDepthPS"); AssignVertexShaderLayout("TerrainTessellationQuadSSAOShader"); return true; }
//todo: this function is an abomination, this is just disgusting. fix it. //...seriously, this is really, really horrible. I mean this is amazingly bad. void OBS::MainCaptureLoop() { int curRenderTarget = 0, curYUVTexture = 0, curCopyTexture = 0; int copyWait = NUM_RENDER_BUFFERS-1; bSentHeaders = false; bFirstAudioPacket = true; bool bLogLongFramesProfile = GlobalConfig->GetInt(TEXT("General"), TEXT("LogLongFramesProfile"), LOGLONGFRAMESDEFAULT) != 0; float logLongFramesProfilePercentage = GlobalConfig->GetFloat(TEXT("General"), TEXT("LogLongFramesProfilePercentage"), 10.f); Vect2 baseSize = Vect2(float(baseCX), float(baseCY)); Vect2 outputSize = Vect2(float(outputCX), float(outputCY)); Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY)); HANDLE hMatrix = yuvScalePixelShader->GetParameterByName(TEXT("yuvMat")); HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI")); //---------------------------------------- // x264 input buffers int curOutBuffer = 0; bool bUsingQSV = videoEncoder->isQSV();//GlobalConfig->GetInt(TEXT("Video Encoding"), TEXT("UseQSV")) != 0; bUsing444 = false; EncoderPicture lastPic; EncoderPicture outPics[NUM_OUT_BUFFERS]; for(int i=0; i<NUM_OUT_BUFFERS; i++) { if(bUsingQSV) { outPics[i].mfxOut = new mfxFrameSurface1; memset(outPics[i].mfxOut, 0, sizeof(mfxFrameSurface1)); mfxFrameData& data = outPics[i].mfxOut->Data; videoEncoder->RequestBuffers(&data); } else { outPics[i].picOut = new x264_picture_t; x264_picture_init(outPics[i].picOut); } } if(bUsing444) { for(int i=0; i<NUM_OUT_BUFFERS; i++) { outPics[i].picOut->img.i_csp = X264_CSP_BGRA; //although the x264 input says BGR, x264 actually will expect packed UYV outPics[i].picOut->img.i_plane = 1; } } else { if(!bUsingQSV) for(int i=0; i<NUM_OUT_BUFFERS; i++) x264_picture_alloc(outPics[i].picOut, X264_CSP_NV12, outputCX, outputCY); } int bCongestionControl = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("CongestionControl"), 0); bool bDynamicBitrateSupported = App->GetVideoEncoder()->DynamicBitrateSupported(); int defaultBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int currentBitRate = defaultBitRate; QWORD lastAdjustmentTime = 0; UINT adjustmentStreamId = 0; //std::unique_ptr<ProfilerNode> encodeThreadProfiler; //---------------------------------------- // time/timestamp stuff bool bWasLaggedFrame = false; totalStreamTime = 0; lastAudioTimestamp = 0; //---------------------------------------- // start audio capture streams desktopAudio->StartCapture(); if(micAudio) micAudio->StartCapture(); //---------------------------------------- // status bar/statistics stuff DWORD fpsCounter = 0; int numLongFrames = 0; int numTotalFrames = 0; bytesPerSec = 0; captureFPS = 0; curFramesDropped = 0; curStrain = 0.0; PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); QWORD lastBytesSent[3] = {0, 0, 0}; DWORD lastFramesDropped = 0; double bpsTime = 0.0; double lastStrain = 0.0f; DWORD numSecondsWaited = 0; //---------------------------------------- // 444->420 thread data int numThreads = MAX(OSGetTotalCores()-2, 1); HANDLE *h420Threads = (HANDLE*)Allocate(sizeof(HANDLE)*numThreads); Convert444Data *convertInfo = (Convert444Data*)Allocate(sizeof(Convert444Data)*numThreads); zero(h420Threads, sizeof(HANDLE)*numThreads); zero(convertInfo, sizeof(Convert444Data)*numThreads); for(int i=0; i<numThreads; i++) { convertInfo[i].width = outputCX; convertInfo[i].height = outputCY; convertInfo[i].hSignalConvert = CreateEvent(NULL, FALSE, FALSE, NULL); convertInfo[i].hSignalComplete = CreateEvent(NULL, FALSE, FALSE, NULL); convertInfo[i].bNV12 = bUsingQSV; convertInfo[i].numThreads = numThreads; if(i == 0) convertInfo[i].startY = 0; else convertInfo[i].startY = convertInfo[i-1].endY; if(i == (numThreads-1)) convertInfo[i].endY = outputCY; else convertInfo[i].endY = ((outputCY/numThreads)*(i+1)) & 0xFFFFFFFE; } bool bEncode; bool bFirstFrame = true; bool bFirstImage = true; bool bFirstEncode = true; bool bUseThreaded420 = bUseMultithreadedOptimizations && (OSGetTotalCores() > 1) && !bUsing444; List<HANDLE> completeEvents; if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { h420Threads[i] = OSCreateThread((XTHREAD)Convert444Thread, convertInfo+i); completeEvents << convertInfo[i].hSignalComplete; } } //---------------------------------------- QWORD streamTimeStart = GetQPCTimeNS(); QWORD lastStreamTime = 0; QWORD firstFrameTimeMS = streamTimeStart/1000000; QWORD frameLengthNS = 1000000000/fps; while(WaitForSingleObject(hVideoEvent, INFINITE) == WAIT_OBJECT_0) { if (bShutdownVideoThread) break; QWORD renderStartTime = GetQPCTimeNS(); totalStreamTime = DWORD((renderStartTime-streamTimeStart)/1000000); bool bRenderView = !IsIconic(hwndMain) && bRenderViewEnabled; QWORD renderStartTimeMS = renderStartTime/1000000; QWORD curStreamTime = latestVideoTimeNS; if (!lastStreamTime) lastStreamTime = curStreamTime-frameLengthNS; QWORD frameDelta = curStreamTime-lastStreamTime; //if (!lastStreamTime) // lastStreamTime = renderStartTime-frameLengthNS; //QWORD frameDelta = renderStartTime-lastStreamTime; double fSeconds = double(frameDelta)*0.000000001; //lastStreamTime = renderStartTime; bool bUpdateBPS = false; profileIn("video thread frame"); //Log(TEXT("Stream Time: %llu"), curStreamTime); //Log(TEXT("frameDelta: %lf"), fSeconds); //------------------------------------ if(bRequestKeyframe && keyframeWait > 0) { keyframeWait -= int(frameDelta); if(keyframeWait <= 0) { GetVideoEncoder()->RequestKeyframe(); bRequestKeyframe = false; } } if(!pushToTalkDown && pushToTalkTimeLeft > 0) { pushToTalkTimeLeft -= int(frameDelta); OSDebugOut(TEXT("time left: %d\r\n"), pushToTalkTimeLeft); if(pushToTalkTimeLeft <= 0) { pushToTalkTimeLeft = 0; bPushToTalkOn = false; } } //------------------------------------ OSEnterMutex(hSceneMutex); if (bPleaseEnableProjector) ActuallyEnableProjector(); else if(bPleaseDisableProjector) DisableProjector(); if(bResizeRenderView) { GS->ResizeView(); bResizeRenderView = false; } //------------------------------------ if(scene) { profileIn("scene->Preprocess"); scene->Preprocess(); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Preprocess(); profileOut; scene->Tick(float(fSeconds)); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Tick(float(fSeconds)); } //------------------------------------ QWORD curBytesSent = 0; if (network) { curBytesSent = network->GetCurrentSentBytes(); curFramesDropped = network->NumDroppedFrames(); } else if (numSecondsWaited) { //reset stats if the network disappears bytesPerSec = 0; bpsTime = 0; numSecondsWaited = 0; curBytesSent = 0; zero(lastBytesSent, sizeof(lastBytesSent)); } bpsTime += fSeconds; if(bpsTime > 1.0f) { if(numSecondsWaited < 3) ++numSecondsWaited; //bytesPerSec = DWORD(curBytesSent - lastBytesSent); bytesPerSec = DWORD(curBytesSent - lastBytesSent[0]) / numSecondsWaited; if(bpsTime > 2.0) bpsTime = 0.0f; else bpsTime -= 1.0; if(numSecondsWaited == 3) { lastBytesSent[0] = lastBytesSent[1]; lastBytesSent[1] = lastBytesSent[2]; lastBytesSent[2] = curBytesSent; } else lastBytesSent[numSecondsWaited] = curBytesSent; captureFPS = fpsCounter; fpsCounter = 0; bUpdateBPS = true; } fpsCounter++; if(network) curStrain = network->GetPacketStrain(); EnableBlending(TRUE); BlendFunction(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA); //------------------------------------ // render the mini render texture LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); SetRenderTarget(mainRenderTextures[curRenderTarget]); Ortho(0.0f, baseSize.x, baseSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0, 0, baseSize.x, baseSize.y); if(scene) scene->Render(); //------------------------------------ if(bTransitioning) { if(!transitionTexture) { transitionTexture = CreateTexture(baseCX, baseCY, GS_BGRA, NULL, FALSE, TRUE); if(transitionTexture) { D3D10Texture *d3dTransitionTex = static_cast<D3D10Texture*>(transitionTexture); D3D10Texture *d3dSceneTex = static_cast<D3D10Texture*>(mainRenderTextures[lastRenderTarget]); GetD3D()->CopyResource(d3dTransitionTex->texture, d3dSceneTex->texture); } else bTransitioning = false; } else if(transitionAlpha >= 1.0f) { delete transitionTexture; transitionTexture = NULL; bTransitioning = false; } } if(bTransitioning) { EnableBlending(TRUE); transitionAlpha += float(fSeconds)*5.0f; if(transitionAlpha > 1.0f) transitionAlpha = 1.0f; } else EnableBlending(FALSE); //------------------------------------ // render the mini view thingy if (bProjector) { SetRenderTarget(projectorTexture); Vect2 renderFrameSize, renderFrameOffset; Vect2 projectorSize = Vect2(float(projectorWidth), float(projectorHeight)); float projectorAspect = (projectorSize.x / projectorSize.y); float baseAspect = (baseSize.x / baseSize.y); if (projectorAspect < baseAspect) { float fProjectorWidth = float(projectorWidth); renderFrameSize = Vect2(fProjectorWidth, fProjectorWidth / baseAspect); renderFrameOffset = Vect2(0.0f, (projectorSize.y-renderFrameSize.y) * 0.5f); } else { float fProjectorHeight = float(projectorHeight); renderFrameSize = Vect2(fProjectorHeight * baseAspect, fProjectorHeight); renderFrameOffset = Vect2((projectorSize.x-renderFrameSize.x) * 0.5f, 0.0f); } DrawPreview(renderFrameSize, renderFrameOffset, projectorSize, curRenderTarget, Preview_Projector); SetRenderTarget(NULL); } if(bRenderView) { // Cache const Vect2 renderFrameSize = GetRenderFrameSize(); const Vect2 renderFrameOffset = GetRenderFrameOffset(); const Vect2 renderFrameCtrlSize = GetRenderFrameControlSize(); SetRenderTarget(NULL); DrawPreview(renderFrameSize, renderFrameOffset, renderFrameCtrlSize, curRenderTarget, bFullscreenMode ? Preview_Fullscreen : Preview_Standard); //draw selections if in edit mode if(bEditMode && !bSizeChanging) { if(scene) { LoadVertexShader(solidVertexShader); LoadPixelShader(solidPixelShader); solidPixelShader->SetColor(solidPixelShader->GetParameter(0), 0xFF0000); scene->RenderSelections(solidPixelShader); } } } else if(bForceRenderViewErase) { InvalidateRect(hwndRenderFrame, NULL, TRUE); UpdateWindow(hwndRenderFrame); bForceRenderViewErase = false; } //------------------------------------ // actual stream output LoadVertexShader(mainVertexShader); LoadPixelShader(yuvScalePixelShader); Texture *yuvRenderTexture = yuvRenderTextures[curRenderTarget]; SetRenderTarget(yuvRenderTexture); switch(colorDesc.matrix) { case ColorMatrix_GBR: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[0] : (float*)yuvMat[0]); break; case ColorMatrix_YCgCo: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[1] : (float*)yuvMat[1]); break; case ColorMatrix_BT2020NCL: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[2] : (float*)yuvMat[2]); break; case ColorMatrix_BT709: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[3] : (float*)yuvMat[3]); break; case ColorMatrix_SMPTE240M: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[4] : (float*)yuvMat[4]); break; default: yuvScalePixelShader->SetMatrix(hMatrix, colorDesc.fullRange ? (float*)yuvFullMat[5] : (float*)yuvMat[5]); } if(downscale < 2.01) yuvScalePixelShader->SetVector2(hScaleVal, 1.0f/baseSize); else if(downscale < 3.01) yuvScalePixelShader->SetVector2(hScaleVal, 1.0f/(outputSize*3.0f)); Ortho(0.0f, outputSize.x, outputSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0.0f, 0.0f, outputSize.x, outputSize.y); //why am I using scaleSize instead of outputSize for the texture? //because outputSize can be trimmed by up to three pixels due to 128-bit alignment. //using the scale function with outputSize can cause slightly inaccurate scaled images if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); DrawSpriteEx(transitionTexture, 0xFFFFFFFF, 0.0f, 0.0f, scaleSize.x, scaleSize.y, 0.0f, 0.0f, 1.0f, 1.0f); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } DrawSpriteEx(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, 0.0f, 0.0f, outputSize.x, outputSize.y, 0.0f, 0.0f, 1.0f, 1.0f); //------------------------------------ if (bProjector && !copyWait) projectorSwap->Present(0, 0); if(bRenderView && !copyWait) static_cast<D3D10System*>(GS)->swap->Present(0, 0); OSLeaveMutex(hSceneMutex); //------------------------------------ // present/upload profileIn("GPU download and conversion"); bEncode = true; if(copyWait) { copyWait--; bEncode = false; } else { //audio sometimes takes a bit to start -- do not start processing frames until audio has started capturing if(!bRecievedFirstAudioFrame) { static bool bWarnedAboutNoAudio = false; if (renderStartTimeMS-firstFrameTimeMS > 10000 && !bWarnedAboutNoAudio) { bWarnedAboutNoAudio = true; //AddStreamInfo (TEXT ("WARNING: OBS is not receiving audio frames. Please check your audio devices."), StreamInfoPriority_Critical); } bEncode = false; } else if(bFirstFrame) { firstFrameTimestamp = lastStreamTime/1000000; bFirstFrame = false; } if(!bEncode) { if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; } } lastStreamTime = curStreamTime; if(bEncode) { UINT prevCopyTexture = (curCopyTexture == 0) ? NUM_RENDER_BUFFERS-1 : curCopyTexture-1; ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; profileIn("CopyResource"); if(!bFirstEncode && bUseThreaded420) { WaitForMultipleObjects(completeEvents.Num(), completeEvents.Array(), TRUE, INFINITE); copyTexture->Unmap(0); } D3D10Texture *d3dYUV = static_cast<D3D10Texture*>(yuvRenderTextures[curYUVTexture]); GetD3D()->CopyResource(copyTexture, d3dYUV->texture); profileOut; ID3D10Texture2D *prevTexture = copyTextures[prevCopyTexture]; if(bFirstImage) //ignore the first frame bFirstImage = false; else { HRESULT result; D3D10_MAPPED_TEXTURE2D map; if(SUCCEEDED(result = prevTexture->Map(0, D3D10_MAP_READ, 0, &map))) { int prevOutBuffer = (curOutBuffer == 0) ? NUM_OUT_BUFFERS-1 : curOutBuffer-1; int nextOutBuffer = (curOutBuffer == NUM_OUT_BUFFERS-1) ? 0 : curOutBuffer+1; EncoderPicture &prevPicOut = outPics[prevOutBuffer]; EncoderPicture &picOut = outPics[curOutBuffer]; EncoderPicture &nextPicOut = outPics[nextOutBuffer]; if(!bUsing444) { profileIn("conversion to 4:2:0"); if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { convertInfo[i].input = (LPBYTE)map.pData; convertInfo[i].inPitch = map.RowPitch; if(bUsingQSV) { mfxFrameData& data = nextPicOut.mfxOut->Data; videoEncoder->RequestBuffers(&data); convertInfo[i].outPitch = data.Pitch; convertInfo[i].output[0] = data.Y; convertInfo[i].output[1] = data.UV; } else { convertInfo[i].output[0] = nextPicOut.picOut->img.plane[0]; convertInfo[i].output[1] = nextPicOut.picOut->img.plane[1]; convertInfo[i].output[2] = nextPicOut.picOut->img.plane[2]; } SetEvent(convertInfo[i].hSignalConvert); } if(bFirstEncode) bFirstEncode = bEncode = false; } else { if(bUsingQSV) { mfxFrameData& data = picOut.mfxOut->Data; videoEncoder->RequestBuffers(&data); LPBYTE output[] = {data.Y, data.UV}; Convert444toNV12((LPBYTE)map.pData, outputCX, map.RowPitch, data.Pitch, outputCY, 0, outputCY, output); } else Convert444toNV12((LPBYTE)map.pData, outputCX, map.RowPitch, outputCX, outputCY, 0, outputCY, picOut.picOut->img.plane); prevTexture->Unmap(0); } profileOut; } if(bEncode) { //encodeThreadProfiler.reset(::new ProfilerNode(TEXT("EncodeThread"), true)); //encodeThreadProfiler->MonitorThread(hEncodeThread); curFramePic = &picOut; } curOutBuffer = nextOutBuffer; } else { //We have to crash, or we end up deadlocking the thread when the convert threads are never signalled if (result == DXGI_ERROR_DEVICE_REMOVED) { String message; HRESULT reason = GetD3D()->GetDeviceRemovedReason(); switch (reason) { case DXGI_ERROR_DEVICE_RESET: case DXGI_ERROR_DEVICE_HUNG: message = TEXT("Your video card or driver froze and was reset. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_DEVICE_REMOVED: message = TEXT("Your video card disappeared from the system. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_DRIVER_INTERNAL_ERROR: message = TEXT("Your video driver reported an internal error. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_INVALID_CALL: message = TEXT("Your video driver reported an invalid call. Please check for possible driver issues."); break; default: message = TEXT("DXGI_ERROR_DEVICE_REMOVED"); break; } message << TEXT(" This error can also occur if you have enabled opencl in x264 custom settings."); CrashError (TEXT("Texture->Map failed: 0x%08x 0x%08x\r\n\r\n%s"), result, reason, message.Array()); } else CrashError (TEXT("Texture->Map failed: 0x%08x"), result); } } if(curCopyTexture == (NUM_RENDER_BUFFERS-1)) curCopyTexture = 0; else curCopyTexture++; if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; if (bCongestionControl && bDynamicBitrateSupported && !bTestStream && totalStreamTime > 15000) { if (curStrain > 25) { if (renderStartTimeMS - lastAdjustmentTime > 1500) { if (currentBitRate > 100) { currentBitRate = (int)(currentBitRate * (1.0 - (curStrain / 400))); App->GetVideoEncoder()->SetBitRate(currentBitRate, -1); if (!adjustmentStreamId) adjustmentStreamId = App->AddStreamInfo (FormattedString(TEXT("Congestion detected, dropping bitrate to %d kbps"), currentBitRate).Array(), StreamInfoPriority_Low); else App->SetStreamInfo(adjustmentStreamId, FormattedString(TEXT("Congestion detected, dropping bitrate to %d kbps"), currentBitRate).Array()); bUpdateBPS = true; } lastAdjustmentTime = renderStartTimeMS; } } else if (currentBitRate < defaultBitRate && curStrain < 5 && lastStrain < 5) { if (renderStartTimeMS - lastAdjustmentTime > 5000) { if (currentBitRate < defaultBitRate) { currentBitRate += (int)(defaultBitRate * 0.05); if (currentBitRate > defaultBitRate) currentBitRate = defaultBitRate; } App->GetVideoEncoder()->SetBitRate(currentBitRate, -1); /*if (!adjustmentStreamId) App->AddStreamInfo (FormattedString(TEXT("Congestion clearing, raising bitrate to %d kbps"), currentBitRate).Array(), StreamInfoPriority_Low); else App->SetStreamInfo(adjustmentStreamId, FormattedString(TEXT("Congestion clearing, raising bitrate to %d kbps"), currentBitRate).Array());*/ App->RemoveStreamInfo(adjustmentStreamId); adjustmentStreamId = 0; bUpdateBPS = true; lastAdjustmentTime = renderStartTimeMS; } } } } lastRenderTarget = curRenderTarget; if(curRenderTarget == (NUM_RENDER_BUFFERS-1)) curRenderTarget = 0; else curRenderTarget++; if(bUpdateBPS || !CloseDouble(curStrain, lastStrain) || curFramesDropped != lastFramesDropped) { PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); lastStrain = curStrain; lastFramesDropped = curFramesDropped; } //------------------------------------ // we're about to sleep so we should flush the d3d command queue profileIn("flush"); GetD3D()->Flush(); profileOut; profileOut; profileOut; //frame //------------------------------------ // frame sync //QWORD renderStopTime = GetQPCTimeNS(); if(bWasLaggedFrame = (frameDelta > frameLengthNS)) { numLongFrames++; if(bLogLongFramesProfile && (numLongFrames/float(max(1, numTotalFrames)) * 100.) > logLongFramesProfilePercentage) DumpLastProfileData(); } //OSDebugOut(TEXT("Frame adjust time: %d, "), frameTimeAdjust-totalTime); numTotalFrames++; } DisableProjector(); //encodeThreadProfiler.reset(); if(!bUsing444) { if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { if(h420Threads[i]) { convertInfo[i].bKillThread = true; SetEvent(convertInfo[i].hSignalConvert); OSTerminateThread(h420Threads[i], 10000); h420Threads[i] = NULL; } if(convertInfo[i].hSignalConvert) { CloseHandle(convertInfo[i].hSignalConvert); convertInfo[i].hSignalConvert = NULL; } if(convertInfo[i].hSignalComplete) { CloseHandle(convertInfo[i].hSignalComplete); convertInfo[i].hSignalComplete = NULL; } } if(!bFirstEncode) { ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; copyTexture->Unmap(0); } } if(bUsingQSV) for(int i = 0; i < NUM_OUT_BUFFERS; i++) delete outPics[i].mfxOut; else for(int i=0; i<NUM_OUT_BUFFERS; i++) { x264_picture_clean(outPics[i].picOut); delete outPics[i].picOut; } } Free(h420Threads); Free(convertInfo); Log(TEXT("Total frames rendered: %d, number of late frames: %d (%0.2f%%) (it's okay for some frames to be late)"), numTotalFrames, numLongFrames, (numTotalFrames > 0) ? (double(numLongFrames)/double(numTotalFrames))*100.0 : 0.0f); }
//============================================================================= // draw //============================================================================= void Title::Draw() { auto graphic_device = GET_GRAPHIC_DEVICE(); auto gb_vs = graphic_device->LoadVertexShader("resources/shader/graphics_buffer.vsc"); auto gb_ps = graphic_device->LoadPixelShader("resources/shader/graphics_buffer.psc"); auto d_vs = graphic_device->LoadVertexShader("resources/shader/deferred.vsc"); auto d_ps = graphic_device->LoadPixelShader("resources/shader/deferred.psc"); auto basic_vs = graphic_device->LoadVertexShader("resources/shader/basic.vsc"); auto basic_ps = graphic_device->LoadPixelShader("resources/shader/basic.psc"); //画面クリア graphic_device->Clear(float4(1.0f, 1.0f, 1.0f, 1.0f), 1.0f); //デバッグワイヤーフレーム // graphic_device->GetDevice()->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); float4 color(1.0f, 1.0f, 1.0f, 1.0f); //シェーダ設定 graphic_device->SetVertexShader(basic_vs); graphic_device->SetPixelShader(basic_ps); basic_vs->SetValue("_view_matrix", (f32*)&observer_2d_->GetViewMatrix(), 16); basic_vs->SetValue("_projection_matrix", (f32*)&observer_2d_->GetProjectionMatrix(), 16); basic_vs->SetValue("_world_matrix", (f32*)&background_->GetMatrix(), 16); basic_vs->SetValue("_color", (f32*)&color,4); basic_ps->SetTexture("_texture_sampler", background_->GetTexture(0)->GetTexture()); //背景 background_->Draw(); //パーティクル for (u32 i = 0; i < PARTICUL_MAX; ++i) { basic_vs->SetValue("_world_matrix", (f32*)&particul_[i].particul_->GetMatrix(), 16); basic_vs->SetValue("_color", (f32*)&color, 4); basic_ps->SetTexture("_texture_sampler", particul_[i].particul_->GetTexture(0)->GetTexture()); //ロゴ particul_[i].particul_->Draw(); } basic_vs->SetValue("_world_matrix", (f32*)&logo_->GetMatrix(), 16); basic_vs->SetValue("_color", (f32*)&color, 4); basic_ps->SetTexture("_texture_sampler", logo_->GetTexture(0)->GetTexture()); //ロゴ logo_->Draw(); draw_cnt_++; if (draw_cnt_ > 100) { use_flag_ = true; } if (draw_cnt_ > 200) { draw_cnt_ = 0; use_flag_ = false; } if (use_flag_) { //ボタン背景 basic_vs->SetValue("_world_matrix", (f32*)&button_interface_->GetMatrix(), 16); basic_vs->SetValue("_color", (f32*)&color, 4); basic_ps->SetTexture("_texture_sampler", button_interface_->GetTexture(0)->GetTexture()); //ボタン背景 button_interface_->Draw(); basic_vs->SetValue("_world_matrix", (f32*)&button_->GetMatrix(), 16); basic_vs->SetValue("_color", (f32*)&color, 4); basic_ps->SetTexture("_texture_sampler", button_->GetTexture(0)->GetTexture()); //ボタン button_->Draw(); } }
//todo: this function is an abomination, this is just disgusting. fix it. //...seriously, this is really, really horrible. I mean this is amazingly bad. void OBS::MainCaptureLoop() { int curRenderTarget = 0, curYUVTexture = 0, curCopyTexture = 0; int copyWait = NUM_RENDER_BUFFERS-1; bSentHeaders = false; bFirstAudioPacket = true; bool bLogLongFramesProfile = GlobalConfig->GetInt(TEXT("General"), TEXT("LogLongFramesProfile"), LOGLONGFRAMESDEFAULT) != 0; float logLongFramesProfilePercentage = GlobalConfig->GetFloat(TEXT("General"), TEXT("LogLongFramesProfilePercentage"), 10.f); Vect2 baseSize = Vect2(float(baseCX), float(baseCY)); Vect2 outputSize = Vect2(float(outputCX), float(outputCY)); Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY)); HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI")); //---------------------------------------- // x264 input buffers int curOutBuffer = 0; bool bUsingQSV = videoEncoder->isQSV();//GlobalConfig->GetInt(TEXT("Video Encoding"), TEXT("UseQSV")) != 0; if(bUsingQSV) bUsing444 = false; EncoderPicture lastPic; EncoderPicture outPics[NUM_OUT_BUFFERS]; DWORD outTimes[NUM_OUT_BUFFERS] = {0, 0, 0}; for(int i=0; i<NUM_OUT_BUFFERS; i++) { if(bUsingQSV) { outPics[i].mfxOut = new mfxFrameSurface1; memset(outPics[i].mfxOut, 0, sizeof(mfxFrameSurface1)); mfxFrameData& data = outPics[i].mfxOut->Data; videoEncoder->RequestBuffers(&data); } else { outPics[i].picOut = new x264_picture_t; x264_picture_init(outPics[i].picOut); } } if(bUsing444) { for(int i=0; i<NUM_OUT_BUFFERS; i++) { outPics[i].picOut->img.i_csp = X264_CSP_BGRA; //although the x264 input says BGR, x264 actually will expect packed UYV outPics[i].picOut->img.i_plane = 1; } } else { if(!bUsingQSV) for(int i=0; i<NUM_OUT_BUFFERS; i++) x264_picture_alloc(outPics[i].picOut, X264_CSP_NV12, outputCX, outputCY); } int bCongestionControl = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("CongestionControl"), 0); bool bDynamicBitrateSupported = App->GetVideoEncoder()->DynamicBitrateSupported(); int defaultBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int currentBitRate = defaultBitRate; QWORD lastAdjustmentTime = 0; UINT adjustmentStreamId = 0; //---------------------------------------- // time/timestamp stuff bufferedTimes.Clear(); ctsOffsets.Clear(); int bufferedFrames = 1; //to avoid constantly polling number of frames #ifdef USE_100NS_TIME QWORD streamTimeStart = GetQPCTime100NS(); QWORD frameTime100ns = 10000000/fps; QWORD sleepTargetTime = 0; bool bWasLaggedFrame = false; #else DWORD streamTimeStart = OSGetTime(); DWORD fpsTimeAdjust = 0; #endif totalStreamTime = 0; lastAudioTimestamp = 0; latestVideoTime = firstSceneTimestamp = GetQPCTimeMS(); DWORD fpsTimeNumerator = 1000-(frameTime*fps); DWORD fpsTimeDenominator = fps; DWORD cfrTime = 0; DWORD cfrTimeAdjust = 0; //---------------------------------------- // start audio capture streams desktopAudio->StartCapture(); if(micAudio) micAudio->StartCapture(); //---------------------------------------- // status bar/statistics stuff DWORD fpsCounter = 0; int numLongFrames = 0; int numTotalFrames = 0; int numTotalDuplicatedFrames = 0; bytesPerSec = 0; captureFPS = 0; curFramesDropped = 0; curStrain = 0.0; PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); QWORD lastBytesSent[3] = {0, 0, 0}; DWORD lastFramesDropped = 0; #ifdef USE_100NS_TIME double bpsTime = 0.0; #else float bpsTime = 0.0f; #endif double lastStrain = 0.0f; DWORD numSecondsWaited = 0; //---------------------------------------- // 444->420 thread data int numThreads = MAX(OSGetTotalCores()-2, 1); HANDLE *h420Threads = (HANDLE*)Allocate(sizeof(HANDLE)*numThreads); Convert444Data *convertInfo = (Convert444Data*)Allocate(sizeof(Convert444Data)*numThreads); zero(h420Threads, sizeof(HANDLE)*numThreads); zero(convertInfo, sizeof(Convert444Data)*numThreads); for(int i=0; i<numThreads; i++) { convertInfo[i].width = outputCX; convertInfo[i].height = outputCY; convertInfo[i].hSignalConvert = CreateEvent(NULL, FALSE, FALSE, NULL); convertInfo[i].hSignalComplete = CreateEvent(NULL, FALSE, FALSE, NULL); convertInfo[i].bNV12 = bUsingQSV; if(i == 0) convertInfo[i].startY = 0; else convertInfo[i].startY = convertInfo[i-1].endY; if(i == (numThreads-1)) convertInfo[i].endY = outputCY; else convertInfo[i].endY = ((outputCY/numThreads)*(i+1)) & 0xFFFFFFFE; } bool bFirstFrame = true; bool bFirstImage = true; bool bFirst420Encode = true; bool bUseThreaded420 = bUseMultithreadedOptimizations && (OSGetTotalCores() > 1) && !bUsing444; List<HANDLE> completeEvents; if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { h420Threads[i] = OSCreateThread((XTHREAD)Convert444Thread, convertInfo+i); completeEvents << convertInfo[i].hSignalComplete; } } //---------------------------------------- QWORD curStreamTime = 0, lastStreamTime, firstFrameTime = GetQPCTimeMS(); #ifdef USE_100NS_TIME lastStreamTime = GetQPCTime100NS()-frameTime100ns; #else lastStreamTime = firstFrameTime-frameTime; #endif //bool bFirstAudioPacket = true; List<ProfilerNode> threadedProfilers; bool bUsingThreadedProfilers = false; while(bRunning || bufferedFrames) { #ifdef USE_100NS_TIME QWORD renderStartTime = GetQPCTime100NS(); totalStreamTime = DWORD((renderStartTime-streamTimeStart)/10000); if(sleepTargetTime == 0 || bWasLaggedFrame) sleepTargetTime = renderStartTime; #else DWORD renderStartTime = OSGetTime(); totalStreamTime = renderStartTime-streamTimeStart; DWORD frameTimeAdjust = frameTime; fpsTimeAdjust += fpsTimeNumerator; if(fpsTimeAdjust > fpsTimeDenominator) { fpsTimeAdjust -= fpsTimeDenominator; ++frameTimeAdjust; } #endif bool bRenderView = !IsIconic(hwndMain) && bRenderViewEnabled; profileIn("frame"); #ifdef USE_100NS_TIME QWORD qwTime = renderStartTime/10000; latestVideoTime = qwTime; QWORD frameDelta = renderStartTime-lastStreamTime; double fSeconds = double(frameDelta)*0.0000001; //Log(TEXT("frameDelta: %f"), fSeconds); lastStreamTime = renderStartTime; #else QWORD qwTime = GetQPCTimeMS(); latestVideoTime = qwTime; QWORD frameDelta = qwTime-lastStreamTime; float fSeconds = float(frameDelta)*0.001f; //Log(TEXT("frameDelta: %llu"), frameDelta); lastStreamTime = qwTime; #endif bool bUpdateBPS = false; profileIn("frame preprocessing and rendering"); //------------------------------------ if(bRequestKeyframe && keyframeWait > 0) { keyframeWait -= int(frameDelta); if(keyframeWait <= 0) { GetVideoEncoder()->RequestKeyframe(); bRequestKeyframe = false; } } if(!bPushToTalkDown && pushToTalkTimeLeft > 0) { pushToTalkTimeLeft -= int(frameDelta); OSDebugOut(TEXT("time left: %d\r\n"), pushToTalkTimeLeft); if(pushToTalkTimeLeft <= 0) { pushToTalkTimeLeft = 0; bPushToTalkOn = false; } } //------------------------------------ OSEnterMutex(hSceneMutex); if(bResizeRenderView) { GS->ResizeView(); bResizeRenderView = false; } //------------------------------------ if(scene) { profileIn("scene->Preprocess"); scene->Preprocess(); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Preprocess(); profileOut; scene->Tick(float(fSeconds)); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Tick(float(fSeconds)); } //------------------------------------ QWORD curBytesSent = network->GetCurrentSentBytes(); curFramesDropped = network->NumDroppedFrames(); bpsTime += fSeconds; if(bpsTime > 1.0f) { if(numSecondsWaited < 3) ++numSecondsWaited; //bytesPerSec = DWORD(curBytesSent - lastBytesSent); bytesPerSec = DWORD(curBytesSent - lastBytesSent[0]) / numSecondsWaited; if(bpsTime > 2.0) bpsTime = 0.0f; else bpsTime -= 1.0; if(numSecondsWaited == 3) { lastBytesSent[0] = lastBytesSent[1]; lastBytesSent[1] = lastBytesSent[2]; lastBytesSent[2] = curBytesSent; } else lastBytesSent[numSecondsWaited] = curBytesSent; captureFPS = fpsCounter; fpsCounter = 0; bUpdateBPS = true; } fpsCounter++; curStrain = network->GetPacketStrain(); EnableBlending(TRUE); BlendFunction(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA); //------------------------------------ // render the mini render texture LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); SetRenderTarget(mainRenderTextures[curRenderTarget]); Ortho(0.0f, baseSize.x, baseSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0, 0, baseSize.x, baseSize.y); if(scene) scene->Render(); //------------------------------------ if(bTransitioning) { if(!transitionTexture) { transitionTexture = CreateTexture(baseCX, baseCY, GS_BGRA, NULL, FALSE, TRUE); if(transitionTexture) { D3D10Texture *d3dTransitionTex = static_cast<D3D10Texture*>(transitionTexture); D3D10Texture *d3dSceneTex = static_cast<D3D10Texture*>(mainRenderTextures[lastRenderTarget]); GetD3D()->CopyResource(d3dTransitionTex->texture, d3dSceneTex->texture); } else bTransitioning = false; } else if(transitionAlpha >= 1.0f) { delete transitionTexture; transitionTexture = NULL; bTransitioning = false; } } if(bTransitioning) { EnableBlending(TRUE); transitionAlpha += float(fSeconds)*5.0f; if(transitionAlpha > 1.0f) transitionAlpha = 1.0f; } else EnableBlending(FALSE); //------------------------------------ // render the mini view thingy if(bRenderView) { // Cache const Vect2 renderFrameSize = GetRenderFrameSize(); const Vect2 renderFrameOffset = GetRenderFrameOffset(); const Vect2 renderFrameCtrlSize = GetRenderFrameControlSize(); SetRenderTarget(NULL); LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); Ortho(0.0f, renderFrameCtrlSize.x, renderFrameCtrlSize.y, 0.0f, -100.0f, 100.0f); if(renderFrameCtrlSize.x != oldRenderFrameCtrlWidth || renderFrameCtrlSize.y != oldRenderFrameCtrlHeight) { // User is drag resizing the window. We don't recreate the swap chains so our coordinates are wrong SetViewport(0.0f, 0.0f, (float)oldRenderFrameCtrlWidth, (float)oldRenderFrameCtrlHeight); } else SetViewport(0.0f, 0.0f, renderFrameCtrlSize.x, renderFrameCtrlSize.y); // Draw background (Black if fullscreen, window colour otherwise) if(bFullscreenMode) ClearColorBuffer(0x000000); else ClearColorBuffer(GetSysColor(COLOR_BTNFACE)); if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); DrawSprite(transitionTexture, 0xFFFFFFFF, renderFrameOffset.x, renderFrameOffset.y, renderFrameOffset.x + renderFrameSize.x, renderFrameOffset.y + renderFrameSize.y); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } DrawSprite(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, renderFrameOffset.x, renderFrameOffset.y, renderFrameOffset.x + renderFrameSize.x, renderFrameOffset.y + renderFrameSize.y); //draw selections if in edit mode if(bEditMode && !bSizeChanging) { if(scene) { LoadVertexShader(solidVertexShader); LoadPixelShader(solidPixelShader); solidPixelShader->SetColor(solidPixelShader->GetParameter(0), 0xFF0000); scene->RenderSelections(solidPixelShader); } } } else if(bForceRenderViewErase) { InvalidateRect(hwndRenderFrame, NULL, TRUE); UpdateWindow(hwndRenderFrame); bForceRenderViewErase = false; } //------------------------------------ // actual stream output LoadVertexShader(mainVertexShader); LoadPixelShader(yuvScalePixelShader); Texture *yuvRenderTexture = yuvRenderTextures[curRenderTarget]; SetRenderTarget(yuvRenderTexture); if(downscale < 2.01) yuvScalePixelShader->SetVector2(hScaleVal, 1.0f/baseSize); else if(downscale < 3.01) yuvScalePixelShader->SetVector2(hScaleVal, 1.0f/(outputSize*3.0f)); Ortho(0.0f, outputSize.x, outputSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0.0f, 0.0f, outputSize.x, outputSize.y); //why am I using scaleSize instead of outputSize for the texture? //because outputSize can be trimmed by up to three pixels due to 128-bit alignment. //using the scale function with outputSize can cause slightly inaccurate scaled images if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); DrawSpriteEx(transitionTexture, 0xFFFFFFFF, 0.0f, 0.0f, scaleSize.x, scaleSize.y, 0.0f, 0.0f, 1.0f, 1.0f); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } DrawSpriteEx(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, 0.0f, 0.0f, outputSize.x, outputSize.y, 0.0f, 0.0f, 1.0f, 1.0f); //------------------------------------ if(bRenderView && !copyWait) static_cast<D3D10System*>(GS)->swap->Present(0, 0); OSLeaveMutex(hSceneMutex); profileOut; //------------------------------------ // present/upload profileIn("video encoding and uploading"); bool bEncode = true; if(copyWait) { copyWait--; bEncode = false; } else { //audio sometimes takes a bit to start -- do not start processing frames until audio has started capturing if(!bRecievedFirstAudioFrame) { static bool bWarnedAboutNoAudio = false; if (qwTime-firstFrameTime > 10000 && !bWarnedAboutNoAudio) { bWarnedAboutNoAudio = true; //AddStreamInfo (TEXT ("WARNING: OBS is not receiving audio frames. Please check your audio devices."), StreamInfoPriority_Critical); } bEncode = false; } else if(bFirstFrame) { firstFrameTime = qwTime; bFirstFrame = false; } if(!bEncode) { if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; } } if(bEncode) { curStreamTime = qwTime-firstFrameTime; UINT prevCopyTexture = (curCopyTexture == 0) ? NUM_RENDER_BUFFERS-1 : curCopyTexture-1; ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; profileIn("CopyResource"); if(!bFirst420Encode && bUseThreaded420) { WaitForMultipleObjects(completeEvents.Num(), completeEvents.Array(), TRUE, INFINITE); copyTexture->Unmap(0); } D3D10Texture *d3dYUV = static_cast<D3D10Texture*>(yuvRenderTextures[curYUVTexture]); GetD3D()->CopyResource(copyTexture, d3dYUV->texture); profileOut; ID3D10Texture2D *prevTexture = copyTextures[prevCopyTexture]; if(bFirstImage) //ignore the first frame bFirstImage = false; else { HRESULT result; D3D10_MAPPED_TEXTURE2D map; if(SUCCEEDED(result = prevTexture->Map(0, D3D10_MAP_READ, 0, &map))) { int prevOutBuffer = (curOutBuffer == 0) ? NUM_OUT_BUFFERS-1 : curOutBuffer-1; int nextOutBuffer = (curOutBuffer == NUM_OUT_BUFFERS-1) ? 0 : curOutBuffer+1; EncoderPicture &prevPicOut = outPics[prevOutBuffer]; EncoderPicture &picOut = outPics[curOutBuffer]; EncoderPicture &nextPicOut = outPics[nextOutBuffer]; if(!bUsing444) { profileIn("conversion to 4:2:0"); if(bUseThreaded420) { outTimes[nextOutBuffer] = (DWORD)curStreamTime; bool firstRun = threadedProfilers.Num() == 0; if(firstRun) threadedProfilers.SetSize(numThreads); for(int i=0; i<numThreads; i++) { convertInfo[i].input = (LPBYTE)map.pData; convertInfo[i].inPitch = map.RowPitch; if(bUsingQSV) { mfxFrameData& data = nextPicOut.mfxOut->Data; videoEncoder->RequestBuffers(&data); convertInfo[i].outPitch = data.Pitch; convertInfo[i].output[0] = data.Y; convertInfo[i].output[1] = data.UV; } else { convertInfo[i].output[0] = nextPicOut.picOut->img.plane[0]; convertInfo[i].output[1] = nextPicOut.picOut->img.plane[1]; convertInfo[i].output[2] = nextPicOut.picOut->img.plane[2]; } if(!firstRun) threadedProfilers[i].~ProfilerNode(); ::new (&threadedProfilers[i]) ProfilerNode(TEXT("Convert444Threads"), true); threadedProfilers[i].MonitorThread(h420Threads[i]); bUsingThreadedProfilers = true; SetEvent(convertInfo[i].hSignalConvert); } if(bFirst420Encode) bFirst420Encode = bEncode = false; } else { outTimes[curOutBuffer] = (DWORD)curStreamTime; if(bUsingQSV) { mfxFrameData& data = picOut.mfxOut->Data; videoEncoder->RequestBuffers(&data); LPBYTE output[] = {data.Y, data.UV}; Convert444toNV12((LPBYTE)map.pData, outputCX, map.RowPitch, data.Pitch, outputCY, 0, outputCY, output); } else Convert444toNV12((LPBYTE)map.pData, outputCX, map.RowPitch, outputCX, outputCY, 0, outputCY, picOut.picOut->img.plane); prevTexture->Unmap(0); } profileOut; } else { outTimes[curOutBuffer] = (DWORD)curStreamTime; picOut.picOut->img.i_stride[0] = map.RowPitch; picOut.picOut->img.plane[0] = (uint8_t*)map.pData; } if(bEncode) { DWORD curFrameTimestamp = outTimes[prevOutBuffer]; //Log(TEXT("curFrameTimestamp: %u"), curFrameTimestamp); //------------------------------------ FrameProcessInfo frameInfo; frameInfo.firstFrameTime = firstFrameTime; frameInfo.prevTexture = prevTexture; if(bDupeFrames) { while(cfrTime < curFrameTimestamp) { DWORD frameTimeAdjust = frameTime; cfrTimeAdjust += fpsTimeNumerator; if(cfrTimeAdjust > fpsTimeDenominator) { cfrTimeAdjust -= fpsTimeDenominator; ++frameTimeAdjust; } DWORD halfTime = (frameTimeAdjust+1)/2; EncoderPicture &nextPic = (curFrameTimestamp-cfrTime <= halfTime) ? picOut : prevPicOut; //Log(TEXT("cfrTime: %u, time: %u"), cfrTime, curFrameTimestamp); //these lines are just for counting duped frames if(nextPic == lastPic) ++numTotalDuplicatedFrames; else lastPic = nextPic; frameInfo.pic = &nextPic; if(bUsingQSV) frameInfo.pic->mfxOut->Data.TimeStamp = cfrTime; else frameInfo.pic->picOut->i_pts = cfrTime; frameInfo.frameTimestamp = cfrTime; ProcessFrame(frameInfo); cfrTime += frameTimeAdjust; //Log(TEXT("cfrTime: %u, chi frame: %u"), cfrTime, (curFrameTimestamp-cfrTime <= halfTime)); } } else { if(bUsingQSV) picOut.mfxOut->Data.TimeStamp = curFrameTimestamp; else picOut.picOut->i_pts = curFrameTimestamp; frameInfo.pic = &picOut; frameInfo.frameTimestamp = curFrameTimestamp; ProcessFrame(frameInfo); } if (!bRunning) bufferedFrames = videoEncoder->GetBufferedFrames (); } if(bUsing444) { prevTexture->Unmap(0); } curOutBuffer = nextOutBuffer; } else { //We have to crash, or we end up deadlocking the thread when the convert threads are never signalled if (result == DXGI_ERROR_DEVICE_REMOVED) { String message; HRESULT reason = GetD3D()->GetDeviceRemovedReason(); switch (reason) { case DXGI_ERROR_DEVICE_RESET: case DXGI_ERROR_DEVICE_HUNG: message = TEXT("Your video card or driver froze and was reset. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_DEVICE_REMOVED: message = TEXT("Your video card disappeared from the system. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_DRIVER_INTERNAL_ERROR: message = TEXT("Your video driver reported an internal error. Please check for possible hardware / driver issues."); break; case DXGI_ERROR_INVALID_CALL: message = TEXT("Your video driver reported an invalid call. Please check for possible driver issues."); break; default: message = TEXT("DXGI_ERROR_DEVICE_REMOVED"); break; } CrashError (TEXT("Texture->Map failed: 0x%08x 0x%08x\r\n\r\n%s"), result, reason, message.Array()); } else CrashError (TEXT("Texture->Map failed: 0x%08x"), result); } } if(curCopyTexture == (NUM_RENDER_BUFFERS-1)) curCopyTexture = 0; else curCopyTexture++; if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; if (bCongestionControl && bDynamicBitrateSupported && !bTestStream) { if (curStrain > 25) { if (qwTime - lastAdjustmentTime > 1500) { if (currentBitRate > 100) { currentBitRate = (int)(currentBitRate * (1.0 - (curStrain / 400))); App->GetVideoEncoder()->SetBitRate(currentBitRate, -1); if (!adjustmentStreamId) adjustmentStreamId = App->AddStreamInfo (FormattedString(TEXT("Congestion detected, dropping bitrate to %d kbps"), currentBitRate).Array(), StreamInfoPriority_Low); else App->SetStreamInfo(adjustmentStreamId, FormattedString(TEXT("Congestion detected, dropping bitrate to %d kbps"), currentBitRate).Array()); bUpdateBPS = true; } lastAdjustmentTime = qwTime; } } else if (currentBitRate < defaultBitRate && curStrain < 5 && lastStrain < 5) { if (qwTime - lastAdjustmentTime > 5000) { if (currentBitRate < defaultBitRate) { currentBitRate += (int)(defaultBitRate * 0.05); if (currentBitRate > defaultBitRate) currentBitRate = defaultBitRate; } App->GetVideoEncoder()->SetBitRate(currentBitRate, -1); /*if (!adjustmentStreamId) App->AddStreamInfo (FormattedString(TEXT("Congestion clearing, raising bitrate to %d kbps"), currentBitRate).Array(), StreamInfoPriority_Low); else App->SetStreamInfo(adjustmentStreamId, FormattedString(TEXT("Congestion clearing, raising bitrate to %d kbps"), currentBitRate).Array());*/ bUpdateBPS = true; lastAdjustmentTime = qwTime; } } } } lastRenderTarget = curRenderTarget; if(curRenderTarget == (NUM_RENDER_BUFFERS-1)) curRenderTarget = 0; else curRenderTarget++; if(bUpdateBPS || !CloseDouble(curStrain, lastStrain) || curFramesDropped != lastFramesDropped) { PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); lastStrain = curStrain; lastFramesDropped = curFramesDropped; } //------------------------------------ // we're about to sleep so we should flush the d3d command queue profileIn("flush"); GetD3D()->Flush(); profileOut; profileOut; //video encoding and uploading profileOut; //frame //------------------------------------ // frame sync #ifdef USE_100NS_TIME QWORD renderStopTime = GetQPCTime100NS(); sleepTargetTime += frameTime100ns; if(bWasLaggedFrame = (sleepTargetTime <= renderStopTime)) { numLongFrames++; if(bLogLongFramesProfile && (numLongFrames/float(max(1, numTotalFrames)) * 100.) > logLongFramesProfilePercentage) DumpLastProfileData(); } else SleepTo(sleepTargetTime); #else DWORD renderStopTime = OSGetTime(); DWORD totalTime = renderStopTime-renderStartTime; if(totalTime > frameTimeAdjust) { numLongFrames++; if(bLogLongFramesProfile && (numLongFrames/float(max(1, numTotalFrames)) * 100.) > logLongFramesProfilePercentage) DumpLastProfileData(); } else if(totalTime < frameTimeAdjust) OSSleep(frameTimeAdjust-totalTime); #endif //OSDebugOut(TEXT("Frame adjust time: %d, "), frameTimeAdjust-totalTime); numTotalFrames++; } if(!bUsing444) { if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { if(h420Threads[i]) { convertInfo[i].bKillThread = true; SetEvent(convertInfo[i].hSignalConvert); if(bUsingThreadedProfilers) threadedProfilers[i].~ProfilerNode(); OSTerminateThread(h420Threads[i], 10000); h420Threads[i] = NULL; } if(convertInfo[i].hSignalConvert) { CloseHandle(convertInfo[i].hSignalConvert); convertInfo[i].hSignalConvert = NULL; } if(convertInfo[i].hSignalComplete) { CloseHandle(convertInfo[i].hSignalComplete); convertInfo[i].hSignalComplete = NULL; } } if(!bFirst420Encode) { ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; copyTexture->Unmap(0); } } if(bUsingQSV) for(int i = 0; i < NUM_OUT_BUFFERS; i++) delete outPics[i].mfxOut; else for(int i=0; i<NUM_OUT_BUFFERS; i++) { x264_picture_clean(outPics[i].picOut); delete outPics[i].picOut; } } Free(h420Threads); Free(convertInfo); Log(TEXT("Total frames rendered: %d, number of frames that lagged: %d (%0.2f%%) (it's okay for some frames to lag)"), numTotalFrames, numLongFrames, (double(numLongFrames)/double(numTotalFrames))*100.0); if(bDupeFrames) Log(TEXT("Total duplicated frames: %d (%0.2f%%)"), numTotalDuplicatedFrames, (double(numTotalDuplicatedFrames)/double(numTotalFrames))*100.0); }
void GraphicsCaptureSource::Render(const Vect2 &pos, const Vect2 &size) { if(capture) { Shader *lastShader = GetCurrentPixelShader(); float fGamma = float(-(gamma-100) + 100) * 0.01f; LoadPixelShader(drawShader); HANDLE hGamma = drawShader->GetParameterByName(TEXT("gamma")); if(hGamma) drawShader->SetFloat(hGamma, fGamma); //---------------------------------------------------------- // capture mouse bMouseCaptured = false; if(bCaptureMouse) { CURSORINFO ci; zero(&ci, sizeof(ci)); ci.cbSize = sizeof(ci); if(GetCursorInfo(&ci) && hwndCapture) { mcpy(&cursorPos, &ci.ptScreenPos, sizeof(cursorPos)); ScreenToClient(hwndCapture, &cursorPos); if(ci.flags & CURSOR_SHOWING) { if(ci.hCursor == hCurrentCursor) bMouseCaptured = true; else { HICON hIcon = CopyIcon(ci.hCursor); hCurrentCursor = ci.hCursor; delete cursorTexture; cursorTexture = NULL; if(hIcon) { ICONINFO ii; if(GetIconInfo(hIcon, &ii)) { xHotspot = int(ii.xHotspot); yHotspot = int(ii.yHotspot); UINT width, height; LPBYTE lpData = GetCursorData(hIcon, ii, width, height); if(lpData) { cursorTexture = CreateTexture(width, height, GS_BGRA, lpData, FALSE); if(cursorTexture) bMouseCaptured = true; Free(lpData); } DeleteObject(ii.hbmColor); DeleteObject(ii.hbmMask); } DestroyIcon(hIcon); } } } } } //---------------------------------------------------------- // game texture Texture *tex = capture->LockTexture(); Vect2 texPos = Vect2(0.0f, 0.0f); Vect2 texStretch = Vect2(1.0f, 1.0f); if(tex) { Vect2 texSize = Vect2(float(tex->Width()), float(tex->Height())); Vect2 totalSize = API->GetBaseSize(); Vect2 center = totalSize*0.5f; BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); if(bStretch) { if(bIgnoreAspect) texStretch *= totalSize; else { float multiplyVal = (texSize.y * (totalSize.x / texSize.x) > totalSize.y) ? totalSize.y / texSize.y : multiplyVal = totalSize.x / texSize.x; texStretch *= texSize*multiplyVal; texPos = center-(texStretch*0.5f); } } else { texStretch *= texSize; texPos = center-(texStretch*0.5f); } Vect2 sizeAdjust = size/totalSize; texPos *= sizeAdjust; texPos += pos; texStretch *= sizeAdjust; RoundVect2(texPos); RoundVect2(texSize); if(bFlip) DrawSprite(tex, 0xFFFFFFFF, texPos.x, texPos.y+texStretch.y, texPos.x+texStretch.x, texPos.y); else DrawSprite(tex, 0xFFFFFFFF, texPos.x, texPos.y, texPos.x+texStretch.x, texPos.y+texStretch.y); capture->UnlockTexture(); BlendFunction(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA); //---------------------------------------------------------- // draw mouse if(bMouseCaptured && cursorTexture && GetForegroundWindow() == hwndCapture) { Vect2 newCursorPos = Vect2(float(cursorPos.x-xHotspot), float(cursorPos.y-xHotspot)); Vect2 newCursorSize = Vect2(float(cursorTexture->Width()), float(cursorTexture->Height())); newCursorPos /= texSize; newCursorSize /= texSize; newCursorPos *= texStretch; newCursorPos += texPos; newCursorSize *= texStretch; bool bInvertCursor = false; if(invertShader) { if(bInvertCursor = ((GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0 || (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0)) LoadPixelShader(invertShader); } DrawSprite(cursorTexture, 0xFFFFFFFF, newCursorPos.x, newCursorPos.y, newCursorPos.x+newCursorSize.x, newCursorPos.y+newCursorSize.y); } } if(lastShader) LoadPixelShader(lastShader); } }
//============================================================================================================================== bool MaterialTessellationShader::Initialize() { ConstantBuffer<ZShadeSandboxLighting::cbMaterialTessellationBuffer> tessellationCB(m_pD3DSystem); tessellationCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbMaterialTessellationBuffer))); m_pTessellationCB = tessellationCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbMaterialDomainBuffer> domainCB(m_pD3DSystem); domainCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbMaterialDomainBuffer))); m_pDomainCB = domainCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbMaterialShadingBuffer> shadingCB(m_pD3DSystem); shadingCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbMaterialShadingBuffer))); m_pShadingCB = shadingCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbLightBuffer> lightCB(m_pD3DSystem); lightCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbLightBuffer))); m_pLightCB = lightCB.Buffer(); ConstantBuffer<ZShadeSandboxLighting::cbSunLightBuffer> sunCB(m_pD3DSystem); sunCB.Initialize(PAD16(sizeof(ZShadeSandboxLighting::cbSunLightBuffer))); m_pSunCB = sunCB.Buffer(); ClearInputLayout(); SetInputLayoutDesc("MaterialTessellationShader", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex, 3); switch (mType) { case ZShadeSandboxLighting::EMaterialTessellationType::Type::eQuad: { LoadVertexShader("QuadMaterialTessellationVS"); LoadHullShader("QuadMaterialTessellationHS"); LoadDomainShader("QuadMaterialTessellationDS"); LoadPixelShader("QuadMaterialTessellationPS"); LoadPixelShader("QuadMaterialTessellationWireframePS"); } break; case ZShadeSandboxLighting::EMaterialTessellationType::Type::eTri: { LoadVertexShader("TriMaterialTessellationVS"); LoadHullShader("TriMaterialTessellationHS"); LoadDomainShader("TriMaterialTessellationDS"); LoadPixelShader("TriMaterialTessellationPS"); LoadPixelShader("TriMaterialTessellationWireframePS"); } break; } AssignVertexShaderLayout("MaterialTessellationShader"); // Instancing SetInputLayoutDesc("MaterialTessellationShaderInstance", ZShadeSandboxMesh::VertexLayout::mesh_layout_pos_normal_tex_instance, 4); switch (mType) { case ZShadeSandboxLighting::EMaterialTessellationType::Type::eQuad: { LoadVertexShader("QuadMaterialTessellationInstanceVS"); } break; case ZShadeSandboxLighting::EMaterialTessellationType::Type::eTri: { LoadVertexShader("TriMaterialTessellationInstanceVS"); } break; } AssignVertexShaderLayout("MaterialTessellationShaderInstance"); return true; }
void RotationManipulator::RenderScaled(const Vect &cameraDir, float scale) { traceInFast(RotationManipulator::RenderScaled); DWORD i; Shader *rotManipShader = GetVertexShader(TEXT("Editor:RotationManipulator.vShader")); LoadVertexShader(rotManipShader); LoadPixelShader(GetPixelShader(TEXT("Base:SolidColor.pShader"))); rotManipShader->SetVector(rotManipShader->GetParameter(2), cameraDir); MatrixPush(); MatrixTranslate(GetWorldPos()); MatrixScale(scale, scale, scale); for(i=0; i<3; i++) { Vect axisColor(0.0f, 0.0f, 0.0f); axisColor.ptr[i] = 1.0f; if(i == activeAxis) axisColor.Set(1.0f, 1.0f, 0.0f); else axisColor.ptr[i] = 1.0f; rotManipShader->SetVector(rotManipShader->GetParameter(1), axisColor); LoadVertexBuffer(axisBuffers[i]); LoadIndexBuffer(NULL); Draw(GS_LINESTRIP); } LoadVertexBuffer(NULL); //---------------------------------------------------- Shader *solidShader = GetVertexShader(TEXT("Base:SolidColor.vShader")); LoadVertexShader(solidShader); MatrixPush(); MatrixRotate(Quat().SetLookDirection(cameraDir)); LoadVertexBuffer(axisBuffers[2]); LoadIndexBuffer(NULL); solidShader->SetColor(solidShader->GetParameter(1), 0.5, 0.5, 0.5, 0.5); Draw(GS_LINESTRIP); MatrixScale(1.25f, 1.25f, 1.25f); //--------------- if(activeAxis == 4) solidShader->SetColor(solidShader->GetParameter(1), 1.0f, 1.0f, 0.0, 1.0f); else solidShader->SetColor(solidShader->GetParameter(1), 0.8, 0.8, 0.8, 0.8); Draw(GS_LINESTRIP); MatrixPop(); MatrixPop(); LoadVertexShader(NULL); LoadPixelShader(NULL); traceOutFast; }
PixelShader ResourcePool::LoadPixelShader(std::string file_name) { return LoadPixelShader(file_name, "PShader"); }
//todo: this function is an abomination, this is just disgusting. fix it. //...seriously, this is really, really horrible. I mean this is amazingly bad. void OBS::MainCaptureLoop() { int curRenderTarget = 0, curYUVTexture = 0, curCopyTexture = 0; int copyWait = NUM_RENDER_BUFFERS-1; bSentHeaders = false; bFirstAudioPacket = true; Vect2 baseSize = Vect2(float(baseCX), float(baseCY)); Vect2 outputSize = Vect2(float(outputCX), float(outputCY)); Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY)); HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI")); LPVOID nullBuff = NULL; //---------------------------------------- // x264 input buffers int curOutBuffer = 0; x264_picture_t *lastPic = NULL; x264_picture_t outPics[NUM_OUT_BUFFERS]; DWORD outTimes[NUM_OUT_BUFFERS] = {0, 0, 0}; for(int i=0; i<NUM_OUT_BUFFERS; i++) x264_picture_init(&outPics[i]); if(bUsing444) { for(int i=0; i<NUM_OUT_BUFFERS; i++) { outPics[i].img.i_csp = X264_CSP_BGRA; //although the x264 input says BGR, x264 actually will expect packed UYV outPics[i].img.i_plane = 1; } } else { for(int i=0; i<NUM_OUT_BUFFERS; i++) x264_picture_alloc(&outPics[i], X264_CSP_I420, outputCX, outputCY); } //---------------------------------------- // time/timestamp stuff LARGE_INTEGER clockFreq; QueryPerformanceFrequency(&clockFreq); bufferedTimes.Clear(); ctsOffsets.Clear(); #ifdef USE_100NS_TIME QWORD streamTimeStart = GetQPCTime100NS(clockFreq.QuadPart); QWORD frameTime100ns = 10000000/fps; QWORD sleepTargetTime = 0; bool bWasLaggedFrame = false; #else DWORD streamTimeStart = OSGetTime(); #endif totalStreamTime = 0; lastAudioTimestamp = 0; latestVideoTime = firstSceneTimestamp = GetQPCTimeMS(clockFreq.QuadPart); DWORD fpsTimeNumerator = 1000-(frameTime*fps); DWORD fpsTimeDenominator = fps; DWORD fpsTimeAdjust = 0; DWORD cfrTime = 0; DWORD cfrTimeAdjust = 0; //---------------------------------------- // start audio capture streams desktopAudio->StartCapture(); if(micAudio) micAudio->StartCapture(); //---------------------------------------- // status bar/statistics stuff DWORD fpsCounter = 0; int numLongFrames = 0; int numTotalFrames = 0; int numTotalDuplicatedFrames = 0; bytesPerSec = 0; captureFPS = 0; curFramesDropped = 0; curStrain = 0.0; PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); QWORD lastBytesSent[3] = {0, 0, 0}; DWORD lastFramesDropped = 0; #ifdef USE_100NS_TIME double bpsTime = 0.0; #else float bpsTime = 0.0f; #endif double lastStrain = 0.0f; DWORD numSecondsWaited = 0; //---------------------------------------- // 444->420 thread data int numThreads = MAX(OSGetTotalCores()-2, 1); HANDLE *h420Threads = (HANDLE*)Allocate(sizeof(HANDLE)*numThreads); Convert444Data *convertInfo = (Convert444Data*)Allocate(sizeof(Convert444Data)*numThreads); zero(h420Threads, sizeof(HANDLE)*numThreads); zero(convertInfo, sizeof(Convert444Data)*numThreads); for(int i=0; i<numThreads; i++) { convertInfo[i].width = outputCX; convertInfo[i].height = outputCY; convertInfo[i].hSignalConvert = CreateEvent(NULL, FALSE, FALSE, NULL); convertInfo[i].hSignalComplete = CreateEvent(NULL, FALSE, FALSE, NULL); if(i == 0) convertInfo[i].startY = 0; else convertInfo[i].startY = convertInfo[i-1].endY; if(i == (numThreads-1)) convertInfo[i].endY = outputCY; else convertInfo[i].endY = ((outputCY/numThreads)*(i+1)) & 0xFFFFFFFE; } bool bFirstFrame = true; bool bFirstImage = true; bool bFirst420Encode = true; bool bUseThreaded420 = bUseMultithreadedOptimizations && (OSGetTotalCores() > 1) && !bUsing444; List<HANDLE> completeEvents; if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { h420Threads[i] = OSCreateThread((XTHREAD)Convert444Thread, convertInfo+i); completeEvents << convertInfo[i].hSignalComplete; } } //---------------------------------------- QWORD curStreamTime = 0, lastStreamTime, firstFrameTime = GetQPCTimeMS(clockFreq.QuadPart); lastStreamTime = firstFrameTime-frameTime; bool bFirstAudioPacket = true; while(bRunning) { #ifdef USE_100NS_TIME QWORD renderStartTime = GetQPCTime100NS(clockFreq.QuadPart); if(sleepTargetTime == 0 || bWasLaggedFrame) sleepTargetTime = renderStartTime; #else DWORD renderStartTime = OSGetTime(); totalStreamTime = renderStartTime-streamTimeStart; DWORD frameTimeAdjust = frameTime; fpsTimeAdjust += fpsTimeNumerator; if(fpsTimeAdjust > fpsTimeDenominator) { fpsTimeAdjust -= fpsTimeDenominator; ++frameTimeAdjust; } #endif bool bRenderView = !IsIconic(hwndMain) && bRenderViewEnabled; profileIn("frame"); #ifdef USE_100NS_TIME QWORD qwTime = renderStartTime/10000; latestVideoTime = qwTime; QWORD frameDelta = renderStartTime-lastStreamTime; double fSeconds = double(frameDelta)*0.0000001; //Log(TEXT("frameDelta: %f"), fSeconds); lastStreamTime = renderStartTime; #else QWORD qwTime = GetQPCTimeMS(clockFreq.QuadPart); latestVideoTime = qwTime; QWORD frameDelta = qwTime-lastStreamTime; float fSeconds = float(frameDelta)*0.001f; //Log(TEXT("frameDelta: %llu"), frameDelta); lastStreamTime = qwTime; #endif //------------------------------------ if(bRequestKeyframe && keyframeWait > 0) { keyframeWait -= int(frameDelta); if(keyframeWait <= 0) { GetVideoEncoder()->RequestKeyframe(); bRequestKeyframe = false; } } if(!bPushToTalkDown && pushToTalkTimeLeft > 0) { pushToTalkTimeLeft -= int(frameDelta); OSDebugOut(TEXT("time left: %d\r\n"), pushToTalkTimeLeft); if(pushToTalkTimeLeft <= 0) { pushToTalkTimeLeft = 0; bPushToTalkOn = false; } } //------------------------------------ OSEnterMutex(hSceneMutex); if(bResizeRenderView) { GS->ResizeView(); bResizeRenderView = false; } //------------------------------------ if(scene) { profileIn("scene->Preprocess"); scene->Preprocess(); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Preprocess(); profileOut; scene->Tick(float(fSeconds)); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->Tick(float(fSeconds)); } //------------------------------------ QWORD curBytesSent = network->GetCurrentSentBytes(); curFramesDropped = network->NumDroppedFrames(); bool bUpdateBPS = false; bpsTime += fSeconds; if(bpsTime > 1.0f) { if(numSecondsWaited < 3) ++numSecondsWaited; //bytesPerSec = DWORD(curBytesSent - lastBytesSent); bytesPerSec = DWORD(curBytesSent - lastBytesSent[0]) / numSecondsWaited; if(bpsTime > 2.0) bpsTime = 0.0f; else bpsTime -= 1.0; if(numSecondsWaited == 3) { lastBytesSent[0] = lastBytesSent[1]; lastBytesSent[1] = lastBytesSent[2]; lastBytesSent[2] = curBytesSent; } else lastBytesSent[numSecondsWaited] = curBytesSent; captureFPS = fpsCounter; fpsCounter = 0; bUpdateBPS = true; } fpsCounter++; curStrain = network->GetPacketStrain(); EnableBlending(TRUE); BlendFunction(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA); //------------------------------------ // render the mini render texture LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); SetRenderTarget(mainRenderTextures[curRenderTarget]); Ortho(0.0f, baseSize.x, baseSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0, 0, baseSize.x, baseSize.y); if(scene) scene->Render(); //------------------------------------ if(bTransitioning) { if(!transitionTexture) { transitionTexture = CreateTexture(baseCX, baseCY, GS_BGRA, NULL, FALSE, TRUE); if(transitionTexture) { D3D10Texture *d3dTransitionTex = static_cast<D3D10Texture*>(transitionTexture); D3D10Texture *d3dSceneTex = static_cast<D3D10Texture*>(mainRenderTextures[lastRenderTarget]); GetD3D()->CopyResource(d3dTransitionTex->texture, d3dSceneTex->texture); } else bTransitioning = false; } else if(transitionAlpha >= 1.0f) { delete transitionTexture; transitionTexture = NULL; bTransitioning = false; } } if(bTransitioning) { EnableBlending(TRUE); transitionAlpha += float(fSeconds)*5.0f; if(transitionAlpha > 1.0f) transitionAlpha = 1.0f; } else EnableBlending(FALSE); //------------------------------------ // render the mini view thingy if(bRenderView) { Vect2 renderFrameSize = Vect2(float(renderFrameWidth), float(renderFrameHeight)); SetRenderTarget(NULL); LoadVertexShader(mainVertexShader); LoadPixelShader(mainPixelShader); Ortho(0.0f, renderFrameSize.x, renderFrameSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0.0f, 0.0f, renderFrameSize.x, renderFrameSize.y); if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); if(renderFrameIn1To1Mode) DrawSprite(transitionTexture, 0xFFFFFFFF, 0.0f, 0.0f, outputSize.x, outputSize.y); else DrawSprite(transitionTexture, 0xFFFFFFFF, 0.0f, 0.0f, renderFrameSize.x, renderFrameSize.y); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } if(renderFrameIn1To1Mode) DrawSprite(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, 0.0f, 0.0f, outputSize.x, outputSize.y); else DrawSprite(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, 0.0f, 0.0f, renderFrameSize.x, renderFrameSize.y); Ortho(0.0f, renderFrameSize.x, renderFrameSize.y, 0.0f, -100.0f, 100.0f); //draw selections if in edit mode if(bEditMode && !bSizeChanging) { LoadVertexShader(solidVertexShader); LoadPixelShader(solidPixelShader); solidPixelShader->SetColor(solidPixelShader->GetParameter(0), 0xFFFF0000); if(renderFrameIn1To1Mode) Ortho(0.0f, renderFrameSize.x * downscale, renderFrameSize.y * downscale, 0.0f, -100.0f, 100.0f); else Ortho(0.0f, baseSize.x, baseSize.y, 0.0f, -100.0f, 100.0f); if(scene) scene->RenderSelections(); } } else if(bForceRenderViewErase) { InvalidateRect(hwndRenderFrame, NULL, TRUE); UpdateWindow(hwndRenderFrame); bForceRenderViewErase = false; } //------------------------------------ // actual stream output LoadVertexShader(mainVertexShader); LoadPixelShader(yuvScalePixelShader); Texture *yuvRenderTexture = yuvRenderTextures[curRenderTarget]; SetRenderTarget(yuvRenderTexture); yuvScalePixelShader->SetVector2(hScaleVal, 1.0f/baseSize); Ortho(0.0f, outputSize.x, outputSize.y, 0.0f, -100.0f, 100.0f); SetViewport(0.0f, 0.0f, outputSize.x, outputSize.y); //why am I using scaleSize instead of outputSize for the texture? //because outputSize can be trimmed by up to three pixels due to 128-bit alignment. //using the scale function with outputSize can cause slightly inaccurate scaled images if(bTransitioning) { BlendFunction(GS_BLEND_ONE, GS_BLEND_ZERO); DrawSpriteEx(transitionTexture, 0xFFFFFFFF, 0.0f, 0.0f, scaleSize.x, scaleSize.y, 0.0f, 0.0f, scaleSize.x, scaleSize.y); BlendFunction(GS_BLEND_FACTOR, GS_BLEND_INVFACTOR, transitionAlpha); } DrawSpriteEx(mainRenderTextures[curRenderTarget], 0xFFFFFFFF, 0.0f, 0.0f, outputSize.x, outputSize.y, 0.0f, 0.0f, outputSize.x, outputSize.y); //------------------------------------ if(bRenderView && !copyWait) static_cast<D3D10System*>(GS)->swap->Present(0, 0); OSLeaveMutex(hSceneMutex); //------------------------------------ // present/upload profileIn("video encoding and uploading"); bool bEncode = true; if(copyWait) { copyWait--; bEncode = false; } else { //audio sometimes takes a bit to start -- do not start processing frames until audio has started capturing if(!bRecievedFirstAudioFrame) bEncode = false; else if(bFirstFrame) { firstFrameTime = qwTime; bFirstFrame = false; } if(!bEncode) { if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; } } if(bEncode) { curStreamTime = qwTime-firstFrameTime; UINT prevCopyTexture = (curCopyTexture == 0) ? NUM_RENDER_BUFFERS-1 : curCopyTexture-1; ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; profileIn("CopyResource"); if(!bFirst420Encode && bUseThreaded420) { WaitForMultipleObjects(completeEvents.Num(), completeEvents.Array(), TRUE, INFINITE); copyTexture->Unmap(0); } D3D10Texture *d3dYUV = static_cast<D3D10Texture*>(yuvRenderTextures[curYUVTexture]); GetD3D()->CopyResource(copyTexture, d3dYUV->texture); profileOut; ID3D10Texture2D *prevTexture = copyTextures[prevCopyTexture]; if(bFirstImage) //ignore the first frame bFirstImage = false; else { HRESULT result; D3D10_MAPPED_TEXTURE2D map; if(SUCCEEDED(result = prevTexture->Map(0, D3D10_MAP_READ, 0, &map))) { int prevOutBuffer = (curOutBuffer == 0) ? NUM_OUT_BUFFERS-1 : curOutBuffer-1; int nextOutBuffer = (curOutBuffer == NUM_OUT_BUFFERS-1) ? 0 : curOutBuffer+1; x264_picture_t &prevPicOut = outPics[prevOutBuffer]; x264_picture_t &picOut = outPics[curOutBuffer]; x264_picture_t &nextPicOut = outPics[nextOutBuffer]; if(!bUsing444) { profileIn("conversion to 4:2:0"); if(bUseThreaded420) { outTimes[nextOutBuffer] = (DWORD)curStreamTime; for(int i=0; i<numThreads; i++) { convertInfo[i].input = (LPBYTE)map.pData; convertInfo[i].pitch = map.RowPitch; convertInfo[i].output[0] = nextPicOut.img.plane[0]; convertInfo[i].output[1] = nextPicOut.img.plane[1]; convertInfo[i].output[2] = nextPicOut.img.plane[2]; SetEvent(convertInfo[i].hSignalConvert); } if(bFirst420Encode) bFirst420Encode = bEncode = false; } else { outTimes[curOutBuffer] = (DWORD)curStreamTime; Convert444to420((LPBYTE)map.pData, outputCX, map.RowPitch, outputCY, 0, outputCY, picOut.img.plane, SSE2Available()); prevTexture->Unmap(0); } profileOut; } else { outTimes[curOutBuffer] = (DWORD)curStreamTime; picOut.img.i_stride[0] = map.RowPitch; picOut.img.plane[0] = (uint8_t*)map.pData; } if(bEncode) { DWORD curFrameTimestamp = outTimes[prevOutBuffer]; //Log(TEXT("curFrameTimestamp: %u"), curFrameTimestamp); //------------------------------------ FrameProcessInfo frameInfo; frameInfo.firstFrameTime = firstFrameTime; frameInfo.prevTexture = prevTexture; if(bUseCFR) { while(cfrTime < curFrameTimestamp) { DWORD frameTimeAdjust = frameTime; cfrTimeAdjust += fpsTimeNumerator; if(cfrTimeAdjust > fpsTimeDenominator) { cfrTimeAdjust -= fpsTimeDenominator; ++frameTimeAdjust; } DWORD halfTime = (frameTimeAdjust+1)/2; x264_picture_t *nextPic = (curFrameTimestamp-cfrTime <= halfTime) ? &picOut : &prevPicOut; //Log(TEXT("cfrTime: %u, time: %u"), cfrTime, curFrameTimestamp); //these lines are just for counting duped frames if(nextPic == lastPic) ++numTotalDuplicatedFrames; else lastPic = nextPic; frameInfo.picOut = nextPic; frameInfo.picOut->i_pts = cfrTime; frameInfo.frameTimestamp = cfrTime; ProcessFrame(frameInfo); cfrTime += frameTimeAdjust; //Log(TEXT("cfrTime: %u, chi frame: %u"), cfrTime, (curFrameTimestamp-cfrTime <= halfTime)); } } else { picOut.i_pts = curFrameTimestamp; frameInfo.picOut = &picOut; frameInfo.frameTimestamp = curFrameTimestamp; ProcessFrame(frameInfo); } } curOutBuffer = nextOutBuffer; } else { //We have to crash, or we end up deadlocking the thread when the convert threads are never signalled CrashError (TEXT("Texture->Map failed: 0x%08x"), result); } } if(curCopyTexture == (NUM_RENDER_BUFFERS-1)) curCopyTexture = 0; else curCopyTexture++; if(curYUVTexture == (NUM_RENDER_BUFFERS-1)) curYUVTexture = 0; else curYUVTexture++; } lastRenderTarget = curRenderTarget; if(curRenderTarget == (NUM_RENDER_BUFFERS-1)) curRenderTarget = 0; else curRenderTarget++; if(bUpdateBPS || !CloseDouble(curStrain, lastStrain) || curFramesDropped != lastFramesDropped) { PostMessage(hwndMain, OBS_UPDATESTATUSBAR, 0, 0); lastStrain = curStrain; lastFramesDropped = curFramesDropped; } profileOut; profileOut; //------------------------------------ // get audio while sleeping or capturing //ReleaseSemaphore(hRequestAudioEvent, 1, NULL); //------------------------------------ // frame sync #ifdef USE_100NS_TIME QWORD renderStopTime = GetQPCTime100NS(clockFreq.QuadPart); sleepTargetTime += frameTime100ns; if(bWasLaggedFrame = (sleepTargetTime <= renderStopTime)) numLongFrames++; else SleepTo(clockFreq.QuadPart, sleepTargetTime); #else DWORD renderStopTime = OSGetTime(); DWORD totalTime = renderStopTime-renderStartTime; if(totalTime > frameTimeAdjust) numLongFrames++; else if(totalTime < frameTimeAdjust) OSSleep(frameTimeAdjust-totalTime); #endif //OSDebugOut(TEXT("Frame adjust time: %d, "), frameTimeAdjust-totalTime); numTotalFrames++; } if(!bUsing444) { if(bUseThreaded420) { for(int i=0; i<numThreads; i++) { if(h420Threads[i]) { convertInfo[i].bKillThread = true; SetEvent(convertInfo[i].hSignalConvert); OSTerminateThread(h420Threads[i], 10000); h420Threads[i] = NULL; } if(convertInfo[i].hSignalConvert) { CloseHandle(convertInfo[i].hSignalConvert); convertInfo[i].hSignalConvert = NULL; } if(convertInfo[i].hSignalComplete) { CloseHandle(convertInfo[i].hSignalComplete); convertInfo[i].hSignalComplete = NULL; } } if(!bFirst420Encode) { ID3D10Texture2D *copyTexture = copyTextures[curCopyTexture]; copyTexture->Unmap(0); } } for(int i=0; i<NUM_OUT_BUFFERS; i++) x264_picture_clean(&outPics[i]); } Free(h420Threads); Free(convertInfo); Log(TEXT("Total frames rendered: %d, number of frames that lagged: %d (%0.2f%%) (it's okay for some frames to lag)"), numTotalFrames, numLongFrames, (double(numLongFrames)/double(numTotalFrames))*100.0); if(bUseCFR) Log(TEXT("Total duplicated CFR frames: %d"), numTotalDuplicatedFrames); }
HRESULT CDirect3D::RestoreDeviceObjects(void) { unsigned int vertexbuffersize = sizeof(TLVERTEX) * 4; preProcess = false; #if C_D3DSHADERS if(psActive) { // Set up pixel shaders LoadPixelShader(); if(psEffect && psEffect->hasPreprocess()) { #if LOG_D3D LOG_MSG("D3D:Pixel shader preprocess active"); #endif preProcess = true; vertexbuffersize = sizeof(TLVERTEX) * 8; } } #endif // Initialize vertex pD3DDevice9->SetFVF(D3DFVF_TLVERTEX); // Create vertex buffer if(FAILED(pD3DDevice9->CreateVertexBuffer(vertexbuffersize, D3DUSAGE_WRITEONLY, D3DFVF_TLVERTEX, D3DPOOL_MANAGED, &vertexBuffer, NULL))) { LOG_MSG("D3D:Failed to create Vertex Buffer"); return E_FAIL; } // Lock vertex buffer and set vertices CreateVertex(); pD3DDevice9->SetStreamSource(0, vertexBuffer, 0, sizeof(TLVERTEX)); // Turn off culling pD3DDevice9->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // Turn off D3D lighting pD3DDevice9->SetRenderState(D3DRS_LIGHTING, false); // Turn off the zbuffer pD3DDevice9->SetRenderState(D3DRS_ZENABLE, false); CreateDisplayTexture(); SetupSceneScaled(); if(!psActive) { pD3DDevice9->SetTexture(0, lpTexture); // Disable Shaders pD3DDevice9->SetVertexShader(0); pD3DDevice9->SetPixelShader(0); pD3DDevice9->SetTransform(D3DTS_PROJECTION, &m_matProj); pD3DDevice9->SetTransform(D3DTS_VIEW, &m_matView); pD3DDevice9->SetTransform(D3DTS_WORLD, &m_matWorld); } #if C_D3DSHADERS else if(psEffect) { if(preProcess) { // Projection is (0,0,0) -> (1,1,1) D3DXMatrixOrthoOffCenterLH(&m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); // Align texels with pixels D3DXMatrixTranslation(&m_matPreView, -0.5f/dwTexWidth, 0.5f/dwTexHeight, 0.0f); // Identity for world D3DXMatrixIdentity(&m_matPreWorld); } else if(FAILED(psEffect->SetMatrices(m_matProj, m_matView, m_matWorld))) { LOG_MSG("D3D:Set matrices failed."); InvalidateDeviceObjects(); return E_FAIL; } } #endif return S_OK; }