diff --git a/qrenderdoc/Styles/RDStyle/RDStyle.cpp b/qrenderdoc/Styles/RDStyle/RDStyle.cpp index 15a652721e7..bed5ecf182c 100644 --- a/qrenderdoc/Styles/RDStyle/RDStyle.cpp +++ b/qrenderdoc/Styles/RDStyle/RDStyle.cpp @@ -470,6 +470,26 @@ QRect RDStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, return opt->rect; } + else if(cc == QStyle::CC_Slider) + { + QRect ret = opt->rect; + ret.adjust(4,1,-4,-1); + if(sc == QStyle::SC_SliderGroove) + { + int halfHeightLessMargin = ret.height() / 2 - 2; + ret.adjust(0, halfHeightLessMargin, 0, -halfHeightLessMargin); + } + else if(sc == QStyle::SC_SliderHandle) + { + ret.adjust(0, 2, 0, -2); + const QAbstractSlider *slider = qobject_cast(widget); + qreal posUNorm = (qreal)(slider->sliderPosition() - slider->minimum()) / (qreal)(slider->maximum() - slider->minimum()); + int sliderX = ret.left() + posUNorm * ret.width(); + ret.setLeft(sliderX - 3); + ret.setRight(sliderX + 3); + } + return ret; + } else if(cc == QStyle::CC_ComboBox) { QRect rect = opt->rect; @@ -1118,6 +1138,19 @@ void RDStyle::drawComplexControl(ComplexControl control, const QStyleOptionCompl return; } + else if(control == QStyle::CC_Slider) + { + QRect grooveRect = subControlRect(control, opt, QStyle::SC_SliderGroove, widget); + p->drawLine(QLine(grooveRect.x(), grooveRect.y() + grooveRect.height() / 2, + grooveRect.right(), grooveRect.y() + grooveRect.height() / 2)); + + QRect handleRect = subControlRect(control, opt, QStyle::SC_SliderHandle, widget); + QBrush sliderBrush = opt->palette.brush(QPalette::Dark); + p->setPen(QPen(sliderBrush, 2.5)); + p->drawRoundedRect(handleRect, 3.0, 3.0); + + return; + } else if(control == QStyle::CC_ComboBox) { const QStyleOptionComboBox *combo = qstyleoption_cast(opt); diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index c8db1a46e1d..7217a04f487 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -5789,6 +5789,20 @@ void BufferViewer::on_highlightVerts_toggled(bool checked) INVOKE_MEMFN(RT_UpdateAndDisplay); } +void BufferViewer::on_vtxExploderSlider_valueChanged(int value) +{ + m_Config.vtxExploderSliderSNorm = (float)value / 100.0f; + + INVOKE_MEMFN(RT_UpdateAndDisplay); +} + +void BufferViewer::on_vtxExploderSlider_sliderReleased() +{ + //Always snaps back to zero + QAbstractSlider *slider = ui->controlsToolbar->findChild(QStringLiteral("vtxExploderSlider")); + slider->setSliderPosition(0); +} + void BufferViewer::on_wireframeRender_toggled(bool checked) { m_Config.wireframeDraw = checked; diff --git a/qrenderdoc/Windows/BufferViewer.h b/qrenderdoc/Windows/BufferViewer.h index a4d3fd6223f..40db51f34eb 100644 --- a/qrenderdoc/Windows/BufferViewer.h +++ b/qrenderdoc/Windows/BufferViewer.h @@ -128,6 +128,8 @@ private slots: void on_showPadding_toggled(bool checked); void on_resourceDetails_clicked(); void on_highlightVerts_toggled(bool checked); + void on_vtxExploderSlider_valueChanged(int value); + void on_vtxExploderSlider_sliderReleased(); void on_wireframeRender_toggled(bool checked); void on_solidShading_currentIndexChanged(int index); void on_drawRange_currentIndexChanged(int index); diff --git a/qrenderdoc/Windows/BufferViewer.ui b/qrenderdoc/Windows/BufferViewer.ui index ff98a2c1e80..09294d62810 100644 --- a/qrenderdoc/Windows/BufferViewer.ui +++ b/qrenderdoc/Windows/BufferViewer.ui @@ -6,8 +6,8 @@ 0 0 - 788 - 537 + 1318 + 837 @@ -120,7 +120,7 @@ 50 220 - 666 + 866 312 @@ -382,6 +382,89 @@ + + + + + 0 + 0 + + + + Exploder + + + + + + + true + + + + 0 + 0 + + + + + 120 + 30 + + + + + 90 + 30 + + + + true + + + Qt::StrongFocus + + + Qt::NoContextMenu + + + Explode vertices + + + slider name + + + slider description + + + true + + + -100 + + + 100 + + + 0 + + + Qt::Horizontal + + + false + + + false + + + QSlider::NoTicks + + + 20 + + + diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index f55f66093e8..8f0f2a0a0e3 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -197,6 +197,8 @@ struct MeshDisplay SolidShade solidShadeMode = SolidShade::NoSolid; DOCUMENT("``True`` if the wireframe of the mesh should be rendered as well as solid shading."); bool wireframeDraw = true; + DOCUMENT("Displace/explode vertices to help visualise vertex reuse vs disjointedness."); + float vtxExploderSliderSNorm = 0.0f; static const uint32_t NoHighlight = ~0U; }; diff --git a/renderdoc/data/glsl/glsl_ubos.h b/renderdoc/data/glsl/glsl_ubos.h index f440decf75a..c76ddc1a8f8 100644 --- a/renderdoc/data/glsl/glsl_ubos.h +++ b/renderdoc/data/glsl/glsl_ubos.h @@ -40,7 +40,8 @@ BINDING(0) uniform MeshUBOData vec2 pointSpriteSize; uint rawoutput; uint flipY; - vec2 padding; + float vtxExploderSNorm; + float padding; } INST_NAME(Mesh); diff --git a/renderdoc/data/glsl/mesh.vert b/renderdoc/data/glsl/mesh.vert index 265547a184c..80b3c520330 100644 --- a/renderdoc/data/glsl/mesh.vert +++ b/renderdoc/data/glsl/mesh.vert @@ -36,6 +36,15 @@ #define SECONDARY_TYPE vec4 #endif +vec3 vtxExploder(vec3 pos, int vid) +{ + float nonLinearVtxExplodeScale = 8.0f * Mesh.vtxExploderSNorm * Mesh.vtxExploderSNorm * Mesh.vtxExploderSNorm; + vec3 explodeDir = normalize(pos); + + float displacement = nonLinearVtxExplodeScale * ((float((vid >> 1) & 0xf) / 15.0f) * 1.5f - 0.5f); + return pos + (explodeDir * displacement); +} + IO_LOCATION(0) in POSITION_TYPE vsin_position; IO_LOCATION(1) in SECONDARY_TYPE vsin_secondary; @@ -48,6 +57,7 @@ void main(void) vec2[](vec2(-1.0f, -1.0f), vec2(-1.0f, 1.0f), vec2(1.0f, -1.0f), vec2(1.0f, 1.0f)); vec4 pos = vec4(vsin_position); + pos.xyz = vtxExploder(pos.xyz, VERTEX_ID); if(Mesh.homogenousInput == 0u) { pos = vec4(pos.xyz, 1); diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index f6cf1d1136a..f7b0934ea39 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -108,6 +108,8 @@ cbuffer MeshVertexCBuffer REG(b0) float2 SpriteSize; uint homogenousInput; + + float vtxExploderSNorm; }; cbuffer MeshGeometryCBuffer REG(b0) diff --git a/renderdoc/data/hlsl/mesh.hlsl b/renderdoc/data/hlsl/mesh.hlsl index 75c6a093431..21acb306518 100644 --- a/renderdoc/data/hlsl/mesh.hlsl +++ b/renderdoc/data/hlsl/mesh.hlsl @@ -37,6 +37,15 @@ struct meshA2V float4 secondary : sec; }; +float3 vtxExploder(float3 pos, uint vid) +{ + float nonLinearVtxExplodeScale = 8.0f * vtxExploderSNorm * vtxExploderSNorm * vtxExploderSNorm; + float3 explodeDir = normalize(pos); + + float displacement = nonLinearVtxExplodeScale * ((float((vid >> 1u) & 0xfu) / 15.0f) * 1.5f - 0.5f); + return pos + (explodeDir * displacement); +} + meshV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) { meshV2F OUT = (meshV2F)0; @@ -45,6 +54,7 @@ meshV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) float2(1.0f, 1.0f)}; float4 pos = IN.pos; + pos.xyz = vtxExploder(pos.xyz, vid); if(homogenousInput == 0u) { diff --git a/renderdoc/driver/d3d11/d3d11_rendermesh.cpp b/renderdoc/driver/d3d11/d3d11_rendermesh.cpp index ddd2ef99fca..d6315f3e3dd 100644 --- a/renderdoc/driver/d3d11/d3d11_rendermesh.cpp +++ b/renderdoc/driver/d3d11/d3d11_rendermesh.cpp @@ -58,6 +58,7 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray &secon vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat)); vertexData.SpriteSize = Vec2f(); vertexData.homogenousInput = cfg.position.unproject; + vertexData.vtxExploderSNorm = cfg.vtxExploderSliderSNorm; Vec4f col(0.0f, 0.0f, 0.0f, 1.0f); ID3D11Buffer *psCBuf = GetDebugManager()->MakeCBuffer(&col, sizeof(col)); @@ -329,6 +330,7 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray &secon // set up state for drawing helpers { vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat)); + vertexData.vtxExploderSNorm = 0.0f; GetDebugManager()->FillCBuffer(vsCBuf, &vertexData, sizeof(vertexData)); m_pImmediateContext->RSSetState(m_MeshRender.SolidRasterState); diff --git a/renderdoc/driver/d3d12/d3d12_rendermesh.cpp b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp index ae76834450e..a361a575606 100644 --- a/renderdoc/driver/d3d12/d3d12_rendermesh.cpp +++ b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp @@ -275,6 +275,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat)); vertexData.SpriteSize = Vec2f(); vertexData.homogenousInput = cfg.position.unproject; + vertexData.vtxExploderSNorm = cfg.vtxExploderSliderSNorm; MeshPixelCBuffer pixelData; @@ -577,6 +578,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon pixelData.MeshDisplayFormat = MESHDISPLAY_SOLID; vertexData.homogenousInput = 0U; + vertexData.vtxExploderSNorm = 0.0f; vsCB = GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData)); diff --git a/renderdoc/driver/gl/gl_rendermesh.cpp b/renderdoc/driver/gl/gl_rendermesh.cpp index ed4efcb024a..4c757d81496 100644 --- a/renderdoc/driver/gl/gl_rendermesh.cpp +++ b/renderdoc/driver/gl/gl_rendermesh.cpp @@ -113,6 +113,7 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray &secondar uboParams.mvp = ModelViewProj; uboParams.homogenousInput = cfg.position.unproject; uboParams.pointSpriteSize = Vec2f(0.0f, 0.0f); + uboParams.vtxExploderSNorm = cfg.vtxExploderSliderSNorm; if(!secondaryDraws.empty()) { @@ -366,6 +367,7 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray &secondar soliddata->mvp = ModelViewProj; soliddata->pointSpriteSize = Vec2f(0.0f, 0.0f); soliddata->homogenousInput = cfg.position.unproject; + soliddata->vtxExploderSNorm = cfg.vtxExploderSliderSNorm; soliddata->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); @@ -469,6 +471,8 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray &secondar // helpers always use basic float-input program drv.glUseProgram(DebugData.meshProg[0]); + uboParams.vtxExploderSNorm = 0.0f; + if(cfg.showBBox) { Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index bb16fc0f099..cab5ccc7c80 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -2396,7 +2396,8 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D data->displayFormat = 0; data->rawoutput = 1; data->flipY = 0; - data->padding = Vec2f(); + data->vtxExploderSNorm = 0.0f; + data->padding = 0.0f; m_MeshRender.UBO.Unmap(); uint32_t viewOffs = 0; diff --git a/renderdoc/driver/vulkan/vk_rendermesh.cpp b/renderdoc/driver/vulkan/vk_rendermesh.cpp index b6cfd4bb9cb..ae53d78b41a 100644 --- a/renderdoc/driver/vulkan/vk_rendermesh.cpp +++ b/renderdoc/driver/vulkan/vk_rendermesh.cpp @@ -549,6 +549,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->displayFormat = MESHDISPLAY_SOLID; data->rawoutput = 0; data->flipY = (cfg.position.flipY == fmt.flipY) ? 0 : 1; + data->vtxExploderSNorm = cfg.vtxExploderSliderSNorm; m_MeshRender.UBO.Unmap(); @@ -722,6 +723,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->displayFormat = (uint32_t)solidShadeMode; data->rawoutput = 0; + data->vtxExploderSNorm = cfg.vtxExploderSliderSNorm; if(solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA; @@ -775,6 +777,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = cfg.position.unproject; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = cfg.vtxExploderSliderSNorm; m_MeshRender.UBO.Unmap(); @@ -869,6 +872,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = 0.0f; m_MeshRender.UBO.Unmap(); @@ -899,6 +903,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = 0.0f; m_MeshRender.UBO.Unmap(); @@ -922,6 +927,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = 0.0f; m_MeshRender.UBO.Unmap(); @@ -940,6 +946,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = 0.0f; m_MeshRender.UBO.Unmap(); @@ -966,6 +973,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->rawoutput = 0; + data->vtxExploderSNorm = 0.0f; m_MeshRender.UBO.Unmap(); @@ -1066,6 +1074,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray &seco uniforms.displayFormat = (uint32_t)SolidShade::Solid; uniforms.homogenousInput = cfg.position.unproject; uniforms.pointSpriteSize = Vec2f(0.0f, 0.0f); + uniforms.vtxExploderSNorm = 0.0f; uint32_t uboOffs = 0; MeshUBOData *ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);