From d1ad81b5bc95b7890a7e4d7045ebc19e36e4280c Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 11 Sep 2023 17:29:37 -0400 Subject: WIP: Images starting to work! Need to fix RGBA and coords --- play/Display_vk.tcl | 538 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 383 insertions(+), 155 deletions(-) diff --git a/play/Display_vk.tcl b/play/Display_vk.tcl index 80cd7d68..e0952b02 100644 --- a/play/Display_vk.tcl +++ b/play/Display_vk.tcl @@ -22,12 +22,13 @@ namespace eval Display { dc cflags -lglfw } - proc vktry {call} { csubst {{ + proc vktry {call} { string map {\n " "} [csubst {{ VkResult res = $call; if (res != VK_SUCCESS) { fprintf(stderr, "Failed $call: %d\n", res); exit(1); } - }} } + }}] } + namespace export vktry dc code { VkInstance instance; @@ -47,6 +48,8 @@ namespace eval Display { VkFramebuffer* swapchainFramebuffers; VkExtent2D swapchainExtent; + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; uint32_t imageIndex; @@ -75,7 +78,7 @@ namespace eval Display { VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_KHR_SURFACE_EXTENSION_NAME, "VK_EXT_metal_surface", - "VK_KHR_get_physical_device_properties2" + "VK_KHR_get_physical_device_properties2" }} : {{ // 2 extensions for non-X11/Wayland display VK_KHR_SURFACE_EXTENSION_NAME, @@ -84,7 +87,6 @@ namespace eval Display { createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]); createInfo.ppEnabledExtensionNames = enabledExtensions; createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; - $[vktry {vkCreateInstance(&createInfo, NULL, &instance)}] } volkLoadInstance(instance); @@ -139,9 +141,13 @@ namespace eval Display { const char *deviceExtensions[] = $[expr { $macos ? {{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, - "VK_KHR_portability_subset" + "VK_KHR_portability_subset", + VK_KHR_MAINTENANCE3_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME }} : {{ - VK_KHR_SWAPCHAIN_EXTENSION_NAME + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_MAINTENANCE3_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME }} }]; VkDeviceCreateInfo createInfo = {0}; @@ -153,6 +159,12 @@ namespace eval Display { createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]); createInfo.ppEnabledExtensionNames = deviceExtensions; + VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; + descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; + // TODO: Do we need more descriptor indexing features? + createInfo.pNext = &descriptorIndexingFeatures; + $[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}] } @@ -370,7 +382,8 @@ namespace eval Display { $[vktry {vkCreateFramebuffer(device, &framebufferInfo, NULL, &swapchainFramebuffers[i])}] } - VkCommandPool commandPool; { + // Set up VkCommandPool commandPool + { VkCommandPoolCreateInfo poolInfo = {0}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; @@ -551,8 +564,9 @@ namespace eval Display { VkPipelineLayout pipelineLayout; { VkPipelineLayoutCreateInfo pipelineLayoutInfo = {0}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 0; - pipelineLayoutInfo.pSetLayouts = NULL; + + pipelineLayoutInfo.pSetLayouts = &imageDescriptorSetLayout; + pipelineLayoutInfo.setLayoutCount = 1; if (pushConstantsSize > 0) { VkPushConstantRange pushConstantRange = {0}; @@ -604,120 +618,6 @@ namespace eval Display { }; }] - # Buffer allocation: - - dc code [csubst { - uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - exit(1); - } - - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, - VkBuffer* buffer, VkDeviceMemory* bufferMemory) { - VkBufferCreateInfo bufferInfo = {0}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - $[vktry {vkCreateBuffer(device, &bufferInfo, NULL, buffer)}] - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, *buffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {0}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - - $[vktry {vkAllocateMemory(device, &allocInfo, NULL, bufferMemory)}] - vkBindBufferMemory(device, *buffer, *bufferMemory, 0); - } - }] - - # Image allocation: - dc code [csubst { - void createImage(uint32_t width, uint32_t height, - VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, - VkImage* image, VkDeviceMemory* imageMemory) { - VkImageCreateInfo imageInfo = {0}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = format; - imageInfo.tiling = tiling; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usage; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - $[vktry {vkCreateImage(device, &imageInfo, NULL, image)}] - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, *image, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {0}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - - $[vktry {vkAllocateMemory(device, &allocInfo, NULL, imageMemory)}] - - vkBindImageMemory(device, *image, *imageMemory, 0); - } - void transitionImageLayout(VkCommandBuffer commandBuffer, - VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) { - VkImageMemoryBarrier barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - VkPipelineStageFlags sourceStage; - VkPipelineStageFlags destinationStage; - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } else { - exit(91); - } - vkCmdPipelineBarrier(commandBuffer, - sourceStage, destinationStage, - 0, - 0, NULL, - 0, NULL, - 1, &barrier); - } - }] - dc proc drawStart {} void { vkWaitForFences(device, 1, &inFlightFence, VK_TRUE, UINT64_MAX); @@ -751,6 +651,10 @@ namespace eval Display { dc proc drawImpl {Pipeline pipeline Tcl_Obj* pushConstants} void { vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); + // TODO: Don't rebind if already bound + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline.pipelineLayout, 0, 1, &imageDescriptorSet, 0, NULL); + if (pipeline.pushConstantsSize > 0) { vkCmdPushConstants(commandBuffer, pipeline.pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, @@ -834,20 +738,23 @@ namespace eval Display { }]] } - variable VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER - variable VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER - set pushConstants [list] set pushConstantsSize 0 foreach {argtype argname} $args { + if {$argtype eq "sampler2D"} { set argtype "int" } + lappend pushConstants [dict create argtype $argtype argname $argname] if {$argtype eq "float"} { set pushConstantsSize [+ $pushConstantsSize 4] } \ - elseif {$argtype eq "vec2"} { set pushConstantsSize [+ $pushConstantsSize 8] } + elseif {$argtype eq "vec2"} { set pushConstantsSize [+ $pushConstantsSize 8] } \ + elseif {$argtype eq "int"} { set pushConstantsSize [+ $pushConstantsSize 4] } \ + else { error "Invalid shader argument type $argtype" } } set fragShaderModule [createShaderModule [glslc -fshader-stage=frag [csubst { #version 450 + layout(set = 0, binding = 0) uniform sampler2D samplers[16]; + $[if {[llength $pushConstants] > 0} { subst { layout(push_constant) uniform Args { [join [lmap field $pushConstants { @@ -870,12 +777,330 @@ namespace eval Display { } }]]] - # pipeline needs to contain a specification of all args, - # so Display::draw can fill the args into UBO and samplers etc. + # pipeline needs to contain a specification of push constants, + # so they can be filled in at draw time. set pipeline [Display::createPipeline $vertShaderModule $fragShaderModule \ [llength $pushConstants] $pushConstants $pushConstantsSize] return $pipeline } + + namespace export dc + namespace eval GpuImageManager { + namespace import [namespace parent]::* + + dc code { + VkDescriptorSetLayout imageDescriptorSetLayout; + VkDescriptorSet imageDescriptorSet; + } + dc proc gpuImageManagerInit {} void { + // Set up imageDescriptorSetLayout: + { + VkDescriptorBindingFlags flags[1]; + flags[0] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + + VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlags = {0}; + bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + bindingFlags.bindingCount = 1; + bindingFlags.pBindingFlags = flags; + + VkDescriptorSetLayoutBinding bindings[1]; + memset(bindings, 0, sizeof(bindings)); + bindings[0].binding = 0; + bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[0].descriptorCount = 16; + bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.bindingCount = 1; + createInfo.pBindings = bindings; + createInfo.pNext = &bindingFlags; + + vkCreateDescriptorSetLayout(device, &createInfo, NULL, &imageDescriptorSetLayout); + } + + VkDescriptorPool descriptorPool; { + VkDescriptorPoolSize poolSize = {0}; + poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSize.descriptorCount = 512; + + VkDescriptorPoolCreateInfo poolInfo = {0}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &poolSize; + poolInfo.maxSets = 100; + $[vktry {vkCreateDescriptorPool(device, &poolInfo, NULL, &descriptorPool)}] + } + + // Set up imageDescriptorSet: + { + VkDescriptorSetAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &imageDescriptorSetLayout; + + $[vktry {vkAllocateDescriptorSets(device, &allocInfo, &imageDescriptorSet)}] + } + } + + # Buffer allocation: + + dc code [csubst { + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + + exit(1); + } + + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, + VkBuffer* buffer, VkDeviceMemory* bufferMemory) { + VkBufferCreateInfo bufferInfo = {0}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + $[vktry {vkCreateBuffer(device, &bufferInfo, NULL, buffer)}] + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, *buffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); + + $[vktry {vkAllocateMemory(device, &allocInfo, NULL, bufferMemory)}] + vkBindBufferMemory(device, *buffer, *bufferMemory, 0); + } + }] + + # Image allocation: + dc code [csubst { + void createImage(uint32_t width, uint32_t height, + VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, + VkImage* image, VkDeviceMemory* imageMemory) { + VkImageCreateInfo imageInfo = {0}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + $[vktry {vkCreateImage(device, &imageInfo, NULL, image)}] + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, *image, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); + + $[vktry {vkAllocateMemory(device, &allocInfo, NULL, imageMemory)}] + + vkBindImageMemory(device, *image, *imageMemory, 0); + } + VkCommandBuffer beginSingleTimeCommands() { + VkCommandBufferAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); + + VkCommandBufferBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + return commandBuffer; + } + void endSingleTimeCommands(VkCommandBuffer commandBuffer) { + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(graphicsQueue); + + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); + } + void transitionImageLayout(VkImage image, VkFormat format, + VkImageLayout oldLayout, VkImageLayout newLayout) { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkImageMemoryBarrier barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + VkPipelineStageFlags sourceStage; + VkPipelineStageFlags destinationStage; + if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + exit(91); + } + vkCmdPipelineBarrier(commandBuffer, + sourceStage, destinationStage, + 0, + 0, NULL, + 0, NULL, + 1, &barrier); + + endSingleTimeCommands(commandBuffer); + } + }] + + dc proc copyImageToGpu {image_t im} int { + size_t size = im.width * im.height * 4; + + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &stagingBuffer, &stagingBufferMemory); + + VkImage textureImage; + VkDeviceMemory textureImageMemory; + createImage(im.width, im.height, + VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &textureImage, &textureImageMemory); + + VkImageView textureImageView; { + VkImageViewCreateInfo viewInfo = {0}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = textureImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + $[vktry {vkCreateImageView(device, &viewInfo, NULL, &textureImageView)}] + } + VkSampler textureSampler; { + VkSamplerCreateInfo samplerInfo = {0}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.anisotropyEnable = VK_FALSE; // TODO: do we want this? + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + $[vktry {vkCreateSampler(device, &samplerInfo, NULL, &textureSampler)}] + } + + // Copy im to stagingBuffer: + { + void* data; vkMapMemory(device, stagingBufferMemory, 0, size, 0, &data); + memcpy(data, im.data, size); + vkUnmapMemory(device, stagingBufferMemory); + } + transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + // Copy stagingBuffer to textureImage: + { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkBufferImageCopy region = {0}; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + + region.imageOffset = (VkOffset3D) {0, 0, 0}; + region.imageExtent = (VkExtent3D) {im.width, im.height, 1}; + vkCmdCopyBufferToImage(commandBuffer, + stagingBuffer, + textureImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ®ion); + + endSingleTimeCommands(commandBuffer); + } + transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + // Write this image+sampler to the imageDescriptorSet + static int nextImageId = 0; + int imageId = nextImageId++; + { + VkDescriptorImageInfo imageInfo = {0}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = textureImageView; + imageInfo.sampler = textureSampler; + + VkWriteDescriptorSet descriptorWrite = {0}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = imageDescriptorSet; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = imageId; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pImageInfo = &imageInfo; + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, NULL); + } + + return imageId; + } + } } proc glslc {args} { @@ -890,44 +1115,47 @@ if {[info exists ::argv0] && $::argv0 eq [info script] || \ namespace eval Display { dc compile } Display::init + Display::GpuImageManager::gpuImageManagerInit - set circle [Display::pipeline {vec2 center float radius} { - float dist = length(gl_FragCoord.xy - center) - radius; - outColor = dist < 0.0 ? vec4(gl_FragCoord.xy / 640, 0, 1.0) : vec4(0, 0, 0, 0); - }] - - set line [Display::pipeline {vec2 from vec2 to float thickness} { - float l = length(to - from); - vec2 d = (to - from) / l; - vec2 q = (gl_FragCoord.xy - (from + to)*0.5); - q = mat2(d.x, -d.y, d.y, d.x) * q; - q = abs(q) - vec2(l, thickness)*0.5; - float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0); + # set circle [Display::pipeline {vec2 center float radius} { + # float dist = length(gl_FragCoord.xy - center) - radius; + # outColor = dist < 0.0 ? vec4(gl_FragCoord.xy / 640, 0, 1.0) : vec4(0, 0, 0, 0); + # }] - outColor = dist < 0.0 ? vec4(1, 0, 1, 1) : vec4(0, 0, 0, 0); - }] + # set line [Display::pipeline {vec2 from vec2 to float thickness} { + # float l = length(to - from); + # vec2 d = (to - from) / l; + # vec2 q = (gl_FragCoord.xy - (from + to)*0.5); + # q = mat2(d.x, -d.y, d.y, d.x) * q; + # q = abs(q) - vec2(l, thickness)*0.5; + # float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0); - # set image [Display::pipeline {sampler2D image} { - # outColor = vec4(1, 0, 0, 1); + # outColor = dist < 0.0 ? vec4(1, 0, 1, 1) : vec4(0, 0, 0, 0); # }] + set image [Display::pipeline {sampler2D image} { + outColor = texture(samplers[image], gl_FragCoord.xy / 360.0); +// outColor = vec4(gl_FragCoord.xy / 360.0, 0.0, 1.0); + }] + # FIXME: bounding box for scissors # FIXME: sampler2D, text - set redOnRight [Display::pipeline {} { - outColor = gl_FragCoord.x > 400 ? vec4(gl_FragCoord.x / 4096.0, 0, 0, 1.0) : vec4(0, 0, 0, 0); - }] + # set redOnRight [Display::pipeline {} { + # outColor = gl_FragCoord.x > 400 ? vec4(gl_FragCoord.x / 4096.0, 0, 0, 1.0) : vec4(0, 0, 0, 0); + # }] - # set im [image loadJpeg "/Users/osnr/Downloads/u9.jpg"] - # set gim [Display::copyImageToGpu $im] + set im [image loadJpeg "/Users/osnr/Downloads/u9.jpg"] + set gim [Display::GpuImageManager::copyImageToGpu $im] + puts $gim Display::drawStart - Display::draw $circle {200 50} 30 - Display::draw $circle {300 300} 20 - Display::draw $line {0 0} {100 100} 10 - Display::draw $redOnRight - # Display::draw $image $gim + # Display::draw $circle {200 50} 30 + # Display::draw $circle {300 300} 20 + # Display::draw $line {0 0} {100 100} 10 + # Display::draw $redOnRight + Display::draw $image $gim Display::drawEnd -- cgit v1.2.3