diff --git a/tools/hello.cpp b/tools/hello.cpp new file mode 100644 index 0000000..f280ac1 --- /dev/null +++ b/tools/hello.cpp @@ -0,0 +1,580 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +#if 0 +static VkBool32 +vk_debug_callback (VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objType, + uint64_t obj, + size_t location, + int32_t code, + const char* layerPrefix, + const char* msg, + void* userData) +{ + (void)flags; + (void)objType; + (void)obj; + (void)location; + (void)code; + (void)layerPrefix; + (void)msg; + (void)userData; + + std::cerr << "validation: " << msg << '\n'; + + return VK_FALSE; +} +#endif + + +VkShaderModule +create_shader (cruft::vk::device &dev, const std::experimental::filesystem::path &src) +{ + auto bytes = util::slurp (src); + assert (bytes.size () % 4 == 0); + + VkShaderModuleCreateInfo create_info {}; + create_info.sType = cruft::vk::structure_type_v; + create_info.codeSize = bytes.size (); + create_info.pCode = reinterpret_cast (bytes.data ()); + + VkShaderModule value; + cruft::vk::error::try_code ( + vkCreateShaderModule (dev.id (), &create_info, nullptr, &value) + ); + + return value; +} + + +/////////////////////////////////////////////////////////////////////////////// +int +main (void) +{ + LOG_INFO ("intialising glfw"); + glfwInit (); + + LOG_INFO ("intialising window"); + glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE); + + int resolution_x = 800, resolution_y = 600; + auto window = glfwCreateWindow (resolution_x, resolution_y, "vkcruft-hello", nullptr, nullptr); + if (!window) { + LOG_ERROR("unable to initialised GLFW"); + return -1; + } + + unsigned int glfwExtensionCount; + auto glfwExtensions = glfwGetRequiredInstanceExtensions (&glfwExtensionCount); + std::vector extensions (glfwExtensions + 0, glfwExtensions + glfwExtensionCount); + extensions.push_back ("VK_EXT_debug_report"); + + const char* layers[] = { + "VK_LAYER_LUNARG_standard_validation" + }; + + cruft::vk::instance instance ( + util::make_view (layers), + util::make_view (extensions.data (), extensions.data () + extensions.size ()) + ); + + auto pdevices = cruft::vk::physical_device::find (instance); + auto &pdevice = pdevices[0]; + + VkSurfaceKHR surface; + cruft::vk::error::try_code ( + glfwCreateWindowSurface (instance.id (), window, nullptr, &surface) + ); + + VkSurfaceCapabilitiesKHR surface_capabilities; + std::vector surface_formats; + std::vector present_modes; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR (pdevice.id (), surface, &surface_capabilities); + { + uint32_t format_count = 0; + cruft::vk::error::try_code ( + vkGetPhysicalDeviceSurfaceFormatsKHR (pdevice.id (), surface, &format_count, nullptr) + ); + + surface_formats.resize (format_count); + cruft::vk::error::try_code ( + vkGetPhysicalDeviceSurfaceFormatsKHR ( + pdevice.id (), surface, &format_count, surface_formats.data () + ) + ); + + + uint32_t present_count = 0; + cruft::vk::error::try_code ( + vkGetPhysicalDeviceSurfacePresentModesKHR (pdevice.id (), surface, &present_count, nullptr) + ); + + present_modes.resize (present_count); + cruft::vk::error::try_code ( + vkGetPhysicalDeviceSurfacePresentModesKHR (pdevice.id (), surface, &present_count, nullptr) + ); + } + + auto queues = pdevice.queue_families (); + int graphics_queue_id = -1, present_queue_id = -1; + for (int i = 0; unsigned (i) != queues.size (); ++i) { + if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + graphics_queue_id = i; + + VkBool32 present_support = false; + vkGetPhysicalDeviceSurfaceSupportKHR (pdevice.id (), i, surface, &present_support); + if (present_support) + present_queue_id = i; + } + + float priority = 1.f; + VkDeviceQueueCreateInfo device_queues[] = + { + { + .sType = cruft::vk::structure_type_v, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = unsigned (graphics_queue_id), + .queueCount = 1, + .pQueuePriorities = &priority, + }, + { + .sType = cruft::vk::structure_type_v, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = unsigned (present_queue_id), + .queueCount = 1, + .pQueuePriorities = &priority + } + }; + + const char *device_extensions[] = { + "VK_KHR_swapchain" + }; + + VkPhysicalDeviceFeatures device_features {}; + + VkDeviceCreateInfo device_info {}; + device_info.sType = cruft::vk::structure_type_v; + device_info.pQueueCreateInfos = std::data (device_queues); + device_info.queueCreateInfoCount = std::size (device_queues); + device_info.pEnabledFeatures = &device_features; + device_info.enabledLayerCount = std::size (layers); + device_info.ppEnabledLayerNames = layers; + device_info.enabledExtensionCount = std::size (device_extensions); + device_info.ppEnabledExtensionNames = std::data (device_extensions); + + cruft::vk::device ldevice (pdevice, device_info); + +#if 0 + VkSurfaceFormatKHR surface_format = + (surface_formats.size () == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED) + ? { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR } + : surface_formats[0]; +#endif + VkSurfaceFormatKHR surface_format { VK_FORMAT_B8G8R8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR }; + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; + VkExtent2D present_extent { + .width = util::limit ( + unsigned (resolution_x), + surface_capabilities.minImageExtent.width, + surface_capabilities.maxImageExtent.width + ), + .height = util::limit ( + unsigned (resolution_y), + surface_capabilities.minImageExtent.height, + surface_capabilities.maxImageExtent.height + ) + }; + + uint32_t image_count = surface_capabilities.minImageCount; + + VkSwapchainCreateInfoKHR swap_create_info { + .sType = cruft::vk::structure_type_v, + .pNext = nullptr, + .flags = {}, + .surface = surface, + .minImageCount = image_count, + .imageFormat = surface_format.format, + .imageColorSpace = surface_format.colorSpace, + .imageExtent = present_extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageSharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .preTransform = surface_capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present_mode, + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; + + VkSwapchainKHR swapchain; + cruft::vk::error::try_code ( + vkCreateSwapchainKHR (ldevice.id (), &swap_create_info, nullptr, &swapchain) + ); + + uint32_t swap_image_count = 0; + cruft::vk::error::try_code ( + vkGetSwapchainImagesKHR (ldevice.id (), swapchain, &swap_image_count, nullptr) + ); + std::vector swap_images (swap_image_count); + cruft::vk::error::try_code ( + vkGetSwapchainImagesKHR (ldevice.id (), swapchain, &swap_image_count, swap_images.data ()) + ); + + std::vector swap_image_views (swap_image_count); + std::transform ( + std::cbegin (swap_images), std::cend (swap_images), + std::begin (swap_image_views), + [&] (auto i) { + VkImageViewCreateInfo create_info {}; + create_info.sType = cruft::vk::structure_type_v, + create_info.pNext = nullptr, + create_info.image = i, + create_info.viewType = VK_IMAGE_VIEW_TYPE_2D, + create_info.format = surface_format.format, + create_info.components = VkComponentMapping { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }; + create_info.subresourceRange = VkImageSubresourceRange { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + }; + + VkImageView v; + cruft::vk::error::try_code ( + vkCreateImageView (ldevice.id (), &create_info, nullptr, &v) + ); + + return v; + }); + + auto graphics_queue = ldevice.queue (graphics_queue_id); + auto present_queue = ldevice.queue (present_queue_id); + + auto vert_module = create_shader (ldevice, "./hello/shader.vert"); + auto frag_module = create_shader (ldevice, "./hello/shader.frag"); + + VkPipelineShaderStageCreateInfo vert_stage_info {}; + vert_stage_info.sType = cruft::vk::structure_type_v; + vert_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_stage_info.module = vert_module; + vert_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo frag_stage_info = vert_stage_info; + frag_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_stage_info.module = frag_module; + + VkPipelineShaderStageCreateInfo stages[] = { + vert_stage_info, frag_stage_info + }; + + VkPipelineVertexInputStateCreateInfo vertex_input {}; + vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input.vertexBindingDescriptionCount = 0; + vertex_input.pVertexBindingDescriptions = nullptr; + vertex_input.vertexAttributeDescriptionCount = 0; + vertex_input.pVertexBindingDescriptions = nullptr; + + VkPipelineInputAssemblyStateCreateInfo assembly_info {}; + assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + assembly_info.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport { + .x = 0.f, + .y = 0.f, + .width = float (present_extent.width), + .height = float (present_extent.height), + .minDepth = 0.f, + .maxDepth = 1.f, + }; + + VkRect2D scissor { + .offset = {}, + .extent = present_extent + }; + + VkPipelineViewportStateCreateInfo viewport_create_info {}; + viewport_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_create_info.viewportCount = 1; + viewport_create_info.pViewports = &viewport; + viewport_create_info.scissorCount = 1; + viewport_create_info.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.f; + rasterizer.depthBiasClamp = 0.f; + rasterizer.depthBiasSlopeFactor = 0.f; + + VkPipelineMultisampleStateCreateInfo multisampling {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState blend_attachment = {}; + blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blend_attachment.blendEnable = VK_FALSE; + blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional + blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional + blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; // Optional + blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional + blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional + blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional + + VkPipelineColorBlendStateCreateInfo colour_blend = {}; + colour_blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colour_blend.logicOpEnable = VK_FALSE; + colour_blend.logicOp = VK_LOGIC_OP_COPY; // Optional + colour_blend.attachmentCount = 1; + colour_blend.pAttachments = &blend_attachment; + colour_blend.blendConstants[0] = 0.0f; // Optional + colour_blend.blendConstants[1] = 0.0f; // Optional + colour_blend.blendConstants[2] = 0.0f; // Optional + colour_blend.blendConstants[3] = 0.0f; // Optional + + VkPipelineLayoutCreateInfo pipeline_layout_info {}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = 0; // Optional + pipeline_layout_info.pSetLayouts = nullptr; // Optional + pipeline_layout_info.pushConstantRangeCount = 0; // Optional + pipeline_layout_info.pPushConstantRanges = 0; // Optional + + VkPipelineLayout pipeline_layout; + cruft::vk::error::try_code ( + vkCreatePipelineLayout (ldevice.id (), &pipeline_layout_info, nullptr, &pipeline_layout) + ); + + VkAttachmentDescription color_attachment {}; + color_attachment.format = surface_format.format; + color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colour_attachment_ref {}; + colour_attachment_ref.attachment = 0; + colour_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colour_attachment_ref; + + VkRenderPassCreateInfo render_pass_info {}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.attachmentCount = 1; + render_pass_info.pAttachments = &color_attachment; + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass; + + VkRenderPass render_pass; + cruft::vk::error::try_code ( + vkCreateRenderPass (ldevice.id (), &render_pass_info, nullptr, &render_pass) + ); + + VkGraphicsPipelineCreateInfo pipeline_info {}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.stageCount = 2; + pipeline_info.pStages = stages; + pipeline_info.pVertexInputState = &vertex_input; + pipeline_info.pInputAssemblyState = &assembly_info; + pipeline_info.pViewportState = &viewport_create_info; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = nullptr; + pipeline_info.pColorBlendState = &colour_blend; + pipeline_info.layout = pipeline_layout; + pipeline_info.renderPass = render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + VkPipeline graphics_pipeline; + cruft::vk::error::try_code ( + vkCreateGraphicsPipelines ( + ldevice.id (), VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &graphics_pipeline + ) + ); + + + std::vector swapchain_framebuffers (swap_image_views.size ()); + for (int i = 0; i < swap_image_views.size (); ++i) { + VkImageView attachments[] = { + swap_image_views[i] + }; + + VkFramebufferCreateInfo framebuffer_info {}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = render_pass; + framebuffer_info.attachmentCount = 1; + framebuffer_info.pAttachments = attachments; + framebuffer_info.width = present_extent.width; + framebuffer_info.height = present_extent.height; + framebuffer_info.layers = 1; + + cruft::vk::error::try_code ( + vkCreateFramebuffer (ldevice.id (), &framebuffer_info, nullptr, &swapchain_framebuffers[i]) + ); + }; + + VkCommandPoolCreateInfo pool_info {}; + pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_info.queueFamilyIndex = device_queues[0].queueFamilyIndex; + + VkCommandPool command_pool; + cruft::vk::error::try_code ( + vkCreateCommandPool (ldevice.id (), &pool_info, nullptr, &command_pool) + ); + + std::vector command_buffers (swapchain_framebuffers.size ()); + VkCommandBufferAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.commandPool = command_pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = (uint32_t) command_buffers.size(); + cruft::vk::error::try_code ( + vkAllocateCommandBuffers (ldevice.id (), &alloc_info, command_buffers.data ()) + ); + + for (int i = 0; i < command_buffers.size (); ++i) { + VkCommandBufferBeginInfo command_begin {}; + command_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + command_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + cruft::vk::error::try_code ( + vkBeginCommandBuffer (command_buffers[i], &command_begin) + ); + + VkRenderPassBeginInfo render_begin {}; + render_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_begin.renderPass = render_pass; + render_begin.framebuffer = swapchain_framebuffers[i]; + render_begin.renderArea.extent = present_extent; + + VkClearValue clear_color { 0.f, 0.f, 0.f, 1.f }; + render_begin.clearValueCount = 1; + render_begin.pClearValues = &clear_color; + + vkCmdBeginRenderPass (command_buffers[i], &render_begin, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline (command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); + + vkCmdDraw (command_buffers[i], 3, 1, 0, 0); + + vkCmdEndRenderPass (command_buffers[i]); + + vkEndCommandBuffer (command_buffers[i]); + }; + + VkSemaphoreCreateInfo semaphore_info {}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkSemaphore image_semaphore, render_semaphore; + cruft::vk::error::try_code ( + vkCreateSemaphore (ldevice.id (), &semaphore_info, nullptr, &image_semaphore) + ); + cruft::vk::error::try_code ( + vkCreateSemaphore (ldevice.id (), &semaphore_info, nullptr, &render_semaphore) + ); + + uint32_t image_index; + cruft::vk::error::try_code ( + vkAcquireNextImageKHR ( + ldevice.id (), swapchain, + std::numeric_limits::max (), + image_semaphore, VK_NULL_HANDLE, + &image_index + ) + ); + + VkSubmitInfo submit_info {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + VkSemaphore wait_semaphores[] = { image_semaphore }; + VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.pWaitDstStageMask = wait_stages; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffers[image_index]; + + VkSemaphore signal_semaphores[] = { render_semaphore }; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphores; + + cruft::vk::error::try_code ( + vkQueueSubmit (graphics_queue.id (), 1, &submit_info, VK_NULL_HANDLE) + ); + + VkSubpassDependency dependency {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + VkPresentInfoKHR present_info {}; + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = signal_semaphores; + + VkSwapchainKHR swapchains[] = { swapchain }; + present_info.swapchainCount = 1; + present_info.pSwapchains = swapchains; + present_info.pImageIndices = &image_index; + present_info.pResults = nullptr; + + vkQueuePresentKHR (present_queue.id (), &present_info); + + LOG_INFO ("entering runloop"); + while (!glfwWindowShouldClose (window)) { + glfwPollEvents (); + } + + vkDeviceWaitIdle (ldevice.id ()); + + LOG_INFO ("terminating glfw"); + glfwDestroyWindow (window); + glfwTerminate (); +} \ No newline at end of file diff --git a/tools/hello/shader.frag b/tools/hello/shader.frag new file mode 100644 index 0000000..84daf5e --- /dev/null +++ b/tools/hello/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/tools/hello/shader.vert b/tools/hello/shader.vert new file mode 100644 index 0000000..d38f815 --- /dev/null +++ b/tools/hello/shader.vert @@ -0,0 +1,25 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +}