mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-21 14:06:45 +00:00
Fix support for triangle fans on GL/Vulkan
This commit is contained in:
@@ -62,6 +62,7 @@ Maths & Utilities
|
||||
.. autofunction:: renderdoc.VertexOffset
|
||||
.. autofunction:: renderdoc.PatchList_Count
|
||||
.. autofunction:: renderdoc.PatchList_Topology
|
||||
.. autofunction:: renderdoc.SupportsRestart
|
||||
.. autofunction:: renderdoc.IsStrip
|
||||
.. autofunction:: renderdoc.IsD3D
|
||||
.. autofunction:: renderdoc.MaskForStage
|
||||
|
||||
@@ -2071,7 +2071,7 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
|
||||
ClearModels();
|
||||
|
||||
if(m_Ctx.CurPipelineState().IsStripRestartEnabled() && draw &&
|
||||
(draw->flags & DrawFlags::Indexed) && IsStrip(draw->topology))
|
||||
(draw->flags & DrawFlags::Indexed) && SupportsRestart(draw->topology))
|
||||
{
|
||||
bufdata->vsinConfig.primRestart = m_Ctx.CurPipelineState().GetStripRestartIndex();
|
||||
|
||||
@@ -2091,9 +2091,6 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
|
||||
float vpWidth = qAbs(vp.width);
|
||||
float vpHeight = qAbs(vp.height);
|
||||
|
||||
m_Config.position.allowRestart = m_Ctx.CurPipelineState().IsStripRestartEnabled();
|
||||
m_Config.position.restartIndex = m_Ctx.CurPipelineState().GetStripRestartIndex();
|
||||
|
||||
m_Config.fov = ui->fovGuess->value();
|
||||
m_Config.aspect = (vpWidth > 0.0f && vpHeight > 0.0f) ? (vpWidth / vpHeight) : 1.0f;
|
||||
m_Config.highlightVert = 0;
|
||||
@@ -2526,6 +2523,11 @@ void BufferViewer::UI_CalculateMeshFormats()
|
||||
m_VSInPosition = MeshFormat();
|
||||
m_VSInSecondary = MeshFormat();
|
||||
|
||||
m_VSInPosition.allowRestart = m_Ctx.CurPipelineState().IsStripRestartEnabled() &&
|
||||
(draw->flags & DrawFlags::Indexed) &&
|
||||
SupportsRestart(draw->topology);
|
||||
m_VSInPosition.restartIndex = m_Ctx.CurPipelineState().GetStripRestartIndex();
|
||||
|
||||
const BufferConfiguration &vsinConfig = m_ModelVSIn->getConfig();
|
||||
|
||||
if(!vsinConfig.columns.empty())
|
||||
@@ -2629,6 +2631,9 @@ void BufferViewer::UI_CalculateMeshFormats()
|
||||
}
|
||||
}
|
||||
|
||||
m_PostVSPosition.allowRestart = m_VSInPosition.allowRestart;
|
||||
m_PostVSPosition.restartIndex = m_VSInPosition.restartIndex;
|
||||
|
||||
const BufferConfiguration &gsoutConfig = m_ModelGSOut->getConfig();
|
||||
|
||||
m_PostGSPosition = MeshFormat();
|
||||
@@ -2654,6 +2659,8 @@ void BufferViewer::UI_CalculateMeshFormats()
|
||||
}
|
||||
}
|
||||
|
||||
m_PostGSPosition.allowRestart = false;
|
||||
|
||||
m_PostGSPosition.indexByteStride = 0;
|
||||
|
||||
if(!(draw->flags & DrawFlags::Indexed))
|
||||
|
||||
@@ -1812,6 +1812,22 @@ constexpr inline uint32_t PatchList_Count(Topology topology)
|
||||
: uint32_t(topology) - uint32_t(Topology::PatchList_1CPs) + 1;
|
||||
}
|
||||
|
||||
DOCUMENT(R"(Check whether or not this topology supports primitive restart.
|
||||
|
||||
.. note:: This is almost but not quite the same as being a line/triangle strip - triangle fans
|
||||
also support restart. See also :func:`IsStrip`.
|
||||
|
||||
:param Topology t: The topology to check.
|
||||
:return: ``True`` if it describes a topology that allows restart, ``False`` for a list.
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
constexpr inline bool SupportsRestart(Topology topology)
|
||||
{
|
||||
return topology == Topology::LineStrip || topology == Topology::TriangleStrip ||
|
||||
topology == Topology::LineStrip_Adj || topology == Topology::TriangleStrip_Adj ||
|
||||
topology == Topology::TriangleFan;
|
||||
}
|
||||
|
||||
DOCUMENT(R"(Check whether or not this is a strip-type topology.
|
||||
|
||||
:param Topology t: The topology to check.
|
||||
|
||||
@@ -65,6 +65,9 @@ bool TriangleRayIntersect(vec3 A, vec3 B, vec3 C, vec3 RayPosition, vec3 RayDire
|
||||
{
|
||||
bool Result = false;
|
||||
|
||||
if(A == B || A == C || B == C)
|
||||
return false;
|
||||
|
||||
vec3 v0v1 = B - A;
|
||||
vec3 v0v2 = C - A;
|
||||
vec3 pvec = cross(RayDirection, v0v2);
|
||||
@@ -161,23 +164,21 @@ void trianglePath(uint threadID)
|
||||
bool hit;
|
||||
if(meshpick.unproject == 1u)
|
||||
{
|
||||
hit = TriangleRayIntersect(pos0.xyz / pos0.w, pos1.xyz / pos1.w, pos2.xyz / pos2.w,
|
||||
meshpick.rayPos, meshpick.rayDir,
|
||||
/*out*/ hitPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
hit = TriangleRayIntersect(pos0.xyz, pos1.xyz, pos2.xyz, meshpick.rayPos, meshpick.rayDir,
|
||||
/*out*/ hitPosition);
|
||||
pos0.xyz /= pos0.w;
|
||||
pos1.xyz /= pos1.w;
|
||||
pos2.xyz /= pos2.w;
|
||||
}
|
||||
|
||||
hit = TriangleRayIntersect(pos0.xyz, pos1.xyz, pos2.xyz, meshpick.rayPos, meshpick.rayDir,
|
||||
/*out*/ hitPosition);
|
||||
|
||||
// ray hit a triangle, so return the vertex that was closest
|
||||
// to the triangle/ray intersection point
|
||||
if(hit)
|
||||
{
|
||||
float dist0 = distance(pos0.xyz / pos0.w, hitPosition);
|
||||
float dist1 = distance(pos1.xyz / pos1.w, hitPosition);
|
||||
float dist2 = distance(pos2.xyz / pos2.w, hitPosition);
|
||||
float dist0 = distance(pos0.xyz, hitPosition);
|
||||
float dist1 = distance(pos1.xyz, hitPosition);
|
||||
float dist2 = distance(pos2.xyz, hitPosition);
|
||||
|
||||
uint result_idx = atomicAdd(pickresult.counter, 1u);
|
||||
|
||||
|
||||
@@ -144,6 +144,9 @@ bool TriangleRayIntersect(float3 A, float3 B, float3 C, float3 RayPosition, floa
|
||||
{
|
||||
bool Result = false;
|
||||
|
||||
if(all(A == B) || all(A == C) || all(B == C))
|
||||
return false;
|
||||
|
||||
float3 v0v1 = B - A;
|
||||
float3 v0v2 = C - A;
|
||||
float3 pvec = cross(RayDirection, v0v2);
|
||||
@@ -224,23 +227,21 @@ void trianglePath(uint threadID)
|
||||
bool hit;
|
||||
if(PickUnproject == 1)
|
||||
{
|
||||
hit = TriangleRayIntersect(pos0.xyz / pos0.w, pos1.xyz / pos1.w, pos2.xyz / pos2.w, PickRayPos,
|
||||
PickRayDir,
|
||||
/*out*/ hitPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
hit = TriangleRayIntersect(pos0.xyz, pos1.xyz, pos2.xyz, PickRayPos, PickRayDir,
|
||||
/*out*/ hitPosition);
|
||||
pos0.xyz /= pos0.w;
|
||||
pos1.xyz /= pos1.w;
|
||||
pos2.xyz /= pos2.w;
|
||||
}
|
||||
|
||||
hit = TriangleRayIntersect(pos0.xyz, pos1.xyz, pos2.xyz, PickRayPos, PickRayDir,
|
||||
/*out*/ hitPosition);
|
||||
|
||||
// ray hit a triangle, so return the vertex that was closest
|
||||
// to the triangle/ray intersection point
|
||||
if(hit)
|
||||
{
|
||||
float dist0 = distance(pos0.xyz / pos0.w, hitPosition);
|
||||
float dist1 = distance(pos1.xyz / pos1.w, hitPosition);
|
||||
float dist2 = distance(pos2.xyz / pos2.w, hitPosition);
|
||||
float dist0 = distance(pos0.xyz, hitPosition);
|
||||
float dist1 = distance(pos1.xyz, hitPosition);
|
||||
float dist2 = distance(pos2.xyz, hitPosition);
|
||||
|
||||
uint meshVert = vertid0;
|
||||
if(dist1 < dist0 && dist1 < dist2)
|
||||
|
||||
@@ -80,6 +80,10 @@ MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines(const MeshForm
|
||||
key |= 1ULL << bit;
|
||||
bit++;
|
||||
|
||||
if(primary.allowRestart)
|
||||
key |= 1ULL << bit;
|
||||
bit++;
|
||||
|
||||
// only 64 bits, make sure they all fit
|
||||
RDCASSERT(bit < 64);
|
||||
|
||||
@@ -100,6 +104,15 @@ MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines(const MeshForm
|
||||
pipeDesc.SampleMask = 0xFFFFFFFF;
|
||||
pipeDesc.SampleDesc.Count = D3D12_MSAA_SAMPLECOUNT;
|
||||
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
||||
|
||||
if(primary.allowRestart)
|
||||
{
|
||||
if(primary.indexByteStride == 2)
|
||||
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
else
|
||||
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
|
||||
}
|
||||
|
||||
D3D_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(primary.topology);
|
||||
|
||||
if(topo == D3D_PRIMITIVE_TOPOLOGY_POINTLIST ||
|
||||
|
||||
@@ -1943,58 +1943,6 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
}
|
||||
}
|
||||
|
||||
drv.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]);
|
||||
MeshPickUBOData *cdata =
|
||||
(MeshPickUBOData *)drv.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshPickUBOData),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
|
||||
cdata->rayPos = rayPos;
|
||||
cdata->rayDir = rayDir;
|
||||
cdata->use_indices = cfg.position.indexByteStride ? 1U : 0U;
|
||||
cdata->numVerts = cfg.position.numIndices;
|
||||
bool isTriangleMesh = true;
|
||||
switch(cfg.position.topology)
|
||||
{
|
||||
case Topology::TriangleList:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleStrip:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleFan:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_FAN;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleList_Adj:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleStrip_Adj:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
}
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
cdata->meshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
// line/point data
|
||||
cdata->unproject = cfg.position.unproject;
|
||||
cdata->mvp = cfg.position.unproject ? pickMVPProj : pickMVP;
|
||||
cdata->coords = Vec2f((float)x, (float)y);
|
||||
cdata->viewport = Vec2f((float)width, (float)height);
|
||||
|
||||
drv.glUnmapBuffer(eGL_UNIFORM_BUFFER);
|
||||
|
||||
GLuint ib = 0;
|
||||
|
||||
uint32_t minIndex = 0;
|
||||
@@ -2007,29 +1955,45 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
if(cfg.position.indexByteStride && cfg.position.indexResourceId != ResourceId())
|
||||
ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.indexResourceId).name;
|
||||
|
||||
const bool fandecode =
|
||||
(cfg.position.topology == Topology::TriangleFan && cfg.position.allowRestart);
|
||||
uint32_t numIndices = cfg.position.numIndices;
|
||||
|
||||
// We copy into our own buffers to promote to the target type (uint32) that the shader expects.
|
||||
// Most IBs will be 16-bit indices, most VBs will not be float4. We also apply baseVertex here
|
||||
|
||||
if(ib)
|
||||
{
|
||||
std::vector<uint32_t> idxtmp;
|
||||
|
||||
// if it's a triangle fan that allows restart, we'll have to unpack it.
|
||||
// Allocate enough space for the list on the GPU, and enough temporary space to upcast into
|
||||
// first
|
||||
if(fandecode)
|
||||
{
|
||||
idxtmp.resize(numIndices);
|
||||
|
||||
numIndices *= 3;
|
||||
}
|
||||
|
||||
// resize up on demand
|
||||
if(DebugData.pickIBBuf == 0 || DebugData.pickIBSize < cfg.position.numIndices * sizeof(uint32_t))
|
||||
if(DebugData.pickIBBuf == 0 || DebugData.pickIBSize < numIndices * sizeof(uint32_t))
|
||||
{
|
||||
drv.glDeleteBuffers(1, &DebugData.pickIBBuf);
|
||||
|
||||
drv.glGenBuffers(1, &DebugData.pickIBBuf);
|
||||
drv.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf);
|
||||
drv.glNamedBufferDataEXT(DebugData.pickIBBuf, cfg.position.numIndices * sizeof(uint32_t),
|
||||
NULL, eGL_STREAM_DRAW);
|
||||
drv.glNamedBufferDataEXT(DebugData.pickIBBuf, numIndices * sizeof(uint32_t), NULL,
|
||||
eGL_STREAM_DRAW);
|
||||
|
||||
DebugData.pickIBSize = cfg.position.numIndices * sizeof(uint32_t);
|
||||
DebugData.pickIBSize = numIndices * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
byte *idxs = new byte[cfg.position.numIndices * cfg.position.indexByteStride];
|
||||
memset(idxs, 0, cfg.position.numIndices * cfg.position.indexByteStride);
|
||||
byte *idxs = new byte[numIndices * cfg.position.indexByteStride];
|
||||
memset(idxs, 0, numIndices * cfg.position.indexByteStride);
|
||||
|
||||
std::vector<uint32_t> outidxs;
|
||||
outidxs.resize(cfg.position.numIndices);
|
||||
outidxs.resize(numIndices);
|
||||
|
||||
drv.glBindBuffer(eGL_COPY_READ_BUFFER, ib);
|
||||
|
||||
@@ -2045,6 +2009,8 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
uint16_t *idxs16 = (uint16_t *)idxs;
|
||||
uint32_t *idxs32 = (uint32_t *)idxs;
|
||||
|
||||
size_t idxcount = 0;
|
||||
|
||||
if(cfg.position.indexByteStride == 1)
|
||||
{
|
||||
for(uint32_t i = 0; i < cfg.position.numIndices; i++)
|
||||
@@ -2069,11 +2035,8 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
}
|
||||
|
||||
outidxs[i] = idx;
|
||||
idxcount++;
|
||||
}
|
||||
|
||||
drv.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf);
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numIndices * sizeof(uint32_t),
|
||||
outidxs.data());
|
||||
}
|
||||
else if(cfg.position.indexByteStride == 2)
|
||||
{
|
||||
@@ -2099,11 +2062,8 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
}
|
||||
|
||||
outidxs[i] = idx;
|
||||
idxcount++;
|
||||
}
|
||||
|
||||
drv.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf);
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numIndices * sizeof(uint32_t),
|
||||
outidxs.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2129,12 +2089,30 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
}
|
||||
|
||||
outidxs[i] = idx;
|
||||
idxcount++;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a triangle fan that allows restart, unpack it
|
||||
if(cfg.position.topology == Topology::TriangleFan && cfg.position.allowRestart)
|
||||
{
|
||||
// resize to how many indices were actually read
|
||||
outidxs.resize(idxcount);
|
||||
|
||||
// patch the index buffer
|
||||
PatchTriangleFanRestartIndexBufer(outidxs, cfg.position.restartIndex);
|
||||
|
||||
for(uint32_t &idx : idxtmp)
|
||||
{
|
||||
if(idx == cfg.position.restartIndex)
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
drv.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf);
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numIndices * sizeof(uint32_t),
|
||||
outidxs.data());
|
||||
numIndices = (uint32_t)outidxs.size();
|
||||
}
|
||||
|
||||
drv.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf);
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, numIndices * sizeof(uint32_t), outidxs.data());
|
||||
}
|
||||
|
||||
// unpack and linearise the data
|
||||
@@ -2177,6 +2155,61 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, (maxIndex + 1) * sizeof(Vec4f), vbData.data());
|
||||
}
|
||||
|
||||
drv.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]);
|
||||
MeshPickUBOData *cdata =
|
||||
(MeshPickUBOData *)drv.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshPickUBOData),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
|
||||
cdata->rayPos = rayPos;
|
||||
cdata->rayDir = rayDir;
|
||||
cdata->use_indices = cfg.position.indexByteStride ? 1U : 0U;
|
||||
cdata->numVerts = numIndices;
|
||||
bool isTriangleMesh = true;
|
||||
switch(cfg.position.topology)
|
||||
{
|
||||
case Topology::TriangleList:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleStrip:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleFan:
|
||||
{
|
||||
if(fandecode)
|
||||
cdata->meshMode = MESH_TRIANGLE_LIST;
|
||||
else
|
||||
cdata->meshMode = MESH_TRIANGLE_FAN;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleList_Adj:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
}
|
||||
case Topology::TriangleStrip_Adj:
|
||||
{
|
||||
cdata->meshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
}
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
cdata->meshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
// line/point data
|
||||
cdata->unproject = cfg.position.unproject;
|
||||
cdata->mvp = cfg.position.unproject ? pickMVPProj : pickMVP;
|
||||
cdata->coords = Vec2f((float)x, (float)y);
|
||||
cdata->viewport = Vec2f((float)width, (float)height);
|
||||
|
||||
drv.glUnmapBuffer(eGL_UNIFORM_BUFFER);
|
||||
|
||||
uint32_t reset[4] = {};
|
||||
drv.glBindBufferBase(eGL_SHADER_STORAGE_BUFFER, 0, DebugData.pickResultBuf);
|
||||
drv.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, sizeof(uint32_t) * 4, &reset);
|
||||
@@ -2194,6 +2227,8 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
drv.glBindBuffer(eGL_COPY_READ_BUFFER, DebugData.pickResultBuf);
|
||||
drv.glGetBufferSubData(eGL_COPY_READ_BUFFER, 0, sizeof(uint32_t), &numResults);
|
||||
|
||||
uint32_t ret = ~0U;
|
||||
|
||||
if(numResults > 0)
|
||||
{
|
||||
if(isTriangleMesh)
|
||||
@@ -2226,7 +2261,7 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
|
||||
drv.glUnmapNamedBufferEXT(DebugData.pickResultBuf);
|
||||
|
||||
return closest->vertid;
|
||||
ret = closest->vertid;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2265,11 +2300,18 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
|
||||
drv.glUnmapNamedBufferEXT(DebugData.pickResultBuf);
|
||||
|
||||
return closest->vertid;
|
||||
ret = closest->vertid;
|
||||
}
|
||||
}
|
||||
|
||||
return ~0U;
|
||||
if(fandecode)
|
||||
{
|
||||
// undo the triangle list expansion
|
||||
if(ret > 2)
|
||||
ret = (ret + 3) / 3 + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
|
||||
|
||||
@@ -730,7 +730,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
|
||||
|
||||
uint32_t stripRestartValue32 = 0;
|
||||
|
||||
if(IsStrip(drawcall->topology) && rs.Enabled[GLRenderState::eEnabled_PrimitiveRestart])
|
||||
if(SupportsRestart(drawcall->topology) && rs.Enabled[GLRenderState::eEnabled_PrimitiveRestart])
|
||||
{
|
||||
stripRestartValue32 = rs.Enabled[GLRenderState::eEnabled_PrimitiveRestartFixedIndex]
|
||||
? ~0U
|
||||
|
||||
@@ -1049,55 +1049,10 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
}
|
||||
}
|
||||
|
||||
MeshPickUBOData *ubo = (MeshPickUBOData *)m_VertexPick.UBO.Map();
|
||||
const bool fandecode =
|
||||
(cfg.position.topology == Topology::TriangleFan && cfg.position.allowRestart);
|
||||
|
||||
ubo->rayPos = rayPos;
|
||||
ubo->rayDir = rayDir;
|
||||
ubo->use_indices = cfg.position.indexByteStride ? 1U : 0U;
|
||||
ubo->numVerts = cfg.position.numIndices;
|
||||
bool isTriangleMesh = true;
|
||||
|
||||
switch(cfg.position.topology)
|
||||
{
|
||||
case Topology::TriangleList:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleStrip:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleFan:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_FAN;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleList_Adj:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleStrip_Adj:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
};
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
ubo->meshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
};
|
||||
}
|
||||
|
||||
// line/point data
|
||||
ubo->unproject = cfg.position.unproject;
|
||||
ubo->mvp = cfg.position.unproject ? pickMVPProj : pickMVP;
|
||||
ubo->coords = Vec2f((float)x, (float)y);
|
||||
ubo->viewport = Vec2f((float)w, (float)h);
|
||||
|
||||
m_VertexPick.UBO.Unmap();
|
||||
uint32_t numIndices = cfg.position.numIndices;
|
||||
|
||||
bytebuf idxs;
|
||||
|
||||
@@ -1116,8 +1071,20 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
|
||||
if(!idxs.empty())
|
||||
{
|
||||
std::vector<uint32_t> idxtmp;
|
||||
|
||||
// if it's a triangle fan that allows restart, we'll have to unpack it.
|
||||
// Allocate enough space for the list on the GPU, and enough temporary space to upcast into
|
||||
// first
|
||||
if(fandecode)
|
||||
{
|
||||
idxtmp.resize(numIndices);
|
||||
|
||||
numIndices *= 3;
|
||||
}
|
||||
|
||||
// resize up on demand
|
||||
if(m_VertexPick.IBSize < cfg.position.numIndices * sizeof(uint32_t))
|
||||
if(m_VertexPick.IBSize < numIndices * sizeof(uint32_t))
|
||||
{
|
||||
if(m_VertexPick.IBSize > 0)
|
||||
{
|
||||
@@ -1125,7 +1092,7 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
m_VertexPick.IBUpload.Destroy();
|
||||
}
|
||||
|
||||
m_VertexPick.IBSize = cfg.position.numIndices * sizeof(uint32_t);
|
||||
m_VertexPick.IBSize = numIndices * sizeof(uint32_t);
|
||||
|
||||
m_VertexPick.IB.Create(m_pDriver, dev, m_VertexPick.IBSize, 1,
|
||||
GPUBuffer::eGPUBufferGPULocal | GPUBuffer::eGPUBufferSSBO);
|
||||
@@ -1133,12 +1100,19 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
}
|
||||
|
||||
uint32_t *outidxs = (uint32_t *)m_VertexPick.IBUpload.Map();
|
||||
uint32_t *mappedPtr = outidxs;
|
||||
|
||||
memset(outidxs, 0, m_VertexPick.IBSize);
|
||||
|
||||
// if we're decoding a fan, we write into our temporary vector first
|
||||
if(fandecode)
|
||||
outidxs = idxtmp.data();
|
||||
|
||||
uint16_t *idxs16 = (uint16_t *)&idxs[0];
|
||||
uint32_t *idxs32 = (uint32_t *)&idxs[0];
|
||||
|
||||
size_t idxcount = 0;
|
||||
|
||||
if(cfg.position.indexByteStride == 2)
|
||||
{
|
||||
size_t bufsize = idxs.size() / 2;
|
||||
@@ -1165,6 +1139,7 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
}
|
||||
|
||||
outidxs[i] = idx;
|
||||
idxcount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1188,9 +1163,31 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
maxIndex = RDCMAX(idx, maxIndex);
|
||||
|
||||
outidxs[i] = idx;
|
||||
idxcount++;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a triangle fan that allows restart, unpack it
|
||||
if(cfg.position.topology == Topology::TriangleFan && cfg.position.allowRestart)
|
||||
{
|
||||
// resize to how many indices were actually read
|
||||
idxtmp.resize(idxcount);
|
||||
|
||||
// patch the index buffer
|
||||
PatchTriangleFanRestartIndexBufer(idxtmp, cfg.position.restartIndex);
|
||||
|
||||
for(uint32_t &idx : idxtmp)
|
||||
{
|
||||
if(idx == cfg.position.restartIndex)
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
numIndices = (uint32_t)idxtmp.size();
|
||||
|
||||
// now copy the decoded list to the GPU
|
||||
memcpy(mappedPtr, idxtmp.data(), idxtmp.size() * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
m_VertexPick.IBUpload.Unmap();
|
||||
}
|
||||
|
||||
@@ -1235,6 +1232,59 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
m_VertexPick.VBUpload.Unmap();
|
||||
}
|
||||
|
||||
MeshPickUBOData *ubo = (MeshPickUBOData *)m_VertexPick.UBO.Map();
|
||||
|
||||
ubo->rayPos = rayPos;
|
||||
ubo->rayDir = rayDir;
|
||||
ubo->use_indices = cfg.position.indexByteStride ? 1U : 0U;
|
||||
ubo->numVerts = numIndices;
|
||||
bool isTriangleMesh = true;
|
||||
|
||||
switch(cfg.position.topology)
|
||||
{
|
||||
case Topology::TriangleList:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleStrip:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleFan:
|
||||
{
|
||||
if(fandecode)
|
||||
ubo->meshMode = MESH_TRIANGLE_LIST;
|
||||
else
|
||||
ubo->meshMode = MESH_TRIANGLE_FAN;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleList_Adj:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
};
|
||||
case Topology::TriangleStrip_Adj:
|
||||
{
|
||||
ubo->meshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
};
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
ubo->meshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
};
|
||||
}
|
||||
|
||||
// line/point data
|
||||
ubo->unproject = cfg.position.unproject;
|
||||
ubo->mvp = cfg.position.unproject ? pickMVPProj : pickMVP;
|
||||
ubo->coords = Vec2f((float)x, (float)y);
|
||||
ubo->viewport = Vec2f((float)w, (float)h);
|
||||
|
||||
m_VertexPick.UBO.Unmap();
|
||||
|
||||
VkDescriptorBufferInfo ibInfo = {};
|
||||
VkDescriptorBufferInfo vbInfo = {};
|
||||
|
||||
@@ -1425,6 +1475,13 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const
|
||||
|
||||
VkMarkerRegion::End();
|
||||
|
||||
if(fandecode)
|
||||
{
|
||||
// undo the triangle list expansion
|
||||
if(ret > 2)
|
||||
ret = (ret + 3) / 3 + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2114,8 +2114,22 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo ia = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||
|
||||
// most topologies are decomposed into triangle lists on output
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
if(pipeCreateInfo.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
else if(pipeCreateInfo.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
|
||||
pipeCreateInfo.pInputAssemblyState->topology ==
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
|
||||
pipeCreateInfo.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ||
|
||||
pipeCreateInfo.pInputAssemblyState->topology ==
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY)
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
else if(pipeCreateInfo.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
|
||||
VkVertexInputBindingDescription binds[] = {
|
||||
// primary
|
||||
{0, 0, VK_VERTEX_INPUT_RATE_VERTEX},
|
||||
|
||||
@@ -1608,8 +1608,8 @@ void VulkanReplay::FetchVSOut(uint32_t eventId)
|
||||
|
||||
if(drawcall->flags & DrawFlags::Indexed)
|
||||
{
|
||||
const bool restart =
|
||||
pipeCreateInfo.pInputAssemblyState->primitiveRestartEnable && IsStrip(drawcall->topology);
|
||||
const bool restart = pipeCreateInfo.pInputAssemblyState->primitiveRestartEnable &&
|
||||
SupportsRestart(drawcall->topology);
|
||||
bytebuf idxdata;
|
||||
std::vector<uint32_t> indices;
|
||||
uint8_t *idx8 = NULL;
|
||||
|
||||
@@ -83,6 +83,10 @@ MeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(VkPipelineLay
|
||||
key |= 1ULL << bit;
|
||||
bit++;
|
||||
|
||||
if(primary.allowRestart)
|
||||
key |= 1ULL << bit;
|
||||
bit++;
|
||||
|
||||
// only 64 bits, make sure they all fit
|
||||
RDCASSERT(bit < 64);
|
||||
|
||||
@@ -138,7 +142,7 @@ MeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(VkPipelineLay
|
||||
false,
|
||||
};
|
||||
|
||||
ia.primitiveRestartEnable = primary.allowRestart && IsStrip(primary.topology);
|
||||
ia.primitiveRestartEnable = primary.allowRestart && SupportsRestart(primary.topology);
|
||||
|
||||
VkRect2D scissor = {{0, 0}, {16384, 16384}};
|
||||
|
||||
|
||||
@@ -143,13 +143,13 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_VertexOffset(Topology t
|
||||
case Topology::LineLoop:
|
||||
case Topology::TriangleStrip:
|
||||
case Topology::LineStrip_Adj:
|
||||
case Topology::TriangleFan:
|
||||
// for strips, each new vertex creates a new primitive
|
||||
return primitive;
|
||||
case Topology::TriangleStrip_Adj:
|
||||
// triangle strip with adjacency is a special case as every other
|
||||
// vert is purely for adjacency so it's doubled
|
||||
return primitive * 2;
|
||||
case Topology::TriangleFan: RDCERR("Cannot get VertexOffset for triangle fan!"); break;
|
||||
}
|
||||
|
||||
return primitive * RENDERDOC_NumVerticesPerPrimitive(topology);
|
||||
|
||||
@@ -259,6 +259,86 @@ void PatchLineStripIndexBuffer(const DrawcallDescription *draw, uint8_t *idx8, u
|
||||
#undef IDX_VALUE
|
||||
}
|
||||
|
||||
void PatchTriangleFanRestartIndexBufer(std::vector<uint32_t> &patchedIndices, uint32_t restartIndex)
|
||||
{
|
||||
if(patchedIndices.empty())
|
||||
return;
|
||||
|
||||
std::vector<uint32_t> newIndices;
|
||||
|
||||
uint32_t firstIndex = patchedIndices[0];
|
||||
|
||||
size_t i = 1;
|
||||
// while we have at least two indices left
|
||||
while(i + 1 < patchedIndices.size())
|
||||
{
|
||||
uint32_t a = patchedIndices[i];
|
||||
uint32_t b = patchedIndices[i + 1];
|
||||
|
||||
if(a != restartIndex && b != restartIndex)
|
||||
{
|
||||
// no restart, add primitive
|
||||
newIndices.push_back(firstIndex);
|
||||
newIndices.push_back(a);
|
||||
newIndices.push_back(b);
|
||||
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if(b == restartIndex)
|
||||
{
|
||||
// we've already added the last triangle before the restart in the previous iteration, just
|
||||
// continue so we hit the a == restartIndex case below
|
||||
i++;
|
||||
}
|
||||
else if(a == restartIndex)
|
||||
{
|
||||
// new first index is b
|
||||
firstIndex = b;
|
||||
// skip both the restartIndex value and the first index, and begin at the next real index (if
|
||||
// it exists)
|
||||
i += 2;
|
||||
|
||||
uint32_t next[2] = {b, b};
|
||||
|
||||
// if this is the last vertex, the triangle will be degenerate
|
||||
if(i < patchedIndices.size())
|
||||
next[0] = patchedIndices[i];
|
||||
if(i + 1 < patchedIndices.size())
|
||||
next[1] = patchedIndices[i + 1];
|
||||
|
||||
// output 3 dummy degenerate triangles so vertex ID mapping is easy
|
||||
// we rotate the triangles so the important vertex is last in each.
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
|
||||
if(1)
|
||||
{
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
newIndices.push_back(restartIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
newIndices.push_back(next[0]);
|
||||
newIndices.push_back(next[1]);
|
||||
newIndices.push_back(firstIndex);
|
||||
|
||||
newIndices.push_back(next[1]);
|
||||
newIndices.push_back(firstIndex);
|
||||
newIndices.push_back(next[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newIndices.swap(patchedIndices);
|
||||
}
|
||||
|
||||
void StandardFillCBufferVariable(uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
|
||||
uint32_t matStride)
|
||||
{
|
||||
@@ -509,7 +589,8 @@ FloatVector HighlightCache::InterpretVertex(const byte *data, uint32_t vert, con
|
||||
|
||||
vert = indices[vert];
|
||||
|
||||
if(IsStrip(cfg.position.topology))
|
||||
if(SupportsRestart(cfg.position.topology) && cfg.position.topology != Topology::TriangleFan &&
|
||||
cfg.position.allowRestart)
|
||||
{
|
||||
if((cfg.position.indexByteStride == 1 && vert == 0xff) ||
|
||||
(cfg.position.indexByteStride == 2 && vert == 0xffff) ||
|
||||
@@ -625,6 +706,8 @@ void HighlightCache::CacheHighlightingData(uint32_t eventId, const MeshDisplay &
|
||||
newKey = inthash(cfg.position.vertexByteStride, newKey);
|
||||
newKey = inthash(cfg.position.indexResourceId, newKey);
|
||||
newKey = inthash(cfg.position.vertexResourceId, newKey);
|
||||
newKey = inthash((uint64_t)cfg.position.allowRestart, newKey);
|
||||
newKey = inthash((uint64_t)cfg.position.restartIndex, newKey);
|
||||
|
||||
if(cacheKey != newKey)
|
||||
{
|
||||
@@ -687,7 +770,7 @@ void HighlightCache::CacheHighlightingData(uint32_t eventId, const MeshDisplay &
|
||||
maxIndex += add;
|
||||
|
||||
uint32_t primRestart = 0;
|
||||
if(IsStrip(cfg.position.topology))
|
||||
if(SupportsRestart(cfg.position.topology) && cfg.position.allowRestart)
|
||||
{
|
||||
if(cfg.position.indexByteStride == 1)
|
||||
primRestart = 0xff;
|
||||
@@ -719,6 +802,13 @@ void HighlightCache::CacheHighlightingData(uint32_t eventId, const MeshDisplay &
|
||||
|
||||
driver->GetBufferData(cfg.position.vertexResourceId, cfg.position.vertexByteOffset,
|
||||
(maxIndex + 1) * cfg.position.vertexByteStride, vertexData);
|
||||
|
||||
// if it's a fan AND it uses primitive restart, decompose it into a triangle list because the
|
||||
// restart changes the central vertex
|
||||
if(cfg.position.topology == Topology::TriangleFan && cfg.position.allowRestart)
|
||||
{
|
||||
PatchTriangleFanRestartIndexBufer(indices, cfg.position.restartIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,10 +825,20 @@ bool HighlightCache::FetchHighlightPositions(const MeshDisplay &cfg, FloatVector
|
||||
uint32_t idx = cfg.highlightVert;
|
||||
Topology meshtopo = cfg.position.topology;
|
||||
|
||||
// if it's a fan AND it uses primitive restart, it was decomposed into a triangle list
|
||||
if(meshtopo == Topology::TriangleFan && cfg.position.allowRestart)
|
||||
{
|
||||
meshtopo = Topology::TriangleList;
|
||||
|
||||
// due to triangle fan expansion the index we need to look up is adjusted
|
||||
if(idx > 2)
|
||||
idx = (idx - 1) * 3 - 1;
|
||||
}
|
||||
|
||||
activeVertex = InterpretVertex(data, idx, cfg, dataEnd, true, valid);
|
||||
|
||||
uint32_t primRestart = 0;
|
||||
if(IsStrip(meshtopo))
|
||||
if(SupportsRestart(meshtopo) && cfg.position.allowRestart)
|
||||
{
|
||||
if(cfg.position.indexByteStride == 1)
|
||||
primRestart = 0xff;
|
||||
@@ -834,6 +934,19 @@ bool HighlightCache::FetchHighlightPositions(const MeshDisplay &cfg, FloatVector
|
||||
activePrim.push_back(InterpretVertex(data, v + 0, cfg, dataEnd, true, valid));
|
||||
activePrim.push_back(InterpretVertex(data, v + 1, cfg, dataEnd, true, valid));
|
||||
}
|
||||
else if(meshtopo == Topology::TriangleFan)
|
||||
{
|
||||
// find first vert in primitive. In fans a vert isn't
|
||||
// in only one primitive, so we pick the first primitive
|
||||
// it's in. This means the first N points are in the first
|
||||
// primitive, and thereafter each point is in the next primitive
|
||||
uint32_t v = RDCMAX(idx, 2U) - 1;
|
||||
|
||||
// first vert in the whole fan
|
||||
activePrim.push_back(InterpretVertex(data, 0, cfg, dataEnd, true, valid));
|
||||
activePrim.push_back(InterpretVertex(data, v + 0, cfg, dataEnd, true, valid));
|
||||
activePrim.push_back(InterpretVertex(data, v + 1, cfg, dataEnd, true, valid));
|
||||
}
|
||||
else if(meshtopo == Topology::TriangleStrip)
|
||||
{
|
||||
// find first vert in primitive. In strips a vert isn't
|
||||
@@ -1029,7 +1142,7 @@ bool HighlightCache::FetchHighlightPositions(const MeshDisplay &cfg, FloatVector
|
||||
}
|
||||
else if(meshtopo >= Topology::PatchList)
|
||||
{
|
||||
uint32_t dim = PatchList_Count(cfg.position.topology);
|
||||
uint32_t dim = PatchList_Count(meshtopo);
|
||||
|
||||
uint32_t v0 = uint32_t(idx / dim) * dim;
|
||||
|
||||
|
||||
@@ -244,6 +244,8 @@ void SetupDrawcallPointers(std::vector<DrawcallDescription *> &drawcallTable,
|
||||
void PatchLineStripIndexBuffer(const DrawcallDescription *draw, uint8_t *idx8, uint16_t *idx16,
|
||||
uint32_t *idx32, std::vector<uint32_t> &patchedIndices);
|
||||
|
||||
void PatchTriangleFanRestartIndexBufer(std::vector<uint32_t> &patchedIndices, uint32_t restartIndex);
|
||||
|
||||
uint64_t CalcMeshOutputSize(uint64_t curSize, uint64_t requiredOutput);
|
||||
|
||||
void StandardFillCBufferVariable(uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
|
||||
|
||||
@@ -25,6 +25,7 @@ set(VULKAN_SRC
|
||||
vk/vk_simple_triangle.cpp
|
||||
vk/vk_spec_constants.cpp
|
||||
vk/vk_structured_buffer_nested.cpp
|
||||
vk/vk_triangle_fan.cpp
|
||||
vk/vk_vertex_attr_zoo.cpp
|
||||
vk/vk_video_textures.cpp
|
||||
vk/vk_vs_max_desc_set.cpp)
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
<ClCompile Include="vk\vk_line_raster.cpp" />
|
||||
<ClCompile Include="vk\vk_multi_thread_windows.cpp" />
|
||||
<ClCompile Include="vk\vk_spec_constants.cpp" />
|
||||
<ClCompile Include="vk\vk_triangle_fan.cpp" />
|
||||
<ClCompile Include="vk\vk_vertex_attr_zoo.cpp" />
|
||||
<ClCompile Include="vk\vk_buffer_address.cpp" />
|
||||
<ClCompile Include="vk\vk_cbuffer_zoo.cpp" />
|
||||
|
||||
@@ -321,6 +321,9 @@
|
||||
<ClCompile Include="vk\vk_spec_constants.cpp">
|
||||
<Filter>Vulkan\demos</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vk\vk_triangle_fan.cpp">
|
||||
<Filter>Vulkan\demos</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D11">
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
|
||||
TEST(VK_Triangle_Fan, VulkanGraphicsTest)
|
||||
{
|
||||
static constexpr const char *Description =
|
||||
"Draws a triangle fan with primitive restart to test different edge cases.";
|
||||
|
||||
std::string common = R"EOSHADER(
|
||||
|
||||
#version 420 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 pixel = R"EOSHADER(
|
||||
|
||||
layout(location = 0) in v2f vertIn;
|
||||
|
||||
layout(location = 0, index = 0) out vec4 Color;
|
||||
|
||||
void main()
|
||||
{
|
||||
Color = vertIn.col;
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
int main()
|
||||
{
|
||||
// initialise, create window, create context, etc
|
||||
if(!Init())
|
||||
return 3;
|
||||
|
||||
VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo());
|
||||
|
||||
vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
|
||||
|
||||
pipeCreateInfo.layout = layout;
|
||||
pipeCreateInfo.renderPass = mainWindow->rp;
|
||||
|
||||
pipeCreateInfo.inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
pipeCreateInfo.inputAssemblyState.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
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 + pixel, ShaderLang::glsl, ShaderStage::frag, "main"),
|
||||
};
|
||||
|
||||
VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
pipeCreateInfo.inputAssemblyState.primitiveRestartEnable = VK_TRUE;
|
||||
|
||||
VkPipeline restartpipe = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
const DefaultA2V verts[] = {
|
||||
// centre A
|
||||
{Vec3f(0.0f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
|
||||
|
||||
// fan A
|
||||
{Vec3f(-0.8f, 0.0f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(-0.5f, 0.3f, 0.0f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.5f, 0.3f, 0.0f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.8f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
|
||||
// centre B
|
||||
{Vec3f(0.0f, -0.75f, 0.0f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
|
||||
|
||||
// fan B
|
||||
{Vec3f(-0.8f, 0.0f - 0.75f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(-0.5f, 0.3f - 0.75f, 0.0f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.0f, 0.5f - 0.75f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.5f, 0.3f - 0.75f, 0.0f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(0.8f, 0.0f - 0.75f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
};
|
||||
|
||||
AllocatedBuffer vb(allocator,
|
||||
vkh::BufferCreateInfo(sizeof(verts), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
|
||||
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
|
||||
|
||||
vb.upload(verts);
|
||||
|
||||
uint32_t indices[13] = {0, 1, 2, 3, 4, 5, ~0U, 6, 7, 8, 9, 10, 11};
|
||||
AllocatedBuffer ib(allocator,
|
||||
vkh::BufferCreateInfo(sizeof(indices), VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
|
||||
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
|
||||
|
||||
ib.upload(indices);
|
||||
|
||||
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());
|
||||
|
||||
vkCmdBeginRenderPass(
|
||||
cmd, vkh::RenderPassBeginInfo(mainWindow->rp, mainWindow->GetFB(), mainWindow->scissor),
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
VkViewport v = mainWindow->viewport;
|
||||
v.width /= 2;
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, restartpipe);
|
||||
vkCmdSetViewport(cmd, 0, 1, &v);
|
||||
vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor);
|
||||
vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0});
|
||||
vkCmdBindIndexBuffer(cmd, ib.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmd, 13, 1, 0, 0, 0);
|
||||
|
||||
v.x += v.width;
|
||||
vkCmdSetViewport(cmd, 0, 1, &v);
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
|
||||
|
||||
vkCmdDrawIndexed(cmd, 6, 1, 0, 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();
|
||||
Reference in New Issue
Block a user