Adding transparency support

This commit is contained in:
Dynamitos
2024-06-20 21:57:26 +02:00
parent 2dc9d57c71
commit bd63b14260
27 changed files with 578 additions and 282 deletions
+63 -47
View File
@@ -1,5 +1,6 @@
import Common;
import Scene;
import Bounding;
groupshared MeshPayload p;
groupshared uint head;
@@ -7,6 +8,7 @@ groupshared MeshData mesh;
groupshared InstanceData instance;
groupshared Frustum viewFrustum;
groupshared float4x4 modelViewProjection;
groupshared bool meshVisible;
struct DepthData
{
@@ -16,6 +18,60 @@ struct DepthData
ParameterBlock<DepthData> pDepthAttachment;
bool isBoxVisible(AABB bounding)
{
uint2 mipDimensions = uint2((uint(pViewParams.screenDimensions.x) + BLOCK_SIZE - 1) / BLOCK_SIZE, (uint(pViewParams.screenDimensions.y) + BLOCK_SIZE - 1) / BLOCK_SIZE);
// now we calculate what mip level we need to only sample up to 4 texels covering the entire meshlet
uint2 screenCornerMin = mipDimensions;
uint2 screenCornerMax = uint2(0, 0);
// we use reverse depth, so higher values are closer
float maxDepth = 0;
{
float4 corners[8];
corners[0] = float4(bounding.min.x, bounding.min.y, bounding.min.z, 1.0f);
corners[1] = float4(bounding.min.x, bounding.min.y, bounding.max.z, 1.0f);
corners[2] = float4(bounding.min.x, bounding.max.y, bounding.min.z, 1.0f);
corners[3] = float4(bounding.min.x, bounding.max.y, bounding.max.z, 1.0f);
corners[4] = float4(bounding.max.x, bounding.min.y, bounding.min.z, 1.0f);
corners[5] = float4(bounding.max.x, bounding.min.y, bounding.max.z, 1.0f);
corners[6] = float4(bounding.max.x, bounding.max.y, bounding.min.z, 1.0f);
corners[7] = float4(bounding.max.x, bounding.max.y, bounding.max.z, 1.0f);
for(uint i = 0; i < 8; ++i)
{
float4 clipCorner = mul(modelViewProjection, corners[i]);
float4 screenCorner = clipToScreen(clipCorner) / BLOCK_SIZE;
screenCornerMin = uint2(min(screenCornerMin.x, uint(screenCorner.x)), min(screenCornerMin.y, uint(screenCorner.y)));
screenCornerMax = uint2(max(screenCornerMax.x, uint(screenCorner.x)), max(screenCornerMax.y, uint(screenCorner.y)));
maxDepth = max(maxDepth, screenCorner.z);
}
}
uint mipOffset = 0;
// in theory this wouldnt work if no corner was in screen, as min would be greater that max, however we verified that with view culling
while(screenCornerMax.x - screenCornerMin.x > 1 || screenCornerMax.y - screenCornerMin.y > 1)
{
mipOffset += mipDimensions.x * mipDimensions.y;
mipDimensions = uint2(mipDimensions.x + 1, mipDimensions.y + 1) / 2;
screenCornerMin /= 2;
screenCornerMax /= 2;
}
// now we sample 4 texels from the depth at the calculated mip level, this should give us the screen extent of the meshlet
float d1 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMin.x];
float d2 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMax.x];
float d3 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMin.x];
float d4 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMax.x];
// we want to check if the minimum depth (the value farthest away) is smaller than the maximum bounding box depth
// otherwise, there is no way for the meshlet to be visible
float d = min(min(d1, d2), min(d3, d4));
if(d < maxDepth)
{
return true;
}
return false;
}
[numthreads(TASK_GROUP_SIZE, 1, 1)]
[shader("amplification")]
void taskMain(
@@ -43,8 +99,13 @@ void taskMain(
viewFrustum.sides[1] = computePlane(origin, corners[1], corners[3]);
viewFrustum.sides[2] = computePlane(origin, corners[0], corners[1]);
viewFrustum.sides[3] = computePlane(origin, corners[3], corners[2]);
meshVisible = isBoxVisible(mesh.bounding);
}
GroupMemoryBarrierWithGroupSync();
if(!meshVisible)
{
return;
}
for (uint i = threadID; i < mesh.numMeshlets; i += TASK_GROUP_SIZE)
{
uint m = p.meshletOffset + i;
@@ -57,53 +118,8 @@ void taskMain(
// if the meshlet is outside of the frustum, we skip it since we cant do depth culling anyways
if(meshlet.bounding.insideFrustum(viewFrustum))
{
uint2 mipDimensions = uint2((uint(pViewParams.screenDimensions.x) + BLOCK_SIZE - 1) / BLOCK_SIZE, (uint(pViewParams.screenDimensions.y) + BLOCK_SIZE - 1) / BLOCK_SIZE);
// now we calculate what mip level we need to only sample up to 4 texels covering the entire meshlet
uint2 screenCornerMin = mipDimensions;
uint2 screenCornerMax = uint2(0, 0);
// we use reverse depth, so higher values are closer
float maxDepth = 0;
{
float4 corners[8];
corners[0] = float4(meshlet.bounding.min.x, meshlet.bounding.min.y, meshlet.bounding.min.z, 1.0f);
corners[1] = float4(meshlet.bounding.min.x, meshlet.bounding.min.y, meshlet.bounding.max.z, 1.0f);
corners[2] = float4(meshlet.bounding.min.x, meshlet.bounding.max.y, meshlet.bounding.min.z, 1.0f);
corners[3] = float4(meshlet.bounding.min.x, meshlet.bounding.max.y, meshlet.bounding.max.z, 1.0f);
corners[4] = float4(meshlet.bounding.max.x, meshlet.bounding.min.y, meshlet.bounding.min.z, 1.0f);
corners[5] = float4(meshlet.bounding.max.x, meshlet.bounding.min.y, meshlet.bounding.max.z, 1.0f);
corners[6] = float4(meshlet.bounding.max.x, meshlet.bounding.max.y, meshlet.bounding.min.z, 1.0f);
corners[7] = float4(meshlet.bounding.max.x, meshlet.bounding.max.y, meshlet.bounding.max.z, 1.0f);
for(uint i = 0; i < 8; ++i)
{
float4 clipCorner = mul(modelViewProjection, corners[i]);
float4 screenCorner = clipToScreen(clipCorner) / BLOCK_SIZE;
screenCornerMin = uint2(min(screenCornerMin.x, uint(screenCorner.x)), min(screenCornerMin.y, uint(screenCorner.y)));
screenCornerMax = uint2(max(screenCornerMax.x, uint(screenCorner.x)), max(screenCornerMax.y, uint(screenCorner.y)));
maxDepth = max(maxDepth, screenCorner.z);
}
}
uint mipOffset = 0;
// in theory this wouldnt work if no corner was in screen, as min would be greater that max, however we verified that with view culling
while(screenCornerMax.x - screenCornerMin.x > 1 || screenCornerMax.y - screenCornerMin.y > 1)
{
mipOffset += mipDimensions.x * mipDimensions.y;
mipDimensions = uint2(mipDimensions.x + 1, mipDimensions.y + 1) / 2;
screenCornerMin /= 2;
screenCornerMax /= 2;
}
// now we sample 4 texels from the depth at the calculated mip level, this should give us the screen extent of the meshlet
float d1 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMin.x];
float d2 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMax.x];
float d3 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMin.x];
float d4 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMax.x];
// we want to check if the minimum depth (the value farthest away) is smaller than the maximum bounding box depth
// otherwise, there is no way for the meshlet to be visible
float d = min(min(d1, d2), min(d3, d4));
// this is technically not correct, as the mipmap is generated with a linear filter, but we actually would need a min filter, but whatever
if(d < maxDepth)
// if the meshlet bounding box is behind the cached depth buffer, we skip
if(isBoxVisible(meshlet.bounding))
{
uint index;
InterlockedAdd(head, 1, index);
+1 -1
View File
@@ -14,7 +14,7 @@ struct MipParam
uint2 srcMipDim;
uint2 dstMipDim;
}
layout(push_constants)
layout(push_constant)
ConstantBuffer<MipParam> pMipParam;
float getSrcDepth(uint2 pos)
+1 -1
View File
@@ -202,7 +202,7 @@ void MaterialLoader::import(MaterialImportArgs args, PMaterialAsset asset) {
}
}
}
asset->material = new Material(graphics, numTextures, numSamplers, numFloats, materialName, std::move(expressions),
asset->material = new Material(graphics, numTextures, numSamplers, numFloats, false, 1, materialName, std::move(expressions),
std::move(parameters), std::move(mat));
asset->material->compile();
+6 -6
View File
@@ -19,7 +19,6 @@
#include <set>
#include <stb_image_write.h>
using namespace Seele;
MeshLoader::MeshLoader(Gfx::PGraphics graphics) : graphics(graphics) {}
@@ -372,10 +371,13 @@ void MeshLoader::loadMaterials(const aiScene* scene, const Array<PTextureAsset>&
}
break;
};
bool twoSided = true;
material->Get(AI_MATKEY_TWOSIDED, twoSided);
float opacity = 1.0f;
material->Get(AI_MATKEY_OPACITY, opacity);
OMaterialAsset baseMat = new MaterialAsset(importPath, materialName);
baseMat->material = new Material(graphics, numTextures, numSamplers, numFloats, materialName, std::move(expressions),
std::move(parameters), std::move(brdf));
baseMat->material = new Material(graphics, numTextures, numSamplers, numFloats, twoSided, opacity, materialName,
std::move(expressions), std::move(parameters), std::move(brdf));
baseMat->material->compile();
graphics->getShaderCompiler()->registerMaterial(baseMat->material);
globalMaterials[m] = baseMat->instantiate(InstantiationParameter{
@@ -473,8 +475,6 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialIns
globalMeshes[meshIndex]->meshlets = std::move(meshlets);
globalMeshes[meshIndex]->indices = std::move(indices);
globalMeshes[meshIndex]->vertexCount = mesh->mNumVertices;
globalMeshes[meshIndex]->blas =
graphics->createBottomLevelAccelerationStructure(Gfx::BottomLevelASCreateInfo(globalMeshes[meshIndex]));
}
}
+5 -8
View File
@@ -63,16 +63,13 @@ int main() {
.filePath = sourcePath / "import/textures/skyboxsun5deg_tn.jpg",
.type = TextureImportType::TEXTURE_CUBEMAP,
});
// AssetImporter::importMesh(MeshImportArgs{
// .filePath = sourcePath / "import/models/greek-temple/source/greek-temple.fbx",
// .importPath = "temple"
// });
AssetImporter::importMesh(MeshImportArgs{.filePath = sourcePath / "import/models/after-the-rain-vr-sound/source/Whitechapel.fbx",
.importPath = "Whitechapel"});
// AssetImporter::importMesh(MeshImportArgs{
// .filePath = sourcePath / "import/models/nitra-castle-rawscan/source/Nitriansky.obj",
// .importPath = "Nitriansky"
// });
//AssetImporter::importMesh(MeshImportArgs{
// .filePath = sourcePath / "import/models/city-suburbs/city-suburbs.gltf",
// .importPath = "suburbs",
//});
vd->commitMeshes();
WindowCreateInfo mainWindowInfo;
mainWindowInfo.title = "SeeleEngine";
mainWindowInfo.width = 1920;
+1
View File
@@ -43,5 +43,6 @@ void Camera::buildViewMatrix() {
Vector lookAt = eyePos + getTransform().getForward();
viewMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0));
cameraPos = eyePos;
cameraForward = getTransform().getForward();
bNeedsViewBuild = false;
}
+2
View File
@@ -16,6 +16,7 @@ struct Camera {
return viewMatrix;
}
Vector getCameraPosition() const { return cameraPos; }
Vector getCameraForward() const { return cameraForward; }
void mouseMove(float deltaX, float deltaY);
void mouseScroll(float x);
void moveX(float amount);
@@ -29,6 +30,7 @@ struct Camera {
float pitch;
Matrix4 viewMatrix;
Vector cameraPos;
Vector cameraForward;
bool bNeedsViewBuild;
};
} // namespace Component
+3 -1
View File
@@ -54,6 +54,7 @@ DEFINE_REF(DescriptorPool)
DECLARE_REF(UniformBuffer)
DECLARE_REF(ShaderBuffer)
DECLARE_REF(Texture)
DECLARE_REF(Texture2D)
DECLARE_REF(Sampler)
class DescriptorSet {
public:
@@ -67,7 +68,8 @@ class DescriptorSet {
virtual void updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::PSampler samplerState) = 0;
virtual void updateTexture(uint32 binding, PTexture texture, PSampler samplerState = nullptr) = 0;
virtual void updateTexture(uint32 binding, uint32 dstArrayIndex, PTexture texture) = 0;
virtual void updateTextureArray(uint32_t binding, Array<PTexture> texture) = 0;
virtual void updateTextureArray(uint32_t binding, Array<PTexture2D> texture) = 0;
virtual void updateSamplerArray(uint32_t binding, Array<PSampler> samplers) = 0;
bool operator<(PDescriptorSet other);
constexpr PDescriptorLayout getLayout() const { return layout; }
+4 -3
View File
@@ -98,6 +98,7 @@ struct ShaderBufferCreateInfo {
DataSource sourceData = DataSource();
uint64 numElements = 1;
uint32 clearValue = 0;
uint8 createCleared = 0;
uint8 dynamic = 0;
uint8 vertexBuffer = 0;
std::string name = "Unnamed";
@@ -169,10 +170,10 @@ struct ColorBlendState {
struct BlendAttachment {
uint32 blendEnable = 0;
SeBlendFactor srcColorBlendFactor = Gfx::SE_BLEND_FACTOR_SRC_ALPHA;
SeBlendFactor dstColorBlendFactor = Gfx::SE_BLEND_FACTOR_SRC_ALPHA;
SeBlendFactor dstColorBlendFactor = Gfx::SE_BLEND_FACTOR_DST_ALPHA;
SeBlendOp colorBlendOp = Gfx::SE_BLEND_OP_ADD;
SeBlendFactor srcAlphaBlendFactor = Gfx::SE_BLEND_FACTOR_SRC_ALPHA;
SeBlendFactor dstAlphaBlendFactor = Gfx::SE_BLEND_FACTOR_SRC_ALPHA;
SeBlendFactor srcAlphaBlendFactor = Gfx::SE_BLEND_FACTOR_ONE;
SeBlendFactor dstAlphaBlendFactor = Gfx::SE_BLEND_FACTOR_ONE;
SeBlendOp alphaBlendOp = Gfx::SE_BLEND_OP_ADD;
SeColorComponentFlags colorWriteMask =
Gfx::SE_COLOR_COMPONENT_R_BIT | Gfx::SE_COLOR_COMPONENT_G_BIT | Gfx::SE_COLOR_COMPONENT_B_BIT | Gfx::SE_COLOR_COMPONENT_A_BIT;
+115 -1
View File
@@ -75,6 +75,9 @@ BasePass::~BasePass() {}
void BasePass::beginFrame(const Component::Camera& cam) {
RenderPass::beginFrame(cam);
cameraPos = cam.getCameraPosition();
cameraForward = cam.getCameraForward();
lightCullingLayout->reset();
opaqueCulling = lightCullingLayout->allocateDescriptorSet();
transparentCulling = lightCullingLayout->allocateDescriptorSet();
@@ -95,7 +98,9 @@ void BasePass::render() {
Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("BasePass");
permutation.setDepthCulling(true); // always use the culling info
permutation.setPositionOnly(false);
Array<VertexData::TransparentDraw> transparentData;
for (VertexData* vertexData : VertexData::getList()) {
transparentData.addAll(vertexData->getTransparentData());
vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer);
vertexData->getInstanceDataSet()->writeChanges();
permutation.setVertexData(vertexData->getTypeName());
@@ -120,6 +125,9 @@ void BasePass::render() {
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
assert(collection != nullptr);
bool twoSided = materialData.material->isTwoSided();
if (graphics->supportMeshShading()) {
Gfx::MeshPipelineCreateInfo pipelineInfo = {
.taskShader = collection->taskShader,
@@ -131,6 +139,10 @@ void BasePass::render() {
{
.samples = viewport->getSamples(),
},
.rasterizationState =
{
.cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT),
},
.depthStencilState =
{
.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL,
@@ -152,6 +164,10 @@ void BasePass::render() {
{
.samples = viewport->getSamples(),
},
.rasterizationState =
{
.cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT),
},
.depthStencilState =
{
.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL,
@@ -184,8 +200,106 @@ void BasePass::render() {
commands.add(std::move(command));
}
}
graphics->executeCommands(std::move(commands));
Map<float, VertexData::TransparentDraw> sortedDraws;
for (const auto& t : transparentData) {
Vector toCenter = Vector(t.worldPosition) - cameraPos;
float dist = glm::length(toCenter) * glm::dot(glm::normalize(toCenter), cameraForward);
sortedDraws[dist] = t;
}
Gfx::ORenderCommand command = graphics->createRenderCommand("TransparentDraw");
command->setViewport(viewport);
for (const auto& [_, t] : sortedDraws) {
permutation.setVertexData(t.vertexData->getTypeName());
permutation.setMaterial(t.matInst->getBaseMaterial()->getName());
Gfx::PermutationId id(permutation);
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
assert(collection != nullptr);
bool twoSided = t.matInst->getBaseMaterial()->isTwoSided();
if (graphics->supportMeshShading()) {
Gfx::MeshPipelineCreateInfo pipelineInfo = {
.taskShader = collection->taskShader,
.meshShader = collection->meshShader,
.fragmentShader = collection->fragmentShader,
.renderPass = renderPass,
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
},
.rasterizationState =
{
.cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT),
},
.depthStencilState =
{
.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL,
},
.colorBlend =
{
.attachmentCount = 1,
.blendAttachments =
{
Gfx::ColorBlendState::BlendAttachment{
.blendEnable = true,
},
},
},
};
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
command->bindPipeline(pipeline);
} else {
Gfx::LegacyPipelineCreateInfo pipelineInfo = {
.vertexShader = collection->vertexShader,
.fragmentShader = collection->fragmentShader,
.renderPass = renderPass,
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
},
.rasterizationState =
{
.cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT),
},
.depthStencilState =
{
.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL,
},
.colorBlend =
{
.attachmentCount = 1,
.blendAttachments =
{
Gfx::ColorBlendState::BlendAttachment{
.blendEnable = true,
},
},
},
};
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
command->bindPipeline(pipeline);
}
command->bindDescriptor({viewParamsSet, t.vertexData->getVertexDataSet(), t.vertexData->getInstanceDataSet(),
scene->getLightEnvironment()->getDescriptorSet(), Material::getDescriptorSet(), transparentCulling});
command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(VertexData::DrawCallOffsets), &t.offsets);
if (graphics->supportMeshShading()) {
command->drawMesh(1, 1, 1);
} else {
// command->bindIndexBuffer(t.vertexData->getIndexBuffer());
// for (const auto& meshData : drawCall.instanceMeshData) {
// // all meshlets of a mesh share the same indices offset
// command->drawIndexed(meshData.numIndices, 1, meshData.firstIndex, vertexData->getIndicesOffset(meshData.meshletOffset),
// 0);
// }
}
}
graphics->endRenderPass();
query->endQuery();
}
@@ -31,6 +31,10 @@ class BasePass : public RenderPass {
// use a different texture here so we can do multisampling
Gfx::OTexture2D basePassDepth;
// used for transparency sorting
Vector cameraPos;
Vector cameraForward;
PCameraActor source;
Gfx::OPipelineLayout basePassLayout;
Gfx::ODescriptorLayout lightCullingLayout;
@@ -105,7 +105,9 @@ void DepthCullingPass::render() {
UVector2 threadGroups = (((mipDims[i] + UVector2(1, 1)) / 2u) + UVector2(BLOCK_SIZE - 1, BLOCK_SIZE - 1)) / uint32(BLOCK_SIZE);
computeCommand->dispatch(threadGroups.x, threadGroups.y, 1);
}
Array<Gfx::OComputeCommand> computeCommands;
computeCommands.add(std::move(computeCommand));
graphics->executeCommands(std::move(computeCommands));
depthMipBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TASK_SHADER_BIT_EXT);
+1 -1
View File
@@ -186,7 +186,7 @@ TextPass::FontData& TextPass::getFontData(PFontAsset font) {
const auto& fontGlyphs = font->getGlyphData();
FontData& fd = fontData[font];
Array<GlyphData> glyphData;
Array<Gfx::PTexture> textures;
Array<Gfx::PTexture2D> textures;
glyphData.reserve(fontGlyphs.size());
for (const auto& [key, value] : fontGlyphs) {
fd.characterToGlyphIndex[key] = static_cast<uint32>(glyphData.size());
+1 -1
View File
@@ -37,7 +37,7 @@ class UIPass : public RenderPass {
Gfx::OPipelineLayout pipelineLayout;
Array<UI::RenderElementStyle> renderElements;
Array<Gfx::PTexture> usedTextures;
Array<Gfx::PTexture2D> usedTextures;
};
DEFINE_REF(UIPass);
} // namespace Seele
@@ -79,6 +79,7 @@ void VisibilityPass::publishOutputs() {
cullingBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.clearValue = 0xffffffff,
.createCleared = true,
.dynamic = true,
.name = "CullingBuffer",
});
+213 -150
View File
@@ -17,6 +17,8 @@ uint64 VertexData::meshletCount = 0;
void VertexData::resetMeshData() {
std::unique_lock l(materialDataLock);
transparentInstanceData.clear();
transparentMeshData.clear();
for (auto& mat : materialData) {
for (auto& inst : mat.instances) {
inst.instanceData.clear();
@@ -36,6 +38,32 @@ void VertexData::updateMesh(entt::entity id, uint32 meshIndex, PMesh mesh, Compo
std::unique_lock l(materialDataLock);
PMaterialInstance referencedInstance = mesh->referencedMaterial->getHandle();
PMaterial mat = referencedInstance->getBaseMaterial();
const auto& data = meshData[mesh->id];
Matrix4 transformMatrix = transform.toMatrix() * mesh->transform;
InstanceData inst = InstanceData{
.transformMatrix = transformMatrix,
.inverseTransformMatrix = glm::inverse(transformMatrix),
};
if (mat->hasTransparency()) {
auto params = referencedInstance->getMaterialOffsets();
transparentData.add(TransparentDraw{
.matInst = referencedInstance,
.vertexData = this,
.offsets =
{
.instanceOffset = static_cast<uint32>(transparentInstanceData.size()),
.textureOffset = params.textureOffset,
.samplerOffset = params.samplerOffset,
.floatOffset = params.floatOffset,
},
.worldPosition = Vector(inst.transformMatrix[3]),
});
transparentInstanceData.add(inst);
transparentMeshData.add(data);
return;
}
if (materialData.size() <= mat->getId()) {
materialData.resize(mat->getId() + 1);
}
@@ -47,12 +75,7 @@ void VertexData::updateMesh(entt::entity id, uint32 meshIndex, PMesh mesh, Compo
BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()];
matInstanceData.materialInstance = referencedInstance;
Matrix4 transformMatrix = transform.toMatrix() * mesh->transform;
matInstanceData.instanceData.add(InstanceData{
.transformMatrix = transformMatrix,
.inverseTransformMatrix = glm::inverse(transformMatrix),
});
const auto& data = meshData[mesh->id];
matInstanceData.instanceData.add(inst);
auto [instanceId, meshletOffset] = getCullingMapping(id, meshIndex, data.numMeshlets);
matInstanceData.instanceMeshData.add(data);
matInstanceData.cullingOffsets.add(meshletOffset);
@@ -157,6 +180,25 @@ void VertexData::createDescriptors() {
});
instanceMeshDataBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_MEMORY_READ_BIT, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
transparentInstanceDataBuffer->rotateBuffer(sizeof(InstanceData) * transparentInstanceData.size());
transparentInstanceDataBuffer->updateContents(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(InstanceData) * transparentInstanceData.size(),
.data = (uint8*)transparentInstanceData.data(),
},
});
transparentMeshDataBuffer->rotateBuffer(sizeof(MeshData) * transparentMeshData.size());
transparentMeshDataBuffer->updateContents(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(MeshData) * transparentMeshData.size(),
.data = (uint8*)transparentMeshData.data(),
},
});
instanceDataLayout->reset();
descriptorSet = instanceDataLayout->allocateDescriptorSet();
descriptorSet->updateBuffer(0, instanceBuffer);
@@ -169,176 +211,197 @@ void VertexData::createDescriptors() {
}
void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet> loadedMeshlets) {
assert(loadedMeshlets.size() < 2048);
std::unique_lock l(vertexDataLock);
meshlets.reserve(meshlets.size() + loadedMeshlets.size());
vertexIndices.reserve(vertexIndices.size() + loadedMeshlets.size() * Gfx::numVerticesPerMeshlet);
primitiveIndices.reserve(primitiveIndices.size() + loadedMeshlets.size() * Gfx::numPrimitivesPerMeshlet * 3);
uint32 meshletOffset = meshlets.size();
AABB meshAABB;
for (uint32 i = 0; i < loadedMeshlets.size(); ++i) {
Meshlet& m = loadedMeshlets[i];
meshAABB = meshAABB.combine(m.boundingBox);
uint32 vertexOffset = vertexIndices.size();
vertexIndices.resize(vertexOffset + m.numVertices);
std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32));
uint32 primitiveOffset = primitiveIndices.size();
primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3));
std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8));
meshlets.add(MeshletDescription{
.bounding = m.boundingBox, //.toSphere(),
.vertexCount = m.numVertices,
.primitiveCount = m.numPrimitives,
.vertexOffset = vertexOffset,
.primitiveOffset = primitiveOffset,
.color = Vector((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX),
.indicesOffset = (uint32)meshOffsets[id],
std::unique_lock l(vertexDataLock);
meshlets.reserve(meshlets.size() + loadedMeshlets.size());
vertexIndices.reserve(vertexIndices.size() + loadedMeshlets.size() * Gfx::numVerticesPerMeshlet);
primitiveIndices.reserve(primitiveIndices.size() + loadedMeshlets.size() * Gfx::numPrimitivesPerMeshlet * 3);
uint32 meshletOffset = meshlets.size();
AABB meshAABB;
for (uint32 i = 0; i < loadedMeshlets.size(); ++i) {
Meshlet& m = loadedMeshlets[i];
meshAABB = meshAABB.combine(m.boundingBox);
uint32 vertexOffset = vertexIndices.size();
vertexIndices.resize(vertexOffset + m.numVertices);
std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32));
uint32 primitiveOffset = primitiveIndices.size();
primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3));
std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8));
meshlets.add(MeshletDescription{
.bounding = m.boundingBox, //.toSphere(),
.vertexCount = m.numVertices,
.primitiveCount = m.numPrimitives,
.vertexOffset = vertexOffset,
.primitiveOffset = primitiveOffset,
.color = Vector((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX),
.indicesOffset = (uint32)meshOffsets[id],
});
}
meshData[id] = MeshData{
.bounding = meshAABB, //.toSphere(),
.numMeshlets = (uint32)loadedMeshlets.size(),
.meshletOffset = meshletOffset,
.firstIndex = (uint32)indices.size(),
.numIndices = (uint32)loadedIndices.size(),
};
indices.resize(indices.size() + loadedIndices.size());
std::memcpy(indices.data() + meshData[id].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32));
}
void VertexData::commitMeshes() {
indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * indices.size(),
.data = (uint8*)indices.data(),
},
.indexType = Gfx::SE_INDEX_TYPE_UINT32,
.name = "IndexBuffer",
});
meshletBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(MeshletDescription) * meshlets.size(),
.data = (uint8*)meshlets.data(),
},
.numElements = meshlets.size(),
.dynamic = false,
.name = "MeshletBuffer",
});
vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * vertexIndices.size(),
.data = (uint8*)vertexIndices.data(),
},
.numElements = vertexIndices.size(),
.dynamic = false,
.name = "VertexIndicesBuffer",
});
}
meshData[id] = MeshData{
.bounding = meshAABB, //.toSphere(),
.numMeshlets = (uint32)loadedMeshlets.size(),
.meshletOffset = meshletOffset,
.firstIndex = (uint32)indices.size(),
.numIndices = (uint32)loadedIndices.size(),
};
indices.resize(indices.size() + loadedIndices.size());
std::memcpy(indices.data() + meshData[id].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32));
indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * indices.size(),
.data = (uint8*)indices.data(),
},
.indexType = Gfx::SE_INDEX_TYPE_UINT32,
.name = "IndexBuffer",
});
meshletBuffer = graphics->createShaderBuffer(
ShaderBufferCreateInfo{.sourceData = {.size = sizeof(MeshletDescription) * meshlets.size(), .data = (uint8*)meshlets.data()},
.numElements = meshlets.size(),
.dynamic = false,
.name = "MeshletBuffer"});
vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{.sourceData =
{
.size = sizeof(uint32) * vertexIndices.size(),
.data = (uint8*)vertexIndices.data(),
},
.numElements = vertexIndices.size(),
.dynamic = false,
.name = "VertexIndicesBuffer"});
primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint8) * primitiveIndices.size(),
.data = (uint8*)primitiveIndices.data(),
},
.numElements = primitiveIndices.size(),
.dynamic = false,
.name = "PrimitiveIndicesBuffer",
});
primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint8) * primitiveIndices.size(),
.data = (uint8*)primitiveIndices.data(),
},
.numElements = primitiveIndices.size(),
.dynamic = false,
.name = "PrimitiveIndicesBuffer",
});
}
MeshId VertexData::allocateVertexData(uint64 numVertices) {
std::unique_lock l(vertexDataLock);
MeshId res{idCounter++};
meshOffsets[res] = head;
meshVertexCounts[res] = numVertices;
head += numVertices;
if (head > verticesAllocated) {
verticesAllocated = std::max(head, verticesAllocated + NUM_DEFAULT_ELEMENTS);
resizeBuffers();
}
return res;
std::unique_lock l(vertexDataLock);
MeshId res{idCounter++};
meshOffsets[res] = head;
meshVertexCounts[res] = numVertices;
head += numVertices;
if (head > verticesAllocated) {
verticesAllocated = std::max(head, verticesAllocated + NUM_DEFAULT_ELEMENTS);
resizeBuffers();
}
return res;
}
uint64 VertexData::getMeshOffset(MeshId id) { return meshOffsets[id]; }
uint64 VertexData::getMeshOffset(MeshId id) {
return meshOffsets[id]; }
uint64 VertexData::getMeshVertexCount(MeshId id) { return meshVertexCounts[id]; }
uint64 VertexData::getMeshVertexCount(MeshId id) {
return meshVertexCounts[id]; }
List<VertexData*> vertexDataList;
List<VertexData*> VertexData::getList() { return vertexDataList; }
List<VertexData*> VertexData::getList() {
return vertexDataList; }
VertexData* VertexData::findByTypeName(std::string name) {
for (auto vd : vertexDataList) {
if (vd->getTypeName() == name) {
return vd;
for (auto vd : vertexDataList) {
if (vd->getTypeName() == name) {
return vd;
}
}
}
return nullptr;
return nullptr;
}
void VertexData::init(Gfx::PGraphics _graphics) {
graphics = _graphics;
verticesAllocated = NUM_DEFAULT_ELEMENTS;
instanceDataLayout = graphics->createDescriptorLayout("pScene");
graphics = _graphics;
verticesAllocated = NUM_DEFAULT_ELEMENTS;
instanceDataLayout = graphics->createDescriptorLayout("pScene");
// instanceData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 0,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 1,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshletData
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 2, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// primitiveIndices
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 3, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// vertexIndices
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 4, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// cullingOffset
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 5, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// cullingInfos
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 6, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// instanceData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 0,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 1,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshletData
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 2, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// primitiveIndices
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 3, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// vertexIndices
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 4, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// cullingOffset
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 5, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
// cullingInfos
instanceDataLayout->addDescriptorBinding(
Gfx::DescriptorBinding{.binding = 6, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
instanceDataLayout->create();
instanceDataLayout->create();
cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "MeshletOffset",
});
instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "InstanceBuffer",
});
instanceMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "MeshDataBuffer",
});
resizeBuffers();
graphics->getShaderCompiler()->registerVertexData(this);
cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "MeshletOffset",
});
instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "InstanceBuffer",
});
instanceMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "MeshDataBuffer",
});
transparentInstanceDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "TransparentInstanceBuffer",
});
transparentMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true,
.name = "TransparentMeshBuffer",
});
resizeBuffers();
graphics->getShaderCompiler()->registerVertexData(this);
}
void VertexData::destroy() {
instanceBuffer = nullptr;
instanceMeshDataBuffer = nullptr;
instanceDataLayout = nullptr;
meshletBuffer = nullptr;
vertexIndicesBuffer = nullptr;
primitiveIndicesBuffer = nullptr;
indexBuffer = nullptr;
meshData.clear();
materialData.clear();
instanceBuffer = nullptr;
instanceMeshDataBuffer = nullptr;
instanceDataLayout = nullptr;
meshletBuffer = nullptr;
vertexIndicesBuffer = nullptr;
primitiveIndicesBuffer = nullptr;
indexBuffer = nullptr;
meshData.clear();
materialData.clear();
}
VertexData::CullingMapping VertexData::getCullingMapping(entt::entity id, uint32 meshIndex, uint32 numMeshlets) {
MeshMapping key = MeshMapping{.id = id, .meshId = meshIndex};
if (!instanceIdMap.contains(key)) {
instanceIdMap[key] = CullingMapping{.instanceId = instanceCount++, .cullingOffset = uint32(meshletCount)};
meshletCount += numMeshlets;
}
return instanceIdMap[key];
MeshMapping key = MeshMapping{.id = id, .meshId = meshIndex};
if (!instanceIdMap.contains(key)) {
instanceIdMap[key] = CullingMapping{.instanceId = instanceCount++, .cullingOffset = uint32(meshletCount)};
meshletCount += numMeshlets;
}
return instanceIdMap[key];
}
VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {}
+18
View File
@@ -41,10 +41,17 @@ class VertexData {
PMaterial material;
Array<BatchedDrawCall> instances;
};
struct TransparentDraw {
PMaterialInstance matInst;
VertexData* vertexData;
DrawCallOffsets offsets;
Vector worldPosition;
};
void resetMeshData();
void updateMesh(entt::entity id, uint32 meshIndex, PMesh mesh, Component::Transform& transform);
void createDescriptors();
void loadMesh(MeshId id, Array<uint32> indices, Array<Meshlet> meshlets);
void commitMeshes();
MeshId allocateVertexData(uint64 numVertices);
uint64 getMeshOffset(MeshId id);
uint64 getMeshVertexCount(MeshId id);
@@ -60,6 +67,7 @@ class VertexData {
Gfx::PDescriptorLayout getInstanceDataLayout() { return instanceDataLayout; }
Gfx::PDescriptorSet getInstanceDataSet() { return descriptorSet; }
const Array<MaterialData>& getMaterialData() const { return materialData; }
const Array<TransparentDraw>& getTransparentData() const { return transparentData; }
const MeshData& getMeshData(MeshId id) { return meshData[id]; }
uint64 getIndicesOffset(uint32 meshletIndex) { return meshlets[meshletIndex].indicesOffset; }
uint64 getNumInstances() const { return instanceData.size(); }
@@ -91,10 +99,13 @@ class VertexData {
};
std::mutex materialDataLock;
Array<MaterialData> materialData;
Array<TransparentDraw> transparentData;
std::mutex vertexDataLock;
Map<MeshId, MeshData> meshData;
Map<MeshId, uint64> meshOffsets;
Map<MeshId, uint64> meshVertexCounts;
Array<MeshletDescription> meshlets;
Array<uint8> primitiveIndices;
Array<uint32> vertexIndices;
@@ -121,8 +132,15 @@ class VertexData {
// Material data
Array<InstanceData> instanceData;
Gfx::OShaderBuffer instanceBuffer;
Array<MeshData> instanceMeshData;
Gfx::OShaderBuffer instanceMeshDataBuffer;
Array<InstanceData> transparentInstanceData;
Gfx::OShaderBuffer transparentInstanceDataBuffer;
Array<MeshData> transparentMeshData;
Gfx::OShaderBuffer transparentMeshDataBuffer;
Gfx::PDescriptorSet descriptorSet;
uint64 idCounter;
uint64 head;
+12 -9
View File
@@ -10,8 +10,8 @@ using namespace Seele::Vulkan;
BufferAllocation::BufferAllocation(PGraphics graphics, const std::string& name, VkBufferCreateInfo bufferInfo,
VmaAllocationCreateInfo allocInfo, Gfx::QueueType owner, uint64 alignment)
: CommandBoundResource(graphics), size(bufferInfo.size), owner(owner) {
VK_CHECK(vmaCreateBufferWithAlignment(graphics->getAllocator(), &bufferInfo, &allocInfo, alignment, &buffer, &allocation, nullptr));
: CommandBoundResource(graphics), size(bufferInfo.size), name(name), owner(owner) {
VK_CHECK(vmaCreateBufferWithAlignment(graphics->getAllocator(), &bufferInfo, &allocInfo, alignment, &buffer, &allocation, &info));
vmaGetAllocationMemoryProperties(graphics->getAllocator(), allocation, &properties);
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
@@ -167,10 +167,10 @@ void BufferAllocation::readContents(uint64 regionOffset, uint64 regionSize, void
}
Buffer::Buffer(PGraphics graphics, uint64 size, VkBufferUsageFlags usage, Gfx::QueueType queueType, bool dynamic, std::string name,
uint32 clearValue)
bool createCleared, uint32 clearValue)
: graphics(graphics), currentBuffer(0), initialOwner(queueType),
usage(usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
dynamic(dynamic), name(name), clearValue(clearValue) {
dynamic(dynamic), createCleared(createCleared), name(name), clearValue(clearValue) {
if (size > 0) {
buffers.add(nullptr);
createBuffer(size, 0);
@@ -235,10 +235,13 @@ void Buffer::createBuffer(uint64 size, uint32 destIndex) {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
};
buffers[destIndex] = new BufferAllocation(graphics, name, info, allocInfo, initialOwner);
PCommand command = graphics->getQueueCommands(initialOwner)->getCommands();
vkCmdFillBuffer(command->getHandle(), buffers[destIndex]->buffer, 0, VK_WHOLE_SIZE, clearValue);
pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
if (createCleared)
{
PCommand command = graphics->getQueueCommands(initialOwner)->getCommands();
vkCmdFillBuffer(command->getHandle(), buffers[destIndex]->buffer, 0, VK_WHOLE_SIZE, clearValue);
pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
}
}
}
@@ -321,7 +324,7 @@ ShaderBuffer::ShaderBuffer(PGraphics graphics, const ShaderBufferCreateInfo& cre
(createInfo.vertexBuffer ? VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
: 0),
createInfo.sourceData.owner, createInfo.dynamic, createInfo.name) {
createInfo.sourceData.owner, createInfo.dynamic, createInfo.name, createInfo.createCleared, createInfo.clearValue) {
if (createInfo.sourceData.size > 0 && createInfo.sourceData.data != nullptr) {
getAlloc()->updateContents(createInfo.sourceData.offset, createInfo.sourceData.size, createInfo.sourceData.data);
}
+4 -1
View File
@@ -22,13 +22,15 @@ class BufferAllocation : public CommandBoundResource {
VmaAllocationInfo info = VmaAllocationInfo();
VkMemoryPropertyFlags properties = 0;
uint64 size = 0;
std::string name;
VkDeviceAddress deviceAddress;
Gfx::QueueType owner;
};
DEFINE_REF(BufferAllocation);
class Buffer {
public:
Buffer(PGraphics graphics, uint64 size, VkBufferUsageFlags usage, Gfx::QueueType initialOwner, bool dynamic, std::string name, uint32 clearValue = 0);
Buffer(PGraphics graphics, uint64 size, VkBufferUsageFlags usage, Gfx::QueueType initialOwner, bool dynamic, std::string name,
bool createCleared = false, uint32 clearValue = 0);
virtual ~Buffer();
VkBuffer getHandle() const { return buffers[currentBuffer]->buffer; }
VkDeviceAddress getDeviceAddress() const { return buffers[currentBuffer]->deviceAddress; }
@@ -44,6 +46,7 @@ class Buffer {
Array<OBufferAllocation> buffers;
VkBufferUsageFlags usage;
bool dynamic;
bool createCleared;
std::string name;
uint32 clearValue;
void rotateBuffer(uint64 size, bool preserveContents = false);
+22 -12
View File
@@ -7,7 +7,6 @@
#include "RenderPass.h"
#include "Window.h"
using namespace Seele;
using namespace Seele::Vulkan;
@@ -151,8 +150,7 @@ void Command::waitForCommand(uint32 timeout) {
checkFence();
}
void Command::setPipelineStatisticsFlags(VkQueryPipelineStatisticFlags flags)
{ statisticsFlags = flags; }
void Command::setPipelineStatisticsFlags(VkQueryPipelineStatisticFlags flags) { statisticsFlags = flags; }
void Command::bindResource(PCommandBoundResource resource) {
resource->bind();
@@ -239,8 +237,10 @@ void RenderCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet, Array<uint
descriptor->bind();
boundResources.add(descriptor.getHandle());
for (auto binding : descriptor->boundResources) {
binding->bind();
boundResources.add(binding);
for (auto res : binding) {
res->bind();
boundResources.add(res);
}
}
VkDescriptorSet setHandle = descriptor->getHandle();
@@ -260,8 +260,13 @@ void RenderCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptorS
boundResources.add(descriptorSet.getHandle());
for (auto binding : descriptorSet->boundResources) {
binding->bind();
boundResources.add(binding);
for (auto res : binding) {
// partially bound descriptors can include nulls
if (res != nullptr) {
res->bind();
boundResources.add(res);
}
}
}
sets[pipeline->getPipelineLayout()->findParameter(descriptorSet->getName())] = descriptorSet->getHandle();
}
@@ -316,7 +321,7 @@ void RenderCommand::drawMeshIndirect(Gfx::PShaderBuffer buffer, uint64 offset, u
vkCmdDrawMeshTasksIndirectEXT(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset, drawCount, stride);
}
void RenderCommand::traceRays() { }
void RenderCommand::traceRays() {}
ComputeCommand::ComputeCommand(PGraphics graphics, VkCommandPool cmdPool) : graphics(graphics), owner(cmdPool) {
VkCommandBufferAllocateInfo allocInfo = {
@@ -378,8 +383,10 @@ void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet, Array<uin
boundResources.add(descriptor.getHandle());
for (auto binding : descriptor->boundResources) {
binding->bind();
boundResources.add(binding);
for (auto res : binding) {
res->bind();
boundResources.add(res);
}
}
VkDescriptorSet setHandle = descriptor->getHandle();
@@ -398,9 +405,12 @@ void ComputeCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptor
boundResources.add(descriptorSet.getHandle());
// std::cout << "Binding descriptor " << descriptorSet->getHandle() << " to cmd " << handle << std::endl;
for (auto binding : descriptorSet->boundResources) {
binding->bind();
boundResources.add(binding);
for (auto res : binding) {
res->bind();
boundResources.add(res);
}
}
sets[pipeline->getPipelineLayout()->findParameter(descriptorSet->getName())] = descriptorSet->getHandle();
}
+52 -19
View File
@@ -168,13 +168,17 @@ DescriptorSet::DescriptorSet(PGraphics graphics, PDescriptorPool owner)
: Gfx::DescriptorSet(owner->getLayout()), CommandBoundResource(graphics), setHandle(VK_NULL_HANDLE), graphics(graphics), owner(owner),
bindCount(0), currentlyInUse(false) {
boundResources.resize(owner->getLayout()->getBindings().size());
for (uint32 i = 0; i < boundResources.size(); ++i)
{
boundResources[i].resize(owner->getLayout()->getBindings()[i].descriptorCount);
}
}
DescriptorSet::~DescriptorSet() {}
void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer) {
PUniformBuffer vulkanBuffer = uniformBuffer.cast<UniformBuffer>();
if (boundResources[binding] == vulkanBuffer->getAlloc()) {
if (boundResources[binding][0] == vulkanBuffer->getAlloc()) {
return;
}
@@ -195,12 +199,12 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBu
.pBufferInfo = &bufferInfos.back(),
});
boundResources[binding] = vulkanBuffer->getAlloc();
boundResources[binding][0] = vulkanBuffer->getAlloc();
}
void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PShaderBuffer shaderBuffer) {
PShaderBuffer vulkanBuffer = shaderBuffer.cast<ShaderBuffer>();
if (boundResources[binding] == vulkanBuffer->getAlloc()) {
if (boundResources[binding][0] == vulkanBuffer->getAlloc()) {
return;
}
@@ -220,12 +224,12 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PShaderBuffer shaderBuff
.pBufferInfo = &bufferInfos.back(),
});
boundResources[binding] = vulkanBuffer->getAlloc();
boundResources[binding][0] = vulkanBuffer->getAlloc();
}
void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PShaderBuffer shaderBuffer) {
PShaderBuffer vulkanBuffer = shaderBuffer.cast<ShaderBuffer>();
if (boundResources[binding] == vulkanBuffer->getAlloc()) {
if (boundResources[binding][index] == vulkanBuffer->getAlloc()) {
return;
}
@@ -246,12 +250,12 @@ void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PShaderBuf
.pBufferInfo = &bufferInfos.back(),
});
boundResources[binding] = vulkanBuffer->getAlloc();
boundResources[binding][index] = vulkanBuffer->getAlloc();
}
void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSampler samplerState) {
PSampler vulkanSampler = samplerState.cast<Sampler>();
if (boundResources[binding] == vulkanSampler->getHandle()) {
if (boundResources[binding][0] == vulkanSampler->getHandle()) {
return;
}
@@ -272,13 +276,13 @@ void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSampler samplerState)
.pImageInfo = &imageInfos.back(),
});
boundResources[binding] = vulkanSampler->getHandle();
boundResources[binding][0] = vulkanSampler->getHandle();
}
void DescriptorSet::updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::PSampler samplerState)
{
PSampler vulkanSampler = samplerState.cast<Sampler>();
if (boundResources[binding] == vulkanSampler->getHandle()) {
if (boundResources[binding][dstArrayIndex] == vulkanSampler->getHandle()) {
return;
}
@@ -299,13 +303,13 @@ void DescriptorSet::updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::P
.pImageInfo = &imageInfos.back(),
});
boundResources[binding] = vulkanSampler->getHandle();
boundResources[binding][dstArrayIndex] = vulkanSampler->getHandle();
}
void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSampler samplerState) {
TextureBase* vulkanTexture = texture.cast<TextureBase>().getHandle();
if (boundResources[binding] == vulkanTexture->getHandle()) {
if (boundResources[binding][0] == vulkanTexture->getHandle()) {
return;
}
@@ -332,13 +336,13 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::
.pImageInfo = &imageInfos.back(),
});
boundResources[binding] = vulkanTexture->getHandle();
boundResources[binding][0] = vulkanTexture->getHandle();
}
void DescriptorSet::updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTexture texture)
{
TextureBase* vulkanTexture = texture.cast<TextureBase>().getHandle();
if (boundResources[binding] == vulkanTexture->getHandle()) {
if (boundResources[binding][dstArrayIndex] == vulkanTexture->getHandle()) {
return;
}
@@ -359,17 +363,16 @@ void DescriptorSet::updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTe
.pImageInfo = &imageInfos.back(),
});
boundResources[binding] = vulkanTexture->getHandle();
boundResources[binding][dstArrayIndex] = vulkanTexture->getHandle();
}
void DescriptorSet::updateTextureArray(uint32_t binding, Array<Gfx::PTexture> textures) {
void DescriptorSet::updateTextureArray(uint32_t binding, Array<Gfx::PTexture2D> textures) {
// maybe make this a parameter?
uint32 arrayElement = 0;
boundResources.resize(binding + textures.size());
for (auto& gfxTexture : textures) {
TextureBase* vulkanTexture = gfxTexture.cast<TextureBase>().getHandle();
if (boundResources[binding + arrayElement] == vulkanTexture->getHandle()) {
if (boundResources[binding][arrayElement] == vulkanTexture->getHandle()) {
continue;
}
imageInfos.add(VkDescriptorImageInfo{
@@ -382,7 +385,7 @@ void DescriptorSet::updateTextureArray(uint32_t binding, Array<Gfx::PTexture> te
if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) {
descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
}
boundResources[binding + arrayElement] = vulkanTexture->getHandle();
boundResources[binding][arrayElement] = vulkanTexture->getHandle();
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
@@ -393,10 +396,40 @@ void DescriptorSet::updateTextureArray(uint32_t binding, Array<Gfx::PTexture> te
.descriptorType = descriptorType,
.pImageInfo = &imageInfos.back(),
});
vulkanTexture->getHandle()->bind();
}
}
void DescriptorSet::updateSamplerArray(uint32_t binding, Array<Gfx::PSampler> samplers) {
// maybe make this a parameter?
uint32 arrayElement = 0;
for (auto& gfxSampler : samplers) {
PSampler vulkanSampler = gfxSampler.cast<Sampler>();
if (boundResources[binding][arrayElement] == vulkanSampler->getHandle()) {
continue;
}
imageInfos.add(VkDescriptorImageInfo{
.sampler = vulkanSampler->getHandle()->sampler,
.imageView = VK_NULL_HANDLE,
.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
boundResources[binding][arrayElement] = vulkanSampler->getHandle();
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = arrayElement++,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.pImageInfo = &imageInfos.back(),
});
}
}
void DescriptorSet::writeChanges() {
if (writeDescriptors.size() > 0) {
if (isCurrentlyBound()) {
+3 -2
View File
@@ -55,7 +55,8 @@ class DescriptorSet : public Gfx::DescriptorSet, public CommandBoundResource {
virtual void updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::PSampler samplerState) override;
virtual void updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSampler sampler = nullptr) override;
virtual void updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTexture texture) override;
virtual void updateTextureArray(uint32_t binding, Array<Gfx::PTexture> texture) override;
virtual void updateTextureArray(uint32_t binding, Array<Gfx::PTexture2D> texture) override;
virtual void updateSamplerArray(uint32_t binding, Array<Gfx::PSampler> samplers) override;
constexpr bool isCurrentlyInUse() const { return currentlyInUse; }
constexpr void allocate() { currentlyInUse = true; }
@@ -70,7 +71,7 @@ class DescriptorSet : public Gfx::DescriptorSet, public CommandBoundResource {
// since the layout is fixed, trying to bind a texture to a buffer
// would not work anyways, so casts should be safe
// Array<void*> cachedData;
Array<PCommandBoundResource> boundResources;
Array<Array<PCommandBoundResource>> boundResources;
VkDescriptorSet setHandle;
PGraphics graphics;
PDescriptorPool owner;
+6 -1
View File
@@ -51,13 +51,18 @@ void QueryPool::end() {
// sizeof(uint64) * currentQuery, resultsStride + sizeof(uint64),
// VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
graphics->getGraphicsCommands()->submitCommands();
std::unique_lock l(queryMutex);
currentQuery = (currentQuery + 1) % numQueries;
queryCV.notify_all();
}
void QueryPool::getQueryResults(Array<uint64>& results) {
//uint64 numInts = resultsStride / sizeof(uint64);
while (currentQuery == pendingQuery)
;
{
std::unique_lock l(queryMutex);
queryCV.wait(l);
}
results.resize(resultsStride/ sizeof(uint64));
vkGetQueryPoolResults(graphics->getDevice(), handle, pendingQuery, 1, resultsStride, results.data(), resultsStride,
VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT);
+2
View File
@@ -24,6 +24,8 @@ class QueryPool {
uint32 currentQuery = 0;
uint32 numQueries;
uint32 resultsStride;
std::mutex queryMutex;
std::condition_variable queryCV;
};
class OcclusionQuery : public Gfx::OcclusionQuery, public QueryPool {
public:
+5 -2
View File
@@ -4,7 +4,6 @@
#include "Graphics.h"
#include "Window.h"
using namespace Seele;
using namespace Seele::Vulkan;
@@ -76,7 +75,11 @@ DestructionManager::DestructionManager(PGraphics graphics) : graphics(graphics)
DestructionManager::~DestructionManager() {}
void DestructionManager::queueResourceForDestruction(OCommandBoundResource resource) { resources.add(std::move(resource)); }
void DestructionManager::queueResourceForDestruction(OCommandBoundResource resource) {
if (resource->isCurrentlyBound()) {
resources.add(std::move(resource));
}
}
void DestructionManager::notifyCommandComplete() {
for (size_t i = 0; i < resources.size(); ++i) {
+21 -14
View File
@@ -20,11 +20,11 @@ Array<PMaterial> Material::materials;
Material::Material() {}
Material::Material(Gfx::PGraphics graphics, uint32 numTextures, uint32 numSamplers, uint32 numFloats, std::string materialName,
Array<OShaderExpression> expressions, Array<std::string> parameter, MaterialNode brdf)
: graphics(graphics), numTextures(numTextures), numSamplers(numSamplers), numFloats(numFloats), instanceId(0),
materialName(materialName), codeExpressions(std::move(expressions)), parameters(std::move(parameter)), brdf(std::move(brdf)),
materialId(materialIdCounter++) {
Material::Material(Gfx::PGraphics graphics, uint32 numTextures, uint32 numSamplers, uint32 numFloats, bool twoSided, float opacity,
std::string materialName, Array<OShaderExpression> expressions, Array<std::string> parameter, MaterialNode brdf)
: graphics(graphics), numTextures(numTextures), numSamplers(numSamplers), numFloats(numFloats), twoSided(twoSided), opacity(opacity),
instanceId(0), materialName(materialName), codeExpressions(std::move(expressions)), parameters(std::move(parameter)),
brdf(std::move(brdf)), materialId(materialIdCounter++) {
if (layout == nullptr) {
init(graphics);
}
@@ -75,13 +75,15 @@ void Material::updateDescriptor() {
Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
layout->reset();
set = layout->allocateDescriptorSet();
for (uint32 i = 0; i < textures.size(); ++i)
{
set->updateTexture(0, i, textures[i]);
for (uint32 i = 0; i < textures.size(); ++i) {
if (textures[i] != nullptr) {
set->updateTexture(0, i, textures[i]);
}
}
for (uint32 i = 0; i < samplers.size(); ++i)
{
set->updateSampler(1, i, samplers[i]);
for (uint32 i = 0; i < samplers.size(); ++i) {
if (samplers[i] != nullptr) {
set->updateSampler(1, i, samplers[i]);
}
}
set->updateBuffer(2, floatBuffer);
set->writeChanges();
@@ -116,11 +118,16 @@ uint32 Material::addFloats(uint32 numFloats) {
OMaterialInstance Material::instantiate() {
return new MaterialInstance(instanceId++, graphics, codeExpressions, parameters, numTextures, numSamplers, numFloats);
}
bool Material::isTwoSided() const { return twoSided; }
bool Material::hasTransparency() const { return opacity != 1.0f; }
float Material::getOpacity() const { return opacity; }
void Material::save(ArchiveBuffer& buffer) const {
Serialization::save(buffer, numTextures);
Serialization::save(buffer, numSamplers);
Serialization::save(buffer, numFloats);
Serialization::save(buffer, twoSided);
Serialization::save(buffer, opacity);
Serialization::save(buffer, instanceId);
Serialization::save(buffer, materialName);
Serialization::save(buffer, codeExpressions);
@@ -130,13 +137,14 @@ void Material::save(ArchiveBuffer& buffer) const {
void Material::load(ArchiveBuffer& buffer) {
graphics = buffer.getGraphics();
if (layout == nullptr)
{
if (layout == nullptr) {
init(graphics);
}
Serialization::load(buffer, numTextures);
Serialization::load(buffer, numSamplers);
Serialization::load(buffer, numFloats);
Serialization::load(buffer, twoSided);
Serialization::load(buffer, opacity);
Serialization::load(buffer, instanceId);
Serialization::load(buffer, materialName);
Serialization::load(buffer, codeExpressions);
@@ -167,4 +175,3 @@ void Material::compile() {
codeStream << "};\n";
graphics->getShaderCompiler()->registerMaterial(this);
}
+9 -1
View File
@@ -10,7 +10,7 @@ DECLARE_NAME_REF(Gfx, Sampler)
class Material {
public:
Material();
Material(Gfx::PGraphics graphics, uint32 numTextures, uint32 numSamplers, uint32 numFloats,
Material(Gfx::PGraphics graphics, uint32 numTextures, uint32 numSamplers, uint32 numFloats, bool twoSided, float opacity,
std::string materialName, Array<OShaderExpression> expressions, Array<std::string> parameter, MaterialNode brdf);
~Material();
static void init(Gfx::PGraphics graphics);
@@ -23,8 +23,14 @@ class Material {
static uint32 addTextures(uint32 numTextures);
static uint32 addSamplers(uint32 numSamplers);
static uint32 addFloats(uint32 numFloats);
OMaterialInstance instantiate();
const std::string& getName() const { return materialName; }
bool isTwoSided() const;
bool hasTransparency() const;
float getOpacity() const;
constexpr uint64 getId() const { return materialId; }
static constexpr const PMaterial findMaterialById(uint64 id) { return materials[id]; }
@@ -41,6 +47,8 @@ class Material {
uint64 instanceId;
uint64 materialId;
std::string materialName;
bool twoSided;
float opacity;
Array<OShaderExpression> codeExpressions;
Array<std::string> parameters;
MaterialNode brdf;