Commit dec9a95d authored by Ken Martin's avatar Ken Martin
Browse files

Add cell coloring support

cleanup handling of descriptor sets
parent cd7f45de
......@@ -2,6 +2,7 @@ set (classes
vtkVulkanActorNode
vtkVulkanBuffer
vtkVulkanBufferManager
vtkVulkanCellToVTKCellMap
vtkVulkanDevice
vtkVulkanFramebuffer
vtkVulkanHardwareSelector
......
......@@ -111,10 +111,6 @@ To be done
* hardware selection (requires a vtk cell to vulkan cell map)
* cell coloring (requires a vtk cell to vulkan cell map)
* cell normals (requires a vtk cell to vulkan cell map)
* PBR lighting (not planning on implementing old style lighting)
* ambient occlusion pass
......
#version 400
#version 430
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
......
#version 400
#version 430
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
......
......@@ -50,7 +50,7 @@ vtkVulkanBuffer::~vtkVulkanBuffer()
}
}
void vtkVulkanBuffer::SetDevice(vtkVulkanDevice *dev)
void vtkVulkanBuffer::SetDevice(vtkVulkanDevice* dev)
{
if (this->Device && dev != this->Device)
{
......
......@@ -56,8 +56,7 @@ vtkVulkanBufferManager::~vtkVulkanBufferManager()
this->ActiveWorkersMutex.lock();
actWorkCount = this->ActiveWorkers.size();
this->ActiveWorkersMutex.unlock();
}
while (actWorkCount > 0);
} while (actWorkCount > 0);
}
void vtkVulkanBufferManager::SetDevice(vtkVulkanDevice* dev)
......@@ -80,7 +79,7 @@ void vtkVulkanBufferManager::PrintSelf(ostream& os, vtkIndent indent)
void vtkVulkanBufferManager::DeleteBuffer(vtkVulkanBuffer* buff)
{
vtkVulkanBuffer *tmp = nullptr;
vtkVulkanBuffer* tmp = nullptr;
// remove from the worker queue
this->WorkerQueueMutex.lock();
......@@ -129,9 +128,9 @@ void vtkVulkanBufferManager::DeleteBuffer(vtkVulkanBuffer* buff)
}
}
void vtkVulkanBufferManager::QueueWorker(Worker &w)
void vtkVulkanBufferManager::QueueWorker(Worker& w)
{
Worker *nw = new Worker();
Worker* nw = new Worker();
nw->Buffer = w.Buffer;
nw->Abort = false;
nw->Manager = this;
......@@ -152,7 +151,7 @@ void vtkVulkanBufferManager::QueueWorker(Worker &w)
this->ActiveWorkersMutex.unlock();
}
void vtkVulkanBufferManager::WorkerCompleted(Worker *w)
void vtkVulkanBufferManager::WorkerCompleted(Worker* w)
{
// remove this worker
this->ActiveWorkersMutex.lock();
......@@ -172,7 +171,7 @@ void vtkVulkanBufferManager::WorkerCompleted(Worker *w)
this->WorkerQueueMutex.lock();
if (this->WorkerQueue.size())
{
Worker *nw = this->WorkerQueue.front();
Worker* nw = this->WorkerQueue.front();
this->WorkerQueue.pop_front();
this->ActiveWorkers.push_back(nw);
nw->Thread = new std::thread(nw->Function, nw);
......@@ -182,6 +181,71 @@ void vtkVulkanBufferManager::WorkerCompleted(Worker *w)
this->ActiveWorkersMutex.unlock();
}
template <typename T>
vtkVulkanBuffer* vtkVulkanBufferManager::GetBuffer(
BufferRequest req, bool async, std::shared_ptr<std::vector<T>>& data)
{
// is the buffer already present, if so return it
this->MapMutex.lock();
auto bi = this->Buffers.find(req);
if (bi != this->Buffers.end())
{
bi->second->Register(this);
this->MapMutex.unlock();
return bi->second;
}
vtkVulkanBuffer* buff = vtkVulkanBuffer::New();
buff->Register(this);
this->Buffers[req] = buff;
this->MapMutex.unlock();
// process the request. fopr Raw we just return the buffer
if (req.Usage == StorageVector)
{
std::shared_ptr<std::vector<T>> da(data);
vtkVulkanBuffer::ArrayInformation ai;
size_t compSize = sizeof(T);
ai.SizeInBytes = static_cast<uint32_t>(da->size()*compSize);
ai.OffsetInBytes = 0;
ai.Format = req.Format;
buff->AddArrayInformation(ai);
if (async)
{
Worker w;
w.Buffer = buff;
w.Manager = this;
w.Function = [da, compSize](Worker* w) {
w->Buffer->Initialize(w->Manager->GetDevice(),
static_cast<uint32_t>(da->size() * compSize),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
// send the points down
w->Buffer->Write(*da);
w->Buffer->SetReady(true);
w->Manager->WorkerCompleted(w);
};
this->QueueWorker(w);
}
else
{
buff->Initialize(this->Device,
static_cast<uint32_t>(da->size() * compSize),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
// send the points down
buff->Write(*da);
buff->SetReady(true);
}
}
return buff;
}
template vtkVulkanBuffer* vtkVulkanBufferManager::GetBuffer(
BufferRequest req, bool async, std::shared_ptr<std::vector<unsigned char>>& data);
vtkVulkanBuffer* vtkVulkanBufferManager::GetBuffer(BufferRequest req, bool async)
{
// is the buffer already present, if so return it
......@@ -217,8 +281,7 @@ vtkVulkanBuffer* vtkVulkanBufferManager::GetBuffer(BufferRequest req, bool async
Worker w;
w.Buffer = buff;
w.Manager = this;
w.Function = [da](Worker *w)
{
w.Function = [da](Worker* w) {
w->Buffer->Initialize(w->Manager->GetDevice(),
da->GetNumberOfTuples() * da->GetNumberOfComponents() * da->GetElementComponentSize(),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
......@@ -442,8 +505,7 @@ vtkVulkanBuffer* vtkVulkanBufferManager::GetBufferPointsNormals(
Worker w;
w.Buffer = buff;
w.Manager = this;
w.Function = [da, normals](Worker *w)
{
w.Function = [da, normals](Worker* w) {
asyncbuffer(w->Manager->GetDevice(), da, normals, w->Buffer);
w->Manager->WorkerCompleted(w);
};
......@@ -723,8 +785,7 @@ vtkVulkanBuffer* vtkVulkanBufferManager::GetBuffer(
Worker w;
w.Buffer = buff;
w.Manager = this;
w.Function = [points, cells, request](Worker *w)
{
w.Function = [points, cells, request](Worker* w) {
fillAnIBO(w->Buffer, w->Manager->GetDevice(), points, cells, request);
w->Manager->WorkerCompleted(w);
};
......
......@@ -22,10 +22,12 @@
#include "vtkObject.h"
#include "vtkRenderingVulkanModule.h" // For export macro
#include <list> // for ivar
#include <map> // for ivar
#include <memory> // for ivar
#include <mutex> // for ivar
#include <vector> // for ivar
#include <vulkan/vulkan.h>
#include <mutex> // for ivar
#include <list> // for ivar
class vtkCellArray;
class vtkDataArray;
......@@ -49,6 +51,7 @@ public:
enum BufferUsage
{
Raw,
StorageVector,
DataArray,
PointsAndNormals,
Triangles,
......@@ -70,8 +73,11 @@ public:
};
vtkVulkanBuffer* GetBuffer(BufferRequest req, bool async);
vtkVulkanBuffer* GetBufferPointsNormals(BufferRequest req, vtkDataArray *normals, bool async);
vtkVulkanBuffer* GetBuffer(vtkPoints* points, vtkCellArray* polys, BufferUsage request, bool async);
template <typename T>
vtkVulkanBuffer* GetBuffer(BufferRequest req, bool async, std::shared_ptr<std::vector<T>>& data);
vtkVulkanBuffer* GetBufferPointsNormals(BufferRequest req, vtkDataArray* normals, bool async);
vtkVulkanBuffer* GetBuffer(
vtkPoints* points, vtkCellArray* polys, BufferUsage request, bool async);
// to be called by vtkVulkanBuffer only
void DeleteBuffer(vtkVulkanBuffer* buff);
......@@ -83,15 +89,15 @@ protected:
class Worker
{
public:
std::function<void(Worker *w)> Function;
vtkVulkanBuffer *Buffer;
vtkVulkanBufferManager *Manager;
std::function<void(Worker* w)> Function;
vtkVulkanBuffer* Buffer;
vtkVulkanBufferManager* Manager;
std::atomic<bool> Abort;
std::thread *Thread;
std::thread* Thread;
};
void QueueWorker(Worker &w);
void WorkerCompleted(Worker *w);
void QueueWorker(Worker& w);
void WorkerCompleted(Worker* w);
std::list<Worker*> WorkerQueue;
std::mutex WorkerQueueMutex;
std::list<Worker*> ActiveWorkers;
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkVulkanCellToVTKCellMap.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkVulkanCellToVTKCellMap.h"
#include "vtkCellArray.h"
#include "vtkPoints.h"
#include "vtkProperty.h"
//------------------------------------------------------------------------------
vtkStandardNewMacro(vtkVulkanCellToVTKCellMap);
//------------------------------------------------------------------------------
vtkVulkanCellToVTKCellMap::vtkVulkanCellToVTKCellMap()
{
this->PrimitiveOffsets[0] = 0;
this->PrimitiveOffsets[1] = 0;
this->PrimitiveOffsets[2] = 0;
this->PrimitiveOffsets[3] = 0;
this->CellMapSizes[0] = 0;
this->CellMapSizes[1] = 0;
this->CellMapSizes[2] = 0;
this->CellMapSizes[3] = 0;
}
//------------------------------------------------------------------------------
vtkVulkanCellToVTKCellMap::~vtkVulkanCellToVTKCellMap() = default;
void vtkVulkanCellToVTKCellMap::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
void vtkVulkanCellToVTKCellMap::SetStartOffset(vtkIdType start)
{
if (this->StartOffset == start)
{
return;
}
// adjust PrimitiveOffsets in case they are already calculated
this->PrimitiveOffsets[0] = this->PrimitiveOffsets[0] - this->StartOffset + start;
this->PrimitiveOffsets[1] = this->PrimitiveOffsets[1] - this->StartOffset + start;
this->PrimitiveOffsets[2] = this->PrimitiveOffsets[2] - this->StartOffset + start;
this->PrimitiveOffsets[3] = this->PrimitiveOffsets[3] - this->StartOffset + start;
this->StartOffset = start;
}
void vtkVulkanCellToVTKCellMap::BuildPrimitiveOffsetsIfNeeded(
vtkCellArray* prims[4], int representation, vtkPoints* points)
{
// if the users created a full cell cell map AND it is still valid then
// the values will be computed as part of that and we should use them
if (!this->CellCellMap.empty())
{
this->TempState.Clear();
this->TempState.Append(prims[0]->GetNumberOfCells() ? prims[0]->GetMTime() : 0, "verts");
this->TempState.Append(prims[1]->GetNumberOfCells() ? prims[1]->GetMTime() : 0, "lines");
this->TempState.Append(prims[2]->GetNumberOfCells() ? prims[2]->GetMTime() : 0, "polys");
this->TempState.Append(prims[3]->GetNumberOfCells() ? prims[3]->GetMTime() : 0, "strips");
this->TempState.Append(representation, "representation");
this->TempState.Append(points ? points->GetMTime() : 0, "points");
if (this->MapBuildState != this->TempState)
{
this->CellCellMap.clear();
}
else
{
return;
}
}
// otherwise compute some conservative values
// verts
this->PrimitiveOffsets[0] = this->StartOffset;
this->CellMapSizes[0] = prims[0]->GetNumberOfConnectivityIds();
// point rep is easy for all prims
if (representation == VTK_POINTS)
{
for (int j = 1; j < 4; j++)
{
this->CellMapSizes[j] = prims[j]->GetNumberOfConnectivityIds();
this->PrimitiveOffsets[j] = this->PrimitiveOffsets[j - 1] + this->CellMapSizes[j - 1];
}
return;
}
// lines
this->CellMapSizes[1] = prims[1]->GetNumberOfConnectivityIds() - prims[1]->GetNumberOfCells();
this->PrimitiveOffsets[1] = this->PrimitiveOffsets[0] + this->CellMapSizes[0];
if (representation == VTK_WIREFRAME)
{
// polys
this->CellMapSizes[2] = prims[2]->GetNumberOfConnectivityIds();
this->PrimitiveOffsets[2] = this->PrimitiveOffsets[1] + this->CellMapSizes[1];
// strips
this->CellMapSizes[3] =
2 * prims[3]->GetNumberOfConnectivityIds() - 3 * prims[3]->GetNumberOfCells();
this->PrimitiveOffsets[3] = this->PrimitiveOffsets[2] + this->CellMapSizes[2];
return;
}
// otherwise surface rep
// polys
this->CellMapSizes[2] = prims[2]->GetNumberOfConnectivityIds() - 2 * prims[2]->GetNumberOfCells();
this->PrimitiveOffsets[2] = this->PrimitiveOffsets[1] + this->CellMapSizes[1];
// strips
this->CellMapSizes[3] = prims[3]->GetNumberOfConnectivityIds() - 2 * prims[3]->GetNumberOfCells();
this->PrimitiveOffsets[3] = this->PrimitiveOffsets[2] + this->CellMapSizes[2];
}
// Create supporting arrays that are needed when rendering cell data
// Some VTK cells have to be broken into smaller cells for Vulkan
// When we have cell data we have to map cell attributes from the VTK
// cell number to the actual Vulkan cell
// The following code fills in
//
// cellCellMap which maps a Vulkan cell id to the VTK cell it came from
//
void vtkVulkanCellToVTKCellMap::BuildCellSupportArrays(
vtkCellArray* prims[4], int representation, vtkPoints* points)
{
// need an array to track what points to orig points
size_t minSize = prims[0]->GetNumberOfCells() + prims[1]->GetNumberOfCells() +
prims[2]->GetNumberOfCells() + prims[3]->GetNumberOfCells();
const vtkIdType* indices(nullptr);
vtkIdType npts(0);
// make sure we have at least minSize
this->CellCellMap.clear();
this->CellCellMap.reserve(minSize);
vtkIdType vtkCellCount = 0;
vtkIdType cumulativeSize = 0;
this->BuildRepresentation = representation;
// points
this->PrimitiveOffsets[0] = this->StartOffset;
for (prims[0]->InitTraversal(); prims[0]->GetNextCell(npts, indices);)
{
for (vtkIdType i = 0; i < npts; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->CellMapSizes[0] = static_cast<vtkIdType>(this->CellCellMap.size());
cumulativeSize = this->CellMapSizes[0];
if (representation == VTK_POINTS)
{
for (int j = 1; j < 4; j++)
{
for (prims[j]->InitTraversal(); prims[j]->GetNextCell(npts, indices);)
{
for (vtkIdType i = 0; i < npts; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[j] = this->PrimitiveOffsets[j - 1] + this->CellMapSizes[j - 1];
this->CellMapSizes[j] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
cumulativeSize = static_cast<vtkIdType>(this->CellCellMap.size());
}
return;
}
// lines
for (prims[1]->InitTraversal(); prims[1]->GetNextCell(npts, indices);)
{
for (vtkIdType i = 0; i < npts - 1; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[1] = this->PrimitiveOffsets[0] + this->CellMapSizes[0];
this->CellMapSizes[1] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
cumulativeSize = static_cast<vtkIdType>(this->CellCellMap.size());
if (representation == VTK_WIREFRAME)
{
// polys
for (prims[2]->InitTraversal(); prims[2]->GetNextCell(npts, indices);)
{
for (vtkIdType i = 0; i < npts; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[2] = this->PrimitiveOffsets[1] + this->CellMapSizes[1];
this->CellMapSizes[2] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
cumulativeSize = static_cast<vtkIdType>(this->CellCellMap.size());
// strips
for (prims[3]->InitTraversal(); prims[3]->GetNextCell(npts, indices);)
{
this->CellCellMap.push_back(vtkCellCount);
for (vtkIdType i = 2; i < npts; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[3] = this->PrimitiveOffsets[2] + this->CellMapSizes[2];
this->CellMapSizes[3] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
return;
}
// polys
for (prims[2]->InitTraversal(); prims[2]->GetNextCell(npts, indices);)
{
if (npts > 2)
{
for (vtkIdType i = 2; i < npts; i++)
{
double p1[3];
points->GetPoint(indices[0], p1);
double p2[3];
points->GetPoint(indices[i - 1], p2);
double p3[3];
points->GetPoint(indices[i], p3);
if ((p1[0] != p2[0] || p1[1] != p2[1] || p1[2] != p2[2]) &&
(p3[0] != p2[0] || p3[1] != p2[1] || p3[2] != p2[2]) &&
(p3[0] != p1[0] || p3[1] != p1[1] || p3[2] != p1[2]))
{
this->CellCellMap.push_back(vtkCellCount);
}
}
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[2] = this->PrimitiveOffsets[1] + this->CellMapSizes[1];
this->CellMapSizes[2] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
cumulativeSize = static_cast<vtkIdType>(this->CellCellMap.size());
// strips
for (prims[3]->InitTraversal(); prims[3]->GetNextCell(npts, indices);)
{
for (vtkIdType i = 2; i < npts; ++i)
{
this->CellCellMap.push_back(vtkCellCount);
}
vtkCellCount++;
} // for cell
this->PrimitiveOffsets[3] = this->PrimitiveOffsets[2] + this->CellMapSizes[2];
this->CellMapSizes[3] = static_cast<vtkIdType>(this->CellCellMap.size()) - cumulativeSize;
}
void vtkVulkanCellToVTKCellMap::Update(vtkCellArray** prims, int representation, vtkPoints* points)
{
this->TempState.Clear();
this->TempState.Append(prims[0]->GetNumberOfCells() ? prims[0]->GetMTime() : 0, "verts");
this->TempState.Append(prims[1]->GetNumberOfCells() ? prims[1]->GetMTime() : 0, "lines");
this->TempState.Append(prims[2]->GetNumberOfCells() ? prims[2]->GetMTime() : 0, "polys");
this->TempState.Append(prims[3]->GetNumberOfCells() ? prims[3]->GetMTime() : 0, "strips");
this->TempState.Append(representation, "representation");
this->TempState.Append(points ? points->GetMTime() : 0, "points");
if (this->MapBuildState != this->TempState)
{
this->MapBuildState = this->TempState;
this->BuildCellSupportArrays(prims, representation, points);
}
}
vtkIdType vtkVulkanCellToVTKCellMap::ConvertVulkanCellIdToVTKCellId(
bool pointPicking, vtkIdType VulkanId)
{
// start with the vert offset and remove that
vtkIdType result = VulkanId - this->PrimitiveOffsets[0];
// check if we really are a vert
if (result < this->CellMapSizes[0])
{
return this->CellCellMap[result];
}
// OK we are a line maybe?
result = VulkanId - this->PrimitiveOffsets[1];
if (pointPicking && this->BuildRepresentation != VTK_POINTS)
{
result /= 2;
}
if (result < this->CellMapSizes[1])
{
return this->CellCellMap[result + this->CellMapSizes[0]];
}
// OK maybe a triangle
result = VulkanId - this->PrimitiveOffsets[2];
if (pointPicking && this->BuildRepresentation == VTK_WIREFRAME)
{
result /= 2;
}
if (pointPicking && this->BuildRepresentation == VTK_SURFACE)
{
result /= 3;
}
if (result < this->CellMapSizes[2])
{
return this->CellCellMap[result + this->CellMapSizes[1] + this->CellMapSizes[0]];
}
// must be a strip
result = VulkanId - this->PrimitiveOffsets[3];
if (pointPicking && this->BuildRepresentation == VTK_WIREFRAME)
{
result /= 2;
}
if (pointPicking && this->BuildRepresentation == VTK_SURFACE)
{
result /= 3;