Implement mesh viewer support for task/mesh shaders

This commit is contained in:
baldurk
2023-10-26 12:50:20 +01:00
parent d898e2ac09
commit 1df7c1ae81
20 changed files with 1481 additions and 551 deletions
+10
View File
@@ -133,6 +133,14 @@ DOCUMENT(R"(Specifies the panel to add a menu item into.
Adds the item to the context menu for GS/Tess output in the mesh previewing :class:`BufferViewer`.
.. data:: MeshPreview_TaskOutVertex
Adds the item to the context menu for task shader output in the mesh previewing :class:`BufferViewer`.
.. data:: MeshPreview_MeshOutVertex
Adds the item to the context menu for mesh shader output in the mesh previewing :class:`BufferViewer`.
.. data:: TextureViewer_Thumbnail
Adds the item to the context menu for all thumbnails in the :class:`TextureViewer`.
@@ -153,6 +161,8 @@ enum class ContextMenu
MeshPreview_VSInVertex,
MeshPreview_VSOutVertex,
MeshPreview_GSOutVertex,
MeshPreview_TaskOutVertex,
MeshPreview_MeshOutVertex,
TextureViewer_Thumbnail,
TextureViewer_InputThumbnail,
TextureViewer_OutputThumbnail,
File diff suppressed because it is too large Load Diff
+29 -9
View File
@@ -169,7 +169,7 @@ private:
IReplayOutput *m_Output;
void updateWindowTitle();
void updateLabelsAndLayout();
void configureDrawRange();
@@ -183,12 +183,12 @@ private:
MeshDataStage m_CurStage;
// cached data from PostVS data
MeshFormat m_PostVS, m_PostGS;
MeshFormat m_Out1Data, m_Out2Data;
// the configurations for 3D preview
MeshFormat m_VSInPosition, m_VSInSecondary;
MeshFormat m_PostVSPosition, m_PostVSSecondary;
MeshFormat m_PostGSPosition, m_PostGSSecondary;
MeshFormat m_InPosition, m_InSecondary;
MeshFormat m_Out1Position, m_Out1Secondary;
MeshFormat m_Out2Position, m_Out2Secondary;
QMutex m_BBoxLock;
QMap<uint32_t, BBoxData> m_BBoxes;
@@ -198,6 +198,8 @@ private:
void UI_UpdateBoundingBox(const CalcBoundingBoxData &bbox);
void UI_UpdateBoundingBoxLabels(int compCount = 0);
void UI_AddTaskPayloads(RDTreeWidgetItem *root, size_t baseOffset,
const rdcarray<ShaderConstant> &consts, BufferData *buffer);
void UI_AddFixedVariables(RDTreeWidgetItem *root, uint32_t baseOffset,
const rdcarray<ShaderConstant> &consts,
const rdcarray<ShaderVariable> &vars);
@@ -242,9 +244,24 @@ private:
bool m_MeshView;
BufferItemModel *m_ModelVSIn;
BufferItemModel *m_ModelVSOut;
BufferItemModel *m_ModelGSOut;
// for ease of reading, these stages are named as in, out1, and out2. Note however that this does
// NOT correspond to which table widgets these fill out. Since it is most common to look at VS In
// and VS Out for classic vertex pipeline draws, and Task Out and Mesh Out for mesh shader draws
// (and because mesh shader input visualisation is not natively available) we pair up VS In and
// Task Out on the same control, VS Out and Mesh Out on the same control, and GS/Tess Out and Mesh
// In on the same control.
// the input stage
BufferItemModel *m_ModelIn;
// the first output stage (vertex, or task)
BufferItemModel *m_ModelOut1;
// the second output stage (geometry, or mesh)
BufferItemModel *m_ModelOut2;
// the container widgets for each stage which are remapped depending on the draw type to one of
// the above. This may mean 1:1 for traditional draws or [0] being out1 (task out), [1] being out2
// (mesh out) and [2] being in
QWidget *m_Containers[3] = {};
PopulateBufferData *m_Scrolls = NULL;
@@ -300,6 +317,7 @@ private:
BufferItemModel *currentBufferModel() { return modelForStage(m_CurStage); }
bool isCurrentRasterOut();
int currentStageIndex();
bool isMeshDraw();
void SetupMeshView();
void SetupRawView();
@@ -311,7 +329,9 @@ private:
void ClearModels();
void UI_CalculateMeshFormats();
void UI_ConfigureFormats();
void UI_ConfigureVertexPipeFormats();
void UI_ConfigureMeshPipeFormats();
void UpdateCurrentMeshConfig();
void EnableCameraGuessControls();
+6 -6
View File
@@ -41,7 +41,7 @@
<bool>false</bool>
</attribute>
</widget>
<widget class="RDTableView" name="vsinData">
<widget class="RDTableView" name="inTable">
<property name="geometry">
<rect>
<x>60</x>
@@ -78,7 +78,7 @@
<bool>false</bool>
</attribute>
</widget>
<widget class="RDTableView" name="vsoutData">
<widget class="RDTableView" name="out1Table">
<property name="geometry">
<rect>
<x>280</x>
@@ -130,7 +130,7 @@
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QWidget" name="vsinTab">
<widget class="QWidget" name="inTab">
<attribute name="title">
<string>VS In</string>
</attribute>
@@ -681,7 +681,7 @@ Enter 0.0 to use automatic/guessed value derived from data.</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="vsoutTab">
<widget class="QWidget" name="out1Tab">
<attribute name="title">
<string>VS Out</string>
</attribute>
@@ -703,7 +703,7 @@ Enter 0.0 to use automatic/guessed value derived from data.</string>
</property>
</layout>
</widget>
<widget class="QWidget" name="gsoutTab">
<widget class="QWidget" name="out2Tab">
<attribute name="title">
<string>GS/DS Out</string>
</attribute>
@@ -726,7 +726,7 @@ Enter 0.0 to use automatic/guessed value derived from data.</string>
</layout>
</widget>
</widget>
<widget class="RDTableView" name="gsoutData">
<widget class="RDTableView" name="out2Table">
<property name="geometry">
<rect>
<x>500</x>
+7 -1
View File
@@ -172,10 +172,16 @@ vec3 CalcCubeCoord(vec2 uv, int face)
#endif
// first few match SolidShade enum
#define MESHDISPLAY_SOLID 0x1
#define MESHDISPLAY_FACELIT 0x2
#define MESHDISPLAY_SECONDARY 0x3
#define MESHDISPLAY_SECONDARY_ALPHA 0x4
#define MESHDISPLAY_MESHLET 0x4
// extra values below
#define MESHDISPLAY_SECONDARY_ALPHA 0x5
#define MAX_NUM_MESHLETS (512 * 1024)
#define TEXDISPLAY_TYPEMASK 0xF
#define TEXDISPLAY_UINT_TEX 0x10
+13
View File
@@ -41,11 +41,24 @@ BINDING(0) uniform MeshUBOData
uint rawoutput;
uint flipY;
vec2 padding;
uvec4 meshletColours[12];
}
INST_NAME(Mesh);
#endif // defined(MESH_UBO) || defined(__cplusplus)
#if defined(MESH_UBO) && defined(VULKAN)
layout(binding = 1, std140) readonly buffer meshlet_data
{
uint meshletCount;
uint meshletOffset;
uvec4 data[];
}
meshlet;
#endif // defined(MESH_UBO)
#if defined(CHECKER_UBO) || defined(__cplusplus)
BINDING(0) uniform CheckerboardUBOData
+1 -1
View File
@@ -46,7 +46,7 @@ void main(void)
{
int type = Mesh.displayFormat;
if(type == MESHDISPLAY_SECONDARY)
if(type == MESHDISPLAY_SECONDARY || type == MESHDISPLAY_MESHLET)
{
color_out = vec4(SECONDARY_NAME.xyz, 1);
}
+66
View File
@@ -42,6 +42,69 @@ IO_LOCATION(1) in SECONDARY_TYPE vsin_secondary;
IO_LOCATION(0) out vec4 vsout_secondary;
IO_LOCATION(1) out vec4 vsout_norm;
#ifdef VULKAN
uint getMeshletCountAt(uint m)
{
uint vecIdx = m / 4;
if((m % 4) == 0)
return meshlet.data[vecIdx].x;
else if((m % 4) == 1)
return meshlet.data[vecIdx].y;
else if((m % 4) == 2)
return meshlet.data[vecIdx].z;
else if((m % 4) == 3)
return meshlet.data[vecIdx].w;
}
vec4 getMeshletColor()
{
uint searchIdx = VERTEX_ID;
// array of prefix summed counts accessible via getMeshletCountAt [x, x+y, x+y+z, ...] we do a
// binary search to find which meshlet this index corresponds to
uint first = 0, last = meshlet.meshletCount - 1;
uint count = last - first;
while(count > 0)
{
uint halfrange = count / 2;
uint mid = first + halfrange;
if(searchIdx < getMeshletCountAt(mid))
{
count = halfrange;
}
else
{
first = mid + 1;
count -= halfrange + 1;
}
}
uint meshletIndex = first;
if(VERTEX_ID < getMeshletCountAt(meshletIndex))
{
meshletIndex += meshlet.meshletOffset;
meshletIndex %= 48;
uvec4 meshletColor = Mesh.meshletColours[meshletIndex / 4];
if((meshletIndex % 4) == 0)
return unpackUnorm4x8(meshletColor.x);
else if((meshletIndex % 4) == 1)
return unpackUnorm4x8(meshletColor.y);
else if((meshletIndex % 4) == 2)
return unpackUnorm4x8(meshletColor.z);
else if((meshletIndex % 4) == 3)
return unpackUnorm4x8(meshletColor.w);
}
return vec4(0, 0, 0, 1);
}
#endif
void main(void)
{
vec2 psprite[4] =
@@ -65,6 +128,9 @@ void main(void)
vsout_norm = vec4(0, 0, 1, 1);
#ifdef VULKAN
if(Mesh.displayFormat == MESHDISPLAY_MESHLET)
vsout_secondary = getMeshletColor();
// GL->VK conventions
gl_Position.y = -gl_Position.y;
if(Mesh.flipY == 1)
+15 -2
View File
@@ -106,8 +106,15 @@ cbuffer MeshVertexCBuffer REG(b0)
row_major float4x4 ModelViewProj;
float2 SpriteSize;
uint homogenousInput;
uint vertMeshDisplayFormat;
uint meshletOffset;
uint meshletCount;
uint padding1;
uint padding2;
uint4 meshletColours[12];
};
cbuffer MeshGeometryCBuffer REG(b0)
@@ -243,10 +250,16 @@ cbuffer DebugSampleOperation REG(b0)
#define RESTYPE_DEPTH_STENCIL_MS 0x7
#define RESTYPE_TEX2D_MS 0x9
// first few match SolidShade enum
#define MESHDISPLAY_SOLID 0x1
#define MESHDISPLAY_FACELIT 0x2
#define MESHDISPLAY_SECONDARY 0x3
#define MESHDISPLAY_SECONDARY_ALPHA 0x4
#define MESHDISPLAY_MESHLET 0x4
// extra values below
#define MESHDISPLAY_SECONDARY_ALPHA 0x5
#define MAX_NUM_MESHLETS (512 * 1024)
#define TEXDISPLAY_TYPEMASK 0xF
#define TEXDISPLAY_NANS 0x0100
+77 -1
View File
@@ -37,6 +37,79 @@ struct meshA2V
float4 secondary : sec;
};
StructuredBuffer<uint4> meshletSizesBuf : register(t0);
float4 unpackUnorm4x8(uint value)
{
uint4 shifted = uint4(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, value >> 24);
return float4(shifted) / 255.0;
}
uint getMeshletCountAt(uint m)
{
uint vecIdx = m / 4;
uint count = 0;
if((m % 4) == 0)
count = meshletSizesBuf[vecIdx].x;
else if((m % 4) == 1)
count = meshletSizesBuf[vecIdx].y;
else if((m % 4) == 2)
count = meshletSizesBuf[vecIdx].z;
else if((m % 4) == 3)
count = meshletSizesBuf[vecIdx].w;
return count;
}
float4 getMeshletColor(uint vid)
{
uint searchIdx = vid;
// array of prefix summed counts accessible via getMeshletCountAt [x, x+y, x+y+z, ...] we do a
// binary search to find which meshlet this index corresponds to
uint first = 0, last = meshletCount - 1;
uint count = last - first;
while(count > 0)
{
uint halfrange = count / 2;
uint mid = first + halfrange;
if(searchIdx < getMeshletCountAt(mid))
{
count = halfrange;
}
else
{
first = mid + 1;
count -= halfrange + 1;
}
}
uint meshletIndex = first;
float4 col = float4(0, 0, 0, 1);
if(vid < getMeshletCountAt(meshletIndex))
{
meshletIndex += meshletOffset;
meshletIndex %= 48;
uint4 meshletColor = meshletColours[meshletIndex / 4];
if((meshletIndex % 4) == 0)
col = unpackUnorm4x8(meshletColor.x);
else if((meshletIndex % 4) == 1)
col = unpackUnorm4x8(meshletColor.y);
else if((meshletIndex % 4) == 2)
col = unpackUnorm4x8(meshletColor.z);
else if((meshletIndex % 4) == 3)
col = unpackUnorm4x8(meshletColor.w);
}
return col;
}
meshV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID)
{
meshV2F OUT = (meshV2F)0;
@@ -56,6 +129,9 @@ meshV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID)
OUT.norm = float3(0, 0, 1);
OUT.secondary = IN.secondary;
if(vertMeshDisplayFormat == MESHDISPLAY_MESHLET)
OUT.secondary = getMeshletColor(vid);
return OUT;
}
@@ -128,7 +204,7 @@ float4 RENDERDOC_MeshPS(meshV2F IN)
{
uint type = MeshDisplayFormat;
if(type == MESHDISPLAY_SECONDARY)
if(type == MESHDISPLAY_SECONDARY || type == MESHDISPLAY_MESHLET)
return float4(IN.secondary.xyz, 1);
else if(type == MESHDISPLAY_SECONDARY_ALPHA)
return float4(IN.secondary.www, 1);
@@ -267,6 +267,12 @@ void D3D11Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
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;
+71
View File
@@ -275,6 +275,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
cbvParam(D3D12_SHADER_VISIBILITY_GEOMETRY, 0, 0),
// 'push constant' CBV
constParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0, 4),
// meshlet sizes SRV
srvParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
},
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
@@ -308,6 +310,41 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
{}, "ps_5_0", &m_MeshPS);
}
{
D3D12_RESOURCE_DESC meshletSizeBuf = {};
meshletSizeBuf.Alignment = 0;
meshletSizeBuf.DepthOrArraySize = 1;
meshletSizeBuf.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
meshletSizeBuf.Flags = D3D12_RESOURCE_FLAG_NONE;
meshletSizeBuf.Format = DXGI_FORMAT_UNKNOWN;
meshletSizeBuf.Height = 1;
meshletSizeBuf.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
meshletSizeBuf.MipLevels = 1;
meshletSizeBuf.SampleDesc.Count = 1;
meshletSizeBuf.SampleDesc.Quality = 0;
meshletSizeBuf.Width = sizeof(uint32_t) * (4 + MAX_NUM_MESHLETS);
D3D12_HEAP_PROPERTIES heapProps;
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &meshletSizeBuf,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
__uuidof(ID3D12Resource), (void **)&m_MeshletBuf);
m_pDevice->InternalRef();
if(FAILED(hr))
{
RDCERR("Failed to create meshlet size buffer, HRESULT: %s", ToStr(hr).c_str());
}
if(m_MeshletBuf)
m_MeshletBuf->SetName(L"m_MeshletBuf");
}
{
rdcstr hlsl = GetEmbeddedResource(misc_hlsl);
@@ -508,6 +545,7 @@ D3D12DebugManager::~D3D12DebugManager()
SAFE_RELEASE(m_MeshGS);
SAFE_RELEASE(m_MeshPS);
SAFE_RELEASE(m_MeshRootSig);
SAFE_RELEASE(m_MeshletBuf);
SAFE_RELEASE(m_ShaderDebugRootSig);
SAFE_RELEASE(m_MathIntrinsicsPso);
@@ -925,6 +963,39 @@ D3D12_GPU_VIRTUAL_ADDRESS D3D12DebugManager::UploadConstants(const void *data, s
return ret;
}
D3D12_GPU_VIRTUAL_ADDRESS D3D12DebugManager::UploadMeshletSizes(uint32_t meshletIndexOffset,
const rdcarray<MeshletSize> &sizes)
{
D3D12_GPU_VIRTUAL_ADDRESS ret = m_MeshletBuf->GetGPUVirtualAddress();
if(sizes.empty())
return ret;
rdcarray<uint32_t> data;
data.resize(sizes.size());
uint32_t prefixCount = meshletIndexOffset;
for(size_t i = 0; i < data.size(); i++)
{
prefixCount += sizes[i].numVertices;
data[i] = prefixCount;
}
if(m_CurMeshletOffset + data.byteSize() > m_MeshletBuf->GetDesc().Width)
m_CurMeshletOffset = 0;
ret += m_CurMeshletOffset;
// passing the unwrapped object here is immaterial as all we do is Map/Unmap, but it means we can
// call this function while capturing without worrying about serialising the map or deadlocking.
FillBuffer(Unwrap(m_MeshletBuf), (size_t)m_CurMeshletOffset, data.data(), data.byteSize());
m_CurMeshletOffset += data.byteSize();
m_CurMeshletOffset =
AlignUp(m_CurMeshletOffset, (UINT64)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
return ret;
}
ID3D12GraphicsCommandListX *D3D12DebugManager::ResetDebugList()
{
m_DebugList->Reset(m_DebugAlloc, NULL);
+5
View File
@@ -156,6 +156,8 @@ public:
ID3D12Resource *MakeCBuffer(UINT64 size);
void FillBuffer(ID3D12Resource *buf, size_t offset, const void *data, size_t size);
D3D12_GPU_VIRTUAL_ADDRESS UploadConstants(const void *data, size_t size);
D3D12_GPU_VIRTUAL_ADDRESS UploadMeshletSizes(uint32_t meshletIndexOffset,
const rdcarray<MeshletSize> &sizes);
ID3D12RootSignature *GetMeshRootSig() { return m_MeshRootSig; }
ID3D12RootSignature *GetShaderDebugRootSig() { return m_ShaderDebugRootSig; }
@@ -244,6 +246,9 @@ private:
ID3D12RootSignature *m_MeshRootSig = NULL;
std::map<uint64_t, MeshDisplayPipelines> m_CachedMeshPipelines;
ID3D12Resource *m_MeshletBuf = NULL;
UINT64 m_CurMeshletOffset = 0;
// Shader debugging resources
ID3D12RootSignature *m_ShaderDebugRootSig = NULL;
ID3D12PipelineState *m_MathIntrinsicsPso = NULL;
+30 -1
View File
@@ -275,6 +275,7 @@ 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.vertMeshDisplayFormat = MESHDISPLAY_SOLID;
MeshPixelCBuffer pixelData;
@@ -305,9 +306,16 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}
memcpy(&vertexData.meshletColours[0].x, uniqueColors, sizeof(uniqueColors));
RDCCOMPILE_ASSERT(sizeof(vertexData.meshletColours) == sizeof(uniqueColors),
"Unique colors array is wrongly sized");
D3D12_GPU_VIRTUAL_ADDRESS vsCB =
GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData));
D3D12_GPU_VIRTUAL_ADDRESS meshletBuf = GetDebugManager()->UploadMeshletSizes(
cfg.position.meshletIndexOffset, cfg.position.meshletSizes);
if(!secondaryDraws.empty())
{
D3D12MarkerRegion region(list, "Secondary draws");
@@ -329,6 +337,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootSignature(rootSig);
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB); // geometry - dummy fill
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
}
pixelData.MeshColour.x = fmt.meshColor.x;
@@ -460,6 +469,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
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;
}
pixelData.MeshDisplayFormat = (int)cfg.solidShadeMode;
@@ -470,7 +480,20 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetPipelineState(pipe);
list->SetGraphicsRootSignature(cache.rootsig);
list->SetGraphicsRootConstantBufferView(0, vsCB);
size_t numMeshlets = RDCMIN(cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);
if(cfg.solidShadeMode == SolidShade::Meshlet)
{
vertexData.meshletCount = (uint32_t)numMeshlets;
vertexData.meshletOffset = (uint32_t)cfg.position.meshletOffset;
vertexData.vertMeshDisplayFormat = MESHDISPLAY_MESHLET;
}
D3D12_GPU_VIRTUAL_ADDRESS vsCBSolid =
GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData));
list->SetGraphicsRootConstantBufferView(0, vsCBSolid);
if(solidShadeMode == SolidShade::Lit)
{
@@ -484,6 +507,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
{
list->SetGraphicsRootConstantBufferView(1, vsCB); // dummy fill for geometry
}
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
Vec4f colour(0.8f, 0.8f, 0.0f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
@@ -530,6 +554,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB);
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
pixelData.MeshColour.x = cfg.position.meshColor.x;
pixelData.MeshColour.y = cfg.position.meshColor.y;
@@ -625,6 +650,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB);
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
list->DrawInstanced(24, 1, 0, 0);
}
@@ -652,6 +678,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB);
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
pixelData.MeshColour = Vec3f(1.0f, 0.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
@@ -706,6 +733,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB);
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
list->DrawInstanced(24, 1, 0, 0);
}
@@ -776,6 +804,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secon
list->SetGraphicsRootConstantBufferView(
0, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData)));
list->SetGraphicsRootShaderResourceView(3, meshletBuf);
list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]);
+16 -5
View File
@@ -3989,13 +3989,19 @@ void VulkanReplay::OverlayRendering::Destroy(WrappedVulkan *driver)
void VulkanReplay::MeshRendering::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool)
{
CREATE_OBJECT(DescSetLayout,
{{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL}});
CREATE_OBJECT(
DescSetLayout,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT, NULL},
});
CREATE_OBJECT(PipeLayout, DescSetLayout, 0);
CREATE_OBJECT(DescSet, descriptorPool, DescSetLayout);
UBO.Create(driver, driver->GetDev(), sizeof(MeshUBOData), 16, 0);
MeshletSSBO.Create(driver, driver->GetDev(), sizeof(uint32_t) * (4 + MAX_NUM_MESHLETS), 16,
GPUBuffer::eGPUBufferSSBO);
BBoxVB.Create(driver, driver->GetDev(), sizeof(Vec4f) * 128, 16, GPUBuffer::eGPUBufferVBuffer);
Vec4f TLN = Vec4f(-1.0f, 1.0f, 0.0f, 1.0f); // TopLeftNear, etc...
@@ -4057,13 +4063,17 @@ void VulkanReplay::MeshRendering::Init(WrappedVulkan *driver, VkDescriptorPool d
AxisFrustumVB.Unmap();
VkDescriptorBufferInfo meshrender = {};
VkDescriptorBufferInfo meshubo = {};
VkDescriptorBufferInfo meshssbo = {};
UBO.FillDescriptor(meshrender);
UBO.FillDescriptor(meshubo);
MeshletSSBO.FillDescriptor(meshssbo);
VkWriteDescriptorSet writes[] = {
{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(DescSet), 0, 0, 1,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, NULL, &meshrender, NULL},
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, NULL, &meshubo, NULL},
{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(DescSet), 1, 0, 1,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, NULL, &meshssbo, NULL},
};
VkDevice dev = driver->GetDev();
@@ -4078,6 +4088,7 @@ void VulkanReplay::MeshRendering::Destroy(WrappedVulkan *driver)
UBO.Destroy();
BBoxVB.Destroy();
MeshletSSBO.Destroy();
AxisFrustumVB.Destroy();
driver->vkDestroyDescriptorSetLayout(driver->GetDev(), DescSetLayout, NULL);
+61 -34
View File
@@ -526,6 +526,8 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}
uint32_t dynOffs[2] = {};
if(!secondaryDraws.empty())
{
size_t mapsUsed = 0;
@@ -537,8 +539,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(fmt.vertexResourceId != ResourceId())
{
// TODO should move the color to a push constant so we don't have to map all the time
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -584,7 +585,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(secondaryCache.pipes[VKMeshDisplayPipelines::ePipe_WireDepth]));
@@ -702,14 +703,14 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
case SolidShade::Secondary:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_Secondary];
break;
case SolidShade::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];
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -726,11 +727,42 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
if(solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA;
if(solidShadeMode == SolidShade::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)
return;
if(cfg.position.meshletSizes.size() > MAX_NUM_MESHLETS)
RDCWARN("Too many meshlets: %zu, only colouring first %zu of them",
cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);
meshletCounts[0] = (uint32_t)numMeshlets;
meshletCounts[1] = (uint32_t)cfg.position.meshletOffset;
meshletCounts += 4;
uint32_t prefixCount = cfg.position.meshletIndexOffset;
for(size_t i = 0; i < numMeshlets; i++)
{
prefixCount += cfg.position.meshletSizes[i].numVertices;
meshletCounts[i] = prefixCount;
}
memcpy(&data->meshletColours[0].x, uniqueColors, sizeof(uniqueColors));
RDCCOMPILE_ASSERT(sizeof(data->meshletColours) == sizeof(uniqueColors),
"Unique colors array is wrongly sized");
m_MeshRender.MeshletSSBO.Unmap();
}
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe));
@@ -764,8 +796,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
Vec4f wireCol =
Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f);
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -780,7 +811,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_WireDepth]));
@@ -858,8 +889,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.buf), &vboffs);
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -874,7 +904,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_WireDepth]));
@@ -888,8 +918,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
VkDeviceSize vboffs = 0;
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.AxisFrustumVB.buf), &vboffs);
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -904,7 +933,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Wire]));
@@ -912,7 +941,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdDraw(Unwrap(cmd), 2, 1, 0, 0);
// poke the color (this would be a good candidate for a push constant)
data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -927,10 +956,10 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdDraw(Unwrap(cmd), 2, 1, 2, 0);
data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -945,7 +974,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdDraw(Unwrap(cmd), 2, 1, 4, 0);
}
@@ -955,8 +984,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
VkDeviceSize vboffs = sizeof(Vec4f) * 6; // skim the axis helpers
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.AxisFrustumVB.buf), &vboffs);
uint32_t uboOffs = 0;
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
@@ -971,7 +999,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Wire]));
@@ -1067,8 +1095,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
uniforms.homogenousInput = cfg.position.unproject;
uniforms.pointSpriteSize = Vec2f(0.0f, 0.0f);
uint32_t uboOffs = 0;
MeshUBOData *ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
MeshUBOData *ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
@@ -1076,7 +1103,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Solid]));
@@ -1087,14 +1114,14 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
// Draw active primitive (red)
uniforms.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(&uboOffs);
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(activePrim.size() >= primSize)
{
@@ -1115,14 +1142,14 @@ 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);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0)
{
@@ -1151,14 +1178,14 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
// Draw active vertex (blue)
uniforms.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(&uboOffs);
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
// vertices are drawn with tri strips
helper.topology = Topology::TriangleStrip;
@@ -1173,7 +1200,7 @@ void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &seco
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Solid]));
@@ -1196,14 +1223,14 @@ 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);
// poke the color (this would be a good candidate for a push constant)
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&uboOffs);
ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = uniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 1, &uboOffs);
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(!inactiveVertices.empty())
{
+1
View File
@@ -682,6 +682,7 @@ private:
void Destroy(WrappedVulkan *driver);
GPUBuffer UBO;
GPUBuffer MeshletSSBO;
GPUBuffer BBoxVB;
GPUBuffer AxisFrustumVB;
+1 -1
View File
@@ -301,7 +301,7 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver)
GenerateGLSLShader(source, ShaderType::Vulkan, 430, defines), blob);
// if we missed the inputHash, make a copy there too.
if(m_CacheShaders)
if(m_CacheShaders && blob)
{
m_ShaderCache[inputHash] = new rdcarray<uint32_t>(*blob);
m_ShaderCacheDirty = true;
+11
View File
@@ -1345,6 +1345,17 @@ const Vec4f colorRamp[22] = {
Vec4f(1.000000f, 0.878431f, 1.000000f, 1.0f), Vec4f(1.000000f, 1.000000f, 1.000000f, 1.0f),
};
// unique colors generated from https://mokole.com/palette.html
const uint32_t uniqueColors[48] = {
0xff00008b, 0xff32cd32, 0xff8fbc8f, 0xff8b008b, 0xffb03060, 0xffd2b48c, 0xff9932cc, 0xffff0000,
0xffff8c00, 0xffffd700, 0xff00ff00, 0xff00ff7f, 0xff4169e1, 0xffe9967a, 0xffdc143c, 0xff00ffff,
0xff00bfff, 0xff0000ff, 0xffa020f0, 0xffadff2f, 0xffff6347, 0xffda70d6, 0xffff00ff, 0xfff0e68c,
0xffffff54, 0xff6495ed, 0xffdda0dd, 0xff90ee90, 0xff87ceeb, 0xffff1493, 0xff7fffd4, 0xffff69b4,
0xff808080, 0xffc0c0c0, 0xff2f4f4f, 0xff556b2f, 0xff8b4513, 0xff6b8e23, 0xff2e8b57, 0xff8b0000,
0xff483d8b, 0xff008000, 0xffb8860b, 0xff008b8b, 0xff4682b4, 0xffd2691e, 0xff9acd32, 0xffcd5c5c,
};
bytebuf GetDiscardPattern(DiscardType type, const ResourceFormat &fmt, uint32_t rowPitch, bool invert)
{
static const rdcliteral patterns[] = {
+1
View File
@@ -352,6 +352,7 @@ struct HighlightCache
};
extern const Vec4f colorRamp[22];
extern const uint32_t uniqueColors[48];
enum class DiscardType : int
{