ADD: changeable resolution
This commit is contained in:
@@ -10,6 +10,10 @@ endif()
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
|
||||
# Third-party deps are vendored; keep builds offline-friendly by default.
|
||||
# BVH2's CMake enables tests by default, which would FetchContent googletest.
|
||||
set(BVH2_ENABLE_TESTS OFF CACHE BOOL "Disable BVH2 tests (offline builds)" FORCE)
|
||||
|
||||
add_subdirectory(third_party)
|
||||
|
||||
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
|
||||
|
||||
@@ -16,18 +16,49 @@ void SwapchainManager::init_swapchain()
|
||||
{
|
||||
create_swapchain(_windowExtent.width, _windowExtent.height);
|
||||
|
||||
// Create images used across the frame (draw, depth, GBuffer)
|
||||
// Split to helper so we can reuse on resize
|
||||
// (Definition added below)
|
||||
//
|
||||
// On creation we also push a cleanup lambda to _deletionQueue for final shutdown.
|
||||
// On resize we will flush that queue first to destroy previous resources.
|
||||
// Create images used across the frame (draw, depth, GBuffer).
|
||||
// These are sized to _renderExtent (independent of the swapchain extent)
|
||||
// so the engine can render at a different internal resolution and then
|
||||
// upscale/letterbox into the swapchain.
|
||||
if (_renderExtent.width == 0 || _renderExtent.height == 0)
|
||||
{
|
||||
_renderExtent = _windowExtent;
|
||||
}
|
||||
resize_render_targets(_renderExtent);
|
||||
}
|
||||
|
||||
// depth/draw/gbuffer sized to fixed logical render extent (letterboxed)
|
||||
auto create_frame_images = [this]() {
|
||||
VkExtent3D drawImageExtent = { kRenderWidth, kRenderHeight, 1 };
|
||||
void SwapchainManager::cleanup()
|
||||
{
|
||||
_deletionQueue.flush();
|
||||
destroy_swapchain();
|
||||
fmt::print("SwapchainManager::cleanup()\n");
|
||||
}
|
||||
|
||||
void SwapchainManager::resize_render_targets(VkExtent2D renderExtent)
|
||||
{
|
||||
if (!_deviceManager || !_resourceManager) return;
|
||||
if (renderExtent.width == 0 || renderExtent.height == 0) return;
|
||||
|
||||
// Avoid doing work when nothing changes (common when called every frame).
|
||||
if (_renderExtent.width == renderExtent.width &&
|
||||
_renderExtent.height == renderExtent.height &&
|
||||
_drawImage.image != VK_NULL_HANDLE &&
|
||||
_depthImage.image != VK_NULL_HANDLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure no in-flight work references these images before we destroy them.
|
||||
vkDeviceWaitIdle(_deviceManager->device());
|
||||
|
||||
// Destroy previous targets (if any), then recreate at the new extent.
|
||||
_deletionQueue.flush();
|
||||
_renderExtent = renderExtent;
|
||||
|
||||
VkExtent3D drawImageExtent = { _renderExtent.width, _renderExtent.height, 1 };
|
||||
|
||||
// Draw HDR target
|
||||
_drawImage = {};
|
||||
_drawImage.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
_drawImage.imageExtent = drawImageExtent;
|
||||
|
||||
@@ -52,6 +83,7 @@ void SwapchainManager::init_swapchain()
|
||||
VK_CHECK(vkCreateImageView(_deviceManager->device(), &rview_info, nullptr, &_drawImage.imageView));
|
||||
|
||||
// Depth
|
||||
_depthImage = {};
|
||||
_depthImage.imageFormat = VK_FORMAT_D32_SFLOAT;
|
||||
_depthImage.imageExtent = drawImageExtent;
|
||||
VkImageUsageFlags depthImageUsages{};
|
||||
@@ -77,29 +109,27 @@ void SwapchainManager::init_swapchain()
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
|
||||
_deletionQueue.push_function([=]() {
|
||||
vkDestroyImageView(_deviceManager->device(), _drawImage.imageView, nullptr);
|
||||
vmaDestroyImage(_deviceManager->allocator(), _drawImage.image, _drawImage.allocation);
|
||||
_deletionQueue.push_function([this]() {
|
||||
if (_drawImage.imageView) vkDestroyImageView(_deviceManager->device(), _drawImage.imageView, nullptr);
|
||||
if (_drawImage.image) vmaDestroyImage(_deviceManager->allocator(), _drawImage.image, _drawImage.allocation);
|
||||
|
||||
vkDestroyImageView(_deviceManager->device(), _depthImage.imageView, nullptr);
|
||||
vmaDestroyImage(_deviceManager->allocator(), _depthImage.image, _depthImage.allocation);
|
||||
if (_depthImage.imageView) vkDestroyImageView(_deviceManager->device(), _depthImage.imageView, nullptr);
|
||||
if (_depthImage.image) vmaDestroyImage(_deviceManager->allocator(), _depthImage.image, _depthImage.allocation);
|
||||
|
||||
_resourceManager->destroy_image(_gBufferPosition);
|
||||
_resourceManager->destroy_image(_gBufferNormal);
|
||||
_resourceManager->destroy_image(_gBufferAlbedo);
|
||||
_resourceManager->destroy_image(_gBufferExtra);
|
||||
_resourceManager->destroy_image(_idBuffer);
|
||||
if (_gBufferPosition.image) _resourceManager->destroy_image(_gBufferPosition);
|
||||
if (_gBufferNormal.image) _resourceManager->destroy_image(_gBufferNormal);
|
||||
if (_gBufferAlbedo.image) _resourceManager->destroy_image(_gBufferAlbedo);
|
||||
if (_gBufferExtra.image) _resourceManager->destroy_image(_gBufferExtra);
|
||||
if (_idBuffer.image) _resourceManager->destroy_image(_idBuffer);
|
||||
|
||||
_drawImage = {};
|
||||
_depthImage = {};
|
||||
_gBufferPosition = {};
|
||||
_gBufferNormal = {};
|
||||
_gBufferAlbedo = {};
|
||||
_gBufferExtra = {};
|
||||
_idBuffer = {};
|
||||
});
|
||||
};
|
||||
|
||||
create_frame_images();
|
||||
}
|
||||
|
||||
void SwapchainManager::cleanup()
|
||||
{
|
||||
_deletionQueue.flush();
|
||||
destroy_swapchain();
|
||||
fmt::print("SwapchainManager::cleanup()\n");
|
||||
}
|
||||
|
||||
void SwapchainManager::create_swapchain(uint32_t width, uint32_t height)
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
void create_swapchain(uint32_t width, uint32_t height);
|
||||
void destroy_swapchain() const;
|
||||
void resize_swapchain(struct SDL_Window *window);
|
||||
void resize_render_targets(VkExtent2D renderExtent);
|
||||
|
||||
VkSwapchainKHR swapchain() const { return _swapchain; }
|
||||
VkFormat swapchainImageFormat() const { return _swapchainImageFormat; }
|
||||
@@ -35,6 +36,8 @@ public:
|
||||
AllocatedImage gBufferExtra() const { return _gBufferExtra; }
|
||||
AllocatedImage idBuffer() const { return _idBuffer; }
|
||||
VkExtent2D windowExtent() const { return _windowExtent; }
|
||||
VkExtent2D renderExtent() const { return _renderExtent; }
|
||||
void set_render_extent(VkExtent2D extent) { _renderExtent = extent; }
|
||||
|
||||
bool resize_requested{false};
|
||||
|
||||
@@ -46,6 +49,7 @@ private:
|
||||
VkFormat _swapchainImageFormat = {};
|
||||
VkExtent2D _swapchainExtent = {};
|
||||
VkExtent2D _windowExtent{kRenderWidth, kRenderHeight};
|
||||
VkExtent2D _renderExtent{kRenderWidth, kRenderHeight};
|
||||
|
||||
std::vector<VkImage> _swapchainImages;
|
||||
std::vector<VkImageView> _swapchainImageViews;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include "config.h"
|
||||
@@ -58,6 +59,28 @@ void vk_engine_draw_debug_ui(VulkanEngine *eng);
|
||||
|
||||
VulkanEngine *loadedEngine = nullptr;
|
||||
|
||||
static VkExtent2D clamp_nonzero_extent(VkExtent2D extent)
|
||||
{
|
||||
if (extent.width == 0) extent.width = 1;
|
||||
if (extent.height == 0) extent.height = 1;
|
||||
return extent;
|
||||
}
|
||||
|
||||
static VkExtent2D scaled_extent(VkExtent2D logicalExtent, float scale)
|
||||
{
|
||||
logicalExtent = clamp_nonzero_extent(logicalExtent);
|
||||
if (!std::isfinite(scale)) scale = 1.0f;
|
||||
scale = std::clamp(scale, 0.1f, 4.0f);
|
||||
|
||||
const float fw = static_cast<float>(logicalExtent.width) * scale;
|
||||
const float fh = static_cast<float>(logicalExtent.height) * scale;
|
||||
|
||||
VkExtent2D out{};
|
||||
out.width = static_cast<uint32_t>(std::max(1.0f, std::floor(fw)));
|
||||
out.height = static_cast<uint32_t>(std::max(1.0f, std::floor(fh)));
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool file_exists_nothrow(const std::string &path)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
@@ -146,9 +169,11 @@ void VulkanEngine::init()
|
||||
// We initialize SDL and create a window with it.
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
// Initialize fixed logical render resolution for the engine.
|
||||
// Initialize default logical render resolution for the engine.
|
||||
_logicalRenderExtent.width = kRenderWidth;
|
||||
_logicalRenderExtent.height = kRenderHeight;
|
||||
_logicalRenderExtent = clamp_nonzero_extent(_logicalRenderExtent);
|
||||
_drawExtent = scaled_extent(_logicalRenderExtent, renderScale);
|
||||
|
||||
constexpr auto window_flags = static_cast<SDL_WindowFlags>(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
|
||||
|
||||
@@ -190,6 +215,7 @@ void VulkanEngine::init()
|
||||
_context->logicalRenderExtent = _logicalRenderExtent;
|
||||
|
||||
_swapchainManager->init(_deviceManager.get(), _resourceManager.get());
|
||||
_swapchainManager->set_render_extent(_drawExtent);
|
||||
_swapchainManager->init_swapchain();
|
||||
|
||||
// Fill remaining context pointers now that managers exist
|
||||
@@ -306,6 +332,45 @@ void VulkanEngine::init()
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
void VulkanEngine::set_logical_render_extent(VkExtent2D extent)
|
||||
{
|
||||
extent = clamp_nonzero_extent(extent);
|
||||
if (_logicalRenderExtent.width == extent.width && _logicalRenderExtent.height == extent.height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logicalRenderExtent = extent;
|
||||
if (_context)
|
||||
{
|
||||
_context->logicalRenderExtent = _logicalRenderExtent;
|
||||
}
|
||||
|
||||
VkExtent2D newDraw = scaled_extent(_logicalRenderExtent, renderScale);
|
||||
if (_swapchainManager)
|
||||
{
|
||||
_swapchainManager->resize_render_targets(newDraw);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanEngine::set_render_scale(float scale)
|
||||
{
|
||||
if (!std::isfinite(scale)) scale = 1.0f;
|
||||
scale = std::clamp(scale, 0.1f, 4.0f);
|
||||
if (std::abs(renderScale - scale) < 1e-4f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderScale = scale;
|
||||
|
||||
VkExtent2D newDraw = scaled_extent(_logicalRenderExtent, renderScale);
|
||||
if (_swapchainManager)
|
||||
{
|
||||
_swapchainManager->resize_render_targets(newDraw);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanEngine::init_default_data()
|
||||
{
|
||||
//> default_img
|
||||
@@ -758,6 +823,17 @@ void VulkanEngine::draw()
|
||||
}
|
||||
}
|
||||
|
||||
// Compute desired internal render-target extent from logical extent + render scale.
|
||||
_drawExtent = scaled_extent(_logicalRenderExtent, renderScale);
|
||||
if (_swapchainManager)
|
||||
{
|
||||
VkExtent2D current = _swapchainManager->renderExtent();
|
||||
if (current.width != _drawExtent.width || current.height != _drawExtent.height)
|
||||
{
|
||||
_swapchainManager->resize_render_targets(_drawExtent);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t swapchainImageIndex;
|
||||
|
||||
VkResult e = vkAcquireNextImageKHR(_deviceManager->device(),
|
||||
@@ -782,11 +858,6 @@ void VulkanEngine::draw()
|
||||
VK_CHECK(e);
|
||||
}
|
||||
|
||||
// Fixed logical render resolution (letterboxed): draw extent is derived
|
||||
// from the engine's logical render size instead of the swapchain/window.
|
||||
_drawExtent.width = static_cast<uint32_t>(static_cast<float>(_logicalRenderExtent.width) * renderScale);
|
||||
_drawExtent.height = static_cast<uint32_t>(static_cast<float>(_logicalRenderExtent.height) * renderScale);
|
||||
|
||||
VK_CHECK(vkResetFences(_deviceManager->device(), 1, &get_current_frame()._renderFence));
|
||||
|
||||
//now that we are sure that the commands finished executing, we can safely reset the command buffer to begin recording again.
|
||||
|
||||
@@ -203,6 +203,12 @@ public:
|
||||
//run main loop
|
||||
void run();
|
||||
|
||||
// Rendering resolution controls:
|
||||
// - logicalRenderExtent controls camera aspect and picking (letterboxed view).
|
||||
// - renderScale controls the internal render target pixel count (logical * scale).
|
||||
void set_logical_render_extent(VkExtent2D extent);
|
||||
void set_render_scale(float scale);
|
||||
|
||||
// Query a conservative streaming texture budget for the texture cache.
|
||||
size_t query_texture_budget_bytes() const;
|
||||
|
||||
|
||||
@@ -51,7 +51,57 @@ namespace
|
||||
ImGui::InputFloat4("data4", reinterpret_cast<float *>(&selected.data.data4));
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::SliderFloat("Render Scale", &eng->renderScale, 0.3f, 1.f);
|
||||
ImGui::TextUnformatted("Render Resolution");
|
||||
|
||||
static int pendingLogicalW = 0;
|
||||
static int pendingLogicalH = 0;
|
||||
if (pendingLogicalW <= 0 || pendingLogicalH <= 0)
|
||||
{
|
||||
pendingLogicalW = static_cast<int>(eng->_logicalRenderExtent.width);
|
||||
pendingLogicalH = static_cast<int>(eng->_logicalRenderExtent.height);
|
||||
}
|
||||
|
||||
ImGui::InputInt("Logical Width", &pendingLogicalW);
|
||||
ImGui::InputInt("Logical Height", &pendingLogicalH);
|
||||
|
||||
if (ImGui::Button("Apply Logical Resolution"))
|
||||
{
|
||||
uint32_t w = static_cast<uint32_t>(pendingLogicalW > 0 ? pendingLogicalW : 1);
|
||||
uint32_t h = static_cast<uint32_t>(pendingLogicalH > 0 ? pendingLogicalH : 1);
|
||||
eng->set_logical_render_extent(VkExtent2D{w, h});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("720p"))
|
||||
{
|
||||
pendingLogicalW = 1280;
|
||||
pendingLogicalH = 720;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("1080p"))
|
||||
{
|
||||
pendingLogicalW = 1920;
|
||||
pendingLogicalH = 1080;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("1440p"))
|
||||
{
|
||||
pendingLogicalW = 2560;
|
||||
pendingLogicalH = 1440;
|
||||
}
|
||||
|
||||
static float pendingScale = 1.0f;
|
||||
if (!ImGui::IsAnyItemActive())
|
||||
{
|
||||
pendingScale = eng->renderScale;
|
||||
}
|
||||
bool scaleChanged = ImGui::SliderFloat("Render Scale", &pendingScale, 0.25f, 2.0f);
|
||||
bool applyScale = scaleChanged && ImGui::IsItemDeactivatedAfterEdit();
|
||||
ImGui::SameLine();
|
||||
applyScale = ImGui::Button("Apply Scale") || applyScale;
|
||||
if (applyScale)
|
||||
{
|
||||
eng->set_render_scale(pendingScale);
|
||||
}
|
||||
}
|
||||
|
||||
// IBL test grid spawner (spheres varying metallic/roughness)
|
||||
|
||||
@@ -45,22 +45,6 @@ void LightingPass::init(EngineContext *context)
|
||||
nullptr, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
|
||||
}
|
||||
|
||||
// Allocate and write GBuffer descriptor set
|
||||
_gBufferInputDescriptorSet = _context->getDescriptors()->allocate(
|
||||
_context->getDevice()->device(), _gBufferInputDescriptorLayout);
|
||||
{
|
||||
DescriptorWriter writer;
|
||||
writer.write_image(0, _context->getSwapchain()->gBufferPosition().imageView, _context->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
writer.write_image(1, _context->getSwapchain()->gBufferNormal().imageView, _context->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
writer.write_image(2, _context->getSwapchain()->gBufferAlbedo().imageView, _context->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
writer.write_image(3, _context->getSwapchain()->gBufferExtra().imageView, _context->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
writer.update_set(_context->getDevice()->device(), _gBufferInputDescriptorSet);
|
||||
}
|
||||
|
||||
// Shadow map descriptor layout (set = 2, updated per-frame). Use array of cascades
|
||||
{
|
||||
DescriptorLayoutBuilder builder;
|
||||
@@ -164,9 +148,9 @@ void LightingPass::register_graph(RenderGraph *graph,
|
||||
|
||||
builder.write_color(drawHandle);
|
||||
},
|
||||
[this, drawHandle, shadowCascades](VkCommandBuffer cmd, const RGPassResources &res, EngineContext *ctx)
|
||||
[this, drawHandle, gbufferPosition, gbufferNormal, gbufferAlbedo, gbufferExtra, shadowCascades](VkCommandBuffer cmd, const RGPassResources &res, EngineContext *ctx)
|
||||
{
|
||||
draw_lighting(cmd, ctx, res, drawHandle, shadowCascades);
|
||||
draw_lighting(cmd, ctx, res, drawHandle, gbufferPosition, gbufferNormal, gbufferAlbedo, gbufferExtra, shadowCascades);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -174,6 +158,10 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
|
||||
EngineContext *context,
|
||||
const RGPassResources &resources,
|
||||
RGImageHandle drawHandle,
|
||||
RGImageHandle gbufferPosition,
|
||||
RGImageHandle gbufferNormal,
|
||||
RGImageHandle gbufferAlbedo,
|
||||
RGImageHandle gbufferExtra,
|
||||
std::span<RGImageHandle> shadowCascades)
|
||||
{
|
||||
EngineContext *ctxLocal = context ? context : _context;
|
||||
@@ -188,6 +176,15 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
|
||||
VkImageView drawView = resources.image_view(drawHandle);
|
||||
if (drawView == VK_NULL_HANDLE) return;
|
||||
|
||||
VkImageView posView = resources.image_view(gbufferPosition);
|
||||
VkImageView nrmView = resources.image_view(gbufferNormal);
|
||||
VkImageView albView = resources.image_view(gbufferAlbedo);
|
||||
VkImageView extView = resources.image_view(gbufferExtra);
|
||||
if (posView == VK_NULL_HANDLE || nrmView == VK_NULL_HANDLE || albView == VK_NULL_HANDLE || extView == VK_NULL_HANDLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose RT only if TLAS is valid; otherwise fall back to non-RT.
|
||||
const bool haveRTFeatures = ctxLocal->getDevice()->supportsAccelerationStructure();
|
||||
const VkAccelerationStructureKHR tlas = (ctxLocal->ray ? ctxLocal->ray->tlas() : VK_NULL_HANDLE);
|
||||
@@ -235,11 +232,27 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
|
||||
}
|
||||
writer.update_set(deviceManager->device(), globalDescriptor);
|
||||
|
||||
// Allocate and write GBuffer descriptor set for this frame (set = 1).
|
||||
VkDescriptorSet gbufferSet = ctxLocal->currentFrame->_frameDescriptors.allocate(
|
||||
deviceManager->device(), _gBufferInputDescriptorLayout);
|
||||
{
|
||||
DescriptorWriter gbw;
|
||||
gbw.write_image(0, posView, ctxLocal->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
gbw.write_image(1, nrmView, ctxLocal->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
gbw.write_image(2, albView, ctxLocal->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
gbw.write_image(3, extView, ctxLocal->getSamplers()->defaultLinear(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
gbw.update_set(deviceManager->device(), gbufferSet);
|
||||
}
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 0, 1, &globalDescriptor, 0,
|
||||
nullptr);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 1, 1,
|
||||
&_gBufferInputDescriptorSet, 0, nullptr);
|
||||
&gbufferSet, 0, nullptr);
|
||||
|
||||
// Allocate and write shadow descriptor set for this frame (set = 2).
|
||||
// When RT is enabled, TLAS is bound in the global set at (set=0, binding=1)
|
||||
|
||||
@@ -27,7 +27,6 @@ private:
|
||||
EngineContext *_context = nullptr;
|
||||
|
||||
VkDescriptorSetLayout _gBufferInputDescriptorLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorSet _gBufferInputDescriptorSet = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout _shadowDescriptorLayout = VK_NULL_HANDLE; // set=2 (array)
|
||||
// Fallbacks if IBL is not loaded
|
||||
AllocatedImage _fallbackIbl2D{}; // 1x1 black
|
||||
@@ -41,6 +40,10 @@ private:
|
||||
EngineContext *context,
|
||||
const class RGPassResources &resources,
|
||||
RGImageHandle drawHandle,
|
||||
RGImageHandle gbufferPosition,
|
||||
RGImageHandle gbufferNormal,
|
||||
RGImageHandle gbufferAlbedo,
|
||||
RGImageHandle gbufferExtra,
|
||||
std::span<RGImageHandle> shadowCascades);
|
||||
|
||||
DeletionQueue _deletionQueue;
|
||||
|
||||
Reference in New Issue
Block a user