Begin adding shadow mapping and a few vulkan fixes

This commit is contained in:
bailehuni 2024-03-23 21:16:30 +00:00
parent 8aa8085f69
commit f04c516d2b
12 changed files with 254 additions and 132 deletions

View File

@ -119,8 +119,8 @@ struct PipelineInfo {
std::string vert_shader_path; std::string vert_shader_path;
std::string frag_shader_path; std::string frag_shader_path;
VertexFormat vertex_format; VertexFormat vertex_format;
CullMode face_cull_mode;
bool alpha_blending; bool alpha_blending;
bool backface_culling;
bool write_z; bool write_z;
bool line_primitives; // false for triangles, true for lines bool line_primitives; // false for triangles, true for lines
std::vector<const DescriptorSetLayout*> descriptor_set_layouts; std::vector<const DescriptorSetLayout*> descriptor_set_layouts;

View File

@ -85,8 +85,12 @@ class Renderer : private ApplicationComponent {
*/ */
// in vertex shader // in vertex shader
UniformDescriptor<glm::mat4> global_uniform; // rarely updates; set 0 struct GlobalUniformData {
UniformDescriptor<glm::mat4> frame_uniform; // updates once per frame; set 1 glm::mat4 proj;
glm::mat4 lightSpaceMatrix;
};
UniformDescriptor<GlobalUniformData> global_uniform; // rarely updates; set 0 binding 0
UniformDescriptor<glm::mat4> frame_uniform; // updates once per frame; set 1 binding 0
// in fragment shader // in fragment shader
const gfx::DescriptorSetLayout* material_set_layout; // set 2; set bound per material const gfx::DescriptorSetLayout* material_set_layout; // set 2; set bound per material
@ -106,6 +110,9 @@ class Renderer : private ApplicationComponent {
const gfx::Pipeline* skybox_pipeline = nullptr; const gfx::Pipeline* skybox_pipeline = nullptr;
const gfx::Buffer* skybox_buffer = nullptr; const gfx::Buffer* skybox_buffer = nullptr;
gfx::Image* shadow_map = nullptr;
const gfx::Sampler* shadow_map_sampler = nullptr;
void DrawRenderList(gfx::DrawBuffer* draw_buffer, const RenderList& render_list); void DrawRenderList(gfx::DrawBuffer* draw_buffer, const RenderList& render_list);
}; };

View File

@ -4,6 +4,7 @@
#define PI_INV 0.31830988618379067153776752674503 #define PI_INV 0.31830988618379067153776752674503
layout(set = 0, binding = 1) uniform samplerCube globalSetSkybox; layout(set = 0, binding = 1) uniform samplerCube globalSetSkybox;
layout(set = 0, binding = 2) uniform sampler2D globalSetShadowmap;
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
@ -16,6 +17,7 @@ layout(location = 3) in vec3 fragLightPosTangentSpace;
layout(location = 4) in vec3 fragNormWorldSpace; layout(location = 4) in vec3 fragNormWorldSpace;
layout(location = 5) in vec3 fragViewPosWorldSpace; layout(location = 5) in vec3 fragViewPosWorldSpace;
layout(location = 6) in vec3 fragPosWorldSpace; layout(location = 6) in vec3 fragPosWorldSpace;
layout(location = 7) in vec4 fragPosLightSpace;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
@ -81,5 +83,13 @@ void main() {
vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164); vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164);
lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz;
projCoords.x = projCoords.x * 0.5 + 0.5;
projCoords.y = projCoords.y * 0.5 + 0.5;
float closestDepth = texture(globalSetShadowmap, projCoords.xy).r;
float currentDepth = projCoords.z;
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
outColor = vec4(min(emission + lighting, 1.0), 1.0); outColor = vec4(min(emission + lighting, 1.0), 1.0);
//outColor = vec4(shadow, 0.0, 0.0, 1.0);
} }

View File

@ -2,6 +2,7 @@
layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer {
mat4 proj; mat4 proj;
mat4 lightSpaceMatrix;
} globalSetUniformBuffer; } globalSetUniformBuffer;
layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { layout(set = 1, binding = 0) uniform FrameSetUniformBuffer {
@ -24,6 +25,7 @@ layout(location = 3) out vec3 fragLightPosTangentSpace;
layout(location = 4) out vec3 fragNormWorldSpace; layout(location = 4) out vec3 fragNormWorldSpace;
layout(location = 5) out vec3 fragViewPosWorldSpace; layout(location = 5) out vec3 fragViewPosWorldSpace;
layout(location = 6) out vec3 fragPosWorldSpace; layout(location = 6) out vec3 fragPosWorldSpace;
layout(location = 7) out vec4 fragPosLightSpace;
void main() { void main() {
vec4 worldPosition = constants.model * vec4(inPosition, 1.0); vec4 worldPosition = constants.model * vec4(inPosition, 1.0);
@ -43,5 +45,7 @@ void main() {
fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
fragPosWorldSpace = worldPosition.xyz; fragPosWorldSpace = worldPosition.xyz;
fragPosLightSpace = globalSetUniformBuffer.lightSpaceMatrix * vec4(worldPosition.xyz, 1.0);
gl_Position.y *= -1.0; gl_Position.y *= -1.0;
} }

View File

@ -2,6 +2,7 @@
layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer {
mat4 proj; mat4 proj;
mat4 lightSpaceMatrix;
} globalSetUniformBuffer; } globalSetUniformBuffer;
layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { layout(set = 1, binding = 0) uniform FrameSetUniformBuffer {

View File

@ -235,7 +235,7 @@ static VkShaderStageFlags getShaderStageFlags(gfx::ShaderStageFlags::Flags flags
return out; return out;
} }
[[maybe_unused]] static VkCullModeFlags getCullModeFlags(gfx::CullMode mode) static VkCullModeFlags getCullModeFlags(gfx::CullMode mode)
{ {
switch (mode) { switch (mode) {
case gfx::CullMode::kCullNone: case gfx::CullMode::kCullNone:
@ -646,7 +646,7 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
VKCHECK(res); VKCHECK(res);
/* perform any pending uniform buffer writes */ /* perform any pending uniform buffer writes */
VKCHECK(vkResetCommandPool(pimpl->device.device, frameData.transferPool, 0)); VKCHECK(vkResetCommandPool(pimpl->device.device, frameData.transferPool, 0)); // TODO: possibly delete this
VkCommandBufferBeginInfo transferBeginInfo{ VkCommandBufferBeginInfo transferBeginInfo{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
@ -658,19 +658,49 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
// transfer cmds... // transfer cmds...
std::vector<VkBufferMemoryBarrier2> barriers{}; if (pimpl->FRAMECOUNT >= FRAMES_IN_FLIGHT) { // cannot (and don't need to) do ownership transfer on first frame[s]
// acquire ownership of buffers
std::vector<VkBufferMemoryBarrier2> acquireBarriers{};
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) {
VkBufferMemoryBarrier2& barrier = acquireBarriers.emplace_back();
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
barrier.srcAccessMask = 0;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
barrier.buffer = uniformBuffer->gpuBuffers[currentFrameIndex].buffer;
barrier.offset = 0;
barrier.size = uniformBuffer->gpuBuffers[currentFrameIndex].size;
}
VkDependencyInfo dependencyInfo{};
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependencyInfo.bufferMemoryBarrierCount = (uint32_t)acquireBarriers.size();
dependencyInfo.pBufferMemoryBarriers = acquireBarriers.data();
vkCmdPipelineBarrier2(frameData.transferBuf, &dependencyInfo);
}
{
// copy stagings buffers to GPU buffer
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) { for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) {
VkBufferCopy copyRegion{}; VkBufferCopy copyRegion{};
copyRegion.srcOffset = 0; copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0; copyRegion.dstOffset = 0;
copyRegion.size = uniformBuffer->stagingBuffer.size; copyRegion.size = uniformBuffer->stagingBuffer.size;
vkCmdCopyBuffer(frameData.transferBuf, uniformBuffer->stagingBuffer.buffer, uniformBuffer->gpuBuffers[currentFrameIndex].buffer, 1, &copyRegion); vkCmdCopyBuffer(frameData.transferBuf, uniformBuffer->stagingBuffer.buffer, uniformBuffer->gpuBuffers[currentFrameIndex].buffer, 1, &copyRegion);
}
}
VkBufferMemoryBarrier2& barrier = barriers.emplace_back(); {
// release buffers to graphics queue
std::vector<VkBufferMemoryBarrier2> releaseBarriers{};
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) {
VkBufferMemoryBarrier2& barrier = releaseBarriers.emplace_back();
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
barrier.dstAccessMask = 0; barrier.dstAccessMask = 0;
barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -678,16 +708,14 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
barrier.offset = 0; barrier.offset = 0;
barrier.size = uniformBuffer->gpuBuffers[currentFrameIndex].size; barrier.size = uniformBuffer->gpuBuffers[currentFrameIndex].size;
} }
pimpl->write_queues[currentFrameIndex].uniform_buffer_writes.clear();
VkDependencyInfo dependencyInfo{}; VkDependencyInfo dependencyInfo{};
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependencyInfo.bufferMemoryBarrierCount = (uint32_t)barriers.size(); dependencyInfo.bufferMemoryBarrierCount = (uint32_t)releaseBarriers.size();
dependencyInfo.pBufferMemoryBarriers = barriers.data(); dependencyInfo.pBufferMemoryBarriers = releaseBarriers.data();
vkCmdPipelineBarrier2(frameData.transferBuf, &dependencyInfo); vkCmdPipelineBarrier2(frameData.transferBuf, &dependencyInfo);
}
VKCHECK(vkEndCommandBuffer(frameData.transferBuf)); VKCHECK(vkEndCommandBuffer(frameData.transferBuf));
VkSubmitInfo transferSubmitInfo{ VkSubmitInfo transferSubmitInfo{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -733,13 +761,25 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
{ // RECORDING { // RECORDING
/* change barriers to perform a queue ownership acquire operation */ // acquire ownership of buffers
for (VkBufferMemoryBarrier2& barrier : barriers) { std::vector<VkBufferMemoryBarrier2> acquireBarriers{};
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) {
VkBufferMemoryBarrier2& barrier = acquireBarriers.emplace_back();
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT;
barrier.srcAccessMask = 0; barrier.srcAccessMask = 0;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT;
barrier.dstAccessMask = VK_ACCESS_2_UNIFORM_READ_BIT; barrier.dstAccessMask = VK_ACCESS_2_UNIFORM_READ_BIT;
barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.buffer = uniformBuffer->gpuBuffers[currentFrameIndex].buffer;
barrier.offset = 0;
barrier.size = uniformBuffer->gpuBuffers[currentFrameIndex].size;
} }
VkDependencyInfo dependencyInfo{};
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependencyInfo.bufferMemoryBarrierCount = (uint32_t)acquireBarriers.size();
dependencyInfo.pBufferMemoryBarriers = acquireBarriers.data();
vkCmdPipelineBarrier2(frameData.drawBuf, &dependencyInfo); vkCmdPipelineBarrier2(frameData.drawBuf, &dependencyInfo);
std::array<VkClearValue, 2> clearValues{}; // Using same value for all components enables std::array<VkClearValue, 2> clearValues{}; // Using same value for all components enables
@ -801,6 +841,27 @@ void GFXDevice::FinishRender(gfx::DrawBuffer* drawBuffer)
vkCmdEndRenderPass(drawBuffer->frameData.drawBuf); vkCmdEndRenderPass(drawBuffer->frameData.drawBuf);
// transfer ownership of uniform buffers back to transfer queue
std::vector<VkBufferMemoryBarrier2> releaseBarriers{};
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[drawBuffer->currentFrameIndex].uniform_buffer_writes) {
VkBufferMemoryBarrier2& barrier = releaseBarriers.emplace_back();
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT;
barrier.srcAccessMask = VK_ACCESS_2_UNIFORM_READ_BIT;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT;
barrier.dstAccessMask = 0;
barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
barrier.buffer = uniformBuffer->gpuBuffers[drawBuffer->currentFrameIndex].buffer;
barrier.offset = 0;
barrier.size = uniformBuffer->gpuBuffers[drawBuffer->currentFrameIndex].size;
}
VkDependencyInfo dependencyInfo{};
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependencyInfo.bufferMemoryBarrierCount = (uint32_t)releaseBarriers.size();
dependencyInfo.pBufferMemoryBarriers = releaseBarriers.data();
vkCmdPipelineBarrier2(drawBuffer->frameData.drawBuf, &dependencyInfo);
res = vkEndCommandBuffer(drawBuffer->frameData.drawBuf); res = vkEndCommandBuffer(drawBuffer->frameData.drawBuf);
VKCHECK(res); VKCHECK(res);
@ -846,6 +907,9 @@ void GFXDevice::FinishRender(gfx::DrawBuffer* drawBuffer)
else if (res != VK_SUCCESS) else if (res != VK_SUCCESS)
throw std::runtime_error("Failed to queue present! Code: " + std::to_string(res)); throw std::runtime_error("Failed to queue present! Code: " + std::to_string(res));
// clear write queue
pimpl->write_queues[drawBuffer->currentFrameIndex].uniform_buffer_writes.clear();
pimpl->FRAMECOUNT++; pimpl->FRAMECOUNT++;
delete drawBuffer; delete drawBuffer;
@ -1011,12 +1075,7 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
rasterizer.rasterizerDiscardEnable = VK_FALSE; // enabling this will not run the fragment shaders at all rasterizer.rasterizerDiscardEnable = VK_FALSE; // enabling this will not run the fragment shaders at all
rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f; rasterizer.lineWidth = 1.0f;
if (info.backface_culling == true) { rasterizer.cullMode = converters::getCullModeFlags(info.face_cull_mode);
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
}
else {
rasterizer.cullMode = VK_CULL_MODE_NONE;
}
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE; rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f; // ignored rasterizer.depthBiasConstantFactor = 0.0f; // ignored
@ -1488,8 +1547,8 @@ gfx::Image* GFXDevice::CreateImage(uint32_t w, uint32_t h, gfx::ImageFormat inpu
beforeCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; beforeCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
beforeCopyBarrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE; beforeCopyBarrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
beforeCopyBarrier.srcAccessMask = VK_ACCESS_2_NONE; beforeCopyBarrier.srcAccessMask = VK_ACCESS_2_NONE;
beforeCopyBarrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT; beforeCopyBarrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; // all subresources will be COPYed or BLITed to next
beforeCopyBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; beforeCopyBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; // Image must be TRANSFER_DST_OPTIMAL before either stage performs a TRANSFER_WRITE
beforeCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; beforeCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
beforeCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; beforeCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
beforeCopyBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; beforeCopyBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1528,10 +1587,11 @@ gfx::Image* GFXDevice::CreateImage(uint32_t w, uint32_t h, gfx::ImageFormat inpu
// Must happen after TRANSFER_WRITE in the COPY stage and BLIT stage. // Must happen after TRANSFER_WRITE in the COPY stage and BLIT stage.
VkImageMemoryBarrier2 beforeBlitBarrier{}; VkImageMemoryBarrier2 beforeBlitBarrier{};
beforeBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; beforeBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
beforeBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; beforeBlitBarrier.srcStageMask =
beforeBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; // previous mip level was either just COPYed to or just BLITed to
beforeBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; beforeBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; // these actions were TRANSFER_WRITEs
beforeBlitBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; beforeBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; // the image will be BLITed from next
beforeBlitBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; // this is a TRANSFER_READ
beforeBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; beforeBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
beforeBlitBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; beforeBlitBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
beforeBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; beforeBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1570,9 +1630,9 @@ gfx::Image* GFXDevice::CreateImage(uint32_t w, uint32_t h, gfx::ImageFormat inpu
VkImageMemoryBarrier2 afterBlitBarrier{}; VkImageMemoryBarrier2 afterBlitBarrier{};
afterBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; afterBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
afterBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; afterBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT;
afterBlitBarrier.srcAccessMask = 0; afterBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; // previous mip level was just READ from in a BLIT
afterBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; afterBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
afterBlitBarrier.dstAccessMask = VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_2_SHADER_READ_BIT; afterBlitBarrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT; // it will next be sampled in a frag shader
afterBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; afterBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
afterBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; afterBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
afterBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; afterBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1597,10 +1657,17 @@ gfx::Image* GFXDevice::CreateImage(uint32_t w, uint32_t h, gfx::ImageFormat inpu
// barrier: (mipLevels - 1) TRANSFER_DST_OPTIMAL -> SHADER_READ_ONLY_OPTIMAL // barrier: (mipLevels - 1) TRANSFER_DST_OPTIMAL -> SHADER_READ_ONLY_OPTIMAL
VkImageMemoryBarrier2 finalBlitBarrier{}; VkImageMemoryBarrier2 finalBlitBarrier{};
finalBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; finalBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
finalBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_COPY_BIT; if (mipLevels == 1) {
// if no mipmaps were generated, the image was just COPYed to with a WRITE
finalBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT; // the final mip level was BLITed to with a WRITE
}
else {
// mips were generated, therefore last mip level was just BLITed to
finalBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT;
}
finalBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; finalBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
finalBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; finalBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
finalBlitBarrier.dstAccessMask = VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_2_SHADER_READ_BIT; finalBlitBarrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
finalBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; finalBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
finalBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; finalBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
finalBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; finalBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1733,7 +1800,7 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VKCHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo)); VKCHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo));
// barrier: (all mip levels): UNDEFINED -> TRANSFER_DST_OPTIMAL // barrier: (all mip levels, all faces): UNDEFINED -> TRANSFER_DST_OPTIMAL
// Used for copying staging buffer AND blitting mipmaps // Used for copying staging buffer AND blitting mipmaps
// Must happen before vkCmdCopyBufferToImage performs a TRANSFER_WRITE in // Must happen before vkCmdCopyBufferToImage performs a TRANSFER_WRITE in
// the COPY stage. // the COPY stage.
@ -1741,7 +1808,8 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
beforeCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; beforeCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
beforeCopyBarrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE; beforeCopyBarrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
beforeCopyBarrier.srcAccessMask = VK_ACCESS_2_NONE; beforeCopyBarrier.srcAccessMask = VK_ACCESS_2_NONE;
beforeCopyBarrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT; beforeCopyBarrier.dstStageMask =
VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; // all parts of the image will be either TRANSFERed to or BLITed to next
beforeCopyBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; beforeCopyBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
beforeCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; beforeCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
beforeCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; beforeCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@ -1782,10 +1850,12 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
// Must happen after TRANSFER_WRITE in the COPY stage and BLIT stage. // Must happen after TRANSFER_WRITE in the COPY stage and BLIT stage.
VkImageMemoryBarrier2 beforeBlitBarrier{}; VkImageMemoryBarrier2 beforeBlitBarrier{};
beforeBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; beforeBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
beforeBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; beforeBlitBarrier.srcStageMask =
beforeBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT; // subresource was either just copied to or just blitted to
beforeBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; beforeBlitBarrier.srcAccessMask =
beforeBlitBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; VK_ACCESS_2_TRANSFER_WRITE_BIT; // wait until CopyBufferToImage and BlitImage have performed TRANSFER_WRITE on subresource
beforeBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; // subresource is going to be blitted from
beforeBlitBarrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; // subresource will be READ from during the blit
beforeBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; beforeBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
beforeBlitBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; beforeBlitBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
beforeBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; beforeBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1807,16 +1877,16 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
blit.srcSubresource.mipLevel = i - 1; blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = face; blit.srcSubresource.baseArrayLayer = face;
blit.srcSubresource.layerCount = 1; blit.srcSubresource.layerCount = 1;
blit.srcOffsets[0] = { 0, 0, 0 }; blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = { mipWidth, mipHeight, 1 }; blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i; blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = face; blit.dstSubresource.baseArrayLayer = face;
blit.dstSubresource.layerCount = 1; blit.dstSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 }; blit.dstOffsets[0] = {0, 0, 0};
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 }; blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1};
vkCmdBlitImage(commandBuffer, out->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, out->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, vkCmdBlitImage(commandBuffer, out->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, out->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
VK_FILTER_LINEAR); VK_FILTER_LINEAR); // WRITE-AFTER-WRITE error here
// barrier: (i - 1) TRANSFER_SRC_OPTIMAL -> SHADER_READ_ONLY_OPTIMALs // barrier: (i - 1) TRANSFER_SRC_OPTIMAL -> SHADER_READ_ONLY_OPTIMALs
// Must happen after usage in the BLIT stage. // Must happen after usage in the BLIT stage.
@ -1824,9 +1894,9 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
VkImageMemoryBarrier2 afterBlitBarrier{}; VkImageMemoryBarrier2 afterBlitBarrier{};
afterBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; afterBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
afterBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT; afterBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT;
afterBlitBarrier.srcAccessMask = 0; afterBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT;
afterBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; afterBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
afterBlitBarrier.dstAccessMask = VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_2_SHADER_READ_BIT; afterBlitBarrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
afterBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; afterBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
afterBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; afterBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
afterBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; afterBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1851,10 +1921,10 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
// barrier: (mipLevels - 1) TRANSFER_DST_OPTIMAL -> SHADER_READ_ONLY_OPTIMAL // barrier: (mipLevels - 1) TRANSFER_DST_OPTIMAL -> SHADER_READ_ONLY_OPTIMAL
VkImageMemoryBarrier2 finalBlitBarrier{}; VkImageMemoryBarrier2 finalBlitBarrier{};
finalBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; finalBlitBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
finalBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_COPY_BIT; finalBlitBarrier.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT;
finalBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; finalBlitBarrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
finalBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; finalBlitBarrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
finalBlitBarrier.dstAccessMask = VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_2_SHADER_READ_BIT; finalBlitBarrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
finalBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; finalBlitBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
finalBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; finalBlitBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
finalBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; finalBlitBarrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
@ -1870,7 +1940,6 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
afterBlitDependency.imageMemoryBarrierCount = 1; afterBlitDependency.imageMemoryBarrierCount = 1;
afterBlitDependency.pImageMemoryBarriers = &finalBlitBarrier; afterBlitDependency.pImageMemoryBarriers = &finalBlitBarrier;
vkCmdPipelineBarrier2(commandBuffer, &afterBlitDependency); vkCmdPipelineBarrier2(commandBuffer, &afterBlitDependency);
} }
VKCHECK(vkEndCommandBuffer(commandBuffer)); VKCHECK(vkEndCommandBuffer(commandBuffer));
@ -1893,7 +1962,6 @@ gfx::Image* GFXDevice::CreateImageCubemap(uint32_t w, uint32_t h, gfx::ImageForm
return out; return out;
} }
void GFXDevice::DestroyImage(const gfx::Image* image) void GFXDevice::DestroyImage(const gfx::Image* image)
{ {
assert(image != nullptr); assert(image != nullptr);

View File

@ -26,13 +26,21 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
auto& binding1 = globalSetBindings.emplace_back(); auto& binding1 = globalSetBindings.emplace_back();
binding1.descriptor_type = gfx::DescriptorType::kCombinedImageSampler; binding1.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
binding1.stage_flags = gfx::ShaderStageFlags::kFragment; binding1.stage_flags = gfx::ShaderStageFlags::kFragment;
auto& binding2 = globalSetBindings.emplace_back();
binding2.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
binding2.stage_flags = gfx::ShaderStageFlags::kFragment;
} }
global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings); global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings);
global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout); global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout);
global_uniform.uniform_buffer_data.data = glm::mat4{1.0f}; global_uniform.uniform_buffer_data.data.proj = glm::mat4{1.0f};
const glm::vec3 light_location{ -0.4278, 0.7923, 0.43502 };
const glm::mat4 light_proj = glm::orthoRH_ZO(-32.0f, 32.0f, -32.0f, 32.0f, -100.0f, 100.0f);
const glm::mat4 light_view = glm::lookAtRH(light_location, glm::vec3{ 0.0f, 0.0f, 0.0f }, glm::vec3{ 0.0f, 0.0f, 1.0f });
global_uniform.uniform_buffer_data.data.lightSpaceMatrix = light_proj * light_view;
global_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data); global_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
device_->UpdateDescriptorUniformBuffer(global_uniform.set, 0, global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data)); device_->UpdateDescriptorUniformBuffer(global_uniform.set, 0, global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data));
// binding1 is updated towards the end of the constructor once the skybox texture is loaded // binding1 is updated towards the end of the constructor once the skybox texture is loaded
// binding2 is updated just after that
std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings; std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
{ {
@ -68,7 +76,7 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
debug_pipeline_info.frag_shader_path = GetResourcePath("engine/shaders/debug.frag"); debug_pipeline_info.frag_shader_path = GetResourcePath("engine/shaders/debug.frag");
debug_pipeline_info.vertex_format = debug_vertex_format; debug_pipeline_info.vertex_format = debug_vertex_format;
debug_pipeline_info.alpha_blending = false; debug_pipeline_info.alpha_blending = false;
debug_pipeline_info.backface_culling = false; // probably ignored for line rendering debug_pipeline_info.face_cull_mode = gfx::CullMode::kCullNone; // probably ignored for line rendering
debug_pipeline_info.write_z = false; // lines don't need the depth buffer debug_pipeline_info.write_z = false; // lines don't need the depth buffer
// debug_pipeline_info.descriptor_set_layouts = empty; // debug_pipeline_info.descriptor_set_layouts = empty;
debug_pipeline_info.line_primitives = true; debug_pipeline_info.line_primitives = true;
@ -76,7 +84,7 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
debug_rendering_things_.pipeline = device_->CreatePipeline(debug_pipeline_info); debug_rendering_things_.pipeline = device_->CreatePipeline(debug_pipeline_info);
} }
// create the skybox cubemap // create the skybox cubemap and update global skybox combined-image-sampler
{ {
constexpr uint32_t cubemap_w = 2048; constexpr uint32_t cubemap_w = 2048;
constexpr uint32_t cubemap_h = 2048; constexpr uint32_t cubemap_h = 2048;
@ -91,7 +99,6 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
face_unsafe_ptrs[face] = face_unq_ptrs[face]->data(); face_unsafe_ptrs[face] = face_unq_ptrs[face]->data();
} }
skybox_cubemap = device_->CreateImageCubemap(cubemap_w, cubemap_h, gfx::ImageFormat::kSRGB, face_unsafe_ptrs); skybox_cubemap = device_->CreateImageCubemap(cubemap_w, cubemap_h, gfx::ImageFormat::kSRGB, face_unsafe_ptrs);
gfx::SamplerInfo sampler_info{}; gfx::SamplerInfo sampler_info{};
sampler_info.magnify = gfx::Filter::kLinear; sampler_info.magnify = gfx::Filter::kLinear;
@ -102,6 +109,8 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
sampler_info.wrap_w = gfx::WrapMode::kClampToEdge; sampler_info.wrap_w = gfx::WrapMode::kClampToEdge;
sampler_info.anisotropic_filtering = true; sampler_info.anisotropic_filtering = true;
skybox_sampler = device_->CreateSampler(sampler_info); skybox_sampler = device_->CreateSampler(sampler_info);
device_->UpdateDescriptorCombinedImageSampler(global_uniform.set, 1, skybox_cubemap, skybox_sampler);
} }
// create skybox shader // create skybox shader
@ -115,15 +124,13 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
pipeline_info.frag_shader_path = GetResourcePath("engine/shaders/skybox.frag"); pipeline_info.frag_shader_path = GetResourcePath("engine/shaders/skybox.frag");
pipeline_info.vertex_format = vertex_format; pipeline_info.vertex_format = vertex_format;
pipeline_info.alpha_blending = false; pipeline_info.alpha_blending = false;
pipeline_info.backface_culling = true; pipeline_info.face_cull_mode = gfx::CullMode::kCullBack;
pipeline_info.write_z = false; pipeline_info.write_z = false;
pipeline_info.line_primitives = false; pipeline_info.line_primitives = false;
pipeline_info.descriptor_set_layouts.push_back(GetGlobalSetLayout()); pipeline_info.descriptor_set_layouts.push_back(GetGlobalSetLayout());
pipeline_info.descriptor_set_layouts.push_back(GetFrameSetLayout()); pipeline_info.descriptor_set_layouts.push_back(GetFrameSetLayout());
skybox_pipeline = device_->CreatePipeline(pipeline_info); skybox_pipeline = device_->CreatePipeline(pipeline_info);
device_->UpdateDescriptorCombinedImageSampler(global_uniform.set, 1, skybox_cubemap, skybox_sampler);
} }
// create skybox vertex buffer // create skybox vertex buffer
@ -136,40 +143,40 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
v.push_back({2.0f, 0.0f, 2.0f}); v.push_back({2.0f, 0.0f, 2.0f});
v.push_back({0.0f, 0.0f, 2.0f}); v.push_back({0.0f, 0.0f, 2.0f});
// back // back
v.push_back({2.0f, 2.0f, 2.0f }); v.push_back({2.0f, 2.0f, 2.0f});
v.push_back({ 2.0f, 2.0f, 0.0f}); v.push_back({2.0f, 2.0f, 0.0f});
v.push_back({0.0f, 2.0f, 0.0f}); v.push_back({0.0f, 2.0f, 0.0f});
v.push_back({0.0f, 2.0f, 0.0f}); v.push_back({0.0f, 2.0f, 0.0f});
v.push_back({0.0f, 2.0f, 2.0f }); v.push_back({0.0f, 2.0f, 2.0f});
v.push_back({ 2.0f, 2.0f, 2.0f }); v.push_back({2.0f, 2.0f, 2.0f});
// left // left
v.push_back({0.0f, 2.0f, 2.0f }); v.push_back({0.0f, 2.0f, 2.0f});
v.push_back({0.0f, 2.0f, 0.0f}); v.push_back({0.0f, 2.0f, 0.0f});
v.push_back({0.0f, 0.0f, 0.0f}); v.push_back({0.0f, 0.0f, 0.0f});
v.push_back({0.0f, 0.0f, 0.0f}); v.push_back({0.0f, 0.0f, 0.0f});
v.push_back({0.0f, 0.0f, 2.0f }); v.push_back({0.0f, 0.0f, 2.0f});
v.push_back({0.0f, 2.0f, 2.0f }); v.push_back({0.0f, 2.0f, 2.0f});
// right // right
v.push_back({ 2.0f, 0.0f, 2.0f }); v.push_back({2.0f, 0.0f, 2.0f});
v.push_back({ 2.0f, 0.0f, 0.0f}); v.push_back({2.0f, 0.0f, 0.0f});
v.push_back({ 2.0f, 2.0f, 0.0f}); v.push_back({2.0f, 2.0f, 0.0f});
v.push_back({ 2.0f, 2.0f, 0.0f}); v.push_back({2.0f, 2.0f, 0.0f});
v.push_back({ 2.0f, 2.0f, 2.0f }); v.push_back({2.0f, 2.0f, 2.0f});
v.push_back({ 2.0f, 0.0f, 2.0f }); v.push_back({2.0f, 0.0f, 2.0f});
// top // top
v.push_back({0.0f, 2.0f, 2.0f }); v.push_back({0.0f, 2.0f, 2.0f});
v.push_back({0.0f, 0.0f, 2.0f }); v.push_back({0.0f, 0.0f, 2.0f});
v.push_back({ 2.0f, 0.0f, 2.0f }); v.push_back({2.0f, 0.0f, 2.0f});
v.push_back({ 2.0f, 0.0f, 2.0f }); v.push_back({2.0f, 0.0f, 2.0f});
v.push_back({ 2.0f, 2.0f, 2.0f }); v.push_back({2.0f, 2.0f, 2.0f});
v.push_back({0.0f, 2.0f, 2.0f }); v.push_back({0.0f, 2.0f, 2.0f});
// bottom // bottom
v.push_back({ 2.0f, 2.0f, 0.0f}); v.push_back({2.0f, 2.0f, 0.0f});
v.push_back({ 2.0f, 0.0f, 0.0f}); v.push_back({2.0f, 0.0f, 0.0f});
v.push_back({0.0f, 0.0f, 0.0f}); v.push_back({0.0f, 0.0f, 0.0f});
v.push_back({0.0f, 0.0f, 0.0f}); v.push_back({0.0f, 0.0f, 0.0f});
v.push_back({0.0f, 2.0f, 0.0f}); v.push_back({0.0f, 2.0f, 0.0f});
v.push_back({ 2.0f, 2.0f, 0.0f}); v.push_back({2.0f, 2.0f, 0.0f});
for (glm::vec3& pos : v) { for (glm::vec3& pos : v) {
pos.x -= 1.0f; pos.x -= 1.0f;
pos.y -= 1.0f; pos.y -= 1.0f;
@ -181,10 +188,31 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
skybox_buffer = device_->CreateBuffer(gfx::BufferType::kVertex, v.size() * sizeof(glm::vec3), v.data()); skybox_buffer = device_->CreateBuffer(gfx::BufferType::kVertex, v.size() * sizeof(glm::vec3), v.data());
} }
// shadow mapping...
{
int w{}, h{};
auto shadowmap_image = util::ReadImageFile(GetResourcePath("textures/shadow_map.png"), w, h);
shadow_map = device_->CreateImage(w, h, gfx::ImageFormat::kLinear, shadowmap_image->data());
gfx::SamplerInfo sampler_info{};
sampler_info.magnify = gfx::Filter::kLinear;
sampler_info.minify = gfx::Filter::kLinear;
sampler_info.mipmap = gfx::Filter::kLinear; // trilinear is apparently good for shadow maps
sampler_info.wrap_u = gfx::WrapMode::kClampToEdge;
sampler_info.wrap_v = gfx::WrapMode::kClampToEdge;
sampler_info.wrap_w = gfx::WrapMode::kClampToEdge;
sampler_info.anisotropic_filtering = false; // Copilot says not to use aniso for shadow maps
shadow_map_sampler = device_->CreateSampler(sampler_info);
device_->UpdateDescriptorCombinedImageSampler(global_uniform.set, 2, shadow_map, shadow_map_sampler);
}
}; };
Renderer::~Renderer() Renderer::~Renderer()
{ {
device_->DestroySampler(shadow_map_sampler);
device_->DestroyImage(shadow_map);
device_->DestroyBuffer(skybox_buffer); device_->DestroyBuffer(skybox_buffer);
device_->DestroyPipeline(skybox_pipeline); device_->DestroyPipeline(skybox_pipeline);
device_->DestroySampler(skybox_sampler); device_->DestroySampler(skybox_sampler);
@ -213,15 +241,19 @@ void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform)
const glm::mat4 proj_matrix = const glm::mat4 proj_matrix =
glm::perspectiveRH_ZO(camera_settings_.vertical_fov_radians, viewport_aspect_ratio_, camera_settings_.clip_near, camera_settings_.clip_far); glm::perspectiveRH_ZO(camera_settings_.vertical_fov_radians, viewport_aspect_ratio_, camera_settings_.clip_near, camera_settings_.clip_far);
/* update SET 0 (rarely changing uniforms)*/ /* update SET 0 (rarely changing uniforms)*/
global_uniform.uniform_buffer_data.data = proj_matrix; global_uniform.uniform_buffer_data.data.proj = proj_matrix;
device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data); device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
} }
// set camera view matrix uniform
/* update SET 1 (per frame uniforms) */
const glm::mat4 view_matrix = glm::inverse(camera_transform); const glm::mat4 view_matrix = glm::inverse(camera_transform);
frame_uniform.uniform_buffer_data.data = view_matrix; frame_uniform.uniform_buffer_data.data = view_matrix;
device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data); device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
// override with light matrix
frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
global_uniform.uniform_buffer_data.data.proj = global_uniform.uniform_buffer_data.data.lightSpaceMatrix;
device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
} }
void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_list, const std::vector<Line>& debug_lines) void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_list, const std::vector<Line>& debug_lines)
@ -260,8 +292,8 @@ void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_l
device_->CmdBindPipeline(draw_buffer, debug_rendering_things_.pipeline); device_->CmdBindPipeline(draw_buffer, debug_rendering_things_.pipeline);
DebugPush push{}; DebugPush push{};
for (const Line& l : debug_lines) { for (const Line& l : debug_lines) {
push.pos1 = global_uniform.uniform_buffer_data.data * frame_uniform.uniform_buffer_data.data * glm::vec4(l.pos1, 1.0f); push.pos1 = global_uniform.uniform_buffer_data.data.proj * frame_uniform.uniform_buffer_data.data * glm::vec4(l.pos1, 1.0f);
push.pos2 = global_uniform.uniform_buffer_data.data * frame_uniform.uniform_buffer_data.data * glm::vec4(l.pos2, 1.0f); push.pos2 = global_uniform.uniform_buffer_data.data.proj * frame_uniform.uniform_buffer_data.data * glm::vec4(l.pos2, 1.0f);
push.color = l.color; push.color = l.color;
device_->CmdPushConstants(draw_buffer, debug_rendering_things_.pipeline, 0, sizeof(DebugPush), &push); device_->CmdPushConstants(draw_buffer, debug_rendering_things_.pipeline, 0, sizeof(DebugPush), &push);
device_->CmdDraw(draw_buffer, 2, 1, 0, 0); device_->CmdDraw(draw_buffer, 2, 1, 0, 0);

View File

@ -48,7 +48,7 @@ Shader::Shader(Renderer* renderer, const std::string& vertPath, const std::strin
info.frag_shader_path = fragPath; info.frag_shader_path = fragPath;
info.vertex_format = vertFormat; info.vertex_format = vertFormat;
info.alpha_blending = settings.alpha_blending; info.alpha_blending = settings.alpha_blending;
info.backface_culling = settings.cull_backface; info.face_cull_mode = settings.cull_backface ? gfx::CullMode::kCullBack : gfx::CullMode::kCullNone;
info.write_z = settings.write_z; info.write_z = settings.write_z;
info.line_primitives = false; info.line_primitives = false;
info.descriptor_set_layouts.push_back(renderer->GetGlobalSetLayout()); info.descriptor_set_layouts.push_back(renderer->GetGlobalSetLayout());

View File

@ -555,12 +555,12 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
// get AABB // get AABB
AABB box{}; AABB box{};
box.min.x = pos_accessor.minValues.at(0); box.min.x = static_cast<float>(pos_accessor.minValues.at(0));
box.min.y = pos_accessor.minValues.at(1); box.min.y = static_cast<float>(pos_accessor.minValues.at(1));
box.min.z = pos_accessor.minValues.at(2); box.min.z = static_cast<float>(pos_accessor.minValues.at(2));
box.max.x = pos_accessor.maxValues.at(0); box.max.x = static_cast<float>(pos_accessor.maxValues.at(0));
box.max.y = pos_accessor.maxValues.at(1); box.max.y = static_cast<float>(pos_accessor.maxValues.at(1));
box.max.z = pos_accessor.maxValues.at(2); box.max.z = static_cast<float>(pos_accessor.maxValues.at(2));
primitive_array.emplace_back(engine_mesh, engine_material, box); primitive_array.emplace_back(engine_mesh, engine_material, box);
} }

View File

@ -204,17 +204,17 @@ namespace engine {
.srcStageMask = VK_PIPELINE_STAGE_NONE, .srcStageMask = VK_PIPELINE_STAGE_NONE,
.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
.srcAccessMask = 0, .srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0, .dependencyFlags = 0,
}, },
{ {
// Image Layout Transition // Image Layout Transition
.srcSubpass = VK_SUBPASS_EXTERNAL, .srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0, .dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_NONE, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0, .srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0, .dependencyFlags = 0,
}, },
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 KiB

View File

@ -89,7 +89,7 @@ void PlayGame(GameSettings settings)
/* floor */ /* floor */
engine::Entity floor = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/floor.glb")); engine::Entity floor = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/floor.glb"));
main_scene->GetComponent<engine::MeshRenderableComponent>(main_scene->GetEntity("Cube", floor))->visible = false; //main_scene->GetComponent<engine::MeshRenderableComponent>(main_scene->GetEntity("Cube", floor))->visible = false;
engine::Entity monke = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/monke.glb")); engine::Entity monke = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/monke.glb"));
main_scene->GetComponent<engine::TransformComponent>(monke)->position.y += 10.0f; main_scene->GetComponent<engine::TransformComponent>(monke)->position.y += 10.0f;