Adding transparency support
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -14,7 +14,7 @@ struct MipParam
|
||||
uint2 srcMipDim;
|
||||
uint2 dstMipDim;
|
||||
}
|
||||
layout(push_constants)
|
||||
layout(push_constant)
|
||||
ConstantBuffer<MipParam> pMipParam;
|
||||
|
||||
float getSrcDepth(uint2 pos)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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) {}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user