2233 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			2233 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"embed"
 | 
						|
	"encoding/binary"
 | 
						|
	"github.com/g3n/engine/loader/obj"
 | 
						|
	"github.com/loov/hrtime"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
	"github.com/veandco/go-sdl2/sdl"
 | 
						|
	"github.com/vkngwrapper/core/v2"
 | 
						|
	"github.com/vkngwrapper/core/v2/common"
 | 
						|
	"github.com/vkngwrapper/core/v2/core1_0"
 | 
						|
	"github.com/vkngwrapper/extensions/v2/ext_debug_utils"
 | 
						|
	"github.com/vkngwrapper/extensions/v2/khr_portability_enumeration"
 | 
						|
	"github.com/vkngwrapper/extensions/v2/khr_portability_subset"
 | 
						|
	"github.com/vkngwrapper/extensions/v2/khr_surface"
 | 
						|
	"github.com/vkngwrapper/extensions/v2/khr_swapchain"
 | 
						|
	vkng_sdl2 "github.com/vkngwrapper/integrations/sdl2/v2"
 | 
						|
	vkngmath "github.com/vkngwrapper/math"
 | 
						|
	"image/png"
 | 
						|
	"log"
 | 
						|
	"math"
 | 
						|
	"runtime"
 | 
						|
	"unsafe"
 | 
						|
)
 | 
						|
 | 
						|
//go:embed shaders images meshes
 | 
						|
var fileSystem embed.FS
 | 
						|
 | 
						|
const MaxFramesInFlight = 2
 | 
						|
 | 
						|
var validationLayers = []string{"VK_LAYER_KHRONOS_validation"}
 | 
						|
var deviceExtensions = []string{khr_swapchain.ExtensionName}
 | 
						|
 | 
						|
const enableValidationLayers = true
 | 
						|
 | 
						|
type QueueFamilyIndices struct {
 | 
						|
	GraphicsFamily *int
 | 
						|
	PresentFamily  *int
 | 
						|
}
 | 
						|
 | 
						|
func (i *QueueFamilyIndices) IsComplete() bool {
 | 
						|
	return i.GraphicsFamily != nil && i.PresentFamily != nil
 | 
						|
}
 | 
						|
 | 
						|
type SwapChainSupportDetails struct {
 | 
						|
	Capabilities *khr_surface.SurfaceCapabilities
 | 
						|
	Formats      []khr_surface.SurfaceFormat
 | 
						|
	PresentModes []khr_surface.PresentMode
 | 
						|
}
 | 
						|
 | 
						|
type Vertex struct {
 | 
						|
	Position vkngmath.Vec3[float32]
 | 
						|
	Color    vkngmath.Vec3[float32]
 | 
						|
	TexCoord vkngmath.Vec2[float32]
 | 
						|
}
 | 
						|
 | 
						|
type UniformBufferObject struct {
 | 
						|
	Model vkngmath.Mat4x4[float32]
 | 
						|
	View  vkngmath.Mat4x4[float32]
 | 
						|
	Proj  vkngmath.Mat4x4[float32]
 | 
						|
}
 | 
						|
 | 
						|
func getVertexBindingDescription() []core1_0.VertexInputBindingDescription {
 | 
						|
	v := Vertex{}
 | 
						|
	return []core1_0.VertexInputBindingDescription{
 | 
						|
		{
 | 
						|
			Binding:   0,
 | 
						|
			Stride:    int(unsafe.Sizeof(v)),
 | 
						|
			InputRate: core1_0.VertexInputRateVertex,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func getVertexAttributeDescriptions() []core1_0.VertexInputAttributeDescription {
 | 
						|
	v := Vertex{}
 | 
						|
	return []core1_0.VertexInputAttributeDescription{
 | 
						|
		{
 | 
						|
			Binding:  0,
 | 
						|
			Location: 0,
 | 
						|
			Format:   core1_0.FormatR32G32B32SignedFloat,
 | 
						|
			Offset:   int(unsafe.Offsetof(v.Position)),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Binding:  0,
 | 
						|
			Location: 1,
 | 
						|
			Format:   core1_0.FormatR32G32B32SignedFloat,
 | 
						|
			Offset:   int(unsafe.Offsetof(v.Color)),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Binding:  0,
 | 
						|
			Location: 2,
 | 
						|
			Format:   core1_0.FormatR32G32SignedFloat,
 | 
						|
			Offset:   int(unsafe.Offsetof(v.TexCoord)),
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type HelloTriangleApplication struct {
 | 
						|
	window *sdl.Window
 | 
						|
	loader core.Loader
 | 
						|
 | 
						|
	instance       core1_0.Instance
 | 
						|
	debugMessenger ext_debug_utils.DebugUtilsMessenger
 | 
						|
	surface        khr_surface.Surface
 | 
						|
 | 
						|
	physicalDevice core1_0.PhysicalDevice
 | 
						|
	device         core1_0.Device
 | 
						|
 | 
						|
	graphicsQueue core1_0.Queue
 | 
						|
	presentQueue  core1_0.Queue
 | 
						|
 | 
						|
	swapchainExtension    khr_swapchain.Extension
 | 
						|
	swapchain             khr_swapchain.Swapchain
 | 
						|
	swapchainImages       []core1_0.Image
 | 
						|
	swapchainImageFormat  core1_0.Format
 | 
						|
	swapchainExtent       core1_0.Extent2D
 | 
						|
	swapchainImageViews   []core1_0.ImageView
 | 
						|
	swapchainFramebuffers []core1_0.Framebuffer
 | 
						|
 | 
						|
	renderPass          core1_0.RenderPass
 | 
						|
	descriptorPool      core1_0.DescriptorPool
 | 
						|
	descriptorSets      []core1_0.DescriptorSet
 | 
						|
	descriptorSetLayout core1_0.DescriptorSetLayout
 | 
						|
	pipelineLayout      core1_0.PipelineLayout
 | 
						|
	graphicsPipeline    core1_0.Pipeline
 | 
						|
 | 
						|
	commandPool    core1_0.CommandPool
 | 
						|
	commandBuffers []core1_0.CommandBuffer
 | 
						|
 | 
						|
	imageAvailableSemaphore []core1_0.Semaphore
 | 
						|
	renderFinishedSemaphore []core1_0.Semaphore
 | 
						|
	inFlightFence           []core1_0.Fence
 | 
						|
	imagesInFlight          []core1_0.Fence
 | 
						|
	currentFrame            int
 | 
						|
	frameStart              float64
 | 
						|
 | 
						|
	vertices           []Vertex
 | 
						|
	indices            []uint32
 | 
						|
	vertexBuffer       core1_0.Buffer
 | 
						|
	vertexBufferMemory core1_0.DeviceMemory
 | 
						|
	indexBuffer        core1_0.Buffer
 | 
						|
	indexBufferMemory  core1_0.DeviceMemory
 | 
						|
 | 
						|
	uniformBuffers       []core1_0.Buffer
 | 
						|
	uniformBuffersMemory []core1_0.DeviceMemory
 | 
						|
 | 
						|
	mipLevels          int
 | 
						|
	textureImage       core1_0.Image
 | 
						|
	textureImageMemory core1_0.DeviceMemory
 | 
						|
	textureImageView   core1_0.ImageView
 | 
						|
	textureSampler     core1_0.Sampler
 | 
						|
 | 
						|
	depthImage       core1_0.Image
 | 
						|
	depthImageMemory core1_0.DeviceMemory
 | 
						|
	depthImageView   core1_0.ImageView
 | 
						|
 | 
						|
	msaaSamples      core1_0.SampleCountFlags
 | 
						|
	colorImage       core1_0.Image
 | 
						|
	colorImageMemory core1_0.DeviceMemory
 | 
						|
	colorImageView   core1_0.ImageView
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) Run() error {
 | 
						|
	err := app.initWindow()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.initVulkan()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer app.cleanup()
 | 
						|
 | 
						|
	return app.mainLoop()
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) initWindow() error {
 | 
						|
	if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	window, err := sdl.CreateWindow("Vulkan", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 800, 600, sdl.WINDOW_SHOWN|sdl.WINDOW_VULKAN|sdl.WINDOW_RESIZABLE)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.window = window
 | 
						|
 | 
						|
	app.loader, err = core.CreateLoaderFromProcAddr(sdl.VulkanGetVkGetInstanceProcAddr())
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) initVulkan() error {
 | 
						|
	err := app.createInstance()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.setupDebugMessenger()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createSurface()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.pickPhysicalDevice()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createLogicalDevice()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createSwapchain()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createImageViews()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createRenderPass()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDescriptorSetLayout()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createGraphicsPipeline()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createCommandPool()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createColorResources()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDepthResources()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createFramebuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createTextureImage()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createTextureImageView()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createSampler()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.loadModel()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	err = app.createVertexBuffer()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createIndexBuffer()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createUniformBuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDescriptorPool()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDescriptorSets()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createCommandBuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.createSyncObjects()
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) mainLoop() error {
 | 
						|
	rendering := true
 | 
						|
 | 
						|
appLoop:
 | 
						|
	for true {
 | 
						|
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
 | 
						|
			switch e := event.(type) {
 | 
						|
			case *sdl.QuitEvent:
 | 
						|
				break appLoop
 | 
						|
			case *sdl.WindowEvent:
 | 
						|
				switch e.Event {
 | 
						|
				case sdl.WINDOWEVENT_MINIMIZED:
 | 
						|
					rendering = false
 | 
						|
				case sdl.WINDOWEVENT_RESTORED:
 | 
						|
					rendering = true
 | 
						|
				case sdl.WINDOWEVENT_RESIZED:
 | 
						|
					w, h := app.window.GetSize()
 | 
						|
					if w > 0 && h > 0 {
 | 
						|
						rendering = true
 | 
						|
						app.recreateSwapChain()
 | 
						|
					} else {
 | 
						|
						rendering = false
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if rendering {
 | 
						|
			err := app.drawFrame()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := app.device.WaitIdle()
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) cleanupSwapChain() {
 | 
						|
	if app.colorImageView != nil {
 | 
						|
		app.colorImageView.Destroy(nil)
 | 
						|
		app.colorImageView = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.colorImage != nil {
 | 
						|
		app.colorImage.Destroy(nil)
 | 
						|
		app.colorImage = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.colorImageMemory != nil {
 | 
						|
		app.colorImageMemory.Free(nil)
 | 
						|
		app.colorImageMemory = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.depthImageView != nil {
 | 
						|
		app.depthImageView.Destroy(nil)
 | 
						|
		app.depthImageView = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.depthImage != nil {
 | 
						|
		app.depthImage.Destroy(nil)
 | 
						|
		app.depthImage = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.depthImageMemory != nil {
 | 
						|
		app.depthImageMemory.Free(nil)
 | 
						|
		app.depthImageMemory = nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, framebuffer := range app.swapchainFramebuffers {
 | 
						|
		framebuffer.Destroy(nil)
 | 
						|
	}
 | 
						|
	app.swapchainFramebuffers = []core1_0.Framebuffer{}
 | 
						|
 | 
						|
	if len(app.commandBuffers) > 0 {
 | 
						|
		app.device.FreeCommandBuffers(app.commandBuffers)
 | 
						|
		app.commandBuffers = []core1_0.CommandBuffer{}
 | 
						|
	}
 | 
						|
 | 
						|
	if app.graphicsPipeline != nil {
 | 
						|
		app.graphicsPipeline.Destroy(nil)
 | 
						|
		app.graphicsPipeline = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.pipelineLayout != nil {
 | 
						|
		app.pipelineLayout.Destroy(nil)
 | 
						|
		app.pipelineLayout = nil
 | 
						|
	}
 | 
						|
 | 
						|
	if app.renderPass != nil {
 | 
						|
		app.renderPass.Destroy(nil)
 | 
						|
		app.renderPass = nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, imageView := range app.swapchainImageViews {
 | 
						|
		imageView.Destroy(nil)
 | 
						|
	}
 | 
						|
	app.swapchainImageViews = []core1_0.ImageView{}
 | 
						|
 | 
						|
	if app.swapchain != nil {
 | 
						|
		app.swapchain.Destroy(nil)
 | 
						|
		app.swapchain = nil
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < len(app.uniformBuffers); i++ {
 | 
						|
		app.uniformBuffers[i].Destroy(nil)
 | 
						|
	}
 | 
						|
	app.uniformBuffers = app.uniformBuffers[:0]
 | 
						|
 | 
						|
	for i := 0; i < len(app.uniformBuffersMemory); i++ {
 | 
						|
		app.uniformBuffersMemory[i].Free(nil)
 | 
						|
	}
 | 
						|
	app.uniformBuffersMemory = app.uniformBuffersMemory[:0]
 | 
						|
 | 
						|
	app.descriptorPool.Destroy(nil)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) cleanup() {
 | 
						|
	app.cleanupSwapChain()
 | 
						|
 | 
						|
	if app.textureSampler != nil {
 | 
						|
		app.textureSampler.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.textureImageView != nil {
 | 
						|
		app.textureImageView.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.textureImage != nil {
 | 
						|
		app.textureImage.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.textureImageMemory != nil {
 | 
						|
		app.textureImageMemory.Free(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.descriptorSetLayout != nil {
 | 
						|
		app.descriptorSetLayout.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.indexBuffer != nil {
 | 
						|
		app.indexBuffer.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.indexBufferMemory != nil {
 | 
						|
		app.indexBufferMemory.Free(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.vertexBuffer != nil {
 | 
						|
		app.vertexBuffer.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.vertexBufferMemory != nil {
 | 
						|
		app.vertexBufferMemory.Free(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, fence := range app.inFlightFence {
 | 
						|
		fence.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, semaphore := range app.renderFinishedSemaphore {
 | 
						|
		semaphore.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, semaphore := range app.imageAvailableSemaphore {
 | 
						|
		semaphore.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.commandPool != nil {
 | 
						|
		app.commandPool.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.device != nil {
 | 
						|
		app.device.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.debugMessenger != nil {
 | 
						|
		app.debugMessenger.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.surface != nil {
 | 
						|
		app.surface.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.instance != nil {
 | 
						|
		app.instance.Destroy(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if app.window != nil {
 | 
						|
		app.window.Destroy()
 | 
						|
	}
 | 
						|
	sdl.Quit()
 | 
						|
 | 
						|
	app.loader.Driver().ObjectStore().PrintDebug()
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) recreateSwapChain() error {
 | 
						|
	w, h := app.window.VulkanGetDrawableSize()
 | 
						|
	if w == 0 || h == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	if (app.window.GetFlags() & sdl.WINDOW_MINIMIZED) != 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := app.device.WaitIdle()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.cleanupSwapChain()
 | 
						|
 | 
						|
	err = app.createSwapchain()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createImageViews()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createRenderPass()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createGraphicsPipeline()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createColorResources()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDepthResources()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createFramebuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createUniformBuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDescriptorPool()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createDescriptorSets()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.createCommandBuffers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.imagesInFlight = []core1_0.Fence{}
 | 
						|
	for i := 0; i < len(app.swapchainImages); i++ {
 | 
						|
		app.imagesInFlight = append(app.imagesInFlight, nil)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createInstance() error {
 | 
						|
	instanceOptions := core1_0.InstanceCreateInfo{
 | 
						|
		ApplicationName:    "Hello Triangle",
 | 
						|
		ApplicationVersion: common.CreateVersion(1, 0, 0),
 | 
						|
		EngineName:         "No Engine",
 | 
						|
		EngineVersion:      common.CreateVersion(1, 0, 0),
 | 
						|
		APIVersion:         common.Vulkan1_2,
 | 
						|
	}
 | 
						|
 | 
						|
	// Add extensions
 | 
						|
	sdlExtensions := app.window.VulkanGetInstanceExtensions()
 | 
						|
	extensions, _, err := app.loader.AvailableExtensions()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, ext := range sdlExtensions {
 | 
						|
		_, hasExt := extensions[ext]
 | 
						|
		if !hasExt {
 | 
						|
			return errors.Errorf("createinstance: cannot initialize sdl: missing extension %s", ext)
 | 
						|
		}
 | 
						|
		instanceOptions.EnabledExtensionNames = append(instanceOptions.EnabledExtensionNames, ext)
 | 
						|
	}
 | 
						|
 | 
						|
	if enableValidationLayers {
 | 
						|
		instanceOptions.EnabledExtensionNames = append(instanceOptions.EnabledExtensionNames, ext_debug_utils.ExtensionName)
 | 
						|
	}
 | 
						|
 | 
						|
	_, enumerationSupported := extensions[khr_portability_enumeration.ExtensionName]
 | 
						|
	if enumerationSupported {
 | 
						|
		instanceOptions.EnabledExtensionNames = append(instanceOptions.EnabledExtensionNames, khr_portability_enumeration.ExtensionName)
 | 
						|
		instanceOptions.Flags |= khr_portability_enumeration.InstanceCreateEnumeratePortability
 | 
						|
	}
 | 
						|
 | 
						|
	// Add layers
 | 
						|
	layers, _, err := app.loader.AvailableLayers()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if enableValidationLayers {
 | 
						|
		for _, layer := range validationLayers {
 | 
						|
			_, hasValidation := layers[layer]
 | 
						|
			if !hasValidation {
 | 
						|
				return errors.Errorf("createInstance: cannot add validation- layer %s not available- install LunarG Vulkan SDK", layer)
 | 
						|
			}
 | 
						|
			instanceOptions.EnabledLayerNames = append(instanceOptions.EnabledLayerNames, layer)
 | 
						|
		}
 | 
						|
 | 
						|
		// Add debug messenger
 | 
						|
		instanceOptions.Next = app.debugMessengerOptions()
 | 
						|
	}
 | 
						|
 | 
						|
	app.instance, _, err = app.loader.CreateInstance(nil, instanceOptions)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) debugMessengerOptions() ext_debug_utils.DebugUtilsMessengerCreateInfo {
 | 
						|
	return ext_debug_utils.DebugUtilsMessengerCreateInfo{
 | 
						|
		MessageSeverity: ext_debug_utils.SeverityError | ext_debug_utils.SeverityWarning,
 | 
						|
		MessageType:     ext_debug_utils.TypeGeneral | ext_debug_utils.TypeValidation | ext_debug_utils.TypePerformance,
 | 
						|
		UserCallback:    app.logDebug,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) setupDebugMessenger() error {
 | 
						|
	if !enableValidationLayers {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	var err error
 | 
						|
	debugLoader := ext_debug_utils.CreateExtensionFromInstance(app.instance)
 | 
						|
	app.debugMessenger, _, err = debugLoader.CreateDebugUtilsMessenger(app.instance, nil, app.debugMessengerOptions())
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createSurface() error {
 | 
						|
	surfaceLoader := khr_surface.CreateExtensionFromInstance(app.instance)
 | 
						|
 | 
						|
	surface, err := vkng_sdl2.CreateSurface(app.instance, surfaceLoader, app.window)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.surface = surface
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) pickPhysicalDevice() error {
 | 
						|
	physicalDevices, _, err := app.instance.EnumeratePhysicalDevices()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, device := range physicalDevices {
 | 
						|
		if app.isDeviceSuitable(device) {
 | 
						|
			app.physicalDevice = device
 | 
						|
			app.msaaSamples, err = app.getMaxUsableSampleCount()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if app.physicalDevice == nil {
 | 
						|
		return errors.Errorf("failed to find a suitable GPU!")
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createLogicalDevice() error {
 | 
						|
	indices, err := app.findQueueFamilies(app.physicalDevice)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	uniqueQueueFamilies := []int{*indices.GraphicsFamily}
 | 
						|
	if uniqueQueueFamilies[0] != *indices.PresentFamily {
 | 
						|
		uniqueQueueFamilies = append(uniqueQueueFamilies, *indices.PresentFamily)
 | 
						|
	}
 | 
						|
 | 
						|
	var queueFamilyOptions []core1_0.DeviceQueueCreateInfo
 | 
						|
	queuePriority := float32(1.0)
 | 
						|
	for _, queueFamily := range uniqueQueueFamilies {
 | 
						|
		queueFamilyOptions = append(queueFamilyOptions, core1_0.DeviceQueueCreateInfo{
 | 
						|
			QueueFamilyIndex: queueFamily,
 | 
						|
			QueuePriorities:  []float32{queuePriority},
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	var extensionNames []string
 | 
						|
	extensionNames = append(extensionNames, deviceExtensions...)
 | 
						|
 | 
						|
	// Makes this example compatible with vulkan portability, necessary to run on mobile & mac
 | 
						|
	extensions, _, err := app.physicalDevice.EnumerateDeviceExtensionProperties()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, supported := extensions[khr_portability_subset.ExtensionName]
 | 
						|
	if supported {
 | 
						|
		extensionNames = append(extensionNames, khr_portability_subset.ExtensionName)
 | 
						|
	}
 | 
						|
 | 
						|
	app.device, _, err = app.physicalDevice.CreateDevice(nil, core1_0.DeviceCreateInfo{
 | 
						|
		QueueCreateInfos: queueFamilyOptions,
 | 
						|
		EnabledFeatures: &core1_0.PhysicalDeviceFeatures{
 | 
						|
			SamplerAnisotropy: true,
 | 
						|
		},
 | 
						|
		EnabledExtensionNames: extensionNames,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.graphicsQueue = app.device.GetQueue(*indices.GraphicsFamily, 0)
 | 
						|
	app.presentQueue = app.device.GetQueue(*indices.PresentFamily, 0)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createSwapchain() error {
 | 
						|
	app.swapchainExtension = khr_swapchain.CreateExtensionFromDevice(app.device)
 | 
						|
 | 
						|
	swapchainSupport, err := app.querySwapChainSupport(app.physicalDevice)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	surfaceFormat := app.chooseSwapSurfaceFormat(swapchainSupport.Formats)
 | 
						|
	presentMode := app.chooseSwapPresentMode(swapchainSupport.PresentModes)
 | 
						|
	extent := app.chooseSwapExtent(swapchainSupport.Capabilities)
 | 
						|
 | 
						|
	imageCount := swapchainSupport.Capabilities.MinImageCount + 1
 | 
						|
	if swapchainSupport.Capabilities.MaxImageCount > 0 && swapchainSupport.Capabilities.MaxImageCount < imageCount {
 | 
						|
		imageCount = swapchainSupport.Capabilities.MaxImageCount
 | 
						|
	}
 | 
						|
 | 
						|
	sharingMode := core1_0.SharingModeExclusive
 | 
						|
	var queueFamilyIndices []int
 | 
						|
 | 
						|
	indices, err := app.findQueueFamilies(app.physicalDevice)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if *indices.GraphicsFamily != *indices.PresentFamily {
 | 
						|
		sharingMode = core1_0.SharingModeConcurrent
 | 
						|
		queueFamilyIndices = append(queueFamilyIndices, *indices.GraphicsFamily, *indices.PresentFamily)
 | 
						|
	}
 | 
						|
 | 
						|
	swapchain, _, err := app.swapchainExtension.CreateSwapchain(app.device, nil, khr_swapchain.SwapchainCreateInfo{
 | 
						|
		Surface: app.surface,
 | 
						|
 | 
						|
		MinImageCount:    imageCount,
 | 
						|
		ImageFormat:      surfaceFormat.Format,
 | 
						|
		ImageColorSpace:  surfaceFormat.ColorSpace,
 | 
						|
		ImageExtent:      extent,
 | 
						|
		ImageArrayLayers: 1,
 | 
						|
		ImageUsage:       core1_0.ImageUsageColorAttachment,
 | 
						|
 | 
						|
		ImageSharingMode:   sharingMode,
 | 
						|
		QueueFamilyIndices: queueFamilyIndices,
 | 
						|
 | 
						|
		PreTransform:   swapchainSupport.Capabilities.CurrentTransform,
 | 
						|
		CompositeAlpha: khr_surface.CompositeAlphaOpaque,
 | 
						|
		PresentMode:    presentMode,
 | 
						|
		Clipped:        true,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.swapchainExtent = extent
 | 
						|
	app.swapchain = swapchain
 | 
						|
	app.swapchainImageFormat = surfaceFormat.Format
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createImageViews() error {
 | 
						|
	images, _, err := app.swapchain.SwapchainImages()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.swapchainImages = images
 | 
						|
 | 
						|
	var imageViews []core1_0.ImageView
 | 
						|
	for _, image := range images {
 | 
						|
		view, err := app.createImageView(image, app.swapchainImageFormat, core1_0.ImageAspectColor, 1)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		imageViews = append(imageViews, view)
 | 
						|
	}
 | 
						|
	app.swapchainImageViews = imageViews
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createRenderPass() error {
 | 
						|
	depthFormat, err := app.findDepthFormat()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	renderPass, _, err := app.device.CreateRenderPass(nil, core1_0.RenderPassCreateInfo{
 | 
						|
		Attachments: []core1_0.AttachmentDescription{
 | 
						|
			{
 | 
						|
				Format:         app.swapchainImageFormat,
 | 
						|
				Samples:        app.msaaSamples,
 | 
						|
				LoadOp:         core1_0.AttachmentLoadOpClear,
 | 
						|
				StoreOp:        core1_0.AttachmentStoreOpStore,
 | 
						|
				StencilLoadOp:  core1_0.AttachmentLoadOpDontCare,
 | 
						|
				StencilStoreOp: core1_0.AttachmentStoreOpDontCare,
 | 
						|
				InitialLayout:  core1_0.ImageLayoutUndefined,
 | 
						|
				FinalLayout:    core1_0.ImageLayoutColorAttachmentOptimal,
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Format:         depthFormat,
 | 
						|
				Samples:        app.msaaSamples,
 | 
						|
				LoadOp:         core1_0.AttachmentLoadOpClear,
 | 
						|
				StoreOp:        core1_0.AttachmentStoreOpDontCare,
 | 
						|
				StencilLoadOp:  core1_0.AttachmentLoadOpDontCare,
 | 
						|
				StencilStoreOp: core1_0.AttachmentStoreOpDontCare,
 | 
						|
				InitialLayout:  core1_0.ImageLayoutUndefined,
 | 
						|
				FinalLayout:    core1_0.ImageLayoutDepthStencilAttachmentOptimal,
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Format:         app.swapchainImageFormat,
 | 
						|
				Samples:        core1_0.Samples1,
 | 
						|
				LoadOp:         core1_0.AttachmentLoadOpDontCare,
 | 
						|
				StoreOp:        core1_0.AttachmentStoreOpStore,
 | 
						|
				StencilLoadOp:  core1_0.AttachmentLoadOpDontCare,
 | 
						|
				StencilStoreOp: core1_0.AttachmentStoreOpDontCare,
 | 
						|
				InitialLayout:  core1_0.ImageLayoutUndefined,
 | 
						|
				FinalLayout:    khr_swapchain.ImageLayoutPresentSrc,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Subpasses: []core1_0.SubpassDescription{
 | 
						|
			{
 | 
						|
				PipelineBindPoint: core1_0.PipelineBindPointGraphics,
 | 
						|
				ColorAttachments: []core1_0.AttachmentReference{
 | 
						|
					{
 | 
						|
						Attachment: 0,
 | 
						|
						Layout:     core1_0.ImageLayoutColorAttachmentOptimal,
 | 
						|
					},
 | 
						|
				},
 | 
						|
				ResolveAttachments: []core1_0.AttachmentReference{
 | 
						|
					{
 | 
						|
						Attachment: 2,
 | 
						|
						Layout:     core1_0.ImageLayoutColorAttachmentOptimal,
 | 
						|
					},
 | 
						|
				},
 | 
						|
				DepthStencilAttachment: &core1_0.AttachmentReference{
 | 
						|
					Attachment: 1,
 | 
						|
					Layout:     core1_0.ImageLayoutDepthStencilAttachmentOptimal,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		SubpassDependencies: []core1_0.SubpassDependency{
 | 
						|
			{
 | 
						|
				SrcSubpass: core1_0.SubpassExternal,
 | 
						|
				DstSubpass: 0,
 | 
						|
 | 
						|
				SrcStageMask:  core1_0.PipelineStageColorAttachmentOutput | core1_0.PipelineStageEarlyFragmentTests,
 | 
						|
				SrcAccessMask: 0,
 | 
						|
 | 
						|
				DstStageMask:  core1_0.PipelineStageColorAttachmentOutput | core1_0.PipelineStageEarlyFragmentTests,
 | 
						|
				DstAccessMask: core1_0.AccessColorAttachmentWrite | core1_0.AccessDepthStencilAttachmentWrite,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.renderPass = renderPass
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createDescriptorSetLayout() error {
 | 
						|
	var err error
 | 
						|
	app.descriptorSetLayout, _, err = app.device.CreateDescriptorSetLayout(nil, core1_0.DescriptorSetLayoutCreateInfo{
 | 
						|
		Bindings: []core1_0.DescriptorSetLayoutBinding{
 | 
						|
			{
 | 
						|
				Binding:         0,
 | 
						|
				DescriptorType:  core1_0.DescriptorTypeUniformBuffer,
 | 
						|
				DescriptorCount: 1,
 | 
						|
 | 
						|
				StageFlags: core1_0.StageVertex,
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Binding:         1,
 | 
						|
				DescriptorType:  core1_0.DescriptorTypeCombinedImageSampler,
 | 
						|
				DescriptorCount: 1,
 | 
						|
 | 
						|
				StageFlags: core1_0.StageFragment,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func bytesToBytecode(b []byte) []uint32 {
 | 
						|
	byteCode := make([]uint32, len(b)/4)
 | 
						|
	for i := 0; i < len(byteCode); i++ {
 | 
						|
		byteIndex := i * 4
 | 
						|
		byteCode[i] = 0
 | 
						|
		byteCode[i] |= uint32(b[byteIndex])
 | 
						|
		byteCode[i] |= uint32(b[byteIndex+1]) << 8
 | 
						|
		byteCode[i] |= uint32(b[byteIndex+2]) << 16
 | 
						|
		byteCode[i] |= uint32(b[byteIndex+3]) << 24
 | 
						|
	}
 | 
						|
 | 
						|
	return byteCode
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createGraphicsPipeline() error {
 | 
						|
	// Load vertex shader
 | 
						|
	vertShaderBytes, err := fileSystem.ReadFile("shaders/vert.spv")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	vertShader, _, err := app.device.CreateShaderModule(nil, core1_0.ShaderModuleCreateInfo{
 | 
						|
		Code: bytesToBytecode(vertShaderBytes),
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer vertShader.Destroy(nil)
 | 
						|
 | 
						|
	// Load fragment shader
 | 
						|
	fragShaderBytes, err := fileSystem.ReadFile("shaders/frag.spv")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	fragShader, _, err := app.device.CreateShaderModule(nil, core1_0.ShaderModuleCreateInfo{
 | 
						|
		Code: bytesToBytecode(fragShaderBytes),
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer fragShader.Destroy(nil)
 | 
						|
 | 
						|
	vertexInput := &core1_0.PipelineVertexInputStateCreateInfo{
 | 
						|
		VertexBindingDescriptions:   getVertexBindingDescription(),
 | 
						|
		VertexAttributeDescriptions: getVertexAttributeDescriptions(),
 | 
						|
	}
 | 
						|
 | 
						|
	inputAssembly := &core1_0.PipelineInputAssemblyStateCreateInfo{
 | 
						|
		Topology:               core1_0.PrimitiveTopologyTriangleList,
 | 
						|
		PrimitiveRestartEnable: false,
 | 
						|
	}
 | 
						|
 | 
						|
	vertStage := core1_0.PipelineShaderStageCreateInfo{
 | 
						|
		Stage:  core1_0.StageVertex,
 | 
						|
		Module: vertShader,
 | 
						|
		Name:   "main",
 | 
						|
	}
 | 
						|
 | 
						|
	fragStage := core1_0.PipelineShaderStageCreateInfo{
 | 
						|
		Stage:  core1_0.StageFragment,
 | 
						|
		Module: fragShader,
 | 
						|
		Name:   "main",
 | 
						|
	}
 | 
						|
 | 
						|
	viewport := &core1_0.PipelineViewportStateCreateInfo{
 | 
						|
		Viewports: []core1_0.Viewport{
 | 
						|
			{
 | 
						|
				X:        0,
 | 
						|
				Y:        0,
 | 
						|
				Width:    float32(app.swapchainExtent.Width),
 | 
						|
				Height:   float32(app.swapchainExtent.Height),
 | 
						|
				MinDepth: 0,
 | 
						|
				MaxDepth: 1,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Scissors: []core1_0.Rect2D{
 | 
						|
			{
 | 
						|
				Offset: core1_0.Offset2D{X: 0, Y: 0},
 | 
						|
				Extent: app.swapchainExtent,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	rasterization := &core1_0.PipelineRasterizationStateCreateInfo{
 | 
						|
		DepthClampEnable:        false,
 | 
						|
		RasterizerDiscardEnable: false,
 | 
						|
 | 
						|
		PolygonMode: core1_0.PolygonModeFill,
 | 
						|
		CullMode:    core1_0.CullModeBack,
 | 
						|
		FrontFace:   core1_0.FrontFaceCounterClockwise,
 | 
						|
 | 
						|
		DepthBiasEnable: false,
 | 
						|
 | 
						|
		LineWidth: 1.0,
 | 
						|
	}
 | 
						|
 | 
						|
	multisample := &core1_0.PipelineMultisampleStateCreateInfo{
 | 
						|
		SampleShadingEnable:  false,
 | 
						|
		RasterizationSamples: app.msaaSamples,
 | 
						|
		MinSampleShading:     1.0,
 | 
						|
	}
 | 
						|
 | 
						|
	depthStencil := &core1_0.PipelineDepthStencilStateCreateInfo{
 | 
						|
		DepthTestEnable:  true,
 | 
						|
		DepthWriteEnable: true,
 | 
						|
		DepthCompareOp:   core1_0.CompareOpLess,
 | 
						|
	}
 | 
						|
 | 
						|
	colorBlend := &core1_0.PipelineColorBlendStateCreateInfo{
 | 
						|
		LogicOpEnabled: false,
 | 
						|
		LogicOp:        core1_0.LogicOpCopy,
 | 
						|
 | 
						|
		BlendConstants: [4]float32{0, 0, 0, 0},
 | 
						|
		Attachments: []core1_0.PipelineColorBlendAttachmentState{
 | 
						|
			{
 | 
						|
				BlendEnabled:   false,
 | 
						|
				ColorWriteMask: core1_0.ColorComponentRed | core1_0.ColorComponentGreen | core1_0.ColorComponentBlue | core1_0.ColorComponentAlpha,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	app.pipelineLayout, _, err = app.device.CreatePipelineLayout(nil, core1_0.PipelineLayoutCreateInfo{
 | 
						|
		SetLayouts: []core1_0.DescriptorSetLayout{
 | 
						|
			app.descriptorSetLayout,
 | 
						|
		},
 | 
						|
	})
 | 
						|
 | 
						|
	pipelines, _, err := app.device.CreateGraphicsPipelines(nil, nil, []core1_0.GraphicsPipelineCreateInfo{
 | 
						|
		{
 | 
						|
			Stages: []core1_0.PipelineShaderStageCreateInfo{
 | 
						|
				vertStage,
 | 
						|
				fragStage,
 | 
						|
			},
 | 
						|
			VertexInputState:   vertexInput,
 | 
						|
			InputAssemblyState: inputAssembly,
 | 
						|
			ViewportState:      viewport,
 | 
						|
			RasterizationState: rasterization,
 | 
						|
			MultisampleState:   multisample,
 | 
						|
			DepthStencilState:  depthStencil,
 | 
						|
			ColorBlendState:    colorBlend,
 | 
						|
			Layout:             app.pipelineLayout,
 | 
						|
			RenderPass:         app.renderPass,
 | 
						|
			Subpass:            0,
 | 
						|
			BasePipelineIndex:  -1,
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.graphicsPipeline = pipelines[0]
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createFramebuffers() error {
 | 
						|
	for _, imageView := range app.swapchainImageViews {
 | 
						|
		framebuffer, _, err := app.device.CreateFramebuffer(nil, core1_0.FramebufferCreateInfo{
 | 
						|
			RenderPass: app.renderPass,
 | 
						|
			Layers:     1,
 | 
						|
			Attachments: []core1_0.ImageView{
 | 
						|
				app.colorImageView,
 | 
						|
				app.depthImageView,
 | 
						|
				imageView,
 | 
						|
			},
 | 
						|
			Width:  app.swapchainExtent.Width,
 | 
						|
			Height: app.swapchainExtent.Height,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		app.swapchainFramebuffers = append(app.swapchainFramebuffers, framebuffer)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createCommandPool() error {
 | 
						|
	indices, err := app.findQueueFamilies(app.physicalDevice)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	pool, _, err := app.device.CreateCommandPool(nil, core1_0.CommandPoolCreateInfo{
 | 
						|
		QueueFamilyIndex: *indices.GraphicsFamily,
 | 
						|
	})
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.commandPool = pool
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createColorResources() error {
 | 
						|
	var err error
 | 
						|
	app.colorImage, app.colorImageMemory, err = app.createImage(
 | 
						|
		app.swapchainExtent.Width,
 | 
						|
		app.swapchainExtent.Height,
 | 
						|
		1,
 | 
						|
		app.msaaSamples,
 | 
						|
		app.swapchainImageFormat,
 | 
						|
		core1_0.ImageTilingOptimal,
 | 
						|
		core1_0.ImageUsageTransientAttachment|core1_0.ImageUsageColorAttachment,
 | 
						|
		core1_0.MemoryPropertyDeviceLocal)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.colorImageView, err = app.createImageView(
 | 
						|
		app.colorImage,
 | 
						|
		app.swapchainImageFormat,
 | 
						|
		core1_0.ImageAspectColor,
 | 
						|
		1)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createDepthResources() error {
 | 
						|
	depthFormat, err := app.findDepthFormat()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.depthImage, app.depthImageMemory, err = app.createImage(app.swapchainExtent.Width,
 | 
						|
		app.swapchainExtent.Height,
 | 
						|
		1,
 | 
						|
		app.msaaSamples,
 | 
						|
		depthFormat,
 | 
						|
		core1_0.ImageTilingOptimal,
 | 
						|
		core1_0.ImageUsageDepthStencilAttachment,
 | 
						|
		core1_0.MemoryPropertyDeviceLocal)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.depthImageView, err = app.createImageView(app.depthImage, depthFormat, core1_0.ImageAspectDepth, 1)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) findSupportedFormat(formats []core1_0.Format, tiling core1_0.ImageTiling, features core1_0.FormatFeatureFlags) (core1_0.Format, error) {
 | 
						|
	for _, format := range formats {
 | 
						|
		props := app.physicalDevice.FormatProperties(format)
 | 
						|
 | 
						|
		if tiling == core1_0.ImageTilingLinear && (props.LinearTilingFeatures&features) == features {
 | 
						|
			return format, nil
 | 
						|
		} else if tiling == core1_0.ImageTilingOptimal && (props.OptimalTilingFeatures&features) == features {
 | 
						|
			return format, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0, errors.Errorf("failed to find supported format for tiling %s, featureset %s", tiling, features)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) findDepthFormat() (core1_0.Format, error) {
 | 
						|
	return app.findSupportedFormat([]core1_0.Format{core1_0.FormatD32SignedFloat, core1_0.FormatD32SignedFloatS8UnsignedInt, core1_0.FormatD24UnsignedNormalizedS8UnsignedInt},
 | 
						|
		core1_0.ImageTilingOptimal,
 | 
						|
		core1_0.FormatFeatureDepthStencilAttachment)
 | 
						|
}
 | 
						|
 | 
						|
func hasStencilComponent(format core1_0.Format) bool {
 | 
						|
	return format == core1_0.FormatD32SignedFloatS8UnsignedInt || format == core1_0.FormatD24UnsignedNormalizedS8UnsignedInt
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createTextureImage() error {
 | 
						|
	//Put image data into staging buffer
 | 
						|
	imageBytes, err := fileSystem.ReadFile("images/viking_room.png")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	decodedImage, err := png.Decode(bytes.NewBuffer(imageBytes))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	imageBounds := decodedImage.Bounds()
 | 
						|
	imageDims := imageBounds.Size()
 | 
						|
	imageSize := imageDims.X * imageDims.Y * 4
 | 
						|
 | 
						|
	app.mipLevels = int(math.Log2(math.Max(float64(imageDims.X), float64(imageDims.Y))))
 | 
						|
 | 
						|
	stagingBuffer, stagingMemory, err := app.createBuffer(imageSize, core1_0.BufferUsageTransferSrc, core1_0.MemoryPropertyHostVisible|core1_0.MemoryPropertyHostCoherent)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	defer stagingBuffer.Destroy(nil)
 | 
						|
	defer stagingMemory.Free(nil)
 | 
						|
 | 
						|
	var pixelData []byte
 | 
						|
 | 
						|
	for y := imageBounds.Min.Y; y < imageBounds.Max.Y; y++ {
 | 
						|
		for x := imageBounds.Min.X; x < imageBounds.Max.Y; x++ {
 | 
						|
			r, g, b, a := decodedImage.At(x, y).RGBA()
 | 
						|
			pixelData = append(pixelData, byte(r), byte(g), byte(b), byte(a))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	err = writeData(stagingMemory, 0, pixelData)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	//Create final image
 | 
						|
	app.textureImage, app.textureImageMemory, err = app.createImage(imageDims.X,
 | 
						|
		imageDims.Y,
 | 
						|
		app.mipLevels,
 | 
						|
		core1_0.Samples1,
 | 
						|
		core1_0.FormatR8G8B8A8SRGB,
 | 
						|
		core1_0.ImageTilingOptimal,
 | 
						|
		core1_0.ImageUsageTransferSrc|core1_0.ImageUsageTransferDst|core1_0.ImageUsageSampled,
 | 
						|
		core1_0.MemoryPropertyDeviceLocal)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// Copy staging to final
 | 
						|
	err = app.transitionImageLayout(app.textureImage, core1_0.FormatR8G8B8A8SRGB, core1_0.ImageLayoutUndefined, core1_0.ImageLayoutTransferDstOptimal, app.mipLevels)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	err = app.copyBufferToImage(stagingBuffer, app.textureImage, imageDims.X, imageDims.Y)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.generateMipmaps(app.textureImage, core1_0.FormatR8G8B8A8SRGB, imageDims.X, imageDims.Y, app.mipLevels)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) generateMipmaps(image core1_0.Image, imageFormat core1_0.Format, width, height int, mipLevels int) error {
 | 
						|
 | 
						|
	properties := app.physicalDevice.FormatProperties(imageFormat)
 | 
						|
 | 
						|
	if (properties.OptimalTilingFeatures & core1_0.FormatFeatureSampledImageFilterLinear) == 0 {
 | 
						|
		return errors.Errorf("texture image format %s does not support linear blitting", imageFormat)
 | 
						|
	}
 | 
						|
 | 
						|
	commandBuffer, err := app.beginSingleTimeCommands()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	barrier := core1_0.ImageMemoryBarrier{
 | 
						|
		Image:               image,
 | 
						|
		SrcQueueFamilyIndex: -1,
 | 
						|
		DstQueueFamilyIndex: -1,
 | 
						|
		SubresourceRange: core1_0.ImageSubresourceRange{
 | 
						|
			AspectMask:     core1_0.ImageAspectColor,
 | 
						|
			BaseArrayLayer: 0,
 | 
						|
			LayerCount:     1,
 | 
						|
			LevelCount:     1,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	mipWidth := width
 | 
						|
	mipHeight := height
 | 
						|
	for i := 1; i < mipLevels; i++ {
 | 
						|
		barrier.SubresourceRange.BaseMipLevel = i - 1
 | 
						|
		barrier.OldLayout = core1_0.ImageLayoutTransferDstOptimal
 | 
						|
		barrier.NewLayout = core1_0.ImageLayoutTransferSrcOptimal
 | 
						|
		barrier.SrcAccessMask = core1_0.AccessTransferWrite
 | 
						|
		barrier.DstAccessMask = core1_0.AccessTransferRead
 | 
						|
 | 
						|
		err = commandBuffer.CmdPipelineBarrier(core1_0.PipelineStageTransfer, core1_0.PipelineStageTransfer, 0, nil, nil, []core1_0.ImageMemoryBarrier{barrier})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		nextMipWidth := mipWidth
 | 
						|
		nextMipHeight := mipHeight
 | 
						|
 | 
						|
		if nextMipWidth > 1 {
 | 
						|
			nextMipWidth /= 2
 | 
						|
		}
 | 
						|
		if nextMipHeight > 1 {
 | 
						|
			nextMipHeight /= 2
 | 
						|
		}
 | 
						|
		err = commandBuffer.CmdBlitImage(image, core1_0.ImageLayoutTransferSrcOptimal, image, core1_0.ImageLayoutTransferDstOptimal, []core1_0.ImageBlit{
 | 
						|
			{
 | 
						|
				SrcSubresource: core1_0.ImageSubresourceLayers{
 | 
						|
					AspectMask:     core1_0.ImageAspectColor,
 | 
						|
					MipLevel:       i - 1,
 | 
						|
					BaseArrayLayer: 0,
 | 
						|
					LayerCount:     1,
 | 
						|
				},
 | 
						|
				SrcOffsets: [2]core1_0.Offset3D{
 | 
						|
					{X: 0, Y: 0, Z: 0},
 | 
						|
					{X: mipWidth, Y: mipHeight, Z: 1},
 | 
						|
				},
 | 
						|
 | 
						|
				DstSubresource: core1_0.ImageSubresourceLayers{
 | 
						|
					AspectMask:     core1_0.ImageAspectColor,
 | 
						|
					MipLevel:       i,
 | 
						|
					BaseArrayLayer: 0,
 | 
						|
					LayerCount:     1,
 | 
						|
				},
 | 
						|
				DstOffsets: [2]core1_0.Offset3D{
 | 
						|
					{X: 0, Y: 0, Z: 0},
 | 
						|
					{X: nextMipWidth, Y: nextMipHeight, Z: 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}, core1_0.FilterLinear)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		barrier.OldLayout = core1_0.ImageLayoutTransferSrcOptimal
 | 
						|
		barrier.NewLayout = core1_0.ImageLayoutShaderReadOnlyOptimal
 | 
						|
		barrier.SrcAccessMask = core1_0.AccessTransferRead
 | 
						|
		barrier.DstAccessMask = core1_0.AccessShaderRead
 | 
						|
		barrier.SrcQueueFamilyIndex = -1
 | 
						|
		barrier.DstQueueFamilyIndex = -1
 | 
						|
		err = commandBuffer.CmdPipelineBarrier(core1_0.PipelineStageTransfer, core1_0.PipelineStageFragmentShader, 0, nil, nil, []core1_0.ImageMemoryBarrier{barrier})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		mipWidth = nextMipWidth
 | 
						|
		mipHeight = nextMipHeight
 | 
						|
	}
 | 
						|
 | 
						|
	barrier.SubresourceRange.BaseMipLevel = mipLevels - 1
 | 
						|
	barrier.OldLayout = core1_0.ImageLayoutTransferDstOptimal
 | 
						|
	barrier.NewLayout = core1_0.ImageLayoutShaderReadOnlyOptimal
 | 
						|
	barrier.SrcAccessMask = core1_0.AccessTransferWrite
 | 
						|
	barrier.DstAccessMask = core1_0.AccessShaderRead
 | 
						|
 | 
						|
	err = commandBuffer.CmdPipelineBarrier(
 | 
						|
		core1_0.PipelineStageTransfer,
 | 
						|
		core1_0.PipelineStageFragmentShader,
 | 
						|
		0, nil, nil,
 | 
						|
		[]core1_0.ImageMemoryBarrier{barrier})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.endSingleTimeCommands(commandBuffer)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) getMaxUsableSampleCount() (core1_0.SampleCountFlags, error) {
 | 
						|
	properties, err := app.physicalDevice.Properties()
 | 
						|
	if err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
 | 
						|
	counts := properties.Limits.FramebufferColorSampleCounts & properties.Limits.FramebufferDepthSampleCounts
 | 
						|
 | 
						|
	if (counts & core1_0.Samples64) != 0 {
 | 
						|
		return core1_0.Samples64, nil
 | 
						|
	}
 | 
						|
	if (counts & core1_0.Samples32) != 0 {
 | 
						|
		return core1_0.Samples32, nil
 | 
						|
	}
 | 
						|
	if (counts & core1_0.Samples16) != 0 {
 | 
						|
		return core1_0.Samples16, nil
 | 
						|
	}
 | 
						|
	if (counts & core1_0.Samples8) != 0 {
 | 
						|
		return core1_0.Samples8, nil
 | 
						|
	}
 | 
						|
	if (counts & core1_0.Samples4) != 0 {
 | 
						|
		return core1_0.Samples4, nil
 | 
						|
	}
 | 
						|
	if (counts & core1_0.Samples2) != 0 {
 | 
						|
		return core1_0.Samples2, nil
 | 
						|
	}
 | 
						|
	return core1_0.Samples1, nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createTextureImageView() error {
 | 
						|
	var err error
 | 
						|
	app.textureImageView, err = app.createImageView(app.textureImage, core1_0.FormatR8G8B8A8SRGB, core1_0.ImageAspectColor, app.mipLevels)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createSampler() error {
 | 
						|
	properties, err := app.physicalDevice.Properties()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.textureSampler, _, err = app.device.CreateSampler(nil, core1_0.SamplerCreateInfo{
 | 
						|
		MagFilter:    core1_0.FilterLinear,
 | 
						|
		MinFilter:    core1_0.FilterLinear,
 | 
						|
		AddressModeU: core1_0.SamplerAddressModeRepeat,
 | 
						|
		AddressModeV: core1_0.SamplerAddressModeRepeat,
 | 
						|
		AddressModeW: core1_0.SamplerAddressModeRepeat,
 | 
						|
 | 
						|
		AnisotropyEnable: true,
 | 
						|
		MaxAnisotropy:    properties.Limits.MaxSamplerAnisotropy,
 | 
						|
 | 
						|
		BorderColor: core1_0.BorderColorIntOpaqueBlack,
 | 
						|
 | 
						|
		MipmapMode: core1_0.SamplerMipmapModeLinear,
 | 
						|
		MinLod:     0,
 | 
						|
		MaxLod:     float32(app.mipLevels),
 | 
						|
	})
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createImageView(image core1_0.Image, format core1_0.Format, aspect core1_0.ImageAspectFlags, mipLevels int) (core1_0.ImageView, error) {
 | 
						|
	imageView, _, err := app.device.CreateImageView(nil, core1_0.ImageViewCreateInfo{
 | 
						|
		Image:    image,
 | 
						|
		ViewType: core1_0.ImageViewType2D,
 | 
						|
		Format:   format,
 | 
						|
		SubresourceRange: core1_0.ImageSubresourceRange{
 | 
						|
			AspectMask:     aspect,
 | 
						|
			BaseMipLevel:   0,
 | 
						|
			LevelCount:     mipLevels,
 | 
						|
			BaseArrayLayer: 0,
 | 
						|
			LayerCount:     1,
 | 
						|
		},
 | 
						|
	})
 | 
						|
	return imageView, err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createImage(width, height int, mipLevels int, numSamples core1_0.SampleCountFlags, format core1_0.Format, tiling core1_0.ImageTiling, usage core1_0.ImageUsageFlags, memoryProperties core1_0.MemoryPropertyFlags) (core1_0.Image, core1_0.DeviceMemory, error) {
 | 
						|
	image, _, err := app.device.CreateImage(nil, core1_0.ImageCreateInfo{
 | 
						|
		ImageType: core1_0.ImageType2D,
 | 
						|
		Extent: core1_0.Extent3D{
 | 
						|
			Width:  width,
 | 
						|
			Height: height,
 | 
						|
			Depth:  1,
 | 
						|
		},
 | 
						|
		MipLevels:     mipLevels,
 | 
						|
		ArrayLayers:   1,
 | 
						|
		Format:        format,
 | 
						|
		Tiling:        tiling,
 | 
						|
		InitialLayout: core1_0.ImageLayoutUndefined,
 | 
						|
		Usage:         usage,
 | 
						|
		SharingMode:   core1_0.SharingModeExclusive,
 | 
						|
		Samples:       numSamples,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	memReqs := image.MemoryRequirements()
 | 
						|
	memoryIndex, err := app.findMemoryType(memReqs.MemoryTypeBits, memoryProperties)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	imageMemory, _, err := app.device.AllocateMemory(nil, core1_0.MemoryAllocateInfo{
 | 
						|
		AllocationSize:  memReqs.Size,
 | 
						|
		MemoryTypeIndex: memoryIndex,
 | 
						|
	})
 | 
						|
 | 
						|
	_, err = image.BindImageMemory(imageMemory, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return image, imageMemory, nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) transitionImageLayout(image core1_0.Image, format core1_0.Format, oldLayout core1_0.ImageLayout, newLayout core1_0.ImageLayout, mipLevels int) error {
 | 
						|
	buffer, err := app.beginSingleTimeCommands()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	var sourceStage, destStage core1_0.PipelineStageFlags
 | 
						|
	var sourceAccess, destAccess core1_0.AccessFlags
 | 
						|
 | 
						|
	if oldLayout == core1_0.ImageLayoutUndefined && newLayout == core1_0.ImageLayoutTransferDstOptimal {
 | 
						|
		sourceAccess = 0
 | 
						|
		destAccess = core1_0.AccessTransferWrite
 | 
						|
		sourceStage = core1_0.PipelineStageTopOfPipe
 | 
						|
		destStage = core1_0.PipelineStageTransfer
 | 
						|
	} else if oldLayout == core1_0.ImageLayoutTransferDstOptimal && newLayout == core1_0.ImageLayoutShaderReadOnlyOptimal {
 | 
						|
		sourceAccess = core1_0.AccessTransferWrite
 | 
						|
		destAccess = core1_0.AccessShaderRead
 | 
						|
		sourceStage = core1_0.PipelineStageTransfer
 | 
						|
		destStage = core1_0.PipelineStageFragmentShader
 | 
						|
	} else {
 | 
						|
		return errors.Errorf("unexpected layout transition: %s -> %s", oldLayout, newLayout)
 | 
						|
	}
 | 
						|
 | 
						|
	err = buffer.CmdPipelineBarrier(sourceStage, destStage, 0, nil, nil, []core1_0.ImageMemoryBarrier{
 | 
						|
		{
 | 
						|
			OldLayout:           oldLayout,
 | 
						|
			NewLayout:           newLayout,
 | 
						|
			SrcQueueFamilyIndex: -1,
 | 
						|
			DstQueueFamilyIndex: -1,
 | 
						|
			Image:               image,
 | 
						|
			SubresourceRange: core1_0.ImageSubresourceRange{
 | 
						|
				AspectMask:     core1_0.ImageAspectColor,
 | 
						|
				BaseMipLevel:   0,
 | 
						|
				LevelCount:     mipLevels,
 | 
						|
				BaseArrayLayer: 0,
 | 
						|
				LayerCount:     1,
 | 
						|
			},
 | 
						|
			SrcAccessMask: sourceAccess,
 | 
						|
			DstAccessMask: destAccess,
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.endSingleTimeCommands(buffer)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) copyBufferToImage(buffer core1_0.Buffer, image core1_0.Image, width, height int) error {
 | 
						|
	cmdBuffer, err := app.beginSingleTimeCommands()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = cmdBuffer.CmdCopyBufferToImage(buffer, image, core1_0.ImageLayoutTransferDstOptimal, []core1_0.BufferImageCopy{
 | 
						|
		{
 | 
						|
			BufferOffset:      0,
 | 
						|
			BufferRowLength:   0,
 | 
						|
			BufferImageHeight: 0,
 | 
						|
 | 
						|
			ImageSubresource: core1_0.ImageSubresourceLayers{
 | 
						|
				AspectMask:     core1_0.ImageAspectColor,
 | 
						|
				MipLevel:       0,
 | 
						|
				BaseArrayLayer: 0,
 | 
						|
				LayerCount:     1,
 | 
						|
			},
 | 
						|
			ImageOffset: core1_0.Offset3D{X: 0, Y: 0, Z: 0},
 | 
						|
			ImageExtent: core1_0.Extent3D{Width: width, Height: height, Depth: 1},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.endSingleTimeCommands(cmdBuffer)
 | 
						|
}
 | 
						|
 | 
						|
func writeData(memory core1_0.DeviceMemory, offset int, data any) error {
 | 
						|
	bufferSize := binary.Size(data)
 | 
						|
 | 
						|
	memoryPtr, _, err := memory.Map(offset, bufferSize, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer memory.Unmap()
 | 
						|
 | 
						|
	dataBuffer := unsafe.Slice((*byte)(memoryPtr), bufferSize)
 | 
						|
 | 
						|
	buf := &bytes.Buffer{}
 | 
						|
	err = binary.Write(buf, common.ByteOrder, data)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	copy(dataBuffer, buf.Bytes())
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) addVertex(decoder *obj.Decoder, uniqueVertices map[int]uint32, face obj.Face, faceIndex int) {
 | 
						|
	vertInd := face.Vertices[faceIndex]
 | 
						|
	index, vertexExists := uniqueVertices[vertInd]
 | 
						|
 | 
						|
	if !vertexExists {
 | 
						|
		vert := Vertex{Position: vkngmath.Vec3[float32]{
 | 
						|
			X: decoder.Vertices[vertInd*3],
 | 
						|
			Y: decoder.Vertices[vertInd*3+1],
 | 
						|
			Z: decoder.Vertices[vertInd*3+2],
 | 
						|
		}, Color: vkngmath.Vec3[float32]{X: 1, Y: 1, Z: 1}}
 | 
						|
 | 
						|
		uvInd := face.Uvs[faceIndex]
 | 
						|
		vert.TexCoord = vkngmath.Vec2[float32]{
 | 
						|
			X: decoder.Uvs[uvInd*2],
 | 
						|
			Y: 1.0 - decoder.Uvs[uvInd*2+1],
 | 
						|
		}
 | 
						|
 | 
						|
		index = uint32(len(app.vertices))
 | 
						|
		app.vertices = append(app.vertices, vert)
 | 
						|
		uniqueVertices[vertInd] = index
 | 
						|
	}
 | 
						|
 | 
						|
	app.indices = append(app.indices, index)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) loadModel() error {
 | 
						|
	meshFile, err := fileSystem.Open("meshes/viking_room.obj")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer meshFile.Close()
 | 
						|
 | 
						|
	matFile, err := fileSystem.Open("meshes/viking_room.mtl")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer matFile.Close()
 | 
						|
 | 
						|
	decoder, err := obj.DecodeReader(meshFile, matFile)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	uniqueVertices := make(map[int]uint32)
 | 
						|
 | 
						|
	for _, decodedObj := range decoder.Objects {
 | 
						|
		for _, face := range decodedObj.Faces {
 | 
						|
			// We need to triangularize faces
 | 
						|
			for i := 2; i < len(face.Vertices); i++ {
 | 
						|
				app.addVertex(decoder, uniqueVertices, face, 0)
 | 
						|
				app.addVertex(decoder, uniqueVertices, face, i-1)
 | 
						|
				app.addVertex(decoder, uniqueVertices, face, i)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createVertexBuffer() error {
 | 
						|
	var err error
 | 
						|
	bufferSize := binary.Size(app.vertices)
 | 
						|
 | 
						|
	stagingBuffer, stagingBufferMemory, err := app.createBuffer(bufferSize, core1_0.BufferUsageTransferSrc, core1_0.MemoryPropertyHostVisible|core1_0.MemoryPropertyHostCoherent)
 | 
						|
	if stagingBuffer != nil {
 | 
						|
		defer stagingBuffer.Destroy(nil)
 | 
						|
	}
 | 
						|
	if stagingBufferMemory != nil {
 | 
						|
		defer stagingBufferMemory.Free(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = writeData(stagingBufferMemory, 0, app.vertices)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.vertexBuffer, app.vertexBufferMemory, err = app.createBuffer(bufferSize, core1_0.BufferUsageTransferDst|core1_0.BufferUsageVertexBuffer, core1_0.MemoryPropertyDeviceLocal)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.copyBuffer(stagingBuffer, app.vertexBuffer, bufferSize)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createIndexBuffer() error {
 | 
						|
	bufferSize := binary.Size(app.indices)
 | 
						|
 | 
						|
	stagingBuffer, stagingBufferMemory, err := app.createBuffer(bufferSize, core1_0.BufferUsageTransferSrc, core1_0.MemoryPropertyHostVisible|core1_0.MemoryPropertyHostCoherent)
 | 
						|
	if stagingBuffer != nil {
 | 
						|
		defer stagingBuffer.Destroy(nil)
 | 
						|
	}
 | 
						|
	if stagingBufferMemory != nil {
 | 
						|
		defer stagingBufferMemory.Free(nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = writeData(stagingBufferMemory, 0, app.indices)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.indexBuffer, app.indexBufferMemory, err = app.createBuffer(bufferSize, core1_0.BufferUsageTransferDst|core1_0.BufferUsageIndexBuffer, core1_0.MemoryPropertyDeviceLocal)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.copyBuffer(stagingBuffer, app.indexBuffer, bufferSize)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createUniformBuffers() error {
 | 
						|
	bufferSize := int(unsafe.Sizeof(UniformBufferObject{}))
 | 
						|
 | 
						|
	for i := 0; i < len(app.swapchainImages); i++ {
 | 
						|
		buffer, memory, err := app.createBuffer(bufferSize, core1_0.BufferUsageUniformBuffer, core1_0.MemoryPropertyHostVisible|core1_0.MemoryPropertyHostCoherent)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		app.uniformBuffers = append(app.uniformBuffers, buffer)
 | 
						|
		app.uniformBuffersMemory = append(app.uniformBuffersMemory, memory)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createDescriptorPool() error {
 | 
						|
	var err error
 | 
						|
	app.descriptorPool, _, err = app.device.CreateDescriptorPool(nil, core1_0.DescriptorPoolCreateInfo{
 | 
						|
		MaxSets: len(app.swapchainImages),
 | 
						|
		PoolSizes: []core1_0.DescriptorPoolSize{
 | 
						|
			{
 | 
						|
				Type:            core1_0.DescriptorTypeUniformBuffer,
 | 
						|
				DescriptorCount: len(app.swapchainImages),
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Type:            core1_0.DescriptorTypeCombinedImageSampler,
 | 
						|
				DescriptorCount: len(app.swapchainImages),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createDescriptorSets() error {
 | 
						|
	var allocLayouts []core1_0.DescriptorSetLayout
 | 
						|
	for i := 0; i < len(app.swapchainImages); i++ {
 | 
						|
		allocLayouts = append(allocLayouts, app.descriptorSetLayout)
 | 
						|
	}
 | 
						|
 | 
						|
	var err error
 | 
						|
	app.descriptorSets, _, err = app.device.AllocateDescriptorSets(core1_0.DescriptorSetAllocateInfo{
 | 
						|
		DescriptorPool: app.descriptorPool,
 | 
						|
		SetLayouts:     allocLayouts,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < len(app.swapchainImages); i++ {
 | 
						|
		err = app.device.UpdateDescriptorSets([]core1_0.WriteDescriptorSet{
 | 
						|
			{
 | 
						|
				DstSet:          app.descriptorSets[i],
 | 
						|
				DstBinding:      0,
 | 
						|
				DstArrayElement: 0,
 | 
						|
 | 
						|
				DescriptorType: core1_0.DescriptorTypeUniformBuffer,
 | 
						|
 | 
						|
				BufferInfo: []core1_0.DescriptorBufferInfo{
 | 
						|
					{
 | 
						|
						Buffer: app.uniformBuffers[i],
 | 
						|
						Offset: 0,
 | 
						|
						Range:  int(unsafe.Sizeof(UniformBufferObject{})),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			{
 | 
						|
				DstSet:          app.descriptorSets[i],
 | 
						|
				DstBinding:      1,
 | 
						|
				DstArrayElement: 0,
 | 
						|
 | 
						|
				DescriptorType: core1_0.DescriptorTypeCombinedImageSampler,
 | 
						|
 | 
						|
				ImageInfo: []core1_0.DescriptorImageInfo{
 | 
						|
					{
 | 
						|
						ImageView:   app.textureImageView,
 | 
						|
						Sampler:     app.textureSampler,
 | 
						|
						ImageLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}, nil)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createBuffer(size int, usage core1_0.BufferUsageFlags, properties core1_0.MemoryPropertyFlags) (core1_0.Buffer, core1_0.DeviceMemory, error) {
 | 
						|
	buffer, _, err := app.device.CreateBuffer(nil, core1_0.BufferCreateInfo{
 | 
						|
		Size:        size,
 | 
						|
		Usage:       usage,
 | 
						|
		SharingMode: core1_0.SharingModeExclusive,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	memRequirements := buffer.MemoryRequirements()
 | 
						|
	memoryTypeIndex, err := app.findMemoryType(memRequirements.MemoryTypeBits, properties)
 | 
						|
	if err != nil {
 | 
						|
		return buffer, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	memory, _, err := app.device.AllocateMemory(nil, core1_0.MemoryAllocateInfo{
 | 
						|
		AllocationSize:  memRequirements.Size,
 | 
						|
		MemoryTypeIndex: memoryTypeIndex,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return buffer, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = buffer.BindBufferMemory(memory, 0)
 | 
						|
	return buffer, memory, err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) beginSingleTimeCommands() (core1_0.CommandBuffer, error) {
 | 
						|
	buffers, _, err := app.device.AllocateCommandBuffers(core1_0.CommandBufferAllocateInfo{
 | 
						|
		CommandPool:        app.commandPool,
 | 
						|
		Level:              core1_0.CommandBufferLevelPrimary,
 | 
						|
		CommandBufferCount: 1,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	buffer := buffers[0]
 | 
						|
	_, err = buffer.Begin(core1_0.CommandBufferBeginInfo{
 | 
						|
		Flags: core1_0.CommandBufferUsageOneTimeSubmit,
 | 
						|
	})
 | 
						|
	return buffer, err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) endSingleTimeCommands(buffer core1_0.CommandBuffer) error {
 | 
						|
	_, err := buffer.End()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = app.graphicsQueue.Submit(nil, []core1_0.SubmitInfo{
 | 
						|
		{
 | 
						|
			CommandBuffers: []core1_0.CommandBuffer{buffer},
 | 
						|
		},
 | 
						|
	})
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = app.graphicsQueue.WaitIdle()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.device.FreeCommandBuffers([]core1_0.CommandBuffer{buffer})
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) copyBuffer(srcBuffer core1_0.Buffer, dstBuffer core1_0.Buffer, size int) error {
 | 
						|
	buffer, err := app.beginSingleTimeCommands()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = buffer.CmdCopyBuffer(srcBuffer, dstBuffer, []core1_0.BufferCopy{
 | 
						|
		{
 | 
						|
			SrcOffset: 0,
 | 
						|
			DstOffset: 0,
 | 
						|
			Size:      size,
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return app.endSingleTimeCommands(buffer)
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) findMemoryType(typeFilter uint32, properties core1_0.MemoryPropertyFlags) (int, error) {
 | 
						|
	memProperties := app.physicalDevice.MemoryProperties()
 | 
						|
	for i, memoryType := range memProperties.MemoryTypes {
 | 
						|
		typeBit := uint32(1 << i)
 | 
						|
 | 
						|
		if (typeFilter&typeBit) != 0 && (memoryType.PropertyFlags&properties) == properties {
 | 
						|
			return i, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0, errors.Errorf("failed to find any suitable memory type!")
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createCommandBuffers() error {
 | 
						|
 | 
						|
	buffers, _, err := app.device.AllocateCommandBuffers(core1_0.CommandBufferAllocateInfo{
 | 
						|
		CommandPool:        app.commandPool,
 | 
						|
		Level:              core1_0.CommandBufferLevelPrimary,
 | 
						|
		CommandBufferCount: len(app.swapchainImages),
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	app.commandBuffers = buffers
 | 
						|
 | 
						|
	for bufferIdx, buffer := range buffers {
 | 
						|
		_, err = buffer.Begin(core1_0.CommandBufferBeginInfo{})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		err = buffer.CmdBeginRenderPass(core1_0.SubpassContentsInline,
 | 
						|
			core1_0.RenderPassBeginInfo{
 | 
						|
				RenderPass:  app.renderPass,
 | 
						|
				Framebuffer: app.swapchainFramebuffers[bufferIdx],
 | 
						|
				RenderArea: core1_0.Rect2D{
 | 
						|
					Offset: core1_0.Offset2D{X: 0, Y: 0},
 | 
						|
					Extent: app.swapchainExtent,
 | 
						|
				},
 | 
						|
				ClearValues: []core1_0.ClearValue{
 | 
						|
					core1_0.ClearValueFloat{0, 0, 0, 1},
 | 
						|
					core1_0.ClearValueDepthStencil{Depth: 1.0, Stencil: 0},
 | 
						|
				},
 | 
						|
			})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		buffer.CmdBindPipeline(core1_0.PipelineBindPointGraphics, app.graphicsPipeline)
 | 
						|
		buffer.CmdBindVertexBuffers(0, []core1_0.Buffer{app.vertexBuffer}, []int{0})
 | 
						|
		buffer.CmdBindIndexBuffer(app.indexBuffer, 0, core1_0.IndexTypeUInt32)
 | 
						|
		buffer.CmdBindDescriptorSets(core1_0.PipelineBindPointGraphics, app.pipelineLayout, 0, []core1_0.DescriptorSet{
 | 
						|
			app.descriptorSets[bufferIdx],
 | 
						|
		}, nil)
 | 
						|
		buffer.CmdDrawIndexed(len(app.indices), 1, 0, 0, 0)
 | 
						|
		buffer.CmdEndRenderPass()
 | 
						|
 | 
						|
		_, err = buffer.End()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) createSyncObjects() error {
 | 
						|
	for i := 0; i < MaxFramesInFlight; i++ {
 | 
						|
		semaphore, _, err := app.device.CreateSemaphore(nil, core1_0.SemaphoreCreateInfo{})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		app.imageAvailableSemaphore = append(app.imageAvailableSemaphore, semaphore)
 | 
						|
 | 
						|
		semaphore, _, err = app.device.CreateSemaphore(nil, core1_0.SemaphoreCreateInfo{})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		app.renderFinishedSemaphore = append(app.renderFinishedSemaphore, semaphore)
 | 
						|
 | 
						|
		fence, _, err := app.device.CreateFence(nil, core1_0.FenceCreateInfo{
 | 
						|
			Flags: core1_0.FenceCreateSignaled,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		app.inFlightFence = append(app.inFlightFence, fence)
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < len(app.swapchainImages); i++ {
 | 
						|
		app.imagesInFlight = append(app.imagesInFlight, nil)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) drawFrame() error {
 | 
						|
	fences := []core1_0.Fence{app.inFlightFence[app.currentFrame]}
 | 
						|
 | 
						|
	_, err := app.device.WaitForFences(true, common.NoTimeout, fences)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	imageIndex, res, err := app.swapchain.AcquireNextImage(common.NoTimeout, app.imageAvailableSemaphore[app.currentFrame], nil)
 | 
						|
	if res == khr_swapchain.VKErrorOutOfDate {
 | 
						|
		return app.recreateSwapChain()
 | 
						|
	} else if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if app.imagesInFlight[imageIndex] != nil {
 | 
						|
		_, err := app.imagesInFlight[imageIndex].Wait(common.NoTimeout)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	app.imagesInFlight[imageIndex] = app.inFlightFence[app.currentFrame]
 | 
						|
 | 
						|
	_, err = app.device.ResetFences(fences)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = app.updateUniformBuffer(imageIndex)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = app.graphicsQueue.Submit(app.inFlightFence[app.currentFrame], []core1_0.SubmitInfo{
 | 
						|
		{
 | 
						|
			WaitSemaphores:   []core1_0.Semaphore{app.imageAvailableSemaphore[app.currentFrame]},
 | 
						|
			WaitDstStageMask: []core1_0.PipelineStageFlags{core1_0.PipelineStageColorAttachmentOutput},
 | 
						|
			CommandBuffers:   []core1_0.CommandBuffer{app.commandBuffers[imageIndex]},
 | 
						|
			SignalSemaphores: []core1_0.Semaphore{app.renderFinishedSemaphore[app.currentFrame]},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	res, err = app.swapchainExtension.QueuePresent(app.presentQueue, khr_swapchain.PresentInfo{
 | 
						|
		WaitSemaphores: []core1_0.Semaphore{app.renderFinishedSemaphore[app.currentFrame]},
 | 
						|
		Swapchains:     []khr_swapchain.Swapchain{app.swapchain},
 | 
						|
		ImageIndices:   []int{imageIndex},
 | 
						|
	})
 | 
						|
	if res == khr_swapchain.VKErrorOutOfDate || res == khr_swapchain.VKSuboptimal {
 | 
						|
		return app.recreateSwapChain()
 | 
						|
	} else if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	app.currentFrame = (app.currentFrame + 1) % MaxFramesInFlight
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) updateUniformBuffer(currentImage int) error {
 | 
						|
	currentTime := hrtime.Now().Seconds()
 | 
						|
	timePeriod := math.Mod(currentTime, 4.0)
 | 
						|
 | 
						|
	ubo := UniformBufferObject{}
 | 
						|
	ubo.Model.SetRotationZ(timePeriod * math.Pi / 2.0)
 | 
						|
	ubo.View.SetLookAt(
 | 
						|
		&vkngmath.Vec3[float32]{X: 2, Y: 2, Z: 2},
 | 
						|
		&vkngmath.Vec3[float32]{X: 0, Y: 0, Z: 0},
 | 
						|
		&vkngmath.Vec3[float32]{X: 0, Y: 0, Z: 1},
 | 
						|
	)
 | 
						|
	aspectRatio := float32(app.swapchainExtent.Width) / float32(app.swapchainExtent.Height)
 | 
						|
 | 
						|
	near := float32(0.1)
 | 
						|
	far := float32(10.0)
 | 
						|
	fovy := math.Pi / 4.0
 | 
						|
 | 
						|
	ubo.Proj.SetPerspective(fovy, aspectRatio, near, far)
 | 
						|
 | 
						|
	err := writeData(app.uniformBuffersMemory[currentImage], 0, &ubo)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) chooseSwapSurfaceFormat(availableFormats []khr_surface.SurfaceFormat) khr_surface.SurfaceFormat {
 | 
						|
	for _, format := range availableFormats {
 | 
						|
		if format.Format == core1_0.FormatB8G8R8A8SRGB && format.ColorSpace == khr_surface.ColorSpaceSRGBNonlinear {
 | 
						|
			return format
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return availableFormats[0]
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) chooseSwapPresentMode(availablePresentModes []khr_surface.PresentMode) khr_surface.PresentMode {
 | 
						|
	for _, presentMode := range availablePresentModes {
 | 
						|
		if presentMode == khr_surface.PresentModeMailbox {
 | 
						|
			return presentMode
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return khr_surface.PresentModeFIFO
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) chooseSwapExtent(capabilities *khr_surface.SurfaceCapabilities) core1_0.Extent2D {
 | 
						|
	if capabilities.CurrentExtent.Width != -1 {
 | 
						|
		return capabilities.CurrentExtent
 | 
						|
	}
 | 
						|
 | 
						|
	widthInt, heightInt := app.window.VulkanGetDrawableSize()
 | 
						|
	width := int(widthInt)
 | 
						|
	height := int(heightInt)
 | 
						|
 | 
						|
	if width < capabilities.MinImageExtent.Width {
 | 
						|
		width = capabilities.MinImageExtent.Width
 | 
						|
	}
 | 
						|
	if width > capabilities.MaxImageExtent.Width {
 | 
						|
		width = capabilities.MaxImageExtent.Width
 | 
						|
	}
 | 
						|
	if height < capabilities.MinImageExtent.Height {
 | 
						|
		height = capabilities.MinImageExtent.Height
 | 
						|
	}
 | 
						|
	if height > capabilities.MaxImageExtent.Height {
 | 
						|
		height = capabilities.MaxImageExtent.Height
 | 
						|
	}
 | 
						|
 | 
						|
	return core1_0.Extent2D{Width: width, Height: height}
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) querySwapChainSupport(device core1_0.PhysicalDevice) (SwapChainSupportDetails, error) {
 | 
						|
	var details SwapChainSupportDetails
 | 
						|
	var err error
 | 
						|
 | 
						|
	details.Capabilities, _, err = app.surface.PhysicalDeviceSurfaceCapabilities(device)
 | 
						|
	if err != nil {
 | 
						|
		return details, err
 | 
						|
	}
 | 
						|
 | 
						|
	details.Formats, _, err = app.surface.PhysicalDeviceSurfaceFormats(device)
 | 
						|
	if err != nil {
 | 
						|
		return details, err
 | 
						|
	}
 | 
						|
 | 
						|
	details.PresentModes, _, err = app.surface.PhysicalDeviceSurfacePresentModes(device)
 | 
						|
	return details, err
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) isDeviceSuitable(device core1_0.PhysicalDevice) bool {
 | 
						|
	indices, err := app.findQueueFamilies(device)
 | 
						|
	if err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	extensionsSupported := app.checkDeviceExtensionSupport(device)
 | 
						|
 | 
						|
	var swapChainAdequate bool
 | 
						|
	if extensionsSupported {
 | 
						|
		swapChainSupport, err := app.querySwapChainSupport(device)
 | 
						|
		if err != nil {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		swapChainAdequate = len(swapChainSupport.Formats) > 0 && len(swapChainSupport.PresentModes) > 0
 | 
						|
	}
 | 
						|
 | 
						|
	features := device.Features()
 | 
						|
	return indices.IsComplete() && extensionsSupported && swapChainAdequate && features.SamplerAnisotropy
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) checkDeviceExtensionSupport(device core1_0.PhysicalDevice) bool {
 | 
						|
	extensions, _, err := device.EnumerateDeviceExtensionProperties()
 | 
						|
	if err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	for _, extension := range deviceExtensions {
 | 
						|
		_, hasExtension := extensions[extension]
 | 
						|
		if !hasExtension {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) findQueueFamilies(device core1_0.PhysicalDevice) (QueueFamilyIndices, error) {
 | 
						|
	indices := QueueFamilyIndices{}
 | 
						|
	queueFamilies := device.QueueFamilyProperties()
 | 
						|
 | 
						|
	for queueFamilyIdx, queueFamily := range queueFamilies {
 | 
						|
		if (queueFamily.QueueFlags & core1_0.QueueGraphics) != 0 {
 | 
						|
			indices.GraphicsFamily = new(int)
 | 
						|
			*indices.GraphicsFamily = queueFamilyIdx
 | 
						|
		}
 | 
						|
 | 
						|
		supported, _, err := app.surface.PhysicalDeviceSurfaceSupport(device, queueFamilyIdx)
 | 
						|
		if err != nil {
 | 
						|
			return indices, err
 | 
						|
		}
 | 
						|
 | 
						|
		if supported {
 | 
						|
			indices.PresentFamily = new(int)
 | 
						|
			*indices.PresentFamily = queueFamilyIdx
 | 
						|
		}
 | 
						|
 | 
						|
		if indices.IsComplete() {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return indices, nil
 | 
						|
}
 | 
						|
 | 
						|
func (app *HelloTriangleApplication) logDebug(msgType ext_debug_utils.DebugUtilsMessageTypeFlags, severity ext_debug_utils.DebugUtilsMessageSeverityFlags, data *ext_debug_utils.DebugUtilsMessengerCallbackData) bool {
 | 
						|
	log.Printf("[%s %s] - %s", severity, msgType, data.Message)
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func main() {
 | 
						|
	runtime.LockOSThread()
 | 
						|
	app := &HelloTriangleApplication{
 | 
						|
		msaaSamples: core1_0.Samples1,
 | 
						|
	}
 | 
						|
 | 
						|
	err := app.Run()
 | 
						|
	if err != nil {
 | 
						|
		log.Fatalf("%+v\n", err)
 | 
						|
	}
 | 
						|
}
 |