diff --git a/gdb/Seele.py b/gdb/Seele.py new file mode 100644 index 0000000..ec18a30 --- /dev/null +++ b/gdb/Seele.py @@ -0,0 +1,31 @@ +import sys +sys.path.insert(0, '/usr/share/gdb/python/') +import gdb.printing +import glm_pp + +class ArrayPrinter: + def __init__(self, val): + self.val = val + + def to_string(self): + return f"Array(size={int(self.val['arraySize'])})" + + def children(self): + data = self.val['_data'] + size = int(self.val['arraySize']) + allocated = int(self.val['allocated']) + #yield f"[size]", size + #yield f"[allocated]", allocated + for i in range(size): + elem_val = (data + i).dereference() + yield f"[{i}]", elem_val + + def display_hint(self): + return "array" + +def build_pretty_printer(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("Seele") + pp.add_printer("Array", r'^Seele::Array<.*>$', ArrayPrinter) + return pp + +gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer()) \ No newline at end of file diff --git a/gdb/glm_pp.py b/gdb/glm_pp.py new file mode 100644 index 0000000..a54dfb4 --- /dev/null +++ b/gdb/glm_pp.py @@ -0,0 +1,68 @@ +import gdb.printing + +_type_letters = { + gdb.TYPE_CODE_FLT: "d", # or "f" + gdb.TYPE_CODE_INT: "i", + gdb.TYPE_CODE_BOOL: "b" +} + +def _vec_info(v): + # vec contains either a union of structs or a struct of unions, depending on + # configuration. gdb can't properly access the named members, and in some + # cases the names are wrong. + # It would be simple to cast to an array, similarly to how operator[] is + # implemented, but values returned by functions called from gdb don't have + # an address. + # Instead, recursively find all fields of required type and sort by offset. + T = v.type.template_argument(0) + letter = _type_letters.get(T.code, "t") + length = v.type.sizeof // T.sizeof + items = {} + def find(v, bitpos): + t = v.type.strip_typedefs() + if t.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION): + for f in t.fields(): + if hasattr(f, "bitpos"): # not static + find(v[f], bitpos + f.bitpos) + elif t == T: + items[bitpos] = v + find(v, 0) + assert len(items) == length + items = [str(f) for k, f in sorted(items.items())] + return letter, length, items + +class VecPrinter: + def __init__(self, v): + self.v = v + + def to_string(self): + letter, length, items = _vec_info(self.v) + return "{}vec{}({})".format(letter, length, ", ".join(items)) + +class MatPrinter: + def __init__(self, v): + self.v = v + + def to_string(self): + V = self.v["value"] + columns = [] + for i in range(V.type.range()[1] + 1): + letter, length, items = _vec_info(V[i]) + columns.append("({})".format(", ".join(items))) + return "{}mat{}x{}({})".format( + letter, len(columns), length, ", ".join(columns)) + +def build_pretty_printer(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("glm_pp") + pp.add_printer( + "glm::vec", r"^glm::(detail::)?tvec\d<[^<>]*>$", VecPrinter) + pp.add_printer( + "glm::mat", r"^glm::(detail::)?tmat\dx\d<[^<>]*>$", MatPrinter) + pp.add_printer( + "Seele::Vector", r"^Seele::Vector.?$", VecPrinter) + pp.add_printer( + "Seele::Matrix", r"^Seele::Matrix.?$", MatPrinter) + return pp + +gdb.printing.register_pretty_printer(gdb.current_objfile(), + build_pretty_printer()) diff --git a/res/shaders/BasePass.slang b/res/shaders/BasePass.slang index 1bc4038..2d259d0 100644 --- a/res/shaders/BasePass.slang +++ b/res/shaders/BasePass.slang @@ -5,16 +5,18 @@ import MATERIAL_FILE_NAME; const static uint64_t NUM_CASCADES = 4; -/*struct ShadowMappingData +struct ShadowMappingData { Texture2DArray shadowMaps[NUM_CASCADES]; - ConstantBuffer lightSpaceMatrices[NUM_CASCADES]; + StructuredBuffer lightSpaceMatrices[NUM_CASCADES]; + + SamplerState shadowSampler; ConstantBuffer cascadeSplits; }; ParameterBlock pShadowMapping; -*/ + struct LightCullingData { RWStructuredBuffer lightIndexList; @@ -42,16 +44,16 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target float3 result = float3(0, 0, 0); for(int i = 0; i < pLightEnv.numDirectionalLights; ++i) { - /*uint cascadeIndex = 0; + uint cascadeIndex = 0; for (uint c = 0; c < NUM_CASCADES - 1; ++c) { if (params.position_VS.z < pShadowMapping.cascadeSplits[c]) { cascadeIndex = c + 1; } } - float4 lightSpacePos = mul(biasMat, mul(pShadowMapping.lightSpaceMatrices[i], float4(params.position_WS, 1))); + float4 lightSpacePos = mul(biasMat, mul(pShadowMapping.lightSpaceMatrices[cascadeIndex][i], float4(params.position_WS, 1))); float4 shadowCoord = lightSpacePos / lightSpacePos.w; - int2 texDim; - pLightEnv.shadowMap.GetDimensions(texDim.x, texDim.y); + int3 texDim; + pShadowMapping.shadowMaps[cascadeIndex].GetDimensions(texDim.x, texDim.y, texDim.z); float scale = 1.5f; float dx = scale * 1.0 / float(texDim.x); float dy = scale * 1.0 / float(texDim.y); @@ -64,7 +66,7 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target float shadow = 1.0f; if (shadowCoord.z > 0.0 && shadowCoord.z < 1.0) { - float dist = pLightEnv.shadowMap.Sample(pLightEnv.shadowSampler, shadowCoord.xy + float2(dx * x, dy * y)).r; + float dist = pShadowMapping.shadowMaps[cascadeIndex].Sample(pShadowMapping.shadowSampler, float3(shadowCoord.xy + float2(dx * x, dy * y), i)).r; if (shadowCoord.w > 0 && dist > shadowCoord.z) { shadow = 0; @@ -73,9 +75,9 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target shadowFactor += shadow; count++; } - }*/ + } - result += /*(shadowFactor / count) **/ pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); + result += (shadowFactor / count) * pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); } for (uint i = 0; i < pLightEnv.numPointLights; ++i) { diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang index c05bcb7..e8c559c 100644 --- a/res/shaders/lib/LightEnv.slang +++ b/res/shaders/lib/LightEnv.slang @@ -61,8 +61,6 @@ struct PointLight : ILightEnv struct LightEnv { StructuredBuffer directionalLights; - Texture2D shadowMap; // todo: not an array - SamplerState shadowSampler; uint numDirectionalLights; StructuredBuffer pointLights; uint numPointLights; diff --git a/src/Engine/Graphics/Descriptor.h b/src/Engine/Graphics/Descriptor.h index 2f85897..04e89d3 100644 --- a/src/Engine/Graphics/Descriptor.h +++ b/src/Engine/Graphics/Descriptor.h @@ -9,7 +9,7 @@ struct DescriptorBinding { std::string name; // In Metal uniforms are plain bytes, and for that we need to know the struct size uint32 uniformLength = 0; - SeDescriptorType descriptorType = SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + SeDescriptorType descriptorType = SE_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK; SeImageViewType textureType = SE_IMAGE_VIEW_TYPE_2D; uint32 descriptorCount = 1; SeDescriptorBindingFlags bindingFlags = 0; @@ -27,7 +27,6 @@ class DescriptorLayout { void reset(); PDescriptorSet allocateDescriptorSet(); virtual void create() = 0; - constexpr const Array& getBindings() const { return descriptorBindings; } constexpr uint32 getHash() const { return hash; } constexpr const std::string& getName() const { return name; } @@ -62,8 +61,9 @@ class DescriptorSet { virtual void writeChanges() = 0; virtual void updateConstants(const std::string& name, uint32 offset, void* data) = 0; virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PShaderBuffer shaderBuffer) = 0; - virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PVertexBuffer indexBuffer) = 0; - virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PIndexBuffer indexBuffer) = 0; + virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PVertexBuffer vertexBuffer) = 0; + virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PIndexBuffer indexBuffer) = 0;\ + virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PUniformBuffer uniformBuffer) = 0; virtual void updateSampler(const std::string& name, uint32 index, Gfx::PSampler samplerState) = 0; virtual void updateTexture(const std::string& name, uint32 index, Gfx::PTextureView texture) = 0; virtual void updateAccelerationStructure(const std::string& name, uint32 index, Gfx::PTopLevelAS as) = 0; diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index b673a91..6414fa8 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -67,6 +67,7 @@ class Graphics { virtual void executeCommands(Array commands) = 0; virtual OTexture2D createTexture2D(const TextureCreateInfo& createInfo) = 0; + virtual OTexture2DArray createTexture2DArray(const TextureCreateInfo& createInfo) = 0; virtual OTexture3D createTexture3D(const TextureCreateInfo& createInfo) = 0; virtual OTextureCube createTextureCube(const TextureCreateInfo& createInfo) = 0; virtual OUniformBuffer createUniformBuffer(const UniformBufferCreateInfo& bulkData) = 0; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 8aa66c2..845e4d8 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -13,6 +13,7 @@ #include "Math/Matrix.h" #include "Math/Vector.h" #include "MinimalEngine.h" +#include "ShadowPass.h" using namespace Seele; @@ -41,7 +42,29 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics) }); lightCullingLayout->create(); + shadowMappingLayout = graphics->createDescriptorLayout("pShadowMapping"); + shadowMappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = SHADOWMAPS_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = NUM_CASCADES, + }); + shadowMappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = LIGHTSPACE_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = NUM_CASCADES, + }); + shadowMappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = SHADOWSAMPLER_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, + }); + shadowMappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = CASCADE_SPLIT_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER + }); + shadowMappingLayout->create(); + basePassLayout->addDescriptorLayout(lightCullingLayout); + basePassLayout->addDescriptorLayout(shadowMappingLayout); basePassLayout->addPushConstants(Gfx::SePushConstantRange{ .stageFlags = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, .offset = 0, @@ -79,6 +102,19 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics) .fogColor = Vector(0, 0, 0), .blendFactor = 0, }; + shadowSampler = graphics->createSampler(SamplerCreateInfo{ + .magFilter = Gfx::SE_FILTER_LINEAR, + .minFilter = Gfx::SE_FILTER_LINEAR, + .mipmapMode = Gfx::SE_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeW = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .mipLodBias = 0.0f, + .maxAnisotropy = 1.0f, + .minLod = 0.0f, + .maxLod = 1.0f, + .borderColor = Gfx::SE_BORDER_COLOR_FLOAT_OPAQUE_WHITE, + }); } BasePass::~BasePass() {} @@ -139,13 +175,23 @@ void BasePass::render() { transparentCulling->updateTexture(LIGHTGRID_NAME, 0, tLightGrid->getDefaultView()); opaqueCulling->writeChanges(); transparentCulling->writeChanges(); + + shadowMappingLayout->reset(); + shadowMapping = shadowMappingLayout->allocateDescriptorSet(); + for (uint32 i = 0; i < NUM_CASCADES; ++i) { + shadowMapping->updateTexture(SHADOWMAPS_NAME, i, shadowMaps[i]->getDefaultView()); + shadowMapping->updateBuffer(LIGHTSPACE_NAME, i, lightSpaceMatrices[i]); + } + shadowMapping->updateSampler(SHADOWSAMPLER_NAME, 0, shadowSampler); + shadowMapping->updateBuffer(CASCADE_SPLIT_NAME, 0, cascadeSplits); + shadowMapping->writeChanges(); query->beginQuery(); timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "BaseBegin"); graphics->beginRenderPass(renderPass); Array transparentData; + // Opaque { - graphics->beginDebugRegion("Opaque"); Array commands; Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("BasePass"); permutation.setDepthCulling(true); // always use the culling info @@ -176,7 +222,7 @@ void BasePass::render() { const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); assert(collection != nullptr); - //bool twoSided = materialData.material->isTwoSided(); + // bool twoSided = materialData.material->isTwoSided(); if (graphics->supportMeshShading()) { Gfx::MeshPipelineCreateInfo pipelineInfo = { @@ -221,7 +267,7 @@ void BasePass::render() { command->bindPipeline(graphics->createGraphicsPipeline(std::move(pipelineInfo))); } command->bindDescriptor({viewParamsSet, vertexData->getVertexDataSet(), vertexData->getInstanceDataSet(), - scene->getLightEnvironment()->getDescriptorSet(), Material::getDescriptorSet(), opaqueCulling}); + scene->getLightEnvironment()->getDescriptorSet(), Material::getDescriptorSet(), shadowMapping, opaqueCulling}); for (const auto& drawCall : materialData.instances) { command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, @@ -241,7 +287,6 @@ void BasePass::render() { } } graphics->executeCommands(std::move(commands)); - graphics->endDebugRegion(); } // commands.add(waterRenderer->render(viewParamsSet)); @@ -249,18 +294,15 @@ void BasePass::render() { // Skybox { - graphics->beginDebugRegion("Skybox"); Gfx::ORenderCommand skyboxCommand = graphics->createRenderCommand("SkyboxRender"); skyboxCommand->setViewport(viewport); skyboxCommand->bindPipeline(skyboxPipeline); skyboxCommand->bindDescriptor({viewParamsSet, skyboxDataSet, textureSet}); skyboxCommand->draw(36, 1, 0, 0); graphics->executeCommands(std::move(skyboxCommand)); - graphics->endDebugRegion(); } // Transparent rendering { - graphics->beginDebugRegion("Transparent"); Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("BasePass"); permutation.setPositionOnly(false); permutation.setDepthCulling(false); // ignore visibility infos for transparency @@ -280,7 +322,7 @@ void BasePass::render() { const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); assert(collection != nullptr); - //bool twoSided = t.matInst->getBaseMaterial()->isTwoSided(); + // bool twoSided = t.matInst->getBaseMaterial()->isTwoSided(); if (graphics->supportMeshShading()) { Gfx::MeshPipelineCreateInfo pipelineInfo = { @@ -343,7 +385,7 @@ void BasePass::render() { transparentCommand->bindPipeline(pipeline); } transparentCommand->bindDescriptor({viewParamsSet, t.vertexData->getVertexDataSet(), t.vertexData->getInstanceDataSet(), - scene->getLightEnvironment()->getDescriptorSet(), Material::getDescriptorSet(), + scene->getLightEnvironment()->getDescriptorSet(), Material::getDescriptorSet(), shadowMapping, transparentCulling}); transparentCommand->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, @@ -360,11 +402,9 @@ void BasePass::render() { } } graphics->executeCommands(std::move(transparentCommand)); - graphics->endDebugRegion(); } // Debug vertices if (gDebugVertices.size() > 0) { - graphics->beginDebugRegion("Debug"); Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("BasePass"); permutation.setDepthCulling(true); // always use the culling info permutation.setPositionOnly(false); @@ -375,7 +415,6 @@ void BasePass::render() { debugCommand->bindVertexBuffer({debugVertices}); debugCommand->draw((uint32)gDebugVertices.size(), 1, 0, 0); graphics->executeCommands(std::move(debugCommand)); - graphics->endDebugRegion(); } graphics->endRenderPass(); @@ -422,18 +461,18 @@ void BasePass::publishOutputs() { Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE); - msDepthAttachment = - Gfx::RenderTargetAttachment(msBasePassDepth->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_DONT_CARE); + msDepthAttachment = Gfx::RenderTargetAttachment(msBasePassDepth->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, + Gfx::SE_ATTACHMENT_STORE_OP_DONT_CARE); msDepthAttachment.clear.depthStencil.depth = 0.0f; - colorAttachment = - Gfx::RenderTargetAttachment(basePassColor->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE); + colorAttachment = Gfx::RenderTargetAttachment(basePassColor->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, + Gfx::SE_ATTACHMENT_STORE_OP_STORE); - msColorAttachment = - Gfx::RenderTargetAttachment(msBasePassColor->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_DONT_CARE); + msColorAttachment = Gfx::RenderTargetAttachment(msBasePassColor->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, + Gfx::SE_ATTACHMENT_STORE_OP_DONT_CARE); msColorAttachment.clear.color.float32[0] = 0; msColorAttachment.clear.color.float32[1] = 1; msColorAttachment.clear.color.float32[2] = 0; @@ -452,6 +491,11 @@ void BasePass::createRenderPass() { // terrainRenderer = new TerrainRenderer(graphics, scene, viewParamsLayout, viewParamsSet); cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); timestamps = resources->requestTimestampQuery("TIMESTAMPS"); + for (uint32 i = 0; i < NUM_CASCADES; ++i) { + shadowMaps[i] = resources->requestTexture(fmt::format("SHADOWMAP_TEXTURE{0}", i)); + lightSpaceMatrices[i] = resources->requestBuffer(fmt::format("SHADOWMAP_LIGHTSPACE{0}", i)); + } + cascadeSplits = resources->requestUniform("SHADOWMAP_CASCADESPLITS"); Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ .colorAttachments = {msColorAttachment}, diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index 132d350..beeea30 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -1,7 +1,9 @@ #pragma once +#include "Graphics/Buffer.h" +#include "Graphics/Descriptor.h" +#include "Graphics/RenderPass/ShadowPass.h" #include "MinimalEngine.h" #include "RenderPass.h" -#include "WaterRenderer.h" namespace Seele { DECLARE_REF(CameraActor) @@ -30,9 +32,14 @@ class BasePass : public RenderPass { Gfx::PTexture2D tLightGrid; constexpr static const char* LIGHTINDEX_NAME = "lightIndexList"; constexpr static const char* LIGHTGRID_NAME = "lightGrid"; + constexpr static const char* SHADOWMAPS_NAME = "shadowMaps"; + constexpr static const char* LIGHTSPACE_NAME = "lightSpaceMatrices"; + constexpr static const char* SHADOWSAMPLER_NAME = "shadowSampler"; + constexpr static const char* CASCADE_SPLIT_NAME = "cascadeSplit"; Gfx::PDescriptorSet opaqueCulling; Gfx::PDescriptorSet transparentCulling; + Gfx::PDescriptorSet shadowMapping; // use a different texture here so we can do multisampling Gfx::OTexture2D msBasePassDepth; @@ -49,6 +56,7 @@ class BasePass : public RenderPass { PCameraActor source; Gfx::OPipelineLayout basePassLayout; Gfx::ODescriptorLayout lightCullingLayout; + Gfx::ODescriptorLayout shadowMappingLayout; Gfx::OPipelineStatisticsQuery query; Gfx::PTimestampQuery timestamps; @@ -58,6 +66,12 @@ class BasePass : public RenderPass { //OWaterRenderer waterRenderer; //OTerrainRenderer terrainRenderer; + // Shadow mapping + Gfx::PTexture2D shadowMaps[NUM_CASCADES]; + Gfx::PShaderBuffer lightSpaceMatrices[NUM_CASCADES]; + Gfx::OSampler shadowSampler; + Gfx::PUniformBuffer cascadeSplits; + // Debug rendering Gfx::OVertexInput debugVertexInput; Gfx::OVertexBuffer debugVertices; diff --git a/src/Engine/Graphics/RenderPass/RenderGraphResources.cpp b/src/Engine/Graphics/RenderPass/RenderGraphResources.cpp index b668e50..7245c78 100644 --- a/src/Engine/Graphics/RenderPass/RenderGraphResources.cpp +++ b/src/Engine/Graphics/RenderPass/RenderGraphResources.cpp @@ -1,6 +1,5 @@ #include "RenderGraphResources.h" #include "Graphics/Query.h" -#include #include using namespace Seele; diff --git a/src/Engine/Graphics/RenderPass/ShadowPass.cpp b/src/Engine/Graphics/RenderPass/ShadowPass.cpp index c1d2d3c..8869f19 100644 --- a/src/Engine/Graphics/RenderPass/ShadowPass.cpp +++ b/src/Engine/Graphics/RenderPass/ShadowPass.cpp @@ -44,7 +44,6 @@ ShadowPass::ShadowPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graph ShadowPass::~ShadowPass() {} void ShadowPass::beginFrame(const Component::Camera& camera, const Component::Transform& transform) { - uint32 cascadeDim = SHADOW_MAP_SIZE; float cascadeSplits[NUM_CASCADES]; float nearClip = camera.nearPlane; @@ -58,19 +57,6 @@ void ShadowPass::beginFrame(const Component::Camera& camera, const Component::Tr float ratio = maxZ / minZ; constexpr float cascadeSplitLambda = 0.95f; for (uint32 i = 0; i < NUM_CASCADES; ++i) { - cascades[i].shadowMaps = graphics->createTexture2D(TextureCreateInfo{ - .format = Gfx::SE_FORMAT_D32_SFLOAT, - .width = cascadeDim, - .height = cascadeDim, - .elements = (uint32)scene->getLightEnvironment()->getNumDirectionalLights(), - .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, - .name = "ShadowMapCascade", - }); - cascades[i].views.clear(); - for (uint32 j = 0; j < cascades[i].shadowMaps->getNumLayers(); ++j) { - cascades[i].views.add(cascades[i].shadowMaps->createTextureView(0, 1, j, 1)); - } - cascadeDim /= 2; float p = (i + 1) / static_cast(NUM_CASCADES); float log = minZ * std::pow(ratio, p); float uniform = minZ + range * p; @@ -131,6 +117,8 @@ void ShadowPass::beginFrame(const Component::Camera& camera, const Component::Tr viewParams.screenDimensions = Vector2(maxExtents.x - minExtents.x, maxExtents.y - minExtents.y); viewParams.invScreenDimensions = 1.0f / viewParams.screenDimensions; cascades[i].viewParams.add(createViewParamsSet()); + + lastSplitDist = cascadeSplits[i]; } } } @@ -146,9 +134,9 @@ void ShadowPass::render() { Array commands; renderPass = graphics->createRenderPass( Gfx::RenderTargetLayout{ - .depthAttachment = Gfx::RenderTargetAttachment( - cascades[c].views[shadowIndex], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, - Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE), + .depthAttachment = Gfx::RenderTargetAttachment(cascades[c].views[shadowIndex], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE), }, { @@ -219,7 +207,8 @@ void ShadowPass::render() { Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); command->bindPipeline(pipeline); } - command->bindDescriptor({cascades[c].viewParams[shadowIndex], vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()}); + command->bindDescriptor( + {cascades[c].viewParams[shadowIndex], vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()}); VertexData::DrawCallOffsets offsets = { .instanceOffset = 0, }; @@ -258,6 +247,12 @@ void ShadowPass::render() { void ShadowPass::endFrame() {} void ShadowPass::publishOutputs() { + cascadeSplitsBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{.sourceData = + { + .size = sizeof(float) * NUM_CASCADES, + .data = nullptr, + }, + .name = "CascadeSplits"}); shadowViewport = graphics->createViewport(nullptr, ViewportCreateInfo{.dimensions = { .size = {SHADOW_MAP_SIZE, SHADOW_MAP_SIZE}, @@ -268,6 +263,39 @@ void ShadowPass::publishOutputs() { .right = 100, .top = 100, .bottom = -100}); + uint32 cascadeDim = SHADOW_MAP_SIZE; + for (uint32 s = 0; s < NUM_CASCADES; ++s) { + cascades[s].shadowMaps = graphics->createTexture2DArray(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_D32_SFLOAT, + .width = cascadeDim, + .height = cascadeDim, + .elements = 1, // TODO: + .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, + .name = "ShadowMapCascade", + }); + cascades[s].lightSpaceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = { + .size = sizeof(Matrix4), + .data = nullptr, + }, + .name = "LightSpaceBuffer" + }); + cascades[s].views.clear(); + for (uint32 j = 0; j < cascades[s].shadowMaps->getNumLayers(); ++j) { + cascades[s].views.add(cascades[s].shadowMaps->createTextureView(0, 1, j, 1)); + } + cascadeDim /= 2; + resources->registerTextureOutput(fmt::format("SHADOWMAP_TEXTURE{0}", s), Gfx::PTexture2DArray(cascades[s].shadowMaps)); + resources->registerBufferOutput(fmt::format("SHADOWMAP_LIGHTSPACE{0}", s), cascades[s].lightSpaceBuffer); + } + cascadeSplitsBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{ + .sourceData = { + .size = sizeof(float) * NUM_CASCADES, + .data = nullptr, + }, + .name = "CASCADE_SPLITS" + }); + resources->registerUniformOutput("SHADOWMAP_CASCADESPLITS", cascadeSplitsBuffer); viewport = shadowViewport; } diff --git a/src/Engine/Graphics/RenderPass/ShadowPass.h b/src/Engine/Graphics/RenderPass/ShadowPass.h index e40e437..6d7a3bf 100644 --- a/src/Engine/Graphics/RenderPass/ShadowPass.h +++ b/src/Engine/Graphics/RenderPass/ShadowPass.h @@ -6,6 +6,7 @@ namespace Seele { static constexpr uint64 SHADOW_MAP_SIZE = 8192; +static constexpr uint64 NUM_CASCADES = 4; class ShadowPass : public RenderPass { public: @@ -20,13 +21,15 @@ class ShadowPass : public RenderPass { virtual void createRenderPass() override; private: AABB cameraFrustumBox; - static constexpr uint64 NUM_CASCADES = 4; struct Cascade { - Gfx::OTexture2D shadowMaps; + Gfx::OTexture2DArray shadowMaps; Array views; + Array lightSpaceMatrices; + Gfx::OShaderBuffer lightSpaceBuffer; Array viewParams; }; StaticArray cascades; + Gfx::OUniformBuffer cascadeSplitsBuffer; Gfx::OPipelineLayout shadowLayout; Gfx::PShaderBuffer cullingBuffer; Gfx::OViewport shadowViewport; diff --git a/src/Engine/Graphics/Texture.cpp b/src/Engine/Graphics/Texture.cpp index 824a9b0..2eec866 100644 --- a/src/Engine/Graphics/Texture.cpp +++ b/src/Engine/Graphics/Texture.cpp @@ -16,6 +16,10 @@ Texture2D::Texture2D(QueueFamilyMapping mapping) : Texture(mapping) {} Texture2D::~Texture2D() {} +Texture2DArray::Texture2DArray(QueueFamilyMapping mapping) : Texture(mapping) {} + +Texture2DArray::~Texture2DArray() {} + Texture3D::Texture3D(QueueFamilyMapping mapping) : Texture(mapping) {} Texture3D::~Texture3D() {} diff --git a/src/Engine/Graphics/Texture.h b/src/Engine/Graphics/Texture.h index 0d0c9f3..a149b35 100644 --- a/src/Engine/Graphics/Texture.h +++ b/src/Engine/Graphics/Texture.h @@ -75,6 +75,32 @@ class Texture2D : public Texture { }; DEFINE_REF(Texture2D) +class Texture2DArray : public Texture { + public: + Texture2DArray(QueueFamilyMapping mapping); + virtual ~Texture2DArray(); + + virtual SeFormat getFormat() const = 0; + virtual uint32 getWidth() const = 0; + virtual uint32 getHeight() const = 0; + virtual uint32 getDepth() const = 0; + virtual uint32 getNumLayers() const = 0; + virtual SeSampleCountFlags getNumSamples() const = 0; + virtual uint32 getMipLevels() const = 0; + virtual void changeLayout(SeImageLayout newLayout, SeAccessFlags srcAccess, SePipelineStageFlags srcStage, SeAccessFlags dstAccess, + SePipelineStageFlags dstStage) = 0; + virtual void generateMipmaps() = 0; + virtual PTextureView getDefaultView() const = 0; + + virtual OTextureView createTextureView(uint32 baseMipLevel, uint32 levelCount, uint32 baseArrayLayer, uint32 layerCount) = 0; + protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; + virtual void executePipelineBarrier(SeAccessFlags srcAccess, SePipelineStageFlags srcStage, SeAccessFlags dstAccess, + SePipelineStageFlags dstStage) = 0; +}; +DEFINE_REF(Texture2DArray) + class Texture3D : public Texture { public: Texture3D(QueueFamilyMapping mapping); diff --git a/src/Engine/Graphics/Vulkan/Descriptor.cpp b/src/Engine/Graphics/Vulkan/Descriptor.cpp index b819057..69d37d9 100644 --- a/src/Engine/Graphics/Vulkan/Descriptor.cpp +++ b/src/Engine/Graphics/Vulkan/Descriptor.cpp @@ -9,10 +9,11 @@ #include "Graphics/Initializer.h" #include "RayTracing.h" #include "Texture.h" +#include "Enums.h" +#include #include "vulkan/vulkan_core.h" #include #include -#include using namespace Seele; using namespace Seele::Vulkan; @@ -32,10 +33,10 @@ void DescriptorLayout::create() { return; } Array bindingFlags; - if (std::ranges::contains(descriptorBindings, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &Gfx::DescriptorBinding::descriptorType)) { + if (std::ranges::contains(descriptorBindings, Gfx::SE_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, &Gfx::DescriptorBinding::descriptorType)) { bindings.add({ .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // although we can pretend that we support inline uniforms, slang does not generate them .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_ALL, // todo .pImmutableSamplers = nullptr, @@ -43,11 +44,12 @@ void DescriptorLayout::create() { bindingFlags.add(0); } for (const auto& gfxBinding : descriptorBindings) { - if (gfxBinding.descriptorType == Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + if (gfxBinding.descriptorType == Gfx::SE_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) { mappings[gfxBinding.name] = { .binding = 0, .constantOffset = constantsSize, .constantSize = gfxBinding.uniformLength, + .type = cast(gfxBinding.descriptorType), }; constantsSize += gfxBinding.uniformLength; constantsStages |= gfxBinding.shaderStages; @@ -92,15 +94,15 @@ DescriptorPool::DescriptorPool(PGraphics graphics, PDescriptorLayout layout) cachedHandles[i] = nullptr; } - Map perTypeSizes; - for (uint32 i = 0; i < layout->getBindings().size(); ++i) { - auto& binding = layout->getBindings()[i]; + Map perTypeSizes; + for (uint32 i = 0; i < layout->bindings.size(); ++i) { + auto& binding = layout->bindings[i]; perTypeSizes[binding.descriptorType] += 512; } Array poolSizes; for (const auto& [type, num] : perTypeSizes) { poolSizes.add(VkDescriptorPoolSize{ - .type = cast(type), + .type = type, .descriptorCount = num, }); } @@ -199,9 +201,9 @@ void DescriptorPool::reset() { DescriptorSet::DescriptorSet(PGraphics graphics, PDescriptorPool owner) : Gfx::DescriptorSet(owner->getLayout()), CommandBoundResource(graphics, owner->getLayout()->getName()), setHandle(VK_NULL_HANDLE), graphics(graphics), owner(owner) { - boundResources.resize(owner->getLayout()->getBindings().size()); + boundResources.resize(owner->getLayout()->bindings.size()); for (uint32 i = 0; i < boundResources.size(); ++i) { - boundResources[i].resize(owner->getLayout()->getBindings()[i].descriptorCount); + boundResources[i].resize(owner->getLayout()->bindings[i].descriptorCount); for (size_t x = 0; x < boundResources[i].size(); ++x) { boundResources[i][x] = nullptr; } @@ -243,8 +245,8 @@ void DescriptorSet::updateBuffer(const std::string& mappingName, uint32 index, G boundResources[binding][index] = vulkanBuffer->getAlloc(); } -void DescriptorSet::updateBuffer(const std::string& mappingName, uint32 index, Gfx::PVertexBuffer indexBuffer) { - PVertexBuffer vulkanBuffer = indexBuffer.cast(); +void DescriptorSet::updateBuffer(const std::string& mappingName, uint32 index, Gfx::PVertexBuffer vertexBuffer) { + PVertexBuffer vulkanBuffer = vertexBuffer.cast(); const auto& map = owner->getLayout()->mappings[mappingName]; uint32 binding = map.binding; // if the buffer is empty @@ -297,6 +299,33 @@ void DescriptorSet::updateBuffer(const std::string& mappingName, uint32 index, G boundResources[binding][index] = vulkanBuffer->getAlloc(); } +void DescriptorSet::updateBuffer(const std::string& mappingName, uint32 index, Gfx::PUniformBuffer uniformBuffer) { + PUniformBuffer vulkanBuffer = uniformBuffer.cast(); + const auto& map = owner->getLayout()->mappings[mappingName]; + uint32 binding = map.binding; + // if the buffer is empty + if (vulkanBuffer->getAlloc() == nullptr) + return; + + bufferInfos.add(VkDescriptorBufferInfo{ + .buffer = vulkanBuffer->getHandle(), + .offset = 0, + .range = vulkanBuffer->getSize(), + }); + writeDescriptors.add(VkWriteDescriptorSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = setHandle, + .dstBinding = binding, + .dstArrayElement = index, + .descriptorCount = 1, + .descriptorType = map.type, + .pBufferInfo = &bufferInfos.back(), + }); + + boundResources[binding][index] = vulkanBuffer->getAlloc(); +} + void DescriptorSet::updateSampler(const std::string& mappingName, uint32 index, Gfx::PSampler samplerState) { PSampler vulkanSampler = samplerState.cast(); const auto& map = owner->getLayout()->mappings[mappingName]; diff --git a/src/Engine/Graphics/Vulkan/Descriptor.h b/src/Engine/Graphics/Vulkan/Descriptor.h index 4a5ca04..b9ce938 100644 --- a/src/Engine/Graphics/Vulkan/Descriptor.h +++ b/src/Engine/Graphics/Vulkan/Descriptor.h @@ -1,6 +1,5 @@ #pragma once #include "Containers/List.h" -#include "Enums.h" #include "Graphics/Descriptor.h" #include "Graphics/Vulkan/Buffer.h" #include "Resources.h" @@ -61,8 +60,9 @@ class DescriptorSet : public Gfx::DescriptorSet, public CommandBoundResource { virtual void writeChanges() override; virtual void updateConstants(const std::string& name, uint32 offset, void* data) override; virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PShaderBuffer shaderBuffer) override; - virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PVertexBuffer indexBuffer) override; + virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PVertexBuffer vertexBuffer) override; virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PIndexBuffer indexBuffer) override; + virtual void updateBuffer(const std::string& name, uint32 index, Gfx::PUniformBuffer uniformBuffer) override; virtual void updateSampler(const std::string& name, uint32 index, Gfx::PSampler samplerState) override; virtual void updateTexture(const std::string& name, uint32 index, Gfx::PTextureView texture) override; virtual void updateAccelerationStructure(const std::string& name, uint32 index, Gfx::PTopLevelAS as) override; diff --git a/src/Engine/Graphics/Vulkan/Graphics.cpp b/src/Engine/Graphics/Vulkan/Graphics.cpp index 2a32b7c..884fcfd 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.cpp +++ b/src/Engine/Graphics/Vulkan/Graphics.cpp @@ -222,6 +222,8 @@ void Graphics::executeCommands(Array commands) { Gfx::OTexture2D Graphics::createTexture2D(const TextureCreateInfo& createInfo) { return new Texture2D(this, createInfo); } +Gfx::OTexture2DArray Graphics::createTexture2DArray(const TextureCreateInfo& createInfo) { return new Texture2DArray(this, createInfo); } + Gfx::OTexture3D Graphics::createTexture3D(const TextureCreateInfo& createInfo) { return new Texture3D(this, createInfo); } Gfx::OTextureCube Graphics::createTextureCube(const TextureCreateInfo& createInfo) { return new TextureCube(this, createInfo); } diff --git a/src/Engine/Graphics/Vulkan/Graphics.h b/src/Engine/Graphics/Vulkan/Graphics.h index 7f410fd..13f53ed 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.h +++ b/src/Engine/Graphics/Vulkan/Graphics.h @@ -113,6 +113,7 @@ class Graphics : public Gfx::Graphics { virtual void executeCommands(Array commands) override; virtual Gfx::OTexture2D createTexture2D(const TextureCreateInfo& createInfo) override; + virtual Gfx::OTexture2DArray createTexture2DArray(const TextureCreateInfo& createInfo) override; virtual Gfx::OTexture3D createTexture3D(const TextureCreateInfo& createInfo) override; virtual Gfx::OTextureCube createTextureCube(const TextureCreateInfo& createInfo) override; virtual Gfx::OUniformBuffer createUniformBuffer(const UniformBufferCreateInfo& bulkData) override; diff --git a/src/Engine/Graphics/Vulkan/Texture.cpp b/src/Engine/Graphics/Vulkan/Texture.cpp index a9e10ad..e997908 100644 --- a/src/Engine/Graphics/Vulkan/Texture.cpp +++ b/src/Engine/Graphics/Vulkan/Texture.cpp @@ -444,18 +444,21 @@ void TextureBase::pipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags handle->pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); } void TextureBase::transferOwnership(Gfx::QueueType newOwner) { handle->transferOwnership(newOwner); } + void TextureBase::changeLayout(Gfx::SeImageLayout newLayout, VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) { handle->changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage); } + void TextureBase::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array& buffer) { handle->download(mipLevel, arrayLayer, face, buffer); } + void TextureBase::generateMipmaps() { handle->generateMipmaps(); } Texture2D::Texture2D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage) : Gfx::Texture2D(graphics->getFamilyMapping()), - TextureBase(graphics, createInfo.elements > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, createInfo, existingImage) {} + TextureBase(graphics, VK_IMAGE_VIEW_TYPE_2D, createInfo, existingImage) {} Texture2D::~Texture2D() {} @@ -483,6 +486,36 @@ void Texture2D::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageF TextureBase::pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); } +Texture2DArray::Texture2DArray(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage) + : Gfx::Texture2DArray(graphics->getFamilyMapping()), + TextureBase(graphics, VK_IMAGE_VIEW_TYPE_2D_ARRAY, createInfo, existingImage) {} + +Texture2DArray::~Texture2DArray() {} + +void Texture2DArray::changeLayout(Gfx::SeImageLayout newLayout, Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage, + Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) { + TextureBase::changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage); +} + +void Texture2DArray::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array& buffer) { + TextureBase::download(mipLevel, arrayLayer, face, buffer); +} + +void Texture2DArray::generateMipmaps() { TextureBase::generateMipmaps(); } + +Gfx::PTextureView Texture2DArray::getDefaultView() const { return PTextureView(handle->imageView); } + +Gfx::OTextureView Texture2DArray::createTextureView(uint32 baseMipLevel, uint32 levelCount, uint32 baseArrayLayer, uint32 layerCount) { + return handle->createTextureView(baseMipLevel, levelCount, baseArrayLayer, layerCount); +} + +void Texture2DArray::executeOwnershipBarrier(Gfx::QueueType newOwner) { TextureBase::transferOwnership(newOwner); } + +void Texture2DArray::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess, + VkPipelineStageFlags dstStage) { + TextureBase::pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); +} + Texture3D::Texture3D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage) : Gfx::Texture3D(graphics->getFamilyMapping()), TextureBase(graphics, VK_IMAGE_VIEW_TYPE_3D, createInfo, existingImage) {} diff --git a/src/Engine/Graphics/Vulkan/Texture.h b/src/Engine/Graphics/Vulkan/Texture.h index 0df7e39..92a911d 100644 --- a/src/Engine/Graphics/Vulkan/Texture.h +++ b/src/Engine/Graphics/Vulkan/Texture.h @@ -135,6 +135,32 @@ class Texture2D : public Gfx::Texture2D, public TextureBase { }; DEFINE_REF(Texture2D) +class Texture2DArray : public Gfx::Texture2DArray, public TextureBase { + public: + Texture2DArray(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage = VK_NULL_HANDLE); + virtual ~Texture2DArray(); + virtual uint32 getWidth() const override { return handle->width; } + virtual uint32 getHeight() const override { return handle->height; } + virtual uint32 getDepth() const override { return handle->depth; } + virtual uint32 getNumLayers() const override { return handle->layerCount; } + virtual Gfx::SeFormat getFormat() const override { return handle->format; } + virtual Gfx::SeSampleCountFlags getNumSamples() const override { return handle->samples; } + virtual uint32 getMipLevels() const override { return handle->mipLevels; } + virtual void changeLayout(Gfx::SeImageLayout newLayout, Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage, + Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) override; + virtual void download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array& buffer) override; + virtual void generateMipmaps() override; + virtual Gfx::PTextureView getDefaultView() const override; + virtual Gfx::OTextureView createTextureView(uint32 baseMipLevel, uint32 levelCount, uint32 baseArrayLayer, uint32 layerCount) override; + + protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner) override; + virtual void executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess, + VkPipelineStageFlags dstStage) override; +}; +DEFINE_REF(Texture2DArray) + class Texture3D : public Gfx::Texture3D, public TextureBase { public: Texture3D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage = VK_NULL_HANDLE); diff --git a/src/Engine/Scene/LightEnvironment.cpp b/src/Engine/Scene/LightEnvironment.cpp index b7bc208..76d3ca0 100644 --- a/src/Engine/Scene/LightEnvironment.cpp +++ b/src/Engine/Scene/LightEnvironment.cpp @@ -14,14 +14,6 @@ LightEnvironment::LightEnvironment(Gfx::PGraphics graphics) .name = "directionalLights", .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, }); - layout->addDescriptorBinding(Gfx::DescriptorBinding{ - .name = "shadowMap", - .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - }); - layout->addDescriptorBinding(Gfx::DescriptorBinding{ - .name = "shadowSampler", - .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, - }); layout->addDescriptorBinding(Gfx::DescriptorBinding{ .name = "numDirectionalLights", .uniformLength = sizeof(uint32),