Mipmapping implemented.

This commit is contained in:
Anish Bhobe 2025-06-15 22:09:08 +02:00
parent 98c5f28146
commit 6da0250c81
5 changed files with 295 additions and 80 deletions

View File

@ -70,10 +70,14 @@ SDL_AppResult SDL_AppIterate( void* appstate )
SDL_SetWindowTitle( appState.window, appState.sprintfBuffer );
}
misc.cameraData.modelMatrix = DirectX::XMMatrixMultiply(
misc.cameraData.modelMatrix,
DirectX::XMMatrixRotationY( DirectX::XMConvertToRadians( 60.0f ) * static_cast<float>( deltaTime ) ) );
memcpy( misc.cameraUniformBufferPtr, &misc.cameraData, sizeof misc.cameraData );
for ( Transform& transform : misc.modelTransform )
{
transform.rotation = DirectX::XMQuaternionMultiply(
DirectX::XMQuaternionRotationAxis(
DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ),
DirectX::XMConvertToRadians( 60.0f ) * static_cast<float>( deltaTime ) ),
transform.rotation );
}
uint32_t currentImageIndex;
VK_CHECK( vkAcquireNextImageKHR(
@ -155,8 +159,21 @@ SDL_AppResult SDL_AppIterate( void* appstate )
vkCmdBindVertexBuffers( cmd, 0, 1, &misc.vertexBuffer, &offset );
vkCmdBindDescriptorSets(
cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, misc.pipelineLayout, 0, 1, &misc.descriptorSet, 0, nullptr );
for ( Transform& localTransform : misc.modelTransform )
{
DirectX::XMMATRIX worldTransform;
{
auto [x, y, z] = localTransform.position;
auto scale = localTransform.scale;
worldTransform = DirectX::XMMatrixScaling( scale, scale, scale ) *
DirectX::XMMatrixRotationQuaternion( localTransform.rotation ) *
DirectX::XMMatrixTranslation( x, y, z );
}
vkCmdPushConstants(
cmd, misc.pipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, sizeof worldTransform, &worldTransform );
vkCmdDraw( cmd, static_cast<uint32_t>( misc.vertices.size() ), 1, 0, 0 );
}
}
vkCmdEndRendering( cmd );
vkCmdPipelineBarrier2( cmd, &misc.renderToPresentDependency );
}

View File

@ -103,13 +103,13 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>EnableAllWarnings</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<TreatWarningAsError>false</TreatWarningAsError>
<TreatWarningAsError>true</TreatWarningAsError>
<ExceptionHandling>Sync</ExceptionHandling>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
@ -124,7 +124,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>EnableAllWarnings</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
@ -132,7 +132,7 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<TreatWarningAsError>false</TreatWarningAsError>
<TreatWarningAsError>true</TreatWarningAsError>
<ExceptionHandling>/EH-</ExceptionHandling>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>

View File

@ -1,12 +1,12 @@
struct VertexOut {
float4 outPosition : SV_Position;
float4 screenPosition : ScreenPosition;
float4 vertexColor : CoarseColor;
float2 texCoord0 : TexCoord0;
};
struct CameraData {
float4x4 model;
float4x4 view;
float4x4 proj;
};
@ -18,6 +18,13 @@ struct PerFrameData {
ParameterBlock<PerFrameData> perFrameData;
struct PerInstanceData {
float4x4 transform;
}
[[vk::push_constant]]
uniform ConstantBuffer<PerInstanceData> pcb;
[shader("vertex")]
VertexOut VertexMain(
uint vertexId: SV_VertexID,
@ -26,7 +33,8 @@ VertexOut VertexMain(
float2 texCoord0,
) {
VertexOut output;
output.outPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(perFrameData.camera.model, float4(position, 1.0f))));
output.outPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(pcb.transform, float4(position, 1.0f))));
output.screenPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(pcb.transform, float4(position, 1.0f))));
output.vertexColor = float4(color, 1.0f);
output.texCoord0 = texCoord0 * 2.0f;
return output;
@ -34,9 +42,16 @@ VertexOut VertexMain(
[shader("fragment")]
float4 FragmentMain(
float4 interpolatePosition : ScreenPosition,
float4 interpolatedColors : CoarseColor,
float2 uv0 : TexCoord0,
) : SV_Target0 {
return float4(perFrameData.texture.Sample(uv0).rgb, 1.0f) * interpolatedColors;
float4 outColor;
if (interpolatePosition.x < 0) {
outColor = float4(perFrameData.texture.SampleLevel(uv0, 0).rgb, 1.0f) * interpolatedColors;
} else {
outColor = float4(perFrameData.texture.Sample(uv0).rgb, 1.0f) * interpolatedColors;
}
return outColor;
}

View File

@ -67,14 +67,20 @@ bool MiscData::init( RenderDevice const& renderDevice )
};
VK_CHECK( vkCreateDescriptorSetLayout( device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout ) );
VkPushConstantRange const pushConstantRange = {
.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS,
.offset = 0,
.size = sizeof( DirectX::XMMATRIX ),
};
VkPipelineLayoutCreateInfo const pipelineLayoutCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.setLayoutCount = 1,
.pSetLayouts = &descriptorSetLayout,
.pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &pushConstantRange,
};
VK_CHECK( vkCreatePipelineLayout( device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout ) );
@ -228,7 +234,7 @@ bool MiscData::init( RenderDevice const& renderDevice )
.blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f },
};
std::array constexpr dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
std::array constexpr dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo const dynamicStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
@ -378,6 +384,10 @@ bool MiscData::init( RenderDevice const& renderDevice )
height = static_cast<uint32_t>( h );
}
// Calculate mips
uint32_t mipLevels =
1 + static_cast<uint32_t>( floorf( log2f( static_cast<float>( std::max( width, height ) ) ) ) );
VkImageCreateInfo const imageCreateInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
@ -385,11 +395,11 @@ bool MiscData::init( RenderDevice const& renderDevice )
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_SRGB,
.extent = { .width = width, .height = height, .depth = 1 },
.mipLevels = 1,
.mipLevels = mipLevels,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@ -410,10 +420,10 @@ bool MiscData::init( RenderDevice const& renderDevice )
VK_CHECK( vmaCreateImage(
renderDevice.gpuAllocator, &imageCreateInfo, &allocationCreateInfo, &texture, &textureAllocation, nullptr ) );
VkImageSubresourceRange constexpr subresourceRange = {
VkImageSubresourceRange const subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.levelCount = mipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
};
@ -454,7 +464,7 @@ bool MiscData::init( RenderDevice const& renderDevice )
.compareEnable = false,
.compareOp = VK_COMPARE_OP_NEVER,
.minLod = 0.0f,
.maxLod = 0.0f,
.maxLod = VK_LOD_CLAMP_NONE,
.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
.unnormalizedCoordinates = false,
};
@ -506,6 +516,7 @@ bool MiscData::init( RenderDevice const& renderDevice )
// All data is copied to stagingBuffer, don't need this.
stbi_image_free( textureData );
// Staging -> Texture transfer
{
Frame& frameInUse = renderDevice.frames[0];
@ -547,10 +558,32 @@ bool MiscData::init( RenderDevice const& renderDevice )
.pImageMemoryBarriers = &creationToTransferImageBarrier,
};
VkImageMemoryBarrier2 const transferToReadyImageBarrier = {
std::array transferToReadyImageBarriers{
// transferToReadyImageBarrier
VkImageMemoryBarrier2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.pNext = nullptr,
.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT,
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = texture,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = mipLevels-1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
VkImageMemoryBarrier2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.pNext = nullptr,
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
@ -559,7 +592,14 @@ bool MiscData::init( RenderDevice const& renderDevice )
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = texture,
.subresourceRange = subresourceRange,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = mipLevels-1,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}
};
VkDependencyInfo const transferToReadyDependency = {
@ -570,10 +610,64 @@ bool MiscData::init( RenderDevice const& renderDevice )
.pMemoryBarriers = nullptr,
.bufferMemoryBarrierCount = 0,
.pBufferMemoryBarriers = nullptr,
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &transferToReadyImageBarrier,
.imageMemoryBarrierCount = static_cast<uint32_t>( transferToReadyImageBarriers.size() ),
.pImageMemoryBarriers = transferToReadyImageBarriers.data(),
};
VkImageSubresourceRange const mipLevelSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
std::array prepareNextMipLevelBarriers{
// prepareNextMipLevelSrcImageBarrier
VkImageMemoryBarrier2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.pNext = nullptr,
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = texture,
.subresourceRange = mipLevelSubresource,
},
// prepareNextMipLevelDstImageBarrier
VkImageMemoryBarrier2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.pNext = nullptr,
.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT,
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT,
.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = texture,
.subresourceRange = mipLevelSubresource,
}
};
VkDependencyInfo const prepareNextMipLevelDependency = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.pNext = nullptr,
.dependencyFlags = 0,
.memoryBarrierCount = 0,
.pMemoryBarriers = nullptr,
.bufferMemoryBarrierCount = 0,
.pBufferMemoryBarriers = nullptr,
.imageMemoryBarrierCount = static_cast<uint32_t>( prepareNextMipLevelBarriers.size() ),
.pImageMemoryBarriers = prepareNextMipLevelBarriers.data(),
};
vkBeginCommandBuffer( frameInUse.commandBuffer, &beginInfo );
{
VkImageSubresourceLayers imageSubresourceLayers = {
@ -593,11 +687,82 @@ bool MiscData::init( RenderDevice const& renderDevice )
.imageExtent = imageCreateInfo.extent
};
// Start
vkCmdPipelineBarrier2( frameInUse.commandBuffer, &creationToTransferDependency );
// Staging -> Image L0
vkCmdCopyBufferToImage(
frameInUse.commandBuffer, stagingBuffer, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion );
prepareNextMipLevelBarriers[0].subresourceRange.baseMipLevel = 0;
prepareNextMipLevelBarriers[1].subresourceRange.baseMipLevel = 1;
int32_t mipSrcWidth = static_cast<int32_t>( width );
int32_t mipSrcHeight = static_cast<int32_t>( height );
int32_t mipDstWidth = std::max( mipSrcWidth / 2, 1 );
int32_t mipDstHeight = std::max( mipSrcHeight / 2, 1 );
VkImageSubresourceLayers constexpr mipSubresourceLayers = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
};
VkImageBlit2 imageBlit = {
.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
.pNext = nullptr,
.srcSubresource = mipSubresourceLayers,
.srcOffsets = { { 0, 0, 0 }, { mipSrcWidth, mipSrcHeight, 1 } },
.dstSubresource = mipSubresourceLayers,
.dstOffsets = { { 0, 0, 0 }, { mipDstWidth, mipDstHeight, 1 } },
};
imageBlit.srcSubresource.mipLevel = 0;
imageBlit.dstSubresource.mipLevel = 1;
imageBlit.srcOffsets[1].x = mipSrcWidth;
imageBlit.srcOffsets[1].y = mipSrcHeight;
imageBlit.dstOffsets[1].x = mipDstWidth;
imageBlit.dstOffsets[1].y = mipDstHeight;
VkBlitImageInfo2 blitInfo = {
.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
.pNext = nullptr,
.srcImage = texture,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstImage = texture,
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.regionCount = 1,
.pRegions = &imageBlit,
.filter = VK_FILTER_LINEAR,
};
// MipMapping
for ( uint32_t dstMipLevel = 1; dstMipLevel < mipLevels; ++dstMipLevel )
{
vkCmdPipelineBarrier2( frameInUse.commandBuffer, &prepareNextMipLevelDependency );
vkCmdBlitImage2( frameInUse.commandBuffer, &blitInfo );
// Prep for NEXT iteration
mipSrcWidth = mipDstWidth;
mipSrcHeight = mipDstHeight;
mipDstWidth = std::max( mipSrcWidth / 2, 1 );
mipDstHeight = std::max( mipSrcHeight / 2, 1 );
imageBlit.srcSubresource.mipLevel = dstMipLevel;
imageBlit.dstSubresource.mipLevel = dstMipLevel + 1;
imageBlit.srcOffsets[1].x = mipSrcWidth;
imageBlit.srcOffsets[1].y = mipSrcHeight;
imageBlit.dstOffsets[1].x = mipDstWidth;
imageBlit.dstOffsets[1].y = mipDstHeight;
// Prep current mip level as source
prepareNextMipLevelBarriers[0].subresourceRange.baseMipLevel = dstMipLevel;
prepareNextMipLevelBarriers[1].subresourceRange.baseMipLevel = dstMipLevel + 1;
}
// End
vkCmdPipelineBarrier2( frameInUse.commandBuffer, &transferToReadyDependency );
}
vkEndCommandBuffer( frameInUse.commandBuffer );
@ -622,12 +787,22 @@ bool MiscData::init( RenderDevice const& renderDevice )
vmaDestroyBuffer( renderDevice.gpuAllocator, stagingBuffer, stagingAllocation );
}
// Model Setup
modelTransform[0].position = { 1.0f, 0.0f, 0.0f };
modelTransform[0].scale = 1.0f;
modelTransform[0].rotation =
DirectX::XMQuaternionRotationAxis( DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ), 0.0f );
modelTransform[1].position = { -1.0f, 0.0f, 0.0f };
modelTransform[1].scale = 1.0f;
modelTransform[1].rotation =
DirectX::XMQuaternionRotationAxis( DirectX::XMVectorSet( 1.0f, 0.0f, 0.0f, 0.0f ), 0.0f );
// Camera
{
cameraPosition = DirectX::XMVectorSet( 0.0f, 0.0f, -5.0f, 1.0f );
cameraPosition = DirectX::XMVectorSet( 0.0f, 0.0f, -4.0f, 1.0f );
cameraTarget = DirectX::XMVectorSet( 0.0f, 0.0f, 0.0f, 1.0f );
cameraUp = DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 1.0f );
cameraData.modelMatrix = DirectX::XMMatrixIdentity();
cameraData.viewMatrix = DirectX::XMMatrixLookAtLH( cameraPosition, cameraTarget, cameraUp );
cameraData.projectionMatrix =
DirectX::XMMatrixPerspectiveFovLH( DirectX::XMConvertToRadians( 70.0f ), 16.0f / 9.0f, 0.1f, 1000.0f );

View File

@ -17,11 +17,17 @@ struct Vertex
DirectX::XMFLOAT2 texCoord0;
};
struct Transform
{
DirectX::XMFLOAT3 position;
float scale;
DirectX::XMVECTOR rotation;
};
struct MiscData
{
struct CameraData
{
DirectX::XMMATRIX modelMatrix;
DirectX::XMMATRIX viewMatrix;
DirectX::XMMATRIX projectionMatrix;
};
@ -44,6 +50,8 @@ struct MiscData
uint64_t _padding; // TODO: Optimize out?
std::array<Transform, 2> modelTransform;
DirectX::XMVECTOR cameraPosition;
DirectX::XMVECTOR cameraTarget;
DirectX::XMVECTOR cameraUp;