Diligent Core ist eine moderne plattformübergreifende Low-Level-Grafik-API, die die Grundlage der Diligent Engine bildet. Das Modul implementiert Direct3D11-, Direct3D12-, OpenGL-, OpenGLES- und Vulkan-Rendering-Backends (Metal-Implementierung ist für kommerzielle Kunden verfügbar) sowie grundlegende plattformspezifische Dienstprogramme. Es ist in sich geschlossen und kann selbst gebaut werden. Informationen zu den unterstützten Plattformen und Funktionen, Build-Anweisungen usw. finden Sie im Haupt-Repository.
Plattform | Build-Status |
---|---|
Win32 | |
Universelles Windows | |
Linux | |
Android | |
MacOS | |
iOS | |
tvOS | |
Emscripten |
Klonen des Repositorys
API-Grundlagen
Pipeline-Ressourcenlayout
Win32
Universelle Windows-Plattform
Linux
MacOS
Android
iOS
Emscripten
Zerstörung des Motors
Initialisierung der Engine
Ressourcen erstellen
Shader erstellen
Pipeline-Status wird initialisiert
Bindung von Shader-Ressourcen
Festlegen des Pipeline-Status und Aufrufen des Zeichenbefehls
Low-Level-API-Interoperabilität
Anweisungen zum Erstellen des NuGet-Pakets
Lizenz
Mitwirken
Veröffentlichungsverlauf
Um das Repository und alle Submodule abzurufen, verwenden Sie den folgenden Befehl:
git clone --recursive https://github.com/DiligentGraphics/DiligentCore.git
Informationen zum Erstellen des Moduls finden Sie in den Buildanweisungen im Master-Repository.
Bevor Sie die von der Engine bereitgestellten Funktionen nutzen können, müssen Sie ein Rendergerät, einen unmittelbaren Kontext und eine Swap-Kette erstellen.
Auf der Win32-Plattform können Sie OpenGL-, Direct3D11-, Direct3D12- oder Vulkan-Geräte wie unten gezeigt erstellen:
void InitializeDiligentEngine(HWND NativeWindowHandle) { SwapChainDesc SCDesc;// RefCntAutoPtr<IRenderDevice> m_pDevice;// RefCntAutoPtr<IDeviceContext> m_pImmediateContext;// RefCntAutoPtr<ISwapChain> m_pSwapChain;switch (m_DeviceType) {Fall RENDER_DEVICE_TYPE_D3D11: { EngineD3D11CreateInfo EngineCI; # if ENGINE_DLL// Laden Sie die DLL und importieren Sie GetEngineFactoryD3D11() functionauto* GetEngineFactoryD3D11 = LoadGraphicsEngineD3D11(); # endifauto* pFactoryD3D11 = GetEngineFactoryD3D11(); pFactoryD3D11->CreateDeviceAndContextsD3D11(EngineCI, &m_pDevice, &m_pImmediateContext); Win32NativeWindow Window{hWnd}; pFactoryD3D11->CreateSwapChainD3D11(m_pDevice, m_pImmediateContext, SCDesc, FullScreenModeDesc{}, Window, &m_pSwapChain); }break;case RENDER_DEVICE_TYPE_D3D12: { # if ENGINE_DLL// Laden Sie die DLL und importieren Sie GetEngineFactoryD3D12() functionauto GetEngineFactoryD3D12 = LoadGraphicsEngineD3D12(); # endifEngineD3D12CreateInfo EngineCI;auto* pFactoryD3D12 = GetEngineFactoryD3D12(); pFactoryD3D12->CreateDeviceAndContextsD3D12(EngineCI, &m_pDevice, &m_pImmediateContext); Win32NativeWindow Window{hWnd}; pFactoryD3D12->CreateSwapChainD3D12(m_pDevice, m_pImmediateContext, SCDesc, FullScreenModeDesc{}, Window, &m_pSwapChain); }break;case RENDER_DEVICE_TYPE_GL: { # if EXPLICITLY_LOAD_ENGINE_GL_DLL// Laden Sie die DLL und importieren Sie GetEngineFactoryOpenGL() functionauto GetEngineFactoryOpenGL = LoadGraphicsEngineOpenGL(); # endifauto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI; EngineCI.Window.hWnd = hWnd; pFactoryOpenGL->CreateDeviceAndSwapChainGL(EngineCI, &m_pDevice, &m_pImmediateContext, SCDesc, &m_pSwapChain); }break;case RENDER_DEVICE_TYPE_VULKAN: { # if EXPLICITLY_LOAD_ENGINE_VK_DLL// Laden Sie die DLL und importieren Sie GetEngineFactoryVk() functionauto GetEngineFactoryVk = LoadGraphicsEngineVk(); # endifEngineVkCreateInfo EngineCI;auto* pFactoryVk = GetEngineFactoryVk(); pFactoryVk->CreateDeviceAndContextsVk(EngineCI, &m_pDevice, &m_pImmediateContext); Win32NativeWindow Window{hWnd}; pFactoryVk->CreateSwapChainVk(m_pDevice, m_pImmediateContext, SCDesc, Window, &m_pSwapChain); }break;default: std::cerr << "Unbekannter Gerätetyp"; } }
Unter Windows kann die Engine statisch mit der Anwendung verknüpft oder als separate DLL erstellt werden. Im ersten Fall können die Factory-Funktionen GetEngineFactoryOpenGL()
, GetEngineFactoryD3D11()
, GetEngineFactoryD3D12()
und GetEngineFactoryVk()
direkt aufgerufen werden. Im zweiten Fall müssen Sie die DLL mit der Funktion LoadGraphicsEngineOpenGL()
, LoadGraphicsEngineD3D11()
, LoadGraphicsEngineD3D12()
oder LoadGraphicsEngineVk()
in den Adressraum des Prozesses laden. Jede Funktion lädt die entsprechende dynamische Bibliothek und importiert die zur Initialisierung der Engine erforderlichen Funktionen. Sie müssen die folgenden Header einfügen:
#include "EngineFactoryD3D11.h"#include "EngineFactoryD3D12.h"#include "EngineFactoryOpenGL.h"#include "EngineFactoryVk.h"
Sie müssen außerdem die folgenden Verzeichnisse zu den Include-Suchpfaden hinzufügen:
DiligentCore/Graphics/GraphicsEngineD3D11/interface
DiligentCore/Graphics/GraphicsEngineD3D12/interface
DiligentCore/Graphics/GraphicsEngineOpenGL/interface
DiligentCore/Graphics/GraphicsEngineVulkan/interface
Alternativ können Sie den Pfad nur zum Stammordner hinzufügen und dann relativ dazu Include-Pfade verwenden.
Aktivieren Sie Diligent
-Namespace:
Verwendung des Namensraums Diligent;
Die Funktionen IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
, IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
und IEngineFactoryVk::CreateDeviceAndContextsVk()
können auch eine bestimmte Anzahl unmittelbarer und verzögerter Kontexte erstellen, die für asynchrones Rendering und Multithread-Befehlsaufzeichnung verwendet werden können. Die Kontexte dürfen nur während der Initialisierung der Engine erstellt werden. Die Funktion füllt ein Array von Zeigern auf die Kontexte, wobei die unmittelbaren Kontexte zuerst angezeigt werden, gefolgt von allen verzögerten Kontexten.
Weitere Informationen finden Sie in der Datei Tutorial00_HelloWin32.cpp.
Auf der universellen Windows-Plattform können Sie ein Direct3D11- oder Direct3D12-Gerät erstellen. Die Initialisierung erfolgt auf die gleiche Weise wie auf der Win32-Plattform. Der Unterschied besteht darin, dass Sie zuerst das Rendergerät und die Gerätekontexte erstellen, indem Sie IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
oder IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
aufrufen. Die Swap-Kette wird später durch einen Aufruf von IEngineFactoryD3D11::CreateSwapChainD3D11()
oder IEngineFactoryD3D12::CreateSwapChainD3D12()
erstellt. Weitere Informationen finden Sie in der Datei SampleAppUWP.cpp.
Auf der Linux-Plattform unterstützt die Engine OpenGL- und Vulkan-Backends. Die Initialisierung des GL-Kontexts unter Linux ist eng mit der Fenstererstellung verbunden. Daher initialisiert Diligent Engine den Kontext nicht, sondern hängt ihn an den von der App initialisierten an. Ein Beispiel für die Engine-Initialisierung unter Linux finden Sie im Tutorial00_HelloLinux.cpp.
Unter MacOS unterstützt Diligent Engine OpenGL-, Vulkan- und Metal-Backends. Die Initialisierung des GL-Kontexts unter MacOS wird von der Anwendung durchgeführt, und die Engine stellt eine Verbindung zum von der App erstellten Kontext her. Weitere Informationen finden Sie unter GLView.mm. Das Vulkan-Backend wird ähnlich wie andere Plattformen initialisiert. Siehe MetalView.mm.
Auf Android können Sie OpenGLES- oder Vulkan-Geräte erstellen. Der folgende Codeausschnitt zeigt ein Beispiel:
auto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI; EngineCI.Window.pAWindow = NativeWindowHandle; pFactoryOpenGL->CreateDeviceAndSwapChainGL( EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Wenn die Engine als dynamische Bibliothek erstellt wird, muss die Bibliothek durch die native Aktivität geladen werden. Der folgende Code zeigt einen möglichen Weg:
static{try{System.loadLibrary("GraphicsEngineOpenGL"); } Catch (UnsatisfiedLinkError e) {Log.e("native-activity", "Failed to Load GraphicsEngineOpenGL Library.n" + e); } }
Die iOS-Implementierung unterstützt OpenGLES, Vulkan und Metal-Backend. Die Initialisierung des GL-Kontexts unter iOS wird von der Anwendung durchgeführt, und die Engine stellt eine Verbindung zum von der App initialisierten Kontext her. Weitere Informationen finden Sie unter EAGLView.mm.
Auf Emscripten können Sie ein OpenGLES-Gerät erstellen. Der folgende Codeausschnitt zeigt ein Beispiel:
//Sie müssen die ID der Leinwand an NativeWindowauto übergeben* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI = {}; EngineCI.Window = NativeWindow{"#canvas"}; pFactoryOpenGL->CreateDeviceAndSwapChainGL(EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Wenn Sie SDL oder GLFW mit vorhandenem Kontext verwenden, können Sie null als natives Fensterhandle angeben: EngineCI.Window = NativeWindow{nullptr}
Die Engine führt eine automatische Referenzzählung durch und schaltet sich ab, wenn die letzte Referenz auf ein Engine-Objekt freigegeben wird.
Geräteressourcen werden vom Rendergerät erstellt. Die beiden Hauptressourcentypen sind Puffer, die linearen Speicher darstellen, und Texturen, die für schnelles Filtern optimierte Speicherlayouts verwenden. Um einen Puffer zu erstellen, müssen Sie BufferDesc
Struktur füllen und IRenderDevice::CreateBuffer()
aufrufen. Der folgende Code erstellt einen einheitlichen (konstanten) Puffer:
BufferDesc BuffDesc; BuffDesc.Name = "Einheitlicher Puffer"; BuffDesc.BindFlags = BIND_UNIFORM_BUFFER; BuffDesc.Usage = USAGE_DYNAMIC; BuffDesc.uiSizeInBytes = sizeof(ShaderConstants); BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; m_pDevice->CreateBuffer(BuffDesc, nullptr, &m_pConstantBuffer);
Um eine Textur zu erstellen, füllen Sie TextureDesc
Struktur auf und rufen Sie IRenderDevice::CreateTexture()
auf, wie im folgenden Beispiel:
TextureDesc TexDesc; TexDesc.Name = "Meine Textur 2D"; TexDesc.Type = TEXTURE_TYPE_2D; TexDesc.Width = 1024; TexDesc.Height = 1024; TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; TexDesc.Usage = USAGE_DEFAULT; TexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; TexDesc.Name = "Beispiel einer 2D-Textur"; m_pRenderDevice->CreateTexture(TexDesc, nullptr, &m_pTestTex);
Es gibt nur eine Funktion CreateTexture()
, die alle Arten von Texturen erstellen kann. Typ, Format, Array-Größe und alle anderen Parameter werden von den Mitgliedern der TextureDesc
Struktur angegeben.
Für jedes während der Texturerstellungszeit angegebene Bindungsflag erstellt das Texturobjekt eine Standardansicht. Die Standard-Shader-Ressourcenansicht befasst sich mit der gesamten Textur, die Standard-Renderziel- und Tiefenschablonenansichten verweisen auf alle Array-Slices in der detailliertesten Mip-Ebene und die ungeordnete Zugriffsansicht verweist auf die gesamte Textur. Um eine Standardansicht der Textur zu erhalten, verwenden Sie die Funktion ITexture::GetDefaultView()
. Beachten Sie, dass diese Funktion den Referenzzähler der zurückgegebenen Schnittstelle nicht erhöht. Sie können zusätzliche Texturansichten mit ITexture::CreateView()
erstellen. Verwenden Sie IBuffer::CreateView()
um zusätzliche Ansichten eines Puffers zu erstellen.
Um einen Shader zu erstellen, füllen Sie ShaderCreateInfo
-Struktur:
ShaderCreateInfo ShaderCI;
Es gibt drei Möglichkeiten, einen Shader zu erstellen. Die erste Möglichkeit besteht darin, über ShaderCreateInfo::Source
Mitglied einen Zeiger auf den Shader-Quellcode bereitzustellen. Die zweite Möglichkeit besteht darin, einen Dateinamen anzugeben. Die dritte Möglichkeit besteht darin, über ShaderCreateInfo::ByteCode
-Mitglied einen Zeiger auf den kompilierten Bytecode bereitzustellen. Die Grafik-Engine ist vollständig von der Plattform entkoppelt. Da das Hostdateisystem plattformabhängig ist, stellt die Struktur ShaderCreateInfo::pShaderSourceStreamFactory
Mitglied bereit, das der Engine Zugriff auf das Dateisystem gewähren soll. Wenn Sie den Namen der Quelldatei angegeben haben, müssen Sie auch einen Zeiger ungleich Null auf die Shader-Quellstream-Factory angeben. Wenn die Shader-Quelle #include
-Anweisungen enthält, wird die Quellstream-Factory auch zum Laden dieser Dateien verwendet. Die Engine bietet eine Standardimplementierung für jede unterstützte Plattform, die in den meisten Fällen ausreichend sein sollte. Sie können jedoch Ihre eigene Implementierung definieren.
Ein wichtiges Mitglied ist ShaderCreateInfo::SourceLanguage
. Die folgenden Werte sind für dieses Mitglied gültig:
SHADER_SOURCE_LANGUAGE_DEFAULT
– Das Shader-Quellformat entspricht der zugrunde liegenden Grafik-API: HLSL für den D3D11- oder D3D12-Modus und GLSL für die Modi OpenGL, OpenGLES und Vulkan.
SHADER_SOURCE_LANGUAGE_HLSL
– Die Shader-Quelle ist in HLSL. Für die Modi OpenGL und OpenGLES wird der Quellcode in GLSL konvertiert. Im Vulkan-Backend wird der Code direkt in SPIRV kompiliert.
SHADER_SOURCE_LANGUAGE_GLSL
– Die Shader-Quelle ist in GLSL.
SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM
– Die Shader-Quellsprache ist GLSL und sollte wörtlich kompiliert werden.
SHADER_SOURCE_LANGUAGE_MSL
– Die Quellsprache ist Metal Shading Language.
Zu den weiteren Mitgliedern der ShaderCreateInfo
Struktur, die den Shader definieren, gehören Suchverzeichnisse, Shader-Makrodefinitionen, Shader-Einstiegspunkt und andere Parameter.
ShaderMacroHelper-Makros; Macros.AddShaderMacro("USE_SHADOWS", 1); Macros.AddShaderMacro("NUM_SHADOW_SAMPLES", 4); Macros.Finalize(); ShaderCI.Macros = Makros;
Wenn alles fertig ist, rufen Sie IRenderDevice::CreateShader()
auf, um das Shader-Objekt zu erstellen:
ShaderCreateInfo ShaderCI; ShaderCI.Desc.Name = "MyPixelShader"; ShaderCI.FilePath = "MyShaderFile.fx"; ShaderCI.EntryPoint = "MyPixelShader"; ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;const auto* SearchDirectories = "shaders;shadersinc;"; RefCntAutoPtr<IShaderSourceInputStreamFactory> pShaderSourceFactory; m_pEngineFactory->CreateDefaultShaderSourceStreamFactory(SearchDirectories, &pShaderSourceFactory); ShaderCI.pShaderSourceStreamFactory = pShaderSourceFactory; RefCntAutoPtr<IShader> pShader; m_pDevice->CreateShader(ShaderCI, &pShader);
Diligent Engine folgt dem Direct3D12/Vulkan-Stil, um die Grafik-/Rechenpipeline zu konfigurieren. Ein monolithisches Pipelines State Object (PSO) umfasst alle erforderlichen Zustände (alle Shader-Stufen, Eingabe-Layout-Beschreibung, Tiefenschablone, Rasterizer- und Blend-Zustandsbeschreibungen usw.). Um ein Grafikpipeline-Statusobjekt zu erstellen, definieren Sie eine Instanz der GraphicsPipelineStateCreateInfo
-Struktur:
GraphicsPipelineStateCreateInfo PSOCreateInfo; PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; PSODesc.Name = „Mein Pipeline-Status“;
Beschreiben Sie die Pipeline-Besonderheiten wie die Anzahl und das Format der Renderziele sowie das Tiefenschablonenformat:
// Dies ist eine GrafikpipelinePSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS; PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 1; PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB; PSOCreateInfo.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
Initialisieren Sie die Zustandsbeschreibung der Tiefenschablone DepthStencilStateDesc
. Beachten Sie, dass der Konstruktor die Mitglieder mit Standardwerten initialisiert und Sie nur diejenigen festlegen dürfen, die vom Standard abweichen.
// Tiefenschablonenzustand initiierenDepthStencilStateDesc& DepthStencilDesc = PSOCreateInfo.GraphicsPipeline.DepthStencilDesc; DepthStencilDesc.DepthEnable = true; DepthStencilDesc.DepthWriteEnable = true;
Blend-Statusbeschreibung BlendStateDesc
initialisieren:
// Mischung initiieren stateBlendStateDesc& BSDesc = PSOCreateInfo.GraphicsPipeline.BlendDesc; BSDesc.IndependentBlendEnable = False;auto &RT0 = BSDesc.RenderTargets[0]; RT0.BlendEnable = True; RT0.RenderTargetWriteMask = COLOR_MASK_ALL; RT0.SrcBlend = BLEND_FACTOR_SRC_ALPHA; RT0.DestBlend = BLEND_FACTOR_INV_SRC_ALPHA; RT0.BlendOp = BLEND_OPERATION_ADD; RT0.SrcBlendAlpha = BLEND_FACTOR_SRC_ALPHA; RT0.DestBlendAlpha = BLEND_FACTOR_INV_SRC_ALPHA; RT0.BlendOpAlpha = BLEND_OPERATION_ADD;
Rasterizer-Statusbeschreibung initialisieren RasterizerStateDesc
:
// Rasterizer initiieren stateRasterizerStateDesc& RasterizerDesc = PSOCreateInfo.GraphicsPipeline.RasterizerDesc; RasterizerDesc.FillMode = FILL_MODE_SOLID; RasterizerDesc.CullMode = CULL_MODE_NONE; RasterizerDesc.FrontCounterClockwise = True; RasterizerDesc.ScissorEnable = True; RasterizerDesc.AntialiasedLineEnable = False;
Eingabelayoutbeschreibung initialisieren InputLayoutDesc
:
// Eingabelayout definierenInputLayoutDesc& Layout = PSOCreateInfo.GraphicsPipeline.InputLayout; LayoutElement LayoutElems[] = {LayoutElement( 0, 0, 3, VT_FLOAT32, False ),LayoutElement( 1, 0, 4, VT_UINT8, True ),LayoutElement( 2, 0, 2, VT_FLOAT32, False ), }; Layout.LayoutElements = LayoutElems; Layout.NumElements = _countof(LayoutElems);
Definieren Sie die primitive Topologie und legen Sie Shader-Zeiger fest:
// Shader und primitive Topologie definierenPSOCreateInfo.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; PSOCreateInfo.pVS = m_pVS; PSOCreateInfo.pPS = m_pPS;
Das Pipeline-Ressourcenlayout informiert die Engine darüber, wie die Anwendung verschiedene Shader-Ressourcenvariablen verwenden wird. Um eine Gruppierung von Ressourcen basierend auf der erwarteten Häufigkeit von Änderungen an Ressourcenbindungen zu ermöglichen, führt Diligent Engine eine Klassifizierung von Shader-Variablen ein:
Statische Variablen ( SHADER_RESOURCE_VARIABLE_TYPE_STATIC
) sind Variablen, von denen erwartet wird, dass sie nur einmal festgelegt werden. Sie dürfen nicht mehr geändert werden, sobald eine Ressource an die Variable gebunden ist. Solche Variablen sollen globale Konstanten wie Kameraattribute oder globale Lichtattribute als konstante Puffer speichern. Beachten Sie, dass sich die Ressourcenbindung möglicherweise nicht ändert, während sich der Inhalt der Ressource entsprechend ihrer Nutzung ändern darf.
Veränderbare Variablen ( SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE
) definieren Ressourcen, von denen erwartet wird, dass sie sich in einer Häufigkeit pro Material ändern. Beispiele können diffuse Texturen, Normal Maps usw. sein. Auch hier sind Aktualisierungen des Inhalts der Ressource orthogobal zu den Bindungsänderungen.
Von dynamischen Variablen ( SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC
) wird erwartet, dass sie sich häufig und zufällig ändern.
Um Variablentypen zu definieren, bereiten Sie ein Array von ShaderResourceVariableDesc
-Strukturen vor und initialisieren Sie die Mitglieder PSODesc.ResourceLayout.Variables
und PSODesc.ResourceLayout.NumVariables
. Außerdem kann PSODesc.ResourceLayout.DefaultVariableType
verwendet werden, um den Typ festzulegen, der verwendet wird, wenn kein Variablenname angegeben wird.
ShaderResourceVariableDesc ShaderVars[] = { {SHADER_TYPE_PIXEL, "g_StaticTexture", SHADER_RESOURCE_VARIABLE_TYPE_STATIC}, {SHADER_TYPE_PIXEL, "g_MutableTexture", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE}, {SHADER_TYPE_PIXEL, "g_DynamicTexture", SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC} }; PSODesc.ResourceLayout.Variables = ShaderVars; PSODesc.ResourceLayout.NumVariables = _countof(ShaderVars); PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC;
Beim Erstellen eines Pipeline-Status können Texturen unveränderliche Sampler dauerhaft zugewiesen werden. Wenn einer Textur ein unveränderlicher Sampler zugewiesen ist, wird dieser immer anstelle des in der Textur-Shader-Ressourcenansicht initialisierten verwendet. Um unveränderliche Sampler zu definieren, bereiten Sie ein Array von ImmutableSamplerDesc
-Strukturen vor und initialisieren Sie die Mitglieder PSODesc.ResourceLayout.ImmutableSamplers
und PSODesc.ResourceLayout.NumImmutableSamplers
. Beachten Sie, dass unveränderliche Sampler einer Texturvariablen eines beliebigen Typs zugewiesen werden können, die nicht unbedingt statisch sein muss, sodass die Texturbindung zur Laufzeit geändert werden kann, während der Sampler unveränderlich bleibt. Es wird dringend empfohlen, nach Möglichkeit unveränderliche Sampler zu verwenden.
ImmutableSamplerDesc ImtblSampler; ImtblSampler.ShaderStages = SHADER_TYPE_PIXEL; ImtblSampler.Desc.MinFilter = FILTER_TYPE_LINEAR; ImtblSampler.Desc.MagFilter = FILTER_TYPE_LINEAR; ImtblSampler.Desc.MipFilter = FILTER_TYPE_LINEAR; ImtblSampler.TextureName = "g_MutableTexture"; PSODesc.ResourceLayout.NumImmutableSamplers = 1; PSODesc.ResourceLayout.ImmutableSamplers = &ImtblSampler;
Dieses Dokument enthält detaillierte Informationen zum Arbeiten mit Textursamplern.
Wenn alle erforderlichen Felder der PSO-Beschreibungsstruktur festgelegt sind, rufen Sie IRenderDevice::CreateGraphicsPipelineState()
auf, um das PSO-Objekt zu erstellen:
m_pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &m_pPSO);
Wie oben erwähnt, basiert die Shader-Ressourcenbindung in Diligent Engine auf der Gruppierung von Variablen in drei verschiedene Gruppen (statisch, veränderlich und dynamisch). Statische Variablen sind Variablen, von denen erwartet wird, dass sie nur einmal festgelegt werden. Sie dürfen nicht mehr geändert werden, sobald eine Ressource an die Variable gebunden ist. Solche Variablen sollen globale Konstanten wie Kameraattribute oder globale Lichtattribute als konstante Puffer speichern. Sie sind direkt an das Pipeline State Object gebunden:
m_pPSO->GetStaticShaderVariable(SHADER_TYPE_PIXEL, "g_tex2DShadowMap")->Set(pShadowMapSRV);
Veränderbare und dynamische Variablen werden über ein neues Objekt namens Shader Resource Binding (SRB) gebunden, das durch den Pipeline-Status ( IPipelineState::CreateShaderResourceBinding()
) oder in erweiterten Anwendungsfällen durch die Pipeline-Ressourcensignatur erstellt wird:
m_pPSO->CreateShaderResourceBinding(&m_pSRB, true);
Der zweite Parameter weist das System an, interne Strukturen im SRB-Objekt zu initialisieren, die auf statische Variablen im PSO verweisen.
Dynamische und veränderliche Ressourcen werden dann über das SRB-Objekt gebunden:
m_pSRB->GetVariable(SHADER_TYPE_PIXEL, "tex2DDiffuse")->Set(pDiffuseTexSRV); m_pSRB->GetVariable(SHADER_TYPE_VERTEX, "cbRandomAttribs")->Set(pRandomAttrsCB);
Der Unterschied zwischen veränderlichen und dynamischen Ressourcen besteht darin, dass veränderbare Ressourcen nur einmal pro Instanz einer Shader-Ressourcenbindung festgelegt werden können. Dynamische Ressourcen können mehrfach festgelegt werden. Es ist wichtig, den Variablentyp richtig festzulegen, da sich dies auf die Leistung auswirkt. Statische und veränderliche Variablen sind effizienter. Dynamische Variablen sind teurer und verursachen einen gewissen Laufzeitaufwand.
Eine alternative Möglichkeit zum Binden von Shader-Ressourcen besteht darin, eine IResourceMapping
Schnittstelle zu erstellen, die Ressourcenliteralnamen den tatsächlichen Ressourcen zuordnet:
ResourceMappingEntry Entries[] = { {"g_Texture", pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)} }; ResourceMappingCreateInfo ResMappingCI; ResMappingCI.pEntries = Einträge; ResMappingCI.NumEntries = _countof(Entries); RefCntAutoPtr<IResourceMapping> pResMapping; pRenderDevice->CreateResourceMapping(ResMappingCI, &pResMapping);
Die Ressourcenzuordnung kann dann verwendet werden, um alle statischen Ressourcen in einem Pipeline-Status zu binden ( IPipelineState::BindStaticResources()
):
m_pPSO->BindStaticResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
oder alle veränderlichen und dynamischen Ressourcen in einer Shader-Ressourcenbindung ( IShaderResourceBinding::BindResources()
):
m_pSRB->BindResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
Der letzte Parameter aller BindResources()
-Funktionen definiert, wie Ressourcen aufgelöst werden sollen:
BIND_SHADER_RESOURCES_UPDATE_STATIC
– Gibt an, dass statische Variablenbindungen aktualisiert werden sollen.
BIND_SHADER_RESOURCES_UPDATE_MUTABLE
– Gibt an, dass veränderbare Variablenbindungen aktualisiert werden sollen.
BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
– Gibt an, dass dynamische Variablenbindungen aktualisiert werden sollen.
BIND_SHADER_RESOURCES_UPDATE_ALL
– Gibt an, dass alle Variablentypen (statisch, veränderlich und dynamisch) aktualisiert werden sollen. Beachten Sie, dass alle Variablentypen so aktualisiert werden, als ob BIND_SHADER_RESOURCES_UPDATE_ALL
angegeben wäre, wenn keines der Flags BIND_SHADER_RESOURCES_UPDATE_STATIC
, BIND_SHADER_RESOURCES_UPDATE_MUTABLE
und BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
gesetzt ist.
BIND_SHADER_RESOURCES_KEEP_EXISTING
– Wenn dieses Flag angegeben ist, werden nur ungelöste Bindungen aktualisiert. Alle vorhandenen Bindungen behalten ihre ursprünglichen Werte. Wenn dieses Flag nicht angegeben ist, wird jede Shader-Variable aktualisiert, wenn die Zuordnung eine entsprechende Ressource enthält.
BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED
– Wenn dieses Flag angegeben ist, wird erwartet, dass alle Shader-Bindungen nach dem Aufruf aufgelöst werden. Ist dies nicht der Fall, wird ein Fehler gemeldet.
BindResources()
kann mehrmals mit unterschiedlichen Ressourcenzuordnungen aufgerufen werden, um Ressourcen zu binden. Es wird jedoch empfohlen, eine große Ressourcenzuordnung zu verwenden, da die Größe der Zuordnung keinen Einfluss auf die Elementsuchzeit hat.
Die Engine führt Laufzeitprüfungen durch, um zu überprüfen, ob die richtigen Ressourcen gebunden werden. Wenn Sie beispielsweise versuchen, einen konstanten Puffer an eine Shader-Ressourcenansichtsvariable zu binden, wird ein Fehler an die Debug-Konsole ausgegeben.
Bevor ein Zeichenbefehl aufgerufen werden kann, sollten alle erforderlichen Vertex- und Indexpuffer sowie der Pipeline-Status an den Gerätekontext gebunden werden:
// Renderziele festlegen, bevor ein Zeichenbefehl ausgegeben wird.auto* pRTV = m_pSwapChain->GetCurrentBackBufferRTV();auto* pDSV = m_pSwapChain->GetDepthBufferDSV(); m_pContext->SetRenderTargets(1, &pRTV, pDSV, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);// Renderziel und Depth-stencilconst löschen float zero[4] = {0, 0, 0, 0}; m_pContext->ClearRenderTarget(pRTV, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); m_pContext->ClearDepthStencil(pDSV, CLEAR_DEPTH_FLAG, 1.f, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);// Vertex- und Indexpuffer festlegenIBuffer* buffer[] = {m_pVertexBuffer}; Uint32-Offsets[] = {0}; m_pContext->SetVertexBuffers(0, 1, Puffer, Offsets, SET_VERTEX_BUFFERS_FLAG_RESET, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); m_pContext->SetIndexBuffer(m_pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); m_pContext->SetPipelineState(m_pPSO);
Alle Methoden, die möglicherweise Ressourcenstatusübergänge durchführen müssen, verwenden die Aufzählung RESOURCE_STATE_TRANSITION_MODE
als Parameter. Die Aufzählung definiert die folgenden Modi:
RESOURCE_STATE_TRANSITION_MODE_NONE
– Führen Sie keine Ressourcenstatusübergänge durch.
RESOURCE_STATE_TRANSITION_MODE_TRANSITION
– Ressourcen in die für den Befehl erforderlichen Zustände überführen.
RESOURCE_STATE_TRANSITION_MODE_VERIFY
– Führen Sie keinen Übergang durch, sondern überprüfen Sie, ob die Zustände korrekt sind.
Der letzte Schritt besteht darin, Shader-Ressourcen für den Gerätekontext bereitzustellen. Dies wird durch die Methode IDeviceContext::CommitShaderResources()
erreicht:
m_pContext->CommitShaderResources(m_pSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
Wenn die Methode nicht aufgerufen wird, erkennt die Engine, dass keine Ressourcen festgeschrieben sind, und gibt eine Debug-Meldung aus. Beachten Sie, dass der letzte Parameter das System anweist, Ressourcen in den richtigen Zustand zu versetzen. Wenn dieses Flag nicht angegeben ist, müssen die Ressourcen durch einen Aufruf von IDeviceContext::TransitionShaderResources()
explizit in die erforderlichen Zustände überführt werden:
m_pContext->TransitionShaderResources(m_pPSO, m_pSRB);
Beachten Sie, dass die Methode einen Zeiger auf den Pipelinestatus erfordert, der die Shader-Ressourcenbindung erstellt hat.
Wenn alle erforderlichen Zustände und Ressourcen gebunden sind, kann IDeviceContext::DrawIndexed()
zum Ausführen eines Zeichenbefehls oder IDeviceContext::DispatchCompute()
zum Ausführen eines Rechenbefehls verwendet werden. Beachten Sie, dass für einen Zeichenbefehl eine Grafikpipeline gebunden sein muss und für einen Versandbefehl eine Rechenpipeline gebunden sein muss. DrawIndexed()
verwendet DrawIndexedAttribs
-Struktur als Argument, zum Beispiel:
DrawIndexedAttribs attrs; attrs.IndexType = VT_UINT16; attrs.NumIndices = 36; attrs.Flags = DRAW_FLAG_VERIFY_STATES; pContext->DrawIndexed(attrs);
Das Flag DRAW_FLAG_VERIFY_STATES
weist die Engine an, zu überprüfen, ob die vom Zeichenbefehl verwendeten Vertex- und Indexpuffer in die richtigen Zustände überführt werden.
DispatchCompute()
verwendet DispatchComputeAttribs
-Struktur, die die Abmessungen des Berechnungsgitters definiert:
m_pContext->SetPipelineState(m_pComputePSO); m_pContext->CommitShaderResources(m_pComputeSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES); DispatchComputeAttribs DispatchAttrs{64, 64, 8}; m_pContext->DispatchCompute(DispatchAttrs);
Sie können mehr über die Engine-API erfahren, indem Sie Beispiele und Tutorials studieren.
Diligent Engine unterstützt umfassend die Interoperabilität mit zugrunde liegenden Low-Level-APIs. Die Engine kann durch Anhängen an ein vorhandenes D3D11/D3D12-Gerät oder einen OpenGL/GLES-Kontext initialisiert werden und bietet Zugriff auf die zugrunde liegenden nativen API-Objekte. Weitere Informationen finden Sie auf den folgenden Seiten:
Direct3D11-Interoperabilität
Direct3D12-Interoperabilität
OpenGL/GLES-Interoperabilität
Vulkan-Interoperabilität
Führen Sie die folgenden Schritte aus, um das NuGet-Paket zu erstellen:
Installieren Sie die erforderlichen Python-Pakete
python -m pip install -r ./BuildTools/.NET/requirements.txt
Führen Sie das NuGet-Paketerstellungsskript aus, zum Beispiel:
python ./BuildTools/.NET/dotnet-build-package.py -c Debug -d ./
Argument | Beschreibung | Erforderlich |
---|---|---|
-c ( configuration ) | Build-Konfiguration nativer dynamischer Bibliotheken (z. B. Debug, Release usw.) | Ja |
-d ( root-dir ) | Der Pfad zum Stammverzeichnis von DiligentCore | Ja |
-s ( settings ) | Der Pfad zur Einstellungsdatei | NEIN |
dotnet-tests | Flag, das angibt, ob .NET-Tests ausgeführt werden sollen | NEIN |
dotnet-publish | Flag, das angibt, ob das Paket in der NuGet-Galerie veröffentlicht werden soll | NEIN |
free-memory | Verwenden Sie dieses Argument, wenn während des Erstellungsprozesses nicht genügend Arbeitsspeicher vorhanden ist | NEIN |
Sie können die Standardeinstellungen mithilfe einer Einstellungsdatei überschreiben (überprüfen Sie das Wörterbuch default_settings
in dotnet-build-package.py
“).
Siehe Apache 2.0-Lizenz.
Dieses Projekt weist einige Abhängigkeiten von Drittanbietern auf, die jeweils über eine unabhängige Lizenzierung verfügen können:
Vulkan-Header: Vulkan-Header-Dateien und API-Registrierung (Apache-Lizenz 2.0).
SPIRV-Cross: SPIRV-Parsing- und Cross-Compilation-Tools (Apache-Lizenz 2.0).
SPIRV-Header: SPIRV-Header-Dateien (Khronos MIT-ähnliche Lizenz).
SPIRV-Tools: SPIRV-Optimierungs- und Validierungstools (Apache-Lizenz 2.0).
glslang: Khronos-Referenzcompiler und Validator für GLSL, ESSL und HLSL (3-Klausel-BSD-Lizenz, 2-Klausel-BSD-Lizenz, MIT, Apache-Lizenz 2.0).
glew: OpenGL Extension Wrangler Library (Mesa 3-D-Grafikbibliothek, Khronos MIT-ähnliche Lizenz).
volk: Meta-Loader für die Vulkan-API (Arseny Kapoulkine MIT-ähnliche Lizenz).
stb: stb-Einzeldatei-Public-Domain-Bibliotheken für C/C++ (MIT-Lizenz oder Public Domain).
googletest: Google Testing and Mocking Framework (BSD 3-Clause „Neue“ oder „Überarbeitete“ Lizenz).
DirectXShaderCompiler: LLVM/Clang-basierter DirectX-Shader-Compiler (LLVM-Release-Lizenz).
DXBCChecksum: DXBC-Prüfsummenberechnungsalgorithmus vom AMD Developer Tools Team (MIT-Universität).
xxHash: Extrem schneller nicht-kryptografischer Hash-Algorithmus (2-Klausel-BSD-Lizenz).
Um Ihren Code beizutragen, senden Sie eine Pull-Anfrage an dieses Repository. Diligent Engine wird unter der Apache 2.0-Lizenz vertrieben, die garantiert, dass der Inhalt im DiligentCore -Repository frei von Einschränkungen des geistigen Eigentums ist. Durch die Übermittlung von Inhalten an dieses Repository lizenzieren Sie diese Inhalte unter denselben Bedingungen und stimmen zu, dass die Inhalte frei von Ansprüchen auf geistiges Eigentum sind und Sie das Recht haben, sie unter diesen Bedingungen zu lizenzieren.
Diligent Engine verwendet das Clang-Format, um einen konsistenten Quellcodestil in der gesamten Codebasis sicherzustellen. Das Format wird von CI für jede Commit- und Pull-Anfrage validiert und der Build schlägt fehl, wenn ein Problem mit der Codeformatierung festgestellt wird. Auf dieser Seite finden Sie Anweisungen zum Einrichten des Clang-Formats und der automatischen Codeformatierung.
Siehe Veröffentlichungsverlauf
diligentgraphics.com