mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-16 20:47:12 +00:00
Centralise generation of buffer format strings for struct buffers
* We also fix a number of issues that could cause incorrect formats to be generated. * Test cases added for D3D11/GL/Vulkan to test different struct types. These aren't automated at the moment because most of the code they're testing is in the UI itself.
This commit is contained in:
@@ -484,13 +484,49 @@ QString FormatElement::GenerateTextureBufferFormat(const TextureDescription &tex
|
||||
case ResourceFormatType::Regular:
|
||||
{
|
||||
if(tex.format.compByteWidth == 1)
|
||||
baseType = lit("byte");
|
||||
{
|
||||
if(tex.format.compType == CompType::UNorm)
|
||||
baseType = lit("unormb");
|
||||
else if(tex.format.compType == CompType::SNorm)
|
||||
baseType = lit("snormb");
|
||||
else if(tex.format.compType == CompType::SInt)
|
||||
baseType = lit("byte");
|
||||
else
|
||||
baseType = lit("ubyte");
|
||||
}
|
||||
else if(tex.format.compByteWidth == 2)
|
||||
baseType = lit("short");
|
||||
{
|
||||
if(tex.format.compType == CompType::UNorm)
|
||||
baseType = lit("unormh");
|
||||
else if(tex.format.compType == CompType::SNorm)
|
||||
baseType = lit("snormh");
|
||||
else if(tex.format.compType == CompType::Float)
|
||||
baseType = lit("half");
|
||||
else if(tex.format.compType == CompType::SInt)
|
||||
baseType = lit("short");
|
||||
else
|
||||
baseType = lit("ushort");
|
||||
}
|
||||
else if(tex.format.compByteWidth == 4)
|
||||
{
|
||||
if(tex.format.compType == CompType::Float)
|
||||
baseType = lit("float");
|
||||
else if(tex.format.compType == CompType::SInt)
|
||||
baseType = lit("int");
|
||||
else
|
||||
baseType = lit("uint");
|
||||
}
|
||||
else
|
||||
baseType = lit("int");
|
||||
{
|
||||
if(tex.format.compType == CompType::Float || tex.format.compType == CompType::Double)
|
||||
baseType = lit("double");
|
||||
else if(tex.format.compType == CompType::SInt)
|
||||
baseType = lit("long");
|
||||
else
|
||||
baseType = lit("ulong");
|
||||
}
|
||||
|
||||
baseType = QFormatStr("rgb x%1%2").arg(baseType).arg(tex.format.compCount);
|
||||
baseType = QFormatStr("rgb %1%2").arg(baseType).arg(tex.format.compCount);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1923,46 +1923,6 @@ void D3D11PipelineStateViewer::setState()
|
||||
}
|
||||
}
|
||||
|
||||
QString D3D11PipelineStateViewer::formatMembers(int indent, const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars)
|
||||
{
|
||||
QString indentstr(indent * 4, QLatin1Char(' '));
|
||||
|
||||
QString ret;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(const ShaderConstant &v : vars)
|
||||
{
|
||||
if(!v.type.members.empty())
|
||||
{
|
||||
if(i > 0)
|
||||
ret += lit("\n");
|
||||
ret += indentstr + lit("// struct %1\n").arg(v.type.descriptor.name);
|
||||
ret += indentstr + lit("{\n") + formatMembers(indent + 1, v.name + lit("_"), v.type.members) +
|
||||
indentstr + lit("}\n");
|
||||
if(i < vars.count() - 1)
|
||||
ret += lit("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString arr;
|
||||
if(v.type.descriptor.elements > 1)
|
||||
arr = QFormatStr("[%1]").arg(v.type.descriptor.elements);
|
||||
ret += QFormatStr("%1%2 %3%4%5;\n")
|
||||
.arg(indentstr)
|
||||
.arg(v.type.descriptor.name)
|
||||
.arg(nameprefix)
|
||||
.arg(v.name)
|
||||
.arg(arr);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int column)
|
||||
{
|
||||
const D3D11Pipe::Shader *stage = stageForSender(item->treeWidget());
|
||||
@@ -2102,103 +2062,10 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in
|
||||
|
||||
if(shaderRes)
|
||||
{
|
||||
const ShaderResource &res = *shaderRes;
|
||||
format = m_Common.GenerateBufferFormatter(*shaderRes, view.res.viewFormat, offs);
|
||||
|
||||
if(!res.variableType.members.empty())
|
||||
{
|
||||
format = lit("// struct %1\n{\n%2}")
|
||||
.arg(res.variableType.descriptor.name)
|
||||
.arg(formatMembers(1, QString(), res.variableType.members));
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &desc = res.variableType.descriptor;
|
||||
|
||||
if(view.res.viewFormat.type == ResourceFormatType::Undefined)
|
||||
{
|
||||
format = QString();
|
||||
if(desc.rowMajorStorage)
|
||||
format += lit("row_major ");
|
||||
|
||||
format += ToQStr(desc.type);
|
||||
if(desc.rows > 1 && desc.columns > 1)
|
||||
format += QFormatStr("%1x%2").arg(desc.rows).arg(desc.columns);
|
||||
else if(desc.columns > 1)
|
||||
format += QString::number(desc.columns);
|
||||
|
||||
if(!desc.name.empty())
|
||||
format += lit(" ") + desc.name;
|
||||
|
||||
if(desc.elements > 1)
|
||||
format += QFormatStr("[%1]").arg(desc.elements);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ResourceFormat &fmt = view.res.viewFormat;
|
||||
if(fmt.type == ResourceFormatType::R10G10B10A2)
|
||||
{
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("uintten");
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormten");
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R11G11B10)
|
||||
{
|
||||
format = lit("floateleven");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(fmt.compByteWidth)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormb");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormb");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("ubyte");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("byte");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormh");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormh");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("ushort");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("short");
|
||||
if(fmt.compType == CompType::Float)
|
||||
format = lit("half");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormf");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormf");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("uint");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("int");
|
||||
if(fmt.compType == CompType::Float)
|
||||
format = lit("float");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(view.res.bufferFlags & D3DBufferViewFlags::Raw)
|
||||
format = lit("xint");
|
||||
|
||||
format += QString::number(fmt.compCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(view.res.bufferFlags & D3DBufferViewFlags::Raw)
|
||||
format = lit("xint");
|
||||
}
|
||||
|
||||
IBufferViewer *viewer = m_Ctx.ViewBuffer(offs, size, view.res.resourceResourceId, format);
|
||||
|
||||
@@ -104,7 +104,6 @@ private:
|
||||
void setEmptyRow(RDTreeWidgetItem *node);
|
||||
void highlightIABind(int slot);
|
||||
|
||||
QString formatMembers(int indent, const QString &nameprefix, const rdcarray<ShaderConstant> &vars);
|
||||
const D3D11Pipe::Shader *stageForSender(QWidget *widget);
|
||||
|
||||
bool HasImportantViewParams(const D3D11Pipe::View &view, TextureDescription *tex);
|
||||
|
||||
@@ -1809,46 +1809,6 @@ void D3D12PipelineStateViewer::setState()
|
||||
}
|
||||
}
|
||||
|
||||
QString D3D12PipelineStateViewer::formatMembers(int indent, const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars)
|
||||
{
|
||||
QString indentstr(indent * 4, QLatin1Char(' '));
|
||||
|
||||
QString ret;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(const ShaderConstant &v : vars)
|
||||
{
|
||||
if(!v.type.members.empty())
|
||||
{
|
||||
if(i > 0)
|
||||
ret += lit("\n");
|
||||
ret += indentstr + lit("// struct %1\n").arg(v.type.descriptor.name);
|
||||
ret += indentstr + lit("{\n") + formatMembers(indent + 1, v.name + lit("_"), v.type.members) +
|
||||
indentstr + lit("}\n");
|
||||
if(i < vars.count() - 1)
|
||||
ret += lit("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString arr;
|
||||
if(v.type.descriptor.elements > 1)
|
||||
arr = QFormatStr("[%1]").arg(v.type.descriptor.elements);
|
||||
ret += QFormatStr("%1%2 %3%4%5;\n")
|
||||
.arg(indentstr)
|
||||
.arg(v.type.descriptor.name)
|
||||
.arg(nameprefix)
|
||||
.arg(v.name)
|
||||
.arg(arr);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int column)
|
||||
{
|
||||
const D3D12Pipe::Shader *stage = stageForSender(item->treeWidget());
|
||||
@@ -1954,103 +1914,10 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in
|
||||
|
||||
if(shaderRes)
|
||||
{
|
||||
const ShaderResource &res = *shaderRes;
|
||||
format = m_Common.GenerateBufferFormatter(*shaderRes, view.res.viewFormat, offs);
|
||||
|
||||
if(!res.variableType.members.empty())
|
||||
{
|
||||
format = QFormatStr("// struct %1\n{\n%2}")
|
||||
.arg(res.variableType.descriptor.name)
|
||||
.arg(formatMembers(1, QString(), res.variableType.members));
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &desc = res.variableType.descriptor;
|
||||
|
||||
if(view.res.viewFormat.type == ResourceFormatType::Undefined)
|
||||
{
|
||||
format = QString();
|
||||
if(desc.rowMajorStorage)
|
||||
format += lit("row_major ");
|
||||
|
||||
format += ToQStr(desc.type);
|
||||
if(desc.rows > 1 && desc.columns > 1)
|
||||
format += QFormatStr("%1x%2").arg(desc.rows).arg(desc.columns);
|
||||
else if(desc.columns > 1)
|
||||
format += QString::number(desc.columns);
|
||||
|
||||
if(!desc.name.empty())
|
||||
format += lit(" ") + desc.name;
|
||||
|
||||
if(desc.elements > 1)
|
||||
format += QFormatStr("[%1]").arg(desc.elements);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ResourceFormat &fmt = view.res.viewFormat;
|
||||
if(fmt.type == ResourceFormatType::R10G10B10A2)
|
||||
{
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("uintten");
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormten");
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R11G11B10)
|
||||
{
|
||||
format = lit("floateleven");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(fmt.compByteWidth)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormb");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormb");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("ubyte");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("byte");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormh");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormh");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("ushort");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("short");
|
||||
if(fmt.compType == CompType::Float)
|
||||
format = lit("half");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if(fmt.compType == CompType::UNorm)
|
||||
format = lit("unormf");
|
||||
if(fmt.compType == CompType::SNorm)
|
||||
format = lit("snormf");
|
||||
if(fmt.compType == CompType::UInt)
|
||||
format = lit("uint");
|
||||
if(fmt.compType == CompType::SInt)
|
||||
format = lit("int");
|
||||
if(fmt.compType == CompType::Float)
|
||||
format = lit("float");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(view.res.bufferFlags & D3DBufferViewFlags::Raw)
|
||||
format = lit("xint");
|
||||
|
||||
format += QString::number(fmt.compCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(view.res.bufferFlags & D3DBufferViewFlags::Raw)
|
||||
format = lit("xint");
|
||||
}
|
||||
|
||||
IBufferViewer *viewer = m_Ctx.ViewBuffer(offs, size, view.res.resourceId, format);
|
||||
|
||||
@@ -2117,46 +2117,6 @@ void GLPipelineStateViewer::setState()
|
||||
}
|
||||
}
|
||||
|
||||
QString GLPipelineStateViewer::formatMembers(int indent, const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars)
|
||||
{
|
||||
QString indentstr(indent * 4, QLatin1Char(' '));
|
||||
|
||||
QString ret;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(const ShaderConstant &v : vars)
|
||||
{
|
||||
if(!v.type.members.empty())
|
||||
{
|
||||
if(i > 0)
|
||||
ret += lit("\n");
|
||||
ret += indentstr + QFormatStr("// struct %1\n").arg(v.type.descriptor.name);
|
||||
ret += indentstr + lit("{\n") + formatMembers(indent + 1, v.name + lit("_"), v.type.members) +
|
||||
indentstr + lit("}\n");
|
||||
if(i < vars.count() - 1)
|
||||
ret += lit("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString arr;
|
||||
if(v.type.descriptor.elements > 1)
|
||||
arr = QFormatStr("[%1]").arg(v.type.descriptor.elements);
|
||||
ret += QFormatStr("%1%2 %3%4%5;\n")
|
||||
.arg(indentstr)
|
||||
.arg(v.type.descriptor.name)
|
||||
.arg(nameprefix)
|
||||
.arg(v.name)
|
||||
.arg(arr);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int column)
|
||||
{
|
||||
const GLPipe::Shader *stage = stageForSender(item->treeWidget());
|
||||
@@ -2196,43 +2156,7 @@ void GLPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int c
|
||||
|
||||
const ShaderResource &shaderRes = stage->reflection->readWriteResources[buf.bindPoint];
|
||||
|
||||
QString format = lit("// struct %1\n").arg(shaderRes.variableType.descriptor.name);
|
||||
|
||||
if(shaderRes.variableType.members.count() > 1)
|
||||
{
|
||||
format += tr("// members skipped as they are fixed size:\n");
|
||||
for(int i = 0; i < shaderRes.variableType.members.count() - 1; i++)
|
||||
format += QFormatStr("// %1 %2;\n")
|
||||
.arg(shaderRes.variableType.members[i].type.descriptor.name)
|
||||
.arg(shaderRes.variableType.members[i].name);
|
||||
}
|
||||
|
||||
if(!shaderRes.variableType.members.empty())
|
||||
{
|
||||
format += lit("{\n") +
|
||||
formatMembers(1, QString(), shaderRes.variableType.members.back().type.members) +
|
||||
lit("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &desc = shaderRes.variableType.descriptor;
|
||||
|
||||
format = QString();
|
||||
if(desc.rowMajorStorage)
|
||||
format += lit("row_major ");
|
||||
|
||||
format += ToQStr(desc.type);
|
||||
if(desc.rows > 1 && desc.columns > 1)
|
||||
format += QFormatStr("%1x%2").arg(desc.rows).arg(desc.columns);
|
||||
else if(desc.columns > 1)
|
||||
format += QString::number(desc.columns);
|
||||
|
||||
if(!desc.name.empty())
|
||||
format += lit(" ") + desc.name;
|
||||
|
||||
if(desc.elements > 1)
|
||||
format += QFormatStr("[%1]").arg(desc.elements);
|
||||
}
|
||||
QString format = m_Common.GenerateBufferFormatter(shaderRes, ResourceFormat(), buf.offset);
|
||||
|
||||
if(buf.ID != ResourceId())
|
||||
{
|
||||
|
||||
@@ -39,6 +39,71 @@
|
||||
#include "VulkanPipelineStateViewer.h"
|
||||
#include "ui_PipelineStateViewer.h"
|
||||
|
||||
static uint32_t byteSize(const ResourceFormat &fmt)
|
||||
{
|
||||
if(fmt.Special())
|
||||
{
|
||||
switch(fmt.type)
|
||||
{
|
||||
default:
|
||||
case ResourceFormatType::R9G9B9E5:
|
||||
case ResourceFormatType::R5G6B5:
|
||||
case ResourceFormatType::R5G5B5A1:
|
||||
case ResourceFormatType::R4G4B4A4:
|
||||
case ResourceFormatType::R4G4:
|
||||
case ResourceFormatType::BC1:
|
||||
case ResourceFormatType::BC2:
|
||||
case ResourceFormatType::BC3:
|
||||
case ResourceFormatType::BC4:
|
||||
case ResourceFormatType::BC5:
|
||||
case ResourceFormatType::BC6:
|
||||
case ResourceFormatType::BC7:
|
||||
case ResourceFormatType::ETC2:
|
||||
case ResourceFormatType::EAC:
|
||||
case ResourceFormatType::ASTC:
|
||||
case ResourceFormatType::D16S8:
|
||||
case ResourceFormatType::D24S8:
|
||||
case ResourceFormatType::D32S8:
|
||||
case ResourceFormatType::S8:
|
||||
case ResourceFormatType::YUV8:
|
||||
case ResourceFormatType::YUV10:
|
||||
case ResourceFormatType::YUV12:
|
||||
case ResourceFormatType::YUV16:
|
||||
case ResourceFormatType::PVRTC: return ~0U;
|
||||
case ResourceFormatType::R10G10B10A2:
|
||||
case ResourceFormatType::R11G11B10: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.compByteWidth * fmt.compCount;
|
||||
}
|
||||
|
||||
static QString padding(uint32_t bytes)
|
||||
{
|
||||
if(bytes == 0)
|
||||
return QString();
|
||||
|
||||
QString ret;
|
||||
|
||||
if(bytes > 4)
|
||||
{
|
||||
ret += lit("xint pad[%1];").arg(bytes / 4);
|
||||
|
||||
bytes = bytes % 4;
|
||||
}
|
||||
|
||||
if(bytes == 4)
|
||||
ret += lit("xint pad;");
|
||||
else if(bytes == 3)
|
||||
ret += lit("xshort pad; xbyte pad;");
|
||||
else if(bytes == 2)
|
||||
ret += lit("xshort pad;");
|
||||
else if(bytes == 1)
|
||||
ret += lit("xbyte pad;");
|
||||
|
||||
return ret + lit("\n");
|
||||
}
|
||||
|
||||
PipelineStateViewer::PipelineStateViewer(ICaptureContext &ctx, QWidget *parent)
|
||||
: QFrame(parent), ui(new Ui::PipelineStateViewer), m_Ctx(ctx)
|
||||
{
|
||||
@@ -549,6 +614,241 @@ void PipelineStateViewer::setMeshViewPixmap(RDLabel *meshView)
|
||||
});
|
||||
}
|
||||
|
||||
QString PipelineStateViewer::formatMembers(int indent, int requiredByteStride,
|
||||
const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars)
|
||||
{
|
||||
QString indentstr(indent * 4, QLatin1Char(' '));
|
||||
|
||||
QString ret;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(const ShaderConstant &v : vars)
|
||||
{
|
||||
if(!v.type.members.empty())
|
||||
{
|
||||
if(i > 0)
|
||||
ret += lit("\n");
|
||||
|
||||
if(v.type.descriptor.name == "struct")
|
||||
ret += indentstr + lit("// struct\n");
|
||||
else
|
||||
ret += indentstr + lit("// struct %1\n").arg(v.type.descriptor.name);
|
||||
|
||||
ret += indentstr + lit("{\n") + formatMembers(indent + 1, v.type.descriptor.arrayByteStride,
|
||||
v.name + lit("_"), v.type.members) +
|
||||
indentstr + lit("}\n");
|
||||
if(i < vars.count() - 1)
|
||||
ret += lit("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString arr;
|
||||
if(v.type.descriptor.elements > 1)
|
||||
arr = QFormatStr("[%1]").arg(v.type.descriptor.elements);
|
||||
ret += QFormatStr("%1%2 %3%4%5;\n")
|
||||
.arg(indentstr)
|
||||
.arg(v.type.descriptor.name)
|
||||
.arg(nameprefix)
|
||||
.arg(v.name)
|
||||
.arg(arr);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(requiredByteStride > 0)
|
||||
{
|
||||
uint32_t structStart = 0;
|
||||
|
||||
const ShaderConstant *lastChild = &vars.back();
|
||||
|
||||
structStart += lastChild->byteOffset;
|
||||
while(!lastChild->type.members.isEmpty())
|
||||
{
|
||||
lastChild = &lastChild->type.members.back();
|
||||
structStart += lastChild->byteOffset;
|
||||
}
|
||||
|
||||
uint32_t size = lastChild->type.descriptor.rows * lastChild->type.descriptor.columns;
|
||||
if(lastChild->type.descriptor.type == VarType::Double ||
|
||||
lastChild->type.descriptor.type == VarType::ULong ||
|
||||
lastChild->type.descriptor.type == VarType::SLong)
|
||||
size *= 8;
|
||||
else if(lastChild->type.descriptor.type == VarType::Float ||
|
||||
lastChild->type.descriptor.type == VarType::UInt ||
|
||||
lastChild->type.descriptor.type == VarType::SInt)
|
||||
size *= 4;
|
||||
else if(lastChild->type.descriptor.type == VarType::Half ||
|
||||
lastChild->type.descriptor.type == VarType::UShort ||
|
||||
lastChild->type.descriptor.type == VarType::SShort)
|
||||
size *= 2;
|
||||
|
||||
if(lastChild->type.descriptor.elements > 1)
|
||||
size *= lastChild->type.descriptor.elements;
|
||||
|
||||
uint32_t padBytes = requiredByteStride - (lastChild->byteOffset + size);
|
||||
|
||||
if(padBytes > 0)
|
||||
ret += indentstr + padding(padBytes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString PipelineStateViewer::GenerateBufferFormatter(const ShaderResource &res,
|
||||
const ResourceFormat &viewFormat,
|
||||
uint64_t &baseByteOffset)
|
||||
{
|
||||
QString format;
|
||||
|
||||
if(!res.variableType.members.empty())
|
||||
{
|
||||
const rdcarray<ShaderConstant> *members = &res.variableType.members;
|
||||
|
||||
uint32_t requiredStride = 0;
|
||||
|
||||
if(m_Ctx.APIProps().pipelineType == GraphicsAPI::Vulkan ||
|
||||
m_Ctx.APIProps().pipelineType == GraphicsAPI::OpenGL)
|
||||
{
|
||||
// GL/Vulkan allow fixed-sized members before the array-of-structs. This can't be represented
|
||||
// in a buffer format so we skip it
|
||||
if(members->count() > 1)
|
||||
{
|
||||
format += lit("// %1 members skipped as they are fixed size:\n").arg(res.name);
|
||||
for(int i = 0; i < members->count() - 1; i++)
|
||||
{
|
||||
QString arraySize;
|
||||
if(members->at(i).type.descriptor.elements > 1)
|
||||
arraySize = QFormatStr("[%1]").arg(members->at(i).type.descriptor.elements);
|
||||
format += QFormatStr("// %1 %2%3;\n")
|
||||
.arg(members->at(i).type.descriptor.name)
|
||||
.arg(members->at(i).name)
|
||||
.arg(arraySize);
|
||||
}
|
||||
|
||||
format += lit("// final array struct @ byte offset %1\n{\n").arg(members->back().byteOffset);
|
||||
|
||||
baseByteOffset += members->back().byteOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
format += lit("// struct %1\n{\n").arg(res.name);
|
||||
}
|
||||
|
||||
// if the last member is a struct, remove one level of indirection before declaring the
|
||||
// repeated structure
|
||||
if(!members->back().type.members.isEmpty())
|
||||
{
|
||||
requiredStride = members->back().type.descriptor.arrayByteStride;
|
||||
|
||||
members = &members->back().type.members;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
format = lit("// struct %1\n{\n").arg(res.variableType.descriptor.name);
|
||||
}
|
||||
|
||||
format += formatMembers(1, requiredStride, QString(), *members);
|
||||
format += lit("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &desc = res.variableType.descriptor;
|
||||
|
||||
if(viewFormat.type == ResourceFormatType::Undefined)
|
||||
{
|
||||
if(desc.type == VarType::Unknown)
|
||||
{
|
||||
format = desc.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(desc.rowMajorStorage)
|
||||
format += lit("row_major ");
|
||||
|
||||
format += ToQStr(desc.type);
|
||||
if(desc.rows > 1 && desc.columns > 1)
|
||||
format += QFormatStr("%1x%2").arg(desc.rows).arg(desc.columns);
|
||||
else if(desc.columns > 1)
|
||||
format += QString::number(desc.columns);
|
||||
|
||||
if(!desc.name.empty())
|
||||
format += lit(" ") + desc.name;
|
||||
|
||||
if(desc.elements > 1)
|
||||
format += QFormatStr("[%1]").arg(desc.elements);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(viewFormat.type == ResourceFormatType::R10G10B10A2)
|
||||
{
|
||||
if(viewFormat.compType == CompType::UInt)
|
||||
format = lit("uintten");
|
||||
if(viewFormat.compType == CompType::UNorm)
|
||||
format = lit("unormten");
|
||||
}
|
||||
else if(viewFormat.type == ResourceFormatType::R11G11B10)
|
||||
{
|
||||
format = lit("floateleven");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(viewFormat.compByteWidth)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if(viewFormat.compType == CompType::UNorm)
|
||||
format = lit("unormb");
|
||||
if(viewFormat.compType == CompType::SNorm)
|
||||
format = lit("snormb");
|
||||
if(viewFormat.compType == CompType::UInt)
|
||||
format = lit("ubyte");
|
||||
if(viewFormat.compType == CompType::SInt)
|
||||
format = lit("byte");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if(viewFormat.compType == CompType::UNorm)
|
||||
format = lit("unormh");
|
||||
if(viewFormat.compType == CompType::SNorm)
|
||||
format = lit("snormh");
|
||||
if(viewFormat.compType == CompType::UInt)
|
||||
format = lit("ushort");
|
||||
if(viewFormat.compType == CompType::SInt)
|
||||
format = lit("short");
|
||||
if(viewFormat.compType == CompType::Float)
|
||||
format = lit("half");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if(viewFormat.compType == CompType::UNorm)
|
||||
format = lit("unormf");
|
||||
if(viewFormat.compType == CompType::SNorm)
|
||||
format = lit("snormf");
|
||||
if(viewFormat.compType == CompType::UInt)
|
||||
format = lit("uint");
|
||||
if(viewFormat.compType == CompType::SInt)
|
||||
format = lit("int");
|
||||
if(viewFormat.compType == CompType::Float)
|
||||
format = lit("float");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
format += QString::number(viewFormat.compCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
void PipelineStateViewer::MakeShaderVariablesHLSL(bool cbufferContents,
|
||||
const rdcarray<ShaderConstant> &vars,
|
||||
QString &struct_contents, QString &struct_defs)
|
||||
@@ -920,69 +1220,6 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId
|
||||
button->setMenu(menu);
|
||||
}
|
||||
|
||||
static uint32_t byteSize(const ResourceFormat &fmt)
|
||||
{
|
||||
if(fmt.Special())
|
||||
{
|
||||
switch(fmt.type)
|
||||
{
|
||||
default:
|
||||
case ResourceFormatType::R9G9B9E5:
|
||||
case ResourceFormatType::R5G6B5:
|
||||
case ResourceFormatType::R5G5B5A1:
|
||||
case ResourceFormatType::R4G4B4A4:
|
||||
case ResourceFormatType::R4G4:
|
||||
case ResourceFormatType::BC1:
|
||||
case ResourceFormatType::BC2:
|
||||
case ResourceFormatType::BC3:
|
||||
case ResourceFormatType::BC4:
|
||||
case ResourceFormatType::BC5:
|
||||
case ResourceFormatType::BC6:
|
||||
case ResourceFormatType::BC7:
|
||||
case ResourceFormatType::ETC2:
|
||||
case ResourceFormatType::EAC:
|
||||
case ResourceFormatType::ASTC:
|
||||
case ResourceFormatType::D16S8:
|
||||
case ResourceFormatType::D24S8:
|
||||
case ResourceFormatType::D32S8:
|
||||
case ResourceFormatType::S8:
|
||||
case ResourceFormatType::YUV8:
|
||||
case ResourceFormatType::YUV10:
|
||||
case ResourceFormatType::YUV12:
|
||||
case ResourceFormatType::YUV16:
|
||||
case ResourceFormatType::PVRTC: return ~0U;
|
||||
case ResourceFormatType::R10G10B10A2:
|
||||
case ResourceFormatType::R11G11B10: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.compByteWidth * fmt.compCount;
|
||||
}
|
||||
|
||||
static QString padding(uint32_t bytes)
|
||||
{
|
||||
if(bytes == 0)
|
||||
return QString();
|
||||
|
||||
QString ret;
|
||||
|
||||
if(bytes > 4)
|
||||
{
|
||||
ret += lit("xint pad[%1];").arg(bytes / 4);
|
||||
|
||||
bytes = bytes % 4;
|
||||
}
|
||||
|
||||
if(bytes == 3)
|
||||
ret += lit("xshort pad; xbyte pad;");
|
||||
else if(bytes == 2)
|
||||
ret += lit("xshort pad;");
|
||||
else if(bytes == 1)
|
||||
ret += lit("xbyte pad;");
|
||||
|
||||
return ret + lit("\n");
|
||||
}
|
||||
|
||||
QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
|
||||
{
|
||||
rdcarray<BoundVBuffer> vbs = m_Ctx.CurPipelineState().GetVBuffers();
|
||||
|
||||
@@ -70,6 +70,9 @@ public:
|
||||
void SetupShaderEditButton(QToolButton *button, ResourceId pipelineId, ResourceId shaderId,
|
||||
const ShaderReflection *shaderDetails);
|
||||
|
||||
QString GenerateBufferFormatter(const ShaderResource &res, const ResourceFormat &viewFormat,
|
||||
uint64_t &baseByteOffset);
|
||||
|
||||
QString GetVBufferFormatString(uint32_t slot);
|
||||
|
||||
void setTopologyDiagram(QLabel *diagram, Topology topo);
|
||||
@@ -90,6 +93,9 @@ private:
|
||||
|
||||
QMenu *editMenus[6] = {};
|
||||
|
||||
QString formatMembers(int indent, int requiredByteStride, const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars);
|
||||
|
||||
QString GenerateHLSLStub(const ShaderReflection *shaderDetails, const QString &entryFunc);
|
||||
IShaderViewer *EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry,
|
||||
ShaderCompileFlags compileFlags, ShaderEncoding encoding,
|
||||
|
||||
@@ -75,16 +75,18 @@ struct VulkanBufferTag
|
||||
bindPoint = 0;
|
||||
offset = size = 0;
|
||||
}
|
||||
VulkanBufferTag(bool rw, uint32_t b, ResourceId id, uint64_t offs, uint64_t sz)
|
||||
VulkanBufferTag(bool rw, uint32_t b, ResourceFormat f, ResourceId id, uint64_t offs, uint64_t sz)
|
||||
{
|
||||
rwRes = rw;
|
||||
bindPoint = b;
|
||||
ID = id;
|
||||
fmt = f;
|
||||
offset = offs;
|
||||
size = sz;
|
||||
}
|
||||
bool rwRes;
|
||||
uint32_t bindPoint;
|
||||
ResourceFormat fmt;
|
||||
ResourceId ID;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
@@ -1056,8 +1058,9 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails,
|
||||
if(descriptorLen == UINT64_MAX)
|
||||
descriptorLen = len - descriptorBind->byteOffset;
|
||||
|
||||
tag = QVariant::fromValue(VulkanBufferTag(isrw, bindPoint, buf->resourceId,
|
||||
descriptorBind->byteOffset, descriptorLen));
|
||||
tag = QVariant::fromValue(VulkanBufferTag(isrw, bindPoint, descriptorBind->viewFormat,
|
||||
buf->resourceId, descriptorBind->byteOffset,
|
||||
descriptorLen));
|
||||
|
||||
isbuf = true;
|
||||
}
|
||||
@@ -1973,7 +1976,7 @@ void VulkanPipelineStateViewer::setState()
|
||||
length, s.counterBufferResourceId, (qulonglong)s.counterBufferOffset, QString()});
|
||||
|
||||
node->setTag(QVariant::fromValue(
|
||||
VulkanBufferTag(false, ~0U, s.bufferResourceId, s.byteOffset, length)));
|
||||
VulkanBufferTag(false, ~0U, ResourceFormat(), s.bufferResourceId, s.byteOffset, length)));
|
||||
|
||||
if(!filledSlot)
|
||||
setEmptyRow(node);
|
||||
@@ -2391,46 +2394,6 @@ void VulkanPipelineStateViewer::setState()
|
||||
}
|
||||
}
|
||||
|
||||
QString VulkanPipelineStateViewer::formatMembers(int indent, const QString &nameprefix,
|
||||
const rdcarray<ShaderConstant> &vars)
|
||||
{
|
||||
QString indentstr(indent * 4, QLatin1Char(' '));
|
||||
|
||||
QString ret = QString();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(const ShaderConstant &v : vars)
|
||||
{
|
||||
if(!v.type.members.isEmpty())
|
||||
{
|
||||
if(i > 0)
|
||||
ret += lit("\n");
|
||||
ret += indentstr + lit("// struct %1\n").arg(v.type.descriptor.name);
|
||||
ret += indentstr + lit("{\n") + formatMembers(indent + 1, v.name + lit("_"), v.type.members) +
|
||||
indentstr + lit("}\n");
|
||||
if(i < vars.count() - 1)
|
||||
ret += lit("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString arr = QString();
|
||||
if(v.type.descriptor.elements > 1)
|
||||
arr = QFormatStr("[%1]").arg(v.type.descriptor.elements);
|
||||
ret += QFormatStr("%1%2 %3%4%5;\n")
|
||||
.arg(indentstr)
|
||||
.arg(v.type.descriptor.name)
|
||||
.arg(nameprefix)
|
||||
.arg(v.name)
|
||||
.arg(arr);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VulkanPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int column)
|
||||
{
|
||||
const VKPipe::Shader *stage = stageForSender(item->treeWidget());
|
||||
@@ -2478,41 +2441,7 @@ void VulkanPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, i
|
||||
? stage->reflection->readWriteResources[buf.bindPoint]
|
||||
: stage->reflection->readOnlyResources[buf.bindPoint];
|
||||
|
||||
format = lit("// struct %1\n").arg(shaderRes.variableType.descriptor.name);
|
||||
|
||||
if(shaderRes.variableType.members.count() > 1)
|
||||
{
|
||||
format += lit("// members skipped as they are fixed size:\n");
|
||||
for(int i = 0; i < shaderRes.variableType.members.count() - 1; i++)
|
||||
format += QFormatStr("// %1 %2;\n")
|
||||
.arg(shaderRes.variableType.members[i].type.descriptor.name)
|
||||
.arg(shaderRes.variableType.members[i].name);
|
||||
}
|
||||
|
||||
if(!shaderRes.variableType.members.isEmpty())
|
||||
{
|
||||
format += lit("{\n") + formatMembers(1, QString(), shaderRes.variableType.members) + lit("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &desc = shaderRes.variableType.descriptor;
|
||||
|
||||
format = QString();
|
||||
if(desc.rowMajorStorage)
|
||||
format += lit("row_major ");
|
||||
|
||||
format += ToQStr(desc.type);
|
||||
if(desc.rows > 1 && desc.columns > 1)
|
||||
format += QFormatStr("%1x%2").arg(desc.rows).arg(desc.columns);
|
||||
else if(desc.columns > 1)
|
||||
format += QString::number(desc.columns);
|
||||
|
||||
if(!desc.name.isEmpty())
|
||||
format += lit(" ") + desc.name;
|
||||
|
||||
if(desc.elements > 1)
|
||||
format += QFormatStr("[%1]").arg(desc.elements);
|
||||
}
|
||||
format = m_Common.GenerateBufferFormatter(shaderRes, buf.fmt, buf.offset);
|
||||
}
|
||||
|
||||
if(buf.ID != ResourceId())
|
||||
|
||||
@@ -636,19 +636,19 @@ struct ShaderVariableDescriptor
|
||||
return false;
|
||||
}
|
||||
DOCUMENT("The :class:`VarType` that this basic constant stores.");
|
||||
VarType type;
|
||||
VarType type = VarType::Unknown;
|
||||
DOCUMENT("The number of rows in this matrix.");
|
||||
uint8_t rows;
|
||||
uint8_t rows = 1;
|
||||
DOCUMENT("The number of columns in this matrix.");
|
||||
uint8_t columns;
|
||||
uint8_t columns = 1;
|
||||
DOCUMENT("The number of bytes between the start of one column/row in a matrix and the next.");
|
||||
uint8_t matrixByteStride;
|
||||
uint8_t matrixByteStride = 0;
|
||||
DOCUMENT("``True`` if the matrix is stored as row major instead of column major.");
|
||||
bool rowMajorStorage;
|
||||
bool rowMajorStorage = false;
|
||||
DOCUMENT("The number of elements in the array, or 1 if it's not an array.");
|
||||
uint32_t elements;
|
||||
uint32_t elements = 1;
|
||||
DOCUMENT("The number of bytes between the start of one element in the array and the next.");
|
||||
uint32_t arrayByteStride;
|
||||
uint32_t arrayByteStride = 0;
|
||||
DOCUMENT("The name of the type of this constant, e.g. a ``struct`` name.");
|
||||
rdcstr name;
|
||||
};
|
||||
|
||||
@@ -799,6 +799,8 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
|
||||
bool multiDimArray = false;
|
||||
int arrayIdx = 0;
|
||||
|
||||
bool blockLevel = true;
|
||||
|
||||
// reverse figure out structures and structure arrays
|
||||
while(strchr(nm, '.') || strchr(nm, '['))
|
||||
{
|
||||
@@ -856,6 +858,9 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
|
||||
parentVar.type.descriptor.arrayByteStride = topLevelStride;
|
||||
parentVar.type.descriptor.matrixByteStride = 0;
|
||||
|
||||
if(!blockLevel)
|
||||
topLevelStride = 0;
|
||||
|
||||
bool found = false;
|
||||
|
||||
// if we can find the base variable already, we recurse into its members
|
||||
@@ -873,6 +878,8 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
|
||||
parentmembers = &((*parentmembers)[i].type.members);
|
||||
found = true;
|
||||
|
||||
blockLevel = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1001,6 +1008,15 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
|
||||
}
|
||||
}
|
||||
|
||||
void MakeChildByteOffsetsRelative(ShaderConstant &member)
|
||||
{
|
||||
for(ShaderConstant &child : member.type.members)
|
||||
{
|
||||
MakeChildByteOffsetsRelative(child);
|
||||
child.byteOffset -= member.byteOffset;
|
||||
}
|
||||
}
|
||||
|
||||
int ParseVersionStatement(const char *version)
|
||||
{
|
||||
if(strncmp(version, "#version", 8))
|
||||
@@ -1633,57 +1649,29 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref
|
||||
{
|
||||
sort(members[ssbo]);
|
||||
|
||||
// account for padding for std430 layout, if we have a root array of
|
||||
// structs, we need to pad the struct up to have the correct alignment
|
||||
if(members[ssbo].size() == 1 && !members[ssbo][0].type.members.empty() &&
|
||||
members[ssbo][0].type.descriptor.arrayByteStride != 0)
|
||||
std::swap(rwresources[ssbos[ssbo]].variableType.members, members[ssbo][0].type.members);
|
||||
}
|
||||
|
||||
// patch-up reflection data. For top-level arrays use the stride & rough size to calculate the
|
||||
// number of elements, and make all child byteOffset values relative to their parent
|
||||
for(size_t ssbo = 0; ssbo < ssbos.size(); ssbo++)
|
||||
{
|
||||
rdcarray<ShaderConstant> &ssboVars = rwresources[ssbo].variableType.members;
|
||||
for(size_t rootMember = 0; rootMember + 1 < ssboVars.size(); rootMember++)
|
||||
{
|
||||
// now that we're sorted, see what the tightly packed stride would be by looking at the last
|
||||
// member
|
||||
uint32_t desiredStride = members[ssbo][0].type.descriptor.arrayByteStride;
|
||||
ShaderConstant &member = ssboVars[rootMember];
|
||||
|
||||
ShaderConstant *last = &members[ssbo][0].type.members.back();
|
||||
while(!last->type.members.empty())
|
||||
last = &last->type.members.back();
|
||||
const uint32_t memberSizeBound = ssboVars[rootMember + 1].byteOffset - member.byteOffset;
|
||||
const uint32_t stride = member.type.descriptor.arrayByteStride;
|
||||
|
||||
// start from the offset
|
||||
uint32_t stride = last->byteOffset;
|
||||
|
||||
// add its size
|
||||
uint32_t size = last->type.descriptor.rows * last->type.descriptor.columns * 4;
|
||||
if(last->type.descriptor.type == VarType::Double)
|
||||
size *= 2;
|
||||
|
||||
if(last->type.descriptor.elements > 1)
|
||||
size *= last->type.descriptor.elements;
|
||||
|
||||
stride += size;
|
||||
|
||||
if(stride < desiredStride)
|
||||
if(stride != 0 && member.type.descriptor.elements <= 1 && memberSizeBound > 2 * stride)
|
||||
{
|
||||
uint32_t padding = desiredStride - stride;
|
||||
|
||||
RDCASSERT((padding % 4) == 0 && padding <= 16, padding);
|
||||
|
||||
padding /= 4;
|
||||
|
||||
ShaderConstant paddingVar;
|
||||
paddingVar.name = "__padding";
|
||||
paddingVar.byteOffset = last->byteOffset + size;
|
||||
paddingVar.type.descriptor.type = VarType::UInt;
|
||||
paddingVar.type.descriptor.rows = 1;
|
||||
paddingVar.type.descriptor.columns = (uint8_t)RDCMIN(padding, 255U);
|
||||
paddingVar.type.descriptor.elements = 1;
|
||||
paddingVar.type.descriptor.rowMajorStorage = false;
|
||||
paddingVar.type.descriptor.arrayByteStride = 0;
|
||||
paddingVar.type.descriptor.matrixByteStride = 0;
|
||||
paddingVar.type.descriptor.name = StringFormat::Fmt("uint%u", padding);
|
||||
|
||||
members[ssbo][0].type.members.push_back(paddingVar);
|
||||
member.type.descriptor.elements = memberSizeBound / stride;
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(rwresources[ssbos[ssbo]].variableType.members, members[ssbo]);
|
||||
for(ShaderConstant &member : ssboVars)
|
||||
MakeChildByteOffsetsRelative(member);
|
||||
}
|
||||
|
||||
delete[] members;
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11_test.h"
|
||||
|
||||
struct D3D11_Structured_Buffer_Nested : D3D11GraphicsTest
|
||||
{
|
||||
static constexpr const char *Description =
|
||||
"Test reading from structured buffers with nested structs";
|
||||
|
||||
std::string pixel = R"EOSHADER(
|
||||
|
||||
struct supernest
|
||||
{
|
||||
float x;
|
||||
};
|
||||
|
||||
struct nest
|
||||
{
|
||||
float3 v;
|
||||
supernest s;
|
||||
float a, b, c;
|
||||
};
|
||||
|
||||
struct mystruct
|
||||
{
|
||||
nest n[3];
|
||||
float4 p;
|
||||
};
|
||||
|
||||
StructuredBuffer<mystruct> buf1 : register(t0);
|
||||
Buffer<float3> buf2 : register(t1);
|
||||
RWBuffer<float4> out_buf : register(u1);
|
||||
|
||||
float4 main() : SV_Target0
|
||||
{
|
||||
int idx = 0;
|
||||
out_buf[idx++] = buf1[0].p;
|
||||
out_buf[idx++] = buf1[1].p;
|
||||
out_buf[idx++] = buf1[2].p;
|
||||
out_buf[idx++] = float4(buf1[0].n[0].v, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[3].n[1].v, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[6].n[2].v, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[4].n[0].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[5].n[1].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[7].n[2].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++] = float4(buf1[8].n[1].s.x, 0.0f, 0.0f, 1.0f);
|
||||
idx++;
|
||||
out_buf[idx++] = float4(buf2[3], 1.0f);
|
||||
out_buf[idx++] = float4(buf2[4], 1.0f);
|
||||
out_buf[idx++] = float4(buf2[5], 1.0f);
|
||||
return 1.0f.xxxx;
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// initialise, create window, create device, etc
|
||||
if(!Init(argc, argv))
|
||||
return 3;
|
||||
|
||||
ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_5_0");
|
||||
ID3DBlobPtr psblob = Compile(pixel, "main", "ps_5_0");
|
||||
|
||||
CreateDefaultInputLayout(vsblob);
|
||||
|
||||
ID3D11VertexShaderPtr vs = CreateVS(vsblob);
|
||||
ID3D11PixelShaderPtr ps = CreatePS(psblob);
|
||||
|
||||
ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(DefaultTri);
|
||||
|
||||
float data[16 * 100];
|
||||
|
||||
for(int i = 0; i < 16 * 100; i++)
|
||||
data[i] = float(i);
|
||||
|
||||
ID3D11BufferPtr structbuf = MakeBuffer().Structured(25 * sizeof(float)).Data(data).SRV();
|
||||
ID3D11ShaderResourceViewPtr structbufSRV = MakeSRV(structbuf);
|
||||
|
||||
ID3D11BufferPtr typedbuf = MakeBuffer().Data(data).SRV();
|
||||
ID3D11ShaderResourceViewPtr typedbufSRV = MakeSRV(typedbuf).Format(DXGI_FORMAT_R32G32B32_FLOAT);
|
||||
|
||||
ID3D11BufferPtr outbuf = MakeBuffer().Structured(4 * sizeof(float)).Size(1024).UAV();
|
||||
ID3D11UnorderedAccessViewPtr outbufUAV = MakeUAV(outbuf);
|
||||
|
||||
while(Running())
|
||||
{
|
||||
ClearRenderTargetView(bbRTV, {0.4f, 0.5f, 0.6f, 1.0f});
|
||||
|
||||
IASetVertexBuffer(vb, sizeof(DefaultA2V), 0);
|
||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->IASetInputLayout(defaultLayout);
|
||||
|
||||
ctx->VSSetShader(vs, NULL, 0);
|
||||
ctx->PSSetShader(ps, NULL, 0);
|
||||
|
||||
ID3D11ShaderResourceView *srvs[] = {structbufSRV, typedbufSRV};
|
||||
|
||||
ctx->PSSetShaderResources(0, 2, srvs);
|
||||
|
||||
RSSetViewport({0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
|
||||
|
||||
float zeros[4] = {};
|
||||
ctx->ClearUnorderedAccessViewFloat(outbufUAV, zeros);
|
||||
|
||||
ctx->OMSetRenderTargetsAndUnorderedAccessViews(1, &bbRTV.GetInterfacePtr(), NULL, 1, 1,
|
||||
&outbufUAV.GetInterfacePtr(), NULL);
|
||||
|
||||
ctx->Draw(3, 0);
|
||||
|
||||
Present();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(D3D11_Structured_Buffer_Nested);
|
||||
@@ -141,6 +141,7 @@
|
||||
<ClCompile Include="d3d11\d3d11_streamout.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_stripped_shaders.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_structured_buffer_misaligned_dirty.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_structured_buffer_nested.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_structured_buffer_read.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_test.cpp" />
|
||||
<ClCompile Include="d3d11\d3d11_texture_3d.cpp" />
|
||||
@@ -174,6 +175,7 @@
|
||||
<ClCompile Include="gl\gl_separable_geometry_shader.cpp" />
|
||||
<ClCompile Include="gl\gl_simple_triangle.cpp" />
|
||||
<ClCompile Include="gl\gl_spirv_shader.cpp" />
|
||||
<ClCompile Include="gl\gl_structured_buffer_nested.cpp" />
|
||||
<ClCompile Include="gl\gl_test.cpp" />
|
||||
<ClCompile Include="gl\gl_test_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
@@ -196,6 +198,7 @@
|
||||
<ClCompile Include="vk\vk_draw_zoo.cpp" />
|
||||
<ClCompile Include="vk\vk_helpers.cpp" />
|
||||
<ClCompile Include="vk\vk_indirect.cpp" />
|
||||
<ClCompile Include="vk\vk_structured_buffer_nested.cpp" />
|
||||
<ClCompile Include="vk\vk_overlay_test.cpp" />
|
||||
<ClCompile Include="vk\vk_sample_locations.cpp" />
|
||||
<ClCompile Include="vk\vk_adv_cbuffer_zoo.cpp" />
|
||||
|
||||
@@ -255,6 +255,15 @@
|
||||
<ClCompile Include="vk\vk_adv_cbuffer_zoo.cpp">
|
||||
<Filter>Vulkan\demos</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="d3d11\d3d11_structured_buffer_nested.cpp">
|
||||
<Filter>D3D11\demos</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vk\vk_structured_buffer_nested.cpp">
|
||||
<Filter>Vulkan\demos</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl\gl_structured_buffer_nested.cpp">
|
||||
<Filter>OpenGL\demos</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D11">
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2019 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "gl_test.h"
|
||||
|
||||
struct GL_Structured_Buffer_Nested : OpenGLGraphicsTest
|
||||
{
|
||||
static constexpr const char *Description =
|
||||
"Just draws a simple triangle, using normal pipeline. Basic test that can be used "
|
||||
"for any dead-simple tests that don't require any particular API use";
|
||||
|
||||
std::string common = R"EOSHADER(
|
||||
|
||||
#version 430 core
|
||||
|
||||
#define v2f v2f_block \
|
||||
{ \
|
||||
vec4 pos; \
|
||||
vec4 col; \
|
||||
vec4 uv; \
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string vertex = R"EOSHADER(
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec4 Color;
|
||||
layout(location = 2) in vec2 UV;
|
||||
|
||||
out v2f vertOut;
|
||||
|
||||
void main()
|
||||
{
|
||||
vertOut.pos = vec4(Position.xyz, 1);
|
||||
gl_Position = vertOut.pos;
|
||||
vertOut.col = Color;
|
||||
vertOut.uv = vec4(UV.xy, 0, 1);
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string pixel = R"EOSHADER(
|
||||
|
||||
in v2f vertIn;
|
||||
|
||||
layout(location = 0, index = 0) out vec4 Color;
|
||||
|
||||
struct supernest
|
||||
{
|
||||
float x;
|
||||
};
|
||||
|
||||
struct nest
|
||||
{
|
||||
vec3 v;
|
||||
supernest s;
|
||||
float a, b, c;
|
||||
};
|
||||
|
||||
layout(binding = 0, std430) buffer nest_struct_buffer
|
||||
{
|
||||
nest n[3];
|
||||
vec4 p;
|
||||
nest rtarray[];
|
||||
} nestbuf;
|
||||
|
||||
layout(binding = 1) uniform samplerBuffer plainbuf;
|
||||
|
||||
layout(binding = 2, std430) buffer struct_buffer
|
||||
{
|
||||
nest rtarray[];
|
||||
} structbuf;
|
||||
|
||||
layout(binding = 3, std430) buffer output_buffer
|
||||
{
|
||||
vec4 dump[];
|
||||
} out_buf;
|
||||
|
||||
void main()
|
||||
{
|
||||
int idx = 0;
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[1].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[2].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[2].s.x, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = nestbuf.p;
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[3].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[6].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[4].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[5].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[7].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[8].s.x, 0.0f, 0.0f, 1.0f);
|
||||
idx++;
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 3);
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 4);
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 5);
|
||||
idx++;
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[3].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[6].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[4].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[5].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[7].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[8].s.x, 0.0f, 0.0f, 1.0f);
|
||||
Color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// initialise, create window, create context, etc
|
||||
if(!Init(argc, argv))
|
||||
return 3;
|
||||
|
||||
GLuint vao = MakeVAO();
|
||||
glBindVertexArray(vao);
|
||||
|
||||
GLuint vb = MakeBuffer();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vb);
|
||||
glBufferStorage(GL_ARRAY_BUFFER, sizeof(DefaultTri), DefaultTri, 0);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(0));
|
||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(sizeof(Vec3f)));
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V),
|
||||
(void *)(sizeof(Vec3f) + sizeof(Vec4f)));
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
GLuint program = MakeProgram(common + vertex, common + pixel);
|
||||
glObjectLabel(GL_PROGRAM, program, -1, "Full program");
|
||||
|
||||
float data[16 * 100];
|
||||
|
||||
for(int i = 0; i < 16 * 100; i++)
|
||||
data[i] = float(i);
|
||||
|
||||
GLuint buf = MakeBuffer();
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buf);
|
||||
glBufferStorage(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, 0);
|
||||
|
||||
GLuint outbuf = MakeBuffer();
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, outbuf);
|
||||
glBufferStorage(GL_SHADER_STORAGE_BUFFER, 1024, NULL, 0);
|
||||
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buf);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buf);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, outbuf);
|
||||
|
||||
GLuint tbuf_store = MakeBuffer();
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, tbuf_store);
|
||||
glBufferStorage(GL_TEXTURE_BUFFER, sizeof(data), data, 0);
|
||||
|
||||
GLuint tbuf = MakeTexture();
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tbuf);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, tbuf_store);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tbuf);
|
||||
|
||||
while(Running())
|
||||
{
|
||||
float zeros[4] = {};
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, outbuf);
|
||||
glClearBufferSubData(GL_SHADER_STORAGE_BUFFER, GL_RGBA32F, 0, 1024, GL_RGBA, GL_FLOAT, zeros);
|
||||
|
||||
float col[] = {0.4f, 0.5f, 0.6f, 1.0f};
|
||||
glClearBufferfv(GL_COLOR, 0, col);
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight));
|
||||
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buf);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
Present();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(GL_Structured_Buffer_Nested);
|
||||
@@ -487,6 +487,23 @@ struct ImageViewCreateInfo : public VkImageViewCreateInfo
|
||||
operator const VkImageViewCreateInfo *() const { return this; }
|
||||
};
|
||||
|
||||
struct BufferViewCreateInfo : public VkBufferViewCreateInfo
|
||||
{
|
||||
BufferViewCreateInfo(VkBuffer buffer, VkFormat format, VkDeviceSize offset = 0,
|
||||
VkDeviceSize range = VK_WHOLE_SIZE)
|
||||
{
|
||||
sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
||||
pNext = NULL;
|
||||
this->flags = 0;
|
||||
this->buffer = buffer;
|
||||
this->format = format;
|
||||
this->offset = offset;
|
||||
this->range = range;
|
||||
}
|
||||
|
||||
operator const VkBufferViewCreateInfo *() const { return this; }
|
||||
};
|
||||
|
||||
struct BufferCreateInfo : public VkBufferCreateInfo
|
||||
{
|
||||
BufferCreateInfo(VkDeviceSize size, VkBufferUsageFlags usage, VkBufferCreateFlags flags = 0,
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2019 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "vk_test.h"
|
||||
|
||||
struct VK_Structured_Buffer_Nested : VulkanGraphicsTest
|
||||
{
|
||||
static constexpr const char *Description =
|
||||
"Just draws a simple triangle, using normal pipeline. Basic test that can be used "
|
||||
"for any dead-simple tests that don't require any particular API use";
|
||||
|
||||
std::string common = R"EOSHADER(
|
||||
|
||||
#version 450 core
|
||||
|
||||
struct v2f
|
||||
{
|
||||
vec4 pos;
|
||||
vec4 col;
|
||||
vec4 uv;
|
||||
};
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
const std::string vertex = R"EOSHADER(
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec4 Color;
|
||||
layout(location = 2) in vec2 UV;
|
||||
|
||||
layout(location = 0) out v2f vertOut;
|
||||
|
||||
void main()
|
||||
{
|
||||
vertOut.pos = vec4(Position.xyz*vec3(1,-1,1), 1);
|
||||
gl_Position = vertOut.pos;
|
||||
vertOut.col = Color;
|
||||
vertOut.uv = vec4(UV.xy, 0, 1);
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
const std::string glslpixel = R"EOSHADER(
|
||||
|
||||
layout(location = 0) in v2f vertIn;
|
||||
|
||||
layout(location = 0, index = 0) out vec4 Color;
|
||||
|
||||
struct supernest
|
||||
{
|
||||
float x;
|
||||
};
|
||||
|
||||
struct nest
|
||||
{
|
||||
vec3 v;
|
||||
supernest s;
|
||||
float a, b, c;
|
||||
};
|
||||
|
||||
layout(binding = 0, std430) buffer nest_struct_buffer
|
||||
{
|
||||
nest n[3];
|
||||
vec4 p;
|
||||
nest rtarray[];
|
||||
} nestbuf;
|
||||
|
||||
layout(binding = 1) uniform samplerBuffer plainbuf;
|
||||
|
||||
layout(binding = 2, std430) buffer struct_buffer
|
||||
{
|
||||
nest rtarray[];
|
||||
} structbuf;
|
||||
|
||||
layout(binding = 3, std430) buffer output_buffer
|
||||
{
|
||||
vec4 dump[];
|
||||
} out_buf;
|
||||
|
||||
void main()
|
||||
{
|
||||
int idx = 0;
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[1].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[2].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.n[2].s.x, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = nestbuf.p;
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[3].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[6].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[4].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[5].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[7].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(nestbuf.rtarray[8].s.x, 0.0f, 0.0f, 1.0f);
|
||||
idx++;
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 3);
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 4);
|
||||
out_buf.dump[idx++] = texelFetch(plainbuf, 5);
|
||||
idx++;
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[0].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[3].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[6].v, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[4].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[5].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[7].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf.dump[idx++] = vec4(structbuf.rtarray[8].s.x, 0.0f, 0.0f, 1.0f);
|
||||
Color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string hlslpixel = R"EOSHADER(
|
||||
|
||||
struct supernest
|
||||
{
|
||||
float x;
|
||||
};
|
||||
|
||||
struct nest
|
||||
{
|
||||
float3 v;
|
||||
supernest s;
|
||||
float a, b, c;
|
||||
};
|
||||
|
||||
struct mystruct
|
||||
{
|
||||
nest n[3];
|
||||
float3 p;
|
||||
};
|
||||
|
||||
StructuredBuffer<mystruct> buf1 : register(t0);
|
||||
Buffer<float3> buf2 : register(t1);
|
||||
|
||||
struct dump
|
||||
{
|
||||
float4 val;
|
||||
};
|
||||
|
||||
RWStructuredBuffer<dump> out_buf : register(u3);
|
||||
|
||||
float4 main() : SV_Target0
|
||||
{
|
||||
int idx = 0;
|
||||
out_buf[idx++].val = float4(buf1[0].p, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[1].p, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[2].p, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[0].n[0].v, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[3].n[1].v, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[6].n[2].v, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[4].n[0].a, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[5].n[1].b, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[7].n[2].c, 0.0f, 0.0f, 1.0f);
|
||||
out_buf[idx++].val = float4(buf1[8].n[1].s.x, 0.0f, 0.0f, 1.0f);
|
||||
idx++;
|
||||
out_buf[idx++].val = float4(buf2[3], 1.0f);
|
||||
out_buf[idx++].val = float4(buf2[4], 1.0f);
|
||||
out_buf[idx++].val = float4(buf2[5], 1.0f);
|
||||
return 1.0f.xxxx;
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
features.fragmentStoresAndAtomics = true;
|
||||
|
||||
// initialise, create window, create context, etc
|
||||
if(!Init(argc, argv))
|
||||
return 3;
|
||||
|
||||
VkDescriptorSetLayout setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({
|
||||
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
}));
|
||||
|
||||
VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout}));
|
||||
|
||||
vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
|
||||
|
||||
pipeCreateInfo.layout = layout;
|
||||
pipeCreateInfo.renderPass = swapRenderPass;
|
||||
|
||||
pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, DefaultA2V)};
|
||||
pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = {
|
||||
vkh::vertexAttr(0, 0, DefaultA2V, pos), vkh::vertexAttr(1, 0, DefaultA2V, col),
|
||||
vkh::vertexAttr(2, 0, DefaultA2V, uv),
|
||||
};
|
||||
|
||||
pipeCreateInfo.stages = {
|
||||
CompileShaderModule(common + vertex, ShaderLang::glsl, ShaderStage::vert, "main"),
|
||||
CompileShaderModule(common + glslpixel, ShaderLang::glsl, ShaderStage::frag, "main"),
|
||||
};
|
||||
|
||||
VkPipeline glslpipe = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
pipeCreateInfo.stages[1] =
|
||||
CompileShaderModule(hlslpixel, ShaderLang::hlsl, ShaderStage::frag, "main");
|
||||
|
||||
VkPipeline hlslpipe = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
AllocatedBuffer vb(
|
||||
allocator, vkh::BufferCreateInfo(sizeof(DefaultTri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
|
||||
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
|
||||
|
||||
vb.upload(DefaultTri);
|
||||
|
||||
float data[16 * 100];
|
||||
|
||||
for(int i = 0; i < 16 * 100; i++)
|
||||
data[i] = float(i);
|
||||
|
||||
AllocatedBuffer ssbo(
|
||||
allocator, vkh::BufferCreateInfo(sizeof(data), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT),
|
||||
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
|
||||
|
||||
ssbo.upload(data);
|
||||
|
||||
AllocatedBuffer out_ssbo(allocator,
|
||||
vkh::BufferCreateInfo(1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
|
||||
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
|
||||
|
||||
VkDescriptorSet descset = allocateDescriptorSet(setlayout);
|
||||
|
||||
VkBufferView bufview =
|
||||
createBufferView(vkh::BufferViewCreateInfo(ssbo.buffer, VK_FORMAT_R32G32B32_SFLOAT));
|
||||
|
||||
vkh::updateDescriptorSets(
|
||||
device,
|
||||
{
|
||||
vkh::WriteDescriptorSet(descset, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
{vkh::DescriptorBufferInfo(ssbo.buffer)}),
|
||||
vkh::WriteDescriptorSet(descset, 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, {bufview}),
|
||||
vkh::WriteDescriptorSet(descset, 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
{vkh::DescriptorBufferInfo(ssbo.buffer)}),
|
||||
vkh::WriteDescriptorSet(descset, 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
{vkh::DescriptorBufferInfo(out_ssbo.buffer)}),
|
||||
});
|
||||
|
||||
while(Running())
|
||||
{
|
||||
VkCommandBuffer cmd = GetCommandBuffer();
|
||||
|
||||
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
|
||||
|
||||
VkImage swapimg =
|
||||
StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL,
|
||||
vkh::ClearColorValue(0.4f, 0.5f, 0.6f, 1.0f), 1,
|
||||
vkh::ImageSubresourceRange());
|
||||
|
||||
vkh::cmdPipelineBarrier(
|
||||
cmd, {},
|
||||
{
|
||||
vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, out_ssbo.buffer),
|
||||
});
|
||||
|
||||
vkCmdFillBuffer(cmd, out_ssbo.buffer, 0, 1024, 0);
|
||||
|
||||
vkh::cmdPipelineBarrier(
|
||||
cmd, {},
|
||||
{
|
||||
vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
out_ssbo.buffer),
|
||||
});
|
||||
|
||||
vkCmdBeginRenderPass(
|
||||
cmd, vkh::RenderPassBeginInfo(swapRenderPass, swapFramebuffers[swapIndex], scissor),
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe);
|
||||
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {});
|
||||
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||
vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0});
|
||||
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
vkh::cmdPipelineBarrier(
|
||||
cmd, {},
|
||||
{
|
||||
vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
out_ssbo.buffer),
|
||||
});
|
||||
|
||||
vkCmdBeginRenderPass(
|
||||
cmd, vkh::RenderPassBeginInfo(swapRenderPass, swapFramebuffers[swapIndex], scissor),
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, hlslpipe);
|
||||
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {});
|
||||
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
vkEndCommandBuffer(cmd);
|
||||
|
||||
Submit(0, 1, {cmd});
|
||||
|
||||
Present();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(VK_Structured_Buffer_Nested);
|
||||
@@ -445,6 +445,9 @@ VulkanGraphicsTest::~VulkanGraphicsTest()
|
||||
for(VkImageView view : imageviews)
|
||||
vkDestroyImageView(device, view, NULL);
|
||||
|
||||
for(VkBufferView view : bufferviews)
|
||||
vkDestroyBufferView(device, view, NULL);
|
||||
|
||||
for(VkPipelineLayout layout : pipelayouts)
|
||||
vkDestroyPipelineLayout(device, layout, NULL);
|
||||
|
||||
@@ -748,6 +751,14 @@ VkImageView VulkanGraphicsTest::createImageView(const VkImageViewCreateInfo *inf
|
||||
return ret;
|
||||
}
|
||||
|
||||
VkBufferView VulkanGraphicsTest::createBufferView(const VkBufferViewCreateInfo *info)
|
||||
{
|
||||
VkBufferView ret;
|
||||
CHECK_VKR(vkCreateBufferView(device, info, NULL, &ret));
|
||||
bufferviews.push_back(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VkPipelineLayout VulkanGraphicsTest::createPipelineLayout(const VkPipelineLayoutCreateInfo *info)
|
||||
{
|
||||
VkPipelineLayout ret;
|
||||
|
||||
@@ -172,6 +172,7 @@ struct VulkanGraphicsTest : public GraphicsTest
|
||||
VkFramebuffer createFramebuffer(const VkFramebufferCreateInfo *info);
|
||||
VkRenderPass createRenderPass(const VkRenderPassCreateInfo *info);
|
||||
VkImageView createImageView(const VkImageViewCreateInfo *info);
|
||||
VkBufferView createBufferView(const VkBufferViewCreateInfo *info);
|
||||
VkPipelineLayout createPipelineLayout(const VkPipelineLayoutCreateInfo *info);
|
||||
VkDescriptorSetLayout createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *info);
|
||||
|
||||
@@ -225,6 +226,7 @@ struct VulkanGraphicsTest : public GraphicsTest
|
||||
std::vector<VkFramebuffer> framebuffers;
|
||||
std::vector<VkRenderPass> renderpasses;
|
||||
std::vector<VkImageView> imageviews;
|
||||
std::vector<VkBufferView> bufferviews;
|
||||
std::vector<VkPipelineLayout> pipelayouts;
|
||||
std::vector<VkDescriptorSetLayout> setlayouts;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user