diff --git a/GPU/Common/IndexGenerator.cpp b/GPU/Common/IndexGenerator.cpp index e3ae7e1619..3e9cb10a37 100644 --- a/GPU/Common/IndexGenerator.cpp +++ b/GPU/Common/IndexGenerator.cpp @@ -193,6 +193,7 @@ void IndexGenerator::AddStrip(int numVerts, int indexOffset, bool clockwise) { #endif } +// God of War uses this for text. Otherwise rare, not much reason to optimize. void IndexGenerator::AddFan(int numVerts, int indexOffset, bool clockwise) { const int numTris = numVerts - 2; u16 *outInds = inds_; diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index aee9829fac..8111b8a4da 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -896,20 +896,30 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa u32 op = 0; DisplayList list; + bool isOnBlockTransfer = false; if (gpuDebug->GetCurrentDisplayList(list)) { op = Memory::Read_U32(list.pc); // TODO: Also add support for block transfer previews! - bool isOnPrim = (op >> 24) == GE_CMD_PRIM; - if (isOnPrim) { + bool isOnPrim = false; + switch (op >> 24) { + case GE_CMD_PRIM: + isOnPrim = true; if (reloadPreview_) { GetPrimPreview(op, previewPrim_, previewVertices_, previewIndices_, previewCount_); reloadPreview_ = false; } - } else { + break; + case GE_CMD_TRANSFERSTART: + isOnBlockTransfer = true; + break; + default: + // Disable the current preview. previewCount_ = 0; + break; } + } ImGui::BeginChild("texture/fb view"); // Leave room for 1 line below us @@ -917,125 +927,134 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa ImDrawList *drawList = ImGui::GetWindowDrawList(); if (coreState == CORE_STEPPING_GE) { - VirtualFramebuffer *vfb = rbViewer_.vfb; - if (vfb) { - if (vfb->fbo) { - ImGui::Text("Framebuffer: %s", vfb->fbo->Tag()); - } else { - ImGui::Text("Framebuffer"); + if (isOnBlockTransfer) { + ImGui::Text("Block transfer! Proper preview coming in the future.\n"); + ImGui::Text("%08x -> %08x, %d bpp (strides: %d, %d)", gstate.getTransferSrcAddress(), gstate.getTransferDstAddress(), gstate.getTransferBpp(), gstate.getTransferSrcStride(), gstate.getTransferDstStride()); + ImGui::Text("%dx%d pixels", gstate.getTransferWidth(), gstate.getTransferHeight()); + ImGui::Text("Src pos: %d, %d", gstate.getTransferSrcX(), gstate.getTransferSrcY()); + ImGui::Text("Dst pos: %d, %d", gstate.getTransferDstX(), gstate.getTransferDstY()); + ImGui::Text("Total bytes to transfer: %d", gstate.getTransferWidth() * gstate.getTransferHeight() * gstate.getTransferBpp()); + } else { + // Visualize prim by default (even if we're not directly on a prim instruction). + VirtualFramebuffer *vfb = rbViewer_.vfb; + if (vfb) { + if (vfb->fbo) { + ImGui::Text("Framebuffer: %s", vfb->fbo->Tag()); + } else { + ImGui::Text("Framebuffer"); + } } - } - // Use selectable instead of tab bar so we can get events (haven't figured that out). - static const Draw::Aspect aspects[3] = { Draw::Aspect::COLOR_BIT, Draw::Aspect::DEPTH_BIT, Draw::Aspect::STENCIL_BIT, }; - static const char *const aspectNames[3] = { "Color", "Depth", "Stencil" }; - for (int i = 0; i < ARRAY_SIZE(aspects); i++) { - if (i != 0) + // Use selectable instead of tab bar so we can get events (haven't figured that out). + static const Draw::Aspect aspects[3] = { Draw::Aspect::COLOR_BIT, Draw::Aspect::DEPTH_BIT, Draw::Aspect::STENCIL_BIT, }; + static const char *const aspectNames[3] = { "Color", "Depth", "Stencil" }; + for (int i = 0; i < ARRAY_SIZE(aspects); i++) { + if (i != 0) + ImGui::SameLine(); + if (ImGui::Selectable(aspectNames[i], aspects[i] == selectedAspect_, 0, ImVec2(120.0f, 0.0f))) { + selectedAspect_ = aspects[i]; + NotifyStep(); + } + } + + if (selectedAspect_ == Draw::Aspect::DEPTH_BIT) { + float minimum = 0.5f; + float maximum = 256.0f; ImGui::SameLine(); - if (ImGui::Selectable(aspectNames[i], aspects[i] == selectedAspect_, 0, ImVec2(120.0f, 0.0f))) { - selectedAspect_ = aspects[i]; - NotifyStep(); + ImGui::SetNextItemWidth(200.0f); + if (ImGui::DragFloat("Z scale", &rbViewer_.scale, 1.0f, 0.5f, 256.0f, "%0.2f", ImGuiSliderFlags_Logarithmic)) { + rbViewer_.Snapshot(); + swViewer_.Snapshot(); + } } - } - if (selectedAspect_ == Draw::Aspect::DEPTH_BIT) { - float minimum = 0.5f; - float maximum = 256.0f; - ImGui::SameLine(); - ImGui::SetNextItemWidth(200.0f); - if (ImGui::DragFloat("Z scale", &rbViewer_.scale, 1.0f, 0.5f, 256.0f, "%0.2f", ImGuiSliderFlags_Logarithmic)) { - rbViewer_.Snapshot(); - swViewer_.Snapshot(); - } - } - - const ImVec2 p0 = ImGui::GetCursorScreenPos(); - ImVec2 p1; - float scale = 1.0f; - if (vfb && vfb->fbo) { - scale = vfb->renderScaleFactor; - p1 = ImVec2(p0.x + vfb->fbo->Width(), p0.y + vfb->fbo->Height()); - } else { - // Guess - p1 = ImVec2(p0.x + swViewer_.width, p0.y + swViewer_.height); - } - - // Draw border and background color - drawList->PushClipRect(p0, p1, true); - - PixelLookup *lookup = nullptr; - if (vfb) { - rbViewer_.Draw(gpuDebug, draw); - lookup = &rbViewer_; - // ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(vfb->fbo, Draw::Aspect::COLOR_BIT, ImGuiPipeline::TexturedOpaque); - // ImGui::Image(texId, ImVec2(vfb->width, vfb->height)); - } else { - swViewer_.Draw(gpuDebug, draw); - lookup = &swViewer_; - } - - // Draw vertex preview on top! - DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewCount_, false, scale, scale); - - drawList->PopClipRect(); - - if (ImGui::IsItemHovered()) { - int x = (int)(ImGui::GetMousePos().x - p0.x); - int y = (int)(ImGui::GetMousePos().y - p0.y); - char temp[128]; - if (lookup->FormatValueAt(temp, sizeof(temp), x, y)) { - ImGui::Text("(%d, %d): %s", x, y, temp); + const ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1; + float scale = 1.0f; + if (vfb && vfb->fbo) { + scale = vfb->renderScaleFactor; + p1 = ImVec2(p0.x + vfb->fbo->Width(), p0.y + vfb->fbo->Height()); } else { - ImGui::Text("%d, %d: N/A"); + // Guess + p1 = ImVec2(p0.x + swViewer_.width, p0.y + swViewer_.height); } - } else { - ImGui::TextUnformatted("(no pixel hovered)"); - } - if (vfb && vfb->fbo) { - ImGui::Text("VFB %dx%d (emulated: %dx%d)", vfb->width, vfb->height, vfb->fbo->Width(), vfb->fbo->Height()); - } else { - // Use the swViewer_! - ImGui::Text("Raw FB: %08x (%s)", gstate.getFrameBufRawAddress(), GeBufferFormatToString(gstate.FrameBufFormat())); - } + // Draw border and background color + drawList->PushClipRect(p0, p1, true); - if (gstate.isModeClear()) { - ImGui::Text("(clear mode - texturing not used)"); - } else if (!gstate.isTextureMapEnabled()) { - ImGui::Text("(texturing not enabled"); - } else { - TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon(); - TexCacheEntry *tex = texcache ? texcache->SetTexture() : nullptr; - if (tex) { - ImGui::Text("Texture: "); - texcache->ApplyTexture(); - - void *nativeView = texcache->GetNativeTextureView(tex, true); - ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView); - - float texW = dimWidth(tex->dim); - float texH = dimHeight(tex->dim); - - const ImVec2 p0 = ImGui::GetCursorScreenPos(); - const ImVec2 sz = ImGui::GetContentRegionAvail(); - const ImVec2 p1 = ImVec2(p0.x + texW, p0.y + texH); - - // Draw border and background color - drawList->PushClipRect(p0, p1, true); - - ImGui::Image(texId, ImVec2(texW, texH)); - DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewCount_, true, texW, texH); - - drawList->PopClipRect(); + PixelLookup *lookup = nullptr; + if (vfb) { + rbViewer_.Draw(gpuDebug, draw); + lookup = &rbViewer_; + // ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(vfb->fbo, Draw::Aspect::COLOR_BIT, ImGuiPipeline::TexturedOpaque); + // ImGui::Image(texId, ImVec2(vfb->width, vfb->height)); } else { - ImGui::Text("(no valid texture bound)"); - // In software mode, we should just decode the texture here. - // TODO: List some of the texture params here. + swViewer_.Draw(gpuDebug, draw); + lookup = &swViewer_; } + + // Draw vertex preview on top! + DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewCount_, false, scale, scale); + + drawList->PopClipRect(); + + if (ImGui::IsItemHovered()) { + int x = (int)(ImGui::GetMousePos().x - p0.x); + int y = (int)(ImGui::GetMousePos().y - p0.y); + char temp[128]; + if (lookup->FormatValueAt(temp, sizeof(temp), x, y)) { + ImGui::Text("(%d, %d): %s", x, y, temp); + } else { + ImGui::Text("%d, %d: N/A"); + } + } else { + ImGui::TextUnformatted("(no pixel hovered)"); + } + + if (vfb && vfb->fbo) { + ImGui::Text("VFB %dx%d (emulated: %dx%d)", vfb->width, vfb->height, vfb->fbo->Width(), vfb->fbo->Height()); + } else { + // Use the swViewer_! + ImGui::Text("Raw FB: %08x (%s)", gstate.getFrameBufRawAddress(), GeBufferFormatToString(gstate.FrameBufFormat())); + } + + if (gstate.isModeClear()) { + ImGui::Text("(clear mode - texturing not used)"); + } else if (!gstate.isTextureMapEnabled()) { + ImGui::Text("(texturing not enabled"); + } else { + TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon(); + TexCacheEntry *tex = texcache ? texcache->SetTexture() : nullptr; + if (tex) { + ImGui::Text("Texture: "); + texcache->ApplyTexture(); + + void *nativeView = texcache->GetNativeTextureView(tex, true); + ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView); + + float texW = dimWidth(tex->dim); + float texH = dimHeight(tex->dim); + + const ImVec2 p0 = ImGui::GetCursorScreenPos(); + const ImVec2 sz = ImGui::GetContentRegionAvail(); + const ImVec2 p1 = ImVec2(p0.x + texW, p0.y + texH); + + // Draw border and background color + drawList->PushClipRect(p0, p1, true); + + ImGui::Image(texId, ImVec2(texW, texH)); + DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewCount_, true, texW, texH); + + drawList->PopClipRect(); + } else { + ImGui::Text("(no valid texture bound)"); + // In software mode, we should just decode the texture here. + // TODO: List some of the texture params here. + } + } + + // Let's display the current CLUT. } - - // Let's display the current CLUT. - } else { ImGui::Text("Click the buttons above (Tex, etc) to stop"); }