mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
ImGui thin3d backend: Add texture binding support
This commit is contained in:
parent
a74e4a105c
commit
57845b02c5
2 changed files with 74 additions and 28 deletions
|
@ -12,28 +12,52 @@ static Lin::Matrix4x4 g_drawMatrix;
|
|||
static ImFont *g_proportionalFont = nullptr;
|
||||
static ImFont *g_fixedFont = nullptr;
|
||||
|
||||
struct ImGui_ImplThin3d_Data {
|
||||
struct RegisteredTexture {
|
||||
bool isFramebuffer;
|
||||
union {
|
||||
Draw::Texture *texture;
|
||||
Draw::Framebuffer *framebuffer;
|
||||
};
|
||||
};
|
||||
|
||||
struct BackendData {
|
||||
Draw::SamplerState *fontSampler = nullptr;
|
||||
Draw::Texture *fontImage = nullptr;
|
||||
Draw::Pipeline *pipeline = nullptr;
|
||||
std::vector<RegisteredTexture> tempTextures;
|
||||
};
|
||||
|
||||
#define TEX_ID_OFFSET 256
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not tested and probably dysfunctional in this backend.
|
||||
static ImGui_ImplThin3d_Data* ImGui_ImplThin3d_GetBackendData() {
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplThin3d_Data *)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
static BackendData *ImGui_ImplThin3d_GetBackendData() {
|
||||
return ImGui::GetCurrentContext() ? (BackendData *)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawData* draw_data, Draw::Pipeline *pipeline, int fb_width, int fb_height) {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
static void BindTexture(Draw::DrawContext *draw, BackendData *bd, ImTextureID textureId) {
|
||||
if (!textureId) {
|
||||
draw->BindTexture(0, bd->fontImage);
|
||||
} else {
|
||||
size_t index = (size_t)textureId - TEX_ID_OFFSET;
|
||||
_dbg_assert_(index < bd->tempTextures.size());
|
||||
if (bd->tempTextures[index].framebuffer) {
|
||||
draw->BindFramebufferAsTexture(bd->tempTextures[index].framebuffer, 0, Draw::FBChannel::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
draw->BindTexture(0, bd->tempTextures[index].texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawData* drawData, Draw::Pipeline *pipeline, int fb_width, int fb_height) {
|
||||
BackendData *bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
// Bind pipeline and texture
|
||||
draw->BindPipeline(pipeline);
|
||||
draw->BindTexture(0, bd->fontImage);
|
||||
draw->BindSamplerStates(0, 1, &bd->fontSampler);
|
||||
|
||||
// Setup viewport:
|
||||
// Setup viewport
|
||||
{
|
||||
Draw::Viewport viewport;
|
||||
viewport.TopLeftX = 0;
|
||||
|
@ -46,10 +70,11 @@ static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawDat
|
|||
}
|
||||
|
||||
// Setup scale and translation:
|
||||
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
// We currently ignore DisplayPos.
|
||||
// Our visible imgui space lies from drawData->DisplayPps (top left) to drawData->DisplayPos + drawData->DisplaySize (bottom right).
|
||||
// DisplayPos is (0,0) for single viewport apps. We currently ignore DisplayPos.
|
||||
// We probably only need to do this at the start of the frame.
|
||||
{
|
||||
Lin::Matrix4x4 mtx = ComputeOrthoMatrix(draw_data->DisplaySize.x, draw_data->DisplaySize.y, draw->GetDeviceCaps().coordConvention);
|
||||
Lin::Matrix4x4 mtx = ComputeOrthoMatrix(drawData->DisplaySize.x, drawData->DisplaySize.y, draw->GetDeviceCaps().coordConvention);
|
||||
|
||||
Draw::VsTexColUB ub{};
|
||||
memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4));
|
||||
|
@ -63,10 +88,11 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
|
|||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
if (fb_width <= 0 || fb_height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
// Setup desired Vulkan state
|
||||
ImGui_ImplThin3d_SetupRenderState(draw, draw_data, bd->pipeline, fb_width, fb_height);
|
||||
|
@ -77,6 +103,8 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
|
|||
|
||||
_assert_(sizeof(ImDrawIdx) == 2);
|
||||
|
||||
ImTextureID prev = (ImTextureID)-1;
|
||||
|
||||
std::vector<Draw::ClippedDraw> draws;
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
||||
|
@ -84,6 +112,10 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
|
|||
draws.clear();
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->TextureId != prev) {
|
||||
BindTexture(draw, bd, pcmd->TextureId);
|
||||
prev = pcmd->TextureId;
|
||||
}
|
||||
if (pcmd->UserCallback != nullptr) {
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
|
@ -119,10 +151,13 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
|
|||
}
|
||||
|
||||
draw->SetScissorRect(0, 0, fb_width, fb_height);
|
||||
|
||||
// Discard temp textures.
|
||||
bd->tempTextures.clear();
|
||||
}
|
||||
|
||||
bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
if (!bd->fontSampler) {
|
||||
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
||||
|
@ -138,7 +173,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
|||
}
|
||||
|
||||
if (!bd->pipeline) {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
using namespace Draw;
|
||||
|
||||
|
@ -179,7 +214,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
|||
|
||||
if (!bd->fontImage) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
|
@ -204,7 +239,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
|||
|
||||
void ImGui_ImplThin3d_DestroyDeviceObjects() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
if (bd->fontImage) {
|
||||
bd->fontImage->Release();
|
||||
bd->fontImage = nullptr;
|
||||
|
@ -236,7 +271,7 @@ bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw, const uint8_t *ttf_font, siz
|
|||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplThin3d_Data* bd = IM_NEW(ImGui_ImplThin3d_Data)();
|
||||
BackendData* bd = IM_NEW(BackendData)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_thin3d";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
@ -253,7 +288,7 @@ void ImGui_PopFont() {
|
|||
}
|
||||
|
||||
void ImGui_ImplThin3d_Shutdown() {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
|
@ -265,7 +300,7 @@ void ImGui_ImplThin3d_Shutdown() {
|
|||
}
|
||||
|
||||
void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix) {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplThin3d_Init()?");
|
||||
|
||||
// This one checks if objects already have been created, so ok to call every time.
|
||||
|
@ -273,13 +308,22 @@ void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatri
|
|||
g_drawMatrix = drawMatrix;
|
||||
}
|
||||
|
||||
// Register a texture. No-op.
|
||||
ImTextureID ImGui_ImplThin3d_AddTexture(Draw::Texture *texture) {
|
||||
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
return (void *)texture;
|
||||
ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture) {
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
RegisteredTexture tex{ false };
|
||||
tex.texture = texture;
|
||||
|
||||
bd->tempTextures.push_back(tex);
|
||||
return (ImTextureID)(uint64_t)(TEX_ID_OFFSET + bd->tempTextures.size() - 1);
|
||||
}
|
||||
|
||||
// Unregister a texture. No-op.
|
||||
Draw::Texture *ImGui_ImplThin3d_RemoveTexture(ImTextureID tex) {
|
||||
return (Draw::Texture *)tex;
|
||||
ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer) {
|
||||
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
|
||||
|
||||
RegisteredTexture tex{ true };
|
||||
tex.framebuffer = framebuffer;
|
||||
|
||||
bd->tempTextures.push_back(tex);
|
||||
return (ImTextureID)(uint64_t)(TEX_ID_OFFSET + bd->tempTextures.size() - 1);
|
||||
}
|
||||
|
|
|
@ -41,8 +41,10 @@ IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_dat
|
|||
IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw);
|
||||
IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects();
|
||||
|
||||
IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTexture(Draw::Texture *texture);
|
||||
IMGUI_IMPL_API Draw::Texture *ImGui_ImplThin3d_RemoveTexture(ImTextureID texture);
|
||||
// These register a texture for imgui drawing, but just for the current frame.
|
||||
// Textures are unregistered again in RenderDrawData. This is just simpler.
|
||||
IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture);
|
||||
IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer);
|
||||
|
||||
void ImGui_PushFixedFont();
|
||||
void ImGui_PopFont();
|
||||
|
|
Loading…
Add table
Reference in a new issue