//--------------------------------------------------------------------------------- static HRESULT CreateTextureFromWIC( _In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_ IWICBitmapFrameDecode *frame, _In_ size_t maxsize, _In_ D3D11_USAGE usage, _In_ unsigned int bindFlags, _In_ unsigned int cpuAccessFlags, _In_ unsigned int miscFlags, _In_ bool forceSRGB, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView ) { UINT width, height; HRESULT hr = frame->GetSize( &width, &height ); if ( FAILED(hr) ) return hr; assert( width > 0 && height > 0 ); if ( !maxsize ) { // This is a bit conservative because the hardware could support larger textures than // the Feature Level defined minimums, but doing it this way is much easier and more // performant for WIC than the 'fail and retry' model used by DDSTextureLoader switch( d3dDevice->GetFeatureLevel() ) { case D3D_FEATURE_LEVEL_9_1: case D3D_FEATURE_LEVEL_9_2: maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case D3D_FEATURE_LEVEL_9_3: maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case D3D_FEATURE_LEVEL_10_0: case D3D_FEATURE_LEVEL_10_1: maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; default: maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; break; } } assert( maxsize > 0 ); UINT twidth, theight; if ( width > maxsize || height > maxsize ) { float ar = static_cast<float>(height) / static_cast<float>(width); if ( width > height ) { twidth = static_cast<UINT>( maxsize ); theight = static_cast<UINT>( static_cast<float>(maxsize) * ar ); } else { theight = static_cast<UINT>( maxsize ); twidth = static_cast<UINT>( static_cast<float>(maxsize) / ar ); } assert( twidth <= maxsize && theight <= maxsize ); } else { twidth = width; theight = height; } // Determine format WICPixelFormatGUID pixelFormat; hr = frame->GetPixelFormat( &pixelFormat ); if ( FAILED(hr) ) return hr; WICPixelFormatGUID convertGUID; memcpy( &convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID) ); size_t bpp = 0; DXGI_FORMAT format = _WICToDXGI( pixelFormat ); if ( format == DXGI_FORMAT_UNKNOWN ) { if ( memcmp( &GUID_WICPixelFormat96bppRGBFixedPoint, &pixelFormat, sizeof(WICPixelFormatGUID) ) == 0 ) { #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) || defined(_WIN7_PLATFORM_UPDATE) if ( g_WIC2 ) { memcpy( &convertGUID, &GUID_WICPixelFormat96bppRGBFloat, sizeof(WICPixelFormatGUID) ); format = DXGI_FORMAT_R32G32B32_FLOAT; } else #endif { memcpy( &convertGUID, &GUID_WICPixelFormat128bppRGBAFloat, sizeof(WICPixelFormatGUID) ); format = DXGI_FORMAT_R32G32B32A32_FLOAT; } } else { for( size_t i=0; i < _countof(g_WICConvert); ++i ) { if ( memcmp( &g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID) ) == 0 ) { memcpy( &convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID) ); format = _WICToDXGI( g_WICConvert[i].target ); assert( format != DXGI_FORMAT_UNKNOWN ); bpp = _WICBitsPerPixel( convertGUID ); break; } } } if ( format == DXGI_FORMAT_UNKNOWN ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } else { bpp = _WICBitsPerPixel( pixelFormat ); } #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) || defined(_WIN7_PLATFORM_UPDATE) if ( (format == DXGI_FORMAT_R32G32B32_FLOAT) && d3dContext != 0 && textureView != 0 ) { // Special case test for optional device support for autogen mipchains for R32G32B32_FLOAT UINT fmtSupport = 0; hr = d3dDevice->CheckFormatSupport( DXGI_FORMAT_R32G32B32_FLOAT, &fmtSupport ); if ( FAILED(hr) || !( fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN ) ) { // Use R32G32B32A32_FLOAT instead which is required for Feature Level 10.0 and up memcpy( &convertGUID, &GUID_WICPixelFormat128bppRGBAFloat, sizeof(WICPixelFormatGUID) ); format = DXGI_FORMAT_R32G32B32A32_FLOAT; bpp = 128; } } #endif if ( !bpp ) return E_FAIL; // Verify our target format is supported by the current device // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support) UINT support = 0; hr = d3dDevice->CheckFormatSupport( format, &support ); if ( FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D) ) { // Fallback to RGBA 32-bit format which is supported by all devices memcpy( &convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID) ); format = DXGI_FORMAT_R8G8B8A8_UNORM; bpp = 32; } // Allocate temporary memory for image size_t rowPitch = ( twidth * bpp + 7 ) / 8; size_t imageSize = rowPitch * theight; std::unique_ptr<uint8_t[]> temp( new (std::nothrow) uint8_t[ imageSize ] ); if (!temp) return E_OUTOFMEMORY; // Load image data if ( memcmp( &convertGUID, &pixelFormat, sizeof(GUID) ) == 0 && twidth == width && theight == height ) { // No format conversion or resize needed hr = frame->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() ); if ( FAILED(hr) ) return hr; } else if ( twidth != width || theight != height ) { // Resize IWICImagingFactory* pWIC = _GetWIC(); if ( !pWIC ) return E_NOINTERFACE; ScopedObject<IWICBitmapScaler> scaler; hr = pWIC->CreateBitmapScaler( &scaler ); if ( FAILED(hr) ) return hr; hr = scaler->Initialize( frame, twidth, theight, WICBitmapInterpolationModeFant ); if ( FAILED(hr) ) return hr; WICPixelFormatGUID pfScaler; hr = scaler->GetPixelFormat( &pfScaler ); if ( FAILED(hr) ) return hr; if ( memcmp( &convertGUID, &pfScaler, sizeof(GUID) ) == 0 ) { // No format conversion needed hr = scaler->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() ); if ( FAILED(hr) ) return hr; } else { ScopedObject<IWICFormatConverter> FC; hr = pWIC->CreateFormatConverter( &FC ); if ( FAILED(hr) ) return hr; hr = FC->Initialize( scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom ); if ( FAILED(hr) ) return hr; hr = FC->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() ); if ( FAILED(hr) ) return hr; } } else { // Format conversion but no resize IWICImagingFactory* pWIC = _GetWIC(); if ( !pWIC ) return E_NOINTERFACE; ScopedObject<IWICFormatConverter> FC; hr = pWIC->CreateFormatConverter( &FC ); if ( FAILED(hr) ) return hr; hr = FC->Initialize( frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom ); if ( FAILED(hr) ) return hr; hr = FC->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() ); if ( FAILED(hr) ) return hr; } // See if format is supported for auto-gen mipmaps (varies by feature level) bool autogen = false; if ( d3dContext != 0 && textureView != 0 ) // Must have context and shader-view to auto generate mipmaps { UINT fmtSupport = 0; hr = d3dDevice->CheckFormatSupport( format, &fmtSupport ); if ( SUCCEEDED(hr) && ( fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN ) ) { autogen = true; } } // Create texture D3D11_TEXTURE2D_DESC desc; desc.Width = twidth; desc.Height = theight; desc.MipLevels = (autogen) ? 0 : 1; desc.ArraySize = 1; desc.Format = (forceSRGB) ? MakeSRGB( format ) : format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = usage; desc.CPUAccessFlags = cpuAccessFlags; if ( autogen ) { desc.BindFlags = bindFlags | D3D11_BIND_RENDER_TARGET; desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_GENERATE_MIPS; } else { desc.BindFlags = bindFlags; desc.MiscFlags = miscFlags; } D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = temp.get(); initData.SysMemPitch = static_cast<UINT>( rowPitch ); initData.SysMemSlicePitch = static_cast<UINT>( imageSize ); ID3D11Texture2D* tex = nullptr; hr = d3dDevice->CreateTexture2D( &desc, (autogen) ? nullptr : &initData, &tex ); if ( SUCCEEDED(hr) && tex != 0 ) { if (textureView != 0) { D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; memset( &SRVDesc, 0, sizeof( SRVDesc ) ); SRVDesc.Format = desc.Format; SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1; hr = d3dDevice->CreateShaderResourceView( tex, &SRVDesc, textureView ); if ( FAILED(hr) ) { tex->Release(); return hr; } if ( autogen ) { assert( d3dContext != 0 ); d3dContext->UpdateSubresource( tex, 0, nullptr, temp.get(), static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize) ); d3dContext->GenerateMips( *textureView ); } } if (texture != 0) { *texture = tex; } else { SetDebugObjectName(tex, "WICTextureLoader"); tex->Release(); } } return hr; }
// 建立渲染窗口 ///////////////////////////////////////////////////////////////////////////////// void RenderEngine::CreateRenderWindow(std::string const & name, RenderSettings& settings) { if (settings.stereo_method != STM_OculusVR) { stereo_separation_ = settings.stereo_separation; } this->DoCreateRenderWindow(name, settings); this->CheckConfig(settings); RenderDeviceCaps const & caps = this->DeviceCaps(); screen_frame_buffer_ = cur_frame_buffer_; uint32_t const screen_width = screen_frame_buffer_->Width(); uint32_t const screen_height = screen_frame_buffer_->Height(); float const screen_aspect = static_cast<float>(screen_width) / screen_height; if (!MathLib::equal(screen_aspect, static_cast<float>(settings.width) / settings.height)) { settings.width = static_cast<uint32_t>(settings.height * screen_aspect + 0.5f); } RenderFactory& rf = Context::Instance().RenderFactoryInstance(); pp_rl_ = rf.MakeRenderLayout(); pp_rl_->TopologyType(RenderLayout::TT_TriangleStrip); float2 pos[] = { float2(-1, +1), float2(+1, +1), float2(-1, -1), float2(+1, -1) }; GraphicsBufferPtr pp_pos_vb = rf.MakeVertexBuffer(BU_Static, EAH_GPU_Read | EAH_Immutable, sizeof(pos), &pos[0]); pp_rl_->BindVertexStream(pp_pos_vb, std::make_tuple(vertex_element(VEU_Position, 0, EF_GR32F))); uint32_t const render_width = static_cast<uint32_t>(settings.width * default_render_width_scale_ + 0.5f); uint32_t const render_height = static_cast<uint32_t>(settings.height * default_render_height_scale_ + 0.5f); hdr_enabled_ = settings.hdr; if (settings.hdr) { hdr_pp_ = MakeSharedPtr<HDRPostProcess>(settings.fft_lens_effects); skip_hdr_pp_ = SyncLoadPostProcess("Copy.ppml", "copy"); } ppaa_enabled_ = settings.ppaa ? 1 : 0; gamma_enabled_ = settings.gamma; color_grading_enabled_ = settings.color_grading; if (settings.ppaa || settings.color_grading || settings.gamma) { for (size_t i = 0; i < 12; ++ i) { ldr_pps_[i] = SyncLoadPostProcess("PostToneMapping.ppml", "PostToneMapping" + boost::lexical_cast<std::string>(i)); } ldr_pp_ = ldr_pps_[ppaa_enabled_ * 4 + gamma_enabled_ * 2 + color_grading_enabled_]; } bool need_resize = false; if (!settings.hide_win) { need_resize = ((render_width != screen_width) || (render_height != screen_height)); resize_pps_[0] = SyncLoadPostProcess("Resizer.ppml", "bilinear"); resize_pps_[1] = MakeSharedPtr<BicubicFilteringPostProcess>(); float const scale_x = static_cast<float>(screen_width) / render_width; float const scale_y = static_cast<float>(screen_height) / render_height; float2 pos_scale; if (scale_x < scale_y) { pos_scale.x() = 1; pos_scale.y() = (scale_x * render_height) / screen_height; } else { pos_scale.x() = (scale_y * render_width) / screen_width; pos_scale.y() = 1; } for (size_t i = 0; i < 2; ++ i) { resize_pps_[i]->SetParam(0, pos_scale); } } for (int i = 0; i < 4; ++ i) { default_frame_buffers_[i] = screen_frame_buffer_; } RenderViewPtr ds_view; if (hdr_pp_ || ldr_pp_ || (settings.stereo_method != STM_None)) { ds_tex_ = this->ScreenDepthStencilTexture(); if (ds_tex_ && (screen_width == render_width) && (screen_height == render_height)) { ds_view = rf.Make2DDepthStencilRenderView(*ds_tex_, 0, 1, 0); } else { if (caps.texture_format_support(EF_D32F) || caps.texture_format_support(EF_D24S8) || caps.texture_format_support(EF_D16)) { ElementFormat fmt; if ((settings.depth_stencil_fmt != EF_Unknown) && caps.texture_format_support(settings.depth_stencil_fmt)) { fmt = settings.depth_stencil_fmt; } else { BOOST_ASSERT(caps.texture_format_support(EF_D16)); fmt = EF_D16; } ds_tex_ = rf.MakeTexture2D(render_width, render_height, 1, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write, nullptr); ds_view = rf.Make2DDepthStencilRenderView(*ds_tex_, 0, 1, 0); } else { ElementFormat fmt; if ((settings.depth_stencil_fmt != EF_Unknown) && caps.rendertarget_format_support(settings.depth_stencil_fmt, 1, 0)) { fmt = settings.depth_stencil_fmt; } else { BOOST_ASSERT(caps.rendertarget_format_support(EF_D16, 1, 0)); fmt = EF_D16; } ds_view = rf.Make2DDepthStencilRenderView(render_width, render_height, fmt, 1, 0); } } } if (settings.stereo_method != STM_None) { mono_frame_buffer_ = rf.MakeFrameBuffer(); mono_frame_buffer_->GetViewport()->camera = cur_frame_buffer_->GetViewport()->camera; ElementFormat fmt; if (caps.texture_format_support(settings.color_fmt) && caps.rendertarget_format_support(settings.color_fmt, 1, 0)) { fmt = settings.color_fmt; } else { if (caps.texture_format_support(EF_ABGR8) && caps.rendertarget_format_support(EF_ABGR8, 1, 0)) { fmt = EF_ABGR8; } else { BOOST_ASSERT(caps.texture_format_support(EF_ARGB8) && caps.rendertarget_format_support(EF_ARGB8, 1, 0)); fmt = EF_ARGB8; } } mono_tex_ = rf.MakeTexture2D(screen_width, screen_height, 1, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write, nullptr); mono_frame_buffer_->Attach(FrameBuffer::ATT_Color0, rf.Make2DRenderView(*mono_tex_, 0, 1, 0)); default_frame_buffers_[0] = default_frame_buffers_[1] = default_frame_buffers_[2] = mono_frame_buffer_; overlay_frame_buffer_ = rf.MakeFrameBuffer(); overlay_frame_buffer_->GetViewport()->camera = cur_frame_buffer_->GetViewport()->camera; overlay_tex_ = rf.MakeTexture2D(screen_width, screen_height, 1, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write, nullptr); overlay_frame_buffer_->Attach(FrameBuffer::ATT_Color0, rf.Make2DRenderView(*overlay_tex_, 0, 1, 0)); RenderViewPtr screen_size_ds_view; if (need_resize) { screen_size_ds_view = rf.Make2DDepthStencilRenderView(screen_width, screen_height, ds_view->Format(), 1, 0); } else { screen_size_ds_view = ds_view; } overlay_frame_buffer_->Attach(FrameBuffer::ATT_DepthStencil, screen_size_ds_view); } else { if (need_resize) { resize_frame_buffer_ = rf.MakeFrameBuffer(); resize_frame_buffer_->GetViewport()->camera = cur_frame_buffer_->GetViewport()->camera; ElementFormat fmt; if (caps.texture_format_support(EF_ABGR8) && caps.rendertarget_format_support(EF_ABGR8, 1, 0)) { fmt = EF_ABGR8; } else { BOOST_ASSERT(caps.texture_format_support(EF_ARGB8) && caps.rendertarget_format_support(EF_ARGB8, 1, 0)); fmt = EF_ARGB8; } resize_tex_ = rf.MakeTexture2D(render_width, render_height, 1, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write, nullptr); resize_frame_buffer_->Attach(FrameBuffer::ATT_Color0, rf.Make2DRenderView(*resize_tex_, 0, 1, 0)); ElementFormat ds_fmt; if ((settings.depth_stencil_fmt != EF_Unknown) && caps.rendertarget_format_support(settings.depth_stencil_fmt, 1, 0)) { ds_fmt = settings.depth_stencil_fmt; } else { BOOST_ASSERT(caps.rendertarget_format_support(EF_D16, 1, 0)); ds_fmt = EF_D16; } resize_frame_buffer_->Attach(FrameBuffer::ATT_DepthStencil, rf.Make2DDepthStencilRenderView(render_width, render_height, ds_fmt, 1, 0)); default_frame_buffers_[0] = default_frame_buffers_[1] = default_frame_buffers_[2] = resize_frame_buffer_; } } if (ldr_pp_) { ldr_frame_buffer_ = rf.MakeFrameBuffer(); ldr_frame_buffer_->GetViewport()->camera = cur_frame_buffer_->GetViewport()->camera; ElementFormat fmt; if (caps.texture_format_support(EF_ABGR8) && caps.rendertarget_format_support(EF_ABGR8, 1, 0)) { fmt = EF_ABGR8; } else { BOOST_ASSERT(caps.texture_format_support(EF_ARGB8) && caps.rendertarget_format_support(EF_ARGB8, 1, 0)); fmt = EF_ARGB8; } ElementFormat fmt_srgb = MakeSRGB(fmt); if (caps.texture_format_support(fmt_srgb) && caps.rendertarget_format_support(fmt_srgb, 1, 0)) { fmt = fmt_srgb; } ldr_tex_ = rf.MakeTexture2D(render_width, render_height, 1, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write, nullptr); ldr_frame_buffer_->Attach(FrameBuffer::ATT_Color0, rf.Make2DRenderView(*ldr_tex_, 0, 1, 0)); ldr_frame_buffer_->Attach(FrameBuffer::ATT_DepthStencil, ds_view); default_frame_buffers_[0] = default_frame_buffers_[1] = ldr_frame_buffer_; } if (hdr_pp_) { hdr_frame_buffer_ = rf.MakeFrameBuffer(); hdr_frame_buffer_->GetViewport()->camera = cur_frame_buffer_->GetViewport()->camera; ElementFormat fmt; if (caps.fp_color_support) { if (caps.texture_format_support(EF_B10G11R11F) && caps.rendertarget_format_support(EF_B10G11R11F, 1, 0)) { fmt = EF_B10G11R11F; } else { BOOST_ASSERT(caps.texture_format_support(EF_ABGR16F) && caps.rendertarget_format_support(EF_ABGR16F, 1, 0)); fmt = EF_ABGR16F; } } else { if (caps.texture_format_support(EF_ABGR8) && caps.rendertarget_format_support(EF_ABGR8, 1, 0)) { fmt = EF_ABGR8; } else { BOOST_ASSERT(caps.texture_format_support(EF_ARGB8) && caps.rendertarget_format_support(EF_ARGB8, 1, 0)); fmt = EF_ARGB8; } ElementFormat fmt_srgb = MakeSRGB(fmt); if (caps.rendertarget_format_support(fmt_srgb, 1, 0)) { fmt = fmt_srgb; } } hdr_tex_ = rf.MakeTexture2D(render_width, render_height, 4, 1, fmt, 1, 0, EAH_GPU_Read | EAH_GPU_Write | EAH_Generate_Mips, nullptr); hdr_frame_buffer_->Attach(FrameBuffer::ATT_Color0, rf.Make2DRenderView(*hdr_tex_, 0, 1, 0)); hdr_frame_buffer_->Attach(FrameBuffer::ATT_DepthStencil, ds_view); default_frame_buffers_[0] = hdr_frame_buffer_; } this->BindFrameBuffer(default_frame_buffers_[0]); this->Stereo(settings.stereo_method); #ifndef KLAYGE_SHIP PerfProfiler& profiler = PerfProfiler::Instance(); hdr_pp_perf_ = profiler.CreatePerfRange(0, "HDR PP"); ldr_pp_perf_ = profiler.CreatePerfRange(0, "LDR PP"); resize_pp_perf_ = profiler.CreatePerfRange(0, "Resize PP"); stereoscopic_pp_perf_ = profiler.CreatePerfRange(0, "Stereoscopic PP"); #endif }