mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-21 15:59:18 +02:00
merge manul
This commit is contained in:
408
manul/renderer/source/imgui_nvrhi.cpp
Normal file
408
manul/renderer/source/imgui_nvrhi.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
License for Dear ImGui
|
||||
|
||||
Copyright (c) 2014-2019 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "imgui_nvrhi.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "config.h"
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
struct ImguiPushConstants {
|
||||
glm::vec2 m_inv_display_size;
|
||||
float m_ui_nits;
|
||||
MaConfig::MaTonemapType m_tonemap_function;
|
||||
};
|
||||
|
||||
bool ImGui_NVRHI::createFontTexture(nvrhi::ICommandList* commandList)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char *pixels;
|
||||
int width, height;
|
||||
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
{
|
||||
nvrhi::TextureDesc desc;
|
||||
desc.width = width;
|
||||
desc.height = height;
|
||||
desc.format = nvrhi::Format::RGBA8_UNORM;
|
||||
desc.debugName = "ImGui font texture";
|
||||
|
||||
fontTexture = renderer->createTexture(desc);
|
||||
|
||||
commandList->beginTrackingTextureState(fontTexture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common);
|
||||
|
||||
if (fontTexture == nullptr)
|
||||
return false;
|
||||
|
||||
commandList->writeTexture(fontTexture, 0, 0, pixels, width * 4);
|
||||
|
||||
commandList->setPermanentTextureState(fontTexture, nvrhi::ResourceStates::ShaderResource);
|
||||
commandList->commitBarriers();
|
||||
|
||||
io.Fonts->TexID = fontTexture;
|
||||
}
|
||||
|
||||
{
|
||||
const auto desc = nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::Wrap)
|
||||
.setAllFilters(true);
|
||||
|
||||
fontSampler = renderer->createSampler(desc);
|
||||
|
||||
if (fontSampler == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::init(NvRendererBackend *backend)
|
||||
{
|
||||
this->renderer = renderer;
|
||||
|
||||
m_commandList = renderer->createCommandList();
|
||||
|
||||
m_commandList->open();
|
||||
|
||||
vertexShader = backend->CreateShader("imgui_vertex", nvrhi::ShaderType::Vertex);
|
||||
if (vertexShader == nullptr)
|
||||
{
|
||||
printf("error creating NVRHI vertex shader object\n");
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
pixelShader = backend->CreateShader("imgui_pixel", nvrhi::ShaderType::Pixel);
|
||||
if (pixelShader == nullptr)
|
||||
{
|
||||
printf("error creating NVRHI pixel shader object\n");
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create attribute layout object
|
||||
nvrhi::VertexAttributeDesc vertexAttribLayout[] = {
|
||||
{ "POSITION", nvrhi::Format::RG32_FLOAT, 1, 0, offsetof(ImDrawVert,pos), sizeof(ImDrawVert), false },
|
||||
{ "TEXCOORD", nvrhi::Format::RG32_FLOAT, 1, 0, offsetof(ImDrawVert,uv), sizeof(ImDrawVert), false },
|
||||
{ "COLOR", nvrhi::Format::RGBA8_UNORM, 1, 0, offsetof(ImDrawVert,col), sizeof(ImDrawVert), false },
|
||||
};
|
||||
|
||||
shaderAttribLayout = renderer->createInputLayout(vertexAttribLayout, sizeof(vertexAttribLayout) / sizeof(vertexAttribLayout[0]), vertexShader);
|
||||
|
||||
// add the default font - before creating the font texture
|
||||
auto& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontDefault();
|
||||
|
||||
// create font texture
|
||||
if (!createFontTexture(m_commandList))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// create PSO
|
||||
{
|
||||
nvrhi::BlendState blendState;
|
||||
blendState.targets[0].setBlendEnable(true)
|
||||
.setSrcBlend(nvrhi::BlendFactor::SrcAlpha)
|
||||
.setDestBlend(nvrhi::BlendFactor::InvSrcAlpha)
|
||||
.setSrcBlendAlpha(nvrhi::BlendFactor::InvSrcAlpha)
|
||||
.setDestBlendAlpha(nvrhi::BlendFactor::Zero);
|
||||
|
||||
auto rasterState = nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.setCullNone()
|
||||
.setScissorEnable(true)
|
||||
.setDepthClipEnable(true);
|
||||
|
||||
auto depthStencilState = nvrhi::DepthStencilState()
|
||||
.disableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Always);
|
||||
|
||||
nvrhi::RenderState renderState;
|
||||
renderState.blendState = blendState;
|
||||
renderState.depthStencilState = depthStencilState;
|
||||
renderState.rasterState = rasterState;
|
||||
|
||||
nvrhi::BindingLayoutDesc layoutDesc;
|
||||
layoutDesc.visibility = nvrhi::ShaderType::All;
|
||||
layoutDesc.bindings = {
|
||||
nvrhi::BindingLayoutItem::PushConstants(0, sizeof(ImguiPushConstants)),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV(0),
|
||||
nvrhi::BindingLayoutItem::Sampler(0)
|
||||
};
|
||||
bindingLayout = renderer->createBindingLayout(layoutDesc);
|
||||
|
||||
basePSODesc.primType = nvrhi::PrimitiveType::TriangleList;
|
||||
basePSODesc.inputLayout = shaderAttribLayout;
|
||||
basePSODesc.VS = vertexShader;
|
||||
basePSODesc.PS = pixelShader;
|
||||
basePSODesc.renderState = renderState;
|
||||
basePSODesc.bindingLayouts = { bindingLayout };
|
||||
}
|
||||
|
||||
m_commandList->close();
|
||||
renderer->executeCommandList(m_commandList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::reallocateBuffer(nvrhi::BufferHandle& buffer, size_t requiredSize, size_t reallocateSize, const bool indexBuffer)
|
||||
{
|
||||
if (buffer == nullptr || size_t(buffer->getDesc().byteSize) < requiredSize)
|
||||
{
|
||||
nvrhi::BufferDesc desc;
|
||||
desc.byteSize = uint32_t(reallocateSize);
|
||||
desc.structStride = 0;
|
||||
desc.debugName = indexBuffer ? "ImGui index buffer" : "ImGui vertex buffer";
|
||||
desc.canHaveUAVs = false;
|
||||
desc.isVertexBuffer = !indexBuffer;
|
||||
desc.isIndexBuffer = indexBuffer;
|
||||
desc.isDrawIndirectArgs = false;
|
||||
desc.isVolatile = false;
|
||||
desc.initialState = indexBuffer ? nvrhi::ResourceStates::IndexBuffer : nvrhi::ResourceStates::VertexBuffer;
|
||||
desc.keepInitialState = true;
|
||||
|
||||
buffer = renderer->createBuffer(desc);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::beginFrame()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
nvrhi::IGraphicsPipeline* ImGui_NVRHI::getPSO(nvrhi::IFramebuffer* fb)
|
||||
{
|
||||
if (pso)
|
||||
return pso;
|
||||
|
||||
pso = renderer->createGraphicsPipeline(basePSODesc, fb);
|
||||
assert(pso);
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
nvrhi::IBindingSet* ImGui_NVRHI::getBindingSet(void* handle)
|
||||
{
|
||||
nvrhi::ITexture* texture = reinterpret_cast<nvrhi::ITexture*>(handle);
|
||||
auto iter = bindingsCache.find(texture);
|
||||
if (iter != bindingsCache.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetDesc desc;
|
||||
|
||||
desc.bindings = {
|
||||
nvrhi::BindingSetItem::PushConstants(0, sizeof(ImguiPushConstants)),
|
||||
nvrhi::BindingSetItem::Texture_SRV(0, texture),
|
||||
nvrhi::BindingSetItem::Sampler(0, fontSampler)
|
||||
};
|
||||
|
||||
nvrhi::BindingSetHandle binding;
|
||||
binding = renderer->createBindingSet(desc, bindingLayout);
|
||||
assert(binding);
|
||||
|
||||
bindingsCache[texture] = binding;
|
||||
return binding;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::updateGeometry(nvrhi::ICommandList* commandList)
|
||||
{
|
||||
ImDrawData *drawData = ImGui::GetDrawData();
|
||||
|
||||
// create/resize vertex and index buffers if needed
|
||||
if (!reallocateBuffer(vertexBuffer,
|
||||
drawData->TotalVtxCount * sizeof(ImDrawVert),
|
||||
(drawData->TotalVtxCount + 5000) * sizeof(ImDrawVert),
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reallocateBuffer(indexBuffer,
|
||||
drawData->TotalIdxCount * sizeof(ImDrawIdx),
|
||||
(drawData->TotalIdxCount + 5000) * sizeof(ImDrawIdx),
|
||||
true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vtxBuffer.resize(vertexBuffer->getDesc().byteSize / sizeof(ImDrawVert));
|
||||
idxBuffer.resize(indexBuffer->getDesc().byteSize / sizeof(ImDrawIdx));
|
||||
|
||||
// copy and convert all vertices into a single contiguous buffer
|
||||
ImDrawVert *vtxDst = &vtxBuffer[0];
|
||||
ImDrawIdx *idxDst = &idxBuffer[0];
|
||||
|
||||
for(int n = 0; n < drawData->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList *cmdList = drawData->CmdLists[n];
|
||||
|
||||
memcpy(vtxDst, cmdList->VtxBuffer.Data, cmdList->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idxDst, cmdList->IdxBuffer.Data, cmdList->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
|
||||
vtxDst += cmdList->VtxBuffer.Size;
|
||||
idxDst += cmdList->IdxBuffer.Size;
|
||||
}
|
||||
|
||||
commandList->writeBuffer(vertexBuffer, &vtxBuffer[0], vertexBuffer->getDesc().byteSize);
|
||||
commandList->writeBuffer(indexBuffer, &idxBuffer[0], indexBuffer->getDesc().byteSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::render(nvrhi::IFramebuffer* framebuffer)
|
||||
{
|
||||
ImDrawData *drawData = ImGui::GetDrawData();
|
||||
const auto& io = ImGui::GetIO();
|
||||
|
||||
m_commandList->open();
|
||||
m_commandList->beginMarker("ImGUI");
|
||||
|
||||
if (!updateGeometry(m_commandList))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle DPI scaling
|
||||
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
ImguiPushConstants push_constants{};
|
||||
push_constants.m_inv_display_size = {1.f / io.DisplaySize.x, 1.f / io.DisplaySize.y};
|
||||
push_constants.m_ui_nits = NvRenderer::Config()->m_display.GetHDRConfig().m_ui_nits;
|
||||
push_constants.m_tonemap_function = NvRenderer::Config()->m_display.GetHDRConfig().m_tonemap_function;
|
||||
|
||||
// set up graphics state
|
||||
nvrhi::GraphicsState drawState;
|
||||
|
||||
drawState.framebuffer = framebuffer;
|
||||
assert(drawState.framebuffer);
|
||||
|
||||
drawState.pipeline = getPSO(drawState.framebuffer);
|
||||
|
||||
drawState.viewport.viewports.push_back(nvrhi::Viewport(io.DisplaySize.x * io.DisplayFramebufferScale.x,
|
||||
io.DisplaySize.y * io.DisplayFramebufferScale.y));
|
||||
drawState.viewport.scissorRects.resize(1); // updated below
|
||||
|
||||
nvrhi::VertexBufferBinding vbufBinding;
|
||||
vbufBinding.buffer = vertexBuffer;
|
||||
vbufBinding.slot = 0;
|
||||
vbufBinding.offset = 0;
|
||||
drawState.vertexBuffers.push_back(vbufBinding);
|
||||
|
||||
drawState.indexBuffer.buffer = indexBuffer;
|
||||
drawState.indexBuffer.format = (sizeof(ImDrawIdx) == 2 ? nvrhi::Format::R16_UINT : nvrhi::Format::R32_UINT);
|
||||
drawState.indexBuffer.offset = 0;
|
||||
|
||||
// render command lists
|
||||
int vtxOffset = 0;
|
||||
int idxOffset = 0;
|
||||
for(int n = 0; n < drawData->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList *cmdList = drawData->CmdLists[n];
|
||||
for(int i = 0; i < cmdList->CmdBuffer.Size; i++)
|
||||
{
|
||||
const ImDrawCmd *pCmd = &cmdList->CmdBuffer[i];
|
||||
|
||||
if (pCmd->UserCallback)
|
||||
{
|
||||
pCmd->UserCallback(cmdList, pCmd);
|
||||
} else {
|
||||
drawState.bindings = { getBindingSet(pCmd->TextureId) };
|
||||
assert(drawState.bindings[0]);
|
||||
|
||||
drawState.viewport.scissorRects[0] = nvrhi::Rect(int(pCmd->ClipRect.x),
|
||||
int(pCmd->ClipRect.z),
|
||||
int(pCmd->ClipRect.y),
|
||||
int(pCmd->ClipRect.w));
|
||||
|
||||
nvrhi::DrawArguments drawArguments;
|
||||
drawArguments.vertexCount = pCmd->ElemCount;
|
||||
drawArguments.startIndexLocation = idxOffset;
|
||||
drawArguments.startVertexLocation = vtxOffset;
|
||||
|
||||
m_commandList->setGraphicsState(drawState);
|
||||
m_commandList->setPushConstants(&push_constants, sizeof(push_constants));
|
||||
m_commandList->drawIndexed(drawArguments);
|
||||
}
|
||||
|
||||
idxOffset += pCmd->ElemCount;
|
||||
}
|
||||
|
||||
vtxOffset += cmdList->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
m_commandList->endMarker();
|
||||
m_commandList->close();
|
||||
renderer->executeCommandList(m_commandList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_NVRHI::backbufferResizing()
|
||||
{
|
||||
pso = nullptr;
|
||||
}
|
||||
Reference in New Issue
Block a user