Sample 2
This commit is contained in:
70
commonUtils.hpp
Normal file
70
commonUtils.hpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Mykhailo Mamedov. All rights reserved.
|
||||||
|
*
|
||||||
|
* RESEARCH PREVIEW / REFERENCE ONLY:
|
||||||
|
* This source code is provided solely for the purpose of reviewing
|
||||||
|
* the author's research methods and implementation.
|
||||||
|
*
|
||||||
|
* NO LICENSE GRANTED:
|
||||||
|
* This code is NOT for distribution, modification, or use in any
|
||||||
|
* project (commercial or otherwise). Unauthorized copying or
|
||||||
|
* use of this code is strictly prohibited.
|
||||||
|
*
|
||||||
|
* For inquiries regarding use or licensing, contact: ua.modin@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TOOLS_HEADER
|
||||||
|
#define TOOLS_HEADER
|
||||||
|
|
||||||
|
|
||||||
|
namespace M_TOOLS {
|
||||||
|
|
||||||
|
struct Sync {
|
||||||
|
// Barrier quick helper.
|
||||||
|
std::vector<VkBufferMemoryBarrier2> buffers;
|
||||||
|
std::vector<VkImageMemoryBarrier2> images;
|
||||||
|
|
||||||
|
Sync& buffer(VkBuffer buffer, VkPipelineStageFlags2 srcMask, VkAccessFlags2 srcAccessMask,
|
||||||
|
VkPipelineStageFlags2 dstMask, VkAccessFlags2 dstAccessMask, VkDeviceSize offset=0) {
|
||||||
|
VkBufferMemoryBarrier2 barrierInstance{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
|
||||||
|
barrierInstance.srcStageMask = srcMask; barrierInstance.srcAccessMask = srcAccessMask;
|
||||||
|
barrierInstance.dstStageMask = dstMask; barrierInstance.dstAccessMask = dstAccessMask;
|
||||||
|
barrierInstance.buffer = buffer; barrierInstance.size = VK_WHOLE_SIZE;
|
||||||
|
barrierInstance.offset = offset;
|
||||||
|
buffers.push_back(barrierInstance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sync& image(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
|
||||||
|
VkPipelineStageFlags2 srcMask, VkAccessFlags2 srcAccessMask,
|
||||||
|
VkPipelineStageFlags2 dstMask, VkAccessFlags2 dstAccessMask) {
|
||||||
|
VkImageMemoryBarrier2 barrierInstance{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
|
||||||
|
barrierInstance.srcStageMask = srcMask; barrierInstance.srcAccessMask = srcAccessMask;
|
||||||
|
barrierInstance.dstStageMask = dstMask; barrierInstance.dstAccessMask = dstAccessMask;
|
||||||
|
barrierInstance.oldLayout = oldLayout; barrierInstance.newLayout = newLayout;
|
||||||
|
barrierInstance.image = image;
|
||||||
|
barrierInstance.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
images.push_back(barrierInstance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(VkCommandBuffer cmd) {
|
||||||
|
VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||||
|
depInfo.bufferMemoryBarrierCount = (uint32_t)buffers.size();
|
||||||
|
depInfo.pBufferMemoryBarriers = buffers.data();
|
||||||
|
depInfo.imageMemoryBarrierCount = (uint32_t)images.size();
|
||||||
|
depInfo.pImageMemoryBarriers = images.data();
|
||||||
|
vkCmdPipelineBarrier2(cmd, &depInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // TOOLS_HEADER
|
||||||
|
//
|
||||||
|
#ifdef TOOLS_COMPONENT
|
||||||
|
#endif
|
||||||
784
strandComponent.hpp
Normal file
784
strandComponent.hpp
Normal file
@@ -0,0 +1,784 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Mykhailo Mamedov. All rights reserved.
|
||||||
|
*
|
||||||
|
* RESEARCH PREVIEW / REFERENCE ONLY:
|
||||||
|
* This source code is provided solely for the purpose of reviewing
|
||||||
|
* the author's research methods and implementation.
|
||||||
|
*
|
||||||
|
* NO LICENSE GRANTED:
|
||||||
|
* This code is NOT for distribution, modification, or use in any
|
||||||
|
* project (commercial or otherwise). Unauthorized copying or
|
||||||
|
* use of this code is strictly prohibited.
|
||||||
|
*
|
||||||
|
* For inquiries regarding use or licensing, contact: ua.modin@gmail.com
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* High-performance volumetric rendering engine-component
|
||||||
|
* optimized for massive strand geometries (30M+ vertices).
|
||||||
|
* Implements hardware-accelerated ray-marching
|
||||||
|
* and volume-image buffer based shadow casting
|
||||||
|
* to achieve real-time visualization of dense fiber structures.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#ifndef STR_COMPONENT_HEADER
|
||||||
|
#define STR_COMPONENT_HEADER
|
||||||
|
|
||||||
|
namespace M_STR {
|
||||||
|
|
||||||
|
namespace cfg {
|
||||||
|
inline constexpr auto SMOOTH_STRAND_COUNT = 64U;
|
||||||
|
inline constexpr auto IS_NOT_CUBE_MAP = false;
|
||||||
|
inline constexpr auto IS_3D_IMAGE = true;
|
||||||
|
inline constexpr auto IS_LAYOUT_GENNERAL = true;
|
||||||
|
inline constexpr auto UNIFORM_BUFFER_SIZE = sizeof(glm::mat4);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct appInfo {
|
||||||
|
VkDevice Device = NULL;
|
||||||
|
u32 NumImages = 0;
|
||||||
|
VK::VulkanCore* vCore;
|
||||||
|
GLFWwindow* m_pWindow;
|
||||||
|
size_t uniformBufferSize = 0;
|
||||||
|
glm::ivec2 offscreenViewportSize{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PushConstants {
|
||||||
|
glm::mat4 viewProj;
|
||||||
|
glm::vec3 gridOrigin;
|
||||||
|
float gridExtent;
|
||||||
|
glm::vec3 lightDir;
|
||||||
|
float _pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PushConstantsComputeBase {
|
||||||
|
glm::mat4 viewProj;
|
||||||
|
glm::vec3 gridOrigin;
|
||||||
|
float gridCellSize;
|
||||||
|
float gridExtent;
|
||||||
|
u32 frameCount;
|
||||||
|
float _pad[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurveHeader { // Matches GLSL.
|
||||||
|
uint32_t poolOffset;
|
||||||
|
uint32_t pointCount;
|
||||||
|
uint32_t maxPoints;
|
||||||
|
uint32_t _padding; // 16-byte alignment
|
||||||
|
glm::vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurvePoint {
|
||||||
|
glm::vec4 pos; // xyz = position, w = radius
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StrandData { // Master CPU record.
|
||||||
|
uint32_t slotIdx; // Reserved
|
||||||
|
std::vector<CurvePoint> points;
|
||||||
|
glm::vec4 color;
|
||||||
|
uint8_t dirtyCount = 0; // Match with m_numImages to update all frames in flight.
|
||||||
|
|
||||||
|
// Static helper to ingest initial generated data.
|
||||||
|
static void IngestInitialPool(
|
||||||
|
std::vector<StrandData>&targetMasterRecord,
|
||||||
|
std::span<const CurveHeader> srcHeaders,
|
||||||
|
std::span<const CurvePoint> srcPointPool,
|
||||||
|
u32 imagesInFlight
|
||||||
|
) {
|
||||||
|
// We assume target is already resized.
|
||||||
|
for (uint32_t sIdx = 0; sIdx < srcHeaders.size(); ++sIdx) {
|
||||||
|
StrandData& strandTarget = targetMasterRecord[sIdx];
|
||||||
|
const CurveHeader& srcHeader = srcHeaders[sIdx];
|
||||||
|
|
||||||
|
strandTarget.slotIdx = sIdx; // Initial index matches slot index
|
||||||
|
strandTarget.color = srcHeader.color;
|
||||||
|
|
||||||
|
// Extract points from the generated pool
|
||||||
|
strandTarget.points.clear();
|
||||||
|
strandTarget.points.reserve(srcHeader.pointCount);
|
||||||
|
for (uint32_t pIdx = 0; pIdx < srcHeader.pointCount; ++pIdx) {
|
||||||
|
// Read the position+radius into master record.
|
||||||
|
strandTarget.points.push_back(srcPointPool[srcHeader.poolOffset + pIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VolumetricGrid {
|
||||||
|
glm::vec3 origin; // Min corner of the box
|
||||||
|
glm::vec3 extent; // Size of the box
|
||||||
|
};
|
||||||
|
|
||||||
|
VolumetricGrid calculateGrid(const std::vector<CurvePoint>& particles) {
|
||||||
|
glm::vec3 minBound(FLT_MAX);
|
||||||
|
glm::vec3 maxBound(-FLT_MAX);
|
||||||
|
|
||||||
|
for (const auto& p : particles) {
|
||||||
|
minBound = glm::min(minBound, glm::vec3(p.pos));
|
||||||
|
maxBound = glm::max(maxBound, glm::vec3(p.pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
float padding = 1.0f;
|
||||||
|
minBound -= padding;
|
||||||
|
maxBound += padding;
|
||||||
|
|
||||||
|
VolumetricGrid grid;
|
||||||
|
grid.origin = minBound;
|
||||||
|
grid.extent = maxBound - minBound;
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Curves {
|
||||||
|
|
||||||
|
public:
|
||||||
|
VK::BufferMemory m_indirectBuffer;
|
||||||
|
std::vector<StrandData> cpuStrands;
|
||||||
|
std::vector <VK::BufferMemory> curvePointPoolBuffer;
|
||||||
|
std::vector <VK::BufferMemory> curveHeadersBuffer;
|
||||||
|
std::vector<VK::BufferMemory> uniform_buffers;
|
||||||
|
std::vector <VK::BufferMemory> curveSmoothPointsBuffer;
|
||||||
|
std::vector<CurveHeader> curveHeaders;
|
||||||
|
std::vector<CurvePoint> curvePointPool;
|
||||||
|
std::vector <void*> curveHeadersBufferPtr;
|
||||||
|
std::vector <void*> curvePointPoolBufferPtr;
|
||||||
|
std::vector<uint32_t> freeSlots;
|
||||||
|
std::vector<uint32_t> activeStrands;
|
||||||
|
std::vector <VkShaderModule> shaders;
|
||||||
|
|
||||||
|
VK::VulkanTexture shadowBuffer;
|
||||||
|
PushConstantsComputeBase pcComp{};
|
||||||
|
PushConstants pcDraw{};
|
||||||
|
|
||||||
|
M_PIPE::UPipelineV1* pipe = NULL;
|
||||||
|
M_PIPE::UPipelineV1* pipeCurvesCompute = NULL;
|
||||||
|
M_PIPE::UPipelineV1* pipeCurvesFadeCompute = NULL;
|
||||||
|
VkDevice m_device = NULL;
|
||||||
|
u32 m_numImages = 0;
|
||||||
|
GLFWwindow* m_pWindow = NULL;
|
||||||
|
VkShaderModule m_shader_strandCompute = VK_NULL_HANDLE;
|
||||||
|
VkShaderModule m_shader_strandFadeCompute = VK_NULL_HANDLE;
|
||||||
|
VkShaderModule m_shader_strandVertex = VK_NULL_HANDLE;
|
||||||
|
VkShaderModule m_shader_strandFragment = VK_NULL_HANDLE;
|
||||||
|
VK::VulkanCore* vkCore;
|
||||||
|
size_t m_uniformBufferSize = 0;
|
||||||
|
// TODO: Remove.
|
||||||
|
bool runNudges = false;
|
||||||
|
bool hasNudges = false;
|
||||||
|
bool nudgetAlready = false;
|
||||||
|
u32 maxStrands = 200000;
|
||||||
|
u32 maxStrandPoints = 100;
|
||||||
|
|
||||||
|
Curves(appInfo& info);
|
||||||
|
void createCVComputePipeline();
|
||||||
|
void createShadowMapPipeline();
|
||||||
|
void createCurveGraphicPipeline();
|
||||||
|
void createShaders();
|
||||||
|
void CreateIndirectBuffer();
|
||||||
|
void createUniformBuffers();
|
||||||
|
void RecordCommandBufferCurves(VkCommandBuffer CmdBuf, int ImageIndex);
|
||||||
|
//void nudgeParticle(Particle* mappedVram, uint32_t index, glm::vec3 newPos);
|
||||||
|
void generateVines(std::vector<CurveHeader>& headers, std::vector<CurvePoint>& pool, uint32_t numStrands);
|
||||||
|
void generateClumps(std::vector<CurveHeader>& headers, std::vector<CurvePoint>& pool, uint32_t numStrands);
|
||||||
|
void createBuffers();
|
||||||
|
void createShadowImage();
|
||||||
|
void createFadeShadowPipeline();
|
||||||
|
void writeComputeBuffers(VkCommandBuffer CmdBuf, int ImageIndex, u32 currentFrame);
|
||||||
|
void applyNudges(VkCommandBuffer CmdBuf, int ImageIndex, u32 currentFrame);
|
||||||
|
uint32_t findEmptySlot();
|
||||||
|
void UpdateScene(u32 currentFrame);
|
||||||
|
|
||||||
|
~Curves();
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // STR_COMPONENT_HEADER
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// --- The Implementation Section ---
|
||||||
|
#ifdef STR_COMPONENT
|
||||||
|
|
||||||
|
namespace M_STR {
|
||||||
|
|
||||||
|
Curves::Curves(appInfo& info) {
|
||||||
|
m_device = info.Device;
|
||||||
|
m_numImages = info.NumImages;
|
||||||
|
vkCore = info.vCore;
|
||||||
|
m_pWindow = info.m_pWindow;
|
||||||
|
m_uniformBufferSize = info.uniformBufferSize;
|
||||||
|
|
||||||
|
u32 strandsToGen = 100000;
|
||||||
|
curveHeaders.resize(strandsToGen);
|
||||||
|
curvePointPool.resize(strandsToGen * maxStrandPoints);
|
||||||
|
// generateVines(curveHeaders, curvePointPool, strandsToGen);
|
||||||
|
generateClumps(curveHeaders, curvePointPool, strandsToGen);
|
||||||
|
cpuStrands.resize(maxStrands);
|
||||||
|
StrandData::IngestInitialPool(cpuStrands, curveHeaders, curvePointPool, m_numImages);
|
||||||
|
freeSlots.clear();
|
||||||
|
activeStrands.clear();
|
||||||
|
for (uint32_t i = 0; i < maxStrands; ++i) {
|
||||||
|
if (i >= curveHeaders.size()) {
|
||||||
|
freeSlots.push_back(i);
|
||||||
|
cpuStrands[i].points.clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
activeStrands.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pcComp.gridCellSize = 128.0f;
|
||||||
|
VolumetricGrid boundingInfo = calculateGrid(curvePointPool);
|
||||||
|
pcComp.gridOrigin = boundingInfo.origin;
|
||||||
|
pcDraw.gridOrigin = pcComp.gridOrigin;
|
||||||
|
pcComp.gridExtent = boundingInfo.extent.x;
|
||||||
|
pcDraw.gridExtent = boundingInfo.extent.x;
|
||||||
|
pcDraw.lightDir = glm::vec3(-1.0f, 0.3f, -0.02f);
|
||||||
|
pcDraw._pad = 1.0f;
|
||||||
|
|
||||||
|
CreateIndirectBuffer(); // Disabled for now. We need to adj draw pass after compute is finished.
|
||||||
|
createUniformBuffers();
|
||||||
|
createBuffers();
|
||||||
|
createShadowImage();
|
||||||
|
createShaders();
|
||||||
|
createCurveGraphicPipeline(); // Graphics.
|
||||||
|
createFadeShadowPipeline();
|
||||||
|
createCVComputePipeline();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::generateVines(std::vector<CurveHeader>& headers, std::vector<CurvePoint>& pool, uint32_t numStrands) {
|
||||||
|
const uint32_t maxPtsPerStrand = 100;
|
||||||
|
const uint32_t initPtsPerStrand = 64;
|
||||||
|
const float spacing = 0.02f;
|
||||||
|
|
||||||
|
headers.resize(numStrands);
|
||||||
|
pool.resize(numStrands * maxPtsPerStrand);
|
||||||
|
|
||||||
|
std::vector<uint32_t> indices(numStrands);
|
||||||
|
std::iota(indices.begin(), indices.end(), 0);
|
||||||
|
|
||||||
|
std::for_each(std::execution::par, indices.begin(), indices.end(), [&](uint32_t sIdx) {
|
||||||
|
std::mt19937 gen(sIdx);
|
||||||
|
std::uniform_real_distribution<float> angleDist(-0.015f, 0.015f);
|
||||||
|
std::uniform_real_distribution<float> posDist(-10.0f, 10.0f);
|
||||||
|
std::uniform_real_distribution<float> colorDist(0.6f, 1.0f);
|
||||||
|
|
||||||
|
headers[sIdx].poolOffset = sIdx * maxPtsPerStrand;
|
||||||
|
headers[sIdx].pointCount = initPtsPerStrand;
|
||||||
|
headers[sIdx].maxPoints = maxPtsPerStrand;
|
||||||
|
headers[sIdx].color = glm::vec4(colorDist(gen), colorDist(gen), colorDist(gen), 1.0f);
|
||||||
|
|
||||||
|
glm::vec3 currPos(posDist(gen), 0.0f, posDist(gen));
|
||||||
|
glm::vec3 growDir(0, -1, 0);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < initPtsPerStrand; i++) {
|
||||||
|
uint32_t pIdx = headers[sIdx].poolOffset + i;
|
||||||
|
|
||||||
|
// Radius taper.
|
||||||
|
float radius = glm::mix(0.05f, 0.05f, (float)i / 9.0f);
|
||||||
|
pool[pIdx].pos = glm::vec4(currPos, radius);
|
||||||
|
|
||||||
|
// Rotate growth
|
||||||
|
glm::mat4 rot = glm::rotate(glm::mat4(1.0f), angleDist(gen), glm::vec3(1, 0, 0));
|
||||||
|
rot = glm::rotate(rot, angleDist(gen), glm::vec3(0, 0, 1));
|
||||||
|
growDir = glm::vec3(rot * glm::vec4(growDir, 0.0f));
|
||||||
|
|
||||||
|
currPos += growDir * spacing;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::generateClumps(std::vector<CurveHeader>& headers, std::vector<CurvePoint>& pool, uint32_t numStrands) {
|
||||||
|
const uint32_t maxPtsPerStrand = 100;
|
||||||
|
const uint32_t initPtsPerStrand = 64;
|
||||||
|
const float spacing = 0.007f;
|
||||||
|
|
||||||
|
// Attractors
|
||||||
|
const int numClumps = 3;
|
||||||
|
glm::vec3 clumps[numClumps] = {
|
||||||
|
glm::vec3(0, -3, 0),
|
||||||
|
glm::vec3(2.0f, -3.2f, 1.5f) * 2.0f,
|
||||||
|
glm::vec3(-1.5f, -3.7f, -2.0f) * 3.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint32_t> indices(numStrands);
|
||||||
|
std::iota(indices.begin(), indices.end(), 0);
|
||||||
|
|
||||||
|
std::for_each(std::execution::par, indices.begin(), indices.end(), [&](uint32_t sIdx) {
|
||||||
|
std::mt19937 gen(sIdx);
|
||||||
|
std::uniform_real_distribution<float> jitter(-1.4f, 1.4f);
|
||||||
|
std::uniform_real_distribution<float> noise(-0.05f, 0.05f);
|
||||||
|
std::uniform_real_distribution<float> colorDist(0.6f, 1.0f);
|
||||||
|
|
||||||
|
// Assign this strand to one of the clumps
|
||||||
|
glm::vec3 center = clumps[sIdx % numClumps];
|
||||||
|
|
||||||
|
headers[sIdx].poolOffset = sIdx * maxPtsPerStrand;
|
||||||
|
headers[sIdx].pointCount = initPtsPerStrand;
|
||||||
|
headers[sIdx].maxPoints = maxPtsPerStrand;
|
||||||
|
headers[sIdx].color = glm::vec4(colorDist(gen), colorDist(gen), colorDist(gen), 1.0f);
|
||||||
|
|
||||||
|
glm::vec3 currPos = center + glm::vec3(jitter(gen), jitter(gen), jitter(gen))*2.0f;
|
||||||
|
glm::vec3 growDir = glm::normalize(glm::cross(currPos - center, glm::vec3(0, 1, 0)));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < initPtsPerStrand; i++) {
|
||||||
|
uint32_t pIdx = headers[sIdx].poolOffset + i;
|
||||||
|
pool[pIdx].pos = glm::vec4(currPos, 0.015f);
|
||||||
|
glm::vec3 toCenter = glm::normalize(center - currPos);
|
||||||
|
growDir = glm::normalize(growDir + toCenter * 0.07f + glm::vec3(noise(gen)));
|
||||||
|
currPos += growDir * spacing;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Curves::findEmptySlot() {
|
||||||
|
if (freeSlots.empty()) return UINT32_MAX;
|
||||||
|
uint32_t slot = freeSlots.back();
|
||||||
|
freeSlots.pop_back();
|
||||||
|
activeStrands.push_back(slot);
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::applyNudges(VkCommandBuffer CmdBuf, int ImageIndex, u32 currentFrame) {
|
||||||
|
if (!runNudges)return;
|
||||||
|
if (!nudgetAlready) {
|
||||||
|
UpdateScene(currentFrame); // Adding a strand, nudging the rest in master buffer.
|
||||||
|
nudgetAlready = true;
|
||||||
|
}
|
||||||
|
// Apply master changes to device.
|
||||||
|
std::span<CurveHeader> gpuHeaders{ static_cast<CurveHeader*>(curveHeadersBufferPtr[ImageIndex]), maxStrands };
|
||||||
|
std::span<CurvePoint> gpuPoints{ static_cast<CurvePoint*>(curvePointPoolBufferPtr[ImageIndex]), maxStrands * maxStrandPoints };
|
||||||
|
hasNudges = false;
|
||||||
|
for (uint32_t idx : activeStrands) {
|
||||||
|
auto& localStrandRef = cpuStrands[idx];
|
||||||
|
|
||||||
|
if (localStrandRef.dirtyCount > 0) {
|
||||||
|
// UPLOAD to the current buffer.
|
||||||
|
gpuHeaders[idx].pointCount = localStrandRef.points.size();
|
||||||
|
gpuHeaders[idx].poolOffset = idx * maxStrandPoints;
|
||||||
|
gpuHeaders[idx].color = localStrandRef.color;
|
||||||
|
gpuHeaders[idx].maxPoints = maxStrandPoints;
|
||||||
|
|
||||||
|
// Update point pool for the strand.
|
||||||
|
std::copy(localStrandRef.points.begin(), localStrandRef.points.end(), &gpuPoints[idx * maxStrandPoints]);
|
||||||
|
|
||||||
|
// 2. One buffer is now up to date
|
||||||
|
localStrandRef.dirtyCount--;
|
||||||
|
hasNudges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createUniformBuffers() {
|
||||||
|
assert(m_uniformBufferSize);
|
||||||
|
uniform_buffers = vkCore->CreateUniformBuffers(m_uniformBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createBuffers() {
|
||||||
|
VkResult res;
|
||||||
|
VkBufferUsageFlags bufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
VkMemoryPropertyFlags hostDeviceVisible = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
|
|
||||||
|
VkDeviceSize bufferSize;
|
||||||
|
for (uint32_t i = 0; i < m_numImages; ++i) {
|
||||||
|
VK::BufferMemory curveHeader;
|
||||||
|
void* pBuffer = NULL;
|
||||||
|
void* pBufferPool = NULL;
|
||||||
|
|
||||||
|
// Buffer for structural headers.
|
||||||
|
bufferSize = maxStrands * sizeof(CurveHeader);
|
||||||
|
curveHeader = vkCore->CreateBuffer(
|
||||||
|
bufferSize,
|
||||||
|
bufferUsage,
|
||||||
|
hostDeviceVisible,
|
||||||
|
VK_SHARING_MODE_CONCURRENT,
|
||||||
|
{ vkCore->m_queueFamily, vkCore->m_queueFamilyCompute }
|
||||||
|
);
|
||||||
|
res = vkMapMemory(m_device, curveHeader.m_mem, 0, bufferSize, 0, &pBuffer);
|
||||||
|
CHECK_VK_RESULT(res, "vkMapMemory curveHeader");
|
||||||
|
memcpy(pBuffer, curveHeaders.data(), (size_t)curveHeaders.size() * sizeof(CurveHeader)); // The same data in each buffer.
|
||||||
|
curveHeadersBuffer.push_back(curveHeader);
|
||||||
|
curveHeadersBufferPtr.push_back(pBuffer);
|
||||||
|
|
||||||
|
// Buffer for transit smooth curves to VTX.
|
||||||
|
bufferSize = maxStrands * sizeof(glm::vec4) * cfg::SMOOTH_STRAND_COUNT;
|
||||||
|
curveSmoothPointsBuffer.push_back(
|
||||||
|
vkCore->CreateBuffer(
|
||||||
|
bufferSize,
|
||||||
|
bufferUsage,
|
||||||
|
hostDeviceVisible,
|
||||||
|
VK_SHARING_MODE_CONCURRENT,
|
||||||
|
{ vkCore->m_queueFamily, vkCore->m_queueFamilyCompute }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Point pool buffer, for each frame in flight.
|
||||||
|
bufferSize = maxStrands * maxStrandPoints * sizeof(CurvePoint);
|
||||||
|
VK::BufferMemory curvePool;
|
||||||
|
curvePool = vkCore->CreateBuffer(
|
||||||
|
bufferSize,
|
||||||
|
bufferUsage,
|
||||||
|
hostDeviceVisible,
|
||||||
|
VK_SHARING_MODE_CONCURRENT,
|
||||||
|
{ vkCore->m_queueFamily, vkCore->m_queueFamilyCompute }
|
||||||
|
);
|
||||||
|
res = vkMapMemory(m_device, curvePool.m_mem, 0, bufferSize, 0, &pBufferPool);
|
||||||
|
CHECK_VK_RESULT(res, "vkMapMemory PointPool");
|
||||||
|
memcpy(pBufferPool, curvePointPool.data(), (size_t)curvePointPool.size() * sizeof(CurvePoint));
|
||||||
|
curvePointPoolBuffer.push_back(curvePool);
|
||||||
|
curvePointPoolBufferPtr.push_back(pBufferPool); // For later updates.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createShadowImage() {
|
||||||
|
|
||||||
|
VkResult res;
|
||||||
|
VkFormat imageFormat = VK_FORMAT_R32_SFLOAT;
|
||||||
|
|
||||||
|
vkCore->CreateImage(
|
||||||
|
shadowBuffer,
|
||||||
|
pcComp.gridCellSize, // Width
|
||||||
|
pcComp.gridCellSize, // Heigh
|
||||||
|
imageFormat,
|
||||||
|
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
cfg::IS_NOT_CUBE_MAP, // Cubemap
|
||||||
|
pcComp.gridCellSize, // Depths
|
||||||
|
cfg::IS_3D_IMAGE, // is 3d not 2d
|
||||||
|
VK_SHARING_MODE_CONCURRENT // Sharing mode.
|
||||||
|
);
|
||||||
|
vkCore->setObjectName(m_device, shadowBuffer.m_image, std::format("shadowBufferImage").c_str());
|
||||||
|
|
||||||
|
shadowBuffer.m_view = VK::CreateImageView(
|
||||||
|
vkCore->GetDevice(), shadowBuffer.m_image, imageFormat,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
cfg::IS_NOT_CUBE_MAP, // Cubemap.
|
||||||
|
cfg::IS_3D_IMAGE // is 3d image.
|
||||||
|
);
|
||||||
|
vkCore->setObjectName(m_device, shadowBuffer.m_view, std::format("shadowBufferView").c_str());
|
||||||
|
|
||||||
|
VkSamplerCreateInfo samplerInfo{};
|
||||||
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
// Preserved from previous.
|
||||||
|
samplerInfo.magFilter = VK_FILTER_LINEAR; // automatically blends the 8 surrounding voxels
|
||||||
|
samplerInfo.minFilter = VK_FILTER_LINEAR; // to avoid lego bricks
|
||||||
|
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||||
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
|
||||||
|
// Added for light depth.
|
||||||
|
samplerInfo.compareEnable = VK_FALSE;
|
||||||
|
samplerInfo.compareOp = VK_COMPARE_OP_LESS;
|
||||||
|
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
|
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||||
|
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||||
|
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||||
|
samplerInfo.minLod = 0.0f;
|
||||||
|
samplerInfo.maxLod = 1.0f;
|
||||||
|
res = vkCreateSampler(vkCore->GetDevice(), &samplerInfo, nullptr, &shadowBuffer.m_sampler);
|
||||||
|
CHECK_VK_RESULT(res, "vkCreateSampler");
|
||||||
|
vkCore->setObjectName(m_device, shadowBuffer.m_sampler, std::format("shadowBufferSampler").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::CreateIndirectBuffer() {
|
||||||
|
std::vector<VkDrawIndirectCommand> DrawCommands(1);
|
||||||
|
VkDrawIndirectCommand cmd = {
|
||||||
|
.vertexCount = cfg::SMOOTH_STRAND_COUNT,
|
||||||
|
.instanceCount = maxStrands,
|
||||||
|
.firstVertex = 0,
|
||||||
|
.firstInstance = 0
|
||||||
|
};
|
||||||
|
DrawCommands[0] = cmd;
|
||||||
|
m_indirectBuffer = vkCore->CreateIndirectBuffer(
|
||||||
|
DrawCommands.data(),
|
||||||
|
ARRAY_SIZE_IN_BYTES(DrawCommands)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createShaders() { // TODO: Refactor.
|
||||||
|
m_shader_strandCompute = VK::CreateShaderModuleFromText(m_device, "strandsBase.comp");
|
||||||
|
m_shader_strandFadeCompute = VK::CreateShaderModuleFromText(m_device, "strandsFade.comp");
|
||||||
|
m_shader_strandVertex = VK::CreateShaderModuleFromText(m_device, "crv.vert");
|
||||||
|
m_shader_strandFragment = VK::CreateShaderModuleFromText(m_device, "crv.frag");
|
||||||
|
shaders.push_back(m_shader_strandCompute);
|
||||||
|
shaders.push_back(m_shader_strandFadeCompute);
|
||||||
|
shaders.push_back(m_shader_strandVertex);
|
||||||
|
shaders.push_back(m_shader_strandFragment);
|
||||||
|
vkCore->setObjectName(m_device, m_shader_strandCompute, std::format("m_shader_strandCompute").c_str());
|
||||||
|
vkCore->setObjectName(m_device, m_shader_strandFadeCompute, std::format("m_shader_strandFadeCompute").c_str());
|
||||||
|
vkCore->setObjectName(m_device, m_shader_strandVertex, std::format("m_shader_strandVertex").c_str());
|
||||||
|
vkCore->setObjectName(m_device, m_shader_strandFragment, std::format("m_shader_strandFragment").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createCurveGraphicPipeline() {
|
||||||
|
M_PIPE::PipelineDescU1 pipeInfo{};
|
||||||
|
pipeInfo.Device = m_device;
|
||||||
|
pipeInfo.vertex_shader = m_shader_strandVertex;
|
||||||
|
pipeInfo.fragment_shader = m_shader_strandFragment;
|
||||||
|
pipeInfo.numImages = m_numImages;
|
||||||
|
pipeInfo.pushSize = sizeof(pcDraw);
|
||||||
|
|
||||||
|
std::vector<VkBuffer> smoothBuffers;
|
||||||
|
for (VK::BufferMemory compound : curveSmoothPointsBuffer) {
|
||||||
|
smoothBuffers.push_back(compound.m_buffer);
|
||||||
|
}
|
||||||
|
std::vector<VkBuffer> headBuffers;
|
||||||
|
for (VK::BufferMemory compound : curveHeadersBuffer) {
|
||||||
|
headBuffers.push_back(compound.m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo smoothPointsBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.multiBuffer = smoothBuffers, // Transit to graphics pipe.
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.hasSingleBufferPerSet = true,
|
||||||
|
.bindingOverride = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo headersBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.multiBuffer = headBuffers, // Curve heads.
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.hasSingleBufferPerSet = true,
|
||||||
|
.bindingOverride = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo shadowBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.samplers = {shadowBuffer.m_sampler},
|
||||||
|
.imageViews = {shadowBuffer.m_view},
|
||||||
|
.imageLayoutInit = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.bindingOverride = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
pipeInfo.bindings.push_back(smoothPointsBinding);
|
||||||
|
pipeInfo.bindings.push_back(headersBinding);
|
||||||
|
pipeInfo.bindings.push_back(shadowBinding);
|
||||||
|
|
||||||
|
std::vector<VkFormat> colorFormats;
|
||||||
|
colorFormats.push_back(vkCore->GetSwapChainFormat());
|
||||||
|
pipeInfo.prim_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||||
|
pipeInfo.colorAttachmentFormats = colorFormats;
|
||||||
|
pipeInfo.depthAttachmentFormat = vkCore->GetDepthFormat();
|
||||||
|
pipeInfo.hasDynamicState = true;
|
||||||
|
pipeInfo.pWindow = m_pWindow;
|
||||||
|
pipeInfo.hasViewport = true;
|
||||||
|
pipeInfo.hasRendering = true;
|
||||||
|
pipeInfo.hasRasterization = true;
|
||||||
|
pipeInfo.nameId = "strandGraphicsPipeline";
|
||||||
|
pipeInfo.pCore = vkCore;
|
||||||
|
pipe = new M_PIPE::UPipelineV1(pipeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createFadeShadowPipeline() {
|
||||||
|
M_PIPE::PipelineDescU1 pipe_info{};
|
||||||
|
pipe_info.Device = m_device;
|
||||||
|
pipe_info.numImages = m_numImages;
|
||||||
|
{
|
||||||
|
M_PIPE::BindingInfo shadowImageBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.imageViews = {shadowBuffer.m_view},
|
||||||
|
.imageLayoutInit = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.bindingOverride = 0
|
||||||
|
};
|
||||||
|
pipe_info.bindings.push_back(shadowImageBinding);
|
||||||
|
}
|
||||||
|
pipe_info.compute_shader = m_shader_strandFadeCompute;
|
||||||
|
pipe_info.isCompute = true;
|
||||||
|
pipe_info.nameId = "curvesComputeFadePipeline";
|
||||||
|
pipe_info.pCore = vkCore;
|
||||||
|
pipeCurvesFadeCompute = new M_PIPE::UPipelineV1(pipe_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::writeComputeBuffers(VkCommandBuffer CmdBuf, int ImageIndex, u32 currentFrame) {
|
||||||
|
|
||||||
|
if (currentFrame == 0) {
|
||||||
|
M_TOOLS::Sync()
|
||||||
|
.image(shadowBuffer.m_image,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, // From nothing to General
|
||||||
|
VK_PIPELINE_STAGE_2_NONE, 0, // Source: Nothing
|
||||||
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_ACCESS_2_MEMORY_WRITE_BIT) // Ready for use
|
||||||
|
.apply(CmdBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TOOLS::Sync()
|
||||||
|
.image(shadowBuffer.m_image,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_ACCESS_2_SHADER_READ_BIT, // srcMask, srcAccess
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT) // dstMask, dstAccess
|
||||||
|
.apply(CmdBuf);
|
||||||
|
|
||||||
|
// Shadow fade.
|
||||||
|
pipeCurvesFadeCompute->Bind(CmdBuf);
|
||||||
|
pipeCurvesFadeCompute->bindDescriptorSets(CmdBuf, ImageIndex);
|
||||||
|
vkCmdDispatch(CmdBuf, 16, 16, 16); // TODO: link size.
|
||||||
|
|
||||||
|
if (hasNudges) {
|
||||||
|
// Push vk buffer changes to device.
|
||||||
|
M_TOOLS::Sync()
|
||||||
|
.buffer(curveHeadersBuffer[ImageIndex].m_buffer,
|
||||||
|
VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, // Source: CPU
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT) // Dest: GPU
|
||||||
|
.buffer(curvePointPoolBuffer[ImageIndex].m_buffer,
|
||||||
|
VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT)
|
||||||
|
.apply(CmdBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute catmullRom + shadows
|
||||||
|
pipeCurvesCompute->Bind(CmdBuf);
|
||||||
|
pipeCurvesCompute->bindDescriptorSets(CmdBuf, ImageIndex);
|
||||||
|
pipeCurvesCompute->PushConstants(CmdBuf, sizeof(pcComp), &pcComp);
|
||||||
|
vkCmdPushConstants(
|
||||||
|
CmdBuf, // VkCommandBuffer commandBuffer
|
||||||
|
pipeCurvesCompute->GetPipelineLayout(), // VkPipelineLayout layout
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags
|
||||||
|
0, // offset
|
||||||
|
sizeof(pcComp), // size
|
||||||
|
&pcComp
|
||||||
|
);
|
||||||
|
|
||||||
|
vkCmdDispatch(CmdBuf, maxStrands, 1, 1);
|
||||||
|
|
||||||
|
// hand off shadow and renderable curves to render pipes.
|
||||||
|
M_TOOLS::Sync()
|
||||||
|
.image(shadowBuffer.m_image,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, // srcMask, srcAccess
|
||||||
|
VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE) // dstMask, dstAccess
|
||||||
|
.buffer(curveSmoothPointsBuffer[ImageIndex].m_buffer,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, // srcMask, srcAccess
|
||||||
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_ACCESS_2_SHADER_STORAGE_READ_BIT) // dstMask, dstAccess
|
||||||
|
.apply(CmdBuf);
|
||||||
|
// Note: Don't use NONE mask/access, it would only silence validation.
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::createCVComputePipeline() {
|
||||||
|
M_PIPE::PipelineDescU1 pipe_info{};
|
||||||
|
pipe_info.Device = m_device;
|
||||||
|
pipe_info.numImages = m_numImages;
|
||||||
|
|
||||||
|
std::vector<VkBuffer> smoothBuffers; // TODO: move in pipeline.
|
||||||
|
for (VK::BufferMemory compound : curveSmoothPointsBuffer) {
|
||||||
|
smoothBuffers.push_back(compound.m_buffer);
|
||||||
|
}
|
||||||
|
std::vector<VkBuffer> headBuffers;
|
||||||
|
for (VK::BufferMemory compound : curveHeadersBuffer) {
|
||||||
|
headBuffers.push_back(compound.m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkBuffer> poolBuffers;
|
||||||
|
for (VK::BufferMemory compound : curvePointPoolBuffer) {
|
||||||
|
poolBuffers.push_back(compound.m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
M_PIPE::BindingInfo headersBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.multiBuffer = headBuffers,
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.hasSingleBufferPerSet = true,
|
||||||
|
.bindingOverride = 0
|
||||||
|
};
|
||||||
|
pipe_info.bindings.push_back(headersBinding);
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo pointPoolBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.multiBuffer = poolBuffers, // Point-pool for compute only.
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.hasSingleBufferPerSet = true,
|
||||||
|
.bindingOverride = 1
|
||||||
|
};
|
||||||
|
pipe_info.bindings.push_back(pointPoolBinding);
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo smoothPointsBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.multiBuffer = smoothBuffers, // Transit to graphics pipe.
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.hasSingleBufferPerSet = true,
|
||||||
|
.bindingOverride = 2
|
||||||
|
};
|
||||||
|
pipe_info.bindings.push_back(smoothPointsBinding);
|
||||||
|
|
||||||
|
M_PIPE::BindingInfo shadowImageBinding{
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.imageViews = {shadowBuffer.m_view},
|
||||||
|
.imageLayoutInit = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.hasCustomBinding = true,
|
||||||
|
.bindingOverride = 3
|
||||||
|
};
|
||||||
|
pipe_info.bindings.push_back(shadowImageBinding);
|
||||||
|
}
|
||||||
|
pipe_info.pushSize = sizeof(PushConstantsComputeBase);
|
||||||
|
pipe_info.compute_shader = m_shader_strandCompute;
|
||||||
|
pipe_info.isCompute = true;
|
||||||
|
pipe_info.nameId = "curvesComputePipeline";
|
||||||
|
pipe_info.pCore = vkCore;
|
||||||
|
pipeCurvesCompute = new M_PIPE::UPipelineV1(pipe_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curves::RecordCommandBufferCurves(VkCommandBuffer CmdBuf, int ImageIndex) {
|
||||||
|
vkCore->pfnVkCmdSetPolygonModeEXT(CmdBuf, VkPolygonMode::VK_POLYGON_MODE_FILL);
|
||||||
|
vkCore->pfnVkCmdSetPrimitiveTopologyEXT(CmdBuf, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
|
||||||
|
pipe->Bind(CmdBuf);
|
||||||
|
pipe->PushConstants(CmdBuf, sizeof(pcDraw), &pcDraw);
|
||||||
|
pipe->bindDescriptorSets(CmdBuf, ImageIndex);
|
||||||
|
vkCmdDrawIndirect(CmdBuf,
|
||||||
|
m_indirectBuffer.m_buffer,
|
||||||
|
0, // offset inside the indirect buffer
|
||||||
|
(u32)1, // number of VkDrawIndirectCommand elements
|
||||||
|
sizeof(VkDrawIndirectCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
Curves::~Curves() {
|
||||||
|
vkDeviceWaitIdle(m_device);
|
||||||
|
|
||||||
|
for (auto& buffer : uniform_buffers) {
|
||||||
|
buffer.Destroy(m_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto shaderModule : shaders) {
|
||||||
|
vkDestroyShaderModule(m_device, shaderModule, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto buff : curveHeadersBuffer) {
|
||||||
|
vkUnmapMemory(m_device, buff.m_mem);
|
||||||
|
buff.Destroy(m_device);
|
||||||
|
}
|
||||||
|
for (auto buff : curveSmoothPointsBuffer) {
|
||||||
|
buff.Destroy(m_device);
|
||||||
|
}
|
||||||
|
m_indirectBuffer.Destroy(m_device);
|
||||||
|
|
||||||
|
for (auto buff : curvePointPoolBuffer) {
|
||||||
|
vkUnmapMemory(m_device, buff.m_mem);
|
||||||
|
buff.Destroy(m_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowBuffer.Destroy(m_device);
|
||||||
|
|
||||||
|
delete pipe;
|
||||||
|
delete pipeCurvesCompute;
|
||||||
|
delete pipeCurvesFadeCompute;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
|
// --- The Implementation Section End ---
|
||||||
Reference in New Issue
Block a user