summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOmar Rizwan <omar@omar.website>2023-09-11 21:29:37 +0000
committerOmar Rizwan <omar@omar.website>2023-09-11 21:29:37 +0000
commitd1ad81b5bc95b7890a7e4d7045ebc19e36e4280c (patch)
tree4e30cbbef4247a2c1859024a9b6abaff5e2d22cc
parentc: Detect C proc name collisions (diff)
downloadfolk-d1ad81b5bc95b7890a7e4d7045ebc19e36e4280c.tar.gz
folk-d1ad81b5bc95b7890a7e4d7045ebc19e36e4280c.zip
WIP: Images starting to work! Need to fix RGBA and coords
-rw-r--r--play/Display_vk.tcl538
1 files 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,
+ &region);
+
+ 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