void GetUniformMeshStreamOutLayout(FStreamOutElementList& Layout) { Layout.Add(FStreamOutElement(0, "SV_Position", 0, 4, 0)); Layout.Add(FStreamOutElement(0, "Tangent", 0, 3, 0)); Layout.Add(FStreamOutElement(0, "Tangent", 1, 3, 0)); Layout.Add(FStreamOutElement(0, "Tangent", 2, 3, 0)); Layout.Add(FStreamOutElement(0, "UV", 0, 2, 0)); Layout.Add(FStreamOutElement(0, "UV", 1, 2, 0)); Layout.Add(FStreamOutElement(0, "VertexColor", 0, 4, 0)); }
/** Returns number of float's in the uniform vertex. */ int32 ComputeUniformVertexStride() { FStreamOutElementList Layout; int32 StreamStride = 0; GetUniformMeshStreamOutLayout(Layout); for (int32 ElementIndex = 0; ElementIndex < Layout.Num(); ElementIndex++) { StreamStride += Layout[ElementIndex].ComponentCount; } // D3D11 stream out buffer element stride must be a factor of 4 return FMath::DivideAndRoundUp(StreamStride, 4) * 4; }
FGeometryShaderRHIRef FD3D11DynamicRHI::RHICreateGeometryShaderWithStreamOutput(const TArray<uint8>& Code, const FStreamOutElementList& ElementList, uint32 NumStrides, const uint32* Strides, int32 RasterizedStream) { check(Code.Num()); FD3D11GeometryShader* Shader = new FD3D11GeometryShader; FMemoryReader Ar( Code, true ); Ar << Shader->ShaderResourceTable; int32 Offset = Ar.Tell(); const uint8* CodePtr = Code.GetData() + Offset; const size_t CodeSize = Code.Num() - Offset - 1; uint32 D3DRasterizedStream = RasterizedStream; if (RasterizedStream == -1) { D3DRasterizedStream = D3D11_SO_NO_RASTERIZED_STREAM; } D3D11_SO_DECLARATION_ENTRY StreamOutEntries[D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT]; for (int32 EntryIndex = 0; EntryIndex < ElementList.Num(); EntryIndex++) { StreamOutEntries[EntryIndex].Stream = ElementList[EntryIndex].Stream; StreamOutEntries[EntryIndex].SemanticName = ElementList[EntryIndex].SemanticName; StreamOutEntries[EntryIndex].SemanticIndex = ElementList[EntryIndex].SemanticIndex; StreamOutEntries[EntryIndex].StartComponent = ElementList[EntryIndex].StartComponent; StreamOutEntries[EntryIndex].ComponentCount = ElementList[EntryIndex].ComponentCount; StreamOutEntries[EntryIndex].OutputSlot = ElementList[EntryIndex].OutputSlot; } VERIFYD3D11RESULT( Direct3DDevice->CreateGeometryShaderWithStreamOutput( (void*)CodePtr, CodeSize, StreamOutEntries, ElementList.Num(), Strides, NumStrides, D3DRasterizedStream, NULL, Shader->Resource.GetInitReference() ) ); // bGlobalUniformBufferUsed is in the last byte, see CompileD3D11Shader Shader->bShaderNeedsGlobalConstantBuffer = Code[Code.Num() - 1] != 0; return Shader; }
FGeometryShaderRHIRef FD3D11DynamicRHI::RHICreateGeometryShaderWithStreamOutput(const TArray<uint8>& Code, const FStreamOutElementList& ElementList, uint32 NumStrides, const uint32* Strides, int32 RasterizedStream) { check(Code.Num()); uint32 D3DRasterizedStream = RasterizedStream; if (RasterizedStream == -1) { D3DRasterizedStream = D3D11_SO_NO_RASTERIZED_STREAM; } D3D11_SO_DECLARATION_ENTRY StreamOutEntries[D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT]; for (int32 EntryIndex = 0; EntryIndex < ElementList.Num(); EntryIndex++) { StreamOutEntries[EntryIndex].Stream = ElementList[EntryIndex].Stream; StreamOutEntries[EntryIndex].SemanticName = ElementList[EntryIndex].SemanticName; StreamOutEntries[EntryIndex].SemanticIndex = ElementList[EntryIndex].SemanticIndex; StreamOutEntries[EntryIndex].StartComponent = ElementList[EntryIndex].StartComponent; StreamOutEntries[EntryIndex].ComponentCount = ElementList[EntryIndex].ComponentCount; StreamOutEntries[EntryIndex].OutputSlot = ElementList[EntryIndex].OutputSlot; } TRefCountPtr<ID3D11GeometryShader> D3DShader; VERIFYD3D11RESULT(Direct3DDevice->CreateGeometryShaderWithStreamOutput( (const void*)Code.GetTypedData(), // bGlobalUniformBufferUsed is in the last byte, see CompileD3D11Shader Code.Num() - 1, StreamOutEntries, ElementList.Num(), Strides, NumStrides, D3DRasterizedStream, NULL, (ID3D11GeometryShader**)D3DShader.GetInitReference())); return new FD3D11GeometryShader(D3DShader, Code); }
void FShaderResource::InitRHI() { checkf(Code.Num() > 0, TEXT("FShaderResource::InitRHI was called with empty bytecode, which can happen if the resource is initialized multiple times on platforms with no editor data.")); // we can't have this called on the wrong platform's shaders if (!ArePlatformsCompatible(GMaxRHIShaderPlatform, (EShaderPlatform)Target.Platform)) { if (FPlatformProperties::RequiresCookedData()) { UE_LOG(LogShaders, Fatal, TEXT("FShaderResource::InitRHI got platform %s but it is not compatible with %s"), *LegacyShaderPlatformToShaderFormat((EShaderPlatform)Target.Platform).ToString(), *LegacyShaderPlatformToShaderFormat(GMaxRHIShaderPlatform).ToString()); } return; } INC_DWORD_STAT_BY(STAT_Shaders_NumShadersUsedForRendering, 1); SCOPE_CYCLE_COUNTER(STAT_Shaders_RTShaderLoadTime); FShaderCache* ShaderCache = FShaderCache::GetShaderCache(); if(Target.Frequency == SF_Vertex) { VertexShader = ShaderCache ? ShaderCache->GetVertexShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateVertexShader(Code); } else if(Target.Frequency == SF_Pixel) { PixelShader = ShaderCache ? ShaderCache->GetPixelShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreatePixelShader(Code); } else if(Target.Frequency == SF_Hull) { HullShader = ShaderCache ? ShaderCache->GetHullShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateHullShader(Code); } else if(Target.Frequency == SF_Domain) { DomainShader = ShaderCache ? ShaderCache->GetDomainShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateDomainShader(Code); } else if(Target.Frequency == SF_Geometry) { if (SpecificType) { FStreamOutElementList ElementList; TArray<uint32> StreamStrides; int32 RasterizedStream = -1; SpecificType->GetStreamOutElements(ElementList, StreamStrides, RasterizedStream); checkf(ElementList.Num(), *FString::Printf(TEXT("Shader type %s was given GetStreamOutElements implementation that had no elements!"), SpecificType->GetName())); //@todo - not using the cache GeometryShader = RHICreateGeometryShaderWithStreamOutput(Code, ElementList, StreamStrides.Num(), StreamStrides.GetData(), RasterizedStream); } else { GeometryShader = ShaderCache ? ShaderCache->GetGeometryShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateGeometryShader(Code); } } else if(Target.Frequency == SF_Compute) { ComputeShader = ShaderCache ? ShaderCache->GetComputeShader((EShaderPlatform)Target.Platform, Code) : RHICreateComputeShader(Code); } if (Target.Frequency != SF_Geometry) { checkf(!SpecificType, *FString::Printf(TEXT("Only geometry shaders can use GetStreamOutElements, shader type %s"), SpecificType->GetName())); } if (!FPlatformProperties::HasEditorOnlyData()) { DEC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), Code.Num()); DEC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, Code.GetAllocatedSize()); Code.Empty(); } }
FGeometryShaderRHIRef FD3D12DynamicRHI::RHICreateGeometryShaderWithStreamOutput(const TArray<uint8>& Code, const FStreamOutElementList& ElementList, uint32 NumStrides, const uint32* Strides, int32 RasterizedStream) { check(Code.Num()); FD3D12GeometryShader* Shader = new FD3D12GeometryShader; FMemoryReader Ar(Code, true); Ar << Shader->ShaderResourceTable; int32 Offset = Ar.Tell(); const uint8* CodePtr = Code.GetData() + Offset; const SIZE_T CodeSize = Code.Num() - Offset - 5; Shader->StreamOutput.RasterizedStream = RasterizedStream; if (RasterizedStream == -1) { Shader->StreamOutput.RasterizedStream = D3D12_SO_NO_RASTERIZED_STREAM; } Shader->StreamOutput.NumEntries = ElementList.Num(); Shader->pStreamOutEntries = new D3D12_SO_DECLARATION_ENTRY[ElementList.Num()]; Shader->StreamOutput.pSODeclaration = Shader->pStreamOutEntries; if (Shader->pStreamOutEntries == nullptr) { return nullptr; // Out of memory } for (int32 EntryIndex = 0; EntryIndex < ElementList.Num(); EntryIndex++) { Shader->pStreamOutEntries[EntryIndex].Stream = ElementList[EntryIndex].Stream; Shader->pStreamOutEntries[EntryIndex].SemanticName = ElementList[EntryIndex].SemanticName; Shader->pStreamOutEntries[EntryIndex].SemanticIndex = ElementList[EntryIndex].SemanticIndex; Shader->pStreamOutEntries[EntryIndex].StartComponent = ElementList[EntryIndex].StartComponent; Shader->pStreamOutEntries[EntryIndex].ComponentCount = ElementList[EntryIndex].ComponentCount; Shader->pStreamOutEntries[EntryIndex].OutputSlot = ElementList[EntryIndex].OutputSlot; } // bGlobalUniformBufferUsed and resource counts are packed in the last few bytes, see CompileD3D11Shader Shader->bShaderNeedsGlobalConstantBuffer = Code[Code.Num() - 5] != 0; Shader->SamplerCount = Code[Code.Num() - 4]; Shader->SRVCount = Code[Code.Num() - 3]; Shader->CBCount = Code[Code.Num() - 2]; Shader->UAVCount = Code[Code.Num() - 1]; // Indicate this shader uses stream output Shader->bShaderNeedsStreamOutput = true; // Copy the strides Shader->StreamOutput.NumStrides = NumStrides; Shader->pStreamOutStrides = new uint32[NumStrides]; Shader->StreamOutput.pBufferStrides = Shader->pStreamOutStrides; if (Shader->pStreamOutStrides == nullptr) { return nullptr; // Out of memory } FMemory::Memcpy(Shader->pStreamOutStrides, Strides, sizeof(uint32) * NumStrides); Shader->Code = Code; D3D12_SHADER_BYTECODE ShaderBytecode; ShaderBytecode.pShaderBytecode = Shader->Code.GetData() + Offset; ShaderBytecode.BytecodeLength = CodeSize; Shader->ShaderBytecode.SetShaderBytecode(ShaderBytecode); return Shader; }