Diligent Core — это современный кроссплатформенный низкоуровневый графический API, который составляет основу Diligent Engine. Модуль реализует механизмы рендеринга Direct3D11, Direct3D12, OpenGL, OpenGLES и Vulkan (реализация Metal доступна для коммерческих клиентов), а также базовые утилиты для конкретной платформы. Он автономен и может быть построен самостоятельно. Пожалуйста, обратитесь к основному репозиторию для получения информации о поддерживаемых платформах и функциях, инструкциях по сборке и т. д.
Платформа | Статус сборки |
---|---|
Win32 | |
Универсальные окна | |
Линукс | |
Андроид | |
MacOS | |
iOS | |
ТВОС | |
Эмскриптен |
Клонирование репозитория
Основы API
Схема ресурсов конвейера
Win32
Универсальная платформа Windows
Линукс
MacOS
Андроид
iOS
Эмскриптен
Уничтожение двигателя
Инициализация двигателя
Создание ресурсов
Создание шейдеров
Инициализация состояния конвейера
Привязка ресурсов шейдера
Установка состояния конвейера и вызов команды Draw
Низкоуровневая совместимость API
Инструкции по сборке пакета NuGet
Лицензия
Содействие
История выпусков
Чтобы получить репозиторий и все подмодули, используйте следующую команду:
git clone --recursive https://github.com/DiligentGraphics/DiligentCore.git
Чтобы собрать модуль, см. инструкции по сборке в главном репозитории.
Прежде чем вы сможете использовать какие-либо функции, предоставляемые движком, вам необходимо создать устройство рендеринга, непосредственный контекст и цепочку обмена.
На платформе Win32 вы можете создать устройство OpenGL, Direct3D11, Direct3D12 или Vulkan, как показано ниже:
void InitializeDiligentEngine (HWND NativeWindowHandle) { SwapChainDesc SCDesc;// RefCntAutoPtr<IRenderDevice> m_pDevice;// RefCntAutoPtr<IDeviceContext> m_pImmediateContext;// RefCntAutoPtr<ISwapChain> m_pSwapChain;switch (m_DeviceType) {случай RENDER_DEVICE_TYPE_D3D11: { EngineD3D11CreateInfo EngineCI; # if ENGINE_DLL// Загрузите dll и импортируйте 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); }перерыв;случай RENDER_DEVICE_TYPE_D3D12: { # if ENGINE_DLL// Загрузите dll и импортируйте 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); }перерыв;случай RENDER_DEVICE_TYPE_GL: { # if EXPLICITLY_LOAD_ENGINE_GL_DLL// Загрузите dll и импортируйте GetEngineFactoryOpenGL() functionauto GetEngineFactoryOpenGL = LoadGraphicsEngineOpenGL(); # endifauto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI; EngineCI.Window.hWnd = hWnd; pFactoryOpenGL->CreateDeviceAndSwapChainGL(EngineCI, &m_pDevice, &m_pImmediateContext, SCDesc, &m_pSwapChain); }перерыв;случай RENDER_DEVICE_TYPE_VULKAN: { # if EXPLICITLY_LOAD_ENGINE_VK_DLL// Загрузите dll и импортируйте 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); } перерыв;по умолчанию: std::cerr << "Неизвестный тип устройства"; } }
В Windows движок может быть статически связан с приложением или создан как отдельная DLL. В первом случае фабричные функции GetEngineFactoryOpenGL()
, GetEngineFactoryD3D11()
, GetEngineFactoryD3D12()
и GetEngineFactoryVk()
могут вызываться напрямую. Во втором случае вам необходимо загрузить DLL в адресное пространство процесса с помощью функции LoadGraphicsEngineOpenGL()
, LoadGraphicsEngineD3D11()
, LoadGraphicsEngineD3D12()
или LoadGraphicsEngineVk()
. Каждая функция загружает соответствующую динамическую библиотеку и импортирует функции, необходимые для инициализации движка. Вам необходимо включить следующие заголовки:
#include "EngineFactoryD3D11.h"#include "EngineFactoryD3D12.h"#include "EngineFactoryOpenGL.h"#include "EngineFactoryVk.h"
Вам также необходимо добавить следующие каталоги в пути поиска включения:
DiligentCore/Graphics/GraphicsEngineD3D11/interface
DiligentCore/Graphics/GraphicsEngineD3D12/interface
DiligentCore/Graphics/GraphicsEngineOpenGL/interface
DiligentCore/Graphics/GraphicsEngineVulkan/interface
В качестве альтернативы вы можете добавить путь только к корневой папке, а затем использовать связанные с ней пути включения.
Включите пространство имен Diligent
:
использование пространства имен Diligent;
Функции IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
, IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
и IEngineFactoryVk::CreateDeviceAndContextsVk()
также могут создавать указанное количество немедленных и отложенных контекстов, которые можно использовать для асинхронного рендеринга и многопоточной обработки. запись команд. Контексты могут быть созданы только во время инициализации движка. Функция заполняет массив указателей на контексты, где первыми идут немедленные контексты, а затем все отложенные контексты.
Для получения более подробной информации ознакомьтесь с файлом Tutorial00_HelloWin32.cpp.
На универсальной платформе Windows вы можете создать устройство Direct3D11 или Direct3D12. Инициализация выполняется так же, как и на платформе Win32. Разница в том, что сначала вы создаете устройство рендеринга и контексты устройства, вызывая IEngineFactoryD3D11::CreateDeviceAndContextsD3D11()
или IEngineFactoryD3D12::CreateDeviceAndContextsD3D12()
. Цепочка обмена создается позже путем вызова IEngineFactoryD3D11::CreateSwapChainD3D11()
или IEngineFactoryD3D12::CreateSwapChainD3D12()
. Дополнительную информацию см. в файле SampleAppUWP.cpp.
На платформе Linux движок поддерживает серверные части OpenGL и Vulkan. Инициализация контекста GL в Linux тесно связана с созданием окна. В результате Diligent Engine не инициализирует контекст, а присоединяется к тому, который был инициализирован приложением. Пример инициализации движка в Linux можно найти в Tutorial00_HelloLinux.cpp.
В MacOS Diligent Engine поддерживает серверные части OpenGL, Vulkan и Metal. Инициализация контекста GL в MacOS выполняется приложением, и движок подключается к контексту, созданному приложением; подробности см. в GLView.mm. Серверная часть Vulkan инициализируется аналогично другим платформам. См. MetalView.mm.
На Android вы можете создать устройство OpenGLES или Vulkan. В следующем фрагменте кода показан пример:
auto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI; EngineCI.Window.pAWindow = NativeWindowHandle; pFactoryOpenGL->CreateDeviceAndSwapChainGL( EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Если движок построен как динамическая библиотека, библиотеку необходимо загрузить с помощью встроенного действия. Следующий код показывает один из возможных способов:
static {try {System.loadLibrary("GraphicsEngineOpenGL"); } catch (UnsatisfiedLinkError e) {Log.e("native-activity", "Не удалось загрузить библиотеку GraphicsEngineOpenGL.n" + e); } }
Реализация iOS поддерживает серверную часть OpenGLES, Vulkan и Metal. Инициализация контекста GL в iOS выполняется приложением, и движок подключается к контексту, инициализированному приложением; подробности см. на EAGLView.mm.
В Emscripten вы можете создать устройство OpenGLES. В следующем фрагменте кода показан пример:
//Вам необходимо передать идентификатор холста в NativeWindowauto* pFactoryOpenGL = GetEngineFactoryOpenGL(); EngineGLCreateInfo EngineCI = {}; EngineCI.Window = NativeWindow{"#canvas"}; pFactoryOpenGL-> CreateDeviceAndSwapChainGL (EngineCI, &m_pDevice, &m_pContext, SCDesc, &m_pSwapChain);
Если вы используете SDL или GLFW с существующим контекстом, вы можете указать значение null в качестве собственного дескриптора окна: EngineCI.Window = NativeWindow{nullptr}
Механизм выполняет автоматический подсчет ссылок и отключается, когда освобождается последняя ссылка на объект механизма.
Ресурсы устройства создаются устройством рендеринга. Двумя основными типами ресурсов являются буферы, представляющие линейную память, и текстуры, использующие структуру памяти, оптимизированную для быстрой фильтрации. Чтобы создать буфер, вам необходимо заполнить структуру BufferDesc
и вызвать IRenderDevice::CreateBuffer()
. Следующий код создает универсальный (постоянный) буфер:
Буфердеск Буффдеск; BuffDesc.Name = "Единый буфер"; 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);
Аналогично, чтобы создать текстуру, заполните структуру TextureDesc
и вызовите IRenderDevice::CreateTexture()
как показано в следующем примере:
Текстурдеск TexDesc; TexDesc.Name = "Моя текстура 2D"; TexDesc.Type = TEXTURE_TYPE_2D; TexDesc.Width = 1024; TexDesc.Высота = 1024; TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; TexDesc.Usage = USAGE_DEFAULT; TexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; TexDesc.Name = "Образец 2D-текстуры"; m_pRenderDevice-> CreateTexture (TexDesc, nullptr, & m_pTestTex);
Существует только одна функция CreateTexture()
, способная создавать все типы текстур. Тип, формат, размер массива и все остальные параметры задаются членами структуры TextureDesc
.
Для каждого флага привязки, указанного во время создания текстуры, объект текстуры создает представление по умолчанию. Представление ресурса шейдера по умолчанию обращается ко всей текстуре, представление цели рендеринга по умолчанию и представления трафарета глубины ссылаются на все фрагменты массива на самом подробном MIP-уровне, а представление неупорядоченного доступа ссылается на всю текстуру. Чтобы получить вид по умолчанию из текстуры, используйте функцию ITexture::GetDefaultView()
. Обратите внимание, что эта функция не увеличивает счетчик ссылок возвращаемого интерфейса. Вы можете создать дополнительные представления текстуры, используя ITexture::CreateView()
. Используйте IBuffer::CreateView()
для создания дополнительных представлений буфера.
Чтобы создать шейдер, заполните структуру ShaderCreateInfo
:
ShaderCreateInfo ShaderCI;
Существует три способа создания шейдера. Первый способ — предоставить указатель на исходный код шейдера через элемент ShaderCreateInfo::Source
. Второй способ — указать имя файла. Третий способ — предоставить указатель на скомпилированный байт-код через элемент ShaderCreateInfo::ByteCode
. Графический движок полностью отделен от платформы. Поскольку файловая система хоста зависит от платформы, структура предоставляет элемент ShaderCreateInfo::pShaderSourceStreamFactory
, который предназначен для предоставления подсистеме доступа к файловой системе. Если вы указали имя исходного файла, вы также должны предоставить ненулевой указатель на фабрику исходного потока шейдера. Если исходный код шейдера содержит какие-либо директивы #include
, фабрика исходного потока также будет использоваться для загрузки этих файлов. Движок обеспечивает реализацию по умолчанию для каждой поддерживаемой платформы, чего в большинстве случаев должно быть достаточно. Однако вы можете определить свою собственную реализацию.
Важным членом является ShaderCreateInfo::SourceLanguage
. Ниже приведены допустимые значения для этого элемента:
SHADER_SOURCE_LANGUAGE_DEFAULT
— исходный формат шейдера соответствует базовому графическому API: HLSL для режима D3D11 или D3D12 и GLSL для режимов OpenGL, OpenGLES и Vulkan.
SHADER_SOURCE_LANGUAGE_HLSL
— источник шейдера находится в HLSL. Для режимов OpenGL и OpenGLES исходный код будет преобразован в GLSL. В серверной части Vulkan код будет напрямую скомпилирован в SPIRV.
SHADER_SOURCE_LANGUAGE_GLSL
— источник шейдера находится в GLSL.
SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM
— исходным языком шейдера является GLSL, и его следует скомпилировать дословно.
SHADER_SOURCE_LANGUAGE_MSL
— исходный язык — Metal Shading Language.
Другие члены структуры ShaderCreateInfo
определяют шейдер, включая каталоги поиска, определения макросов шейдера, точку входа шейдера и другие параметры.
Макросы ShaderMacroHelper; Macros.AddShaderMacro("USE_SHADOWS", 1); Macros.AddShaderMacro("NUM_SHADOW_SAMPLES", 4); Макросы.Финализировать(); ShaderCI.Macros = Макросы;
Когда все будет готово, вызовите IRenderDevice::CreateShader()
чтобы создать объект шейдера:
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 следует стилю Direct3D12/Vulkan для настройки графического/вычислительного конвейера. Один монолитный объект состояния конвейеров (PSO) охватывает все необходимые состояния (все этапы шейдера, описание входного макета, трафарет глубины, растеризатор и описания состояний смешивания и т. д.). Чтобы создать объект состояния графического конвейера, определите экземпляр структуры GraphicsPipelineStateCreateInfo
:
GraphicsPipelineStateCreateInfo PSOCreateInfo; PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; PSODesc.Name = "Состояние моего конвейера";
Опишите особенности конвейера, такие как количество и формат целей рендеринга, а также формат трафарета глубины:
// Это графический конвейерPSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS; PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 1; PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB; PSOCreateInfo.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
Инициализировать описание состояния трафарета глубины DepthStencilStateDesc
. Обратите внимание, что конструктор инициализирует элементы значениями по умолчанию, и вы можете установить только те, которые отличаются от значений по умолчанию.
// Инициализация трафарета глубины stateDepthStencilStateDesc& DepthStencilDesc = PSOCreateInfo.GraphicsPipeline.DepthStencilDesc; DepthStencilDesc.DepthEnable = true; DepthStencilDesc.DepthWriteEnable = true;
Инициализировать описание состояния смешивания BlendStateDesc
:
// Инициализация blend stateBlendStateDesc& BSDesc = PSOCreateInfo.GraphicsPipeline.BlendDesc; BSDesc.IndependentBlendEnable = False;auto &RT0 = BSDesc.RenderTargets[0]; RT0.BlendEnable = Истина; 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;
Инициализировать описание состояния растеризатора RasterizerStateDesc
:
// Инициализация растеризатора stateRasterizerStateDesc& RasterizerDesc = PSOCreateInfo.GraphicsPipeline.RasterizerDesc; RasterizerDesc.FillMode = FILL_MODE_SOLID; RasterizerDesc.CullMode = CULL_MODE_NONE; RasterizerDesc.FrontCounterClockwise = True; RasterizerDesc.ScissorEnable = Истина; RasterizerDesc.AntialiasedLineEnable = False;
Инициализировать описание макета ввода InputLayoutDesc
:
// Определить макет вводаInputLayoutDesc& 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);
Определите примитивную топологию и установите указатели шейдера:
// Определить топологию шейдера и примитиваPSOCreateInfo.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; PSOCreateInfo.pVS = m_pVS; PSOCreateInfo.pPS = m_pPS;
Схема ресурсов конвейера сообщает движку, как приложение будет использовать различные переменные ресурсов шейдера. Чтобы обеспечить группировку ресурсов на основе ожидаемой частоты изменений привязок ресурсов, Diligent Engine вводит классификацию переменных шейдера:
Статические переменные ( SHADER_RESOURCE_VARIABLE_TYPE_STATIC
) — это переменные, которые, как ожидается, будут установлены только один раз. Их нельзя изменить после привязки ресурса к переменной. Такие переменные предназначены для хранения глобальных констант, таких как атрибуты камеры или буферы констант глобальных атрибутов освещения. Обратите внимание, что привязка ресурса не может меняться, в то время как содержимое ресурса может меняться в зависимости от его использования.
Изменяемые переменные ( SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE
) определяют ресурсы, которые, как ожидается, будут изменяться с частотой каждого материала. Примеры могут включать диффузные текстуры, карты нормалей и т. д. Опять же, обновления содержимого ресурса ортогональны изменениям привязки.
Ожидается, что динамические переменные ( SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC
) будут меняться часто и случайным образом.
Чтобы определить типы переменных, подготовьте массив структур ShaderResourceVariableDesc
и инициализируйте члены PSODesc.ResourceLayout.Variables
и PSODesc.ResourceLayout.NumVariables
. Также PSODesc.ResourceLayout.DefaultVariableType
можно использовать для установки типа, который будет использоваться, если имя переменной не указано.
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;
При создании состояния конвейера текстурам можно навсегда назначить неизменяемые сэмплеры. Если текстуре назначен неизменяемый сэмплер, он всегда будет использоваться вместо того, который инициализирован в представлении ресурсов шейдера текстуры. Чтобы определить неизменяемые сэмплеры, подготовьте массив структур ImmutableSamplerDesc
и инициализируйте члены PSODesc.ResourceLayout.ImmutableSamplers
и PSODesc.ResourceLayout.NumImmutableSamplers
. Обратите внимание, что неизменяемые сэмплеры могут быть назначены переменной текстуры любого типа, не обязательно статической, так что привязку текстуры можно изменить во время выполнения, в то время как сэмплер останется неизменным. Настоятельно рекомендуется по возможности использовать неизменяемые сэмплеры.
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;
В этом документе представлена подробная информация о работе с сэмплерами текстур.
Когда все обязательные поля структуры описания PSO заданы, вызовите IRenderDevice::CreateGraphicsPipelineState()
чтобы создать объект PSO:
m_pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &m_pPSO);
Как упоминалось выше, привязка ресурсов шейдера в Diligent Engine основана на группировке переменных в 3 разные группы (статические, изменяемые и динамические). Статические переменные — это переменные, которые, как ожидается, будут установлены только один раз. Их нельзя изменить после привязки ресурса к переменной. Такие переменные предназначены для хранения глобальных констант, таких как атрибуты камеры или буферы констант глобальных атрибутов освещения. Они привязаны непосредственно к объекту состояния конвейера:
m_pPSO->GetStaticShaderVariable(SHADER_TYPE_PIXEL, "g_tex2DShadowMap")->Set(pShadowMapSRV);
Изменяемые и динамические переменные связываются через новый объект под названием Shader Resource Binding (SRB), который создается состоянием конвейера ( IPipelineState::CreateShaderResourceBinding()
) или сигнатурой ресурса конвейера в расширенных случаях использования:
m_pPSO->CreateShaderResourceBinding(&m_pSRB, true);
Второй параметр указывает системе инициализировать внутренние структуры в объекте SRB, которые ссылаются на статические переменные в PSO.
Динамические и изменяемые ресурсы затем связываются через объект SRB:
m_pSRB->GetVariable(SHADER_TYPE_PIXEL, "tex2DDiffuse")->Set(pDiffuseTexSRV); m_pSRB->GetVariable(SHADER_TYPE_VERTEX, "cbRandomAttribs")->Set(pRandomAttrsCB);
Разница между изменяемыми и динамическими ресурсами заключается в том, что изменяемые ресурсы могут быть установлены только один раз для каждого экземпляра привязки ресурса шейдера. Динамические ресурсы можно задавать несколько раз. Важно правильно установить тип переменной, поскольку это влияет на производительность. Статические и изменяемые переменные более эффективны. Динамические переменные являются более дорогими и приводят к некоторым накладным расходам во время выполнения.
Альтернативный способ привязки ресурсов шейдера — создать интерфейс IResourceMapping
, который сопоставляет имена литералов ресурсов с фактическими ресурсами:
Записи ResourceMappingEntry[] = { {"g_Texture", pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)} }; ResourceMappingCreateInfo ResMappingCI; ResMappingCI.pEntries = Записи; ResMappingCI.NumEntries = _countof(Entries); RefCntAutoPtr<IResourceMapping> pResMapping; pRenderDevice->CreateResourceMapping(ResMappingCI, &pResMapping);
Затем сопоставление ресурсов можно использовать для привязки всех статических ресурсов в состоянии конвейера ( IPipelineState::BindStaticResources()
):
m_pPSO->BindStaticResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
или все изменяемые и динамические ресурсы в привязке ресурса шейдера ( IShaderResourceBinding::BindResources()
):
m_pSRB->BindResources(SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, pResMapping, BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED);
Последний параметр всех функций BindResources()
определяет, как следует разрешать ресурсы:
BIND_SHADER_RESOURCES_UPDATE_STATIC
— указывает, что привязки статических переменных должны быть обновлены.
BIND_SHADER_RESOURCES_UPDATE_MUTABLE
— указывает, что привязки изменяемых переменных должны быть обновлены.
BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
— указывает, что привязки динамических переменных должны быть обновлены.
BIND_SHADER_RESOURCES_UPDATE_ALL
— указывает, что все типы переменных (статические, изменяемые и динамические) должны быть обновлены. Обратите внимание: если ни один из флагов BIND_SHADER_RESOURCES_UPDATE_STATIC
, BIND_SHADER_RESOURCES_UPDATE_MUTABLE
и BIND_SHADER_RESOURCES_UPDATE_DYNAMIC
не установлен, все типы переменных обновляются так, как если бы был указан BIND_SHADER_RESOURCES_UPDATE_ALL
.
BIND_SHADER_RESOURCES_KEEP_EXISTING
— если указан этот флаг, будут обновляться только неразрешенные привязки. Все существующие привязки сохранят свои исходные значения. Если этот флаг не указан, каждая переменная шейдера будет обновлена, если отображение содержит соответствующий ресурс.
BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED
— если этот флаг указан, ожидается, что все привязки шейдеров будут разрешены после вызова. Если это не так, будет сообщено об ошибке.
BindResources()
может вызываться несколько раз с разными сопоставлениями ресурсов для привязки ресурсов. Однако рекомендуется использовать одно большое сопоставление ресурсов, поскольку размер сопоставления не влияет на время поиска элемента.
Механизм выполняет проверки во время выполнения, чтобы убедиться, что привязываются правильные ресурсы. Например, если вы попытаетесь привязать буфер констант к переменной представления ресурса шейдера, на консоль отладки будет выведена ошибка.
Прежде чем можно будет вызвать любую команду отрисовки, все необходимые буферы вершин и индексов, а также состояние конвейера должны быть привязаны к контексту устройства:
// Устанавливаем цели рендеринга перед выполнением любой команды рисования.auto* pRTV = m_pSwapChain->GetCurrentBackBufferRTV();auto* pDSV = m_pSwapChain->GetDepthBufferDSV(); m_pContext->SetRenderTargets(1, &pRTV, pDSV, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);// Очистить цель рендеринга и константу глубины трафарета float ноль[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);// Установить буферы вершин и индексовIBuffer* buffer[] = {m_pVertexBuffer}; Uint32 смещения[] = {0}; m_pContext->SetVertexBuffers(0, 1, буфер, смещения, 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);
Все методы, которым может потребоваться выполнить переходы между состояниями ресурсов, принимают в качестве параметра перечисление RESOURCE_STATE_TRANSITION_MODE
. Перечисление определяет следующие режимы:
RESOURCE_STATE_TRANSITION_MODE_NONE
— не выполнять переходы между состояниями ресурсов.
RESOURCE_STATE_TRANSITION_MODE_TRANSITION
— перевод ресурсов в состояния, необходимые команде.
RESOURCE_STATE_TRANSITION_MODE_VERIFY
— не выполнять переход, но проверять правильность состояний.
Последний шаг — зафиксировать ресурсы шейдера в контексте устройства. Это достигается с помощью метода IDeviceContext::CommitShaderResources()
:
m_pContext->CommitShaderResources(m_pSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
Если метод не вызывается, механизм обнаружит, что ресурсы не зафиксированы, и выведет отладочное сообщение. Обратите внимание, что последний параметр указывает системе перевести ресурсы в правильные состояния. Если этот флаг не указан, ресурсы должны быть явно переведены в требуемые состояния путем вызова IDeviceContext::TransitionShaderResources()
:
m_pContext->TransitionShaderResources(m_pPSO, m_pSRB);
Обратите внимание, что для этого метода требуется указатель на состояние конвейера, в котором создана привязка ресурса шейдера.
Когда все необходимые состояния и ресурсы привязаны, IDeviceContext::DrawIndexed()
можно использовать для выполнения команды рисования, или IDeviceContext::DispatchCompute()
можно использовать для выполнения команды вычисления. Обратите внимание, что для команды рисования должен быть привязан графический конвейер, а для команды отправки — вычислительный конвейер. DrawIndexed()
принимает в качестве аргумента структуру DrawIndexedAttribs
, например:
Атрибуты DrawIndexedAttribs; attrs.IndexType = VT_UINT16; attrs.NumIndices = 36; attrs.Flags = DRAW_FLAG_VERIFY_STATES; pContext->DrawIndexed(attrs);
Флаг DRAW_FLAG_VERIFY_STATES
указывает движку проверить, что буферы вершин и индексов, используемые командой рисования, переводятся в правильные состояния.
DispatchCompute()
принимает структуру DispatchComputeAttribs
, которая определяет размеры вычислительной сетки:
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);
Вы можете узнать больше об API движка, изучив примеры и руководства.
Diligent Engine широко поддерживает взаимодействие с базовыми API-интерфейсами низкого уровня. Движок можно инициализировать путем подключения к существующему устройству D3D11/D3D12 или контексту OpenGL/GLES и обеспечить доступ к базовым собственным объектам API. Для получения дополнительной информации обратитесь к следующим страницам:
Совместимость с Direct3D11
Совместимость с Direct3D12
Совместимость OpenGL/GLES
Совместимость с Вулканом
Выполните следующие шаги для сборки пакета NuGet:
Установите необходимые пакеты Python
python -m pip install -r ./BuildTools/.NET/requirements.txt
Запустите сценарий сборки пакета NuGet, например:
python ./BuildTools/.NET/dotnet-build-package.py -c Debug -d ./
Аргумент | Описание | Необходимый |
---|---|---|
-c ( configuration ) | Конфигурация сборки собственных динамических библиотек (например, отладка, выпуск и т. д.) | Да |
-d ( root-dir ) | Путь к корневому каталогу DiligentCore | Да |
-s ( settings ) | Путь к файлу настроек | Нет |
dotnet-tests | Флаг, указывающий, следует ли запускать тесты .NET. | Нет |
dotnet-publish | Флаг, указывающий, следует ли публиковать пакет в галерее NuGet. | Нет |
free-memory | Используйте этот аргумент, если в процессе сборки вам не хватает памяти. | Нет |
Вы можете переопределить настройки по умолчанию, используя файл настроек (проверьте словарь default_settings
в dotnet-build-package.py
).
См. лицензию Apache 2.0.
Этот проект имеет некоторые сторонние зависимости, каждая из которых может иметь независимое лицензирование:
Vulkan-Headers: файлы заголовков Vulkan и реестр API (лицензия Apache 2.0).
SPIRV-Cross: инструменты синтаксического анализа и кросс-компиляции SPIRV (лицензия Apache 2.0).
SPIRV-Headers: файлы заголовков SPIRV (лицензия типа Khronos MIT).
SPIRV-Tools: инструменты оптимизации и проверки SPIRV (лицензия Apache 2.0).
glslang: эталонный компилятор и валидатор Khronos для GLSL, ESSL и HLSL (лицензия BSD с 3 пунктами, лицензия BSD с 2 пунктами, MIT, лицензия Apache 2.0).
glew: библиотека OpenGL Extension Wrangler (библиотека трехмерной графики Mesa, лицензия Khronos MIT).
volk: Мета-загрузчик для Vulkan API (лицензия Арсения Капулкина, подобная MIT).
stb: однофайловые общедоступные библиотеки stb для C/C++ (лицензия MIT или общедоступное достояние).
googletest: Google Testing and Mocking Framework (3 пункта «Новой» или «пересмотренной» лицензии BSD).
DirectXShaderCompiler: компилятор шейдеров DirectX на основе LLVM/Clang (лицензия выпуска LLVM).
DXBCChecksum: алгоритм вычисления контрольной суммы DXBC, разработанный командой инструментов разработчиков AMD (MIT lincesne).
xxHash: Чрезвычайно быстрый некриптографический алгоритм хеширования (лицензия BSD с 2 пунктами).
Чтобы добавить свой код, отправьте запрос на включение в этот репозиторий. Diligent Engine распространяется по лицензии Apache 2.0, которая гарантирует, что содержимое репозитория DiligentCore не имеет ограничений интеллектуальной собственности. Отправляя любой контент в этот репозиторий, вы лицензируете этот контент на тех же условиях и соглашаетесь с тем, что этот контент не содержит каких-либо претензий на интеллектуальную собственность, и вы имеете право лицензировать его на этих условиях.
Diligent Engine использует формат clang для обеспечения единообразного стиля исходного кода во всей базе кода. Формат проверяется CI для каждого запроса фиксации и извлечения, и сборка завершится ошибкой, если будет обнаружена какая-либо проблема с форматированием кода. На этой странице приведены инструкции по настройке формата clang и автоматического форматирования кода.
См. историю выпусков
diligentgraphics.com