separate samplers and sampled images

This commit is contained in:
Zack Buhman 2026-04-11 13:22:27 -05:00
parent 466c7b030e
commit 1456e04200
2 changed files with 114 additions and 27 deletions

View File

@ -24,8 +24,15 @@ struct ShaderData
[[vk::binding(0, 0)]] ConstantBuffer<ShaderData> data; [[vk::binding(0, 0)]] ConstantBuffer<ShaderData> data;
[[vk::binding(0, 1)]] SamplerState samplers[]; [[vk::binding(0, 1)]] SamplerState samplers[2];
[[vk::binding(0, 1)]] Texture2D textures[]; [[vk::binding(1, 1)]] Texture2D texture;
struct PushConstant {
int SamplerIndex;
};
[[vk::push_constant]]
struct PushConstant constants;
[shader("vertex")] [shader("vertex")]
VSOutput VSMain(VSInput input) VSOutput VSMain(VSInput input)
@ -45,7 +52,7 @@ VSOutput VSMain(VSInput input)
[shader("pixel")] [shader("pixel")]
float4 PSMain(VSOutput input) : SV_TARGET float4 PSMain(VSOutput input) : SV_TARGET
{ {
float3 color = textures[0].Sample(samplers[0], input.Texture).bgr; float3 color = texture.Sample(samplers[constants.SamplerIndex], input.Texture).bgr;
float3 N = normalize(input.Normal); float3 N = normalize(input.Normal);
float3 L = normalize(input.LightDirection); float3 L = normalize(input.LightDirection);

View File

@ -121,7 +121,7 @@ VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
VkImage textureImage{ VK_NULL_HANDLE }; VkImage textureImage{ VK_NULL_HANDLE };
VkImageView textureImageView{ VK_NULL_HANDLE }; VkImageView textureImageView{ VK_NULL_HANDLE };
VkDeviceMemory textureImageMemory{ VK_NULL_HANDLE }; VkDeviceMemory textureImageMemory{ VK_NULL_HANDLE };
VkSampler textureSampler{ VK_NULL_HANDLE }; VkSampler textureSamplers[3]{ VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE };
VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; VkDescriptorPool descriptorPool{ VK_NULL_HANDLE };
VkDescriptorSetLayout uniformBufferDescriptorSetLayout{ VK_NULL_HANDLE }; VkDescriptorSetLayout uniformBufferDescriptorSetLayout{ VK_NULL_HANDLE };
@ -398,6 +398,10 @@ VkDeviceSize allocateFromMemoryRequirements(VkPhysicalDeviceMemoryProperties2 co
return stride; return stride;
} }
inline static int positive_modulo(int i, unsigned int n) {
return (i % n + n) % n;
}
int main() int main()
{ {
SDL_CHECK(SDL_Init(SDL_INIT_VIDEO)); SDL_CHECK(SDL_Init(SDL_INIT_VIDEO));
@ -892,7 +896,29 @@ int main()
// texture sampler // texture sampler
VkSamplerCreateInfo samplerCreateInfo{ VkSamplerCreateInfo samplerCreateInfo0{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.anisotropyEnable = VK_FALSE,
.maxLod = 0.0, // (float)ddsFile->header.dwMipMapCount
};
VK_CHECK(vkCreateSampler(device, &samplerCreateInfo0, nullptr, &textureSamplers[0]));
VkSamplerCreateInfo samplerCreateInfo1{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.anisotropyEnable = VK_FALSE,
.maxLod = VK_LOD_CLAMP_NONE, // (float)ddsFile->header.dwMipMapCount,
};
VK_CHECK(vkCreateSampler(device, &samplerCreateInfo1, nullptr, &textureSamplers[1]));
VkSamplerCreateInfo samplerCreateInfo2{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR, .magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR, .minFilter = VK_FILTER_LINEAR,
@ -901,9 +927,9 @@ int main()
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.anisotropyEnable = VK_TRUE, .anisotropyEnable = VK_TRUE,
.maxAnisotropy = 16.0f, .maxAnisotropy = 16.0f,
.maxLod = (float)ddsFile->header.dwMipMapCount, .maxLod = VK_LOD_CLAMP_NONE, // (float)ddsFile->header.dwMipMapCount,
}; };
VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &textureSampler)); VK_CHECK(vkCreateSampler(device, &samplerCreateInfo2, nullptr, &textureSamplers[2]));
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// descriptors // descriptors
@ -913,9 +939,13 @@ int main()
// pool // pool
// //
VkDescriptorPoolSize descriptorPoolSizes[2]{ VkDescriptorPoolSize descriptorPoolSizes[3]{
{ {
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .type = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = 3,
},
{
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1, .descriptorCount = 1,
}, },
{ {
@ -926,7 +956,7 @@ int main()
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = 3, .maxSets = 3,
.poolSizeCount = 2, .poolSizeCount = 3,
.pPoolSizes = descriptorPoolSizes .pPoolSizes = descriptorPoolSizes
}; };
VK_CHECK(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool)); VK_CHECK(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
@ -966,17 +996,25 @@ int main()
// texture descriptor set layout/allocation // texture descriptor set layout/allocation
// //
VkDescriptorSetLayoutBinding textureDescriptorSetLayoutBinding{ VkDescriptorSetLayoutBinding textureDescriptorSetLayoutBindings[2]{
.binding = 0, {
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .binding = 0,
.descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT .descriptorCount = 3,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
}
}; };
VkDescriptorSetLayoutCreateInfo textureDescriptorSetLayoutCreateInfo{ VkDescriptorSetLayoutCreateInfo textureDescriptorSetLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1, .bindingCount = 2,
.pBindings = &textureDescriptorSetLayoutBinding .pBindings = textureDescriptorSetLayoutBindings
}; };
VK_CHECK(vkCreateDescriptorSetLayout(device, &textureDescriptorSetLayoutCreateInfo, nullptr, &textureDescriptorSetLayout)); VK_CHECK(vkCreateDescriptorSetLayout(device, &textureDescriptorSetLayoutCreateInfo, nullptr, &textureDescriptorSetLayout));
@ -992,22 +1030,39 @@ int main()
// descriptor set writes // descriptor set writes
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
constexpr int writeDescriptorSetsCount = 1 + maxFramesInFlight; constexpr int writeDescriptorSetsCount = 2 + maxFramesInFlight;
VkWriteDescriptorSet writeDescriptorSets[writeDescriptorSetsCount]; VkWriteDescriptorSet writeDescriptorSets[writeDescriptorSetsCount];
VkDescriptorImageInfo textureDescriptorImageInfo = { VkDescriptorImageInfo textureSamplerDescriptorImageInfos[3] = {
.sampler = textureSampler, {
.imageView = textureImageView, .sampler = textureSamplers[0],
.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL },
{
.sampler = textureSamplers[1],
},
{
.sampler = textureSamplers[2],
},
}; };
writeDescriptorSets[0] = { writeDescriptorSets[0] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = textureDescriptorSet, .dstSet = textureDescriptorSet,
.dstBinding = 0, .dstBinding = 0,
.descriptorCount = 3,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.pImageInfo = textureSamplerDescriptorImageInfos
};
VkDescriptorImageInfo textureImageDescriptorImageInfo = {
.imageView = textureImageView,
.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL
};
writeDescriptorSets[1] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = textureDescriptorSet,
.dstBinding = 1,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = &textureDescriptorImageInfo .pImageInfo = &textureImageDescriptorImageInfo
}; };
for (uint32_t i = 0; i < maxFramesInFlight; i++) { for (uint32_t i = 0; i < maxFramesInFlight; i++) {
@ -1017,7 +1072,7 @@ int main()
.range = VK_WHOLE_SIZE, .range = VK_WHOLE_SIZE,
}; };
writeDescriptorSets[1 + i] = { writeDescriptorSets[2 + i] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = uniformBufferDescriptorSets[i], .dstSet = uniformBufferDescriptorSets[i],
.dstBinding = 0, .dstBinding = 0,
@ -1054,10 +1109,17 @@ int main()
textureDescriptorSetLayout, textureDescriptorSetLayout,
}; };
VkPushConstantRange pushConstantRange{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.size = (sizeof (int32_t))
};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{ VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 2, .setLayoutCount = 2,
.pSetLayouts = descriptorSetLayouts, .pSetLayouts = descriptorSetLayouts,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &pushConstantRange
}; };
VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
@ -1236,6 +1298,7 @@ int main()
uint32_t frameIndex{ 0 }; uint32_t frameIndex{ 0 };
uint32_t imageIndex{ 0 }; uint32_t imageIndex{ 0 };
bool quit{ false }; bool quit{ false };
int32_t samplerIndex{ 0 };
while (quit == false) { while (quit == false) {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
@ -1246,6 +1309,20 @@ int main()
if (event.key.key == SDLK_ESCAPE) { if (event.key.key == SDLK_ESCAPE) {
quit = true; quit = true;
} }
if (!event.key.repeat) {
switch (event.key.key) {
case SDLK_LEFT:
samplerIndex = positive_modulo(samplerIndex - 1, 3);
printf("samplerIndex: %d\n", samplerIndex);
break;
case SDLK_RIGHT:
samplerIndex = positive_modulo(samplerIndex + 1, 3);
printf("samplerIndex: %d\n", samplerIndex);
break;
default:
break;
}
}
} }
if (event.type == SDL_EVENT_WINDOW_RESIZED) { if (event.type == SDL_EVENT_WINDOW_RESIZED) {
SDL_CHECK(SDL_GetWindowSize(window, &windowSize.x, &windowSize.y)); SDL_CHECK(SDL_GetWindowSize(window, &windowSize.x, &windowSize.y));
@ -1378,6 +1455,7 @@ int main()
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndexBuffer, &vertexOffset); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndexBuffer, &vertexOffset);
VkDeviceSize indexOffset{ vertexBufferSize }; VkDeviceSize indexOffset{ vertexBufferSize };
vkCmdBindIndexBuffer(commandBuffer, vertexIndexBuffer, indexOffset, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(commandBuffer, vertexIndexBuffer, indexOffset, VK_INDEX_TYPE_UINT32);
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, (sizeof (int32_t)), &samplerIndex);
VkDeviceSize indexCount{ 2400 }; VkDeviceSize indexCount{ 2400 };
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[MAIN_PIPELINE]); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[MAIN_PIPELINE]);
@ -1469,7 +1547,9 @@ int main()
vkFreeMemory(device, vertexIndexBufferMemory, nullptr); vkFreeMemory(device, vertexIndexBufferMemory, nullptr);
vkDestroyImageView(device, textureImageView, nullptr); vkDestroyImageView(device, textureImageView, nullptr);
vkDestroySampler(device, textureSampler, nullptr); vkDestroySampler(device, textureSamplers[0], nullptr);
vkDestroySampler(device, textureSamplers[1], nullptr);
vkDestroySampler(device, textureSamplers[2], nullptr);
vkDestroyImage(device, textureImage, nullptr); vkDestroyImage(device, textureImage, nullptr);
vkFreeMemory(device, textureImageMemory, nullptr); vkFreeMemory(device, textureImageMemory, nullptr);