Merge pull request #19662 from hrydgard/more-im-debugger

ImDebugger: Add the ability to draw using multiple pipelines
This commit is contained in:
Henrik Rydgård 2024-11-27 08:29:35 +01:00 committed by GitHub
commit c685373444
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 237 additions and 125 deletions

View file

@ -164,7 +164,7 @@ public:
void DrawIndexed(int indexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -1407,7 +1407,13 @@ void D3D11DrawContext::DrawIndexedUP(const void *vdata, int vertexCount, const v
DrawIndexed(indexCount, 0);
}
void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) {
void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
if (draws.is_empty() || !vertexCount || !indexCount) {
return;
}
curPipeline_ = (D3D11Pipeline *)draws[0].pipeline;
int vbyteSize = vertexCount * curPipeline_->input->stride;
int ibyteSize = indexCount * sizeof(u16);
@ -1417,9 +1423,16 @@ void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCo
UpdateBuffer(upIBuffer_, (const uint8_t *)idata, 0, ibyteSize, Draw::UPDATE_DISCARD);
BindIndexBuffer(upIBuffer_, 0);
UpdateDynamicUniformBuffer(ub, ubSize);
ApplyCurrentState();
for (int i = 0; i < draws.size(); i++) {
if (draws[i].pipeline != curPipeline_) {
curPipeline_ = (D3D11Pipeline *)draws[i].pipeline;
ApplyCurrentState();
UpdateDynamicUniformBuffer(ub, ubSize);
}
if (draws[i].bindTexture) {
ID3D11ShaderResourceView *view = ((D3D11Texture *)draws[i].bindTexture)->View();
context_->PSSetShaderResources(0, 1, &view);
@ -1427,6 +1440,8 @@ void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCo
ID3D11ShaderResourceView *view = ((D3D11Framebuffer *)draws[i].bindFramebufferAsTex)->colorSRView;
context_->PSSetShaderResources(0, 1, &view);
}
ID3D11SamplerState *sstate = ((D3D11SamplerState *)draws[i].samplerState)->ss;
context_->PSSetSamplers(0, 1, &sstate);
D3D11_RECT rc;
rc.left = draws[i].clipx;
rc.top = draws[i].clipy;

View file

@ -574,7 +574,7 @@ public:
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -1203,16 +1203,29 @@ void D3D9Context::DrawIndexedUP(const void *vdata, int vertexCount, const void *
vdata, curPipeline_->inputLayout->GetStride());
}
void D3D9Context::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) {
void D3D9Context::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
if (draws.is_empty() || !vertexCount || !indexCount) {
return;
}
BindPipeline(draws[0].pipeline);
curPipeline_->inputLayout->Apply(device_);
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
ApplyDynamicState();
UpdateDynamicUniformBuffer(ub, ubSize);
// Suboptimal!
// Suboptimal! Should dirty-track textures.
for (int i = 0; i < draws.size(); i++) {
if (draws[i].pipeline != curPipeline_) {
D3D9Pipeline *d3d9Pipeline = (D3D9Pipeline *)draws[i].pipeline;
d3d9Pipeline->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
curPipeline_ = d3d9Pipeline;
}
if (draws[i].bindTexture) {
device_->SetTexture(0, ((D3D9Texture *)draws[i].bindTexture)->TexturePtr());
} else if (draws[i].bindFramebufferAsTex) {
// We ignore aspect in D3D9 :(
device_->SetTexture(0, ((D3D9Framebuffer *)draws[i].bindFramebufferAsTex)->tex.Get());
}

View file

@ -444,7 +444,7 @@ public:
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -1442,7 +1442,14 @@ void OpenGLContext::DrawIndexedUP(const void *vdata, int vertexCount, const void
renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset, curPipeline_->prim, indexCount, GL_UNSIGNED_SHORT, 1);
}
void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) {
void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
if (draws.is_empty() || !vertexCount || !indexCount) {
return;
}
BindPipeline(draws[0].pipeline);
UpdateDynamicUniformBuffer(ub, ubSize);
_assert_(curPipeline_->inputLayout != nullptr);
int stride = curPipeline_->inputLayout->stride;
uint32_t vdataSize = stride * vertexCount;
@ -1463,6 +1470,12 @@ void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount
ApplySamplers();
for (auto &draw : draws) {
if (draw.pipeline != curPipeline_) {
OpenGLPipeline *glPipeline = (OpenGLPipeline *)draw.pipeline;
_dbg_assert_(glPipeline->inputLayout->stride == stride);
BindPipeline(glPipeline); // this updated curPipeline_.
UpdateDynamicUniformBuffer(ub, ubSize);
}
if (draw.bindTexture) {
renderManager_.BindTexture(0, ((OpenGLTexture *)draw.bindTexture)->GetTex());
} else if (draw.bindFramebufferAsTex) {

View file

@ -493,7 +493,7 @@ public:
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
// Specialized for quick IMGUI drawing.
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw>) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw>, const void *dynUniforms, size_t size) override;
void BindCurrentPipeline();
void ApplyDynamicState();
@ -1557,13 +1557,15 @@ void VKContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *id
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, indexCount, 1);
}
void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) {
void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
_dbg_assert_(vertexCount >= 0);
_dbg_assert_(indexCount >= 0);
if (vertexCount <= 0 || indexCount <= 0 || draws.is_empty()) {
return;
}
curPipeline_ = (VKPipeline *)draws[0].pipeline;
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
size_t vdataSize = vertexCount * curPipeline_->stride;
uint32_t vbBindOffset;
@ -1579,18 +1581,28 @@ void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, co
_assert_(idataPtr != nullptr);
memcpy(idataPtr, idata, idataSize);
curPipeline_->SetDynamicUniformData(ub, ubSize);
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
BindCurrentPipeline();
ApplyDynamicState();
for (auto &draw : draws) {
if (draw.pipeline != curPipeline_) {
VKPipeline *vkPipe = (VKPipeline *)draw.pipeline;
renderManager_.BindPipeline(vkPipe->pipeline, vkPipe->flags, pipelineLayout_);
curPipeline_ = (VKPipeline *)draw.pipeline;
curPipeline_->SetDynamicUniformData(ub, ubSize);
}
// TODO: Dirty-check these.
if (draw.bindTexture) {
BindTexture(0, draw.bindTexture);
} else if (draw.bindFramebufferAsTex) {
BindFramebufferAsTexture(draw.bindFramebufferAsTex, 0, FBChannel::FB_COLOR_BIT, 0);
}
Draw::SamplerState *sstate = draw.samplerState;
BindSamplerStates(0, 1, &sstate);
int descSetIndex;
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
BindDescriptors(vulkanUBObuf, descriptors);

View file

@ -705,6 +705,8 @@ struct ClippedDraw {
s16 cliph;
Draw::Texture *bindTexture;
Draw::Framebuffer *bindFramebufferAsTex;
Draw::SamplerState *samplerState;
Draw::Pipeline *pipeline;
};
class DrawContext {
@ -843,7 +845,7 @@ public:
virtual void DrawUP(const void *vdata, int vertexCount) = 0;
virtual void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) = 0;
// Intended for ImGui display lists, easier to do optimally this way.
virtual void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws) = 0;
virtual void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *dynUniforms, size_t size) = 0;
// Frame management (for the purposes of sync and resource management, necessary with modern APIs). Default implementations here.
virtual void BeginFrame(DebugFlags debugFlags) = 0;

View file

@ -3667,13 +3667,12 @@ static void ApplyKillzoneFramebufferSplit(FramebufferHeuristicParams *params, in
void FramebufferManagerCommon::DrawImGuiDebug(int &selected) const {
ImGui::BeginTable("framebuffers", 4);
ImGui::TableSetupColumn("Tag");
ImGui::TableSetupColumn("Color Addr");
ImGui::TableSetupColumn("Depth Addr");
ImGui::TableSetupColumn("Size");
ImGui::TableSetupColumn("Tag", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Color Addr", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Depth Addr", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
ImGui::TableSetColumnIndex(0);
for (int i = 0; i < (int)vfbs_.size(); i++) {
ImGui::TableNextRow();
@ -3705,10 +3704,15 @@ void FramebufferManagerCommon::DrawImGuiDebug(int &selected) const {
}
ImGui::EndTable();
// Fix out-of-bounds issues when framebuffers are removed.
if (selected >= vfbs_.size()) {
selected = -1;
}
if (selected != -1) {
// Now, draw the image of the selected framebuffer.
Draw::Framebuffer *fb = vfbs_[selected]->fbo;
ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb);
ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb, Draw::FB_COLOR_BIT, ImGuiPipeline::TexturedOpaque);
ImGui::Image(texId, ImVec2(fb->Width(), fb->Height()));
}
}

View file

@ -4,6 +4,7 @@
#include "ext/imgui/imgui_internal.h"
#include "Common/StringUtils.h"
#include "Common/Data/Format/IniFile.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Core/RetroAchievements.h"
@ -230,7 +231,7 @@ static void DrawFilesystemBrowser(ImConfig &cfg) {
}
static void DrawKernelObjects(ImConfig &cfg) {
if (!ImGui::Begin("Kernel Objects", &cfg.filesystemBrowserOpen)) {
if (!ImGui::Begin("Kernel Objects", &cfg.kernelObjectsOpen)) {
ImGui::End();
return;
}
@ -691,6 +692,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Ge (GPU)")) {
ImGui::MenuItem("Display Output", nullptr, &cfg_.displayOpen);
ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen);
// More to come here...
ImGui::EndMenu();
@ -762,6 +764,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawFramebuffersWindow(cfg_, gpuDebug->GetFramebufferManagerCommon());
}
if (cfg_.displayOpen) {
DrawDisplayWindow(cfg_, gpuDebug->GetFramebufferManagerCommon());
}
if (cfg_.structViewerOpen) {
structViewer_.Draw(mipsDebug, &cfg_.structViewerOpen);
}
@ -914,3 +920,7 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
}
ImGui::End();
}
void ImDebugger::LoadConfig() {
IniFile ini;
}

View file

@ -37,6 +37,7 @@ public:
void DirtySymbolMap() {
symsDirty_ = true;
}
private:
// We just keep the state directly in the window. Can refactor later.
@ -56,11 +57,6 @@ private:
char searchTerm_[64]{};
};
class ImLuaConsole {
public:
// Stub
};
struct ImConfig {
bool disasmOpen = true;
bool demoOpen = false;
@ -73,6 +69,7 @@ struct ImConfig {
bool atracOpen = true;
bool structViewerOpen = false;
bool framebuffersOpen = false;
bool displayOpen = false;
bool styleEditorOpen = false;
bool filesystemBrowserOpen = false;
bool kernelObjectsOpen = false;
@ -86,6 +83,8 @@ struct ImConfig {
int selectedFramebuffer = -1;
int selectedBreakpoint = -1;
int selectedMemCheck = -1;
bool displayLatched = false;
};
enum ImUiCmd {
@ -96,14 +95,20 @@ struct ImUiCommand {
ImUiCmd cmd;
};
struct ImDebugger {
class ImDebugger {
public:
ImDebugger();
void Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug);
private:
// We use a separate ini file from the main PPSSPP config.
void LoadConfig();
void SaveConfig();
RequesterToken reqToken_;
ImDisasmWindow disasm_;
ImLuaConsole luaConsole_;
ImStructViewer structViewer_;
// Open variables.

View file

@ -1,7 +1,11 @@
#include "ext/imgui/imgui.h"
#include "ext/imgui/imgui_impl_thin3d.h"
#include "UI/ImDebugger/ImGe.h"
#include "UI/ImDebugger/ImDebugger.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "Core/HLE/sceDisplay.h"
void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager) {
if (!ImGui::Begin("Framebuffers", &cfg.framebuffersOpen)) {
ImGui::End();
@ -12,3 +16,30 @@ void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebuffer
ImGui::End();
}
void DrawDisplayWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager) {
if (!ImGui::Begin("Display", &cfg.framebuffersOpen)) {
ImGui::End();
return;
}
ImGui::Checkbox("Display latched", &cfg.displayLatched);
PSPPointer<u8> topaddr;
u32 linesize;
u32 pixelFormat;
__DisplayGetFramebuf(&topaddr, &linesize, &pixelFormat, cfg.displayLatched);
VirtualFramebuffer *fb = framebufferManager->GetVFBAt(topaddr.ptr);
if (fb && fb->fbo) {
ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb->fbo, Draw::FB_COLOR_BIT, ImGuiPipeline::TexturedOpaque);
ImGui::Image(texId, ImVec2(fb->width, fb->height));
ImGui::Text("%s - %08x", fb->fbo->Tag(), topaddr.ptr);
} else {
// TODO: Sometimes we should display RAM here.
ImGui::Text("Framebuffer not available to display");
}
ImGui::End();
}

View file

@ -7,6 +7,7 @@ struct ImConfig;
class FramebufferManagerCommon;
void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
void DrawDisplayWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
class ImGeDebugger {
public:

View file

@ -16,14 +16,18 @@ struct RegisteredTexture {
bool isFramebuffer;
union {
Draw::Texture *texture;
Draw::Framebuffer *framebuffer;
struct {
Draw::Framebuffer *framebuffer;
Draw::FBChannel aspect;
};
};
ImGuiPipeline pipeline;
};
struct BackendData {
Draw::SamplerState *fontSampler = nullptr;
Draw::Texture *fontImage = nullptr;
Draw::Pipeline *pipeline = nullptr;
Draw::Pipeline *pipelines[2]{};
std::vector<RegisteredTexture> tempTextures;
};
@ -36,39 +40,6 @@ static BackendData *ImGui_ImplThin3d_GetBackendData() {
return ImGui::GetCurrentContext() ? (BackendData *)ImGui::GetIO().BackendRendererUserData : nullptr;
}
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->BindSamplerStates(0, 1, &bd->fontSampler);
// Setup viewport
{
Draw::Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = (float)fb_width;
viewport.Height = (float)fb_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
draw->SetViewport(viewport);
}
// Setup scale and translation:
// 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(drawData->DisplaySize.x, drawData->DisplaySize.y, draw->GetDeviceCaps().coordConvention);
Draw::VsTexColUB ub{};
memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4));
ub.saturation = 1.0f;
draw->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
}
}
// Render function
void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw) {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
@ -79,9 +50,23 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
}
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
draw->BindSamplerStates(0, 1, &bd->fontSampler);
// Setup desired Vulkan state
ImGui_ImplThin3d_SetupRenderState(draw, draw_data, bd->pipeline, fb_width, fb_height);
// Setup viewport
Draw::Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = (float)fb_width;
viewport.Height = (float)fb_height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
draw->SetViewport(viewport);
Lin::Matrix4x4 mtx = ComputeOrthoMatrix(draw_data->DisplaySize.x, draw_data->DisplaySize.y, draw->GetDeviceCaps().coordConvention);
Draw::VsTexColUB ub{};
memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4));
ub.saturation = 1.0f;
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
@ -94,6 +79,8 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
std::vector<Draw::ClippedDraw> draws;
Draw::Texture *boundTexture;
Draw::Framebuffer *boundFBAsTexture;
Draw::Pipeline *boundPipeline = bd->pipelines[0];
Draw::SamplerState *boundSampler = bd->fontSampler;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++) {
@ -101,55 +88,56 @@ 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->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.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) {
ImGui_ImplThin3d_SetupRenderState(draw, draw_data, bd->pipeline, fb_width, fb_height);
} else {
pcmd->UserCallback(cmd_list, pcmd);
}
// We don't use the callback mechanism.
_dbg_assert_(pcmd->UserCallback == nullptr);
// Update the texture pointers.
if (!pcmd->TextureId) {
// Default
boundTexture = bd->fontImage;
boundFBAsTexture = nullptr;
boundPipeline = bd->pipelines[0];
boundSampler = bd->fontSampler;
} else {
// Update the texture pointers.
if (!pcmd->TextureId) {
boundTexture = bd->fontImage;
boundFBAsTexture = nullptr;
size_t index = (size_t)pcmd->TextureId - TEX_ID_OFFSET;
_dbg_assert_(index < bd->tempTextures.size());
if (bd->tempTextures[index].framebuffer) {
boundFBAsTexture = bd->tempTextures[index].framebuffer;
boundTexture = nullptr;
} else {
size_t index = (size_t)pcmd->TextureId - TEX_ID_OFFSET;
_dbg_assert_(index < bd->tempTextures.size());
if (bd->tempTextures[index].framebuffer) {
boundFBAsTexture = bd->tempTextures[index].framebuffer;
boundTexture = nullptr;
} else {
boundTexture = bd->tempTextures[index].texture;
boundFBAsTexture = nullptr;
}
boundTexture = bd->tempTextures[index].texture;
boundFBAsTexture = nullptr;
}
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
Draw::ClippedDraw clippedDraw;
clippedDraw.bindTexture = boundTexture;
clippedDraw.bindFramebufferAsTex = boundFBAsTexture;
clippedDraw.clipx = clip_min.x;
clippedDraw.clipy = clip_min.y;
clippedDraw.clipw = clip_max.x - clip_min.x;
clippedDraw.cliph = clip_max.y - clip_min.y;
clippedDraw.indexCount = pcmd->ElemCount;
clippedDraw.indexOffset = pcmd->IdxOffset;
draws.push_back(clippedDraw);
boundPipeline = bd->pipelines[(int)bd->tempTextures[index].pipeline];
boundSampler = bd->fontSampler;
}
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
Draw::ClippedDraw clippedDraw;
clippedDraw.pipeline = boundPipeline;
clippedDraw.bindTexture = boundTexture;
clippedDraw.bindFramebufferAsTex = boundFBAsTexture;
clippedDraw.samplerState = boundSampler;
clippedDraw.clipx = clip_min.x;
clippedDraw.clipy = clip_min.y;
clippedDraw.clipw = clip_max.x - clip_min.x;
clippedDraw.cliph = clip_max.y - clip_min.y;
clippedDraw.indexCount = pcmd->ElemCount;
clippedDraw.indexOffset = pcmd->IdxOffset;
draws.push_back(clippedDraw);
}
draw->DrawIndexedClippedBatchUP(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.size(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size(), draws);
draw->DrawIndexedClippedBatchUP(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.size(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size(), draws, &ub, sizeof(ub));
}
draw->SetScissorRect(0, 0, fb_width, fb_height);
@ -174,7 +162,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
bd->fontSampler = draw->CreateSamplerState(desc);
}
if (!bd->pipeline) {
if (!bd->pipelines[0]) {
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
using namespace Draw;
@ -193,6 +181,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD,
BlendFactor::ONE, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD,
});
BlendState *blendOpaque = draw->CreateBlendState({ false, 0xF });
DepthStencilStateDesc dsDesc{};
DepthStencilState *depthStencil = draw->CreateDepthStencilState(dsDesc);
@ -211,7 +200,15 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
&vsTexColBufDesc
};
bd->pipeline = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline");
bd->pipelines[0] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline");
pipelineDesc.blend = blendOpaque;
bd->pipelines[1] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline-opaque");
inputLayout->Release();
blend->Release();
blendOpaque->Release();
depthStencil->Release();
rasterNoCull->Release();
}
if (!bd->fontImage) {
@ -247,9 +244,11 @@ void ImGui_ImplThin3d_DestroyDeviceObjects() {
bd->fontImage = nullptr;
io.Fonts->SetTexID(0);
}
if (bd->pipeline) {
bd->pipeline->Release();
bd->pipeline = nullptr;
for (int i = 0; i < ARRAY_SIZE(bd->pipelines); i++) {
if (bd->pipelines[i]) {
bd->pipelines[i]->Release();
bd->pipelines[i] = nullptr;
}
}
if (bd->fontSampler) {
bd->fontSampler->Release();
@ -310,21 +309,24 @@ void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatri
g_drawMatrix = drawMatrix;
}
ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture) {
ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, ImGuiPipeline pipeline) {
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
RegisteredTexture tex{ false };
tex.texture = texture;
tex.pipeline = pipeline;
bd->tempTextures.push_back(tex);
return (ImTextureID)(uint64_t)(TEX_ID_OFFSET + bd->tempTextures.size() - 1);
}
ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer) {
ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect, ImGuiPipeline pipeline) {
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
RegisteredTexture tex{ true };
tex.framebuffer = framebuffer;
tex.aspect = aspect;
tex.pipeline = pipeline;
bd->tempTextures.push_back(tex);
return (ImTextureID)(uint64_t)(TEX_ID_OFFSET + bd->tempTextures.size() - 1);

View file

@ -34,28 +34,32 @@
#include "Common/Math/lin/matrix4x4.h"
// Called by user code. Takes ownership of the font buffer and later deletes it.
IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw, const uint8_t *ttf_font, size_t size);
IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown();
IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix);
IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw);
IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw, const uint8_t *ttf_font, size_t size);
IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown();
IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix);
IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw);
IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects();
enum class ImGuiPipeline {
TexturedAlphaBlend = 0,
TexturedOpaque = 1,
};
// 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);
IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, ImGuiPipeline pipeline = ImGuiPipeline::TexturedAlphaBlend);
IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect = Draw::FB_COLOR_BIT, ImGuiPipeline pipeline = ImGuiPipeline::TexturedAlphaBlend);
void ImGui_PushFixedFont();
void ImGui_PopFont();
// Helper structure to hold the data needed by one rendering context into one OS window
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
struct ImGui_ImplThin3dH_Window
{
int Width = 0;
int Height = 0;
bool ClearEnable = true;
struct ImGui_ImplThin3dH_Window {
int Width = 0;
int Height = 0;
bool ClearEnable = true;
};
#endif // #ifndef IMGUI_DISABLE