From 1ca55a823723bc6bade6edb05332f2cf831613cd Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 10 May 2017 14:25:23 +0100 Subject: [PATCH] Add an optional 'rgb' specifier to colour buffer cells backgrounds * When opening a texture as a buffer we can make use of this. --- qrenderdoc/Code/FormatElement.cpp | 56 ++++---- qrenderdoc/Code/QRDUtils.h | 25 +++- qrenderdoc/Widgets/BufferFormatSpecifier.ui | 8 +- qrenderdoc/Windows/BufferViewer.cpp | 140 +++++++++++++++----- qrenderdoc/Windows/TextureViewer.cpp | 71 +++++++++- 5 files changed, 230 insertions(+), 70 deletions(-) diff --git a/qrenderdoc/Code/FormatElement.cpp b/qrenderdoc/Code/FormatElement.cpp index 6c73002f4..487a92771 100644 --- a/qrenderdoc/Code/FormatElement.cpp +++ b/qrenderdoc/Code/FormatElement.cpp @@ -120,11 +120,13 @@ FormatElement::FormatElement() rowmajor = false; matrixdim = 0; hex = false; + rgb = false; systemValue = ShaderBuiltin::Undefined; } FormatElement::FormatElement(const QString &Name, int buf, uint offs, bool perInst, int instRate, - bool rowMat, uint matDim, ResourceFormat f, bool hexDisplay) + bool rowMat, uint matDim, ResourceFormat f, bool hexDisplay, + bool rgbDisplay) { name = Name; buffer = buf; @@ -135,6 +137,7 @@ FormatElement::FormatElement(const QString &Name, int buf, uint offs, bool perIn rowmajor = rowMat; matrixdim = matDim; hex = hexDisplay; + rgb = rgbDisplay; systemValue = ShaderBuiltin::Undefined; } @@ -146,20 +149,22 @@ QList FormatElement::ParseFormatString(const QString &formatStrin // regex doesn't account for trailing or preceeding whitespace, or comments QRegularExpression regExpr( - lit("^(row_major\\s+)?" // row_major matrix - "(" - "uintten|unormten" - "|floateleven" - "|unormh|unormb" - "|snormh|snormb" - "|bool" // bool is stored as 4-byte int - "|byte|short|int" // signed ints - "|ubyte|ushort|uint" // unsigned ints - "|xbyte|xshort|xint" // hex ints - "|half|float|double" // float types - "|vec|uvec|ivec" // OpenGL vector types - "|mat|umat|imat" // OpenGL matrix types - ")" + lit("^" // start of the line + "(row_major\\s+)?" // row_major matrix + "(rgb\\s+)?" // rgb element colourising + "(" // group the options for the type + "uintten|unormten" // R10G10B10A2 types + "|floateleven" // R11G11B10 special type + "|unormh|unormb" // UNORM 16-bit and 8-bit types + "|snormh|snormb" // SNORM 16-bit and 8-bit types + "|bool" // bool is stored as 4-byte int + "|byte|short|int" // signed ints + "|ubyte|ushort|uint" // unsigned ints + "|xbyte|xshort|xint" // hex ints + "|half|float|double" // float types + "|vec|uvec|ivec" // OpenGL vector types + "|mat|umat|imat" // OpenGL matrix types + ")" // end of the type group "([1-9])?" // might be a vector "(x[1-9])?" // or a matrix "(\\s+[A-Za-z_][A-Za-z0-9_]*)?" // get identifier name @@ -197,15 +202,16 @@ QList FormatElement::ParseFormatString(const QString &formatStrin break; } - QString basetype = match.captured(2); + QString basetype = match.captured(3); bool row_major = !match.captured(1).isEmpty(); - QString vectorDim = !match.captured(3).isEmpty() ? match.captured(3) : lit("1"); - QString matrixDim = !match.captured(4).isEmpty() ? match.captured(4).mid(1) : lit("1"); - QString name = !match.captured(5).isEmpty() ? match.captured(5).trimmed() : lit("data"); - QString arrayDim = !match.captured(6).isEmpty() ? match.captured(6).trimmed() : lit("[1]"); + bool rgb = !match.captured(2).isEmpty(); + QString vectorDim = !match.captured(4).isEmpty() ? match.captured(4) : lit("1"); + QString matrixDim = !match.captured(5).isEmpty() ? match.captured(5).mid(1) : lit("1"); + QString name = !match.captured(6).isEmpty() ? match.captured(6).trimmed() : lit("data"); + QString arrayDim = !match.captured(7).isEmpty() ? match.captured(7).trimmed() : lit("[1]"); arrayDim = arrayDim.mid(1, arrayDim.count() - 2); - if(!match.captured(4).isEmpty()) + if(!match.captured(5).isEmpty()) { vectorDim.swap(matrixDim); } @@ -222,7 +228,7 @@ QList FormatElement::ParseFormatString(const QString &formatStrin uint32_t width = 0; // check for square matrix declarations like 'mat4' and 'mat3' - if(basetype == lit("mat") && !match.captured(4).isEmpty()) + if(basetype == lit("mat") && !match.captured(5).isEmpty()) matrixDim = vectorDim; // calculate format @@ -367,7 +373,7 @@ QList FormatElement::ParseFormatString(const QString &formatStrin if(arrayCount == 1) { - FormatElement elem(name, 0, offset, false, 1, row_major, matrixCount, fmt, hex); + FormatElement elem(name, 0, offset, false, 1, row_major, matrixCount, fmt, hex, rgb); uint32_t advance = elem.byteSize(); @@ -402,7 +408,7 @@ QList FormatElement::ParseFormatString(const QString &formatStrin for(uint a = 0; a < arrayCount; a++) { FormatElement elem(QFormatStr("%1[%2]").arg(name).arg(a), 0, offset, false, 1, row_major, - matrixCount, fmt, hex); + matrixCount, fmt, hex, rgb); elems.push_back(elem); @@ -433,7 +439,7 @@ QList FormatElement::ParseFormatString(const QString &formatStrin if(maxLen > 0 && maxLen < 4) fmt.compByteWidth = 1; - elems.push_back(FormatElement(lit("data"), 0, 0, false, 1, false, 1, fmt, true)); + elems.push_back(FormatElement(lit("data"), 0, 0, false, 1, false, 1, fmt, true, false)); } return elems; diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 83e450ace..3429913a3 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -589,7 +589,7 @@ struct FormatElement public: FormatElement(); FormatElement(const QString &Name, int buf, uint offs, bool perInst, int instRate, bool rowMat, - uint matDim, ResourceFormat f, bool hexDisplay); + uint matDim, ResourceFormat f, bool hexDisplay, bool rgbDisplay); static QList ParseFormatString(const QString &formatString, uint64_t maxLen, bool tightPacking, QString &errors); @@ -602,15 +602,15 @@ public: uint32_t byteSize() const; QString name; + ResourceFormat format; + ShaderBuiltin systemValue; int buffer; uint32_t offset; - bool perinstance; int instancerate; - bool rowmajor; uint32_t matrixdim; - ResourceFormat format; - bool hex; - ShaderBuiltin systemValue; + bool perinstance; + bool rowmajor; + bool hex, rgb; }; QString TypeString(const ShaderVariable &v); @@ -639,6 +639,19 @@ struct Formatter { return QFormatStr("%1").arg(u, hex ? 4 : 0, hex ? 16 : 10, QLatin1Char('0')); } + static QString Format(uint8_t u, bool hex = false) + { + return QFormatStr("%1").arg(u, hex ? 2 : 0, hex ? 16 : 10, QLatin1Char('0')); + } + static QString HexFormat(uint32_t u, uint32_t byteSize) + { + if(byteSize == 1) + return Format(uint8_t(u & 0xff), true); + else if(byteSize == 2) + return Format(uint16_t(u & 0xffff), true); + else + return Format(u, true); + } static QString Format(int32_t i, bool hex = false) { return QString::number(i); } static const QFont &PreferredFont() { return m_Font; } private: diff --git a/qrenderdoc/Widgets/BufferFormatSpecifier.ui b/qrenderdoc/Widgets/BufferFormatSpecifier.ui index 3d4ee4918..ff445fcff 100644 --- a/qrenderdoc/Widgets/BufferFormatSpecifier.ui +++ b/qrenderdoc/Widgets/BufferFormatSpecifier.ui @@ -65,9 +65,9 @@ 0 - - Apply - + + Apply + @@ -84,6 +84,8 @@ Hex-formatted integer types: xbyte, xshort, xint Additionally special formats: unorm[hb] (half, byte) and snorm[hb], uintten/unormten (10:10:10:2 packing), floateleven (11:11:10F packing) +You can prepend 'rgb' onto an element to colour backgrounds with the RGB values, e.g. 'rgb xbyte4 pixels[256]'. + Vectors (e.g. float4), matrices ([row_major] half3x4) and arrays (float[16]) are supported. diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index a6c360e96..8b2fc032c 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -447,37 +447,103 @@ public: if((role == Qt::BackgroundRole || role == Qt::ForegroundRole) && col >= reservedColumnCount()) { - int elIdx = columnLookup[col - reservedColumnCount()]; - int compIdx = componentForIndex(col); - if(elIdx == positionEl) + if(meshView) { - if(role == Qt::ForegroundRole) - return QBrush(Qt::black); + int elIdx = columnLookup[col - reservedColumnCount()]; + int compIdx = componentForIndex(col); - if(compIdx != 3 || !meshInput) + if(elIdx == positionEl) { - // C# SkyBlue - return QBrush(QColor::fromRgb(135, 206, 235)); + if(role == Qt::ForegroundRole) + return QBrush(Qt::black); + + if(compIdx != 3 || !meshInput) + { + // C# SkyBlue + return QBrush(QColor::fromRgb(135, 206, 235)); + } + else + { + // C# LightCyan + return QBrush(QColor::fromRgb(224, 255, 255)); + } } - else + else if(secondaryEnabled && elIdx == secondaryEl) { - // C# LightCyan - return QBrush(QColor::fromRgb(224, 255, 255)); + if(role == Qt::ForegroundRole) + return QBrush(Qt::black); + + if((secondaryElAlpha && compIdx == 3) || (!secondaryElAlpha && compIdx != 3)) + { + // C# LightGreen + return QBrush(QColor::fromRgb(144, 238, 144)); + } + else + { + return QBrush(QColor::fromRgb(200, 238, 200)); + } } } - else if(secondaryEnabled && elIdx == secondaryEl) + else { - if(role == Qt::ForegroundRole) - return QBrush(Qt::black); + const FormatElement &el = elementForColumn(col); - if((secondaryElAlpha && compIdx == 3) || (!secondaryElAlpha && compIdx != 3)) + if(el.rgb && el.buffer < buffers.size()) { - // C# LightGreen - return QBrush(QColor::fromRgb(144, 238, 144)); - } - else - { - return QBrush(QColor::fromRgb(200, 238, 200)); + const byte *data = buffers[el.buffer]->data; + const byte *end = buffers[el.buffer]->end; + + data += buffers[el.buffer]->stride * row; + data += el.offset; + + // only slightly wasteful, we need to fetch all variants together + // since some formats are packed and can't be read individually + QVariantList list = el.GetVariants(data, end); + + if(!list.isEmpty()) + { + QMetaType::Type vt = (QMetaType::Type)list[0].type(); + + QColor rgb; + + if(vt == QMetaType::Double) + { + double r = qBound(0.0, list[0].toDouble(), 1.0); + double g = list.size() > 1 ? qBound(0.0, list[1].toDouble(), 1.0) : 0.0; + double b = list.size() > 2 ? qBound(0.0, list[2].toDouble(), 1.0) : 0.0; + + rgb = QColor::fromRgbF(r, g, b); + } + else if(vt == QMetaType::Float) + { + float r = qBound(0.0f, list[0].toFloat(), 1.0f); + float g = list.size() > 1 ? qBound(0.0f, list[1].toFloat(), 1.0f) : 0.0; + float b = list.size() > 2 ? qBound(0.0f, list[2].toFloat(), 1.0f) : 0.0; + + rgb = QColor::fromRgbF(r, g, b); + } + else if(vt == QMetaType::UInt || vt == QMetaType::UShort || vt == QMetaType::UChar) + { + uint r = qBound(0U, list[0].toUInt(), 255U); + uint g = list.size() > 1 ? qBound(0U, list[1].toUInt(), 255U) : 0.0; + uint b = list.size() > 2 ? qBound(0U, list[2].toUInt(), 255U) : 0.0; + + rgb = QColor::fromRgb(r, g, b); + } + else if(vt == QMetaType::Int || vt == QMetaType::Short || vt == QMetaType::SChar) + { + int r = qBound(0, list[0].toInt(), 255); + int g = list.size() > 1 ? qBound(0, list[1].toInt(), 255) : 0.0; + int b = list.size() > 2 ? qBound(0, list[2].toInt(), 255) : 0.0; + + rgb = QColor::fromRgb(r, g, b); + } + + if(role == Qt::BackgroundRole) + return QBrush(rgb); + else if(role == Qt::ForegroundRole) + return QBrush(contrastingColor(rgb, QColor::fromRgb(0, 0, 0))); + } } } } @@ -573,7 +639,11 @@ public: } else if(vt == QMetaType::UInt || vt == QMetaType::UShort || vt == QMetaType::UChar) { - ret = Formatter::Format(v.toUInt(), el.hex); + uint u = v.toUInt(); + if(el.hex && el.format.specialFormat == SpecialFormat::Unknown) + ret = Formatter::HexFormat(u, el.format.compByteWidth); + else + ret = Formatter::Format(u, el.hex); } else if(vt == QMetaType::Int || vt == QMetaType::Short || vt == QMetaType::SChar) { @@ -2027,7 +2097,7 @@ void BufferViewer::configureMeshColumns() FormatElement f(a.Name, a.VertexBuffer, a.RelativeByteOffset, a.PerInstance, a.InstanceRate, false, // row major matrix 1, // matrix dimension - a.Format, false); + a.Format, false, false); m_ModelVSIn->columns.push_back(f); } @@ -2514,25 +2584,23 @@ void BufferViewer::CalcColumnWidth() floatFmt.compCount = 1; ResourceFormat intFmt; - floatFmt.compByteWidth = 4; - floatFmt.compType = CompType::UInt; - floatFmt.compCount = 1; + intFmt.compByteWidth = 4; + intFmt.compType = CompType::UInt; + intFmt.compCount = 1; - FormatElement(lit("ColumnSizeTest"), 0, 0, false, 1, false, 1, floatFmt, false); - FormatElement(lit("ColumnSizeTest"), 0, 0, false, 1, false, 1, intFmt, true); - FormatElement(lit("ColumnSizeTest"), 0, 0, false, 1, false, 1, intFmt, false); + QString headerText = lit("ColumnSizeTest"); m_ModelVSIn->columns.clear(); m_ModelVSIn->columns.push_back( - FormatElement(lit("ColumnSizeTest"), 0, 0, false, 1, false, 1, floatFmt, false)); + FormatElement(headerText, 0, 0, false, 1, false, 1, floatFmt, false, false)); m_ModelVSIn->columns.push_back( - FormatElement(lit("ColumnSizeTest"), 0, 4, false, 1, false, 1, floatFmt, false)); + FormatElement(headerText, 0, 4, false, 1, false, 1, floatFmt, false, false)); m_ModelVSIn->columns.push_back( - FormatElement(lit("ColumnSizeTest"), 0, 8, false, 1, false, 1, floatFmt, false)); + FormatElement(headerText, 0, 8, false, 1, false, 1, floatFmt, false, false)); m_ModelVSIn->columns.push_back( - FormatElement(lit("ColumnSizeTest"), 0, 12, false, 1, false, 1, intFmt, true)); + FormatElement(headerText, 0, 12, false, 1, false, 1, intFmt, true, false)); m_ModelVSIn->columns.push_back( - FormatElement(lit("ColumnSizeTest"), 0, 16, false, 1, false, 1, intFmt, false)); + FormatElement(headerText, 0, 16, false, 1, false, 1, intFmt, false, false)); m_ModelVSIn->numRows = 2; @@ -2659,13 +2727,15 @@ void BufferViewer::processFormat(const QString &format) Reset(); + QList cols = FormatElement::ParseFormatString(format, 0, true, errors); + CalcColumnWidth(); ClearModels(); m_Format = format; - m_ModelVSIn->columns = FormatElement::ParseFormatString(format, 0, true, errors); + m_ModelVSIn->columns = cols; uint32_t stride = 0; for(const FormatElement &el : m_ModelVSIn->columns) diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 1ba313807..42172ef7a 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -3212,8 +3212,77 @@ void TextureViewer::on_viewTexBuffer_clicked() if(texptr) { + QString baseType; + + QString varName = lit("pixels"); + + uint32_t w = texptr->width; + + switch(texptr->format.specialFormat) + { + case SpecialFormat::BC1: + case SpecialFormat::BC2: + case SpecialFormat::BC3: + case SpecialFormat::BC4: + case SpecialFormat::BC5: + case SpecialFormat::BC6: + case SpecialFormat::BC7: + case SpecialFormat::ETC2: + case SpecialFormat::EAC: + case SpecialFormat::ASTC: + varName = lit("block"); + // display a 4x4 block at a time + w /= 4; + default: break; + } + + switch(texptr->format.specialFormat) + { + case SpecialFormat::Unknown: + { + if(texptr->format.compByteWidth == 1) + baseType = lit("byte"); + else if(texptr->format.compByteWidth == 2) + baseType = lit("short"); + else + baseType = lit("int"); + + baseType = QFormatStr("rgb x%1%2").arg(baseType).arg(texptr->format.compCount); + + break; + } + // 2x4 byte block, for 64-bit block formats + case SpecialFormat::BC1: + case SpecialFormat::BC4: + case SpecialFormat::ETC2: + case SpecialFormat::EAC: + baseType = lit("row_major xint2x1"); + break; + // 4x4 byte block, for 128-bit block formats + case SpecialFormat::BC2: + case SpecialFormat::BC3: + case SpecialFormat::BC5: + case SpecialFormat::BC6: + case SpecialFormat::BC7: + case SpecialFormat::ASTC: baseType = lit("row_major xint4x1"); break; + case SpecialFormat::R10G10B10A2: baseType = lit("uintten"); break; + case SpecialFormat::R11G11B10: baseType = lit("rgb floateleven"); break; + case SpecialFormat::R5G6B5: + case SpecialFormat::R5G5B5A1: baseType = lit("xshort"); break; + case SpecialFormat::R9G9B9E5: baseType = lit("xint"); break; + case SpecialFormat::R4G4B4A4: baseType = lit("xbyte2"); break; + case SpecialFormat::R4G4: baseType = lit("xbyte"); break; + case SpecialFormat::D16S8: + case SpecialFormat::D24S8: + case SpecialFormat::D32S8: + case SpecialFormat::YUV: baseType = lit("xint4"); break; + case SpecialFormat::S8: baseType = lit("xbyte"); break; + } + + QString format = QFormatStr("%1 %2[%3];").arg(baseType).arg(varName).arg(w); + IBufferViewer *viewer = - m_Ctx.ViewTextureAsBuffer(m_TexDisplay.sliceFace, m_TexDisplay.mip, texptr->ID); + m_Ctx.ViewTextureAsBuffer(m_TexDisplay.sliceFace, m_TexDisplay.mip, texptr->ID, format); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); }