Diligent Core es una moderna API de gráficos de bajo nivel multiplataforma que constituye la base de Diligent Engine. El módulo implementa backends de renderizado Direct3D11, Direct3D12, OpenGL, OpenGLES y Vulkan (la implementación de Metal está disponible para clientes comerciales), así como utilidades básicas específicas de la plataforma. Es autónomo y puede construirse solo. Consulte el repositorio principal para obtener información sobre las plataformas y funciones compatibles, instrucciones de compilación, etc.
Plataforma | Estado de construcción |
---|---|
Win32 | |
ventanas universales | |
linux | |
Androide | |
Mac OS | |
iOS | |
tvOS | |
escritos |
Clonando el repositorio
Conceptos básicos de API
Diseño de recursos de canalización
Win32
Plataforma universal de Windows
linux
Mac OS
Androide
iOS
escritos
Destruyendo el motor
Inicializando el motor
Creando recursos
Creando sombreadores
Inicializando el estado de la tubería
Recursos de sombreadores vinculantes
Establecer el estado de la canalización e invocar el comando Draw
Interoperabilidad API de bajo nivel
Instrucciones de compilación del paquete NuGet
Licencia
Contribuyendo
Historial de lanzamientos
Para obtener el repositorio y todos los submódulos, use el siguiente comando:
git clone --recursive https://github.com/DiligentGraphics/DiligentCore.git
Para compilar el módulo, consulte las instrucciones de compilación en el repositorio principal.
Antes de poder utilizar cualquier funcionalidad proporcionada por el motor, necesita crear un dispositivo de renderizado, un contexto inmediato y una cadena de intercambio.
En la plataforma Win32, puede crear un dispositivo OpenGL, Direct3D11, Direct3D12 o Vulkan como se muestra a continuación:
void InicializarDiligentEngine(HWND NativeWindowHandle) { SwapChainDesc SCDesc;// RefCntAutoPtr<IRenderDevice> m_pDevice;// RefCntAutoPtr<IDeviceContext> m_pImmediateContext;// RefCntAutoPtr<ISwapChain> m_pSwapChain;switch (m_DeviceType) {caso RENDER_DEVICE_TYPE_D3D11: { MotorD3D11CreateInfo MotorCI; # if ENGINE_DLL// Carga el dll e importa GetEngineFactoryD3D11() functionauto* GetEngineFactoryD3D11 = LoadGraphicsEngineD3D11(); # endifauto* pFactoryD3D11 = GetEngineFactoryD3D11(); pFactoryD3D11->CreateDeviceAndContextsD3D11(EngineCI, &m_pDevice, &m_pImmediateContext); Ventana Win32NativeWindow{hWnd}; pFactoryD3D11->CreateSwapChainD3D11(m_pDevice, m_pImmediateContext, SCDesc, FullScreenModeDesc{}, Ventana, &m_pSwapChain); }romper;caso RENDER_DEVICE_TYPE_D3D12: { # if ENGINE_DLL// Carga el dll e importa GetEngineFactoryD3D12() functionauto GetEngineFactoryD3D12 = LoadGraphicsEngineD3D12(); # endifEngineD3D12CreateInfo EngineCI;auto* pFactoryD3D12 = GetEngineFactoryD3D12(); pFactoryD3D12->CreateDeviceAndContextsD3D12(EngineCI, &m_pDevice, &m_pImmediateContext); Ventana Win32NativeWindow{hWnd}; pFactoryD3D12->CreateSwapChainD3D12(m_pDevice, m_pImmediateContext, SCDesc, FullScreenModeDesc{}, Ventana, &m_pSwapChain); }romper;caso RENDER_DEVICE_TYPE_GL: { # if EXPLICITLY_LOAD_ENGINE_GL_DLL// Cargue el dll e importe la función GetEngineFactoryOpenGL()auto GetEngineFactoryOpenGL = LoadGraphicsEngineOpenGL(); # endifauto* pFactoryOpenGL = GetEngineFactoryOpenGL(); MotorGLCreateInfo MotorCI; MotorCI.Window.hWnd = hWnd; pFactoryOpenGL->CreateDeviceAndSwapChainGL(EngineCI, &m_pDevice, &m_pImmediateContext, SCDesc, &m_pSwapChain); }romper;caso RENDER_DEVICE_TYPE_VULKAN: { # if EXPLICITLY_LOAD_ENGINE_VK_DLL// Cargue el dll e importe la función GetEngineFactoryVk()auto GetEngineFactoryVk = LoadGraphicsEngineVk(); # endifEngineVkCreateInfo EngineCI;auto* pFactoryVk = GetEngineFactoryVk(); pFactoryVk->CreateDeviceAndContextsVk(EngineCI, &m_pDevice, &m_pImmediateContext); Ventana Win32NativeWindow{hWnd}; pFactoryVk->CreateSwapChainVk(m_pDevice, m_pImmediateContext, SCDesc, Ventana, &m_pSwapChain); }romper;predeterminado: std::cerr << "Tipo de dispositivo desconocido"; } }
En Windows, el motor puede vincularse estáticamente a la aplicación o crearse como una DLL independiente. En el primer caso, las funciones de fábrica GetEngineFactoryOpenGL()
, GetEngineFactoryD3D11()
, GetEngineFactoryD3D12()
y GetEngineFactoryVk()
se pueden llamar directamente. En el segundo caso, debe cargar la DLL en el espacio de direcciones del proceso usando la función LoadGraphicsEngineOpenGL()
, LoadGraphicsEngineD3D11()
, LoadGraphicsEngineD3D12()
o LoadGraphicsEngineVk()
. Cada función carga la biblioteca dinámica adecuada e importa las funciones necesarias para inicializar el motor. Debe incluir los siguientes encabezados:
#incluye "EngineFactoryD3D11.h"#incluye "EngineFactoryD3D12.h"#incluye "EngineFactoryOpenGL.h"#incluye "EngineFactoryVk.h"
También debe agregar los siguientes directorios a las rutas de búsqueda incluidas:
DiligentCore/Graphics/GraphicsEngineD3D11/interface
DiligentCore/Graphics/GraphicsEngineD3D12/interface
DiligentCore/Graphics/GraphicsEngineOpenGL/interface
DiligentCore/Graphics/GraphicsEngineVulkan/interface
Como alternativa, solo puede agregar la ruta a la carpeta raíz y luego usar incluir rutas relativas a ella.
Habilite el espacio de nombres Diligent
:
usando el espacio de nombres Diligente;
Las funciones IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
, IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
e IEngineFactoryVk::CreateDeviceAndContextsVk()
también pueden crear un número específico de contextos inmediatos y diferidos, que se pueden usar para la representación asincrónica y la grabación de comandos multiproceso. Los contextos sólo pueden crearse durante la inicialización del motor. La función completa una serie de punteros a los contextos, donde van primero los contextos inmediatos, seguidos de todos los contextos diferidos.
Para obtener más detalles, consulte el archivo Tutorial00_HelloWin32.cpp.
En la Plataforma universal de Windows, puede crear un dispositivo Direct3D11 o Direct3D12. La inicialización se realiza de la misma manera que en la plataforma Win32. La diferencia es que primero crea el dispositivo de representación y los contextos del dispositivo llamando IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
o IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
. La cadena de intercambio se crea posteriormente mediante una llamada a IEngineFactoryD3D11::CreateSwapChainD3D11()
o IEngineFactoryD3D12::CreateSwapChainD3D12()
. Mire el archivo SampleAppUWP.cpp para obtener más detalles.
En la plataforma Linux, el motor admite backends OpenGL y Vulkan. La inicialización del contexto GL en Linux está estrechamente relacionada con la creación de ventanas. Como resultado, Diligent Engine no inicializa el contexto, sino que lo adjunta al inicializado por la aplicación. Puede encontrar un ejemplo de inicialización del motor en Linux en Tutorial00_HelloLinux.cpp.
En MacOS, Diligent Engine admite backends OpenGL, Vulkan y Metal. La aplicación realiza la inicialización del contexto GL en MacOS y el motor se asocia al contexto creado por la aplicación; consulte GLView.mm para obtener más detalles. El backend de Vulkan se inicializa de manera similar a otras plataformas. Consulte MetalView.mm.
En Android, puedes crear un dispositivo OpenGLES o Vulkan. El siguiente fragmento de código muestra un ejemplo:
auto* pFactoryOpenGL = GetEngineFactoryOpenGL(); MotorGLCreateInfo MotorCI; EngineCI.Window.pAWindow = NativeWindowHandle; pFactoryOpenGL->CreateDeviceAndSwapChainGL( EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Si el motor está construido como una biblioteca dinámica, la actividad nativa debe cargar la biblioteca. El siguiente código muestra una forma posible:
estático{prueba{System.loadLibrary("GraphicsEngineOpenGL"); } catch (UnsatisfiedLinkError e) {Log.e("actividad nativa", "Error al cargar la biblioteca GraphicsEngineOpenGL.n" + e); } }
La implementación de iOS es compatible con OpenGLES, Vulkan y Metal backend. La aplicación realiza la inicialización del contexto GL en iOS y el motor se adjunta al contexto inicializado por la aplicación; consulte EAGLView.mm para obtener más detalles.
En Emscripten, puede crear un dispositivo OpenGLES. El siguiente fragmento de código muestra un ejemplo:
//Necesitas pasar el id del lienzo a NativeWindowauto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo MotorCI = {}; EngineCI.Window = NativeWindow{"#canvas"}; pFactoryOpenGL->CreateDeviceAndSwapChainGL(EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Si utiliza SDL o GLFW con contexto existente, puede proporcionar null como identificador de ventana nativo: EngineCI.Window = NativeWindow{nullptr}
El motor realiza un recuento automático de referencias y se apaga cuando se libera la última referencia a un objeto del motor.
Los recursos del dispositivo son creados por el dispositivo de renderizado. Los dos tipos de recursos principales son los buffers, que representan memoria lineal, y las texturas, que utilizan diseños de memoria optimizados para un filtrado rápido. Para crear un búfer, debe completar la estructura BufferDesc
y llamar IRenderDevice::CreateBuffer()
. El siguiente código crea un búfer uniforme (constante):
BufferDesc BuffDesc; BuffDesc.Name = "Búfer uniforme"; BuffDesc.BindFlags = BIND_UNIFORM_BUFFER; BuffDesc.Usage = USAGE_DYNAMIC; BuffDesc.uiSizeInBytes = tamaño de (ShaderConstants); BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; m_pDevice->CreateBuffer(BuffDesc, nullptr, &m_pConstantBuffer);
De manera similar, para crear una textura, complete la estructura TextureDesc
y llame IRenderDevice::CreateTexture()
como en el siguiente ejemplo:
TexturaDesc TexDesc; TexDesc.Name = "Mi textura 2D"; TexDesc.Type = TEXTURE_TYPE_2D; TexDesc.Ancho = 1024; TexDesc.Altura = 1024; TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; TexDesc.Usage = USAGE_DEFAULT; TexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; TexDesc.Name = "Muestra de textura 2D"; m_pRenderDevice->CreateTexture(TexDesc, nullptr, &m_pTestTex);
Sólo existe una función CreateTexture()
que es capaz de crear todo tipo de texturas. El tipo, el formato, el tamaño de la matriz y todos los demás parámetros los especifican los miembros de la estructura TextureDesc
.
Para cada indicador de vinculación especificado durante el tiempo de creación de la textura, el objeto de textura crea una vista predeterminada. La vista de recursos de sombreado predeterminada aborda toda la textura, las vistas predeterminadas de destino de renderizado y plantilla de profundidad hacen referencia a todos los sectores de la matriz en el nivel mip más detallado, y la vista de acceso desordenado hace referencia a toda la textura. Para obtener una vista predeterminada de la textura, use la función ITexture::GetDefaultView()
. Tenga en cuenta que esta función no incrementa el contador de referencia de la interfaz devuelta. Puede crear vistas de textura adicionales usando ITexture::CreateView()
. Utilice IBuffer::CreateView()
para crear vistas adicionales de un búfer.
Para crear un sombreador, complete la estructura ShaderCreateInfo
:
ShaderCreateInfo ShaderCI;
Hay tres formas de crear un sombreador. La primera forma es proporcionar un puntero al código fuente del sombreador a través del miembro ShaderCreateInfo::Source
. La segunda forma es proporcionar un nombre de archivo. La tercera forma es proporcionar un puntero al código de bytes compilado a través del miembro ShaderCreateInfo::ByteCode
. Graphics Engine está completamente desacoplado de la plataforma. Dado que el sistema de archivos del host depende de la plataforma, la estructura expone el miembro ShaderCreateInfo::pShaderSourceStreamFactory
que está destinado a otorgar al motor acceso al sistema de archivos. Si proporcionó el nombre del archivo fuente, también debe proporcionar un puntero no nulo a la fábrica de secuencias fuente del sombreador. Si la fuente del sombreador contiene directivas #include
, la fábrica de secuencias de origen también se utilizará para cargar estos archivos. El motor proporciona una implementación predeterminada para cada plataforma compatible que debería ser suficiente en la mayoría de los casos. Sin embargo, puede definir su propia implementación.
Un miembro importante es ShaderCreateInfo::SourceLanguage
. Los siguientes son valores válidos para este miembro:
SHADER_SOURCE_LANGUAGE_DEFAULT
: el formato de origen del sombreador coincide con la API de gráficos subyacente: HLSL para el modo D3D11 o D3D12 y GLSL para los modos OpenGL, OpenGLES y Vulkan.
SHADER_SOURCE_LANGUAGE_HLSL
: la fuente del sombreador está en HLSL. Para los modos OpenGL y OpenGLES, el código fuente se convertirá a GLSL. En el back-end de Vulkan, el código se compilará directamente en SPIRV.
SHADER_SOURCE_LANGUAGE_GLSL
: la fuente del sombreador está en GLSL.
SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM
: el lenguaje fuente del sombreador es GLSL y debe compilarse palabra por palabra.
SHADER_SOURCE_LANGUAGE_MSL
: el idioma de origen es Metal Shading Language.
Otros miembros de la estructura ShaderCreateInfo
definen el sombreador, incluidos directorios de búsqueda, definiciones de macros de sombreador, puntos de entrada del sombreador y otros parámetros.
Macros ShaderMacroHelper; Macros.AddShaderMacro("USE_SHADOWS", 1); Macros.AddShaderMacro("NUM_SHADOW_SAMPLES", 4); Macros.Finalize(); ShaderCI.Macros = Macros;
Cuando todo esté listo, llame IRenderDevice::CreateShader()
para crear el objeto sombreador:
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 sigue el estilo Direct3D12/Vulkan para configurar el canal de gráficos/cómputo. Un objeto de estado de canalización (PSO) monolítico abarca todos los estados requeridos (todas las etapas de sombreado, descripción del diseño de entrada, plantilla de profundidad, rasterizador y descripciones de estado de fusión, etc.). Para crear un objeto de estado de canalización de gráficos, defina una instancia de la estructura GraphicsPipelineStateCreateInfo
:
GraphicsPipelineStateCreateInfo PSOCreateInfo; PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; PSODesc.Name = "Estado de mi canalización";
Describa los detalles específicos de la canalización, como el número y el formato de los objetivos de renderizado, así como el formato de plantilla de profundidad:
// Esta es una canalización de gráficosPSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS; PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 1; PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB; PSOCreateInfo.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
Inicialice la descripción del estado de la plantilla de profundidad DepthStencilStateDesc
. Tenga en cuenta que el constructor inicializa los miembros con valores predeterminados y usted solo puede configurar los que son diferentes de los predeterminados.
// Iniciar estado de plantilla de profundidadDepthStencilStateDesc& DepthStencilDesc = PSOCreateInfo.GraphicsPipeline.DepthStencilDesc; DepthStencilDesc.DepthEnable = verdadero; DepthStencilDesc.DepthWriteEnable = verdadero;
Inicializar la descripción del estado de mezcla BlendStateDesc
:
// Iniciar blend stateBlendStateDesc& BSDesc = PSOCreateInfo.GraphicsPipeline.BlendDesc; BSDesc.IndependentBlendEnable = False;auto &RT0 = BSDesc.RenderTargets[0]; RT0.BlendEnable = Verdadero; 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;
Inicializar la descripción del estado del rasterizador RasterizerStateDesc
:
// Inicia el estado del rasterizadorRasterizerStateDesc& RasterizerDesc = PSOCreateInfo.GraphicsPipeline.RasterizerDesc; RasterizerDesc.FillMode = FILL_MODE_SOLID; RasterizerDesc.CullMode = CULL_MODE_NONE; RasterizerDesc.FrontCounterClockwise = Verdadero; RasterizerDesc.ScissorEnable = Verdadero; RasterizerDesc.AntialiasedLineEnable = Falso;
Inicializar la descripción del diseño de entrada InputLayoutDesc
:
// Definir diseño de entradaInputLayoutDesc& Layout = PSOCreateInfo.GraphicsPipeline.InputLayout; Elemento de diseñoElems de diseño[] = {LayoutElement (0, 0, 3, VT_FLOAT32, Falso), LayoutElement (1, 0, 4, VT_UINT8, Verdadero), LayoutElement (2, 0, 2, VT_FLOAT32, Falso), }; Diseño.LayoutElements = DiseñoElems; Diseño.NumElements = _countof(LayoutElems);
Defina la topología primitiva y establezca punteros de sombreado:
// Definir sombreador y topología primitivaPSOCreateInfo.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; PSOCreateInfo.pVS = m_pVS; PSOCreateInfo.pPS = m_pPS;
El diseño de recursos de canalización informa al motor cómo la aplicación utilizará diferentes variables de recursos de sombreado. Para permitir la agrupación de recursos según la frecuencia esperada de los cambios en los enlaces de recursos, Diligent Engine introduce la clasificación de variables de sombreado:
Las variables estáticas ( SHADER_RESOURCE_VARIABLE_TYPE_STATIC
) son variables que se espera que se establezcan solo una vez. No se pueden cambiar una vez que un recurso está vinculado a la variable. Estas variables están destinadas a mantener constantes globales, como atributos de cámara o atributos de luz globales, buffers constantes. Tenga en cuenta que es el enlace del recurso el que no puede cambiar, mientras que el contenido del recurso puede cambiar según su uso.
Las variables mutables ( SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE
) definen los recursos que se espera que cambien con una frecuencia por material. Los ejemplos pueden incluir texturas difusas, mapas normales, etc. Nuevamente, las actualizaciones del contenido del recurso son ortogobales a los cambios vinculantes.
Se espera que las variables dinámicas ( SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC
) cambien con frecuencia y de forma aleatoria.
Para definir tipos de variables, prepare una matriz de estructuras ShaderResourceVariableDesc
e inicialice los miembros PSODesc.ResourceLayout.Variables
y PSODesc.ResourceLayout.NumVariables
. También se puede utilizar PSODesc.ResourceLayout.DefaultVariableType
para establecer el tipo que se utilizará si no se proporciona un nombre de variable.
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;
Al crear un estado de canalización, a las texturas se les pueden asignar muestreadores inmutables de forma permanente. Si se asigna una muestra inmutable a una textura, siempre se usará en lugar de la inicializada en la vista de recursos del sombreador de texturas. Para definir muestreadores inmutables, prepare una matriz de estructuras ImmutableSamplerDesc
e inicialice los miembros PSODesc.ResourceLayout.ImmutableSamplers
y PSODesc.ResourceLayout.NumImmutableSamplers
. Tenga en cuenta que los samplers inmutables se pueden asignar a una variable de textura de cualquier tipo, no necesariamente estática, de modo que el enlace de textura se pueda cambiar en tiempo de ejecución, mientras que el sampler permanecerá inmutable. Se recomienda encarecidamente utilizar muestreadores inmutables siempre que sea posible.
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;
Este documento proporciona información detallada sobre cómo trabajar con muestreadores de texturas.
Cuando todos los campos obligatorios de la estructura de descripción de PSO estén configurados, llame IRenderDevice::CreateGraphicsPipelineState()
para crear el objeto PSO:
m_pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &m_pPSO);
Como se mencionó anteriormente, la vinculación de recursos de sombreado en Diligent Engine se basa en agrupar variables en 3 grupos diferentes (estático, mutable y dinámico). Las variables estáticas son variables que se espera que se establezcan solo una vez. No se pueden cambiar una vez que un recurso está vinculado a la variable. Estas variables están destinadas a mantener constantes globales, como atributos de cámara o atributos de luz globales, buffers constantes. Están vinculados directamente al objeto de estado de tubería:
m_pPSO->GetStaticShaderVariable(SHADER_TYPE_PIXEL, "g_tex2DSadowMap")->Set(pShadowMapSRV);
Las variables mutables y dinámicas se vinculan mediante un nuevo objeto llamado Shader Resource Binding (SRB), que se crea mediante el estado de la canalización ( IPipelineState::CreateShaderResourceBinding()
) o la firma del recurso de la canalización en casos de uso avanzados:
m_pPSO->CreateShaderResourceBinding(&m_pSRB, verdadero);
El segundo parámetro le dice al sistema que inicialice estructuras internas en el objeto SRB que hacen referencia a variables estáticas en el PSO.
Luego, los recursos dinámicos y mutables se vinculan a través del objeto SRB:
m_pSRB->GetVariable(SHADER_TYPE_PIXEL, "tex2DDiffuse")->Set(pDiffuseTexSRV); m_pSRB->GetVariable(SHADER_TYPE_VERTEX, "cbRandomAttribs")->Set(pRandomAttrsCB);
La diferencia entre recursos mutables y dinámicos es que los recursos mutables solo se pueden configurar una vez por instancia de un enlace de recurso de sombreado. Los recursos dinámicos se pueden configurar varias veces. Es importante configurar correctamente el tipo de variable ya que esto afecta el rendimiento. Las variables estáticas y mutables son más eficientes. Las variables dinámicas son más caras e introducen cierta sobrecarga en el tiempo de ejecución.
Una forma alternativa de vincular recursos de sombreador es crear una interfaz IResourceMapping
que asigne nombres literales de recursos a los recursos reales:
Entradas de ResourceMappingEntry[] = { {"g_Texture", pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)} }; ResourceMappingCreateInfo ResMappingCI; ResMappingCI.pEntries = Entradas; ResMappingCI.NumEntries = _countof(Entries); RefCntAutoPtr<IResourceMapping> pResMapping; pRenderDevice->CreateResourceMapping(ResMappingCI, &pResMapping);
Luego, la asignación de recursos se puede utilizar para vincular todos los recursos estáticos en un estado de canalización ( IPipelineState::BindStaticResources()
):
m_pPSO->BindStaticResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
o todos los recursos mutables y dinámicos en un enlace de recursos de sombreador ( IShaderResourceBinding::BindResources()
):
m_pSRB->BindResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
El último parámetro de todas las funciones BindResources()
define cómo se deben resolver los recursos:
BIND_SHADER_RESOURCES_UPDATE_STATIC
: indica que los enlaces de variables estáticas deben actualizarse.
BIND_SHADER_RESOURCES_UPDATE_MUTABLE
: indica que los enlaces de variables mutables deben actualizarse.
BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
: indica que los enlaces de variables dinámicas deben actualizarse.
BIND_SHADER_RESOURCES_UPDATE_ALL
: indica que todos los tipos de variables (estáticas, mutables y dinámicas) deben actualizarse. Tenga en cuenta que si no se establece ninguno de los indicadores BIND_SHADER_RESOURCES_UPDATE_STATIC
, BIND_SHADER_RESOURCES_UPDATE_MUTABLE
y BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
, todos los tipos de variables se actualizan como si se hubiera especificado BIND_SHADER_RESOURCES_UPDATE_ALL
.
BIND_SHADER_RESOURCES_KEEP_EXISTING
: si se especifica este indicador, solo se actualizarán los enlaces no resueltos. Todos los enlaces existentes mantendrán sus valores originales. Si no se especifica este indicador, cada variable de sombreado se actualizará si la asignación contiene el recurso correspondiente.
BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED
: si se especifica este indicador, se espera que todos los enlaces de sombreado se resuelvan después de la llamada. Si este no es el caso, se informará un error.
BindResources()
se puede llamar varias veces con diferentes asignaciones de recursos para vincular recursos. Sin embargo, se recomienda utilizar un mapeo de recursos grande ya que el tamaño del mapeo no afecta el tiempo de búsqueda de elementos.
El motor realiza comprobaciones en tiempo de ejecución para verificar que se estén vinculando los recursos correctos. Por ejemplo, si intenta vincular un búfer constante a una variable de vista de recursos de sombreado, se enviará un error a la consola de depuración.
Antes de que se pueda invocar cualquier comando de dibujo, todos los buffers de índice y vértice requeridos, así como el estado de la canalización, deben estar vinculados al contexto del dispositivo:
// Establece objetivos de renderizado antes de emitir cualquier comando de dibujo.auto* pRTV = m_pSwapChain->GetCurrentBackBufferRTV();auto* pDSV = m_pSwapChain->GetDepthBufferDSV(); m_pContext->SetRenderTargets(1, &pRTV, pDSV, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);// Borrar el objetivo de renderizado y la profundidad-stencilconst 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);// Establecer buffers de vértice e índiceIBuffer* buffer[] = {m_pVertexBuffer}; Uint32 compensaciones [] = {0}; m_pContext->SetVertexBuffers(0, 1, búfer, compensaciones, 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);
Todos los métodos que puedan necesitar realizar transiciones de estado de recursos toman la enumeración RESOURCE_STATE_TRANSITION_MODE
como parámetro. La enumeración define los siguientes modos:
RESOURCE_STATE_TRANSITION_MODE_NONE
: no realiza transiciones de estado de recursos.
RESOURCE_STATE_TRANSITION_MODE_TRANSITION
: transición de recursos a los estados requeridos por el comando.
RESOURCE_STATE_TRANSITION_MODE_VERIFY
: no realice la transición, pero verifique que los estados sean correctos.
El último paso es asignar recursos de sombreado al contexto del dispositivo. Esto se logra mediante el método IDeviceContext::CommitShaderResources()
:
m_pContext->CommitShaderResources(m_pSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
Si no se llama al método, el motor detectará que los recursos no están comprometidos y generará un mensaje de depuración. Tenga en cuenta que el último parámetro le indica al sistema que transfiera los recursos a los estados correctos. Si no se especifica este indicador, los recursos deben pasar explícitamente a los estados requeridos mediante una llamada a IDeviceContext::TransitionShaderResources()
:
m_pContext->TransitionShaderResources(m_pPSO, m_pSRB);
Tenga en cuenta que el método requiere un puntero al estado de la canalización que creó el enlace del recurso del sombreador.
Cuando todos los estados y recursos necesarios están vinculados, se puede utilizar IDeviceContext::DrawIndexed()
para ejecutar un comando de dibujo o IDeviceContext::DispatchCompute()
para ejecutar un comando de cálculo. Tenga en cuenta que para un comando de dibujo, se debe vincular una canalización de gráficos y, para un comando de distribución, se debe vincular una canalización de cálculo. DrawIndexed()
toma la estructura DrawIndexedAttribs
como argumento, por ejemplo:
atributos DrawIndexedAttribs; atributos.IndexType = VT_UINT16; atributos.NumIndices = 36; atributos.Flags = DRAW_FLAG_VERIFY_STATES; pContext->DrawIndexed(atributos);
El indicador DRAW_FLAG_VERIFY_STATES
indica al motor que verifique que los buffers de vértice e índice utilizados por el comando de dibujo hayan pasado a los estados adecuados.
DispatchCompute()
toma la estructura DispatchComputeAttribs
que define las dimensiones de la cuadrícula de cálculo:
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);
Puede obtener más información sobre la API del motor estudiando ejemplos y tutoriales.
Diligent Engine admite ampliamente la interoperabilidad con API subyacentes de bajo nivel. El motor se puede inicializar conectándolo a un dispositivo D3D11/D3D12 existente o al contexto OpenGL/GLES y proporciona acceso a los objetos API nativos subyacentes. Consulte las siguientes páginas para obtener más información:
Interoperabilidad Direct3D11
Interoperabilidad Direct3D12
Interoperabilidad OpenGL/GLES
Interoperabilidad de Vulkan
Siga los siguientes pasos para compilar el paquete NuGet:
Instale los paquetes de Python necesarios
python -m pip install -r ./BuildTools/.NET/requirements.txt
Ejecute el script de compilación del paquete NuGet, por ejemplo:
python ./BuildTools/.NET/dotnet-build-package.py -c Debug -d ./
Argumento | Descripción | Requerido |
---|---|---|
-c ( configuration ) | Configuración de compilación de bibliotecas dinámicas nativas (por ejemplo, depuración, lanzamiento, etc.) | Sí |
-d ( root-dir ) | La ruta al directorio raíz de DiligentCore | Sí |
-s ( settings ) | La ruta al archivo de configuración. | No |
dotnet-tests | Bandera que indica si se deben ejecutar pruebas .NET | No |
dotnet-publish | Marca que indica si se debe publicar el paquete en la Galería NuGet | No |
free-memory | Utilice este argumento si encuentra memoria insuficiente durante el proceso de compilación. | No |
Puede anular la configuración predeterminada utilizando un archivo de configuración (consulte el diccionario default_settings
en dotnet-build-package.py
).
Ver licencia Apache 2.0.
Este proyecto tiene algunas dependencias de terceros, cada una de las cuales puede tener licencias independientes:
Vulkan-Headers: Archivos de encabezado de Vulkan y registro API (Licencia Apache 2.0).
SPIRV-Cross: Herramientas de compilación cruzada y análisis SPIRV (Licencia Apache 2.0).
SPIRV-Headers: archivos de encabezado SPIRV (licencia similar a Khronos MIT).
SPIRV-Tools: Herramientas de optimización y validación de SPIRV (Licencia Apache 2.0).
glslang: compilador y validador de referencia de Khronos para GLSL, ESSL y HLSL (licencia BSD de 3 cláusulas, licencia BSD de 2 cláusulas, MIT, licencia Apache 2.0).
glew: Biblioteca Wrangler de extensión OpenGL (biblioteca de gráficos 3-D de Mesa, licencia similar a Khronos MIT).
volk: Metacargador para Vulkan API (licencia tipo MIT de Arseny Kapoulkine).
stb: bibliotecas stb de dominio público de un solo archivo para C/C++ (licencia MIT o dominio público).
googletest: Marco de prueba y simulación de Google (licencia BSD de 3 cláusulas "nueva" o "revisada").
DirectXShaderCompiler: Compilador DirectX Shader basado en LLVM/Clang (licencia de lanzamiento de LLVM).
DXBCChecksum: Algoritmo de cálculo de suma de comprobación DXBC del equipo de herramientas de desarrollo de AMD (MIT lincesne).
xxHash: Algoritmo hash no criptográfico extremadamente rápido (Licencia BSD de 2 cláusulas).
Para contribuir con su código, envíe una solicitud de extracción a este repositorio. Diligent Engine se distribuye bajo la licencia Apache 2.0 que garantiza que el contenido del repositorio de DiligentCore está libre de gravámenes de propiedad intelectual. Al enviar cualquier contenido a este repositorio, usted otorga la licencia de ese contenido bajo los mismos términos, y acepta que el contenido está libre de cualquier reclamo de propiedad intelectual y que tiene derecho a licenciarlo bajo esos términos.
Diligent Engine utiliza el formato clang para garantizar un estilo de código fuente coherente en todo el código base. CI valida el formato para cada confirmación y solicitud de extracción, y la compilación fallará si se encuentra algún problema de formato del código. Consulte esta página para obtener instrucciones sobre cómo configurar el formato clang y el formato de código automático.
Ver historial de lanzamientos
diligentegraphics.com