Add a $dispatch() helper to filter only dispatches (and properties)

This commit is contained in:
baldurk
2021-06-02 11:20:34 +01:00
parent 7b83524bc8
commit 3bc221d625
+241
View File
@@ -1219,6 +1219,7 @@ public:
MAKE_BUILTIN_FILTER(param);
MAKE_BUILTIN_FILTER(event);
MAKE_BUILTIN_FILTER(draw);
MAKE_BUILTIN_FILTER(dispatch);
}
}
void ResetCache() { m_VisibleCache.clear(); }
@@ -1852,6 +1853,246 @@ private:
}
}
IEventBrowser::EventFilterCallback filterFunction_dispatch(QString name, QString parameters,
ParseError &errors)
{
// $dispatch(...) => returns true only for dispatches, optionally with a particular property
// filter
QList<Token> tokens = tokenise(parameters);
// no parameters, just return if it's a draw
if(tokens.isEmpty())
return [](ICaptureContext *, const rdcstr &, const rdcstr &, uint32_t eventId,
const SDChunk *, const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch);
};
// we upcast to int64_t so we can compare both unsigned and signed values without losing any
// precision (we don't have any uint64_ts to compare)
using PropGetter = int64_t (*)(const DrawcallDescription *);
struct NamedProp
{
const char *name;
PropGetter getter;
};
static const NamedProp namedProps[] = {
NAMED_PROP("dispatchx", draw->dispatchDimension[0]),
NAMED_PROP("dispatchy", draw->dispatchDimension[1]),
NAMED_PROP("dispatchz", draw->dispatchDimension[2]),
NAMED_PROP("x", draw->dispatchDimension[0]), NAMED_PROP("y", draw->dispatchDimension[1]),
NAMED_PROP("z", draw->dispatchDimension[2]),
NAMED_PROP("dispatchsize", draw->dispatchDimension[0] * draw->dispatchDimension[1] *
draw->dispatchDimension[2]),
NAMED_PROP("size", draw->dispatchDimension[0] * draw->dispatchDimension[1] *
draw->dispatchDimension[2]),
};
QByteArray prop = tokens[0].text.toLower().toLatin1();
int numericPropIndex = -1;
for(size_t i = 0; i < ARRAY_COUNT(namedProps); i++)
{
if(prop == namedProps[i].name)
numericPropIndex = (int)i;
}
// any numeric value that can be compared to a number
if(numericPropIndex >= 0)
{
PropGetter propGetter = namedProps[numericPropIndex].getter;
static const QStringList operators = {
lit("=="), lit("!="), lit("<"), lit(">"), lit("<="), lit(">="),
};
int operatorIdx = tokens.size() > 1 ? operators.indexOf(tokens[1].text) : -1;
if(tokens.size() > 1 && tokens[1].text == lit("="))
operatorIdx = 0;
if(tokens.size() != 3 || operatorIdx < 0 || operatorIdx >= operators.size())
{
errors.setText(tr("Invalid expression, expected single comparison with operators: %3",
"EventFilterModel")
.arg(operators.join(lit(", "))));
return NULL;
}
bool ok = false;
int64_t value = tokens[2].text.toLongLong(&ok, 0);
if(!ok)
{
errors.position = tokens[2].position;
errors.length = tokens[2].length;
errors.setText(tr("Invalid value, expected integer", "EventFilterModel"));
return NULL;
}
switch(operatorIdx)
{
case 0:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) == value;
};
case 1:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) != value;
};
case 2:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) < value;
};
case 3:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) > value;
};
case 4:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) <= value;
};
case 5:
return [propGetter, value](ICaptureContext *, const rdcstr &, const rdcstr &,
uint32_t eventId, const SDChunk *,
const DrawcallDescription *draw, const rdcstr &) {
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
propGetter(draw) >= value;
};
default: errors.setText(tr("Internal error", "EventFilterModel")); return NULL;
}
}
else if(tokens[0].text.toLower() == lit("duration"))
{
// deliberately don't allow equality/inequality
static const QStringList operators = {
lit("<"), lit(">"), lit("<="), lit(">="),
};
int operatorIdx = tokens.size() > 1 ? operators.indexOf(tokens[1].text) : -1;
if(tokens.size() != 3 || operatorIdx < 0 || operatorIdx >= operators.size())
{
errors.setText(tr("Invalid expression, expected single comparison with operators: %3",
"EventFilterModel")
.arg(operators.join(lit(", "))));
return NULL;
}
// multiplier to change the read value into nanoseconds
double mult = 1.0;
if(tokens[2].text.endsWith(lit("ms")))
{
mult = 1000000.0;
tokens[2].text.resize(tokens[2].text.size() - 2);
}
else if(tokens[2].text.endsWith(lit("us")))
{
mult = 1000.0;
tokens[2].text.resize(tokens[2].text.size() - 2);
}
else if(tokens[2].text.endsWith(lit("ns")))
{
mult = 1.0;
tokens[2].text.resize(tokens[2].text.size() - 2);
}
else if(tokens[2].text.endsWith(lit("s")))
{
mult = 1000000000.0;
tokens[2].text.resize(tokens[2].text.size() - 1);
}
else
{
errors.position = tokens[2].position;
errors.length = tokens[2].length;
errors.setText(
tr("Duration must be suffixed with one of s, ms, us, or ns", "EventFilterModel"));
return NULL;
}
bool ok = false;
double value = tokens[2].text.toDouble(&ok);
// if it doesn't read as a double, try as an integer
if(!ok)
{
int64_t valInt = tokens[2].text.toLongLong(&ok);
if(ok)
value = double(valInt);
}
if(!ok)
{
errors.position = tokens[2].position;
errors.length = tokens[2].length;
errors.setText(tr("Invalid value, expected duration suffixed with one of s, ms, us, or ns",
"EventFilterModel"));
return NULL;
}
int64_t nanoValue = int64_t(value * mult);
switch(operatorIdx)
{
case 0:
return
[this, nanoValue](ICaptureContext *, const rdcstr &, const rdcstr &, uint32_t eventId,
const SDChunk *, const DrawcallDescription *draw, const rdcstr &) {
double dur = m_Model->GetSecondsDurationForEID(eventId);
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
dur >= 0.0 && int64_t(dur * 1000000000.0) < nanoValue;
};
case 1:
return
[this, nanoValue](ICaptureContext *, const rdcstr &, const rdcstr &, uint32_t eventId,
const SDChunk *, const DrawcallDescription *draw, const rdcstr &) {
double dur = m_Model->GetSecondsDurationForEID(eventId);
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
dur >= 0.0 && int64_t(dur * 1000000000.0) > nanoValue;
};
case 2:
return
[this, nanoValue](ICaptureContext *, const rdcstr &, const rdcstr &, uint32_t eventId,
const SDChunk *, const DrawcallDescription *draw, const rdcstr &) {
double dur = m_Model->GetSecondsDurationForEID(eventId);
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
dur >= 0.0 && int64_t(dur * 1000000000.0) <= nanoValue;
};
case 3:
return
[this, nanoValue](ICaptureContext *, const rdcstr &, const rdcstr &, uint32_t eventId,
const SDChunk *, const DrawcallDescription *draw, const rdcstr &) {
double dur = m_Model->GetSecondsDurationForEID(eventId);
return draw->eventId == eventId && (draw->flags & DrawFlags::Dispatch) &&
dur >= 0.0 && int64_t(dur * 1000000000.0) >= nanoValue;
};
default: errors.setText(tr("Internal error", "EventFilterModel")); return NULL;
}
}
else
{
errors.setText(tr("Unrecognised property expression", "EventFilterModel"));
return NULL;
}
}
IEventBrowser::EventFilterCallback MakeFunctionMatcher(QString name, QString parameters,
ParseError &errors)
{