/** Preprocesses a shader without performing compilation, and dump it out for debugging*/ void D3D9PreProcessShader( const TCHAR* strFilename, const FString& strShaderFile, vector<D3DXMACRO>& Defines, const FD3DIncludeEnvironment& Environment, const TCHAR* strShaderPath ) { TRefCountPtr<ID3DXBuffer> ShaderCode; TRefCountPtr<ID3DXBuffer> ErrorText; FTCHARToANSI AnsiShaderFile(strShaderFile.c_str()); FD3DIncludeEnvironment IncludeEnvironment(Environment); HRESULT ret = D3DXPreprocessShader( (ANSICHAR*)AnsiShaderFile, strShaderFile.size(), &Defines.at(0), &IncludeEnvironment, ShaderCode.GetInitReference(), ErrorText.GetInitReference() ); if( FAILED(ret) ) { debugf(NAME_Warning, TEXT("Preprocess failed for shader %s: %s"), strFilename, ANSI_TO_TCHAR(ErrorText->GetBufferPointer())); } else { TCHAR Tmp[MAX_SPRINTF]; appSprintf(Tmp, TEXT("%s%s.pre"), strShaderPath, strFilename); appSaveStringToFile(ANSI_TO_TCHAR(ShaderCode->GetBufferPointer()), Tmp); } }
void FSlateD3DRenderer::Private_CreateViewport( TSharedRef<SWindow> InWindow, const FVector2D &WindowSize ) { TSharedRef< FGenericWindow > NativeWindow = InWindow->GetNativeWindow().ToSharedRef(); bool bFullscreen = IsViewportFullscreen( *InWindow ); bool bWindowed = true;//@todo implement fullscreen: !bFullscreen; DXGI_SWAP_CHAIN_DESC SwapChainDesc; FMemory::Memzero(&SwapChainDesc, sizeof(SwapChainDesc) ); SwapChainDesc.BufferCount = 1; SwapChainDesc.BufferDesc.Width = FMath::TruncToInt(WindowSize.X); SwapChainDesc.BufferDesc.Height = FMath::TruncToInt(WindowSize.Y); SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; SwapChainDesc.BufferDesc.RefreshRate.Numerator = 0; SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1; SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; SwapChainDesc.OutputWindow = (HWND)NativeWindow->GetOSWindowHandle(); SwapChainDesc.SampleDesc.Count = 1; SwapChainDesc.SampleDesc.Quality = 0; SwapChainDesc.Windowed = bWindowed; SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; TRefCountPtr<IDXGIDevice> DXGIDevice; HRESULT Hr = GD3DDevice->QueryInterface( __uuidof(IDXGIDevice), (void**)DXGIDevice.GetInitReference() ); check( SUCCEEDED(Hr) ); TRefCountPtr<IDXGIAdapter> DXGIAdapter; Hr = DXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)DXGIAdapter.GetInitReference() ); check( SUCCEEDED(Hr) ); TRefCountPtr<IDXGIFactory> DXGIFactory; DXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)DXGIFactory.GetInitReference() ); check( SUCCEEDED(Hr) ); FSlateD3DViewport Viewport; Hr = DXGIFactory->CreateSwapChain(DXGIDevice.GetReference(), &SwapChainDesc, Viewport.D3DSwapChain.GetInitReference() ); check( SUCCEEDED(Hr) ); Hr = DXGIFactory->MakeWindowAssociation((HWND)NativeWindow->GetOSWindowHandle(),DXGI_MWA_NO_ALT_ENTER); check(SUCCEEDED(Hr)); uint32 Width = FMath::TruncToInt(WindowSize.X); uint32 Height = FMath::TruncToInt(WindowSize.Y); Viewport.ViewportInfo.MaxDepth = 1.0f; Viewport.ViewportInfo.MinDepth = 0.0f; Viewport.ViewportInfo.Width = Width; Viewport.ViewportInfo.Height = Height; Viewport.ViewportInfo.TopLeftX = 0; Viewport.ViewportInfo.TopLeftY = 0; CreateBackBufferResources( Viewport.D3DSwapChain, Viewport.BackBufferTexture, Viewport.RenderTargetView ); Viewport.ProjectionMatrix = CreateProjectionMatrixD3D( Width, Height ); WindowToViewportMap.Add( &InWindow.Get(), Viewport ); }
void FOculusRiftPlugin::SetGraphicsAdapter(const ovrGraphicsLuid& luid) { TRefCountPtr<IDXGIFactory> DXGIFactory; if(SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**) DXGIFactory.GetInitReference()))) { for(int32 adapterIndex = 0;; adapterIndex++) { TRefCountPtr<IDXGIAdapter> DXGIAdapter; DXGI_ADAPTER_DESC DXGIAdapterDesc; if( FAILED(DXGIFactory->EnumAdapters(adapterIndex, DXGIAdapter.GetInitReference())) || FAILED(DXGIAdapter->GetDesc(&DXGIAdapterDesc)) ) { break; } if(!FMemory::Memcmp(&luid, &DXGIAdapterDesc.AdapterLuid, sizeof(LUID))) { // Remember this adapterIndex so we use the right adapter, even when we startup without HMD connected GConfig->SetInt(TEXT("Oculus.Settings"), TEXT("GraphicsAdapter"), adapterIndex, GEngineIni); break; } } } }
void FSlateD3DRenderer::CreateBackBufferResources( TRefCountPtr<IDXGISwapChain>& InSwapChain, TRefCountPtr<ID3D11Texture2D>& OutBackBuffer, TRefCountPtr<ID3D11RenderTargetView>& OutRTV ) { InSwapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (void**)OutBackBuffer.GetInitReference() ); D3D11_RENDER_TARGET_VIEW_DESC RTVDesc; RTVDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; RTVDesc.Texture2D.MipSlice = 0; HRESULT Hr = GD3DDevice->CreateRenderTargetView( OutBackBuffer, &RTVDesc, OutRTV.GetInitReference() ); check( SUCCEEDED(Hr) ); }
FDynamicRHI* FD3D12DynamicRHIModule::CreateRHI() { TRefCountPtr<IDXGIFactory4> DXGIFactory; SafeCreateDXGIFactory(DXGIFactory.GetInitReference()); check(DXGIFactory); return new FD3D12DynamicRHI(DXGIFactory, ChosenAdapter); }
FD3D11Viewport::FD3D11Viewport(FD3D11DynamicRHI* InD3DRHI,HWND InWindowHandle,uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat): D3DRHI(InD3DRHI), LastFlipTime(0), LastFrameComplete(0), LastCompleteTime(0), SyncCounter(0), bSyncedLastFrame(false), WindowHandle(InWindowHandle), MaximumFrameLatency(3), SizeX(InSizeX), SizeY(InSizeY), bIsFullscreen(bInIsFullscreen), PixelFormat(InPreferredPixelFormat), bIsValid(true), FrameSyncEvent(InD3DRHI) { check(IsInGameThread()); D3DRHI->Viewports.Add(this); // Ensure that the D3D device has been created. D3DRHI->InitD3DDevice(); // Create a backbuffer/swapchain for each viewport TRefCountPtr<IDXGIDevice> DXGIDevice; VERIFYD3D11RESULT(D3DRHI->GetDevice()->QueryInterface( IID_IDXGIDevice, (void**)DXGIDevice.GetInitReference() )); // Create the swapchain. DXGI_SWAP_CHAIN_DESC SwapChainDesc; FMemory::Memzero( &SwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC) ); SwapChainDesc.BufferDesc = SetupDXGI_MODE_DESC(); // MSAA Sample count SwapChainDesc.SampleDesc.Count = 1; SwapChainDesc.SampleDesc.Quality = 0; SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; // 1:single buffering, 2:double buffering, 3:triple buffering SwapChainDesc.BufferCount = 1; SwapChainDesc.OutputWindow = WindowHandle; SwapChainDesc.Windowed = !bIsFullscreen; // DXGI_SWAP_EFFECT_DISCARD / DXGI_SWAP_EFFECT_SEQUENTIAL SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; VERIFYD3D11RESULT(D3DRHI->GetFactory()->CreateSwapChain(DXGIDevice,&SwapChainDesc,SwapChain.GetInitReference())); // Set the DXGI message hook to not change the window behind our back. D3DRHI->GetFactory()->MakeWindowAssociation(WindowHandle,DXGI_MWA_NO_WINDOW_CHANGES); // Create a RHI surface to represent the viewport's back buffer. BackBuffer = GetSwapChainSurface(D3DRHI, PixelFormat, SwapChain); // Tell the window to redraw when they can. // @todo: For Slate viewports, it doesn't make sense to post WM_PAINT messages (we swallow those.) ::PostMessage( WindowHandle, WM_PAINT, 0, 0 ); BeginInitResource(&FrameSyncEvent); }
/** * Creates a FD3D11Surface to represent a swap chain's back buffer. */ FD3D11Texture2D* GetSwapChainSurface(FD3D11DynamicRHI* D3DRHI,IDXGISwapChain* SwapChain) { // Grab the back buffer TRefCountPtr<ID3D11Texture2D> BackBufferResource; VERIFYD3D11RESULT_EX(SwapChain->GetBuffer(0,IID_ID3D11Texture2D,(void**)BackBufferResource.GetInitReference()), D3DRHI->GetDevice()); // create the render target view TRefCountPtr<ID3D11RenderTargetView> BackBufferRenderTargetView; D3D11_RENDER_TARGET_VIEW_DESC RTVDesc; RTVDesc.Format = DXGI_FORMAT_UNKNOWN; RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; RTVDesc.Texture2D.MipSlice = 0; VERIFYD3D11RESULT(D3DRHI->GetDevice()->CreateRenderTargetView(BackBufferResource,&RTVDesc,BackBufferRenderTargetView.GetInitReference())); D3D11_TEXTURE2D_DESC TextureDesc; BackBufferResource->GetDesc(&TextureDesc); TArray<TRefCountPtr<ID3D11RenderTargetView> > RenderTargetViews; RenderTargetViews.Add(BackBufferRenderTargetView); // create a shader resource view to allow using the backbuffer as a texture TRefCountPtr<ID3D11ShaderResourceView> BackBufferShaderResourceView; D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; SRVDesc.Format = DXGI_FORMAT_UNKNOWN; SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; SRVDesc.Texture2D.MostDetailedMip = 0; SRVDesc.Texture2D.MipLevels = 1; VERIFYD3D11RESULT(D3DRHI->GetDevice()->CreateShaderResourceView(BackBufferResource,&SRVDesc,BackBufferShaderResourceView.GetInitReference())); FD3D11Texture2D* NewTexture = new FD3D11Texture2D( D3DRHI, BackBufferResource, BackBufferShaderResourceView, false, 1, RenderTargetViews, NULL, TextureDesc.Width, TextureDesc.Height, 1, 1, 1, PF_A2B10G10R10, false, false, false ); D3D11TextureAllocated2D(*NewTexture); NewTexture->DoNoDeferDelete(); return NewTexture; }
FIndexBufferRHIRef FD3D11DynamicRHI::RHICreateIndexBuffer(uint32 Stride,uint32 Size,uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) { // Explicitly check that the size is nonzero before allowing CreateIndexBuffer to opaquely fail. check(Size > 0); // Describe the index buffer. D3D11_BUFFER_DESC Desc; ZeroMemory( &Desc, sizeof( D3D11_BUFFER_DESC ) ); Desc.ByteWidth = Size; Desc.Usage = (InUsage & BUF_AnyDynamic) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT; Desc.BindFlags = D3D11_BIND_INDEX_BUFFER; Desc.CPUAccessFlags = (InUsage & BUF_AnyDynamic) ? D3D11_CPU_ACCESS_WRITE : 0; Desc.MiscFlags = 0; if (InUsage & BUF_UnorderedAccess) { Desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; } if(InUsage & BUF_DrawIndirect) { Desc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; } if (InUsage & BUF_ShaderResource) { Desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; } // If a resource array was provided for the resource, create the resource pre-populated D3D11_SUBRESOURCE_DATA InitData; D3D11_SUBRESOURCE_DATA* pInitData = NULL; if(CreateInfo.ResourceArray) { check(Size == CreateInfo.ResourceArray->GetResourceDataSize()); InitData.pSysMem = CreateInfo.ResourceArray->GetResourceData(); InitData.SysMemPitch = Size; InitData.SysMemSlicePitch = 0; pInitData = &InitData; } TRefCountPtr<ID3D11Buffer> IndexBufferResource; VERIFYD3D11RESULT(Direct3DDevice->CreateBuffer(&Desc,pInitData,IndexBufferResource.GetInitReference())); UpdateBufferStats(IndexBufferResource, true); if(CreateInfo.ResourceArray) { // Discard the resource array's contents. CreateInfo.ResourceArray->Discard(); } return new FD3D11IndexBuffer(IndexBufferResource, Stride, Size, InUsage); }
FUnorderedAccessViewRHIRef FD3D12DynamicRHI::RHICreateUnorderedAccessView(FStructuredBufferRHIParamRef StructuredBufferRHI, bool bUseUAVCounter, bool bAppendBuffer) { FD3D12StructuredBuffer* StructuredBuffer = FD3D12DynamicRHI::ResourceCast(StructuredBufferRHI); const D3D12_RESOURCE_DESC& BufferDesc = StructuredBuffer->Resource->GetDesc(); const uint32 BufferUsage = StructuredBuffer->GetUsage(); const bool bByteAccessBuffer = (BufferUsage & BUF_ByteAddressBuffer) != 0; const bool bStructuredBuffer = !bByteAccessBuffer; check(bByteAccessBuffer != bStructuredBuffer); // You can't have a structured buffer that allows raw views D3D12_UNORDERED_ACCESS_VIEW_DESC UAVDesc ={}; UAVDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; UAVDesc.Format = DXGI_FORMAT_UNKNOWN; uint32 EffectiveStride = StructuredBuffer->GetStride(); if (bByteAccessBuffer) { UAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; EffectiveStride = 4; } else if (BufferUsage & BUF_DrawIndirect) { UAVDesc.Format = DXGI_FORMAT_R32_UINT; EffectiveStride = 4; } UAVDesc.Buffer.FirstElement = StructuredBuffer->ResourceLocation->GetOffset() / EffectiveStride; UAVDesc.Buffer.NumElements = StructuredBuffer->ResourceLocation->GetEffectiveBufferSize() / EffectiveStride; UAVDesc.Buffer.StructureByteStride = bStructuredBuffer ? EffectiveStride : 0; UAVDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; UAVDesc.Buffer.CounterOffsetInBytes = 0; const bool bNeedsCounterResource = bAppendBuffer | bUseUAVCounter; TRefCountPtr<FD3D12Resource> CounterResource; if (bNeedsCounterResource) { GetRHIDevice()->GetResourceHelper().CreateBuffer(D3D12_HEAP_TYPE_DEFAULT, 4, CounterResource.GetInitReference(), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); } if (bByteAccessBuffer) { UAVDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; } return new FD3D12UnorderedAccessView(GetRHIDevice(), &UAVDesc, StructuredBuffer->ResourceLocation, CounterResource); }
int32 FD3DGPUProfiler::RecordEventTimestamp(ID3D11Device* Direct3DDevice, ID3D11DeviceContext* Direct3DDeviceIMContext) { check(CurrentGPUProfile); D3D11_QUERY_DESC TimestampQueryDesc; TimestampQueryDesc.Query = D3D11_QUERY_TIMESTAMP; TimestampQueryDesc.MiscFlags = 0; TRefCountPtr<ID3D11Query> TimestampQuery; VERIFYD3D11RESULT(Direct3DDevice->CreateQuery(&TimestampQueryDesc,TimestampQuery.GetInitReference())); Direct3DDeviceIMContext->End(TimestampQuery); return CurrentGPUProfile->EventTimestampQueries.Add(TimestampQuery); }
static uint32 CountAdapterOutputs(TRefCountPtr<IDXGIAdapter>& Adapter) { uint32 OutputCount = 0; for(;;) { TRefCountPtr<IDXGIOutput> Output; HRESULT hr = Adapter->EnumOutputs(OutputCount, Output.GetInitReference()); if(FAILED(hr)) { break; } ++OutputCount; } return OutputCount; }
/** * Initializes the static variables, if necessary. */ void FD3D11BufferedGPUTiming::PlatformStaticInitialize(void* UserData) { // Are the static variables initialized? check( !GAreGlobalsInitialized ); // Get the GPU timestamp frequency. GTimingFrequency = 0; TRefCountPtr<ID3D11Query> FreqQuery; FD3D11DynamicRHI* D3DRHI = (FD3D11DynamicRHI*)UserData; ID3D11DeviceContext *D3D11DeviceContext = D3DRHI->GetDeviceContext(); HRESULT D3DResult; D3D11_QUERY_DESC QueryDesc; QueryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; QueryDesc.MiscFlags = 0; D3DResult = D3DRHI->GetDevice()->CreateQuery(&QueryDesc, FreqQuery.GetInitReference() ); if ( D3DResult == S_OK ) { D3D11DeviceContext->Begin(FreqQuery); D3D11DeviceContext->End(FreqQuery); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT FreqQueryData; D3DResult = D3D11DeviceContext->GetData(FreqQuery,&FreqQueryData,sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT),0); double StartTime = FPlatformTime::Seconds(); while ( D3DResult == S_FALSE && (FPlatformTime::Seconds() - StartTime) < 0.1 ) { FPlatformProcess::Sleep( 0.005f ); D3DResult = D3D11DeviceContext->GetData(FreqQuery,&FreqQueryData,sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT),0); } if(D3DResult == S_OK) { GTimingFrequency = FreqQueryData.Frequency; checkSlow(!FreqQueryData.Disjoint); } } FreqQuery = NULL; }
bool FD3D11Viewport::Present(bool bLockToVsync) { bool bNativelyPresented = true; #if D3D11_WITH_DWMAPI // We can't call Present if !bIsValid, as it waits a window message to be processed, but the main thread may not be pumping the message handler. if(bIsValid) { // Check if the viewport's swap chain has been invalidated by DXGI. BOOL bSwapChainFullscreenState; TRefCountPtr<IDXGIOutput> SwapChainOutput; VERIFYD3D11RESULT(SwapChain->GetFullscreenState(&bSwapChainFullscreenState,SwapChainOutput.GetInitReference())); // Can't compare BOOL with bool... if ( (!!bSwapChainFullscreenState) != bIsFullscreen ) { bIsValid = false; // Minimize the window. // use SW_FORCEMINIMIZE if the messaging thread is likely to be blocked for a sizeable period. // SW_FORCEMINIMIZE also prevents the minimize animation from playing. ::ShowWindow(WindowHandle,SW_MINIMIZE); } } // When desktop composition is enabled, locking to vsync via the Present // call is unreliable. Instead, communicate with the desktop window manager // directly to enable vsync. const bool bSyncWithDWM = bLockToVsync && !bIsFullscreen && RHIConsoleVariables::bSyncWithDWM && IsCompositionEnabled(); if (bSyncWithDWM) { PresentWithVsyncDWM(); } else #endif //D3D11_WITH_DWMAPI { // Present the back buffer to the viewport window. bNativelyPresented = PresentChecked(bLockToVsync ? RHIConsoleVariables::SyncInterval : 0); } return bNativelyPresented; }
FRenderQueryRHIRef FD3D11DynamicRHI::RHICreateRenderQuery(ERenderQueryType QueryType) { TRefCountPtr<ID3D11Query> Query; D3D11_QUERY_DESC Desc; if(QueryType == RQT_Occlusion) { Desc.Query = D3D11_QUERY_OCCLUSION; } else if(QueryType == RQT_AbsoluteTime) { Desc.Query = D3D11_QUERY_TIMESTAMP; } else { check(0); } Desc.MiscFlags = 0; VERIFYD3D11RESULT(Direct3DDevice->CreateQuery(&Desc,Query.GetInitReference())); return new FD3D11OcclusionQuery(Query, QueryType); }
void FSlateD3DRenderer::CreateDepthStencilBuffer( FSlateD3DViewport& Viewport ) { TRefCountPtr<ID3D11Texture2D> DepthStencil; D3D11_TEXTURE2D_DESC DescDepth; DescDepth.Width = Viewport.ViewportInfo.Width; DescDepth.Height = Viewport.ViewportInfo.Height; DescDepth.MipLevels = 1; DescDepth.ArraySize = 1; #if DEPTH_32_BIT_CONVERSION DescDepth.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; #else DescDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; #endif DescDepth.SampleDesc.Count = 1; DescDepth.SampleDesc.Quality = 0; DescDepth.Usage = D3D11_USAGE_DEFAULT; DescDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; DescDepth.CPUAccessFlags = 0; DescDepth.MiscFlags = 0; HRESULT Hr = GD3DDevice->CreateTexture2D( &DescDepth, NULL, DepthStencil.GetInitReference() ); check( SUCCEEDED(Hr) ); D3D11_DEPTH_STENCIL_VIEW_DESC DescDSV; #if DEPTH_32_BIT_CONVERSION DescDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT ; #else DescDSV.Format = DXGI_FORMAT_D24_UNORM_S8_UINT ; #endif DescDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; DescDSV.Texture2D.MipSlice = 0; DescDSV.Flags = 0; // Create the depth stencil view Hr = GD3DDevice->CreateDepthStencilView( DepthStencil, &DescDSV, Viewport.DepthStencilView.GetInitReference() ); check( SUCCEEDED(Hr) ); }
/** Merges a set of D3DXMeshes. */ static void MergeD3DXMeshes( IDirect3DDevice9* Device, TRefCountPtr<ID3DXMesh>& OutMesh,TArray<int32>& OutBaseFaceIndex,const TArray<ID3DXMesh*>& Meshes) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); // Count the number of faces and vertices in the input meshes. int32 NumFaces = 0; int32 NumVertices = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { NumFaces += Meshes[MeshIndex]->GetNumFaces(); NumVertices += Meshes[MeshIndex]->GetNumVertices(); } // Create mesh for source data VERIFYD3D9RESULT(D3DXCreateMesh( NumFaces, NumVertices, D3DXMESH_SYSTEMMEM, (D3DVERTEXELEMENT9*)VertexElements.GetData(), Device, OutMesh.GetInitReference() ) ); // Fill D3DXMesh FUtilVertex* ResultVertices; uint16* ResultIndices; ::DWORD * ResultAttributes; OutMesh->LockVertexBuffer(0,(LPVOID*)&ResultVertices); OutMesh->LockIndexBuffer(0,(LPVOID*)&ResultIndices); OutMesh->LockAttributeBuffer(0, &ResultAttributes); int32 BaseVertexIndex = 0; int32 BaseFaceIndex = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { ID3DXMesh* Mesh = Meshes[MeshIndex]; FUtilVertex* Vertices; uint16* Indices; ::DWORD * Attributes; Mesh->LockVertexBuffer(0,(LPVOID*)&Vertices); Mesh->LockIndexBuffer(0,(LPVOID*)&Indices); Mesh->LockAttributeBuffer(0, &Attributes); for(uint32 FaceIndex = 0;FaceIndex < Mesh->GetNumFaces();FaceIndex++) { for(uint32 VertexIndex = 0;VertexIndex < 3;VertexIndex++) { *ResultIndices++ = BaseVertexIndex + *Indices++; } } OutBaseFaceIndex.Add(BaseFaceIndex); BaseFaceIndex += Mesh->GetNumFaces(); FMemory::Memcpy(ResultVertices,Vertices,Mesh->GetNumVertices() * sizeof(FUtilVertex)); ResultVertices += Mesh->GetNumVertices(); BaseVertexIndex += Mesh->GetNumVertices(); FMemory::Memcpy(ResultAttributes,Attributes,Mesh->GetNumFaces() * sizeof(uint32)); ResultAttributes += Mesh->GetNumFaces(); Mesh->UnlockIndexBuffer(); Mesh->UnlockVertexBuffer(); Mesh->UnlockAttributeBuffer(); } OutMesh->UnlockIndexBuffer(); OutMesh->UnlockVertexBuffer(); OutMesh->UnlockAttributeBuffer(); }
void* FD3D11DynamicRHI::RHILockIndexBuffer(FIndexBufferRHIParamRef IndexBufferRHI,uint32 Offset,uint32 Size,EResourceLockMode LockMode) { FD3D11IndexBuffer* IndexBuffer = ResourceCast(IndexBufferRHI); // If this resource is bound to the device, unbind it ConditionalClearShaderResource(IndexBuffer); // Determine whether the index buffer is dynamic or not. D3D11_BUFFER_DESC Desc; IndexBuffer->Resource->GetDesc(&Desc); const bool bIsDynamic = (Desc.Usage == D3D11_USAGE_DYNAMIC); FD3D11LockedKey LockedKey(IndexBuffer->Resource); FD3D11LockedData LockedData; if(bIsDynamic) { check(LockMode == RLM_WriteOnly); // If the buffer is dynamic, map its memory for writing. D3D11_MAPPED_SUBRESOURCE MappedSubresource; VERIFYD3D11RESULT(Direct3DDeviceIMContext->Map(IndexBuffer->Resource,0,D3D11_MAP_WRITE_DISCARD,0,&MappedSubresource)); LockedData.SetData(MappedSubresource.pData); LockedData.Pitch = MappedSubresource.RowPitch; } else { if(LockMode == RLM_ReadOnly) { // If the static buffer is being locked for reading, create a staging buffer. D3D11_BUFFER_DESC StagingBufferDesc; ZeroMemory( &StagingBufferDesc, sizeof( D3D11_BUFFER_DESC ) ); StagingBufferDesc.ByteWidth = Size; StagingBufferDesc.Usage = D3D11_USAGE_STAGING; StagingBufferDesc.BindFlags = 0; StagingBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; StagingBufferDesc.MiscFlags = 0; TRefCountPtr<ID3D11Buffer> StagingIndexBuffer; VERIFYD3D11RESULT(Direct3DDevice->CreateBuffer(&StagingBufferDesc,NULL,StagingIndexBuffer.GetInitReference())); LockedData.StagingResource = StagingIndexBuffer; // Copy the contents of the index buffer to the staging buffer. Direct3DDeviceIMContext->CopyResource(StagingIndexBuffer,IndexBuffer->Resource); // Map the staging buffer's memory for reading. D3D11_MAPPED_SUBRESOURCE MappedSubresource; VERIFYD3D11RESULT(Direct3DDeviceIMContext->Map(StagingIndexBuffer,0,D3D11_MAP_READ,0,&MappedSubresource)); LockedData.SetData(MappedSubresource.pData); LockedData.Pitch = MappedSubresource.RowPitch; } else { // If the static buffer is being locked for writing, allocate memory for the contents to be written to. LockedData.AllocData(Desc.ByteWidth); LockedData.Pitch = Desc.ByteWidth; } } // Add the lock to the lock map. OutstandingLocks.Add(LockedKey,LockedData); // Return the offset pointer return (void*)((uint8*)LockedData.GetData() + Offset); }
FSamplerStateRHIRef FD3D11DynamicRHI::RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) { D3D11_SAMPLER_DESC SamplerDesc; FMemory::Memzero(&SamplerDesc,sizeof(D3D11_SAMPLER_DESC)); int32 MaxAnisotropyCVar = GetCachedScalabilityCVars().MaxAnisotropy; SamplerDesc.AddressU = TranslateAddressMode(Initializer.AddressU); SamplerDesc.AddressV = TranslateAddressMode(Initializer.AddressV); SamplerDesc.AddressW = TranslateAddressMode(Initializer.AddressW); SamplerDesc.MipLODBias = Initializer.MipBias; SamplerDesc.MaxAnisotropy = FMath::Clamp(Initializer.MaxAnisotropy > 0 ? Initializer.MaxAnisotropy : MaxAnisotropyCVar,1,16); SamplerDesc.MinLOD = Initializer.MinMipLevel; SamplerDesc.MaxLOD = Initializer.MaxMipLevel; // Determine whether we should use one of the comparison modes const bool bComparisonEnabled = Initializer.SamplerComparisonFunction != SCF_Never; switch(Initializer.Filter) { case SF_AnisotropicLinear: case SF_AnisotropicPoint: if (SamplerDesc.MaxAnisotropy == 1) { SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR; } else { // D3D11 doesn't allow using point filtering for mip filter when using anisotropic filtering SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_ANISOTROPIC : D3D11_FILTER_ANISOTROPIC; } break; case SF_Trilinear: SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR; break; case SF_Bilinear: SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT : D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; break; case SF_Point: SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_POINT; break; } const FLinearColor LinearBorderColor = FColor(Initializer.BorderColor); SamplerDesc.BorderColor[0] = LinearBorderColor.R; SamplerDesc.BorderColor[1] = LinearBorderColor.G; SamplerDesc.BorderColor[2] = LinearBorderColor.B; SamplerDesc.BorderColor[3] = LinearBorderColor.A; SamplerDesc.ComparisonFunc = TranslateSamplerCompareFunction(Initializer.SamplerComparisonFunction); #if LOCK_GSamplerStateCache QUICK_SCOPE_CYCLE_COUNTER(FD3D11DynamicRHI_RHICreateSamplerState_LockAndCreate); FScopeLock Lock(&GSamplerStateCacheLock); #endif // D3D11 will return the same pointer if the particular state description was already created TRefCountPtr<ID3D11SamplerState> SamplerStateHandle; VERIFYD3D11RESULT(Direct3DDevice->CreateSamplerState(&SamplerDesc, SamplerStateHandle.GetInitReference())); FD3D11SamplerState** Found = GSamplerStateCache.Find(SamplerStateHandle); if (Found) { return *Found; } FD3D11SamplerState* SamplerState = new FD3D11SamplerState; SamplerState->Resource = SamplerStateHandle; // Manually add reference as we control the creation/destructions SamplerState->AddRef(); GSamplerStateCache.Add(SamplerStateHandle.GetReference(), SamplerState); return SamplerState; }
FStructuredBufferRHIRef FD3D11DynamicRHI::RHICreateStructuredBuffer(uint32 Stride,uint32 Size,uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) { // Explicitly check that the size is nonzero before allowing CreateStructuredBuffer to opaquely fail. check(Size > 0); // Check for values that will cause D3D calls to fail check(Size / Stride > 0 && Size % Stride == 0); D3D11_BUFFER_DESC Desc; ZeroMemory( &Desc, sizeof( D3D11_BUFFER_DESC ) ); Desc.ByteWidth = Size; Desc.Usage = (InUsage & BUF_AnyDynamic) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT; Desc.BindFlags = 0; if(InUsage & BUF_ShaderResource) { // Setup bind flags so we can create a view to read from the buffer in a shader. Desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; } if (InUsage & BUF_UnorderedAccess) { // Setup bind flags so we can create a writeable UAV to the buffer Desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; } if (InUsage & BUF_StreamOutput) { Desc.BindFlags |= D3D11_BIND_STREAM_OUTPUT; } Desc.CPUAccessFlags = (InUsage & BUF_AnyDynamic) ? D3D11_CPU_ACCESS_WRITE : 0; Desc.MiscFlags = 0; if (InUsage & BUF_DrawIndirect) { Desc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; } else { if (InUsage & BUF_ByteAddressBuffer) { Desc.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; } else { Desc.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; } } Desc.StructureByteStride = Stride; if (FPlatformProperties::SupportsFastVRAMMemory()) { if (InUsage & BUF_FastVRAM) { FFastVRAMAllocator::GetFastVRAMAllocator()->AllocUAVBuffer(Desc); } } // If a resource array was provided for the resource, create the resource pre-populated D3D11_SUBRESOURCE_DATA InitData; D3D11_SUBRESOURCE_DATA* pInitData = NULL; if(CreateInfo.ResourceArray) { check(Size == CreateInfo.ResourceArray->GetResourceDataSize()); InitData.pSysMem = CreateInfo.ResourceArray->GetResourceData(); InitData.SysMemPitch = Size; InitData.SysMemSlicePitch = 0; pInitData = &InitData; } TRefCountPtr<ID3D11Buffer> StructuredBufferResource; VERIFYD3D11RESULT_EX(Direct3DDevice->CreateBuffer(&Desc,pInitData,StructuredBufferResource.GetInitReference()), Direct3DDevice); UpdateBufferStats(StructuredBufferResource, true); if(CreateInfo.ResourceArray) { // Discard the resource array's contents. CreateInfo.ResourceArray->Discard(); } return new FD3D11StructuredBuffer(StructuredBufferResource,Stride,Size,InUsage); }
void FD3D11DynamicRHI::InitD3DDevice() { check( IsInGameThread() ); // Wait for the rendering thread to go idle. SCOPED_SUSPEND_RENDERING_THREAD(false); // If the device we were using has been removed, release it and the resources we created for it. if(bDeviceRemoved) { UE_LOG(LogD3D11RHI, Log, TEXT("bDeviceRemoved")); check(Direct3DDevice); HRESULT hRes = Direct3DDevice->GetDeviceRemovedReason(); const TCHAR* Reason = TEXT("?"); switch(hRes) { case DXGI_ERROR_DEVICE_HUNG: Reason = TEXT("HUNG"); break; case DXGI_ERROR_DEVICE_REMOVED: Reason = TEXT("REMOVED"); break; case DXGI_ERROR_DEVICE_RESET: Reason = TEXT("RESET"); break; case DXGI_ERROR_DRIVER_INTERNAL_ERROR: Reason = TEXT("INTERNAL_ERROR"); break; case DXGI_ERROR_INVALID_CALL: Reason = TEXT("INVALID_CALL"); break; } bDeviceRemoved = false; // Cleanup the D3D device. CleanupD3DDevice(); // We currently don't support removed devices because FTexture2DResource can't recreate its RHI resources from scratch. // We would also need to recreate the viewport swap chains from scratch. UE_LOG(LogD3D11RHI, Fatal, TEXT("The Direct3D 11 device that was being used has been removed (Error: %d '%s'). Please restart the game."), hRes, Reason); } // If we don't have a device yet, either because this is the first viewport, or the old device was removed, create a device. if(!Direct3DDevice) { UE_LOG(LogD3D11RHI, Log, TEXT("!Direct3DDevice")); check(!GIsRHIInitialized); // Clear shadowed shader resources. ClearState(); // Determine the adapter and device type to use. TRefCountPtr<IDXGIAdapter> Adapter; // In Direct3D 11, if you are trying to create a hardware or a software device, set pAdapter != NULL which constrains the other inputs to be: // DriverType must be D3D_DRIVER_TYPE_UNKNOWN // Software must be NULL. D3D_DRIVER_TYPE DriverType = D3D_DRIVER_TYPE_UNKNOWN; uint32 DeviceFlags = D3D11RHI_ShouldAllowAsyncResourceCreation() ? 0 : D3D11_CREATE_DEVICE_SINGLETHREADED; // Use a debug device if specified on the command line. const bool bWithD3DDebug = D3D11RHI_ShouldCreateWithD3DDebug(); if (bWithD3DDebug) { DeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; UE_LOG(LogD3D11RHI, Log, TEXT("InitD3DDevice: -D3DDebug = %s"), bWithD3DDebug ? TEXT("on") : TEXT("off")); } GTexturePoolSize = 0; TRefCountPtr<IDXGIAdapter> EnumAdapter; if(DXGIFactory1->EnumAdapters(ChosenAdapter,EnumAdapter.GetInitReference()) != DXGI_ERROR_NOT_FOUND) { if (EnumAdapter)// && EnumAdapter->CheckInterfaceSupport(__uuidof(ID3D11Device),NULL) == S_OK) { DXGI_ADAPTER_DESC AdapterDesc; if (SUCCEEDED(EnumAdapter->GetDesc(&AdapterDesc))) { Adapter = EnumAdapter; GRHIAdapterName = AdapterDesc.Description; GRHIVendorId = AdapterDesc.VendorId; // Issue: 32bit windows doesn't report 64bit value, we take what we get. FD3D11GlobalStats::GDedicatedVideoMemory = int64(AdapterDesc.DedicatedVideoMemory); FD3D11GlobalStats::GDedicatedSystemMemory = int64(AdapterDesc.DedicatedSystemMemory); FD3D11GlobalStats::GSharedSystemMemory = int64(AdapterDesc.SharedSystemMemory); // Total amount of system memory, clamped to 8 GB int64 TotalPhysicalMemory = FMath::Min(int64(FPlatformMemory::GetConstants().TotalPhysicalGB), 8ll) * (1024ll * 1024ll * 1024ll); // Consider 50% of the shared memory but max 25% of total system memory. int64 ConsideredSharedSystemMemory = FMath::Min( FD3D11GlobalStats::GSharedSystemMemory / 2ll, TotalPhysicalMemory / 4ll ); FD3D11GlobalStats::GTotalGraphicsMemory = 0; if ( IsRHIDeviceIntel() ) { // It's all system memory. FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedVideoMemory; FD3D11GlobalStats::GTotalGraphicsMemory += FD3D11GlobalStats::GDedicatedSystemMemory; FD3D11GlobalStats::GTotalGraphicsMemory += ConsideredSharedSystemMemory; } else if ( FD3D11GlobalStats::GDedicatedVideoMemory >= 200*1024*1024 ) { // Use dedicated video memory, if it's more than 200 MB FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedVideoMemory; } else if ( FD3D11GlobalStats::GDedicatedSystemMemory >= 200*1024*1024 ) { // Use dedicated system memory, if it's more than 200 MB FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedSystemMemory; } else if ( FD3D11GlobalStats::GSharedSystemMemory >= 400*1024*1024 ) { // Use some shared system memory, if it's more than 400 MB FD3D11GlobalStats::GTotalGraphicsMemory = ConsideredSharedSystemMemory; } else { // Otherwise consider 25% of total system memory for graphics. FD3D11GlobalStats::GTotalGraphicsMemory = TotalPhysicalMemory / 4ll; } if ( sizeof(SIZE_T) < 8 ) { // Clamp to 1 GB if we're less than 64-bit FD3D11GlobalStats::GTotalGraphicsMemory = FMath::Min( FD3D11GlobalStats::GTotalGraphicsMemory, 1024ll * 1024ll * 1024ll ); } else { // Clamp to 1.9 GB if we're 64-bit FD3D11GlobalStats::GTotalGraphicsMemory = FMath::Min( FD3D11GlobalStats::GTotalGraphicsMemory, 1945ll * 1024ll * 1024ll ); } if ( GPoolSizeVRAMPercentage > 0 ) { float PoolSize = float(GPoolSizeVRAMPercentage) * 0.01f * float(FD3D11GlobalStats::GTotalGraphicsMemory); // Truncate GTexturePoolSize to MB (but still counted in bytes) GTexturePoolSize = int64(FGenericPlatformMath::TruncToFloat(PoolSize / 1024.0f / 1024.0f)) * 1024 * 1024; UE_LOG(LogRHI,Log,TEXT("Texture pool is %llu MB (%d%% of %llu MB)"), GTexturePoolSize / 1024 / 1024, GPoolSizeVRAMPercentage, FD3D11GlobalStats::GTotalGraphicsMemory / 1024 / 1024); } const bool bIsPerfHUD = !FCString::Stricmp(AdapterDesc.Description,TEXT("NVIDIA PerfHUD")); if(bIsPerfHUD) { DriverType = D3D_DRIVER_TYPE_REFERENCE; } } else { check(!"Internal error, GetDesc() failed but before it worked") } } } else {
void FD3D11DynamicRHIModule::FindAdapter() { // Once we chosen one we don't need to do it again. check(!ChosenAdapter.IsValid()); // Try to create the DXGIFactory1. This will fail if we're not running Vista SP2 or higher. TRefCountPtr<IDXGIFactory1> DXGIFactory1; SafeCreateDXGIFactory(DXGIFactory1.GetInitReference()); if(!DXGIFactory1) { return; } bool bAllowPerfHUD = true; #if UE_BUILD_SHIPPING || UE_BUILD_TEST bAllowPerfHUD = false; #endif int32 CVarValue = CVarGraphicsAdapter.GetValueOnGameThread(); const bool bFavorNonIntegrated = CVarValue == -1; TRefCountPtr<IDXGIAdapter> TempAdapter; D3D_FEATURE_LEVEL MaxAllowedFeatureLevel = GetAllowedD3DFeatureLevel(); FD3D11Adapter FirstWithoutIntegratedAdapter; FD3D11Adapter FirstAdapter; bool bIsAnyAMD = false; bool bIsAnyIntel = false; bool bIsAnyNVIDIA = false; // Enumerate the DXGIFactory's adapters. for(uint32 AdapterIndex = 0; DXGIFactory1->EnumAdapters(AdapterIndex,TempAdapter.GetInitReference()) != DXGI_ERROR_NOT_FOUND; ++AdapterIndex) { // Check that if adapter supports D3D11. if(TempAdapter) { D3D_FEATURE_LEVEL ActualFeatureLevel = (D3D_FEATURE_LEVEL)0; if(SafeTestD3D11CreateDevice(TempAdapter,MaxAllowedFeatureLevel,&ActualFeatureLevel)) { // Log some information about the available D3D11 adapters. DXGI_ADAPTER_DESC AdapterDesc; VERIFYD3D11RESULT(TempAdapter->GetDesc(&AdapterDesc)); uint32 OutputCount = CountAdapterOutputs(TempAdapter); UE_LOG(LogD3D11RHI, Log, TEXT("Found D3D11 adapter %u: %s (Feature Level %s)"), AdapterIndex, AdapterDesc.Description, GetFeatureLevelString(ActualFeatureLevel) ); UE_LOG(LogD3D11RHI, Log, TEXT("Adapter has %uMB of dedicated video memory, %uMB of dedicated system memory, and %uMB of shared system memory, %d output[s]"), (uint32)(AdapterDesc.DedicatedVideoMemory / (1024*1024)), (uint32)(AdapterDesc.DedicatedSystemMemory / (1024*1024)), (uint32)(AdapterDesc.SharedSystemMemory / (1024*1024)), OutputCount ); bool bIsAMD = AdapterDesc.VendorId == 0x1002; bool bIsIntel = AdapterDesc.VendorId == 0x8086; bool bIsNVIDIA = AdapterDesc.VendorId == 0x10DE; if(bIsAMD) bIsAnyAMD = true; if(bIsIntel) bIsAnyIntel = true; if(bIsNVIDIA) bIsAnyNVIDIA = true; // Simple heuristic but without profiling it's hard to do better const bool bIsIntegrated = bIsIntel; // PerfHUD is for performance profiling const bool bIsPerfHUD = !FCString::Stricmp(AdapterDesc.Description,TEXT("NVIDIA PerfHUD")); FD3D11Adapter CurrentAdapter(AdapterIndex, ActualFeatureLevel); if(!OutputCount) { // This device has no outputs. Reject it, // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205075%28v=vs.85%29.aspx#WARP_new_for_Win8 continue; } if(bIsPerfHUD && !bAllowPerfHUD) { // we don't allow the PerfHUD adapter continue; } if(CVarValue >= 0 && AdapterIndex != CVarValue) { // the user wants a specific adapter, not this one continue; } if(!bIsIntegrated && !FirstWithoutIntegratedAdapter.IsValid()) { FirstWithoutIntegratedAdapter = CurrentAdapter; } if(!FirstAdapter.IsValid()) { FirstAdapter = CurrentAdapter; } } } } if(bFavorNonIntegrated && (bIsAnyAMD || bIsAnyNVIDIA)) { ChosenAdapter = FirstWithoutIntegratedAdapter; // We assume Intel is integrated graphics (slower than discrete) than NVIDIA or AMD cards and rather take a different one if(!ChosenAdapter.IsValid()) { ChosenAdapter = FirstAdapter; } } else { ChosenAdapter = FirstAdapter; } if(ChosenAdapter.IsValid()) { UE_LOG(LogD3D11RHI, Log, TEXT("Chosen D3D11 Adapter Id = %u"), ChosenAdapter.AdapterIndex); } else { UE_LOG(LogD3D11RHI, Error, TEXT("Failed to choose a D3D11 Adapter.")); } }
FUnorderedAccessViewRHIRef FD3D11DynamicRHI::RHICreateUnorderedAccessView(FTextureRHIParamRef TextureRHI) { FD3D11TextureBase* Texture = GetD3D11TextureFromRHITexture(TextureRHI); D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc; if (TextureRHI->GetTexture3D() != NULL) { FD3D11Texture3D* Texture3D = (FD3D11Texture3D*)Texture; UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D; UAVDesc.Texture3D.MipSlice = 0; UAVDesc.Texture3D.FirstWSlice = 0; UAVDesc.Texture3D.WSize = Texture3D->GetSizeZ(); } else { UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; UAVDesc.Texture2D.MipSlice = 0; } UAVDesc.Format = FindShaderResourceDXGIFormat((DXGI_FORMAT)GPixelFormats[TextureRHI->GetFormat()].PlatformFormat, false); TRefCountPtr<ID3D11UnorderedAccessView> UnorderedAccessView; VERIFYD3D11RESULT(Direct3DDevice->CreateUnorderedAccessView(Texture->GetResource(),&UAVDesc,(ID3D11UnorderedAccessView**)UnorderedAccessView.GetInitReference())); return new FD3D11UnorderedAccessView(UnorderedAccessView,Texture); }
bool FD3D9MeshUtilities::GenerateUVs( struct FRawMesh& RawMesh, uint32 TexCoordIndex, float MinChartSpacingPercent, float BorderSpacingPercent, bool bUseMaxStretch, const TArray< int32 >* InFalseEdgeIndices, uint32& MaxCharts, float& MaxDesiredStretch, FText& OutError ) { OutError = FText(); if(!IsValid()) { OutError = LOCTEXT("GenerateUVs_FailedInvalid", "GenerateUVs failed, mesh was invalid."); return false; } int32 NumTexCoords = 0; for (int32 i = 0; i < MAX_MESH_TEXTURE_COORDS; ++i) { if (RawMesh.WedgeTexCoords[i].Num() != RawMesh.WedgeIndices.Num()) { break; } NumTexCoords++; } if (TexCoordIndex > (uint32)NumTexCoords) { OutError = LOCTEXT("GenerateUVs_FailedUVs", "GenerateUVs failed, incorrect number of texcoords."); return false; } TRefCountPtr<ID3DXMesh> ChartMesh; TArray<uint32> AtlasAndChartAdjacency; TArray<int32> AtlasAndChartTriangleCharts; { const bool bUseFalseEdges = InFalseEdgeIndices != NULL; // When using false edges we don't remove degenerates as we want our incoming selected edge list to map // correctly to the D3DXMesh. const bool bRemoveDegenerateTriangles = !bUseFalseEdges; // Create a D3DXMesh for the triangles being charted. TRefCountPtr<ID3DXMesh> SourceMesh; if (!ConvertRawMeshToD3DXMesh(Device, RawMesh,bRemoveDegenerateTriangles,SourceMesh)) { OutError = LOCTEXT("GenerateUVs_FailedConvert", "GenerateUVs failed, couldn't convert to a D3DXMesh."); return false; } //generate adjacency info for the mesh, which is needed later TArray<uint32> Adjacency; GenerateAdjacency(SourceMesh,Adjacency,FFragmentedAdjacencyFilter()); // We don't clean the mesh as this can collapse vertices or delete degenerate triangles, and // we want our incoming selected edge list to map correctly to the D3DXMesh. if( !bUseFalseEdges ) { //clean the mesh TRefCountPtr<ID3DXMesh> TempMesh; TArray<uint32> CleanedAdjacency; CleanedAdjacency.AddUninitialized(SourceMesh->GetNumFaces() * 3); if( FAILED(D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, SourceMesh, (::DWORD *)Adjacency.GetTypedData(), TempMesh.GetInitReference(), (::DWORD *)CleanedAdjacency.GetTypedData(), NULL ) ) ) { OutError = LOCTEXT("GenerateUVs_FailedClean", "GenerateUVs failed, couldn't clean mesh."); return false; } SourceMesh = TempMesh; Adjacency = CleanedAdjacency; } // Setup the D3DX "false edge" array. This is three DWORDS per face that define properties of the // face's edges. Values of -1 indicates that the edge may be used as a UV seam in a the chart. Any // other value indicates that the edge should never be a UV seam. This essentially allows us to // provide a precise list of edges to be used as UV seams in the new charts. uint32* FalseEdgeArray = NULL; TArray<uint32> FalseEdges; if( bUseFalseEdges ) { // -1 means "always use this edge as a chart UV seam" to D3DX FalseEdges.AddUninitialized( SourceMesh->GetNumFaces() * 3 ); for( int32 CurFalseEdgeIndex = 0; CurFalseEdgeIndex < (int32)SourceMesh->GetNumFaces() * 3; ++CurFalseEdgeIndex ) { FalseEdges[ CurFalseEdgeIndex ] = -1; } // For each tagged edge for( int32 CurTaggedEdgeIndex = 0; CurTaggedEdgeIndex < InFalseEdgeIndices->Num(); ++CurTaggedEdgeIndex ) { const int32 EdgeIndex = ( *InFalseEdgeIndices )[ CurTaggedEdgeIndex ]; // Mark this as a false edge by setting it to a value other than negative one FalseEdges[ EdgeIndex ] = Adjacency[ CurTaggedEdgeIndex ]; } FalseEdgeArray = (uint32*)FalseEdges.GetTypedData(); } // Partition the mesh's triangles into charts. TRefCountPtr<ID3DXBuffer> PartitionResultAdjacencyBuffer; TRefCountPtr<ID3DXBuffer> FacePartitionBuffer; HRESULT Result = D3DXUVAtlasPartition( SourceMesh, bUseMaxStretch ? 0 : MaxCharts, // Max charts (0 = use max stretch instead) MaxDesiredStretch, TexCoordIndex, (::DWORD *)Adjacency.GetTypedData(), (::DWORD *)FalseEdgeArray, // False edges NULL, // IMT data &GenerateUVsStatusCallback, 0.01f, // Callback frequency NULL, // Callback user data D3DXUVATLAS_GEODESIC_QUALITY, ChartMesh.GetInitReference(), FacePartitionBuffer.GetInitReference(), NULL, PartitionResultAdjacencyBuffer.GetInitReference(), &MaxDesiredStretch, &MaxCharts ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPartition() returned %u with MaxDesiredStretch=%.2f, TexCoordIndex=%u."), Result, MaxDesiredStretch, TexCoordIndex ); OutError = LOCTEXT("GenerateUVs_FailedPartition", "GenerateUVs failed, D3DXUVAtlasPartition failed."); return false; } // Extract the chart adjacency data from the D3DX buffer into an array. for(uint32 TriangleIndex = 0;TriangleIndex < ChartMesh->GetNumFaces();TriangleIndex++) { for(int32 EdgeIndex = 0;EdgeIndex < 3;EdgeIndex++) { AtlasAndChartAdjacency.Add(*((uint32*)PartitionResultAdjacencyBuffer->GetBufferPointer()+TriangleIndex*3+EdgeIndex)); } } // Extract the triangle chart data from the D3DX buffer into an array. uint32* FacePartitionBufferPointer = (uint32*)FacePartitionBuffer->GetBufferPointer(); for(uint32 TriangleIndex = 0;TriangleIndex < ChartMesh->GetNumFaces();TriangleIndex++) { AtlasAndChartTriangleCharts.Add(*FacePartitionBufferPointer++); } // Scale the partitioned UVs down. FUtilVertex* LockedVertices; ChartMesh->LockVertexBuffer(0,(LPVOID*)&LockedVertices); for(uint32 VertexIndex = 0;VertexIndex < ChartMesh->GetNumVertices();VertexIndex++) { LockedVertices[VertexIndex].UVs[TexCoordIndex] /= 2048.0f; } ChartMesh->UnlockVertexBuffer(); } if(ChartMesh) { // Create a buffer to hold the triangle chart data. TRefCountPtr<ID3DXBuffer> MergedTriangleChartsBuffer; VERIFYD3D9RESULT(D3DXCreateBuffer( AtlasAndChartTriangleCharts.Num() * sizeof(int32), MergedTriangleChartsBuffer.GetInitReference() )); uint32* MergedTriangleChartsBufferPointer = (uint32*)MergedTriangleChartsBuffer->GetBufferPointer(); for(int32 TriangleIndex = 0;TriangleIndex < AtlasAndChartTriangleCharts.Num();TriangleIndex++) { *MergedTriangleChartsBufferPointer++ = AtlasAndChartTriangleCharts[TriangleIndex]; } const uint32 FakeTexSize = 1024; const float GutterSize = ( float )FakeTexSize * MinChartSpacingPercent * 0.01f; // Pack the charts into a unified atlas. HRESULT Result = D3DXUVAtlasPack( ChartMesh, FakeTexSize, FakeTexSize, GutterSize, TexCoordIndex, (::DWORD *)AtlasAndChartAdjacency.GetTypedData(), &GenerateUVsStatusCallback, 0.01f, // Callback frequency NULL, 0, MergedTriangleChartsBuffer ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPack() returned %u."), Result ); OutError = LOCTEXT("GenerateUVs_FailedPack", "GenerateUVs failed, D3DXUVAtlasPack failed."); return false; } int32 NewNumTexCoords = FMath::Max<int32>(NumTexCoords, TexCoordIndex + 1); FRawMesh FinalMesh; if (!ConvertD3DXMeshToRawMesh(ChartMesh, FinalMesh, NewNumTexCoords)) { OutError = LOCTEXT("GenerateUVs_FailedSimple", "GenerateUVs failed, couldn't convert the simplified D3DXMesh back to a UStaticMesh."); return false; } // Scale/offset the UVs appropriately to ensure there is empty space around the border { const float BorderSize = BorderSpacingPercent * 0.01f; const float ScaleAmount = 1.0f - BorderSize * 2.0f; for( int32 CurUVIndex = 0; CurUVIndex < MAX_MESH_TEXTURE_COORDS; ++CurUVIndex ) { int32 NumWedges = FinalMesh.WedgeTexCoords[CurUVIndex].Num(); for( int32 WedgeIndex = 0; WedgeIndex < NumWedges; ++WedgeIndex ) { FVector2D& UV = FinalMesh.WedgeTexCoords[CurUVIndex][WedgeIndex]; UV.X = BorderSize + UV.X * ScaleAmount; UV.Y = BorderSize + UV.Y * ScaleAmount; } } } RawMesh = FinalMesh; } return true; }
FUnorderedAccessViewRHIRef FD3D11DynamicRHI::RHICreateUnorderedAccessView(FStructuredBufferRHIParamRef StructuredBufferRHI, bool bUseUAVCounter, bool bAppendBuffer) { FD3D11StructuredBuffer* StructuredBuffer = ResourceCast(StructuredBufferRHI); D3D11_BUFFER_DESC BufferDesc; StructuredBuffer->Resource->GetDesc(&BufferDesc); const bool bByteAccessBuffer = (BufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) != 0; D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc; UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; UAVDesc.Format = DXGI_FORMAT_UNKNOWN; if (BufferDesc.MiscFlags & D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS) { UAVDesc.Format = DXGI_FORMAT_R32_UINT; } else if (bByteAccessBuffer) { UAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; } UAVDesc.Buffer.FirstElement = 0; // For byte access buffers and indirect draw argument buffers, GetDesc returns a StructureByteStride of 0 even though we created it with 4 const uint32 EffectiveStride = BufferDesc.StructureByteStride == 0 ? 4 : BufferDesc.StructureByteStride; UAVDesc.Buffer.NumElements = BufferDesc.ByteWidth / EffectiveStride; UAVDesc.Buffer.Flags = 0; if (bUseUAVCounter) { UAVDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_COUNTER; } if (bAppendBuffer) { UAVDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_APPEND; } if (bByteAccessBuffer) { UAVDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW; } TRefCountPtr<ID3D11UnorderedAccessView> UnorderedAccessView; VERIFYD3D11RESULT(Direct3DDevice->CreateUnorderedAccessView(StructuredBuffer->Resource,&UAVDesc,(ID3D11UnorderedAccessView**)UnorderedAccessView.GetInitReference())); return new FD3D11UnorderedAccessView(UnorderedAccessView,StructuredBuffer); }
FUnorderedAccessViewRHIRef FD3D11DynamicRHI::RHICreateUnorderedAccessView(FVertexBufferRHIParamRef VertexBufferRHI, uint8 Format) { DYNAMIC_CAST_D3D11RESOURCE(VertexBuffer,VertexBuffer); D3D11_BUFFER_DESC BufferDesc; VertexBuffer->Resource->GetDesc(&BufferDesc); const bool bByteAccessBuffer = (BufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) != 0; D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc; UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; UAVDesc.Format = FindUnorderedAccessDXGIFormat((DXGI_FORMAT)GPixelFormats[Format].PlatformFormat); UAVDesc.Buffer.FirstElement = 0; UAVDesc.Buffer.NumElements = BufferDesc.ByteWidth / GPixelFormats[Format].BlockBytes; UAVDesc.Buffer.Flags = 0; if (bByteAccessBuffer) { UAVDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW; UAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; } TRefCountPtr<ID3D11UnorderedAccessView> UnorderedAccessView; VERIFYD3D11RESULT(Direct3DDevice->CreateUnorderedAccessView(VertexBuffer->Resource,&UAVDesc,(ID3D11UnorderedAccessView**)UnorderedAccessView.GetInitReference())); return new FD3D11UnorderedAccessView(UnorderedAccessView,VertexBuffer); }
FD3D11Texture2DSet* FD3D11Texture2DSet::D3D11CreateTexture2DSet( FD3D11DynamicRHI* InD3D11RHI, ovrSwapTextureSet* InTextureSet, const D3D11_TEXTURE2D_DESC& InDsDesc, EPixelFormat InFormat, uint32 InFlags ) { check(InTextureSet); TArray<TRefCountPtr<ID3D11RenderTargetView> > RenderTargetViews; FD3D11Texture2DSet* NewTextureSet = new FD3D11Texture2DSet( InD3D11RHI, nullptr, nullptr, false, 1, RenderTargetViews, /*DepthStencilViews=*/ NULL, InDsDesc.Width, InDsDesc.Height, 0, InDsDesc.MipLevels, InDsDesc.SampleDesc.Count, InFormat, /*bInCubemap=*/ false, InFlags, /*bPooledTexture=*/ false ); const uint32 TexCount = InTextureSet->TextureCount; const bool bSRGB = (InFlags & TexCreate_SRGB) != 0; const DXGI_FORMAT PlatformResourceFormat = (DXGI_FORMAT)GPixelFormats[InFormat].PlatformFormat; const DXGI_FORMAT PlatformShaderResourceFormat = FindShaderResourceDXGIFormat(PlatformResourceFormat, bSRGB); const DXGI_FORMAT PlatformRenderTargetFormat = FindShaderResourceDXGIFormat(PlatformResourceFormat, bSRGB); D3D11_RTV_DIMENSION RenderTargetViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; if (InDsDesc.SampleDesc.Count > 1) { RenderTargetViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; } for (uint32 i = 0; i < TexCount; ++i) { ovrD3D11Texture D3DTex; D3DTex.Texture = InTextureSet->Textures[i]; TArray<TRefCountPtr<ID3D11RenderTargetView> > RenderTargetViews; if (InFlags & TexCreate_RenderTargetable) { // Create a render target view for each mip for (uint32 MipIndex = 0; MipIndex < InDsDesc.MipLevels; MipIndex++) { check(!(InFlags & TexCreate_TargetArraySlicesIndependently)); // not supported D3D11_RENDER_TARGET_VIEW_DESC RTVDesc; FMemory::Memzero(&RTVDesc, sizeof(RTVDesc)); RTVDesc.Format = PlatformRenderTargetFormat; RTVDesc.ViewDimension = RenderTargetViewDimension; RTVDesc.Texture2D.MipSlice = MipIndex; TRefCountPtr<ID3D11RenderTargetView> RenderTargetView; VERIFYD3D11RESULT(InD3D11RHI->GetDevice()->CreateRenderTargetView(D3DTex.D3D11.pTexture, &RTVDesc, RenderTargetView.GetInitReference())); RenderTargetViews.Add(RenderTargetView); } } TRefCountPtr<ID3D11ShaderResourceView> ShaderResourceView = D3DTex.D3D11.pSRView; // Create a shader resource view for the texture. if (!ShaderResourceView && (InFlags & TexCreate_ShaderResource)) { D3D11_SRV_DIMENSION ShaderResourceViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; SRVDesc.Format = PlatformShaderResourceFormat; SRVDesc.ViewDimension = ShaderResourceViewDimension; SRVDesc.Texture2D.MostDetailedMip = 0; SRVDesc.Texture2D.MipLevels = InDsDesc.MipLevels; VERIFYD3D11RESULT(InD3D11RHI->GetDevice()->CreateShaderResourceView(D3DTex.D3D11.pTexture, &SRVDesc, ShaderResourceView.GetInitReference())); check(IsValidRef(ShaderResourceView)); } NewTextureSet->AddTexture(D3DTex.D3D11.pTexture, ShaderResourceView, &RenderTargetViews); } NewTextureSet->TextureSet = InTextureSet; NewTextureSet->InitWithCurrentElement(); return NewTextureSet; }
/** * Returns a supported screen resolution that most closely matches the input. * @param Width - Input: Desired resolution width in pixels. Output: A width that the platform supports. * @param Height - Input: Desired resolution height in pixels. Output: A height that the platform supports. */ void FD3D11DynamicRHI::RHIGetSupportedResolution( uint32 &Width, uint32 &Height ) { uint32 InitializedMode = false; DXGI_MODE_DESC BestMode; BestMode.Width = 0; BestMode.Height = 0; { HRESULT hr = S_OK; TRefCountPtr<IDXGIAdapter> Adapter; hr = DXGIFactory->EnumAdapters(ChosenAdapter,Adapter.GetInitReference()); if( DXGI_ERROR_NOT_FOUND == hr ) { return; } if( FAILED(hr) ) { return; } // get the description of the adapter DXGI_ADAPTER_DESC AdapterDesc; VERIFYD3D11RESULT(Adapter->GetDesc(&AdapterDesc)); // Enumerate outputs for this adapter // TODO: Cap at 1 for default output for(uint32 o = 0;o < 1; o++) { TRefCountPtr<IDXGIOutput> Output; hr = Adapter->EnumOutputs(o,Output.GetInitReference()); if(DXGI_ERROR_NOT_FOUND == hr) break; if(FAILED(hr)) return; // TODO: GetDisplayModeList is a terribly SLOW call. It can take up to a second per invocation. // We might want to work around some DXGI badness here. DXGI_FORMAT Format = DXGI_FORMAT_R8G8B8A8_UNORM; uint32 NumModes = 0; hr = Output->GetDisplayModeList(Format,0,&NumModes,NULL); if(hr == DXGI_ERROR_NOT_FOUND) { return; } else if(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { UE_LOG(LogD3D11RHI, Fatal, TEXT("This application cannot be run over a remote desktop configuration") ); return; } DXGI_MODE_DESC* ModeList = new DXGI_MODE_DESC[ NumModes ]; VERIFYD3D11RESULT(Output->GetDisplayModeList(Format,0,&NumModes,ModeList)); for(uint32 m = 0;m < NumModes;m++) { // Search for the best mode // Suppress static analysis warnings about a potentially out-of-bounds read access to ModeList. This is a false positive - Index is always within range. CA_SUPPRESS( 6385 ); bool IsEqualOrBetterWidth = FMath::Abs((int32)ModeList[m].Width - (int32)Width) <= FMath::Abs((int32)BestMode.Width - (int32)Width); bool IsEqualOrBetterHeight = FMath::Abs((int32)ModeList[m].Height - (int32)Height) <= FMath::Abs((int32)BestMode.Height - (int32)Height); if(!InitializedMode || (IsEqualOrBetterWidth && IsEqualOrBetterHeight)) { BestMode = ModeList[m]; InitializedMode = true; } } delete[] ModeList; } } check(InitializedMode); Width = BestMode.Width; Height = BestMode.Height; }
bool FD3D9MeshUtilities::LayoutUVs( struct FRawMesh& RawMesh, uint32 TextureResolution, uint32 TexCoordIndex, FText& OutError ) { OutError = FText(); if(!IsValid() || !RawMesh.IsValid()) { OutError = LOCTEXT("LayoutUVs_FailedInvalid", "LayoutUVs failed, mesh was invalid."); return false; } int32 NumTexCoords = 0; for (int32 i = 0; i < MAX_MESH_TEXTURE_COORDS; ++i) { if (RawMesh.WedgeTexCoords[i].Num() != RawMesh.WedgeIndices.Num()) { break; } NumTexCoords++; } if (TexCoordIndex > (uint32)NumTexCoords) { OutError = LOCTEXT("LayoutUVs_FailedUVs", "LayoutUVs failed, incorrect number of texcoords."); return false; } // Sort the mesh's triangles by whether they need to be charted, or just to be packed into the atlas. FRawMesh MeshToAtlas = RawMesh; if (TexCoordIndex > 0) { MeshToAtlas.WedgeTexCoords[TexCoordIndex] = MeshToAtlas.WedgeTexCoords[0]; } TRefCountPtr<ID3DXMesh> ChartMesh; TArray<uint32> AtlasAndChartAdjacency; TArray<int32> AtlasAndChartTriangleCharts; TRefCountPtr<ID3DXMesh> MergedMesh; TArray<uint32> MergedAdjacency; TArray<int32> MergedTriangleCharts; TRefCountPtr<ID3DXMesh> AtlasOnlyMesh; TArray<uint32> AtlasOnlyAdjacency; TArray<int32> AtlasOnlyTriangleCharts; { // Create a D3DXMesh for the triangles that only need to be atlassed. const bool bRemoveDegenerateTriangles = true; if (!ConvertRawMeshToD3DXMesh(Device,MeshToAtlas,bRemoveDegenerateTriangles,AtlasOnlyMesh)) { OutError = LOCTEXT("LayoutUVs_FailedConvert", "LayoutUVs failed, couldn't convert to a D3DXMesh."); return false; } // generate mapping orientations info FLayoutUVWindingInfo WindingInfo(AtlasOnlyMesh, TexCoordIndex); // Generate adjacency for the pre-charted triangles based on their input charts. GenerateAdjacency(AtlasOnlyMesh,AtlasOnlyAdjacency,FUVChartAdjacencyFilter(TexCoordIndex), &WindingInfo); ////clean the mesh TRefCountPtr<ID3DXMesh> TempMesh; TArray<uint32> CleanedAdjacency; CleanedAdjacency.AddUninitialized(AtlasOnlyMesh->GetNumFaces() * 3); if( FAILED(D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, AtlasOnlyMesh, (::DWORD *)AtlasOnlyAdjacency.GetTypedData(), TempMesh.GetInitReference(), (::DWORD *)CleanedAdjacency.GetTypedData(), NULL ) ) ) { OutError = LOCTEXT("LayoutUVs_FailedClean", "LayoutUVs failed, couldn't clean mesh."); return false; } // Group the pre-charted triangles into indexed charts based on their adjacency in the chart. AssignMinimalAdjacencyGroups(CleanedAdjacency,AtlasOnlyTriangleCharts); MergedMesh = TempMesh; MergedAdjacency = CleanedAdjacency; MergedTriangleCharts = AtlasOnlyTriangleCharts; } if(MergedMesh) { // Create a buffer to hold the triangle chart data. TRefCountPtr<ID3DXBuffer> MergedTriangleChartsBuffer; VERIFYD3D9RESULT(D3DXCreateBuffer( MergedTriangleCharts.Num() * sizeof(int32), MergedTriangleChartsBuffer.GetInitReference() )); uint32* MergedTriangleChartsBufferPointer = (uint32*)MergedTriangleChartsBuffer->GetBufferPointer(); for(int32 TriangleIndex = 0;TriangleIndex < MergedTriangleCharts.Num();TriangleIndex++) { *MergedTriangleChartsBufferPointer++ = MergedTriangleCharts[TriangleIndex]; } const float GutterSize = 2.0f; // Pack the charts into a unified atlas. HRESULT Result = D3DXUVAtlasPack( MergedMesh, TextureResolution, TextureResolution, GutterSize, TexCoordIndex, (::DWORD *)MergedAdjacency.GetTypedData(), NULL, 0, NULL, 0, MergedTriangleChartsBuffer ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPack() returned %u."), Result ); OutError = LOCTEXT("LayoutUVs_FailedPack", "LayoutUVs failed, D3DXUVAtlasPack failed."); return false; } int32 NewNumTexCoords = FMath::Max<int32>(NumTexCoords, TexCoordIndex + 1); FRawMesh FinalMesh; if (!ConvertD3DXMeshToRawMesh(MergedMesh, FinalMesh, NewNumTexCoords)) { OutError = LOCTEXT("LayoutUVs_FailedSimple", "LayoutUVs failed, couldn't convert the simplified D3DXMesh back to a UStaticMesh."); return false; } RawMesh = FinalMesh; } return true; }
static FD3D11Texture2D* D3D11CreateTexture2DAlias( FD3D11DynamicRHI* InD3D11RHI, ID3D11Texture2D* InResource, ID3D11ShaderResourceView* InShaderResourceView, uint32 InSizeX, uint32 InSizeY, uint32 InSizeZ, uint32 InNumMips, uint32 InNumSamples, EPixelFormat InFormat, uint32 InFlags) { const bool bSRGB = (InFlags & TexCreate_SRGB) != 0; const DXGI_FORMAT PlatformResourceFormat = (DXGI_FORMAT)GPixelFormats[InFormat].PlatformFormat; const DXGI_FORMAT PlatformShaderResourceFormat = FindShaderResourceDXGIFormat(PlatformResourceFormat, bSRGB); const DXGI_FORMAT PlatformRenderTargetFormat = FindShaderResourceDXGIFormat(PlatformResourceFormat, bSRGB); D3D11_RTV_DIMENSION RenderTargetViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; if (InNumSamples > 1) { RenderTargetViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; } TArray<TRefCountPtr<ID3D11RenderTargetView> > RenderTargetViews; if (InFlags & TexCreate_RenderTargetable) { // Create a render target view for each mip for (uint32 MipIndex = 0; MipIndex < InNumMips; MipIndex++) { check(!(InFlags & TexCreate_TargetArraySlicesIndependently)); // not supported D3D11_RENDER_TARGET_VIEW_DESC RTVDesc; FMemory::Memzero(&RTVDesc, sizeof(RTVDesc)); RTVDesc.Format = PlatformRenderTargetFormat; RTVDesc.ViewDimension = RenderTargetViewDimension; RTVDesc.Texture2D.MipSlice = MipIndex; TRefCountPtr<ID3D11RenderTargetView> RenderTargetView; VERIFYD3D11RESULT(InD3D11RHI->GetDevice()->CreateRenderTargetView(InResource, &RTVDesc, RenderTargetView.GetInitReference())); RenderTargetViews.Add(RenderTargetView); } } TRefCountPtr<ID3D11ShaderResourceView> ShaderResourceView; // Create a shader resource view for the texture. if (!InShaderResourceView && (InFlags & TexCreate_ShaderResource)) { D3D11_SRV_DIMENSION ShaderResourceViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; SRVDesc.Format = PlatformShaderResourceFormat; SRVDesc.ViewDimension = ShaderResourceViewDimension; SRVDesc.Texture2D.MostDetailedMip = 0; SRVDesc.Texture2D.MipLevels = InNumMips; VERIFYD3D11RESULT(InD3D11RHI->GetDevice()->CreateShaderResourceView(InResource, &SRVDesc, ShaderResourceView.GetInitReference())); check(IsValidRef(ShaderResourceView)); } else { ShaderResourceView = InShaderResourceView; } FD3D11Texture2D* NewTexture = new FD3D11Texture2D( InD3D11RHI, InResource, ShaderResourceView, false, 1, RenderTargetViews, /*DepthStencilViews=*/ NULL, InSizeX, InSizeY, InSizeZ, InNumMips, InNumSamples, InFormat, /*bInCubemap=*/ false, InFlags, /*bPooledTexture=*/ false ); return NewTexture; }
/** * Creates a D3DXMESH from a FStaticMeshRenderData * @param Triangles The triangles to create the mesh from. * @param bRemoveDegenerateTriangles True if degenerate triangles should be removed * @param OutD3DMesh Mesh to create * @return Boolean representing success or failure */ bool ConvertRawMeshToD3DXMesh( IDirect3DDevice9* Device, FRawMesh& RawMesh, const bool bRemoveDegenerateTriangles, TRefCountPtr<ID3DXMesh>& OutD3DMesh ) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); TArray<FUtilVertex> Vertices; TArray<uint16> Indices; TArray<uint32> Attributes; int32 NumWedges = RawMesh.WedgeIndices.Num(); int32 NumTriangles = NumWedges / 3; int32 NumUVs = 0; for (; NumUVs < 8; ++NumUVs) { if (RawMesh.WedgeTexCoords[NumUVs].Num() != RawMesh.WedgeIndices.Num()) { break; } } bool bHaveColors = RawMesh.WedgeColors.Num() == NumWedges; bool bHaveNormals = RawMesh.WedgeTangentZ.Num() == NumWedges; bool bHaveTangents = bHaveNormals && RawMesh.WedgeTangentX.Num() == NumWedges && RawMesh.WedgeTangentY.Num() == NumWedges; for(int32 TriangleIndex = 0;TriangleIndex < NumTriangles;TriangleIndex++) { bool bTriangleIsDegenerate = false; if( bRemoveDegenerateTriangles ) { // Detect if the triangle is degenerate. for(int32 EdgeIndex = 0;EdgeIndex < 3;EdgeIndex++) { const int32 Wedge0 = TriangleIndex * 3 + EdgeIndex; const int32 Wedge1 = TriangleIndex * 3 + ((EdgeIndex + 1) % 3); if((RawMesh.GetWedgePosition(Wedge0) - RawMesh.GetWedgePosition(Wedge1)).IsNearlyZero(THRESH_POINTS_ARE_SAME * 4.0f)) { bTriangleIsDegenerate = true; break; } } } if(!bTriangleIsDegenerate) { Attributes.Add(RawMesh.FaceMaterialIndices[TriangleIndex]); for(int32 J=0;J<3;J++) { FUtilVertex* Vertex = new(Vertices) FUtilVertex; FMemory::Memzero(Vertex,sizeof(FUtilVertex)); int32 WedgeIndex = TriangleIndex * 3 + J; Vertex->Position = RawMesh.GetWedgePosition(WedgeIndex); if (bHaveColors) { Vertex->Color = RawMesh.WedgeColors[WedgeIndex]; } else { Vertex->Color = FColor::White; } //store the smoothing mask per vertex since there is only one per-face attribute that is already being used (materialIndex) Vertex->SmoothingMask = RawMesh.FaceSmoothingMasks[TriangleIndex]; if (bHaveTangents) { Vertex->TangentX = RawMesh.WedgeTangentX[WedgeIndex]; Vertex->TangentY = RawMesh.WedgeTangentY[WedgeIndex]; } if (bHaveNormals) { Vertex->TangentZ = RawMesh.WedgeTangentZ[WedgeIndex]; } for(int32 UVIndex = 0; UVIndex < NumUVs; UVIndex++) { Vertex->UVs[UVIndex] = RawMesh.WedgeTexCoords[UVIndex][WedgeIndex]; } Indices.Add(Vertices.Num() - 1); } } } // This code uses the raw triangles. Needs welding, etc. const int32 NumFaces = Indices.Num() / 3; const int32 NumVertices = NumFaces*3; check(Attributes.Num() == NumFaces); check(NumFaces * 3 == Indices.Num()); // Create mesh for source data if (FAILED(D3DXCreateMesh(NumFaces,NumVertices,D3DXMESH_SYSTEMMEM,(D3DVERTEXELEMENT9 *)VertexElements.GetData(),Device,OutD3DMesh.GetInitReference()) ) ) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXCreateMesh() Failed!")); return false; } // Fill D3DMesh mesh FUtilVertex* D3DVertices; uint16* D3DIndices; ::DWORD * D3DAttributes; OutD3DMesh->LockVertexBuffer(0,(LPVOID*)&D3DVertices); OutD3DMesh->LockIndexBuffer(0,(LPVOID*)&D3DIndices); OutD3DMesh->LockAttributeBuffer(0, &D3DAttributes); FMemory::Memcpy(D3DVertices,Vertices.GetTypedData(),Vertices.Num() * sizeof(FUtilVertex)); FMemory::Memcpy(D3DIndices,Indices.GetTypedData(),Indices.Num() * sizeof(uint16)); FMemory::Memcpy(D3DAttributes,Attributes.GetTypedData(),Attributes.Num() * sizeof(uint32)); OutD3DMesh->UnlockIndexBuffer(); OutD3DMesh->UnlockVertexBuffer(); OutD3DMesh->UnlockAttributeBuffer(); return true; }