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 Jan 21, 2021
1 parent 3519b9c commit 4e7239c
Show file tree
Hide file tree
Showing 9 changed files with 549 additions and 290 deletions.
112 changes: 76 additions & 36 deletions backends/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 @@ -264,50 +268,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 @@ -471,7 +504,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}

ImGui_ImplDX10_CreateFontsTexture();
ImGui_ImplDX10_UpdateFontsTexture();

return true;
}
Expand All @@ -483,6 +516,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 @@ -501,6 +535,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 @@ -530,6 +565,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();
}
112 changes: 76 additions & 36 deletions backends/imgui_impl_dx11.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: DirectX11: Add support for updating font textures.
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
Expand Down Expand Up @@ -47,7 +48,10 @@ static ID3D11InputLayout* g_pInputLayout = NULL;
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
static ID3D11PixelShader* g_pPixelShader = NULL;
static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11Texture2D* g_pFontTexture = NULL;
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
static int g_FontTextureWidth = 0;
static int g_FontTextureHeight = 0;
static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = NULL;
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
Expand Down Expand Up @@ -276,50 +280,79 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}

static void ImGui_ImplDX11_CreateFontsTexture()
static void ImGui_ImplDX11_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))
{
D3D11_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 = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;

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

// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &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
{
D3D11_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 = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;

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

// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(g_pFontTexture, &srvDesc, &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

D3D11_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_pd3dDeviceContext->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)
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
Expand Down Expand Up @@ -483,7 +516,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}

ImGui_ImplDX11_CreateFontsTexture();
ImGui_ImplDX11_UpdateFontsTexture();

return true;
}
Expand All @@ -495,6 +528,7 @@ void ImGui_ImplDX11_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->Release(); g_pFontTexture = NULL; }
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }

Expand All @@ -513,6 +547,7 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx11";
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_ImplDX11_NewFrame)

// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
Expand Down Expand Up @@ -545,6 +580,11 @@ void ImGui_ImplDX11_Shutdown()

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

if (!g_pFontSampler)
ImGui_ImplDX11_CreateDeviceObjects();

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

0 comments on commit 4e7239c

Please sign in to comment.