From 6d77396b4d6a1b30f6315f7e1152480c023671d6 Mon Sep 17 00:00:00 2001 From: redstrate <54911369+redstrate@users.noreply.github.com> Date: Mon, 15 Feb 2021 17:59:54 -0500 Subject: [PATCH] Support CopyTexture command on Vulkan --- engine/gfx/public/gfx.hpp | 1 + engine/gfx/public/gfx_commandbuffer.hpp | 10 +- engine/gfx/vulkan/include/gfx_vulkan.hpp | 4 +- engine/gfx/vulkan/src/gfx_vulkan.cpp | 209 ++++++++++++------- engine/gfx/vulkan/src/gfx_vulkan_texture.hpp | 1 + engine/renderer/src/scenecapture.cpp | 33 ++- engine/renderer/src/shadowpass.cpp | 2 + 7 files changed, 168 insertions(+), 92 deletions(-) diff --git a/engine/gfx/public/gfx.hpp b/engine/gfx/public/gfx.hpp index 3601da5..57b66fa 100755 --- a/engine/gfx/public/gfx.hpp +++ b/engine/gfx/public/gfx.hpp @@ -41,6 +41,7 @@ enum class GFXTextureUsage : int { Sampled = 1, Attachment = 2, ShaderWrite = 3, + Transfer = 4 }; inline GFXTextureUsage operator|(const GFXTextureUsage a, const GFXTextureUsage b) { diff --git a/engine/gfx/public/gfx_commandbuffer.hpp b/engine/gfx/public/gfx_commandbuffer.hpp index 912d19d..002f280 100755 --- a/engine/gfx/public/gfx_commandbuffer.hpp +++ b/engine/gfx/public/gfx_commandbuffer.hpp @@ -60,7 +60,8 @@ enum class GFXCommandType { PushGroup, PopGroup, InsertLabel, - Dispatch + Dispatch, + EndRenderPass }; struct GFXDrawCommand { @@ -362,5 +363,12 @@ public: commands.push_back(command); } + void end_render_pass() { + GFXDrawCommand command; + command.type = GFXCommandType::EndRenderPass; + + commands.push_back(command); + } + std::vector commands; }; diff --git a/engine/gfx/vulkan/include/gfx_vulkan.hpp b/engine/gfx/vulkan/include/gfx_vulkan.hpp index 3973dee..bf94b11 100755 --- a/engine/gfx/vulkan/include/gfx_vulkan.hpp +++ b/engine/gfx/vulkan/include/gfx_vulkan.hpp @@ -74,8 +74,8 @@ private: uint64_t getDescriptorHash(GFXVulkanPipeline* pipeline); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); - void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout); - void inlineTransitionImageLayout(VkCommandBuffer command_buffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout); + void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout); + void inlineTransitionImageLayout(VkCommandBuffer command_buffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout); VkShaderModule createShaderModule(const uint32_t* code, const int length); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp index a12c357..332b79a 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan.cpp +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -342,6 +342,9 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { else { imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; } + + if((info.usage & GFXTextureUsage::Transfer) == GFXTextureUsage::Transfer) + imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; VkImageAspectFlagBits imageAspect; if (info.format == GFXPixelFormat::DEPTH_32F) @@ -396,8 +399,19 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { vkAllocateMemory(device, &allocInfo, nullptr, &texture->memory); vkBindImageMemory(device, texture->handle, texture->memory, 0); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = info.mip_count; + range.baseArrayLayer = 0; + range.layerCount = info.array_length; + + if(info.type == GFXTextureType::Cubemap || info.type == GFXTextureType::CubemapArray) + range.layerCount *= 6; + + texture->range = range; - transitionImageLayout(texture->handle, imageFormat, imageAspect, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + transitionImageLayout(texture->handle, imageFormat, imageAspect, range, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // create image view VkImageViewCreateInfo viewInfo = {}; @@ -419,11 +433,8 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { break; } viewInfo.format = imageFormat; + viewInfo.subresourceRange = range; viewInfo.subresourceRange.aspectMask = imageAspect; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = info.mip_count; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = array_length; vkCreateImageView(device, &viewInfo, nullptr, &texture->view); @@ -487,8 +498,14 @@ void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) { // copy staging buffer to image VkCommandBuffer commandBuffer = beginSingleTimeCommands(); - - inlineTransitionImageLayout(commandBuffer, vulkanTexture->handle, vulkanTexture->format, vulkanTexture->aspect, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + inlineTransitionImageLayout(commandBuffer, vulkanTexture->handle, vulkanTexture->format, vulkanTexture->aspect, range, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = vulkanTexture->aspect; @@ -503,7 +520,7 @@ void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) { vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, vulkanTexture->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - inlineTransitionImageLayout(commandBuffer, vulkanTexture->handle, vulkanTexture->format, vulkanTexture->aspect, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + inlineTransitionImageLayout(commandBuffer, vulkanTexture->handle, vulkanTexture->format, vulkanTexture->aspect, range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); endSingleTimeCommands(commandBuffer); } @@ -574,7 +591,13 @@ GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& in if (texture->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) expectedLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - transitionImageLayout(texture->handle, texture->format, texture->aspect, texture->layout, expectedLayout); + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + transitionImageLayout(texture->handle, texture->format, texture->aspect, range, texture->layout, expectedLayout); } VkFramebufferCreateInfo framebufferInfo = {}; @@ -1015,91 +1038,91 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { for (auto command : command_buffer->commands) { switch (command.type) { - case GFXCommandType::SetRenderPass: - { - // end the previous render pass - if (currentRenderPass != VK_NULL_HANDLE) { - vkCmdEndRenderPass(cmd); - } - - GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass; - GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer; - - if (renderPass != nullptr) { - currentRenderPass = renderPass->handle; - } - else { - currentRenderPass = swapchainRenderPass; - } - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = currentRenderPass; - - if (framebuffer != nullptr) { - renderPassInfo.framebuffer = framebuffer->handle; - + case GFXCommandType::SetRenderPass: + { + // end the previous render pass + if (currentRenderPass != VK_NULL_HANDLE) { + vkCmdEndRenderPass(cmd); + } + + GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass; + GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer; + + if (renderPass != nullptr) { + currentRenderPass = renderPass->handle; + } + else { + currentRenderPass = swapchainRenderPass; + } + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = currentRenderPass; + + if (framebuffer != nullptr) { + renderPassInfo.framebuffer = framebuffer->handle; + VkViewport viewport = {}; - viewport.y = static_cast(framebuffer->height); + viewport.y = static_cast(framebuffer->height); viewport.width = static_cast(framebuffer->width); viewport.height = -static_cast(framebuffer->height); viewport.maxDepth = 1.0f; - + vkCmdSetViewport(cmd, 0, 1, &viewport); - + VkRect2D scissor = {}; scissor.extent.width = framebuffer->width; scissor.extent.height = framebuffer->height; - + vkCmdSetScissor(cmd, 0, 1, &scissor); - } - else { - renderPassInfo.framebuffer = swapchainFramebuffers[imageIndex]; - + } + else { + renderPassInfo.framebuffer = swapchainFramebuffers[imageIndex]; + VkViewport viewport = {}; - viewport.y = static_cast(surfaceHeight); + viewport.y = static_cast(surfaceHeight); viewport.width = static_cast(surfaceWidth); viewport.height = -static_cast(surfaceHeight); viewport.maxDepth = 1.0f; - + vkCmdSetViewport(cmd, 0, 1, &viewport); - + VkRect2D scissor = {}; scissor.extent.width = surfaceWidth; scissor.extent.height = surfaceHeight; - + vkCmdSetScissor(cmd, 0, 1, &scissor); - } - - renderPassInfo.renderArea.offset = { command.data.set_render_pass.render_area.offset.x, command.data.set_render_pass.render_area.offset.y }; + } + + renderPassInfo.renderArea.offset = { command.data.set_render_pass.render_area.offset.x, command.data.set_render_pass.render_area.offset.y }; renderPassInfo.renderArea.extent = { command.data.set_render_pass.render_area.extent.width, command.data.set_render_pass.render_area.extent.height }; - - std::vector clearColors; - if (renderPass != nullptr) { - clearColors.resize(renderPass->numAttachments); - } - else { - clearColors.resize(1); - } - - clearColors[0].color.float32[0] = command.data.set_render_pass.clear_color.r; - clearColors[0].color.float32[1] = command.data.set_render_pass.clear_color.g; - clearColors[0].color.float32[2] = command.data.set_render_pass.clear_color.b; - clearColors[0].color.float32[3] = command.data.set_render_pass.clear_color.a; - + + std::vector clearColors; + if (renderPass != nullptr) { + clearColors.resize(renderPass->numAttachments); + } + else { + clearColors.resize(1); + } + + clearColors[0].color.float32[0] = command.data.set_render_pass.clear_color.r; + clearColors[0].color.float32[1] = command.data.set_render_pass.clear_color.g; + clearColors[0].color.float32[2] = command.data.set_render_pass.clear_color.b; + clearColors[0].color.float32[3] = command.data.set_render_pass.clear_color.a; + if(renderPass != nullptr) { if(renderPass->depth_attachment != -1) clearColors[renderPass->depth_attachment].depthStencil.depth = 1.0f; } - - renderPassInfo.clearValueCount = static_cast(clearColors.size()); - renderPassInfo.pClearValues = clearColors.data(); - - vkCmdBeginRenderPass(cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - currentPipeline = nullptr; - } - break; + + renderPassInfo.clearValueCount = static_cast(clearColors.size()); + renderPassInfo.pClearValues = clearColors.data(); + + vkCmdBeginRenderPass(cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + currentPipeline = nullptr; + } + break; case GFXCommandType::SetGraphicsPipeline: { currentPipeline = (GFXVulkanPipeline*)command.data.set_graphics_pipeline.pipeline; @@ -1170,7 +1193,40 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { vkCmdSetDepthBias(cmd, command.data.set_depth_bias.constant, command.data.set_depth_bias.clamp, command.data.set_depth_bias.slope_factor); } break; + case GFXCommandType::CopyTexture: + { + GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src; + GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst; + + inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, src->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dst->range, dst->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6; + + VkImageCopy region = {}; + region.extent = {static_cast(command.data.copy_texture.width), static_cast(command.data.copy_texture.height), 1}; + region.dstSubresource.baseArrayLayer = slice_offset; + region.dstSubresource.mipLevel = command.data.copy_texture.to_level; + region.srcSubresource.aspectMask = src->aspect; + region.dstSubresource.aspectMask = dst->aspect; + region.srcSubresource.layerCount = 1; + region.dstSubresource.layerCount = 1; + + vkCmdCopyImage(cmd, src->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src->layout); + inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dst->range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst->layout); + } + break; + case GFXCommandType::EndRenderPass: + { + if(currentRenderPass != nullptr) { + vkCmdEndRenderPass(cmd); + currentRenderPass = nullptr; + } } + break; + } } // end the last render pass @@ -1744,15 +1800,15 @@ uint32_t GFXVulkan::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags pr return -1; } -void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout) { +void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout) { VkCommandBuffer commandBuffer = beginSingleTimeCommands(); - inlineTransitionImageLayout(commandBuffer, image, format, aspect, oldLayout, newLayout); + inlineTransitionImageLayout(commandBuffer, image, format, aspect, range, oldLayout, newLayout); endSingleTimeCommands(commandBuffer); } -void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout) { +void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout) { VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = oldLayout; @@ -1760,11 +1816,8 @@ void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkIma barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; + barrier.subresourceRange = range; barrier.subresourceRange.aspectMask = aspect; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; diff --git a/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp b/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp index 6aaca85..9648353 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp +++ b/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp @@ -16,4 +16,5 @@ public: VkFormat format; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageAspectFlagBits aspect; + VkImageSubresourceRange range; }; diff --git a/engine/renderer/src/scenecapture.cpp b/engine/renderer/src/scenecapture.cpp index 54feb52..387a00a 100755 --- a/engine/renderer/src/scenecapture.cpp +++ b/engine/renderer/src/scenecapture.cpp @@ -42,6 +42,18 @@ struct SceneInformation { int p[3]; }; +struct SkyPushConstant { + Matrix4x4 view; + Vector4 sun_position_fov; + float aspect; +}; + +struct FilterPushConstant { + Matrix4x4 mvp; + float roughness; + float buffer[15]; +}; + const int mipLevels = 5; const std::array sceneTransforms = { @@ -71,7 +83,7 @@ SceneCapture::SceneCapture(GFX* gfx) { textureInfo.width = scene_cubemap_resolution; textureInfo.height = scene_cubemap_resolution; textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; - textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Transfer; textureInfo.samplingMode = SamplingMode::ClampToEdge; offscreenTexture = gfx->create_texture(textureInfo); @@ -297,6 +309,7 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { command_buffer->draw(0, 4, 0, 1); + command_buffer->end_render_pass(); command_buffer->copy_texture(offscreenTexture, scene_cubemap_resolution, scene_cubemap_resolution, environmentCube, face, 0, 0); }; @@ -332,7 +345,8 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { command_buffer->set_push_constant(&mvp, sizeof(Matrix4x4)); command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0); - + + command_buffer->end_render_pass(); command_buffer->copy_texture(irradianceOffscreenTexture, irradiance_cubemap_resolution, irradiance_cubemap_resolution, scene->irradianceCubeArray, face, last_probe, 0); }; @@ -359,11 +373,7 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { command_buffer->set_vertex_buffer(cubeMesh->position_buffer, 0, 0); command_buffer->set_index_buffer(cubeMesh->index_buffer, IndexType::UINT32); - struct PushConstant { - Matrix4x4 mvp; - float roughness; - } pc; - + FilterPushConstant pc; pc.mvp = projection * sceneTransforms[face]; pc.roughness = ((float)mip) / (float)(mipLevels - 1); @@ -373,6 +383,7 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0); + command_buffer->end_render_pass(); command_buffer->copy_texture(prefilteredOffscreenTexture, info.render_area.extent.width, info.render_area.extent.height, scene->prefilteredCubeArray, face, last_probe, mip); }; @@ -401,7 +412,7 @@ void SceneCapture::createSkyResources() { }; pipelineInfo.shader_input.push_constants = { - {(sizeof(Matrix4x4) + sizeof(Vector4) + sizeof(float)), 0} + {sizeof(SkyPushConstant), 0} }; pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; @@ -417,7 +428,7 @@ void SceneCapture::createIrradianceResources() { textureInfo.width = irradiance_cubemap_resolution; textureInfo.height = irradiance_cubemap_resolution; textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; - textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Transfer; textureInfo.samplingMode = SamplingMode::ClampToEdge; irradianceOffscreenTexture = gfx->create_texture(textureInfo); @@ -471,7 +482,7 @@ void SceneCapture::createPrefilterResources() { textureInfo.width = scene_cubemap_resolution; textureInfo.height = scene_cubemap_resolution; textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; - textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Transfer; textureInfo.samplingMode = SamplingMode::ClampToEdge; prefilteredOffscreenTexture = gfx->create_texture(textureInfo); @@ -504,7 +515,7 @@ void SceneCapture::createPrefilterResources() { pipelineInfo.vertex_input.attributes.push_back(positionAttribute); pipelineInfo.shader_input.push_constants = { - {sizeof(Matrix4x4) + sizeof(float), 0} + {sizeof(FilterPushConstant), 0} }; pipelineInfo.shader_input.bindings = { diff --git a/engine/renderer/src/shadowpass.cpp b/engine/renderer/src/shadowpass.cpp index f63fcc8..6767316 100755 --- a/engine/renderer/src/shadowpass.cpp +++ b/engine/renderer/src/shadowpass.cpp @@ -245,6 +245,7 @@ void ShadowPass::render_spot(GFXCommandBuffer* command_buffer, Scene& scene, Obj if(light.enable_shadows) render_meshes(command_buffer, scene, realMVP, Matrix4x4(), scene.get(light_object).get_world_position(), Light::Type::Spot, frustum, 0); + command_buffer->end_render_pass(); command_buffer->copy_texture(offscreen_depth, render_options.shadow_resolution, render_options.shadow_resolution, scene.spotLightArray, 0, last_spot_light, 0); scene.spot_light_dirty[last_spot_light] = false; @@ -286,6 +287,7 @@ void ShadowPass::render_point(GFXCommandBuffer* command_buffer, Scene& scene, Ob render_meshes(command_buffer, scene, projection * shadowTransforms[face], model, lightPos, Light::Type::Point, frustum, last_point_light); + command_buffer->end_render_pass(); command_buffer->copy_texture(offscreen_color_texture, render_options.shadow_resolution, render_options.shadow_resolution, scene.pointLightArray, face, last_point_light, 0); }