Skip to content

Commit

Permalink
Shadows, Backends: added font texture updating support for DX9-DX12 a…
Browse files Browse the repository at this point in the history
…nd Vulkan. (experimental)
  • Loading branch information
ShironekoBen authored and ocornut committed Jun 3, 2020
1 parent 30bcce0 commit bb8a3cb
Show file tree
Hide file tree
Showing 9 changed files with 548 additions and 291 deletions.
70 changes: 39 additions & 31 deletions examples/example_glfw_vulkan/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ int main(int, char**)
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);

io.BackendFlags |= ImGuiBackendFlags_RendererHasTexReload; // Set flag to indicate that we can reload textures when requested.

// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
Expand All @@ -409,37 +411,7 @@ int main(int, char**)
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);

// Upload Fonts
{
// Use any command queue
VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;

err = vkResetCommandPool(g_Device, command_pool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(command_buffer, &begin_info);
check_vk_result(err);

ImGui_ImplVulkan_CreateFontsTexture(command_buffer);

VkSubmitInfo end_info = {};
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
end_info.commandBufferCount = 1;
end_info.pCommandBuffers = &command_buffer;
err = vkEndCommandBuffer(command_buffer);
check_vk_result(err);
err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE);
check_vk_result(err);

err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
ImGui_ImplVulkan_DestroyFontUploadObjects();
}
//IM_ASSERT(font != NULL);

// Our state
bool show_demo_window = true;
Expand Down Expand Up @@ -467,6 +439,42 @@ int main(int, char**)

// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();

// Upload Fonts
if (io.Fonts->IsDirty())
{
// We don't want to trample on the previous frame if it is still in-flight
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);

// Use any command queue
VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;

err = vkResetCommandPool(g_Device, command_pool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(command_buffer, &begin_info);
check_vk_result(err);

ImGui_ImplVulkan_UpdateFontsTexture(command_buffer);

VkSubmitInfo end_info = {};
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
end_info.commandBufferCount = 1;
end_info.pCommandBuffers = &command_buffer;
err = vkEndCommandBuffer(command_buffer);
check_vk_result(err);
err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE);
check_vk_result(err);

err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
ImGui_ImplVulkan_DestroyFontUploadObjects();
}

ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();

Expand Down
10 changes: 10 additions & 0 deletions examples/example_win32_directx12/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ int main(int, char**)
g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart());

io.BackendFlags |= ImGuiBackendFlags_RendererHasTexReload; // Set flag to indicate that we can reload textures when requested.

// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
Expand Down Expand Up @@ -131,6 +133,14 @@ int main(int, char**)
// Start the Dear ImGui frame
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();

// Upload Fonts
if (io.Fonts->IsDirty())
{
WaitForLastSubmittedFrame();
ImGui_ImplDX12_UpdateFontsTexture();
}

ImGui::NewFrame();

// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
Expand Down
112 changes: 76 additions & 36 deletions examples/imgui_impl_dx10.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-04-24: DirectX10: Add support for updating font textures.
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
Expand Down Expand Up @@ -45,8 +46,11 @@ static ID3D10VertexShader* g_pVertexShader = NULL;
static ID3D10InputLayout* g_pInputLayout = NULL;
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10PixelShader* g_pPixelShader = NULL;
static ID3D10Texture2D* g_pFontTexture = NULL;
static ID3D10SamplerState* g_pFontSampler = NULL;
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
static int g_FontTextureWidth = 0;
static int g_FontTextureHeight = 0;
static ID3D10RasterizerState* g_pRasterizerState = NULL;
static ID3D10BlendState* g_pBlendState = NULL;
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
Expand Down Expand Up @@ -265,50 +269,79 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}

static void ImGui_ImplDX10_CreateFontsTexture()
static void ImGui_ImplDX10_UpdateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();

// Build texture atlas
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
int dirty_x, dirty_y, dirty_width, dirty_height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, NULL, &dirty_x, &dirty_y, &dirty_width, &dirty_height);

// Upload texture to graphics system
if ((!g_pFontTextureView) || (g_FontTextureWidth != width) || (g_FontTextureHeight != height))
{
D3D10_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;

ID3D10Texture2D *pTexture = NULL;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);

// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
ZeroMemory(&srv_desc, sizeof(srv_desc));
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
pTexture->Release();
// Either we have no texture or the size has changed, so (re-)create the texture

// Release old texture
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (g_pFontTexture) { g_pFontTexture->Release(); g_pFontTexture = NULL; }

// Create new texture
{
D3D10_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;

D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &g_pFontTexture);

// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
ZeroMemory(&srv_desc, sizeof(srv_desc));
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(g_pFontTexture, &srv_desc, &g_pFontTextureView);
}

// Store size
g_FontTextureWidth = width;
g_FontTextureHeight = height;

// Store our identifier
io.Fonts->TexID = (ImTextureID)g_pFontTextureView;
}
else if ((dirty_width > 0) && (dirty_height > 0))
{
// Upload the dirty region

D3D10_BOX box;
box.left = dirty_x;
box.right = dirty_x + dirty_width;
box.top = dirty_y;
box.bottom = dirty_y + dirty_height;
box.front = 0;
box.back = 1;

g_pd3dDevice->UpdateSubresource(g_pFontTexture, 0, &box, pixels, g_FontTextureWidth * 4, 0);
}

// Store our identifier
io.Fonts->TexID = (ImTextureID)g_pFontTextureView;
// Create texture sampler if required

// Create texture sampler
if (!g_pFontSampler)
{
D3D10_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
Expand Down Expand Up @@ -472,7 +505,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}

ImGui_ImplDX10_CreateFontsTexture();
ImGui_ImplDX10_UpdateFontsTexture();

return true;
}
Expand All @@ -484,6 +517,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects()

if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (g_pFontTexture) { g_pFontTexture->Release(); g_pFontTexture = NULL; }
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }

Expand All @@ -502,6 +536,7 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx10";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTexReload; // We support font atlas texture reloading (IsDirty() check in ImGui_ImplDX10_NewFrame)

// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
Expand Down Expand Up @@ -531,6 +566,11 @@ void ImGui_ImplDX10_Shutdown()

void ImGui_ImplDX10_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();

if (!g_pFontSampler)
ImGui_ImplDX10_CreateDeviceObjects();

if (io.Fonts->IsDirty())
ImGui_ImplDX10_UpdateFontsTexture();
}
Loading

0 comments on commit bb8a3cb

Please sign in to comment.