mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #19662 from hrydgard/more-im-debugger
ImDebugger: Add the ability to draw using multiple pipelines
This commit is contained in:
commit
c685373444
12 changed files with 237 additions and 125 deletions
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ struct ImConfig;
|
|||
class FramebufferManagerCommon;
|
||||
|
||||
void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
|
||||
void DrawDisplayWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
|
||||
|
||||
class ImGeDebugger {
|
||||
public:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue