Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesh exploder #3134

Merged
merged 1 commit into from
Dec 9, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/getting_started/quick_start.rst
Original file line number Diff line number Diff line change
@@ -184,7 +184,7 @@ More details can be found on the :doc:`../window/mesh_viewer` page.

Mesh Viewer allows you to inspect the geometry data as it passes through the pipeline. Both raw data in a grid view and 3D inspection is possible. The tabs in the preview window allow you to choose at which part of the pipeline you'd like to visualise the data.

By default the preview shows a wireframe rendering of the mesh, but you can choose solid shading options. This can either be simple shading or use a secondary attribute as color. Right clicking on any column allows you to choose the secondary attribute for rendering.
By default the preview shows a wireframe rendering of the mesh, but you can choose different visualisations. This can either be simple shading, a vertex exploder utility, or using a secondary attribute as color. Right clicking on any column allows you to choose the secondary attribute for rendering.

You can also select which attribute is the position, in case either the auto-detection failed or you want to visualise another attribute like texture co-ordinates in 3D space.

Binary file added docs/imgs/Screenshots/ExploderBadShoes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/imgs/Screenshots/ExploderGoodShoes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/python_api/renderdoc/outputs.rst
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ Mesh View
.. autoclass:: MeshFormat
:members:

.. autoclass:: SolidShade
.. autoclass:: Visualisation
:members:

.. autoclass:: Camera
11 changes: 10 additions & 1 deletion docs/window/mesh_viewer.rst
Original file line number Diff line number Diff line change
@@ -47,12 +47,21 @@ Page up and Page down will move vertically 'up' and 'down' relative to the camer
Mesh Preview
------------

In the 3D Mesh preview, you have the option to display the mesh with some solid shading modes, not just as a wireframe mesh. When solid shading you can toggle the wireframe on and off.
In the 3D Mesh preview, you have the option to display the mesh with some colored visualisations, not just as a wireframe mesh. When using one of the visualisations, you can toggle the wireframe on and off.

* Solid Color simply displays a solid color for each triangle.
* Flat Shaded will perform basic flat lighting calculations based on triangle normals to give a better idea of the topology of the mesh.
* Secondary will display the selected secondary mesh element.
* Meshlet is only relevant when using mesh shaders, and will colourise each meshlet with a different colour.
* Exploded will display a shaded mesh where vertex colors are a function of the vertex index (SV_VertexID or gl_VertexID). This means adjacent primitives that do not share the exact same vertices can be more easily seen by a hard break in coloring. Additionally, a slider allows displacing vertices along an explosion direction by an amount based on the vertex index, which also helps better visualise shared or disjoint vertices and can also help in visualising other mesh problems (e.g. hidden or duplicate vertices/primitives).

.. figure:: ../imgs/Screenshots/ExploderBadShoes.png

Exploded: Visualising a mesh with no vertex sharing.

.. figure:: ../imgs/Screenshots/ExploderGoodShoes.png

Exploded: Visualising a mesh with widely shared vertices.

To select which element will be displayed as secondary, simply right click on the column you would like to use. This can be done on the input and output separately, and 4-component columns have the option to either show RGB as color, or alpha as grayscale.

42 changes: 42 additions & 0 deletions qrenderdoc/Styles/RDStyle/RDStyle.cpp
Original file line number Diff line number Diff line change
@@ -37,6 +37,9 @@

namespace Constants
{
static const int SliderHandleHalfWidth = 4;
static const int SliderGrooveHeight = 4;

static const int ButtonMargin = 6;
static const int ButtonBorder = 1;

@@ -470,6 +473,32 @@ QRect RDStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,

return opt->rect;
}
else if(cc == QStyle::CC_Slider)
{
QRect ret = opt->rect;
ret.adjust(1, 1, -1, -1);
if(sc == QStyle::SC_SliderGroove)
{
int toGrooveHeightHalfReduction = (ret.height() - Constants::SliderGrooveHeight) / 2;
ret.adjust(Constants::SliderHandleHalfWidth, toGrooveHeightHalfReduction,
-Constants::SliderHandleHalfWidth, -toGrooveHeightHalfReduction);
}
else if(sc == QStyle::SC_SliderHandle)
{
const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(widget);
int sliderMin = slider->minimum();
int sliderMax = slider->maximum();
int sliderPos = slider->sliderPosition();
qreal posUNorm = (qreal)(sliderPos - sliderMin) / (qreal)(sliderMax - sliderMin);
int grooveLeft = ret.left() + Constants::SliderHandleHalfWidth;
int grooveRight = ret.right() - Constants::SliderHandleHalfWidth;
int grooveWidth = grooveRight - grooveLeft;
int sliderX = (int)(posUNorm * (qreal)grooveWidth) + grooveLeft;
ret.setLeft(sliderX - Constants::SliderHandleHalfWidth);
ret.setRight(sliderX + Constants::SliderHandleHalfWidth);
}
return ret;
}
else if(cc == QStyle::CC_ComboBox)
{
QRect rect = opt->rect;
@@ -1118,6 +1147,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 handleBrush = (m_Scheme == Light) ? opt->palette.brush(QPalette::Dark)
: opt->palette.brush(QPalette::Text);
p->fillRect(handleRect, handleBrush);

return;
}
else if(control == QStyle::CC_ComboBox)
{
const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
93 changes: 66 additions & 27 deletions qrenderdoc/Windows/BufferViewer.cpp
Original file line number Diff line number Diff line change
@@ -2402,6 +2402,7 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
memset(&m_Config, 0, sizeof(m_Config));
m_Config.type = MeshDataStage::VSIn;
m_Config.wireframeDraw = true;
m_Config.exploderScale = 1.0f;

ui->outputTabs->setCurrentIndex(0);
m_CurStage = MeshDataStage::VSIn;
@@ -2537,10 +2538,11 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)

configureDrawRange();

ui->solidShading->clear();
ui->solidShading->addItems({tr("None"), tr("Solid Colour"), tr("Flat Shaded"), tr("Secondary")});
ui->solidShading->adjustSize();
ui->solidShading->setCurrentIndex(0);
ui->visualisation->clear();
ui->visualisation->addItems(
{tr("None"), tr("Solid Colour"), tr("Flat Shaded"), tr("Secondary"), tr("Exploded")});
ui->visualisation->adjustSize();
ui->visualisation->setCurrentIndex(0);

ui->matrixType->addItems({tr("Perspective"), tr("Orthographic")});

@@ -2843,7 +2845,7 @@ void BufferViewer::SetupMeshView()
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setPosColumn(-1);
model->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
model->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary, false);

UI_ConfigureFormats();
on_resetCamera_clicked();
@@ -2863,8 +2865,8 @@ void BufferViewer::SetupMeshView()
QObject::connect(m_SelectSecondColumn, &QAction::triggered, [this]() {
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setSecondaryColumn(m_ContextColumn, m_Config.solidShadeMode == SolidShade::Secondary,
false);
model->setSecondaryColumn(m_ContextColumn,
m_Config.visualisationMode == Visualisation::Secondary, false);

UI_ConfigureFormats();
UpdateCurrentMeshConfig();
@@ -2873,8 +2875,8 @@ void BufferViewer::SetupMeshView()
QObject::connect(m_SelectSecondAlphaColumn, &QAction::triggered, [this]() {
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setSecondaryColumn(m_ContextColumn, m_Config.solidShadeMode == SolidShade::Secondary,
true);
model->setSecondaryColumn(m_ContextColumn,
m_Config.visualisationMode == Visualisation::Secondary, true);
UI_ConfigureFormats();
UpdateCurrentMeshConfig();
INVOKE_MEMFN(RT_UpdateAndDisplay);
@@ -3674,22 +3676,25 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
// similarly for secondary columns
if(m_ModelIn->secondaryColumn() == -1 ||
bufdata->highlightNames[1] != bufdata->inConfig.columnName(m_ModelIn->secondaryColumn()))
m_ModelIn->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelIn->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

// and as above for VS Out / GS Out
if(m_ModelOut1->posColumn() == -1 ||
bufdata->highlightNames[2] != bufdata->out1Config.columnName(m_ModelOut1->posColumn()))
m_ModelOut1->setPosColumn(-1);
if(m_ModelOut1->secondaryColumn() == -1 ||
bufdata->highlightNames[3] != bufdata->out1Config.columnName(m_ModelOut1->secondaryColumn()))
m_ModelOut1->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelOut1->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

if(m_ModelOut2->posColumn() == -1 ||
bufdata->highlightNames[4] != bufdata->out2Config.columnName(m_ModelOut2->posColumn()))
m_ModelOut2->setPosColumn(-1);
if(m_ModelOut2->secondaryColumn() == -1 ||
bufdata->highlightNames[5] != bufdata->out2Config.columnName(m_ModelOut2->secondaryColumn()))
m_ModelOut2->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelOut2->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

EnableCameraGuessControls();

@@ -5306,9 +5311,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(0, tr("Mesh Input"));
ui->outputTabs->setTabText(1, tr("Mesh Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) != tr("Meshlet"))
ui->solidShading->addItem(tr("Meshlet"));
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) != tr("Meshlet"))
ui->visualisation->addItem(tr("Meshlet"));
ui->visualisation->adjustSize();
}
else
{
@@ -5334,9 +5339,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(1, tr("VS Out"));
ui->outputTabs->setTabText(2, tr("GS/DS Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) == tr("Meshlet"))
ui->solidShading->removeItem(ui->solidShading->count() - 1);
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) == tr("Meshlet"))
ui->visualisation->removeItem(ui->visualisation->count() - 1);
ui->visualisation->adjustSize();
}
}
else
@@ -5363,9 +5368,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(1, tr("VS Out"));
ui->outputTabs->setTabText(2, tr("GS/DS Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) == tr("Meshlet"))
ui->solidShading->removeItem(ui->solidShading->count() - 1);
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) == tr("Meshlet"))
ui->visualisation->removeItem(ui->visualisation->count() - 1);
ui->visualisation->adjustSize();
}
}
else
@@ -6678,7 +6683,7 @@ void BufferViewer::UpdateHighlightVerts()
{
m_Config.highlightVert = ~0U;

if(!ui->highlightVerts->isChecked())
if(ui->highlightVerts->isHidden() || !ui->highlightVerts->isChecked())
return;

RDTableView *table = currentTable();
@@ -6777,14 +6782,33 @@ 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_exploderReset_clicked()
{
ui->vtxExploderSlider->setSliderPosition(0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I like this behaviour honestly, as it means if I want to examine a mesh while exploded from different angles it becomes a constant back and forth of dragging the slider, then moving the camera, then dragging it again. It's also just a bit weird for the program to revert something I did - it feels almost like a bug where the value is supposed to be read-only but it can be temporarily modified before snapping back. I'm not sure what your thoughts were or how strongly you thought this behaviour was desirable?

I think a reset-to-default button would be preferable. It could be just an icon'd tool button with a tooltip, although there is a slight snag in that the 'reset' icon is used earlier to reset the camera position to zero. We can probably find an appropriate alternative icon or just go with 'Reset' text.

I did notice the same thing as you - scrolling with the mouse wheel or clicking to the left or right of the handle will move it without it being 'released'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I quite like the auto-return behaviour but I'm wondering if there's a nice way to have both the auto-return and the normal slider behaviour, perhaps with a little 2-position radio knob: In one position, it always auto-returns-to-zero when released. In the other position, it stays put when released but you can reset it with a quick flick and return of the knob between positions... Although now I say that, I worry that'll make the U.I. a bit too tight/busy... and I don't look forward to having to wrangle Qt into dealing with and rendering such a widget. 😄

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went and added a slider reset button. Takes up a bit more space but I agree that it can help to be able to navigate around the mesh with it slightly exploded.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't dislike the auto-return behaviour necessarily and it can be useful sometimes, but I'm not sure the value is justified by the cost of keeping it implemented and having this atypical behaviour. As I think you've come around to as well it's not really feasible to provide both mechanisms. It ends up either being overcomplicated if there's an explicit UI control, or too hidden and confusing if there's some kind of shortcut like holding shift while dragging to make it temporary. Someone could do that by accident and get really lost.

My intuition is that you really have to pick one way and stick to it, and although it's occasionally nice to have it return I don't see a sufficient benefit. I'd be fine if you wanted to maybe add a shortcut key for escape to reset while the slider is focussed - which it should be immediately after interacting with it. It's not discoverable and isn't quite fully automatic but it is at least something.

}

void BufferViewer::on_exploderScale_valueChanged(double value)
{
m_Config.exploderScale = (float)value;

INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_wireframeRender_toggled(bool checked)
{
m_Config.wireframeDraw = checked;

INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_solidShading_currentIndexChanged(int index)
void BufferViewer::on_visualisation_currentIndexChanged(int index)
{
ui->wireframeRender->setEnabled(index > 0);

@@ -6794,16 +6818,31 @@ void BufferViewer::on_solidShading_currentIndexChanged(int index)
m_Config.wireframeDraw = true;
}

m_Config.solidShadeMode = (SolidShade)qMax(0, index);
bool explodeHidden = (index != (int)Visualisation::Explode);
ui->vtxExploderLabel->setHidden(explodeHidden);
ui->vtxExploderSlider->setHidden(explodeHidden);
ui->exploderReset->setHidden(explodeHidden);
ui->exploderScaleLabel->setHidden(explodeHidden);
ui->exploderScale->setHidden(explodeHidden);
// Because the vertex/prim highlights draw from a new, temporary vertex buffer,
// those vertex IDs (which determine the explode displacement) won't necessarily
// match the original mesh's IDs and exploded vertices. Because of this, it seems
// cleanest to just avoid drawing the highlighted vert/prim with the explode
// visualisation (while also getting back a little room on the toolbar used by
// the extra exploder controls).
ui->highlightVerts->setHidden(!explodeHidden);
UpdateHighlightVerts();

m_Config.visualisationMode = (Visualisation)qMax(0, index);

m_ModelIn->setSecondaryColumn(m_ModelIn->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelIn->secondaryAlpha());
m_ModelOut1->setSecondaryColumn(m_ModelOut1->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelOut1->secondaryAlpha());
m_ModelOut2->setSecondaryColumn(m_ModelOut2->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelOut2->secondaryAlpha());

INVOKE_MEMFN(RT_UpdateAndDisplay);
5 changes: 4 additions & 1 deletion qrenderdoc/Windows/BufferViewer.h
Original file line number Diff line number Diff line change
@@ -128,8 +128,11 @@ 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_exploderReset_clicked();
void on_exploderScale_valueChanged(double value);
void on_wireframeRender_toggled(bool checked);
void on_solidShading_currentIndexChanged(int index);
void on_visualisation_currentIndexChanged(int index);
void on_drawRange_currentIndexChanged(int index);
void on_controlType_currentIndexChanged(int index);
void on_camSpeed_valueChanged(double value);
135 changes: 130 additions & 5 deletions qrenderdoc/Windows/BufferViewer.ui
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>788</width>
<height>537</height>
<width>1300</width>
<height>837</height>
</rect>
</property>
<property name="windowTitle">
@@ -307,14 +307,14 @@
</widget>
</item>
<item>
<widget class="QLabel" name="solidShadingLabel">
<widget class="QLabel" name="visualisationLabel">
<property name="text">
<string>Solid Shading</string>
<string>Visualisation</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="solidShading"/>
<widget class="QComboBox" name="visualisation"/>
</item>
<item>
<widget class="QToolButton" name="wireframeRender">
@@ -382,6 +382,131 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="vtxExploderLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Exploder</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="vtxExploderSlider">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>90</width>
<height>30</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="toolTip">
<string>Explode vertices</string>
</property>
<property name="accessibleName">
<string>slider name</string>
</property>
<property name="accessibleDescription">
<string>slider description</string>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exploderReset">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Reset/zero exploder slider</string>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="exploderScaleLabel">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="exploderScale">
<property name="toolTip">
<string>Exploder scaling</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
9 changes: 7 additions & 2 deletions renderdoc/api/replay/control_types.h
Original file line number Diff line number Diff line change
@@ -309,10 +309,15 @@ struct MeshDisplay
DOCUMENT("``True`` if the bounding box around the mesh should be rendered.");
bool showBBox = false;

DOCUMENT("The :class:`solid shading mode <SolidShade>` to use when rendering the current mesh.");
SolidShade solidShadeMode = SolidShade::NoSolid;
DOCUMENT(
"The :class:`visualisation mode <Visualisation>` to use when rendering the current mesh.");
Visualisation visualisationMode = Visualisation::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;
DOCUMENT("Scales the exploded vertex displacement.");
float exploderScale = 1.0f;

static const uint32_t NoHighlight = ~0U;
};
11 changes: 8 additions & 3 deletions renderdoc/api/replay/replay_enums.h
Original file line number Diff line number Diff line change
@@ -2895,7 +2895,7 @@ constexpr inline ResourceUsage RWResUsage(ShaderStage stage)
return RWResUsage(uint32_t(stage));
}

DOCUMENT(R"(What kind of solid shading to use when rendering a mesh.
DOCUMENT(R"(What kind of visualisation to use when rendering a mesh.
.. data:: NoSolid
@@ -2913,22 +2913,27 @@ DOCUMENT(R"(What kind of solid shading to use when rendering a mesh.
The mesh should be rendered using the secondary element as color.
.. data:: Explode
The mesh should be rendered with vertices displaced and coloured by vertex ID.
.. data:: Meshlet
The mesh should be rendered colorising each meshlet differently.
)");
enum class SolidShade : uint32_t
enum class Visualisation : uint32_t
{
NoSolid = 0,
Solid,
Lit,
Secondary,
Explode,
Meshlet,
Count,
};

DECLARE_REFLECTION_ENUM(SolidShade);
DECLARE_REFLECTION_ENUM(Visualisation);

DOCUMENT(R"(The fill mode for polygons.
7 changes: 4 additions & 3 deletions renderdoc/data/glsl/glsl_globals.h
Original file line number Diff line number Diff line change
@@ -172,14 +172,15 @@ vec3 CalcCubeCoord(vec2 uv, int face)

#endif

// first few match SolidShade enum
// first few match Visualisation enum
#define MESHDISPLAY_SOLID 0x1
#define MESHDISPLAY_FACELIT 0x2
#define MESHDISPLAY_SECONDARY 0x3
#define MESHDISPLAY_MESHLET 0x4
#define MESHDISPLAY_EXPLODE 0x4
#define MESHDISPLAY_MESHLET 0x5

// extra values below
#define MESHDISPLAY_SECONDARY_ALPHA 0x5
#define MESHDISPLAY_SECONDARY_ALPHA 0x6

#define MAX_NUM_MESHLETS (512 * 1024)

9 changes: 8 additions & 1 deletion renderdoc/data/glsl/glsl_ubos.h
Original file line number Diff line number Diff line change
@@ -35,12 +35,19 @@ BINDING(0) uniform MeshUBOData
mat4 mvp;
mat4 invProj;
vec4 color;

int displayFormat;
uint homogenousInput;
vec2 pointSpriteSize;

uint rawoutput;
uint flipY;
vec2 padding;
float vtxExploderSNorm;
float exploderScale;

vec3 exploderCentre;
float padding;

uvec4 meshletColours[12];
}
INST_NAME(Mesh);
6 changes: 6 additions & 0 deletions renderdoc/data/glsl/mesh.frag
Original file line number Diff line number Diff line change
@@ -60,6 +60,12 @@ void main(void)

color_out = vec4(Mesh.color.xyz * abs(dot(lightDir, NORM_NAME.xyz)), 1);
}
else if(type == MESHDISPLAY_EXPLODE)
{
vec3 lightDir = normalize(vec3(0, -0.3f, -1));

color_out = vec4(SECONDARY_NAME.xyz * abs(dot(lightDir, NORM_NAME.xyz)), 1);
}
else // if(type == MESHDISPLAY_SOLID)
{
color_out = vec4(Mesh.color.xyz, 1);
69 changes: 68 additions & 1 deletion renderdoc/data/glsl/mesh.vert
Original file line number Diff line number Diff line change
@@ -36,6 +36,70 @@
#define SECONDARY_TYPE vec4
#endif

// This function is mostly duplicated between 'mesh.hlsl' and 'mesh.vert'.
// Without a convenient shared common source, changes to one should be
// reflected in the other.
void vtxExploder(in int vtxID, inout vec3 pos, inout vec3 secondary)
{
if(Mesh.exploderScale > 0.0f)
{
float nonLinearVtxExplodeScale = 4.0f * Mesh.exploderScale * Mesh.vtxExploderSNorm *
Mesh.vtxExploderSNorm * Mesh.vtxExploderSNorm;

// A vertex might be coincident with our 'exploderCentre' so that, when normalized,
// can give us INFs/NaNs that, even if multiplied by a zero 'exploderScale', can
// leave us with bad numbers (as seems to be the case with glsl/vulkan, but not hlsl).
// Still, we should make this case safe for when we have a non-zero 'exploderScale' -
vec3 offset = pos - Mesh.exploderCentre;
float offsetDistSquared = dot(offset, offset);
vec3 safeExplodeDir = offset * inversesqrt(max(offsetDistSquared, FLT_EPSILON));

float displacement =
nonLinearVtxExplodeScale * ((float((vtxID >> 1) & 0xf) / 15.0f) * 1.5f - 0.5f);
pos += (safeExplodeDir * displacement);

// For the exploder visualisation, colour verts based on vertex ID, which we
// store in secondary.
//
// Interpolate a colour gradient from 0.0 to 1.0 and back to 0.0 for vertex IDs
// 0 to 16 to 32 respectively -
// 1 - | .`.
// | .` `.
// | .` | `.
// 0.5-| .` `.
// | .` | `. .
// |.` `. .`
// 0.0-+-----------+-----------+--- vtx IDs
// 0 16 32

float vtxIDMod32Div16 = float(vtxID % 32) / 16.0f; // 0: 0.0 16: 1.0 31: 1.94
float descending = floor(vtxIDMod32Div16); // 0..15: 0.0 16..31: 1.0
float gradientVal = abs(vtxIDMod32Div16 - (2.0f * descending)); // 0.0..1.0

// Use a hopefully fairly intuitive temperature gradient scheme to help visualise
// contiguous/nearby sequences of vertices, which should also show up breaks in
// colour where verts aren't shared between adjacent primitives.
const vec3 gradientColours[5] =
vec3[](vec3(0.004f, 0.002f, 0.025f), // 0.0..0.25: Dark blue
vec3(0.305f, 0.001f, 0.337f), // 0.25..0.5: Purple
vec3(0.665f, 0.033f, 0.133f), // 0.5..0.75: Purple orange
vec3(1.000f, 0.468f, 0.000f), // 0.75..1.0: Orange
vec3(1.000f, 1.000f, 1.000f) // 1.0: White
);

uint gradientSectionStartIdx = uint(gradientVal * 4.0f);
uint gradientSectionEndIdx = min(gradientSectionStartIdx + 1u, 4u);
vec3 gradSectionStartCol = gradientColours[gradientSectionStartIdx];
vec3 gradSectionEndCol = gradientColours[gradientSectionEndIdx];

float sectionLerp = gradientVal - float(gradientSectionStartIdx) * 0.25f;
vec3 gradCol = mix(gradientColours[gradientSectionStartIdx],
gradientColours[gradientSectionEndIdx], sectionLerp);

secondary = gradCol;
}
}

IO_LOCATION(0) in POSITION_TYPE vsin_position;
IO_LOCATION(1) in SECONDARY_TYPE vsin_secondary;

@@ -111,6 +175,9 @@ 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);
vec4 secondary = vec4(vsin_secondary);
vtxExploder(VERTEX_ID, pos.xyz, secondary.xyz);

if(Mesh.homogenousInput == 0u)
{
pos = vec4(pos.xyz, 1);
@@ -124,7 +191,7 @@ void main(void)

gl_Position = Mesh.mvp * pos;
gl_Position.xy += Mesh.pointSpriteSize.xy * 0.01f * psprite[VERTEX_ID % 4] * gl_Position.w;
vsout_secondary = vec4(vsin_secondary);
vsout_secondary = vec4(secondary);
vsout_norm = vec4(0, 0, 1, 1);

#ifdef VULKAN
14 changes: 9 additions & 5 deletions renderdoc/data/hlsl/hlsl_cbuffers.h
Original file line number Diff line number Diff line change
@@ -107,12 +107,15 @@ cbuffer MeshVertexCBuffer REG(b0)

float2 SpriteSize;
uint homogenousInput;
uint vertMeshDisplayFormat;
float vtxExploderSNorm;

float3 exploderCentre;
float exploderScale; // Non-zero values imply use of the exploder visualisation.

uint vertMeshDisplayFormat;
uint meshletOffset;
uint meshletCount;
uint padding1;
uint padding2;

uint4 meshletColours[12];
};
@@ -250,14 +253,15 @@ cbuffer DebugSampleOperation REG(b0)
#define RESTYPE_DEPTH_STENCIL_MS 0x7
#define RESTYPE_TEX2D_MS 0x9

// first few match SolidShade enum
// first few match Visualisation enum
#define MESHDISPLAY_SOLID 0x1
#define MESHDISPLAY_FACELIT 0x2
#define MESHDISPLAY_SECONDARY 0x3
#define MESHDISPLAY_MESHLET 0x4
#define MESHDISPLAY_EXPLODE 0x4
#define MESHDISPLAY_MESHLET 0x5

// extra values below
#define MESHDISPLAY_SECONDARY_ALPHA 0x5
#define MESHDISPLAY_SECONDARY_ALPHA 0x6

#define MAX_NUM_MESHLETS (512 * 1024)

71 changes: 71 additions & 0 deletions renderdoc/data/hlsl/mesh.hlsl
Original file line number Diff line number Diff line change
@@ -37,6 +37,70 @@ struct meshA2V
float4 secondary : sec;
};

// This function is mostly duplicated between 'mesh.hlsl' and 'mesh.vert'.
// Without a convenient shared common source, changes to one should be
// reflected in the other.
void vtxExploder(in uint vtxID, inout float3 pos, inout float3 secondary)
{
if(exploderScale > 0.0f)
{
float nonLinearVtxExplodeScale =
4.0f * exploderScale * vtxExploderSNorm * vtxExploderSNorm * vtxExploderSNorm;

// A vertex might be coincident with our 'exploderCentre' so that, when normalized,
// can give us INFs/NaNs that, even if multiplied by a zero 'exploderScale', can
// leave us with bad numbers (as seems to be the case with glsl/vulkan, but not hlsl).
// Still, we should make this case safe for when we have a non-zero 'exploderScale' -
float3 offset = pos - exploderCentre;
float offsetDistSquared = dot(offset, offset);
float3 safeExplodeDir = offset * rsqrt(max(offsetDistSquared, FLT_EPSILON));

float displacement =
nonLinearVtxExplodeScale * ((float((vtxID >> 1u) & 0xfu) / 15.0f) * 1.5f - 0.5f);
pos += (safeExplodeDir * displacement);

// For the exploder visualisation, colour verts based on vertex ID, which we
// store in secondary.
//
// Interpolate a colour gradient from 0.0 to 1.0 and back to 0.0 for vertex IDs
// 0 to 16 to 32 respectively -
// 1 - | .`.
// | .` `.
// | .` | `.
// 0.5-| .` `.
// | .` | `. .
// |.` `. .`
// 0.0-+-----------+-----------+--- vtx IDs
// 0 16 32

float vtxIDMod32Div16 = (float)(vtxID % 32u) / 16.0f; // 0: 0.0 16: 1.0 31: 1.94
float descending = floor(vtxIDMod32Div16); // 0..15: 0.0 16..31: 1.0
float gradientVal = abs(vtxIDMod32Div16 - (2.0f * descending)); // 0.0..1.0

// Use a hopefully fairly intuitive temperature gradient scheme to help visualise
// contiguous/nearby sequences of vertices, which should also show up breaks in
// colour where verts aren't shared between adjacent primitives.
const float3 gradientColours[5] = {
float3(0.004f, 0.002f, 0.025f), // 0.0..0.25: Dark blue
float3(0.305f, 0.001f, 0.337f), // 0.25..0.5: Purple
float3(0.665f, 0.033f, 0.133f), // 0.5..0.75: Purple orange
float3(1.000f, 0.468f, 0.000f), // 0.75..1.0: Orange
float3(1.000f, 1.000f, 1.000f) // 1.0: White
};

uint gradientSectionStartIdx = (uint)(gradientVal * 4.0f);
uint gradientSectionEndIdx = min(gradientSectionStartIdx + 1u, 4u);
float3 gradSectionStartCol = gradientColours[gradientSectionStartIdx];
float3 gradSectionEndCol = gradientColours[gradientSectionEndIdx];

float sectionLerp = gradientVal - (float)gradientSectionStartIdx * 0.25f;
float3 gradCol = lerp(gradientColours[gradientSectionStartIdx],
gradientColours[gradientSectionEndIdx], sectionLerp);

secondary = gradCol;
}
}

StructuredBuffer<uint4> meshletSizesBuf : register(t0);

float4 unpackUnorm4x8(uint value)
@@ -118,6 +182,7 @@ meshV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID)
float2(1.0f, 1.0f)};

float4 pos = IN.pos;
vtxExploder(vid, pos.xyz, IN.secondary.xyz);

if(homogenousInput == 0u)
{
@@ -214,6 +279,12 @@ float4 RENDERDOC_MeshPS(meshV2F IN)

return float4(MeshColour.xyz * abs(dot(lightDir, IN.norm)), 1);
}
else if(type == MESHDISPLAY_EXPLODE)
{
float3 lightDir = normalize(float3(0, -0.3f, -1));

return float4(IN.secondary.xyz * abs(dot(lightDir, IN.norm)), 1);
}
else // if(type == MESHDISPLAY_SOLID)
return float4(MeshColour.xyz, 1);
}
42 changes: 29 additions & 13 deletions renderdoc/driver/d3d11/d3d11_rendermesh.cpp
Original file line number Diff line number Diff line change
@@ -33,6 +33,19 @@

#include "data/hlsl/hlsl_cbuffers.h"

static uint32_t VisModeToMeshDisplayFormat(const MeshDisplay &cfg)
{
switch(cfg.visualisationMode)
{
default: return (uint32_t)cfg.visualisationMode;
case Visualisation::Secondary:
return cfg.second.showAlpha ? MESHDISPLAY_SECONDARY_ALPHA : MESHDISPLAY_SECONDARY;
case Visualisation::Meshlet:
RDCERR("D3D11 does not support meshlet rendering");
return MESHDISPLAY_SOLID;
}
}

void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondaryDraws,
const MeshDisplay &cfg)
{
@@ -58,6 +71,12 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat));
vertexData.SpriteSize = Vec2f();
vertexData.homogenousInput = cfg.position.unproject;
vertexData.vtxExploderSNorm = cfg.vtxExploderSliderSNorm;
vertexData.exploderCentre =
Vec3f((cfg.minBounds.x + cfg.maxBounds.x) * 0.5f, (cfg.minBounds.y + cfg.maxBounds.y) * 0.5f,
(cfg.minBounds.z + cfg.maxBounds.z) * 0.5f);
vertexData.exploderScale =
(cfg.visualisationMode == Visualisation::Explode) ? cfg.exploderScale : 0.0f;

Vec4f col(0.0f, 0.0f, 0.0f, 1.0f);
ID3D11Buffer *psCBuf = GetDebugManager()->MakeCBuffer(&col, sizeof(col));
@@ -260,27 +279,21 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
m_pImmediateContext->IASetIndexBuffer(NULL, DXGI_FORMAT_UNKNOWN, NULL);

// draw solid shaded mode
if(cfg.solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList_1CPs)
if(cfg.visualisationMode != Visualisation::NoSolid &&
cfg.position.topology < Topology::PatchList_1CPs)
{
m_pImmediateContext->RSSetState(m_General.RasterState);

m_pImmediateContext->IASetPrimitiveTopology(topo);

pixelData.MeshDisplayFormat = (int)cfg.solidShadeMode;
if(cfg.solidShadeMode == SolidShade::Meshlet)
{
RDCERR("D3D11 does not support mesh rendering");
pixelData.MeshDisplayFormat = (int)SolidShade::Solid;
}

if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
pixelData.MeshDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA;
pixelData.MeshDisplayFormat = VisModeToMeshDisplayFormat(cfg);

pixelData.MeshColour = Vec3f(0.8f, 0.8f, 0.0f);
GetDebugManager()->FillCBuffer(psCBuf, &pixelData, sizeof(pixelData));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &psCBuf);

if(cfg.solidShadeMode == SolidShade::Lit)
if(cfg.visualisationMode == Visualisation::Lit ||
cfg.visualisationMode == Visualisation::Explode)
{
MeshGeometryCBuffer geomData;

@@ -298,12 +311,13 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
else
m_pImmediateContext->Draw(cfg.position.numIndices, 0);

if(cfg.solidShadeMode == SolidShade::Lit)
if(cfg.visualisationMode == Visualisation::Lit ||
cfg.visualisationMode == Visualisation::Explode)
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
}

// draw wireframe mode
if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw ||
if(cfg.visualisationMode == Visualisation::NoSolid || cfg.wireframeDraw ||
cfg.position.topology >= Topology::PatchList_1CPs)
{
m_pImmediateContext->RSSetState(m_MeshRender.WireframeRasterState);
@@ -335,6 +349,8 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
// set up state for drawing helpers
{
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat));
vertexData.vtxExploderSNorm = 0.0f;
vertexData.exploderScale = 0.0f;
GetDebugManager()->FillCBuffer(vsCBuf, &vertexData, sizeof(vertexData));

m_pImmediateContext->RSSetState(m_MeshRender.SolidRasterState);
58 changes: 40 additions & 18 deletions renderdoc/driver/d3d12/d3d12_rendermesh.cpp
Original file line number Diff line number Diff line change
@@ -38,6 +38,16 @@

RDOC_EXTERN_CONFIG(bool, D3D12_Debug_SingleSubmitFlushing);

static uint32_t VisModeToMeshDisplayFormat(const MeshDisplay &cfg)
{
switch(cfg.visualisationMode)
{
default: return (uint32_t)cfg.visualisationMode;
case Visualisation::Secondary:
return cfg.second.showAlpha ? MESHDISPLAY_SECONDARY_ALPHA : MESHDISPLAY_SECONDARY;
}
}

MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines(const MeshFormat &primary,
const MeshFormat &secondary)
{
@@ -93,7 +103,7 @@ MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines(const MeshForm

MeshDisplayPipelines &cache = m_CachedMeshPipelines[key];

if(cache.pipes[(uint32_t)SolidShade::NoSolid] != NULL)
if(cache.pipes[(uint32_t)Visualisation::NoSolid] != NULL)
return cache;

cache.rootsig = m_MeshRootSig;
@@ -276,6 +286,12 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat));
vertexData.SpriteSize = Vec2f();
vertexData.homogenousInput = cfg.position.unproject;
vertexData.vtxExploderSNorm = cfg.vtxExploderSliderSNorm;
vertexData.exploderCentre =
Vec3f((cfg.minBounds.x + cfg.maxBounds.x) * 0.5f, (cfg.minBounds.y + cfg.maxBounds.y) * 0.5f,
(cfg.minBounds.z + cfg.maxBounds.z) * 0.5f);
vertexData.exploderScale =
(cfg.visualisationMode == Visualisation::Explode) ? cfg.exploderScale : 0.0f;
vertexData.vertMeshDisplayFormat = MESHDISPLAY_SOLID;

MeshPixelCBuffer pixelData;
@@ -425,13 +441,13 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
}

SolidShade solidShadeMode = cfg.solidShadeMode;

// can't support secondary shading without a buffer - no pipeline will have been created
if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId())
solidShadeMode = SolidShade::NoSolid;
const Visualisation finalVisualisation = (cfg.visualisationMode == Visualisation::Secondary &&
cfg.second.vertexResourceId == ResourceId())
? Visualisation::NoSolid
: cfg.visualisationMode;

if(solidShadeMode == SolidShade::Secondary)
if(finalVisualisation == Visualisation::Secondary)
{
D3D12MarkerRegion::Set(list, "Secondary");

@@ -454,36 +470,40 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
}

// solid render
if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList)
if(finalVisualisation != Visualisation::NoSolid && cfg.position.topology < Topology::PatchList)
{
D3D12MarkerRegion region(list, "Solid render");

ID3D12PipelineState *pipe = NULL;
switch(solidShadeMode)
switch(finalVisualisation)
{
default:
case SolidShade::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break;
case SolidShade::Lit:
case Visualisation::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break;
case Visualisation::Lit:
case Visualisation::Explode:
pipe = cache.pipes[MeshDisplayPipelines::ePipe_Lit];
// point list topologies don't have lighting obvious, just render them as solid
if(!pipe)
pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth];
break;
case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break;
case SolidShade::Meshlet: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break;
case Visualisation::Secondary:
pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary];
break;
case Visualisation::Meshlet:
pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth];
break;
}

pixelData.MeshDisplayFormat = (int)cfg.solidShadeMode;
if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
pixelData.MeshDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA;
pixelData.MeshDisplayFormat = VisModeToMeshDisplayFormat(cfg);

pixelData.MeshColour = Vec3f(0.8f, 0.8f, 0.0f);

list->SetPipelineState(pipe);
list->SetGraphicsRootSignature(cache.rootsig);

size_t numMeshlets = RDCMIN(cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);

if(cfg.solidShadeMode == SolidShade::Meshlet)
if(finalVisualisation == Visualisation::Meshlet)
{
vertexData.meshletCount = (uint32_t)numMeshlets;
vertexData.meshletOffset = (uint32_t)cfg.position.meshletOffset;
@@ -496,7 +516,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon

list->SetGraphicsRootConstantBufferView(0, vsCBSolid);

if(solidShadeMode == SolidShade::Lit)
if(finalVisualisation == Visualisation::Lit || finalVisualisation == Visualisation::Explode)
{
MeshGeometryCBuffer geomData;
geomData.InvProj = projMat.Inverse();
@@ -540,7 +560,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
}

// wireframe render
if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw ||
if(finalVisualisation == Visualisation::NoSolid || cfg.wireframeDraw ||
cfg.position.topology >= Topology::PatchList)
{
D3D12MarkerRegion region(list, "Wireframe render");
@@ -603,6 +623,8 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
pixelData.MeshDisplayFormat = MESHDISPLAY_SOLID;

vertexData.homogenousInput = 0U;
vertexData.vtxExploderSNorm = 0.0f;
vertexData.exploderScale = 0.0f;

vsCB = GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData));

47 changes: 31 additions & 16 deletions renderdoc/driver/gl/gl_rendermesh.cpp
Original file line number Diff line number Diff line change
@@ -33,6 +33,16 @@
#define OPENGL 1
#include "data/glsl/glsl_ubos_cpp.h"

static int VisModeToMeshDisplayFormat(const MeshDisplay &cfg)
{
switch(cfg.visualisationMode)
{
default: return (int)cfg.visualisationMode;
case Visualisation::Secondary:
return cfg.second.showAlpha ? MESHDISPLAY_SECONDARY_ALPHA : MESHDISPLAY_SECONDARY;
}
}

void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondaryDraws,
const MeshDisplay &cfg)
{
@@ -113,6 +123,12 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondar
uboParams.mvp = ModelViewProj;
uboParams.homogenousInput = cfg.position.unproject;
uboParams.pointSpriteSize = Vec2f(0.0f, 0.0f);
uboParams.vtxExploderSNorm = cfg.vtxExploderSliderSNorm;
uboParams.exploderScale =
(cfg.visualisationMode == Visualisation::Explode) ? cfg.exploderScale : 0.0f;
uboParams.exploderCentre =
Vec3f((cfg.minBounds.x + cfg.maxBounds.x) * 0.5f, (cfg.minBounds.y + cfg.maxBounds.y) * 0.5f,
(cfg.minBounds.z + cfg.maxBounds.z) * 0.5f);

if(!secondaryDraws.empty())
{
@@ -333,13 +349,15 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondar
drv.glEnable(eGL_DEPTH_TEST);

// solid render
if(cfg.solidShadeMode != SolidShade::NoSolid && topo != eGL_PATCHES)
if(cfg.visualisationMode != Visualisation::NoSolid && topo != eGL_PATCHES)
{
drv.glDepthFunc(eGL_LESS);

GLuint solidProg = prog;

if(cfg.solidShadeMode == SolidShade::Lit && DebugData.meshgsProg[0])
if((cfg.visualisationMode == Visualisation::Lit ||
cfg.visualisationMode == Visualisation::Explode) &&
DebugData.meshgsProg[0])
{
// pick program with GS for per-face lighting
solidProg = DebugData.meshgsProg[progidx];
@@ -363,18 +381,11 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondar
return;
}

soliddata->mvp = ModelViewProj;
soliddata->pointSpriteSize = Vec2f(0.0f, 0.0f);
soliddata->homogenousInput = cfg.position.unproject;

soliddata->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f);
uboParams.color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f);
uboParams.displayFormat = VisModeToMeshDisplayFormat(cfg);
*soliddata = uboParams;

uint32_t OutputDisplayFormat = (uint32_t)cfg.solidShadeMode;
if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA;
soliddata->displayFormat = OutputDisplayFormat;

if(cfg.solidShadeMode == SolidShade::Lit)
if(cfg.visualisationMode == Visualisation::Lit || cfg.visualisationMode == Visualisation::Explode)
soliddata->invProj = projMat.Inverse();

drv.glUnmapBuffer(eGL_UNIFORM_BUFFER);
@@ -417,14 +428,14 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondar

drv.glDepthFunc(eGL_ALWAYS);

uboParams.displayFormat = MESHDISPLAY_SOLID;

// wireframe render
if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || topo == eGL_PATCHES)
if(cfg.visualisationMode == Visualisation::NoSolid || cfg.wireframeDraw || topo == eGL_PATCHES)
{
uboParams.color = Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y,
cfg.position.meshColor.z, cfg.position.meshColor.w);

uboParams.displayFormat = MESHDISPLAY_SOLID;

if(!IsGLES)
drv.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE);

@@ -469,6 +480,10 @@ void GLReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondar
// helpers always use basic float-input program
drv.glUseProgram(DebugData.meshProg[0]);

uboParams.vtxExploderSNorm = 0.0f;
uboParams.exploderScale = 0.0f;
uboParams.exploderCentre = Vec3f();

if(cfg.showBBox)
{
Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w);
4 changes: 3 additions & 1 deletion renderdoc/driver/vulkan/vk_overlay.cpp
Original file line number Diff line number Diff line change
@@ -2732,7 +2732,9 @@ 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->exploderScale = 0.0f;
data->exploderCentre = Vec3f();
m_MeshRender.UBO.Unmap();

uint32_t viewOffs = 0;
184 changes: 91 additions & 93 deletions renderdoc/driver/vulkan/vk_rendermesh.cpp
Original file line number Diff line number Diff line change
@@ -37,6 +37,16 @@

RDOC_EXTERN_CONFIG(bool, Vulkan_Debug_SingleSubmitFlushing);

static int VisModeToMeshDisplayFormat(Visualisation vis, bool showAlpha)
{
switch(vis)
{
default: return (int)vis;
case Visualisation::Secondary:
return showAlpha ? MESHDISPLAY_SECONDARY_ALPHA : MESHDISPLAY_SECONDARY;
}
}

VKMeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(VkPipelineLayout pipeLayout,
const MeshFormat &primary,
const MeshFormat &secondary)
@@ -138,7 +148,7 @@ VKMeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(VkPipelineL

VKMeshDisplayPipelines &cache = m_CachedMeshPipelines[key];

if(cache.pipes[(uint32_t)SolidShade::NoSolid] != VK_NULL_HANDLE)
if(cache.pipes[(uint32_t)Visualisation::NoSolid] != VK_NULL_HANDLE)
return cache;

const VkDevDispatchTable *vt = ObjDisp(m_Device);
@@ -526,6 +536,25 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}

// can't support secondary shading without a buffer - no pipeline will have been created
const Visualisation finalVisualisation = (cfg.visualisationMode == Visualisation::Secondary &&
cfg.second.vertexResourceId == ResourceId())
? Visualisation::NoSolid
: cfg.visualisationMode;

MeshUBOData meshUniforms = {};
meshUniforms.mvp = ModelViewProj;
meshUniforms.displayFormat = MESHDISPLAY_SOLID;
meshUniforms.homogenousInput = cfg.position.unproject;
meshUniforms.pointSpriteSize = Vec2f(0.0f, 0.0f);
meshUniforms.rawoutput = 0;
meshUniforms.vtxExploderSNorm = cfg.vtxExploderSliderSNorm;
meshUniforms.exploderScale =
(finalVisualisation == Visualisation::Explode) ? cfg.exploderScale : 0.0f;
meshUniforms.exploderCentre =
Vec3f((cfg.minBounds.x + cfg.maxBounds.x) * 0.5f, (cfg.minBounds.y + cfg.maxBounds.y) * 0.5f,
(cfg.minBounds.z + cfg.maxBounds.z) * 0.5f);

uint32_t dynOffs[2] = {};

if(!secondaryDraws.empty())
@@ -543,13 +572,10 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w);
data->homogenousInput = cfg.position.unproject;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->displayFormat = MESHDISPLAY_SOLID;
data->rawoutput = 0;
data->flipY = (cfg.position.flipY == fmt.flipY) ? 0 : 1;
meshUniforms.color =
Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w);
meshUniforms.flipY = (cfg.position.flipY == fmt.flipY) ? 0 : 1;
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -663,13 +689,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs);
}

SolidShade solidShadeMode = cfg.solidShadeMode;

// can't support secondary shading without a buffer - no pipeline will have been created
if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId())
solidShadeMode = SolidShade::NoSolid;

if(solidShadeMode == SolidShade::Secondary)
if(finalVisualisation == Visualisation::Secondary)
{
VkBuffer vb =
m_pDriver->GetResourceManager()->GetCurrentHandle<VkBuffer>(cfg.second.vertexResourceId);
@@ -687,53 +707,49 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
}

// solid render
if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList)
if(finalVisualisation != Visualisation::NoSolid && cfg.position.topology < Topology::PatchList)
{
VkPipeline pipe = VK_NULL_HANDLE;
switch(solidShadeMode)
switch(finalVisualisation)
{
default:
case SolidShade::Solid: pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth]; break;
case SolidShade::Lit:
case Visualisation::Solid:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
case Visualisation::Lit:
case Visualisation::Explode:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_Lit];
// point list topologies don't have lighting obvious, just render them as solid
// Also, can't support lit rendering without the pipeline - maybe geometry shader wasn't supported.
if(pipe == VK_NULL_HANDLE)
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
case SolidShade::Secondary:
case Visualisation::Secondary:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_Secondary];
break;
case SolidShade::Meshlet: pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth]; break;
case Visualisation::Meshlet:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
}

// can't support lit rendering without the pipeline - maybe geometry shader wasn't supported.
if(solidShadeMode == SolidShade::Lit && pipe == VK_NULL_HANDLE)
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];

MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;

if(solidShadeMode == SolidShade::Lit)
data->invProj = projMat.Inverse();
if(finalVisualisation == Visualisation::Lit || finalVisualisation == Visualisation::Explode)
meshUniforms.invProj = projMat.Inverse();

data->mvp = ModelViewProj;
data->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f);
data->homogenousInput = cfg.position.unproject;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->displayFormat = (uint32_t)solidShadeMode;
data->rawoutput = 0;
meshUniforms.color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f);
meshUniforms.displayFormat = VisModeToMeshDisplayFormat(finalVisualisation, cfg.second.showAlpha);
meshUniforms.flipY = 0;

if(solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA;

if(solidShadeMode == SolidShade::Meshlet)
if(finalVisualisation == Visualisation::Meshlet)
{
size_t numMeshlets = RDCMIN(cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);

uint32_t *meshletCounts = (uint32_t *)m_MeshRender.MeshletSSBO.Map(
&dynOffs[1], AlignUp4(numMeshlets + 4) * sizeof(uint32_t));
if(!data)
if(!meshletCounts)
return;

if(cfg.position.meshletSizes.size() > MAX_NUM_MESHLETS)
@@ -751,13 +767,15 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
meshletCounts[i] = prefixCount;
}

memcpy(&data->meshletColours[0].x, uniqueColors, sizeof(uniqueColors));
RDCCOMPILE_ASSERT(sizeof(data->meshletColours) == sizeof(uniqueColors),
memcpy(&meshUniforms.meshletColours[0].x, uniqueColors, sizeof(uniqueColors));
RDCCOMPILE_ASSERT(sizeof(meshUniforms.meshletColours) == sizeof(uniqueColors),
"Unique colors array is wrongly sized");

m_MeshRender.MeshletSSBO.Unmap();
}

*data = meshUniforms;

m_MeshRender.UBO.Unmap();

vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -789,8 +807,10 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
}
}

meshUniforms.displayFormat = MESHDISPLAY_SOLID;

// wireframe render
if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw ||
if(finalVisualisation == Visualisation::NoSolid || cfg.wireframeDraw ||
cfg.position.topology >= Topology::PatchList)
{
Vec4f wireCol =
@@ -800,12 +820,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = wireCol;
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = cfg.position.unproject;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = wireCol;
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -851,6 +867,11 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco

helper.vertexByteStride = sizeof(Vec4f);

meshUniforms.homogenousInput = 0;
meshUniforms.vtxExploderSNorm = 0.0f;
meshUniforms.exploderScale = 0.0f;
meshUniforms.exploderCentre = Vec3f();

// cache pipelines for use in drawing wireframe helpers
cache = GetDebugManager()->CacheMeshDisplayPipelines(m_MeshRender.PipeLayout, helper, helper);

@@ -893,12 +914,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f);
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = 0;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f);
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -922,12 +939,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f);
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = 0;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f);
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -945,12 +958,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = 0;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -963,12 +972,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f);
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = 0;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f);
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -988,12 +993,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(!data)
return;

data->mvp = ModelViewProj;
data->color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
data->displayFormat = (uint32_t)SolidShade::Solid;
data->homogenousInput = 0;
data->pointSpriteSize = Vec2f(0.0f, 0.0f);
data->rawoutput = 0;
meshUniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
*data = meshUniforms;

m_MeshRender.UBO.Unmap();

@@ -1088,17 +1089,14 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
else
ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat));

MeshUBOData uniforms = {};
uniforms.mvp = ModelViewProj;
uniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
uniforms.displayFormat = (uint32_t)SolidShade::Solid;
uniforms.homogenousInput = cfg.position.unproject;
uniforms.pointSpriteSize = Vec2f(0.0f, 0.0f);
meshUniforms.mvp = ModelViewProj;
meshUniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
meshUniforms.homogenousInput = cfg.position.unproject;

MeshUBOData *ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();

vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -1112,12 +1110,12 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
// render primitives

// Draw active primitive (red)
uniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f);
meshUniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
@@ -1140,12 +1138,12 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
}

// Draw adjacent primitives (green)
uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
meshUniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
@@ -1173,15 +1171,15 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
float scale = 800.0f / float(m_DebugHeight);
float asp = float(m_DebugWidth) / float(m_DebugHeight);

uniforms.pointSpriteSize = Vec2f(scale / asp, scale);
meshUniforms.pointSpriteSize = Vec2f(scale / asp, scale);

// Draw active vertex (blue)
uniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f);
meshUniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
@@ -1221,12 +1219,12 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
}

// Draw inactive vertices (green)
uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
meshUniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
10 changes: 5 additions & 5 deletions util/test/rdtest/shared/Mesh_Zoo.py
Original file line number Diff line number Diff line change
@@ -118,7 +118,7 @@ def check_capture(self, capture_filename: str, controller: rd.ReplayController):

rdtest.log.success("Base rendering is as expected")

self.cfg.solidShadeMode = rd.SolidShade.Secondary
self.cfg.visualisationMode = rd.Visualisation.Secondary
self.cfg.wireframeDraw = False

# allow for blending with white for the frustum
@@ -244,7 +244,7 @@ def check_capture(self, capture_filename: str, controller: rd.ReplayController):

rdtest.log.success("Rendering of float2 color secondary in instance 1 is as expected")

self.cfg.solidShadeMode = rd.SolidShade.NoSolid
self.cfg.visualisationMode = rd.Visualisation.NoSolid
self.cfg.showAllInstances = True

self.cache_output()
@@ -370,18 +370,18 @@ def check_capture(self, capture_filename: str, controller: rd.ReplayController):
rdtest.log.success("Point picking is as expected")

self.cfg.highlightVert = rd.MeshDisplay.NoHighlight
self.cfg.solidShadeMode = rd.SolidShade.Solid
self.cfg.visualisationMode = rd.Visualisation.Solid

self.cache_output()
self.cfg.solidShadeMode = rd.SolidShade.Lit
self.cfg.visualisationMode = rd.Visualisation.Lit
self.cache_output()

rdtest.log.success("Point solid and lit rendering works as expected")

self.controller.SetFrameEvent(self.find_action("Lines").next.eventId, False)

self.cache_output()
self.cfg.solidShadeMode = rd.SolidShade.Lit
self.cfg.visualisationMode = rd.Visualisation.Lit
self.cache_output()

rdtest.log.success("Lines solid and lit rendering works as expected")